fix: peer verification successful

This commit is contained in:
Akash Mondal
2025-06-29 05:37:57 +00:00
committed by lla-dane
parent e2fee14bc5
commit 8263052f88
6 changed files with 831 additions and 56 deletions

View File

@ -276,9 +276,6 @@ class QUICListener(IListener):
# Parse packet to extract connection information
packet_info = self.parse_quic_packet(data)
print(
f"🔧 DEBUG: Address mappings: {dict((k, v.hex()) for k, v in self._addr_to_cid.items())}"
)
print(
f"🔧 DEBUG: Pending connections: {[cid.hex() for cid in self._pending_connections.keys()]}"
)
@ -333,33 +330,6 @@ class QUICListener(IListener):
)
return
# If no exact match, try address-based routing (connection ID might not match)
mapped_cid = self._addr_to_cid.get(addr)
if mapped_cid:
print(
f"🔧 PACKET: Found address mapping {addr} -> {mapped_cid.hex()}"
)
print(
f"🔧 PACKET: Client dest_cid {dest_cid.hex()} != our cid {mapped_cid.hex()}"
)
if mapped_cid in self._connections:
print(
"✅ PACKET: Using established connection via address mapping"
)
connection = self._connections[mapped_cid]
await self._route_to_connection(connection, data, addr)
return
elif mapped_cid in self._pending_connections:
print(
"✅ PACKET: Using pending connection via address mapping"
)
quic_conn = self._pending_connections[mapped_cid]
await self._handle_pending_connection(
quic_conn, data, addr, mapped_cid
)
return
# No existing connection found, create new one
print(f"🔧 PACKET: Creating new connection for {addr}")
await self._handle_new_connection(data, addr, packet_info)
@ -491,10 +461,9 @@ class QUICListener(IListener):
)
# Create QUIC connection with proper parameters for server
# CRITICAL FIX: Pass the original destination connection ID from the initial packet
quic_conn = QuicConnection(
configuration=server_config,
original_destination_connection_id=packet_info.destination_cid, # Use the original DCID from packet
original_destination_connection_id=packet_info.destination_cid,
)
quic_conn._replenish_connection_ids()

View File

@ -1,3 +1,4 @@
"""
QUIC Security implementation for py-libp2p Module 5.
Implements libp2p TLS specification for QUIC transport with peer identity integration.
@ -15,6 +16,7 @@ from cryptography.hazmat.primitives.asymmetric import ec, rsa
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.x509.base import Certificate
from cryptography.x509.extensions import Extension, UnrecognizedExtension
from cryptography.x509.oid import NameOID
from libp2p.crypto.keys import PrivateKey, PublicKey
@ -128,57 +130,106 @@ class LibP2PExtensionHandler:
) from e
@staticmethod
def parse_signed_key_extension(extension_data: bytes) -> tuple[PublicKey, bytes]:
def parse_signed_key_extension(extension: Extension) -> tuple[PublicKey, bytes]:
"""
Parse the libp2p Public Key Extension to extract public key and signature.
Args:
extension_data: The extension data bytes
Returns:
Tuple of (libp2p_public_key, signature)
Raises:
QUICCertificateError: If extension parsing fails
Parse the libp2p Public Key Extension with enhanced debugging.
"""
try:
print(f"🔍 Extension type: {type(extension)}")
print(f"🔍 Extension.value type: {type(extension.value)}")
# Extract the raw bytes from the extension
if isinstance(extension.value, UnrecognizedExtension):
# Use the .value property to get the bytes
raw_bytes = extension.value.value
print("🔍 Extension is UnrecognizedExtension, using .value property")
else:
# Fallback if it's already bytes somehow
raw_bytes = extension.value
print("🔍 Extension.value is already bytes")
print(f"🔍 Total extension length: {len(raw_bytes)} bytes")
print(f"🔍 Extension hex (first 50 bytes): {raw_bytes[:50].hex()}")
if not isinstance(raw_bytes, bytes):
raise QUICCertificateError(f"Expected bytes, got {type(raw_bytes)}")
offset = 0
# Parse public key length and data
if len(extension_data) < 4:
if len(raw_bytes) < 4:
raise QUICCertificateError("Extension too short for public key length")
public_key_length = int.from_bytes(
extension_data[offset : offset + 4], byteorder="big"
raw_bytes[offset : offset + 4], byteorder="big"
)
print(f"🔍 Public key length: {public_key_length} bytes")
offset += 4
if len(extension_data) < offset + public_key_length:
if len(raw_bytes) < offset + public_key_length:
raise QUICCertificateError("Extension too short for public key data")
public_key_bytes = extension_data[offset : offset + public_key_length]
public_key_bytes = raw_bytes[offset : offset + public_key_length]
print(f"🔍 Public key data: {public_key_bytes.hex()}")
offset += public_key_length
print(f"🔍 Offset after public key: {offset}")
# Parse signature length and data
if len(extension_data) < offset + 4:
if len(raw_bytes) < offset + 4:
raise QUICCertificateError("Extension too short for signature length")
signature_length = int.from_bytes(
extension_data[offset : offset + 4], byteorder="big"
raw_bytes[offset : offset + 4], byteorder="big"
)
print(f"🔍 Signature length: {signature_length} bytes")
offset += 4
print(f"🔍 Offset after signature length: {offset}")
if len(extension_data) < offset + signature_length:
if len(raw_bytes) < offset + signature_length:
raise QUICCertificateError("Extension too short for signature data")
signature = extension_data[offset : offset + signature_length]
signature = raw_bytes[offset : offset + signature_length]
print(f"🔍 Extracted signature length: {len(signature)} bytes")
print(f"🔍 Signature hex (first 20 bytes): {signature[:20].hex()}")
print(f"🔍 Signature starts with DER header: {signature[:2].hex() == '3045'}")
# Detailed signature analysis
if len(signature) >= 2:
if signature[0] == 0x30:
der_length = signature[1]
print(f"🔍 DER sequence length field: {der_length}")
print(f"🔍 Expected DER total: {der_length + 2}")
print(f"🔍 Actual signature length: {len(signature)}")
if len(signature) != der_length + 2:
print(f"⚠️ DER length mismatch! Expected {der_length + 2}, got {len(signature)}")
# Try truncating to correct DER length
if der_length + 2 < len(signature):
print(f"🔧 Truncating signature to correct DER length: {der_length + 2}")
signature = signature[:der_length + 2]
# Check if we have extra data
expected_total = 4 + public_key_length + 4 + signature_length
print(f"🔍 Expected total length: {expected_total}")
print(f"🔍 Actual total length: {len(raw_bytes)}")
if len(raw_bytes) > expected_total:
extra_bytes = len(raw_bytes) - expected_total
print(f"⚠️ Extra {extra_bytes} bytes detected!")
print(f"🔍 Extra data: {raw_bytes[expected_total:].hex()}")
# Deserialize the public key
public_key = LibP2PKeyConverter.deserialize_public_key(public_key_bytes)
print(f"🔍 Successfully deserialized public key: {type(public_key)}")
print(f"🔍 Final signature to return: {len(signature)} bytes")
return public_key, signature
except Exception as e:
print(f"❌ Extension parsing failed: {e}")
import traceback
print(f"❌ Traceback: {traceback.format_exc()}")
raise QUICCertificateError(
f"Failed to parse signed key extension: {e}"
) from e
@ -361,9 +412,15 @@ class PeerAuthenticator:
if not libp2p_extension:
raise QUICPeerVerificationError("Certificate missing libp2p extension")
assert libp2p_extension.value is not None
print(f"Extension type: {type(libp2p_extension)}")
print(f"Extension value type: {type(libp2p_extension.value)}")
if hasattr(libp2p_extension.value, "__len__"):
print(f"Extension value length: {len(libp2p_extension.value)}")
print(f"Extension value: {libp2p_extension.value}")
# Parse the extension to get public key and signature
public_key, signature = self.extension_handler.parse_signed_key_extension(
libp2p_extension.value
libp2p_extension
)
# Get certificate public key for signature verification
@ -376,7 +433,7 @@ class PeerAuthenticator:
signature_payload = b"libp2p-tls-handshake:" + cert_public_key_bytes
try:
public_key.verify(signature, signature_payload)
public_key.verify(signature_payload, signature)
except Exception as e:
raise QUICPeerVerificationError(
f"Invalid signature in libp2p extension: {e}"
@ -387,6 +444,8 @@ class PeerAuthenticator:
# Verify against expected peer ID if provided
if expected_peer_id and derived_peer_id != expected_peer_id:
print(f"Expected Peer id: {expected_peer_id}")
print(f"Derived Peer ID: {derived_peer_id}")
raise QUICPeerVerificationError(
f"Peer ID mismatch: expected {expected_peer_id}, "
f"got {derived_peer_id}"