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  }