github.com/defanghe/fabric@v2.1.1+incompatible/internal/peer/gossip/mcs.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package gossip 8 9 import ( 10 "bytes" 11 "fmt" 12 "time" 13 14 pcommon "github.com/hyperledger/fabric-protos-go/common" 15 "github.com/hyperledger/fabric/bccsp" 16 "github.com/hyperledger/fabric/common/flogging" 17 "github.com/hyperledger/fabric/common/policies" 18 "github.com/hyperledger/fabric/common/util" 19 "github.com/hyperledger/fabric/gossip/api" 20 "github.com/hyperledger/fabric/gossip/common" 21 "github.com/hyperledger/fabric/internal/pkg/identity" 22 "github.com/hyperledger/fabric/msp" 23 "github.com/hyperledger/fabric/msp/mgmt" 24 "github.com/hyperledger/fabric/protoutil" 25 "github.com/pkg/errors" 26 ) 27 28 var mcsLogger = flogging.MustGetLogger("peer.gossip.mcs") 29 30 // Hasher is the interface provides the hash function should be used for all gossip components. 31 type Hasher interface { 32 Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) 33 } 34 35 // MSPMessageCryptoService implements the MessageCryptoService interface 36 // using the peer MSPs (local and channel-related) 37 // 38 // In order for the system to be secure it is vital to have the 39 // MSPs to be up-to-date. Channels' MSPs are updated via 40 // configuration transactions distributed by the ordering service. 41 // 42 // A similar mechanism needs to be in place to update the local MSP, as well. 43 // This implementation assumes that these mechanisms are all in place and working. 44 type MSPMessageCryptoService struct { 45 channelPolicyManagerGetter policies.ChannelPolicyManagerGetter 46 localSigner identity.SignerSerializer 47 deserializer mgmt.DeserializersManager 48 hasher Hasher 49 } 50 51 // NewMCS creates a new instance of MSPMessageCryptoService 52 // that implements MessageCryptoService. 53 // The method takes in input: 54 // 1. a policies.ChannelPolicyManagerGetter that gives access to the policy manager of a given channel via the Manager method. 55 // 2. an instance of identity.SignerSerializer 56 // 3. an identity deserializer manager 57 func NewMCS( 58 channelPolicyManagerGetter policies.ChannelPolicyManagerGetter, 59 localSigner identity.SignerSerializer, 60 deserializer mgmt.DeserializersManager, 61 hasher Hasher, 62 ) *MSPMessageCryptoService { 63 return &MSPMessageCryptoService{ 64 channelPolicyManagerGetter: channelPolicyManagerGetter, 65 localSigner: localSigner, 66 deserializer: deserializer, 67 hasher: hasher, 68 } 69 } 70 71 // ValidateIdentity validates the identity of a remote peer. 72 // If the identity is invalid, revoked, expired it returns an error. 73 // Else, returns nil 74 func (s *MSPMessageCryptoService) ValidateIdentity(peerIdentity api.PeerIdentityType) error { 75 // As prescribed by the contract of method, 76 // below we check only that peerIdentity is not 77 // invalid, revoked or expired. 78 79 _, _, err := s.getValidatedIdentity(peerIdentity) 80 return err 81 } 82 83 // GetPKIidOfCert returns the PKI-ID of a peer's identity 84 // If any error occurs, the method return nil 85 // The PKid of a peer is computed as the SHA2-256 of peerIdentity which 86 // is supposed to be the serialized version of MSP identity. 87 // This method does not validate peerIdentity. 88 // This validation is supposed to be done appropriately during the execution flow. 89 func (s *MSPMessageCryptoService) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType { 90 // Validate arguments 91 if len(peerIdentity) == 0 { 92 mcsLogger.Error("Invalid Peer Identity. It must be different from nil.") 93 94 return nil 95 } 96 97 sid, err := s.deserializer.Deserialize(peerIdentity) 98 if err != nil { 99 mcsLogger.Errorf("Failed getting validated identity from peer identity %s: [%s]", peerIdentity, err) 100 101 return nil 102 } 103 104 // concatenate msp-id and idbytes 105 // idbytes is the low-level representation of an identity. 106 // it is supposed to be already in its minimal representation 107 108 mspIDRaw := []byte(sid.Mspid) 109 raw := append(mspIDRaw, sid.IdBytes...) 110 111 // Hash 112 digest, err := s.hasher.Hash(raw, &bccsp.SHA256Opts{}) 113 if err != nil { 114 mcsLogger.Errorf("Failed computing digest of serialized identity %s: [%s]", peerIdentity, err) 115 return nil 116 } 117 118 return digest 119 } 120 121 // VerifyBlock returns nil if the block is properly signed, and the claimed seqNum is the 122 // sequence number that the block's header contains. 123 // else returns error 124 func (s *MSPMessageCryptoService) VerifyBlock(chainID common.ChannelID, seqNum uint64, block *pcommon.Block) error { 125 if block.Header == nil { 126 return fmt.Errorf("Invalid Block on channel [%s]. Header must be different from nil.", chainID) 127 } 128 129 blockSeqNum := block.Header.Number 130 if seqNum != blockSeqNum { 131 return fmt.Errorf("Claimed seqNum is [%d] but actual seqNum inside block is [%d]", seqNum, blockSeqNum) 132 } 133 134 // - Extract channelID and compare with chainID 135 channelID, err := protoutil.GetChainIDFromBlock(block) 136 if err != nil { 137 return fmt.Errorf("Failed getting channel id from block with id [%d] on channel [%s]: [%s]", block.Header.Number, chainID, err) 138 } 139 140 if channelID != string(chainID) { 141 return fmt.Errorf("Invalid block's channel id. Expected [%s]. Given [%s]", chainID, channelID) 142 } 143 144 // - Unmarshal medatada 145 if block.Metadata == nil || len(block.Metadata.Metadata) == 0 { 146 return fmt.Errorf("Block with id [%d] on channel [%s] does not have metadata. Block not valid.", block.Header.Number, chainID) 147 } 148 149 metadata, err := protoutil.GetMetadataFromBlock(block, pcommon.BlockMetadataIndex_SIGNATURES) 150 if err != nil { 151 return fmt.Errorf("Failed unmarshalling medatata for signatures [%s]", err) 152 } 153 154 // - Verify that Header.DataHash is equal to the hash of block.Data 155 // This is to ensure that the header is consistent with the data carried by this block 156 if !bytes.Equal(protoutil.BlockDataHash(block.Data), block.Header.DataHash) { 157 return fmt.Errorf("Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]", block.Header.Number, chainID) 158 } 159 160 // - Get Policy for block validation 161 162 // Get the policy manager for channelID 163 cpm := s.channelPolicyManagerGetter.Manager(channelID) 164 if cpm == nil { 165 return fmt.Errorf("Could not acquire policy manager for channel %s", channelID) 166 } 167 mcsLogger.Debugf("Got policy manager for channel [%s]", channelID) 168 169 // Get block validation policy 170 policy, ok := cpm.GetPolicy(policies.BlockValidation) 171 // ok is true if it was the policy requested, or false if it is the default policy 172 mcsLogger.Debugf("Got block validation policy for channel [%s] with flag [%t]", channelID, ok) 173 174 // - Prepare SignedData 175 signatureSet := []*protoutil.SignedData{} 176 for _, metadataSignature := range metadata.Signatures { 177 shdr, err := protoutil.UnmarshalSignatureHeader(metadataSignature.SignatureHeader) 178 if err != nil { 179 return fmt.Errorf("Failed unmarshalling signature header for block with id [%d] on channel [%s]: [%s]", block.Header.Number, chainID, err) 180 } 181 signatureSet = append( 182 signatureSet, 183 &protoutil.SignedData{ 184 Identity: shdr.Creator, 185 Data: util.ConcatenateBytes(metadata.Value, metadataSignature.SignatureHeader, protoutil.BlockHeaderBytes(block.Header)), 186 Signature: metadataSignature.Signature, 187 }, 188 ) 189 } 190 191 // - Evaluate policy 192 return policy.EvaluateSignedData(signatureSet) 193 } 194 195 // Sign signs msg with this peer's signing key and outputs 196 // the signature if no error occurred. 197 func (s *MSPMessageCryptoService) Sign(msg []byte) ([]byte, error) { 198 return s.localSigner.Sign(msg) 199 } 200 201 // Verify checks that signature is a valid signature of message under a peer's verification key. 202 // If the verification succeeded, Verify returns nil meaning no error occurred. 203 // If peerIdentity is nil, then the verification fails. 204 func (s *MSPMessageCryptoService) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error { 205 identity, chainID, err := s.getValidatedIdentity(peerIdentity) 206 if err != nil { 207 mcsLogger.Errorf("Failed getting validated identity from peer identity [%s]", err) 208 209 return err 210 } 211 212 if len(chainID) == 0 { 213 // At this stage, this means that peerIdentity 214 // belongs to this peer's LocalMSP. 215 // The signature is validated directly 216 return identity.Verify(message, signature) 217 } 218 219 // At this stage, the signature must be validated 220 // against the reader policy of the channel 221 // identified by chainID 222 223 return s.VerifyByChannel(chainID, peerIdentity, signature, message) 224 } 225 226 // VerifyByChannel checks that signature is a valid signature of message 227 // under a peer's verification key, but also in the context of a specific channel. 228 // If the verification succeeded, Verify returns nil meaning no error occurred. 229 // If peerIdentity is nil, then the verification fails. 230 func (s *MSPMessageCryptoService) VerifyByChannel(chainID common.ChannelID, peerIdentity api.PeerIdentityType, signature, message []byte) error { 231 // Validate arguments 232 if len(peerIdentity) == 0 { 233 return errors.New("Invalid Peer Identity. It must be different from nil.") 234 } 235 236 // Get the policy manager for channel chainID 237 cpm := s.channelPolicyManagerGetter.Manager(string(chainID)) 238 if cpm == nil { 239 return fmt.Errorf("Could not acquire policy manager for channel %s", string(chainID)) 240 } 241 mcsLogger.Debugf("Got policy manager for channel [%s]", string(chainID)) 242 243 // Get channel reader policy 244 policy, flag := cpm.GetPolicy(policies.ChannelApplicationReaders) 245 mcsLogger.Debugf("Got reader policy for channel [%s] with flag [%t]", string(chainID), flag) 246 247 return policy.EvaluateSignedData( 248 []*protoutil.SignedData{{ 249 Data: message, 250 Identity: []byte(peerIdentity), 251 Signature: signature, 252 }}, 253 ) 254 } 255 256 func (s *MSPMessageCryptoService) Expiration(peerIdentity api.PeerIdentityType) (time.Time, error) { 257 id, _, err := s.getValidatedIdentity(peerIdentity) 258 if err != nil { 259 return time.Time{}, errors.Wrap(err, "Unable to extract msp.Identity from peer Identity") 260 } 261 return id.ExpiresAt(), nil 262 263 } 264 265 func (s *MSPMessageCryptoService) getValidatedIdentity(peerIdentity api.PeerIdentityType) (msp.Identity, common.ChannelID, error) { 266 // Validate arguments 267 if len(peerIdentity) == 0 { 268 return nil, nil, errors.New("Invalid Peer Identity. It must be different from nil.") 269 } 270 271 sId, err := s.deserializer.Deserialize(peerIdentity) 272 if err != nil { 273 mcsLogger.Error("failed deserializing identity", err) 274 return nil, nil, err 275 } 276 277 // Notice that peerIdentity is assumed to be the serialization of an identity. 278 // So, first step is the identity deserialization and then verify it. 279 280 // First check against the local MSP. 281 // If the peerIdentity is in the same organization of this node then 282 // the local MSP is required to take the final decision on the validity 283 // of the signature. 284 lDes := s.deserializer.GetLocalDeserializer() 285 identity, err := lDes.DeserializeIdentity([]byte(peerIdentity)) 286 if err == nil { 287 // No error means that the local MSP successfully deserialized the identity. 288 // We now check additional properties. 289 if err := lDes.IsWellFormed(sId); err != nil { 290 return nil, nil, errors.Wrap(err, "identity is not well formed") 291 } 292 // TODO: The following check will be replaced by a check on the organizational units 293 // when we allow the gossip network to have organization unit (MSP subdivisions) 294 // scoped messages. 295 // The following check is consistent with the SecurityAdvisor#OrgByPeerIdentity 296 // implementation. 297 // TODO: Notice that the following check saves us from the fact 298 // that DeserializeIdentity does not yet enforce MSP-IDs consistency. 299 // This check can be removed once DeserializeIdentity will be fixed. 300 if identity.GetMSPIdentifier() == s.deserializer.GetLocalMSPIdentifier() { 301 // Check identity validity 302 303 // Notice that at this stage we don't have to check the identity 304 // against any channel's policies. 305 // This will be done by the caller function, if needed. 306 return identity, nil, identity.Validate() 307 } 308 } 309 310 // Check against managers 311 for chainID, mspManager := range s.deserializer.GetChannelDeserializers() { 312 // Deserialize identity 313 identity, err := mspManager.DeserializeIdentity([]byte(peerIdentity)) 314 if err != nil { 315 mcsLogger.Debugf("Failed deserialization identity %s on [%s]: [%s]", peerIdentity, chainID, err) 316 continue 317 } 318 319 // We managed deserializing the identity with this MSP manager. Now we check if it's well formed. 320 if err := mspManager.IsWellFormed(sId); err != nil { 321 return nil, nil, errors.Wrap(err, "identity is not well formed") 322 } 323 324 // Check identity validity 325 // Notice that at this stage we don't have to check the identity 326 // against any channel's policies. 327 // This will be done by the caller function, if needed. 328 329 if err := identity.Validate(); err != nil { 330 mcsLogger.Debugf("Failed validating identity %s on [%s]: [%s]", peerIdentity, chainID, err) 331 continue 332 } 333 334 mcsLogger.Debugf("Validation succeeded %s on [%s]", peerIdentity, chainID) 335 336 return identity, common.ChannelID(chainID), nil 337 } 338 339 return nil, nil, fmt.Errorf("Peer Identity %s cannot be validated. No MSP found able to do that.", peerIdentity) 340 }