Răsfoiți Sursa

node: Don't accept replayed heartbeats from other peers

Evan Gray 1 an în urmă
părinte
comite
fcabf0c99e
2 a modificat fișierele cu 41 adăugiri și 3 ștergeri
  1. 9 0
      node/pkg/p2p/p2p.go
  2. 32 3
      node/pkg/p2p/p2p_test.go

+ 9 - 0
node/pkg/p2p/p2p.go

@@ -803,6 +803,15 @@ func processSignedHeartbeat(from peer.ID, s *gossipv1.SignedHeartbeat, gs *commo
 		return nil, fmt.Errorf("GuardianAddr in heartbeat does not match signerAddr")
 	}
 
+	// Don't accept replayed heartbeats from other peers
+	signedPeer, err := peer.IDFromBytes(h.P2PNodeId)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode peer ID from bytes: %w", err)
+	}
+	if signedPeer != from {
+		return nil, fmt.Errorf("guardian signed peer does not match sending peer")
+	}
+
 	// Store verified heartbeat in global guardian set state.
 	if err := gst.SetHeartbeat(signerAddr, from, &h); err != nil {
 		return nil, fmt.Errorf("failed to store in guardian set state: %w", err)

+ 32 - 3
node/pkg/p2p/p2p_test.go

@@ -6,6 +6,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/libp2p/go-libp2p/core/peer"
 	"github.com/stretchr/testify/assert"
 
 	node_common "github.com/certusone/wormhole/node/pkg/common"
@@ -21,6 +22,8 @@ func TestSignedHeartbeat(t *testing.T) {
 		timestamp             int64
 		gk                    *ecdsa.PrivateKey
 		heartbeatGuardianAddr string
+		fromP2pId             peer.ID
+		p2pNodeId             []byte
 		expectSuccess         bool
 	}
 
@@ -29,10 +32,18 @@ func TestSignedHeartbeat(t *testing.T) {
 	gk, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
 	assert.NoError(t, err)
 	gAddr := ethcrypto.PubkeyToAddress(gk.PublicKey)
+	fromP2pId, err := peer.Decode("12D3KooWSgMXkhzTbKTeupHYmyG7sFJ5LpVreQcwVnX8RD7LBpy9")
+	assert.NoError(t, err)
+	p2pNodeId, err := fromP2pId.Marshal()
+	assert.NoError(t, err)
 
 	gk2, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
 	assert.NoError(t, err)
 	gAddr2 := ethcrypto.PubkeyToAddress(gk2.PublicKey)
+	fromP2pId2, err := peer.Decode("12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU")
+	assert.NoError(t, err)
+	p2pNodeId2, err := fromP2pId2.Marshal()
+	assert.NoError(t, err)
 
 	tests := []testCase{
 		// happy case
@@ -40,6 +51,8 @@ func TestSignedHeartbeat(t *testing.T) {
 			timestamp:             time.Now().UnixNano(),
 			gk:                    gk,
 			heartbeatGuardianAddr: gAddr.String(),
+			fromP2pId:             fromP2pId,
+			p2pNodeId:             p2pNodeId,
 			expectSuccess:         true,
 		},
 		// guardian signed a heartbeat for another guardian
@@ -47,20 +60,35 @@ func TestSignedHeartbeat(t *testing.T) {
 			timestamp:             time.Now().UnixNano(),
 			gk:                    gk,
 			heartbeatGuardianAddr: gAddr2.String(),
+			fromP2pId:             fromP2pId,
+			p2pNodeId:             p2pNodeId,
 			expectSuccess:         false,
 		},
 		// old heartbeat
 		{
 			timestamp:             time.Now().Add(-time.Hour).UnixNano(),
 			gk:                    gk,
-			heartbeatGuardianAddr: gAddr2.String(),
+			heartbeatGuardianAddr: gAddr.String(),
+			fromP2pId:             fromP2pId,
+			p2pNodeId:             p2pNodeId,
 			expectSuccess:         false,
 		},
 		// heartbeat from the distant future
 		{
 			timestamp:             time.Now().Add(time.Hour).UnixNano(),
 			gk:                    gk,
-			heartbeatGuardianAddr: gAddr2.String(),
+			heartbeatGuardianAddr: gAddr.String(),
+			fromP2pId:             fromP2pId,
+			p2pNodeId:             p2pNodeId,
+			expectSuccess:         false,
+		},
+		// mismatched peer id
+		{
+			timestamp:             time.Now().UnixNano(),
+			gk:                    gk,
+			heartbeatGuardianAddr: gAddr.String(),
+			fromP2pId:             fromP2pId,
+			p2pNodeId:             p2pNodeId2,
 			expectSuccess:         false,
 		},
 	}
@@ -79,6 +107,7 @@ func TestSignedHeartbeat(t *testing.T) {
 			GuardianAddr:  tc.heartbeatGuardianAddr,
 			BootTimestamp: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC).UnixNano(),
 			Features:      []string{},
+			P2PNodeId:     tc.p2pNodeId,
 		}
 
 		s := createSignedHeartbeat(gk, heartbeat)
@@ -89,7 +118,7 @@ func TestSignedHeartbeat(t *testing.T) {
 
 		gst := node_common.NewGuardianSetState(nil)
 
-		heartbeatResult, err := processSignedHeartbeat("someone", s, gs, gst, false)
+		heartbeatResult, err := processSignedHeartbeat(tc.fromP2pId, s, gs, gst, false)
 
 		if tc.expectSuccess {
 			assert.NoError(t, err)