github.com/aergoio/aergo@v1.3.1/p2p/signature.go (about)

     1  /**
     2   *  @file
     3   *  @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package p2p
     7  
     8  import (
     9  	"fmt"
    10  	"github.com/aergoio/aergo/p2p/p2pcommon"
    11  	"github.com/aergoio/aergo/types"
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/libp2p/go-libp2p-core/crypto"
    14  )
    15  
    16  type defaultMsgSigner struct {
    17  	selfPeerID types.PeerID
    18  	privateKey crypto.PrivKey
    19  	pubKey     crypto.PubKey
    20  
    21  	pidBytes    []byte
    22  	pubKeyBytes []byte
    23  }
    24  
    25  func newDefaultMsgSigner(privKey crypto.PrivKey, pubKey crypto.PubKey, peerID types.PeerID) p2pcommon.MsgSigner {
    26  	pidBytes := []byte(peerID)
    27  	pubKeyBytes, _ := pubKey.Bytes()
    28  	return &defaultMsgSigner{selfPeerID: peerID, privateKey: privKey, pubKey: pubKey, pidBytes: pidBytes, pubKeyBytes: pubKeyBytes}
    29  }
    30  
    31  // sign an outgoing p2p message payload
    32  func (pm *defaultMsgSigner) SignMsg(message *types.P2PMessage) error {
    33  	// TODO this code modify caller's parameter.
    34  	message.Header.PeerID = pm.pidBytes
    35  	message.Header.NodePubKey = pm.pubKeyBytes
    36  	data, err := proto.Marshal(&types.P2PMessage{Header: canonicalizeHeader(message.Header), Data: message.Data})
    37  	if err != nil {
    38  		return err
    39  	}
    40  	signature, err := pm.signBytes(data)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	message.Header.Sign = signature
    45  	return nil
    46  }
    47  
    48  func canonicalizeHeader(src *types.MsgHeader) *types.MsgHeader {
    49  	// copy fields excluding generated fields and signature itself
    50  	return &types.MsgHeader{
    51  		ClientVersion: src.ClientVersion,
    52  		Gossip:        src.Gossip,
    53  		Id:            src.Id,
    54  		Length:        src.Length,
    55  		NodePubKey:    src.NodePubKey,
    56  		PeerID:        src.PeerID,
    57  		Sign:          nil,
    58  		Subprotocol:   src.Subprotocol,
    59  		Timestamp:     src.Timestamp,
    60  	}
    61  }
    62  
    63  // sign binary data using the local node's private key
    64  func (pm *defaultMsgSigner) signBytes(data []byte) ([]byte, error) {
    65  	key := pm.privateKey
    66  	res, err := key.Sign(data)
    67  	return res, err
    68  }
    69  
    70  func (pm *defaultMsgSigner) VerifyMsg(msg *types.P2PMessage, senderID types.PeerID) error {
    71  	// check signature
    72  	pubKey, err := crypto.UnmarshalPublicKey(msg.Header.NodePubKey)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	signature := msg.Header.Sign
    77  	checkOrigin := false
    78  	if checkOrigin {
    79  		// TODO it can be needed, and if that modify code to get peer id from caller and enable this code
    80  		if err := checkPidWithPubkey(senderID, pubKey); err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	data, _ := proto.Marshal(&types.P2PMessage{Header: canonicalizeHeader(msg.Header), Data: msg.Data})
    86  	return verifyBytes(data, signature, pubKey)
    87  }
    88  
    89  func checkPidWithPubkey(peerID types.PeerID, pubKey crypto.PubKey) error {
    90  	// extract node peerID from the provided public key
    91  	idFromKey, err := types.IDFromPublicKey(pubKey)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	// verify that message author node PeerID matches the provided node public key
    97  	if idFromKey != peerID {
    98  		return fmt.Errorf("PeerID mismatch")
    99  	}
   100  	return nil
   101  }
   102  
   103  // VerifyData Verifies incoming p2p message data integrity
   104  // data: data to verify
   105  // signature: author signature provided in the message payload
   106  // pubkey: author public key from the message payload
   107  func verifyBytes(data []byte, signature []byte, pubkey crypto.PubKey) error {
   108  	res, err := pubkey.Verify(data, signature)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if !res {
   113  		return fmt.Errorf("signature mismatch")
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  var dummyBytes = []byte{}
   120  
   121  type dummySigner struct{}
   122  
   123  func (d *dummySigner) SignMsg(msg *types.P2PMessage) error {
   124  	msg.Header.Sign = dummyBytes
   125  	return nil
   126  }
   127  
   128  func (d *dummySigner) VerifyMsg(msg *types.P2PMessage, senderID types.PeerID) error {
   129  	return nil
   130  }
   131  
   132  var _ p2pcommon.MsgSigner = (*dummySigner)(nil)