Skip to content

Commit 731d1ae

Browse files
authored
Merge pull request libp2p#1152 from imApoorva36/fix/peer-id-mismatch-handshake
fix(network): validate peer ID after security handshake
2 parents 1a54acd + 0f5b4f8 commit 731d1ae

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

libp2p/transport/upgrader.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,18 @@ async def upgrade_security(
5858
if is_initiator:
5959
if peer_id is None:
6060
raise ValueError("peer_id must be provided for outbout connection")
61-
return await self.security_multistream.secure_outbound(
61+
secure_conn = await self.security_multistream.secure_outbound(
6262
raw_conn, peer_id
6363
)
64+
# Validate the authenticated peer ID matches the expected peer ID.
65+
authenticated_peer_id = secure_conn.get_remote_peer()
66+
if authenticated_peer_id != peer_id:
67+
await secure_conn.close()
68+
raise SecurityUpgradeFailure(
69+
f"Peer ID mismatch: expected {peer_id}, "
70+
f"got {authenticated_peer_id}"
71+
)
72+
return secure_conn
6473
return await self.security_multistream.secure_inbound(raw_conn)
6574
except (MultiselectError, MultiselectClientError) as error:
6675
raise SecurityUpgradeFailure(

newsfragments/429.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed peer ID validation by checking the authenticated peer ID immediately after security handshake, failing fast on mismatches instead of later during mux negotiation with misleading errors.

tests/core/network/test_swarm.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,40 @@ async def test_swarm_listen_multiple_addresses_connectivity(security_protocol):
415415
pytest.fail(
416416
f"Failed to establish libp2p connection to {full_addr}: {e}"
417417
)
418+
419+
420+
@pytest.mark.trio
421+
async def test_swarm_peer_id_validation(security_protocol):
422+
"""Test that the swarm correctly validates peer IDs during connection."""
423+
async with SwarmFactory.create_batch_and_listen(
424+
2, security_protocol=security_protocol
425+
) as swarms:
426+
# Get the correct address and peer ID of swarm[1]
427+
addrs = tuple(
428+
addr
429+
for transport in swarms[1].listeners.values()
430+
for addr in transport.get_addrs()
431+
)
432+
correct_peer_id = swarms[1].get_peer_id()
433+
434+
# Create a fake peer ID (using swarm[0]'s ID which is definitely wrong)
435+
wrong_peer_id = swarms[0].get_peer_id()
436+
437+
# Add the address with the WRONG peer ID to the peerstore
438+
swarms[0].peerstore.add_addrs(wrong_peer_id, addrs, 10000)
439+
440+
# Attempt to dial with the wrong peer ID should fail with peer ID mismatch
441+
with pytest.raises(SwarmException):
442+
await swarms[0].dial_peer(wrong_peer_id)
443+
444+
# Ensure no connection was established
445+
assert wrong_peer_id not in swarms[0].connections
446+
447+
# Now test with the correct peer ID - this should succeed
448+
swarms[0].peerstore.add_addrs(correct_peer_id, addrs, 10000)
449+
connections = await swarms[0].dial_peer(correct_peer_id)
450+
assert len(connections) > 0, "Connection with correct peer ID should succeed"
451+
452+
# Verify connections are established
453+
assert correct_peer_id in swarms[0].connections
454+
assert swarms[0].get_peer_id() in swarms[1].connections

0 commit comments

Comments
 (0)