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 }