From 9b09a4cb3756f87c1191c892b7a6b74f3c0228be Mon Sep 17 00:00:00 2001 From: Angelo De Caro Date: Mon, 21 Oct 2024 08:15:20 +0200 Subject: [PATCH] proposal response checks the validity of the endorsement signature agains a verifier provider Signed-off-by: Angelo De Caro --- .../core/generic/committer/committer.go | 56 ++++++------ .../fabric/core/generic/transaction/pr.go | 11 +++ platform/fabric/driver/sig.go | 6 ++ platform/fabric/driver/transaction.go | 1 + platform/fabric/membership.go | 5 +- .../fabric/services/endorser/endorsement.go | 90 +++++++++---------- .../fabric/services/endorser/transaction.go | 8 +- platform/fabric/transaction.go | 6 ++ 8 files changed, 100 insertions(+), 83 deletions(-) diff --git a/platform/fabric/core/generic/committer/committer.go b/platform/fabric/core/generic/committer/committer.go index 642201df8..060dcfcd1 100644 --- a/platform/fabric/core/generic/committer/committer.go +++ b/platform/fabric/core/generic/committer/committer.go @@ -736,36 +736,36 @@ func (c *Committer) commit(ctx context.Context, txID string, block uint64, index c.logger.Errorf("[%s] failed to unmarshal envelope [%s]", txID, err) return err } - //if headerType == int32(common.HeaderType_ENDORSER_TRANSACTION) { - if !c.Vault.RWSExists(txID) && c.EnvelopeService.Exists(txID) { - // Then match rwsets - span.AddEvent("extract_stored_env_to_vault") - if err := c.extractStoredEnvelopeToVault(txID); err != nil { - return errors.WithMessagef(err, "failed to load stored enveloper into the vault") - } - span.AddEvent("match_rwset") - if err := c.Vault.Match(txID, pt.Results()); err != nil { - c.logger.Errorf("[%s] rwsets do not match [%s]", txID, err) - return errors2.Wrapf(ErrDiscardTX, "[%s] rwsets do not match [%s]", txID, err) - } - } else { - // Store it - envelopeRaw, err := proto.Marshal(envelope) - if err != nil { - return errors.WithMessagef(err, "failed to store unknown envelope for [%s]", txID) - } - span.AddEvent("store_env") - if err := c.EnvelopeService.StoreEnvelope(txID, envelopeRaw); err != nil { - return errors.WithMessagef(err, "failed to store unknown envelope for [%s]", txID) - } - span.AddEvent("get_rwset_from_evn") - rws, _, err := c.RWSetLoaderService.GetRWSetFromEvn(txID) - if err != nil { - return errors.WithMessagef(err, "failed to get rws from envelope [%s]", txID) + if headerType == int32(common.HeaderType_ENDORSER_TRANSACTION) { + if !c.Vault.RWSExists(txID) && c.EnvelopeService.Exists(txID) { + // Then match rwsets + span.AddEvent("extract_stored_env_to_vault") + if err := c.extractStoredEnvelopeToVault(txID); err != nil { + return errors.WithMessagef(err, "failed to load stored enveloper into the vault") + } + span.AddEvent("match_rwset") + if err := c.Vault.Match(txID, pt.Results()); err != nil { + c.logger.Errorf("[%s] rwsets do not match [%s]", txID, err) + return errors2.Wrapf(ErrDiscardTX, "[%s] rwsets do not match [%s]", txID, err) + } + } else { + // Store it + envelopeRaw, err := proto.Marshal(envelope) + if err != nil { + return errors.WithMessagef(err, "failed to store unknown envelope for [%s]", txID) + } + span.AddEvent("store_env") + if err := c.EnvelopeService.StoreEnvelope(txID, envelopeRaw); err != nil { + return errors.WithMessagef(err, "failed to store unknown envelope for [%s]", txID) + } + span.AddEvent("get_rwset_from_evn") + rws, _, err := c.RWSetLoaderService.GetRWSetFromEvn(txID) + if err != nil { + return errors.WithMessagef(err, "failed to get rws from envelope [%s]", txID) + } + rws.Done() } - rws.Done() } - //} } // Post-Processes diff --git a/platform/fabric/core/generic/transaction/pr.go b/platform/fabric/core/generic/transaction/pr.go index b9a2e9949..6a6bcb884 100644 --- a/platform/fabric/core/generic/transaction/pr.go +++ b/platform/fabric/core/generic/transaction/pr.go @@ -8,6 +8,8 @@ package transaction import ( "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric/protoutil" "github.com/pkg/errors" @@ -83,3 +85,12 @@ func (p *ProposalResponse) Bytes() ([]byte, error) { } return raw, nil } + +func (p *ProposalResponse) VerifyEndorsement(provider driver.VerifierProvider) error { + endorser := view.Identity(p.pr.Endorsement.Endorser) + v, err := provider.GetVerifier(endorser) + if err != nil { + return errors.Wrapf(err, "failed getting verifier for [%s]", endorser) + } + return v.Verify(append(p.Payload(), endorser...), p.EndorserSignature()) +} diff --git a/platform/fabric/driver/sig.go b/platform/fabric/driver/sig.go index c28255b51..18030a039 100644 --- a/platform/fabric/driver/sig.go +++ b/platform/fabric/driver/sig.go @@ -10,6 +10,12 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" ) +// VerifierProvider returns a Verifier for the passed identity +type VerifierProvider interface { + // GetVerifier returns a Verifier for the passed identity + GetVerifier(identity view.Identity) (Verifier, error) +} + type SigningIdentity interface { Serialize() ([]byte, error) Sign(msg []byte) ([]byte, error) diff --git a/platform/fabric/driver/transaction.go b/platform/fabric/driver/transaction.go index af2247d8e..392d29749 100644 --- a/platform/fabric/driver/transaction.go +++ b/platform/fabric/driver/transaction.go @@ -35,6 +35,7 @@ type ProposalResponse interface { ResponseStatus() int32 ResponseMessage() string Bytes() ([]byte, error) + VerifyEndorsement(provider VerifierProvider) error } type Proposal interface { diff --git a/platform/fabric/membership.go b/platform/fabric/membership.go index 9a12ce64f..126feab42 100644 --- a/platform/fabric/membership.go +++ b/platform/fabric/membership.go @@ -135,10 +135,7 @@ func (s *LocalMembership) Refresh() error { } // Verifier is an interface which wraps the Verify method. -type Verifier interface { - // Verify verifies the signature over the passed message. - Verify(message, sigma []byte) error -} +type Verifier = driver.Verifier type MSPManager struct { ch driver.ChannelMembership diff --git a/platform/fabric/services/endorser/endorsement.go b/platform/fabric/services/endorser/endorsement.go index 6bd8c0714..502e79141 100644 --- a/platform/fabric/services/endorser/endorsement.go +++ b/platform/fabric/services/endorser/endorsement.go @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package endorser import ( + "bytes" "encoding/json" "time" @@ -21,28 +22,28 @@ type collectEndorsementsView struct { tx *Transaction parties []view.Identity deleteTransient bool - verifierProviders []VerifierProvider + verifierProviders []fabric.VerifierProvider } func (c *collectEndorsementsView) Call(context view.Context) (interface{}, error) { span := trace.SpanFromContext(context.Context()) // Prepare verifiers - //ch, err := c.tx.FabricNetworkService().Channel(c.tx.Channel()) - //if err != nil { - // return nil, errors.Wrapf(err, "failed getting channel [%s:%s]", c.tx.Network(), c.tx.Channel()) - //} - ////mspManager := ch.MSPManager() + ch, err := c.tx.FabricNetworkService().Channel(c.tx.Channel()) + if err != nil { + return nil, errors.Wrapf(err, "failed getting channel [%s:%s]", c.tx.Network(), c.tx.Channel()) + } + mspManager := ch.MSPManager() - //var vProviders []VerifierProvider - //vProviders = append(vProviders, c.verifierProviders...) - //vProviders = append(vProviders, c.tx.verifierProviders...) - //vProviders = append(vProviders, &verifierProviderWrapper{m: mspManager}) + var vProviders []fabric.VerifierProvider + vProviders = append(vProviders, c.verifierProviders...) + vProviders = append(vProviders, c.tx.verifierProviders...) + vProviders = append(vProviders, &verifierProviderWrapper{m: mspManager}) // Get results to send - //res, err := c.tx.Results() - //if err != nil { - // return nil, errors.Wrapf(err, "failed getting tx results") - //} + res, err := c.tx.Results() + if err != nil { + return nil, errors.Wrapf(err, "failed getting tx results") + } // Contact sequantially all parties. logger.Debugf("Collect Endorsements from [%d] parties [%v]", len(c.parties), c.parties) @@ -125,34 +126,33 @@ func (c *collectEndorsementsView) Call(context view.Context) (interface{}, error return nil, errors.Wrap(err, "failed unmarshalling received proposal response") } - // the signature check should be done by the proposal response to make sure that - // platform dependant operation can be performed. endorser := view.Identity(proposalResponse.Endorser()) - //// Check the validity of the response + // Check the validity of the response if view2.GetEndpointService(context).IsBoundTo(endorser, party) { found = true } - // - //// TODO: check the verifier providers, if any - //verified := false - //for _, provider := range vProviders { - // span.AddEvent("verify_endorsement") - // if v, err := provider.GetVerifier(endorser); err == nil { - // if err := v.Verify(append(proposalResponse.Payload(), endorser...), proposalResponse.EndorserSignature()); err == nil { - // verified = true - // break - // } - // } - //} - //if !verified { - // return nil, errors.Errorf("failed to verify signature for party [%s][%s]", endorser.String(), string(endorser)) - //} - //// Check the content of the response - //// Now results can be equal to what this node has proposed or different - //if !bytes.Equal(res, proposalResponse.Results()) { - // return nil, errors.Errorf("received different results") - //} + + // TODO: check the verifier providers, if any + verified := false + for _, provider := range vProviders { + span.AddEvent("verify_endorsement") + err := proposalResponse.VerifyEndorsement(provider) + if err == nil { + logger.Debugf("endorsement [%s] is valid", endorser) + verified = true + break + } + logger.Debugf("endorsement [%s] is invalid, reason [%s]", endorser, err) + } + if !verified { + return nil, errors.Errorf("failed to verify signature for party [%s][%s]", endorser.String(), string(endorser)) + } + // Check the content of the response + // Now results can be equal to what this node has proposed or different + if !bytes.Equal(res, proposalResponse.Results()) { + return nil, errors.Errorf("received different results") + } logger.Debugf("append response from party [%s]", party) err = c.tx.AppendProposalResponse(proposalResponse) @@ -168,7 +168,7 @@ func (c *collectEndorsementsView) Call(context view.Context) (interface{}, error return c.tx, nil } -func (c *collectEndorsementsView) SetVerifierProviders(p []VerifierProvider) *collectEndorsementsView { +func (c *collectEndorsementsView) SetVerifierProviders(p []fabric.VerifierProvider) *collectEndorsementsView { c.verifierProviders = p return c } @@ -248,10 +248,10 @@ func NewAcceptView(tx *Transaction, ids ...view.Identity) *endorseView { return &endorseView{tx: tx, identities: ids} } -//type verifierProviderWrapper struct { -// m *fabric.MSPManager -//} -// -//func (v *verifierProviderWrapper) GetVerifier(identity view.Identity) (view2.Verifier, error) { -// return v.m.GetVerifier(identity) -//} +type verifierProviderWrapper struct { + m *fabric.MSPManager +} + +func (v *verifierProviderWrapper) GetVerifier(identity view.Identity) (fabric.Verifier, error) { + return v.m.GetVerifier(identity) +} diff --git a/platform/fabric/services/endorser/transaction.go b/platform/fabric/services/endorser/transaction.go index 7a03d0705..e562865ed 100644 --- a/platform/fabric/services/endorser/transaction.go +++ b/platform/fabric/services/endorser/transaction.go @@ -16,15 +16,11 @@ import ( "github.com/pkg/errors" ) -type VerifierProvider interface { - GetVerifier(identity view.Identity) (view2.Verifier, error) -} - type Transaction struct { view2.ServiceProvider Transaction *fabric.Transaction - verifierProviders []VerifierProvider + verifierProviders []fabric.VerifierProvider } func (t *Transaction) ID() string { @@ -218,7 +214,7 @@ func (t *Transaction) FabricNetworkService() *fabric.NetworkService { return t.Transaction.FabricNetworkService() } -func (t *Transaction) AppendVerifierProvider(vp VerifierProvider) { +func (t *Transaction) AppendVerifierProvider(vp fabric.VerifierProvider) { t.verifierProviders = append(t.verifierProviders, vp) } diff --git a/platform/fabric/transaction.go b/platform/fabric/transaction.go index 1dfe59aeb..7ae92765f 100644 --- a/platform/fabric/transaction.go +++ b/platform/fabric/transaction.go @@ -14,6 +14,8 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" ) +type VerifierProvider = driver.VerifierProvider + type TransactionType = driver.TransactionType const ( @@ -126,6 +128,10 @@ func (r *ProposalResponse) Bytes() ([]byte, error) { return r.pr.Bytes() } +func (r *ProposalResponse) VerifyEndorsement(provider VerifierProvider) error { + return r.pr.VerifyEndorsement(provider) +} + type Proposal struct { p driver.Proposal }