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