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)