github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/p2p/discover/v5_encoding_test.go (about)

     1  // Copyright 2019 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package discover
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"encoding/hex"
    23  	"fmt"
    24  	"net"
    25  	"reflect"
    26  	"testing"
    27  
    28  	"github.com/davecgh/go-spew/spew"
    29  	"github.com/zhiqiangxu/go-ethereum/common/mclock"
    30  	"github.com/zhiqiangxu/go-ethereum/crypto"
    31  	"github.com/zhiqiangxu/go-ethereum/p2p/enode"
    32  )
    33  
    34  var (
    35  	testKeyA, _ = crypto.HexToECDSA("eef77acb6c6a6eebc5b363a475ac583ec7eccdb42b6481424c60f59aa326547f")
    36  	testKeyB, _ = crypto.HexToECDSA("66fb62bfbd66b9177a138c1e5cddbe4f7c30c343e94e68df8769459cb1cde628")
    37  	testIDnonce = [32]byte{5, 6, 7, 8, 9, 10, 11, 12}
    38  )
    39  
    40  func TestDeriveKeysV5(t *testing.T) {
    41  	t.Parallel()
    42  
    43  	var (
    44  		n1        = enode.ID{1}
    45  		n2        = enode.ID{2}
    46  		challenge = &whoareyouV5{}
    47  		db, _     = enode.OpenDB("")
    48  		ln        = enode.NewLocalNode(db, testKeyA)
    49  		c         = newWireCodec(ln, testKeyA, mclock.System{})
    50  	)
    51  	defer db.Close()
    52  
    53  	sec1 := c.deriveKeys(n1, n2, testKeyA, &testKeyB.PublicKey, challenge)
    54  	sec2 := c.deriveKeys(n1, n2, testKeyB, &testKeyA.PublicKey, challenge)
    55  	if sec1 == nil || sec2 == nil {
    56  		t.Fatal("key agreement failed")
    57  	}
    58  	if !reflect.DeepEqual(sec1, sec2) {
    59  		t.Fatalf("keys not equal:\n  %+v\n  %+v", sec1, sec2)
    60  	}
    61  }
    62  
    63  // This test checks the basic handshake flow where A talks to B and A has no secrets.
    64  func TestHandshakeV5(t *testing.T) {
    65  	t.Parallel()
    66  	net := newHandshakeTest()
    67  	defer net.close()
    68  
    69  	// A -> B   RANDOM PACKET
    70  	packet, _ := net.nodeA.encode(t, net.nodeB, &findnodeV5{})
    71  	resp := net.nodeB.expectDecode(t, p_unknownV5, packet)
    72  
    73  	// A <- B   WHOAREYOU
    74  	challenge := &whoareyouV5{
    75  		AuthTag:   resp.(*unknownV5).AuthTag,
    76  		IDNonce:   testIDnonce,
    77  		RecordSeq: 0,
    78  	}
    79  	whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge)
    80  	net.nodeA.expectDecode(t, p_whoareyouV5, whoareyou)
    81  
    82  	// A -> B   FINDNODE
    83  	findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &findnodeV5{})
    84  	net.nodeB.expectDecode(t, p_findnodeV5, findnode)
    85  	if len(net.nodeB.c.sc.handshakes) > 0 {
    86  		t.Fatalf("node B didn't remove handshake from challenge map")
    87  	}
    88  
    89  	// A <- B   NODES
    90  	nodes, _ := net.nodeB.encode(t, net.nodeA, &nodesV5{Total: 1})
    91  	net.nodeA.expectDecode(t, p_nodesV5, nodes)
    92  }
    93  
    94  // This test checks that handshake attempts are removed within the timeout.
    95  func TestHandshakeV5_timeout(t *testing.T) {
    96  	t.Parallel()
    97  	net := newHandshakeTest()
    98  	defer net.close()
    99  
   100  	// A -> B   RANDOM PACKET
   101  	packet, _ := net.nodeA.encode(t, net.nodeB, &findnodeV5{})
   102  	resp := net.nodeB.expectDecode(t, p_unknownV5, packet)
   103  
   104  	// A <- B   WHOAREYOU
   105  	challenge := &whoareyouV5{
   106  		AuthTag:   resp.(*unknownV5).AuthTag,
   107  		IDNonce:   testIDnonce,
   108  		RecordSeq: 0,
   109  	}
   110  	whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge)
   111  	net.nodeA.expectDecode(t, p_whoareyouV5, whoareyou)
   112  
   113  	// A -> B   FINDNODE after timeout
   114  	net.clock.Run(handshakeTimeout + 1)
   115  	findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &findnodeV5{})
   116  	net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, findnode)
   117  }
   118  
   119  // This test checks handshake behavior when no record is sent in the auth response.
   120  func TestHandshakeV5_norecord(t *testing.T) {
   121  	t.Parallel()
   122  	net := newHandshakeTest()
   123  	defer net.close()
   124  
   125  	// A -> B   RANDOM PACKET
   126  	packet, _ := net.nodeA.encode(t, net.nodeB, &findnodeV5{})
   127  	resp := net.nodeB.expectDecode(t, p_unknownV5, packet)
   128  
   129  	// A <- B   WHOAREYOU
   130  	nodeA := net.nodeA.n()
   131  	if nodeA.Seq() == 0 {
   132  		t.Fatal("need non-zero sequence number")
   133  	}
   134  	challenge := &whoareyouV5{
   135  		AuthTag:   resp.(*unknownV5).AuthTag,
   136  		IDNonce:   testIDnonce,
   137  		RecordSeq: nodeA.Seq(),
   138  		node:      nodeA,
   139  	}
   140  	whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge)
   141  	net.nodeA.expectDecode(t, p_whoareyouV5, whoareyou)
   142  
   143  	// A -> B   FINDNODE
   144  	findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &findnodeV5{})
   145  	net.nodeB.expectDecode(t, p_findnodeV5, findnode)
   146  
   147  	// A <- B   NODES
   148  	nodes, _ := net.nodeB.encode(t, net.nodeA, &nodesV5{Total: 1})
   149  	net.nodeA.expectDecode(t, p_nodesV5, nodes)
   150  }
   151  
   152  // In this test, A tries to send FINDNODE with existing secrets but B doesn't know
   153  // anything about A.
   154  func TestHandshakeV5_rekey(t *testing.T) {
   155  	t.Parallel()
   156  	net := newHandshakeTest()
   157  	defer net.close()
   158  
   159  	initKeys := &handshakeSecrets{
   160  		readKey:  []byte("BBBBBBBBBBBBBBBB"),
   161  		writeKey: []byte("AAAAAAAAAAAAAAAA"),
   162  	}
   163  	net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), initKeys.readKey, initKeys.writeKey)
   164  
   165  	// A -> B   FINDNODE (encrypted with zero keys)
   166  	findnode, authTag := net.nodeA.encode(t, net.nodeB, &findnodeV5{})
   167  	net.nodeB.expectDecode(t, p_unknownV5, findnode)
   168  
   169  	// A <- B   WHOAREYOU
   170  	challenge := &whoareyouV5{AuthTag: authTag, IDNonce: testIDnonce}
   171  	whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge)
   172  	net.nodeA.expectDecode(t, p_whoareyouV5, whoareyou)
   173  
   174  	// Check that new keys haven't been stored yet.
   175  	if s := net.nodeA.c.sc.session(net.nodeB.id(), net.nodeB.addr()); !bytes.Equal(s.writeKey, initKeys.writeKey) || !bytes.Equal(s.readKey, initKeys.readKey) {
   176  		t.Fatal("node A stored keys too early")
   177  	}
   178  	if s := net.nodeB.c.sc.session(net.nodeA.id(), net.nodeA.addr()); s != nil {
   179  		t.Fatal("node B stored keys too early")
   180  	}
   181  
   182  	// A -> B   FINDNODE encrypted with new keys
   183  	findnode, _ = net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &findnodeV5{})
   184  	net.nodeB.expectDecode(t, p_findnodeV5, findnode)
   185  
   186  	// A <- B   NODES
   187  	nodes, _ := net.nodeB.encode(t, net.nodeA, &nodesV5{Total: 1})
   188  	net.nodeA.expectDecode(t, p_nodesV5, nodes)
   189  }
   190  
   191  // In this test A and B have different keys before the handshake.
   192  func TestHandshakeV5_rekey2(t *testing.T) {
   193  	t.Parallel()
   194  	net := newHandshakeTest()
   195  	defer net.close()
   196  
   197  	initKeysA := &handshakeSecrets{
   198  		readKey:  []byte("BBBBBBBBBBBBBBBB"),
   199  		writeKey: []byte("AAAAAAAAAAAAAAAA"),
   200  	}
   201  	initKeysB := &handshakeSecrets{
   202  		readKey:  []byte("CCCCCCCCCCCCCCCC"),
   203  		writeKey: []byte("DDDDDDDDDDDDDDDD"),
   204  	}
   205  	net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), initKeysA.readKey, initKeysA.writeKey)
   206  	net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), initKeysB.readKey, initKeysA.writeKey)
   207  
   208  	// A -> B   FINDNODE encrypted with initKeysA
   209  	findnode, authTag := net.nodeA.encode(t, net.nodeB, &findnodeV5{Distance: 3})
   210  	net.nodeB.expectDecode(t, p_unknownV5, findnode)
   211  
   212  	// A <- B   WHOAREYOU
   213  	challenge := &whoareyouV5{AuthTag: authTag, IDNonce: testIDnonce}
   214  	whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge)
   215  	net.nodeA.expectDecode(t, p_whoareyouV5, whoareyou)
   216  
   217  	// A -> B   FINDNODE encrypted with new keys
   218  	findnode, _ = net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &findnodeV5{})
   219  	net.nodeB.expectDecode(t, p_findnodeV5, findnode)
   220  
   221  	// A <- B   NODES
   222  	nodes, _ := net.nodeB.encode(t, net.nodeA, &nodesV5{Total: 1})
   223  	net.nodeA.expectDecode(t, p_nodesV5, nodes)
   224  }
   225  
   226  // This test checks some malformed packets.
   227  func TestDecodeErrorsV5(t *testing.T) {
   228  	t.Parallel()
   229  	net := newHandshakeTest()
   230  	defer net.close()
   231  
   232  	net.nodeA.expectDecodeErr(t, errTooShort, []byte{})
   233  	// TODO some more tests would be nice :)
   234  }
   235  
   236  // This benchmark checks performance of authHeader decoding, verification and key derivation.
   237  func BenchmarkV5_DecodeAuthSecp256k1(b *testing.B) {
   238  	net := newHandshakeTest()
   239  	defer net.close()
   240  
   241  	var (
   242  		idA       = net.nodeA.id()
   243  		addrA     = net.nodeA.addr()
   244  		challenge = &whoareyouV5{AuthTag: []byte("authresp"), RecordSeq: 0, node: net.nodeB.n()}
   245  		nonce     = make([]byte, gcmNonceSize)
   246  	)
   247  	header, _, _ := net.nodeA.c.makeAuthHeader(nonce, challenge)
   248  	challenge.node = nil // force ENR signature verification in decoder
   249  	b.ResetTimer()
   250  
   251  	for i := 0; i < b.N; i++ {
   252  		_, _, err := net.nodeB.c.decodeAuthResp(idA, addrA, header, challenge)
   253  		if err != nil {
   254  			b.Fatal(err)
   255  		}
   256  	}
   257  }
   258  
   259  // This benchmark checks how long it takes to decode an encrypted ping packet.
   260  func BenchmarkV5_DecodePing(b *testing.B) {
   261  	net := newHandshakeTest()
   262  	defer net.close()
   263  
   264  	r := []byte{233, 203, 93, 195, 86, 47, 177, 186, 227, 43, 2, 141, 244, 230, 120, 17}
   265  	w := []byte{79, 145, 252, 171, 167, 216, 252, 161, 208, 190, 176, 106, 214, 39, 178, 134}
   266  	net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), r, w)
   267  	net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), w, r)
   268  	addrB := net.nodeA.addr()
   269  	ping := &pingV5{ReqID: []byte("reqid"), ENRSeq: 5}
   270  	enc, _, err := net.nodeA.c.encode(net.nodeB.id(), addrB, ping, nil)
   271  	if err != nil {
   272  		b.Fatalf("can't encode: %v", err)
   273  	}
   274  	b.ResetTimer()
   275  
   276  	for i := 0; i < b.N; i++ {
   277  		_, _, p, _ := net.nodeB.c.decode(enc, addrB)
   278  		if _, ok := p.(*pingV5); !ok {
   279  			b.Fatalf("wrong packet type %T", p)
   280  		}
   281  	}
   282  }
   283  
   284  var pp = spew.NewDefaultConfig()
   285  
   286  type handshakeTest struct {
   287  	nodeA, nodeB handshakeTestNode
   288  	clock        mclock.Simulated
   289  }
   290  
   291  type handshakeTestNode struct {
   292  	ln *enode.LocalNode
   293  	c  *wireCodec
   294  }
   295  
   296  func newHandshakeTest() *handshakeTest {
   297  	t := new(handshakeTest)
   298  	t.nodeA.init(testKeyA, net.IP{127, 0, 0, 1}, &t.clock)
   299  	t.nodeB.init(testKeyB, net.IP{127, 0, 0, 1}, &t.clock)
   300  	return t
   301  }
   302  
   303  func (t *handshakeTest) close() {
   304  	t.nodeA.ln.Database().Close()
   305  	t.nodeB.ln.Database().Close()
   306  }
   307  
   308  func (n *handshakeTestNode) init(key *ecdsa.PrivateKey, ip net.IP, clock mclock.Clock) {
   309  	db, _ := enode.OpenDB("")
   310  	n.ln = enode.NewLocalNode(db, key)
   311  	n.ln.SetStaticIP(ip)
   312  	n.c = newWireCodec(n.ln, key, clock)
   313  }
   314  
   315  func (n *handshakeTestNode) encode(t testing.TB, to handshakeTestNode, p packetV5) ([]byte, []byte) {
   316  	t.Helper()
   317  	return n.encodeWithChallenge(t, to, nil, p)
   318  }
   319  
   320  func (n *handshakeTestNode) encodeWithChallenge(t testing.TB, to handshakeTestNode, c *whoareyouV5, p packetV5) ([]byte, []byte) {
   321  	t.Helper()
   322  	// Copy challenge and add destination node. This avoids sharing 'c' among the two codecs.
   323  	var challenge *whoareyouV5
   324  	if c != nil {
   325  		challengeCopy := *c
   326  		challenge = &challengeCopy
   327  		challenge.node = to.n()
   328  	}
   329  	// Encode to destination.
   330  	enc, authTag, err := n.c.encode(to.id(), to.addr(), p, challenge)
   331  	if err != nil {
   332  		t.Fatal(fmt.Errorf("(%s) %v", n.ln.ID().TerminalString(), err))
   333  	}
   334  	t.Logf("(%s) -> (%s)   %s\n%s", n.ln.ID().TerminalString(), to.id().TerminalString(), p.name(), hex.Dump(enc))
   335  	return enc, authTag
   336  }
   337  
   338  func (n *handshakeTestNode) expectDecode(t *testing.T, ptype byte, p []byte) packetV5 {
   339  	t.Helper()
   340  	dec, err := n.decode(p)
   341  	if err != nil {
   342  		t.Fatal(fmt.Errorf("(%s) %v", n.ln.ID().TerminalString(), err))
   343  	}
   344  	t.Logf("(%s) %#v", n.ln.ID().TerminalString(), pp.NewFormatter(dec))
   345  	if dec.kind() != ptype {
   346  		t.Fatalf("expected packet type %d, got %d", ptype, dec.kind())
   347  	}
   348  	return dec
   349  }
   350  
   351  func (n *handshakeTestNode) expectDecodeErr(t *testing.T, wantErr error, p []byte) {
   352  	t.Helper()
   353  	if _, err := n.decode(p); !reflect.DeepEqual(err, wantErr) {
   354  		t.Fatal(fmt.Errorf("(%s) got err %q, want %q", n.ln.ID().TerminalString(), err, wantErr))
   355  	}
   356  }
   357  
   358  func (n *handshakeTestNode) decode(input []byte) (packetV5, error) {
   359  	_, _, p, err := n.c.decode(input, "127.0.0.1")
   360  	return p, err
   361  }
   362  
   363  func (n *handshakeTestNode) n() *enode.Node {
   364  	return n.ln.Node()
   365  }
   366  
   367  func (n *handshakeTestNode) addr() string {
   368  	return n.ln.Node().IP().String()
   369  }
   370  
   371  func (n *handshakeTestNode) id() enode.ID {
   372  	return n.ln.ID()
   373  }