Skip to content

Commit e075fd1

Browse files
committed
test: Introduce test types and modify v2 handshake function accordingly
Prior to this commit, TestEncryptedP2PState would always send initial_v2_handshake bytes in 2 parts (as required by early key response test). For generalising this test and having different v2 handshake behaviour based on the test type, special behaviours like sending initial_v2_handshake bytes in 2 parts are executed only if test_type is set to EARLY_KEY_RESPONSE.
1 parent 7d07daa commit e075fd1

File tree

1 file changed

+41
-50
lines changed

1 file changed

+41
-50
lines changed

test/functional/p2p_v2_misbehaving.py

Lines changed: 41 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,87 +3,78 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

6-
import random
6+
from enum import Enum
77

8-
from test_framework.test_framework import BitcoinTestFramework
9-
from test_framework.crypto.ellswift import ellswift_create
8+
from test_framework.messages import MAGIC_BYTES
109
from test_framework.p2p import P2PInterface
10+
from test_framework.test_framework import BitcoinTestFramework
1111
from test_framework.v2_p2p import EncryptedP2PState
1212

1313

14-
class TestEncryptedP2PState(EncryptedP2PState):
15-
""" Modify v2 P2P protocol functions for testing that "The responder waits until one byte is received which does
16-
not match the 16 bytes consisting of the network magic followed by "version\x00\x00\x00\x00\x00"." (see BIP 324)
14+
class TestType(Enum):
15+
""" Scenarios to be tested:
1716
18-
- if `send_net_magic` is True, send first 4 bytes of ellswift (match network magic) else send remaining 60 bytes
19-
- `can_data_be_received` is a variable used to assert if data is received on recvbuf.
20-
- v2 TestNode shouldn't respond back if we send V1_PREFIX and data shouldn't be received on recvbuf.
21-
This state is represented using `can_data_be_received` = False.
22-
- v2 TestNode responds back when mismatch from V1_PREFIX happens and data can be received on recvbuf.
23-
This state is represented using `can_data_be_received` = True.
17+
1. EARLY_KEY_RESPONSE - The responder needs to wait until one byte is received which does not match the 16 bytes
18+
consisting of network magic followed by "version\x00\x00\x00\x00\x00" before sending out its ellswift + garbage bytes
2419
"""
20+
EARLY_KEY_RESPONSE = 0
2521

26-
def __init__(self):
27-
super().__init__(initiating=True, net='regtest')
28-
self.send_net_magic = True
29-
self.can_data_be_received = False
30-
31-
def initiate_v2_handshake(self, garbage_len=random.randrange(4096)):
32-
"""Initiator begins the v2 handshake by sending its ellswift bytes and garbage.
33-
Here, the 64 bytes ellswift is assumed to have it's 4 bytes match network magic bytes. It is sent in 2 phases:
34-
1. when `send_network_magic` = True, send first 4 bytes of ellswift (matches network magic bytes)
35-
2. when `send_network_magic` = False, send remaining 60 bytes of ellswift
36-
"""
37-
if self.send_net_magic:
38-
self.privkey_ours, self.ellswift_ours = ellswift_create()
39-
self.sent_garbage = random.randbytes(garbage_len)
40-
self.send_net_magic = False
41-
return b"\xfa\xbf\xb5\xda"
42-
else:
43-
self.can_data_be_received = True
44-
return self.ellswift_ours[4:] + self.sent_garbage
4522

23+
class EarlyKeyResponseState(EncryptedP2PState):
24+
""" Modify v2 P2P protocol functions for testing EARLY_KEY_RESPONSE scenario"""
25+
def __init__(self, initiating, net):
26+
super().__init__(initiating=initiating, net=net)
27+
self.can_data_be_received = False # variable used to assert if data is received on recvbuf.
28+
29+
def initiate_v2_handshake(self):
30+
"""Send ellswift and garbage bytes in 2 parts when TestType = (EARLY_KEY_RESPONSE)"""
31+
self.generate_keypair_and_garbage()
32+
return b""
4633

47-
class PeerEarlyKey(P2PInterface):
34+
35+
class MisbehavingV2Peer(P2PInterface):
4836
"""Custom implementation of P2PInterface which uses modified v2 P2P protocol functions for testing purposes."""
49-
def __init__(self):
37+
def __init__(self, test_type):
5038
super().__init__()
51-
self.v2_state = None
52-
self.connection_opened = False
39+
self.test_type = test_type
5340

5441
def connection_made(self, transport):
55-
"""64 bytes ellswift is sent in 2 parts during `initial_v2_handshake()`"""
56-
self.v2_state = TestEncryptedP2PState()
42+
if self.test_type == TestType.EARLY_KEY_RESPONSE:
43+
self.v2_state = EarlyKeyResponseState(initiating=True, net='regtest')
5744
super().connection_made(transport)
5845

5946
def data_received(self, t):
60-
# check that data can be received on recvbuf only when mismatch from V1_PREFIX happens (send_net_magic = False)
61-
assert self.v2_state.can_data_be_received and not self.v2_state.send_net_magic
47+
if self.test_type == TestType.EARLY_KEY_RESPONSE:
48+
# check that data can be received on recvbuf only when mismatch from V1_PREFIX happens
49+
assert self.v2_state.can_data_be_received
50+
else:
51+
super().data_received(t)
6252

63-
def on_open(self):
64-
self.connection_opened = True
6553

66-
class P2PEarlyKey(BitcoinTestFramework):
54+
class EncryptedP2PMisbehaving(BitcoinTestFramework):
6755
def set_test_params(self):
6856
self.num_nodes = 1
6957
self.extra_args = [["-v2transport=1", "-peertimeout=3"]]
7058

7159
def run_test(self):
60+
self.test_earlykeyresponse()
61+
62+
def test_earlykeyresponse(self):
7263
self.log.info('Sending ellswift bytes in parts to ensure that response from responder is received only when')
7364
self.log.info('ellswift bytes have a mismatch from the 16 bytes(network magic followed by "version\\x00\\x00\\x00\\x00\\x00")')
7465
node0 = self.nodes[0]
7566
self.log.info('Sending first 4 bytes of ellswift which match network magic')
7667
self.log.info('If a response is received, assertion failure would happen in our custom data_received() function')
77-
# send happens in `initiate_v2_handshake()` in `connection_made()`
78-
peer1 = node0.add_p2p_connection(PeerEarlyKey(), wait_for_verack=False, send_version=False, supports_v2_p2p=True, wait_for_v2_handshake=False)
79-
self.wait_until(lambda: peer1.connection_opened)
68+
peer1 = node0.add_p2p_connection(MisbehavingV2Peer(TestType.EARLY_KEY_RESPONSE), wait_for_verack=False, send_version=False, supports_v2_p2p=True, wait_for_v2_handshake=False)
69+
peer1.send_raw_message(MAGIC_BYTES['regtest'])
8070
self.log.info('Sending remaining ellswift and garbage which are different from V1_PREFIX. Since a response is')
8171
self.log.info('expected now, our custom data_received() function wouldn\'t result in assertion failure')
82-
ellswift_and_garbage_data = peer1.v2_state.initiate_v2_handshake()
83-
peer1.send_raw_message(ellswift_and_garbage_data)
84-
peer1.wait_for_disconnect(timeout=5)
85-
self.log.info('successful disconnection when MITM happens in the key exchange phase')
72+
peer1.v2_state.can_data_be_received = True
73+
peer1.send_raw_message(peer1.v2_state.ellswift_ours[4:] + peer1.v2_state.sent_garbage)
74+
with node0.assert_debug_log(['V2 handshake timeout peer=0']):
75+
peer1.wait_for_disconnect(timeout=5)
76+
self.log.info('successful disconnection since modified ellswift was sent as response')
8677

8778

8879
if __name__ == '__main__':
89-
P2PEarlyKey().main()
80+
EncryptedP2PMisbehaving().main()

0 commit comments

Comments
 (0)