diff --git a/examples/multipro/echo.go b/examples/multipro/echo.go index b726e783..82c4185a 100644 --- a/examples/multipro/echo.go +++ b/examples/multipro/echo.go @@ -57,7 +57,7 @@ func (e *EchoProtocol) onEchoRequest(s inet.Stream) { // send response to the request using the message string he provided resp := &p2p.EchoResponse{ - MessageData: NewMessageData(e.node, data.MessageData.Id, false), + MessageData: e.node.NewMessageData(data.MessageData.Id, false), Message: data.Message} // sign the data @@ -121,7 +121,7 @@ func (e *EchoProtocol) Echo(host host.Host) bool { // create message data req := &p2p.EchoRequest{ - MessageData: NewMessageData(e.node, uuid.New().String(), false), + MessageData: e.node.NewMessageData(uuid.New().String(), false), Message: fmt.Sprintf("Echo from %s", e.node.ID())} signature, err := e.node.signProtoMessage(req) diff --git a/examples/multipro/node.go b/examples/multipro/node.go index 0d635708..2b7718a2 100644 --- a/examples/multipro/node.go +++ b/examples/multipro/node.go @@ -5,9 +5,9 @@ import ( "github.com/gogo/protobuf/proto" host "gx/ipfs/QmRS46AyqtpJBsf1zmQdeizSDEzo1qkWR7rdEuPFAv8237/go-libp2p-host" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" - crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" "log" + "time" ) // Node type - a p2p host implementing one or more p2p protocols @@ -18,7 +18,7 @@ type Node struct { // add other protocols here... } -// create a new node with its implemented protocols +// Create a new node with its implemented protocols func NewNode(host host.Host, done chan bool) *Node { node := &Node{Host: host} node.PingProtocol = NewPingProtocol(node, done) @@ -26,13 +26,16 @@ func NewNode(host host.Host, done chan bool) *Node { return node } +// Authenticate incoming p2p message +// message: a protobufs go data object +// data: common p2p message data func (n *Node) authenticateMessage(message proto.Message, data *p2p.MessageData) bool { - // store a temp ref to sig and remove it from data + // store a temp ref to signature and remove it from message data sign := data.Sign data.Sign = "" - // marshall data without the sig to binary format + // marshall data without the signature to protobufs3 binary format bin, err := proto.Marshal(message) if err != nil { log.Println(err, "failed to marshal pb message") @@ -42,15 +45,19 @@ func (n *Node) authenticateMessage(message proto.Message, data *p2p.MessageData) // restore sig in message data (for possible future use) data.Sign = sign + // restore peer id binary format from base58 encoded node id data peerId, err := peer.IDB58Decode(data.NodeId) if err != nil { log.Println(err, "Failed to decode node id from base58") return false } + // verify the data was authored by the signing peer identified by the public key + // and signature included in the message return n.verifyData(bin, []byte(sign), peerId, data.NodePubKey) } +// sign an outgoing p2p message payload func (n *Node) signProtoMessage(message proto.Message) ([]byte, error) { data, err := proto.Marshal(message) if err != nil { @@ -59,17 +66,20 @@ func (n *Node) signProtoMessage(message proto.Message) ([]byte, error) { return n.signData(data) } +// sign binary data using the local node's private key func (n *Node) signData(data []byte) ([]byte, error) { key := n.Peerstore().PrivKey(n.ID()) res, err := key.Sign(data) return res, err } -// precondition: we have info about the signer peer in the local peer store +// Verify incoming p2p message data integrity +// data: data to verify +// signature: author signature provided in the message payload +// peerId: author peer id from the message payload +// pubKeyData: author public key from the message payload func (n *Node) verifyData(data []byte, signature []byte, peerId peer.ID, pubKeyData []byte) bool { - key, err := crypto.UnmarshalPublicKey(pubKeyData) - if err != nil { log.Println(err, "Failed to extract key from message key data") return false @@ -90,7 +100,6 @@ func (n *Node) verifyData(data []byte, signature []byte, peerId peer.ID, pubKeyD } res, err := key.Verify(data, signature) - if err != nil { log.Println(err, "Error authenticating data") return false @@ -98,3 +107,23 @@ func (n *Node) verifyData(data []byte, signature []byte, peerId peer.ID, pubKeyD return res } + +// helper method - generate message data shared between all node's p2p protocols +// messageId: unique for requests, copied from request for responses +func (n *Node) NewMessageData(messageId string, gossip bool) *p2p.MessageData { + + // Add protobufs bin data for message author public key + // this is useful for authenticating messages forwarded by a node authored by another node + nodePubKey, err := n.Peerstore().PubKey(n.ID()).Bytes() + + if err != nil { + panic("Failed to get public key for sender from local peer store.") + } + + return &p2p.MessageData{ClientVersion: clientVersion, + NodeId: peer.IDB58Encode(n.ID()), + NodePubKey: nodePubKey, + Timestamp: time.Now().Unix(), + Id: messageId, + Gossip: gossip} +} diff --git a/examples/multipro/ping.go b/examples/multipro/ping.go index 9ab8ccfb..5960d560 100644 --- a/examples/multipro/ping.go +++ b/examples/multipro/ping.go @@ -56,7 +56,7 @@ func (p *PingProtocol) onPingRequest(s inet.Stream) { // generate response message log.Printf("%s: Sending ping response to %s. Message id: %s...", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id) - resp := &p2p.PingResponse{MessageData: NewMessageData(p.node, data.MessageData.Id, false), + resp := &p2p.PingResponse{MessageData: p.node.NewMessageData(data.MessageData.Id, false), Message: fmt.Sprintf("Ping response from %s", p.node.ID())} // sign the data @@ -117,7 +117,7 @@ func (p *PingProtocol) Ping(host host.Host) bool { log.Printf("%s: Sending ping to: %s....", p.node.ID(), host.ID()) // create message data - req := &p2p.PingRequest{MessageData: NewMessageData(p.node, uuid.New().String(), false), + req := &p2p.PingRequest{MessageData: p.node.NewMessageData(uuid.New().String(), false), Message: fmt.Sprintf("Ping from %s", p.node.ID())} // sign the data diff --git a/examples/multipro/protocol.go b/examples/multipro/protocol.go index 6fe6f608..a8e7e070 100644 --- a/examples/multipro/protocol.go +++ b/examples/multipro/protocol.go @@ -2,13 +2,10 @@ package main import ( "bufio" - p2p "github.com/avive/go-libp2p/examples/multipro/pb" "github.com/gogo/protobuf/proto" protobufCodec "github.com/multiformats/go-multicodec/protobuf" - "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" inet "gx/ipfs/QmbD5yKbXahNvoMqzeuNyKQA9vAs9fUvJg2GXeWU1fVqY5/go-libp2p-net" "log" - "time" ) // node version @@ -28,23 +25,3 @@ func sendProtoMessage(data proto.Message, s inet.Stream) bool { writer.Flush() return true } - -// helper method - generate message data shared between all node's p2p protocols -// messageId - unique for requests, copied from request for responses -func NewMessageData(node *Node, messageId string, gossip bool) *p2p.MessageData { - - // Add protobufs bin data for message author public key - // this is useful for authenticating messages forwarded by a node authored by another node - nodePubKey, err := node.Peerstore().PubKey(node.ID()).Bytes() - - if err != nil { - panic("Failed to get public key for sender from local peer store.") - } - - return &p2p.MessageData{ClientVersion: clientVersion, - NodeId: peer.IDB58Encode(node.ID()), - NodePubKey: nodePubKey, - Timestamp: time.Now().Unix(), - Id: messageId, - Gossip: gossip} -}