github.com/yimialmonte/fabric@v2.1.1+incompatible/core/common/validation/msgvalidation.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package validation 8 9 import ( 10 "bytes" 11 12 "github.com/hyperledger/fabric-protos-go/common" 13 pb "github.com/hyperledger/fabric-protos-go/peer" 14 "github.com/hyperledger/fabric/bccsp" 15 "github.com/hyperledger/fabric/common/flogging" 16 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 17 "github.com/hyperledger/fabric/protoutil" 18 "github.com/pkg/errors" 19 ) 20 21 var putilsLogger = flogging.MustGetLogger("protoutils") 22 23 // given a creator, a message and a signature, 24 // this function returns nil if the creator 25 // is a valid cert and the signature is valid 26 func checkSignatureFromCreator(creatorBytes, sig, msg []byte, ChainID string, cryptoProvider bccsp.BCCSP) error { 27 putilsLogger.Debugf("begin") 28 29 // check for nil argument 30 if creatorBytes == nil || sig == nil || msg == nil { 31 return errors.New("nil arguments") 32 } 33 34 mspObj := mspmgmt.GetIdentityDeserializer(ChainID, cryptoProvider) 35 if mspObj == nil { 36 return errors.Errorf("could not get msp for channel [%s]", ChainID) 37 } 38 39 // get the identity of the creator 40 creator, err := mspObj.DeserializeIdentity(creatorBytes) 41 if err != nil { 42 return errors.WithMessage(err, "MSP error") 43 } 44 45 putilsLogger.Debugf("creator is %s", creator.GetIdentifier()) 46 47 // ensure that creator is a valid certificate 48 err = creator.Validate() 49 if err != nil { 50 return errors.WithMessage(err, "creator certificate is not valid") 51 } 52 53 putilsLogger.Debugf("creator is valid") 54 55 // validate the signature 56 err = creator.Verify(msg, sig) 57 if err != nil { 58 return errors.WithMessage(err, "creator's signature over the proposal is not valid") 59 } 60 61 putilsLogger.Debugf("exits successfully") 62 63 return nil 64 } 65 66 // checks for a valid SignatureHeader 67 func validateSignatureHeader(sHdr *common.SignatureHeader) error { 68 // check for nil argument 69 if sHdr == nil { 70 return errors.New("nil SignatureHeader provided") 71 } 72 73 // ensure that there is a nonce 74 if sHdr.Nonce == nil || len(sHdr.Nonce) == 0 { 75 return errors.New("invalid nonce specified in the header") 76 } 77 78 // ensure that there is a creator 79 if sHdr.Creator == nil || len(sHdr.Creator) == 0 { 80 return errors.New("invalid creator specified in the header") 81 } 82 83 return nil 84 } 85 86 // checks for a valid ChannelHeader 87 func validateChannelHeader(cHdr *common.ChannelHeader) error { 88 // check for nil argument 89 if cHdr == nil { 90 return errors.New("nil ChannelHeader provided") 91 } 92 93 // validate the header type 94 switch common.HeaderType(cHdr.Type) { 95 case common.HeaderType_ENDORSER_TRANSACTION: 96 case common.HeaderType_CONFIG_UPDATE: 97 case common.HeaderType_CONFIG: 98 default: 99 return errors.Errorf("invalid header type %s", common.HeaderType(cHdr.Type)) 100 } 101 102 putilsLogger.Debugf("validateChannelHeader info: header type %d", common.HeaderType(cHdr.Type)) 103 104 // TODO: validate chainID in cHdr.ChainID 105 106 // Validate epoch in cHdr.Epoch 107 // Currently we enforce that Epoch is 0. 108 // TODO: This check will be modified once the Epoch management 109 // will be in place. 110 if cHdr.Epoch != 0 { 111 return errors.Errorf("invalid Epoch in ChannelHeader. Expected 0, got [%d]", cHdr.Epoch) 112 } 113 114 // TODO: Validate version in cHdr.Version 115 116 return nil 117 } 118 119 // checks for a valid Header 120 func validateCommonHeader(hdr *common.Header) (*common.ChannelHeader, *common.SignatureHeader, error) { 121 if hdr == nil { 122 return nil, nil, errors.New("nil header") 123 } 124 125 chdr, err := protoutil.UnmarshalChannelHeader(hdr.ChannelHeader) 126 if err != nil { 127 return nil, nil, err 128 } 129 130 shdr, err := protoutil.UnmarshalSignatureHeader(hdr.SignatureHeader) 131 if err != nil { 132 return nil, nil, err 133 } 134 135 err = validateChannelHeader(chdr) 136 if err != nil { 137 return nil, nil, err 138 } 139 140 err = validateSignatureHeader(shdr) 141 if err != nil { 142 return nil, nil, err 143 } 144 145 return chdr, shdr, nil 146 } 147 148 // validateConfigTransaction validates the payload of a 149 // transaction assuming its type is CONFIG 150 func validateConfigTransaction(data []byte, hdr *common.Header) error { 151 putilsLogger.Debugf("validateConfigTransaction starts for data %p, header %s", data, hdr) 152 153 // check for nil argument 154 if data == nil || hdr == nil { 155 return errors.New("nil arguments") 156 } 157 158 // There is no need to do this validation here, the configtx.Validator handles this 159 160 return nil 161 } 162 163 // validateEndorserTransaction validates the payload of a 164 // transaction assuming its type is ENDORSER_TRANSACTION 165 func validateEndorserTransaction(data []byte, hdr *common.Header) error { 166 putilsLogger.Debugf("validateEndorserTransaction starts for data %p, header %s", data, hdr) 167 168 // check for nil argument 169 if data == nil || hdr == nil { 170 return errors.New("nil arguments") 171 } 172 173 // if the type is ENDORSER_TRANSACTION we unmarshal a Transaction message 174 tx, err := protoutil.UnmarshalTransaction(data) 175 if err != nil { 176 return err 177 } 178 179 // check for nil argument 180 if tx == nil { 181 return errors.New("nil transaction") 182 } 183 184 // TODO: validate tx.Version 185 186 // TODO: validate ChaincodeHeaderExtension 187 188 // hlf version 1 only supports a single action per transaction 189 if len(tx.Actions) != 1 { 190 return errors.Errorf("only one action per transaction is supported, tx contains %d", len(tx.Actions)) 191 } 192 193 putilsLogger.Debugf("validateEndorserTransaction info: there are %d actions", len(tx.Actions)) 194 195 for _, act := range tx.Actions { 196 // check for nil argument 197 if act == nil { 198 return errors.New("nil action") 199 } 200 201 // if the type is ENDORSER_TRANSACTION we unmarshal a SignatureHeader 202 sHdr, err := protoutil.UnmarshalSignatureHeader(act.Header) 203 if err != nil { 204 return err 205 } 206 207 // validate the SignatureHeader - here we actually only 208 // care about the nonce since the creator is in the outer header 209 err = validateSignatureHeader(sHdr) 210 if err != nil { 211 return err 212 } 213 214 putilsLogger.Debugf("validateEndorserTransaction info: signature header is valid") 215 216 // if the type is ENDORSER_TRANSACTION we unmarshal a ChaincodeActionPayload 217 ccActionPayload, err := protoutil.UnmarshalChaincodeActionPayload(act.Payload) 218 if err != nil { 219 return err 220 } 221 222 // extract the proposal response payload 223 prp, err := protoutil.UnmarshalProposalResponsePayload(ccActionPayload.Action.ProposalResponsePayload) 224 if err != nil { 225 return err 226 } 227 228 // build the original header by stitching together 229 // the common ChannelHeader and the per-action SignatureHeader 230 hdrOrig := &common.Header{ChannelHeader: hdr.ChannelHeader, SignatureHeader: act.Header} 231 232 // compute proposalHash 233 pHash, err := protoutil.GetProposalHash2(hdrOrig, ccActionPayload.ChaincodeProposalPayload) 234 if err != nil { 235 return err 236 } 237 238 // ensure that the proposal hash matches 239 if !bytes.Equal(pHash, prp.ProposalHash) { 240 return errors.New("proposal hash does not match") 241 } 242 } 243 244 return nil 245 } 246 247 // ValidateTransaction checks that the transaction envelope is properly formed 248 func ValidateTransaction(e *common.Envelope, cryptoProvider bccsp.BCCSP) (*common.Payload, pb.TxValidationCode) { 249 putilsLogger.Debugf("ValidateTransactionEnvelope starts for envelope %p", e) 250 251 // check for nil argument 252 if e == nil { 253 putilsLogger.Errorf("Error: nil envelope") 254 return nil, pb.TxValidationCode_NIL_ENVELOPE 255 } 256 257 // get the payload from the envelope 258 payload, err := protoutil.UnmarshalPayload(e.Payload) 259 if err != nil { 260 putilsLogger.Errorf("GetPayload returns err %s", err) 261 return nil, pb.TxValidationCode_BAD_PAYLOAD 262 } 263 264 putilsLogger.Debugf("Header is %s", payload.Header) 265 266 // validate the header 267 chdr, shdr, err := validateCommonHeader(payload.Header) 268 if err != nil { 269 putilsLogger.Errorf("validateCommonHeader returns err %s", err) 270 return nil, pb.TxValidationCode_BAD_COMMON_HEADER 271 } 272 273 // validate the signature in the envelope 274 err = checkSignatureFromCreator(shdr.Creator, e.Signature, e.Payload, chdr.ChannelId, cryptoProvider) 275 if err != nil { 276 putilsLogger.Errorf("checkSignatureFromCreator returns err %s", err) 277 return nil, pb.TxValidationCode_BAD_CREATOR_SIGNATURE 278 } 279 280 // TODO: ensure that creator can transact with us (some ACLs?) which set of APIs is supposed to give us this info? 281 282 // continue the validation in a way that depends on the type specified in the header 283 switch common.HeaderType(chdr.Type) { 284 case common.HeaderType_ENDORSER_TRANSACTION: 285 // Verify that the transaction ID has been computed properly. 286 // This check is needed to ensure that the lookup into the ledger 287 // for the same TxID catches duplicates. 288 err = protoutil.CheckTxID( 289 chdr.TxId, 290 shdr.Nonce, 291 shdr.Creator) 292 293 if err != nil { 294 putilsLogger.Errorf("CheckTxID returns err %s", err) 295 return nil, pb.TxValidationCode_BAD_PROPOSAL_TXID 296 } 297 298 err = validateEndorserTransaction(payload.Data, payload.Header) 299 putilsLogger.Debugf("ValidateTransactionEnvelope returns err %s", err) 300 301 if err != nil { 302 putilsLogger.Errorf("validateEndorserTransaction returns err %s", err) 303 return payload, pb.TxValidationCode_INVALID_ENDORSER_TRANSACTION 304 } 305 return payload, pb.TxValidationCode_VALID 306 case common.HeaderType_CONFIG: 307 // Config transactions have signatures inside which will be validated, especially at genesis there may be no creator or 308 // signature on the outermost envelope 309 310 err = validateConfigTransaction(payload.Data, payload.Header) 311 312 if err != nil { 313 putilsLogger.Errorf("validateConfigTransaction returns err %s", err) 314 return payload, pb.TxValidationCode_INVALID_CONFIG_TRANSACTION 315 } 316 return payload, pb.TxValidationCode_VALID 317 default: 318 return nil, pb.TxValidationCode_UNSUPPORTED_TX_PAYLOAD 319 } 320 }