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