github.com/ewagmig/fabric@v2.1.1+incompatible/gossip/protoext/signing.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package protoext
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hyperledger/fabric-protos-go/gossip"
    15  )
    16  
    17  // Signer signs a message, and returns (signature, nil)
    18  // on success, and nil and an error on failure.
    19  type Signer func(msg []byte) ([]byte, error)
    20  
    21  // Verifier receives a peer identity, a signature and a message and returns nil
    22  // if the signature on the message could be verified using the given identity.
    23  type Verifier func(peerIdentity []byte, signature, message []byte) error
    24  
    25  // SignSecret signs the secret payload and creates a secret envelope out of it.
    26  func SignSecret(e *gossip.Envelope, signer Signer, secret *gossip.Secret) error {
    27  	payload, err := proto.Marshal(secret)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	sig, err := signer(payload)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	e.SecretEnvelope = &gossip.SecretEnvelope{
    36  		Payload:   payload,
    37  		Signature: sig,
    38  	}
    39  	return nil
    40  }
    41  
    42  // NoopSign creates a SignedGossipMessage with a nil signature
    43  func NoopSign(m *gossip.GossipMessage) (*SignedGossipMessage, error) {
    44  	signer := func(msg []byte) ([]byte, error) {
    45  		return nil, nil
    46  	}
    47  	sMsg := &SignedGossipMessage{
    48  		GossipMessage: m,
    49  	}
    50  	_, err := sMsg.Sign(signer)
    51  	return sMsg, err
    52  }
    53  
    54  // EnvelopeToGossipMessage un-marshals a given envelope and creates a
    55  // SignedGossipMessage out of it.
    56  // Returns an error if un-marshaling fails.
    57  func EnvelopeToGossipMessage(e *gossip.Envelope) (*SignedGossipMessage, error) {
    58  	if e == nil {
    59  		return nil, errors.New("nil envelope")
    60  	}
    61  	msg := &gossip.GossipMessage{}
    62  	err := proto.Unmarshal(e.Payload, msg)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("Failed unmarshaling GossipMessage from envelope: %v", err)
    65  	}
    66  	return &SignedGossipMessage{
    67  		GossipMessage: msg,
    68  		Envelope:      e,
    69  	}, nil
    70  }
    71  
    72  // InternalEndpoint returns the internal endpoint in the secret envelope, or an
    73  // empty string if a failure occurs.
    74  func InternalEndpoint(s *gossip.SecretEnvelope) string {
    75  	if s == nil {
    76  		return ""
    77  	}
    78  	secret := &gossip.Secret{}
    79  	if err := proto.Unmarshal(s.Payload, secret); err != nil {
    80  		return ""
    81  	}
    82  	return secret.GetInternalEndpoint()
    83  }
    84  
    85  // SignedGossipMessage contains a GossipMessage and the Envelope from which it
    86  // came from
    87  type SignedGossipMessage struct {
    88  	*gossip.Envelope
    89  	*gossip.GossipMessage
    90  }
    91  
    92  // Sign signs a GossipMessage with given Signer.
    93  // Returns an Envelope on success, panics on failure.
    94  func (m *SignedGossipMessage) Sign(signer Signer) (*gossip.Envelope, error) {
    95  	// If we have a secretEnvelope, don't override it.
    96  	// Back it up, and restore it later
    97  	var secretEnvelope *gossip.SecretEnvelope
    98  	if m.Envelope != nil {
    99  		secretEnvelope = m.Envelope.SecretEnvelope
   100  	}
   101  	m.Envelope = nil
   102  	payload, err := proto.Marshal(m.GossipMessage)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	sig, err := signer(payload)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	e := &gossip.Envelope{
   112  		Payload:        payload,
   113  		Signature:      sig,
   114  		SecretEnvelope: secretEnvelope,
   115  	}
   116  	m.Envelope = e
   117  	return e, nil
   118  }
   119  
   120  // Verify verifies a signed GossipMessage with a given Verifier.
   121  // Returns nil on success, error on failure.
   122  func (m *SignedGossipMessage) Verify(peerIdentity []byte, verify Verifier) error {
   123  	if m.Envelope == nil {
   124  		return errors.New("Missing envelope")
   125  	}
   126  	if len(m.Envelope.Payload) == 0 {
   127  		return errors.New("Empty payload")
   128  	}
   129  	if len(m.Envelope.Signature) == 0 {
   130  		return errors.New("Empty signature")
   131  	}
   132  	payloadSigVerificationErr := verify(peerIdentity, m.Envelope.Signature, m.Envelope.Payload)
   133  	if payloadSigVerificationErr != nil {
   134  		return payloadSigVerificationErr
   135  	}
   136  	if m.Envelope.SecretEnvelope != nil {
   137  		payload := m.Envelope.SecretEnvelope.Payload
   138  		sig := m.Envelope.SecretEnvelope.Signature
   139  		if len(payload) == 0 {
   140  			return errors.New("Empty payload")
   141  		}
   142  		if len(sig) == 0 {
   143  			return errors.New("Empty signature")
   144  		}
   145  		return verify(peerIdentity, sig, payload)
   146  	}
   147  	return nil
   148  }
   149  
   150  // IsSigned returns whether the message
   151  // has a signature in the envelope.
   152  func (m *SignedGossipMessage) IsSigned() bool {
   153  	return m.Envelope != nil && m.Envelope.Payload != nil && m.Envelope.Signature != nil
   154  }
   155  
   156  // String returns a string representation
   157  // of a SignedGossipMessage
   158  func (m *SignedGossipMessage) String() string {
   159  	env := "No envelope"
   160  	if m.Envelope != nil {
   161  		var secretEnv string
   162  		if m.SecretEnvelope != nil {
   163  			pl := len(m.SecretEnvelope.Payload)
   164  			sl := len(m.SecretEnvelope.Signature)
   165  			secretEnv = fmt.Sprintf(" Secret payload: %d bytes, Secret Signature: %d bytes", pl, sl)
   166  		}
   167  		env = fmt.Sprintf("%d bytes, Signature: %d bytes%s", len(m.Envelope.Payload), len(m.Envelope.Signature), secretEnv)
   168  	}
   169  	gMsg := "No gossipMessage"
   170  	if m.GossipMessage != nil {
   171  		var isSimpleMsg bool
   172  		if m.GetStateResponse() != nil {
   173  			gMsg = fmt.Sprintf("StateResponse with %d items", len(m.GetStateResponse().Payloads))
   174  		} else if IsDataMsg(m.GossipMessage) && m.GetDataMsg().Payload != nil {
   175  			gMsg = PayloadToString(m.GetDataMsg().Payload)
   176  		} else if IsDataUpdate(m.GossipMessage) {
   177  			update := m.GetDataUpdate()
   178  			gMsg = fmt.Sprintf("DataUpdate: %s", DataUpdateToString(update))
   179  		} else if m.GetMemRes() != nil {
   180  			gMsg = MembershipResponseToString(m.GetMemRes())
   181  		} else if IsStateInfoSnapshot(m.GossipMessage) {
   182  			gMsg = StateInfoSnapshotToString(m.GetStateSnapshot())
   183  		} else if m.GetPrivateRes() != nil {
   184  			gMsg = RemovePvtDataResponseToString(m.GetPrivateRes())
   185  		} else if m.GetAliveMsg() != nil {
   186  			gMsg = AliveMessageToString(m.GetAliveMsg())
   187  		} else if m.GetMemReq() != nil {
   188  			gMsg = MembershipRequestToString(m.GetMemReq())
   189  		} else if m.GetStateInfoPullReq() != nil {
   190  			gMsg = StateInfoPullRequestToString(m.GetStateInfoPullReq())
   191  		} else if m.GetStateInfo() != nil {
   192  			gMsg = StateInfoToString(m.GetStateInfo())
   193  		} else if m.GetDataDig() != nil {
   194  			gMsg = DataDigestToString(m.GetDataDig())
   195  		} else if m.GetDataReq() != nil {
   196  			gMsg = DataRequestToString(m.GetDataReq())
   197  		} else if m.GetLeadershipMsg() != nil {
   198  			gMsg = LeadershipMessageToString(m.GetLeadershipMsg())
   199  		} else {
   200  			gMsg = m.GossipMessage.String()
   201  			isSimpleMsg = true
   202  		}
   203  		if !isSimpleMsg {
   204  			desc := fmt.Sprintf("Channel: %s, nonce: %d, tag: %s", string(m.Channel), m.Nonce, gossip.GossipMessage_Tag_name[int32(m.Tag)])
   205  			gMsg = fmt.Sprintf("%s %s", desc, gMsg)
   206  		}
   207  	}
   208  	return fmt.Sprintf("GossipMessage: %v, Envelope: %s", gMsg, env)
   209  }