github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/endorser/msgvalidation.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package endorser
     8  
     9  import (
    10  	"crypto/sha256"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/hechain20/hechain/core/common/ccprovider"
    14  	"github.com/hechain20/hechain/msp"
    15  	"github.com/hechain20/hechain/protoutil"
    16  	"github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // UnpackedProposal contains the interesting artifacts from inside the proposal.
    22  type UnpackedProposal struct {
    23  	ChaincodeName   string
    24  	ChannelHeader   *common.ChannelHeader
    25  	Input           *peer.ChaincodeInput
    26  	Proposal        *peer.Proposal
    27  	SignatureHeader *common.SignatureHeader
    28  	SignedProposal  *peer.SignedProposal
    29  	ProposalHash    []byte
    30  }
    31  
    32  func (up *UnpackedProposal) ChannelID() string {
    33  	return up.ChannelHeader.ChannelId
    34  }
    35  
    36  func (up *UnpackedProposal) TxID() string {
    37  	return up.ChannelHeader.TxId
    38  }
    39  
    40  // UnpackProposal creates an an *UnpackedProposal which is guaranteed to have
    41  // no zero-ed fields or it returns an error.
    42  func UnpackProposal(signedProp *peer.SignedProposal) (*UnpackedProposal, error) {
    43  	prop, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	hdr, err := protoutil.UnmarshalHeader(prop.Header)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	chdr, err := protoutil.UnmarshalChannelHeader(hdr.ChannelHeader)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	shdr, err := protoutil.UnmarshalSignatureHeader(hdr.SignatureHeader)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	chaincodeHdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(chdr.Extension)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	if chaincodeHdrExt.ChaincodeId == nil {
    69  		return nil, errors.Errorf("ChaincodeHeaderExtension.ChaincodeId is nil")
    70  	}
    71  
    72  	if chaincodeHdrExt.ChaincodeId.Name == "" {
    73  		return nil, errors.Errorf("ChaincodeHeaderExtension.ChaincodeId.Name is empty")
    74  	}
    75  
    76  	cpp, err := protoutil.UnmarshalChaincodeProposalPayload(prop.Payload)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	cis, err := protoutil.UnmarshalChaincodeInvocationSpec(cpp.Input)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	if cis.ChaincodeSpec == nil {
    87  		return nil, errors.Errorf("chaincode invocation spec did not contain chaincode spec")
    88  	}
    89  
    90  	if cis.ChaincodeSpec.Input == nil {
    91  		return nil, errors.Errorf("chaincode input did not contain any input")
    92  	}
    93  
    94  	cppNoTransient := &peer.ChaincodeProposalPayload{Input: cpp.Input, TransientMap: nil}
    95  	ppBytes, err := proto.Marshal(cppNoTransient)
    96  	if err != nil {
    97  		return nil, errors.WithMessage(err, "could not marshal non-transient portion of payload")
    98  	}
    99  
   100  	// TODO, this was preserved from the proputils stuff, but should this be BCCSP?
   101  
   102  	// The proposal hash is the hash of the concatenation of:
   103  	// 1) The serialized Channel Header object
   104  	// 2) The serialized Signature Header object
   105  	// 3) The hash of the part of the chaincode proposal payload that will go to the tx
   106  	// (ie, the parts without the transient data)
   107  	propHash := sha256.New()
   108  	propHash.Write(hdr.ChannelHeader)
   109  	propHash.Write(hdr.SignatureHeader)
   110  	propHash.Write(ppBytes)
   111  
   112  	return &UnpackedProposal{
   113  		SignedProposal:  signedProp,
   114  		Proposal:        prop,
   115  		ChannelHeader:   chdr,
   116  		SignatureHeader: shdr,
   117  		ChaincodeName:   chaincodeHdrExt.ChaincodeId.Name,
   118  		Input:           cis.ChaincodeSpec.Input,
   119  		ProposalHash:    propHash.Sum(nil)[:],
   120  	}, nil
   121  }
   122  
   123  func (up *UnpackedProposal) Validate(idDeserializer msp.IdentityDeserializer) error {
   124  	logger := decorateLogger(endorserLogger, &ccprovider.TransactionParams{
   125  		ChannelID: up.ChannelHeader.ChannelId,
   126  		TxID:      up.TxID(),
   127  	})
   128  
   129  	// validate the header type
   130  	switch common.HeaderType(up.ChannelHeader.Type) {
   131  	case common.HeaderType_ENDORSER_TRANSACTION:
   132  	case common.HeaderType_CONFIG:
   133  		// The CONFIG transaction type has _no_ business coming to the propose API.
   134  		// In fact, anything coming to the Propose API is by definition an endorser
   135  		// transaction, so any other header type seems like it ought to be an error... oh well.
   136  
   137  	default:
   138  		return errors.Errorf("invalid header type %s", common.HeaderType(up.ChannelHeader.Type))
   139  	}
   140  
   141  	// ensure the epoch is 0
   142  	if up.ChannelHeader.Epoch != 0 {
   143  		return errors.Errorf("epoch is non-zero")
   144  	}
   145  
   146  	// ensure that there is a nonce
   147  	if len(up.SignatureHeader.Nonce) == 0 {
   148  		return errors.Errorf("nonce is empty")
   149  	}
   150  
   151  	// ensure that there is a creator
   152  	if len(up.SignatureHeader.Creator) == 0 {
   153  		return errors.New("creator is empty")
   154  	}
   155  
   156  	expectedTxID := protoutil.ComputeTxID(up.SignatureHeader.Nonce, up.SignatureHeader.Creator)
   157  	if up.TxID() != expectedTxID {
   158  		return errors.Errorf("incorrectly computed txid '%s' -- expected '%s'", up.TxID(), expectedTxID)
   159  	}
   160  
   161  	if up.SignedProposal.ProposalBytes == nil {
   162  		return errors.Errorf("empty proposal bytes")
   163  	}
   164  
   165  	if up.SignedProposal.Signature == nil {
   166  		return errors.Errorf("empty signature bytes")
   167  	}
   168  
   169  	// get the identity of the creator
   170  	creator, err := idDeserializer.DeserializeIdentity(up.SignatureHeader.Creator)
   171  	if err != nil {
   172  		logger.Warnw("access denied", "error", err, "identity", protoutil.LogMessageForSerializedIdentity(up.SignatureHeader.Creator))
   173  		return errors.Errorf("access denied: channel [%s] creator org unknown, creator is malformed", up.ChannelID())
   174  	}
   175  
   176  	genericAuthError := errors.Errorf("access denied: channel [%s] creator org [%s]", up.ChannelID(), creator.GetMSPIdentifier())
   177  	// ensure that creator is a valid certificate
   178  	err = creator.Validate()
   179  	if err != nil {
   180  		logger.Warnw("access denied: identity is not valid", "error", err, "identity", protoutil.LogMessageForSerializedIdentity(up.SignatureHeader.Creator))
   181  		return genericAuthError
   182  	}
   183  
   184  	logger = logger.With("mspID", creator.GetMSPIdentifier())
   185  
   186  	logger.Debug("creator is valid")
   187  
   188  	// validate the signature
   189  	err = creator.Verify(up.SignedProposal.ProposalBytes, up.SignedProposal.Signature)
   190  	if err != nil {
   191  		logger.Warnw("access denied: creator's signature over the proposal is not valid", "error", err, "identity", protoutil.LogMessageForSerializedIdentity(up.SignatureHeader.Creator))
   192  		return genericAuthError
   193  	}
   194  
   195  	logger.Debug("signature is valid")
   196  
   197  	return nil
   198  }