-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added timestamp proposal check so that it does not go beyond timewind…
…ow (#4942) Signed-off-by: Fedor Partanskiy <fredprtnsk@gmail.com>
- Loading branch information
Showing
12 changed files
with
470 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
Copyright IBM Corp, SecureKey Technologies Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package filter | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/hyperledger/fabric-protos-go/peer" | ||
"github.com/hyperledger/fabric/core/handlers/auth" | ||
"github.com/hyperledger/fabric/protoutil" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// NewTimeWindowCheckFilter creates a new Filter that checks timewindow expiration | ||
func NewTimeWindowCheckFilter(timeWindow time.Duration) auth.Filter { | ||
return &timewindowCheckFilter{ | ||
timeWindow: timeWindow, | ||
} | ||
} | ||
|
||
type timewindowCheckFilter struct { | ||
next peer.EndorserServer | ||
timeWindow time.Duration | ||
} | ||
|
||
// Init initializes the Filter with the next EndorserServer | ||
func (f *timewindowCheckFilter) Init(next peer.EndorserServer) { | ||
f.next = next | ||
} | ||
|
||
func validateTimewindowProposal(signedProp *peer.SignedProposal, timeWindow time.Duration) error { | ||
prop, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes) | ||
if err != nil { | ||
return errors.Wrap(err, "failed parsing proposal") | ||
} | ||
|
||
hdr, err := protoutil.UnmarshalHeader(prop.Header) | ||
if err != nil { | ||
return errors.Wrap(err, "failed parsing header") | ||
} | ||
|
||
chdr, err := protoutil.UnmarshalChannelHeader(hdr.ChannelHeader) | ||
if err != nil { | ||
return errors.Wrap(err, "failed parsing channel header") | ||
} | ||
|
||
timeProposal := chdr.Timestamp.AsTime().UTC() | ||
now := time.Now().UTC() | ||
|
||
if timeProposal.Add(timeWindow).Before(now) || timeProposal.Add(-timeWindow).After(now) { | ||
return errors.Errorf("request unauthorized due to incorrect timestamp %s, peer time %s, peer.authentication.timewindow %s", | ||
timeProposal.Format(time.RFC3339), now.Format(time.RFC3339), timeWindow.String()) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// ProcessProposal processes a signed proposal | ||
func (f *timewindowCheckFilter) ProcessProposal(ctx context.Context, signedProp *peer.SignedProposal) (*peer.ProposalResponse, error) { | ||
if err := validateTimewindowProposal(signedProp, f.timeWindow); err != nil { | ||
return nil, err | ||
} | ||
return f.next.ProcessProposal(ctx, signedProp) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package filter | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
"time" | ||
|
||
"github.com/golang/protobuf/proto" | ||
"github.com/hyperledger/fabric-protos-go/common" | ||
"github.com/hyperledger/fabric-protos-go/peer" | ||
"github.com/hyperledger/fabric/protoutil" | ||
"github.com/stretchr/testify/require" | ||
"google.golang.org/protobuf/types/known/timestamppb" | ||
) | ||
|
||
func createSignedProposalForCheckTimeWindow(t *testing.T, tt time.Time) *peer.SignedProposal { | ||
sHdr := protoutil.MakeSignatureHeader(createX509Identity(t, "notExpiredCert.pem"), nil) | ||
hdr := protoutil.MakePayloadHeader(&common.ChannelHeader{ | ||
Timestamp: timestamppb.New(tt), | ||
}, sHdr) | ||
hdrBytes, err := proto.Marshal(hdr) | ||
require.NoError(t, err) | ||
prop := &peer.Proposal{ | ||
Header: hdrBytes, | ||
} | ||
propBytes, err := proto.Marshal(prop) | ||
require.NoError(t, err) | ||
return &peer.SignedProposal{ | ||
ProposalBytes: propBytes, | ||
} | ||
} | ||
|
||
func TestTimeWindowCheckFilter(t *testing.T) { | ||
nextEndorser := &mockEndorserServer{} | ||
auth := NewTimeWindowCheckFilter(time.Minute * 15) | ||
auth.Init(nextEndorser) | ||
|
||
now := time.Now() | ||
|
||
// Scenario I: Not expired timestamp | ||
sp := createSignedProposalForCheckTimeWindow(t, now) | ||
_, err := auth.ProcessProposal(context.Background(), sp) | ||
require.NoError(t, err) | ||
require.True(t, nextEndorser.invoked) | ||
nextEndorser.invoked = false | ||
|
||
// Scenario II: Expired timestamp before | ||
sp = createSignedProposalForCheckTimeWindow(t, now.Add(-time.Minute*30)) | ||
_, err = auth.ProcessProposal(context.Background(), sp) | ||
require.Contains(t, err.Error(), "request unauthorized due to incorrect timestamp") | ||
require.False(t, nextEndorser.invoked) | ||
|
||
// Scenario III: Expired timestamp after | ||
sp = createSignedProposalForCheckTimeWindow(t, now.Add(time.Minute*30)) | ||
_, err = auth.ProcessProposal(context.Background(), sp) | ||
require.Contains(t, err.Error(), "request unauthorized due to incorrect timestamp") | ||
require.False(t, nextEndorser.invoked) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.