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  }