github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/peer/gossip/mcs/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 mcs 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 logger = 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 // New 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 New(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 logger.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 logger.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 logger.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, 117 // else returns error 118 func (s *mspMessageCryptoService) VerifyBlock(chainID common.ChainID, signedBlock []byte) error { 119 // - Convert signedBlock to common.Block. 120 block, err := utils.GetBlockFromBlockBytes(signedBlock) 121 if err != nil { 122 return fmt.Errorf("Failed unmarshalling block bytes on channel [%s]: [%s]", chainID, err) 123 } 124 125 if block.Header == nil { 126 return fmt.Errorf("Invalid Block on channel [%s]. Header must be different from nil.", chainID) 127 } 128 129 // - Extract channelID and compare with chainID 130 channelID, err := utils.GetChainIDFromBlock(block) 131 if err != nil { 132 return fmt.Errorf("Failed getting channel id from block with id [%d] on channel [%s]: [%s]", block.Header.Number, chainID, err) 133 } 134 135 if channelID != string(chainID) { 136 return fmt.Errorf("Invalid block's channel id. Expected [%s]. Given [%s]", chainID, channelID) 137 } 138 139 // - Unmarshal medatada 140 if block.Metadata == nil || len(block.Metadata.Metadata) == 0 { 141 return fmt.Errorf("Block with id [%d] on channel [%s] does not have metadata. Block not valid.", block.Header.Number, chainID) 142 } 143 144 metadata, err := utils.GetMetadataFromBlock(block, pcommon.BlockMetadataIndex_SIGNATURES) 145 if err != nil { 146 return fmt.Errorf("Failed unmarshalling medatata for signatures [%s]", err) 147 } 148 149 // - Verify that Header.DataHash is equal to the hash of block.Data 150 // This is to ensure that the header is consistent with the data carried by this block 151 if !bytes.Equal(block.Data.Hash(), block.Header.DataHash) { 152 return fmt.Errorf("Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]", block.Header.Number, chainID) 153 } 154 155 // - Get Policy for block validation 156 157 // Get the policy manager for channelID 158 cpm, ok := s.channelPolicyManagerGetter.Manager(channelID) 159 if cpm == nil { 160 return fmt.Errorf("Could not acquire policy manager for channel %s", channelID) 161 } 162 // ok is true if it was the manager requested, or false if it is the default manager 163 logger.Debugf("Got policy manager for channel [%s] with flag [%s]", channelID, ok) 164 165 // Get block validation policy 166 policy, ok := cpm.GetPolicy(policies.BlockValidation) 167 // ok is true if it was the policy requested, or false if it is the default policy 168 logger.Debugf("Got block validation policy for channel [%s] with flag [%s]", channelID, ok) 169 170 // - Prepare SignedData 171 signatureSet := []*pcommon.SignedData{} 172 for _, metadataSignature := range metadata.Signatures { 173 shdr, err := utils.GetSignatureHeader(metadataSignature.SignatureHeader) 174 if err != nil { 175 return fmt.Errorf("Failed unmarshalling signature header for block with id [%d] on channel [%s]: [%s]", block.Header.Number, chainID, err) 176 } 177 signatureSet = append( 178 signatureSet, 179 &pcommon.SignedData{ 180 Identity: shdr.Creator, 181 Data: util.ConcatenateBytes(metadata.Value, metadataSignature.SignatureHeader, block.Header.Bytes()), 182 Signature: metadataSignature.Signature, 183 }, 184 ) 185 } 186 187 // - Evaluate policy 188 return policy.Evaluate(signatureSet) 189 } 190 191 // Sign signs msg with this peer's signing key and outputs 192 // the signature if no error occurred. 193 func (s *mspMessageCryptoService) Sign(msg []byte) ([]byte, error) { 194 return s.localSigner.Sign(msg) 195 } 196 197 // Verify checks that signature is a valid signature of message under a peer's verification key. 198 // If the verification succeeded, Verify returns nil meaning no error occurred. 199 // If peerIdentity is nil, then the verification fails. 200 func (s *mspMessageCryptoService) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error { 201 identity, chainID, err := s.getValidatedIdentity(peerIdentity) 202 if err != nil { 203 logger.Errorf("Failed getting validated identity from peer identity [%s]", err) 204 205 return err 206 } 207 208 if len(chainID) == 0 { 209 // At this stage, this means that peerIdentity 210 // belongs to this peer's LocalMSP. 211 // The signature is validated directly 212 return identity.Verify(message, signature) 213 } 214 215 // At this stage, the signature must be validated 216 // against the reader policy of the channel 217 // identified by chainID 218 219 return s.VerifyByChannel(chainID, peerIdentity, signature, message) 220 } 221 222 // VerifyByChannel checks that signature is a valid signature of message 223 // under a peer's verification key, but also in the context of a specific channel. 224 // If the verification succeeded, Verify returns nil meaning no error occurred. 225 // If peerIdentity is nil, then the verification fails. 226 func (s *mspMessageCryptoService) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error { 227 // Validate arguments 228 if len(peerIdentity) == 0 { 229 return errors.New("Invalid Peer Identity. It must be different from nil.") 230 } 231 232 // Get the policy manager for channel chainID 233 cpm, flag := s.channelPolicyManagerGetter.Manager(string(chainID)) 234 if cpm == nil { 235 return fmt.Errorf("Could not acquire policy manager for channel %s", string(chainID)) 236 } 237 logger.Debugf("Got policy manager for channel [%s] with flag [%s]", string(chainID), flag) 238 239 // Get channel reader policy 240 policy, flag := cpm.GetPolicy(policies.ChannelApplicationReaders) 241 logger.Debugf("Got reader policy for channel [%s] with flag [%s]", string(chainID), flag) 242 243 return policy.Evaluate( 244 []*pcommon.SignedData{{ 245 Data: message, 246 Identity: []byte(peerIdentity), 247 Signature: signature, 248 }}, 249 ) 250 } 251 252 func (s *mspMessageCryptoService) getValidatedIdentity(peerIdentity api.PeerIdentityType) (msp.Identity, common.ChainID, error) { 253 // Validate arguments 254 if len(peerIdentity) == 0 { 255 return nil, nil, errors.New("Invalid Peer Identity. It must be different from nil.") 256 } 257 258 // Notice that peerIdentity is assumed to be the serialization of an identity. 259 // So, first step is the identity deserialization and then verify it. 260 261 // First check against the local MSP. 262 // If the peerIdentity is in the same organization of this node then 263 // the local MSP is required to take the final decision on the validity 264 // of the signature. 265 identity, err := s.deserializer.GetLocalDeserializer().DeserializeIdentity([]byte(peerIdentity)) 266 if err == nil { 267 // No error means that the local MSP successfully deserialized the identity. 268 // We now check additional properties. 269 270 // TODO: The following check will be replaced by a check on the organizational units 271 // when we allow the gossip network to have organization unit (MSP subdivisions) 272 // scoped messages. 273 // The following check is consistent with the SecurityAdvisor#OrgByPeerIdentity 274 // implementation. 275 // TODO: Notice that the following check saves us from the fact 276 // that DeserializeIdentity does not yet enforce MSP-IDs consistency. 277 // This check can be removed once DeserializeIdentity will be fixed. 278 if identity.GetMSPIdentifier() == s.deserializer.GetLocalMSPIdentifier() { 279 // Check identity validity 280 281 // Notice that at this stage we don't have to check the identity 282 // against any channel's policies. 283 // This will be done by the caller function, if needed. 284 return identity, nil, identity.Validate() 285 } 286 } 287 288 // Check against managers 289 for chainID, mspManager := range s.deserializer.GetChannelDeserializers() { 290 // Deserialize identity 291 identity, err := mspManager.DeserializeIdentity([]byte(peerIdentity)) 292 if err != nil { 293 logger.Debugf("Failed deserialization identity [% x] on [%s]: [%s]", peerIdentity, chainID, err) 294 continue 295 } 296 297 // Check identity validity 298 // Notice that at this stage we don't have to check the identity 299 // against any channel's policies. 300 // This will be done by the caller function, if needed. 301 302 if err := identity.Validate(); err != nil { 303 logger.Debugf("Failed validating identity [% x] on [%s]: [%s]", peerIdentity, chainID, err) 304 continue 305 } 306 307 logger.Debugf("Validation succeeded [% x] on [%s]", peerIdentity, chainID) 308 309 return identity, common.ChainID(chainID), nil 310 } 311 312 return nil, nil, fmt.Errorf("Peer Identity [% x] cannot be validated. No MSP found able to do that.", peerIdentity) 313 }