github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 "errors" 21 "fmt" 22 23 "github.com/hyperledger/fabric/bccsp" 24 "github.com/hyperledger/fabric/bccsp/factory" 25 "github.com/hyperledger/fabric/common/policies" 26 "github.com/hyperledger/fabric/gossip/api" 27 "github.com/hyperledger/fabric/gossip/common" 28 "github.com/hyperledger/fabric/msp" 29 "github.com/hyperledger/fabric/msp/mgmt" 30 protoscommon "github.com/hyperledger/fabric/protos/common" 31 "github.com/op/go-logging" 32 ) 33 34 var logger = logging.MustGetLogger("peer/gossip/mcs") 35 36 // mspMessageCryptoService implements the MessageCryptoService interface 37 // using the peer MSPs (local and channel-related) 38 // 39 // In order for the system to be secure it is vital to have the 40 // MSPs to be up-to-date. Channels' MSPs are updated via 41 // configuration transactions distributed by the ordering service. 42 // 43 // A similar mechanism needs to be in place to update the local MSP, as well. 44 // This implementation assumes that these mechanisms are all in place and working. 45 type mspMessageCryptoService struct { 46 manager policies.Manager 47 } 48 49 // New creates a new instance of mspMessageCryptoService 50 // that implements MessageCryptoService. 51 // The method takes in input a policy manager that gives 52 // access to the policy manager of a given channel via the Manager method. 53 // See fabric/core/peer/peer.go#NewPolicyManagerMgmt and 54 // fabric/common/mocks/policies/policies.go#PolicyManagerMgmt 55 func New(manager policies.Manager) api.MessageCryptoService { 56 return &mspMessageCryptoService{manager: manager} 57 } 58 59 // ValidateIdentity validates the identity of a remote peer. 60 // If the identity is invalid, revoked, expired it returns an error. 61 // Else, returns nil 62 func (s *mspMessageCryptoService) ValidateIdentity(peerIdentity api.PeerIdentityType) error { 63 // As prescibed by the contract of method, 64 // here we check only that peerIdentity is not 65 // invalid, revoked or expired. 66 67 _, _, err := s.getValidatedIdentity(peerIdentity) 68 return err 69 } 70 71 // GetPKIidOfCert returns the PKI-ID of a peer's identity 72 // If any error occurs, the method return nil 73 // The PKid of a peer is computed as the SHA2-256 of peerIdentity which 74 // is supposed to be the serialized version of MSP identity. 75 // This method does not validate peerIdentity. 76 // This validation is supposed to be done appropriately during the execution flow. 77 func (s *mspMessageCryptoService) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType { 78 // Validate arguments 79 if len(peerIdentity) == 0 { 80 logger.Error("Invalid Peer Identity. It must be different from nil.") 81 82 return nil 83 } 84 85 // Hash 86 digest, err := factory.GetDefault().Hash(peerIdentity, &bccsp.SHA256Opts{}) 87 if err != nil { 88 logger.Errorf("Failed computing digest of serialized identity [% x]: [%s]", peerIdentity, err) 89 90 return nil 91 } 92 93 return digest 94 } 95 96 // VerifyBlock returns nil if the block is properly signed, 97 // else returns error 98 func (s *mspMessageCryptoService) VerifyBlock(chainID common.ChainID, signedBlock api.SignedBlock) error { 99 // TODO: to be implemented 100 // Steps: 101 // 1. Check that the block is related to chainID 102 // 2. Verify that the block is properly signed 103 // using the policy associated to chainID 104 105 return nil 106 } 107 108 // Sign signs msg with this peer's signing key and outputs 109 // the signature if no error occurred. 110 func (s *mspMessageCryptoService) Sign(msg []byte) ([]byte, error) { 111 return mgmt.GetLocalSigningIdentityOrPanic().Sign(msg) 112 } 113 114 // Verify checks that signature is a valid signature of message under a peer's verification key. 115 // If the verification succeeded, Verify returns nil meaning no error occurred. 116 // If peerIdentity is nil, then the verification fails. 117 func (s *mspMessageCryptoService) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error { 118 identity, chainID, err := s.getValidatedIdentity(peerIdentity) 119 if err != nil { 120 logger.Errorf("Failed getting validated identity from peer identity [%s]", err) 121 122 return err 123 } 124 125 if len(chainID) == 0 { 126 // At this stage, this means that peerIdentity 127 // belongs to this peer's LocalMSP. 128 // The signature is validated directly 129 return identity.Verify(message, signature) 130 } 131 132 // At this stage, the signature must be validated 133 // against the reader policy of the channel 134 // identified by chainID 135 136 return s.VerifyByChannel(chainID, peerIdentity, signature, message) 137 } 138 139 // VerifyByChannel checks that signature is a valid signature of message 140 // under a peer's verification key, but also in the context of a specific channel. 141 // If the verification succeeded, Verify returns nil meaning no error occurred. 142 // If peerIdentity is nil, then the verification fails. 143 func (s *mspMessageCryptoService) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error { 144 // Validate arguments 145 if len(peerIdentity) == 0 { 146 return errors.New("Invalid Peer Identity. It must be different from nil.") 147 } 148 149 // Get the policy manager for channel chainID 150 cpm, flag := s.manager.Manager([]string{string(chainID)}) 151 logger.Debugf("Got policy manager for channel [%s] with flag [%s]", string(chainID), flag) 152 153 // Get channel reader policy 154 policy, flag := cpm.GetPolicy(policies.ChannelApplicationReaders) 155 logger.Debugf("Got reader policy for channel [%s] with flag [%s]", string(chainID), flag) 156 157 return policy.Evaluate( 158 []*protoscommon.SignedData{{ 159 Data: message, 160 Identity: []byte(peerIdentity), 161 Signature: signature, 162 }}, 163 ) 164 } 165 166 func (s *mspMessageCryptoService) getValidatedIdentity(peerIdentity api.PeerIdentityType) (msp.Identity, common.ChainID, error) { 167 // Validate arguments 168 if len(peerIdentity) == 0 { 169 return nil, nil, errors.New("Invalid Peer Identity. It must be different from nil.") 170 } 171 172 // Notice that peerIdentity is assumed to be the serialization of an identity. 173 // So, first step is the identity deserialization and then verify it. 174 175 // First check against the local MSP. 176 // If the peerIdentity is in the same organization of this node then 177 // the local MSP is required to take the final decision on the validity 178 // of the signature. 179 identity, err := mgmt.GetLocalMSP().DeserializeIdentity([]byte(peerIdentity)) 180 if err != nil { 181 // peerIdentity is NOT in the same organization of this node 182 logger.Debugf("LocalMSP failed deserializing peer identity [% x]: [%s]", []byte(peerIdentity), err) 183 } else { 184 // TODO: The following check will be replaced by a check on the organizational units 185 // when we allow the gossip network to have organization unit (MSP subdivisions) 186 // scoped messages. 187 // The following check is consistent with the SecurityAdvisor#OrgByPeerIdentity 188 // implementation. 189 // TODO: Notice that the following check saves us from the fact 190 // that DeserializeIdentity does not yet enforce MSP-IDs consistency. 191 // This check can be removed once DeserializeIdentity will be fixed. 192 if identity.GetMSPIdentifier() == mgmt.GetLocalSigningIdentityOrPanic().GetMSPIdentifier() { 193 // Check identity validity 194 195 // Notice that at this stage we don't have to check the identity 196 // against any channel's policies. 197 // This will be done by the caller function, if needed. 198 return identity, nil, identity.Validate() 199 } 200 } 201 202 // Check against managers 203 for chainID, mspManager := range mgmt.GetManagers() { 204 // Deserialize identity 205 identity, err := mspManager.DeserializeIdentity([]byte(peerIdentity)) 206 if err != nil { 207 logger.Debugf("Failed deserialization identity [% x] on [%s]: [%s]", peerIdentity, chainID, err) 208 continue 209 } 210 211 // Check identity validity 212 // Notice that at this stage we don't have to check the identity 213 // against any channel's policies. 214 // This will be done by the caller function, if needed. 215 216 if err := identity.Validate(); err != nil { 217 logger.Debugf("Failed validating identity [% x] on [%s]: [%s]", peerIdentity, chainID, err) 218 continue 219 } 220 221 logger.Debugf("Validation succesed [% x] on [%s]", peerIdentity, chainID) 222 223 return identity, common.ChainID(chainID), nil 224 } 225 226 return nil, nil, fmt.Errorf("Peer Identity [% x] cannot be validated. No MSP found able to do that.", peerIdentity) 227 }