@@ -232,13 +232,62 @@ def connection_lost(self, exc):
232
232
self .recvbuf = b""
233
233
self .on_close ()
234
234
235
+ # v2 handshake method
236
+ def v2_handshake (self ):
237
+ """v2 handshake performed before P2P messages are exchanged (see BIP324). P2PConnection is the initiator
238
+ (in inbound connections to TestNode) and the responder (in outbound connections from TestNode).
239
+ Performed by:
240
+ * initiator using `initiate_v2_handshake()`, `complete_handshake()` and `authenticate_handshake()`
241
+ * responder using `respond_v2_handshake()`, `complete_handshake()` and `authenticate_handshake()`
242
+
243
+ `initiate_v2_handshake()` is immediately done by the initiator when the connection is established in
244
+ `connection_made()`. The rest of the initial v2 handshake functions are handled here.
245
+ """
246
+ if not self .v2_state .peer :
247
+ if not self .v2_state .initiating and not self .v2_state .sent_garbage :
248
+ # if the responder hasn't sent garbage yet, the responder is still reading ellswift bytes
249
+ # reads ellswift bytes till the first mismatch from 12 bytes V1_PREFIX
250
+ length , send_handshake_bytes = self .v2_state .respond_v2_handshake (BytesIO (self .recvbuf ))
251
+ self .recvbuf = self .recvbuf [length :]
252
+ if send_handshake_bytes == - 1 :
253
+ self .v2_state = None
254
+ return
255
+ elif send_handshake_bytes :
256
+ self .send_raw_message (send_handshake_bytes )
257
+ elif send_handshake_bytes == b"" :
258
+ return # only after send_handshake_bytes are sent can `complete_handshake()` be done
259
+
260
+ # `complete_handshake()` reads the remaining ellswift bytes from recvbuf
261
+ # and sends response after deriving shared ECDH secret using received ellswift bytes
262
+ length , response = self .v2_state .complete_handshake (BytesIO (self .recvbuf ))
263
+ self .recvbuf = self .recvbuf [length :]
264
+ if response :
265
+ self .send_raw_message (response )
266
+ else :
267
+ return # only after response is sent can `authenticate_handshake()` be done
268
+
269
+ # `self.v2_state.peer` is instantiated only after shared ECDH secret/BIP324 derived keys and ciphers
270
+ # is derived in `complete_handshake()`.
271
+ # so `authenticate_handshake()` which uses the BIP324 derived ciphers gets called after `complete_handshake()`.
272
+ assert self .v2_state .peer
273
+ length , is_mac_auth = self .v2_state .authenticate_handshake (self .recvbuf )
274
+ if not is_mac_auth :
275
+ raise ValueError ("invalid v2 mac tag in handshake authentication" )
276
+ self .recvbuf = self .recvbuf [length :]
277
+ while self .v2_state .tried_v2_handshake and self .queue_messages :
278
+ message = self .queue_messages .pop (0 )
279
+ self .send_message (message )
280
+
235
281
# Socket read methods
236
282
237
283
def data_received (self , t ):
238
284
"""asyncio callback when data is read from the socket."""
239
285
if len (t ) > 0 :
240
286
self .recvbuf += t
241
- self ._on_data ()
287
+ if self .supports_v2_p2p and not self .v2_state .tried_v2_handshake :
288
+ self .v2_handshake ()
289
+ else :
290
+ self ._on_data ()
242
291
243
292
def _on_data (self ):
244
293
"""Try to read P2P messages from the recv buffer.
0 commit comments