fix: add QUICTLSSecurityConfig for better security config handle

This commit is contained in:
Akash Mondal
2025-06-18 06:04:07 +00:00
committed by lla-dane
parent 123c86c091
commit 6633eb01d4
5 changed files with 47 additions and 76 deletions

View File

@ -11,6 +11,7 @@ import sys
import trio import trio
from libp2p.crypto.ed25519 import create_new_key_pair from libp2p.crypto.ed25519 import create_new_key_pair
from libp2p.transport.quic.security import LIBP2P_TLS_EXTENSION_OID
from libp2p.transport.quic.transport import QUICTransport, QUICTransportConfig from libp2p.transport.quic.transport import QUICTransport, QUICTransportConfig
from libp2p.transport.quic.utils import create_quic_multiaddr from libp2p.transport.quic.utils import create_quic_multiaddr
@ -59,11 +60,10 @@ async def test_certificate_generation():
# Check for libp2p extension # Check for libp2p extension
has_libp2p_ext = False has_libp2p_ext = False
for ext in cert.extensions: for ext in cert.extensions:
if str(ext.oid) == "1.3.6.1.4.1.53594.1.1": if ext.oid == LIBP2P_TLS_EXTENSION_OID:
has_libp2p_ext = True has_libp2p_ext = True
print(f"✅ Found libp2p extension: {ext.oid}") print(f"✅ Found libp2p extension: {ext.oid}")
print(f"Extension critical: {ext.critical}") print(f"Extension critical: {ext.critical}")
print(f"Extension value length: {len(ext.value)} bytes")
break break
if not has_libp2p_ext: if not has_libp2p_ext:
@ -209,7 +209,7 @@ async def test_server_startup():
# Check for libp2p extension # Check for libp2p extension
has_libp2p_ext = False has_libp2p_ext = False
for ext in cert.extensions: for ext in cert.extensions:
if str(ext.oid) == "1.3.6.1.4.1.53594.1.1": if ext.oid == LIBP2P_TLS_EXTENSION_OID:
has_libp2p_ext = True has_libp2p_ext = True
break break
print(f"Has libp2p extension: {has_libp2p_ext}") print(f"Has libp2p extension: {has_libp2p_ext}")

View File

@ -17,7 +17,10 @@ import trio
from libp2p.abc import IListener from libp2p.abc import IListener
from libp2p.custom_types import THandler, TProtocol from libp2p.custom_types import THandler, TProtocol
from libp2p.transport.quic.security import QUICTLSConfigManager from libp2p.transport.quic.security import (
LIBP2P_TLS_EXTENSION_OID,
QUICTLSConfigManager,
)
from .config import QUICTransportConfig from .config import QUICTransportConfig
from .connection import QUICConnection from .connection import QUICConnection
@ -442,7 +445,7 @@ class QUICListener(IListener):
cert = server_config.certificate cert = server_config.certificate
has_libp2p_ext = False has_libp2p_ext = False
for ext in cert.extensions: for ext in cert.extensions:
if str(ext.oid) == "1.3.6.1.4.1.53594.1.1": if ext.oid == LIBP2P_TLS_EXTENSION_OID:
has_libp2p_ext = True has_libp2p_ext = True
break break
print(f"🔧 NEW_CONN: Certificate has libp2p extension: {has_libp2p_ext}") print(f"🔧 NEW_CONN: Certificate has libp2p extension: {has_libp2p_ext}")
@ -557,10 +560,10 @@ class QUICListener(IListener):
cert = config.certificate cert = config.certificate
print(f"🔧 QUIC_STATE: Certificate subject: {cert.subject}") print(f"🔧 QUIC_STATE: Certificate subject: {cert.subject}")
print( print(
f"🔧 QUIC_STATE: Certificate valid from: {cert.not_valid_before}" f"🔧 QUIC_STATE: Certificate valid from: {cert.not_valid_before_utc}"
) )
print( print(
f"🔧 QUIC_STATE: Certificate valid until: {cert.not_valid_after}" f"🔧 QUIC_STATE: Certificate valid until: {cert.not_valid_after_utc}"
) )
# Check for connection errors # Check for connection errors

View File

@ -5,7 +5,6 @@ Based on go-libp2p and js-libp2p security patterns.
""" """
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime, timedelta
import logging import logging
import ssl import ssl
from typing import List, Optional, Union from typing import List, Optional, Union
@ -280,15 +279,15 @@ class CertificateGenerator:
libp2p_private_key, cert_public_key_bytes libp2p_private_key, cert_public_key_bytes
) )
# Set validity period using datetime objects (FIXED) from datetime import datetime, timedelta, timezone
now = datetime.utcnow() # Use datetime instead of time.time()
not_before = now - timedelta(seconds=CERTIFICATE_NOT_BEFORE_BUFFER) now = datetime.now(timezone.utc)
not_before = now - timedelta(minutes=1)
not_after = now + timedelta(days=validity_days) not_after = now + timedelta(days=validity_days)
# Generate serial number # Generate serial number
serial_number = int(now.timestamp()) # Convert datetime to timestamp serial_number = int(now.timestamp())
# Build certificate with proper datetime objects
certificate = ( certificate = (
x509.CertificateBuilder() x509.CertificateBuilder()
.subject_name( .subject_name(
@ -537,9 +536,8 @@ class QUICTLSSecurityConfig:
""" """
try: try:
libp2p_oid = "1.3.6.1.4.1.53594.1.1"
for ext in self.certificate.extensions: for ext in self.certificate.extensions:
if str(ext.oid) == libp2p_oid: if ext.oid == LIBP2P_TLS_EXTENSION_OID:
return True return True
return False return False
except Exception: except Exception:
@ -554,14 +552,13 @@ class QUICTLSSecurityConfig:
""" """
try: try:
from datetime import datetime from datetime import datetime, timezone
now = datetime.utcnow() now = datetime.now(timezone.utc)
return ( not_before = self.certificate.not_valid_before_utc
self.certificate.not_valid_before not_after = self.certificate.not_valid_after_utc
<= now
<= self.certificate.not_valid_after return not_before <= now <= not_after
)
except Exception: except Exception:
return False return False
@ -578,8 +575,8 @@ class QUICTLSSecurityConfig:
"subject": str(self.certificate.subject), "subject": str(self.certificate.subject),
"issuer": str(self.certificate.issuer), "issuer": str(self.certificate.issuer),
"serial_number": self.certificate.serial_number, "serial_number": self.certificate.serial_number,
"not_valid_before": self.certificate.not_valid_before, "not_valid_before_utc": self.certificate.not_valid_before_utc,
"not_valid_after": self.certificate.not_valid_after, "not_valid_after_utc": self.certificate.not_valid_after_utc,
"has_libp2p_extension": self.has_libp2p_extension(), "has_libp2p_extension": self.has_libp2p_extension(),
"is_valid": self.is_certificate_valid(), "is_valid": self.is_certificate_valid(),
"certificate_key_match": self.validate_certificate_key_match(), "certificate_key_match": self.validate_certificate_key_match(),
@ -630,7 +627,7 @@ def create_server_tls_config(
peer_id=peer_id, peer_id=peer_id,
is_client_config=False, is_client_config=False,
config_name="server", config_name="server",
verify_mode=False, # Server doesn't verify client certs in libp2p verify_mode=ssl.CERT_REQUIRED, # Server doesn't verify client certs in libp2p
check_hostname=False, check_hostname=False,
**kwargs, **kwargs,
) )
@ -661,7 +658,7 @@ def create_client_tls_config(
peer_id=peer_id, peer_id=peer_id,
is_client_config=True, is_client_config=True,
config_name="client", config_name="client",
verify_mode=False, # Client doesn't verify server certs in libp2p verify_mode=ssl.CERT_NONE, # Client doesn't verify server certs in libp2p
check_hostname=False, check_hostname=False,
**kwargs, **kwargs,
) )

View File

@ -7,6 +7,7 @@ Updated to include Module 5 security integration.
import copy import copy
import logging import logging
import ssl
import sys import sys
from aioquic.quic.configuration import ( from aioquic.quic.configuration import (
@ -202,48 +203,20 @@ class QUICTransport(ITransport):
""" """
try: try:
# Access attributes directly from QUICTLSSecurityConfig
# The security manager should return cryptography objects config.certificate = tls_config.certificate
# not DER bytes, but if it returns DER bytes, we need to handle that config.private_key = tls_config.private_key
certificate = tls_config.certificate config.certificate_chain = tls_config.certificate_chain
private_key = tls_config.private_key
# Check if we received DER bytes and need
# to convert to cryptography objects
if isinstance(certificate, bytes):
from cryptography import x509
certificate = x509.load_der_x509_certificate(certificate)
if isinstance(private_key, bytes):
from cryptography.hazmat.primitives import serialization
private_key = serialization.load_der_private_key( # type: ignore
private_key, password=None
)
# Set directly on the configuration object
config.certificate = certificate
config.private_key = private_key
# Handle certificate chain if provided
certificate_chain = tls_config.certificate_chain
# Convert DER bytes to cryptography objects if needed
chain_objects = []
for cert in certificate_chain:
if isinstance(cert, bytes):
from cryptography import x509
cert = x509.load_der_x509_certificate(cert)
chain_objects.append(cert)
config.certificate_chain = chain_objects
# Set ALPN protocols
config.alpn_protocols = tls_config.alpn_protocols config.alpn_protocols = tls_config.alpn_protocols
# Set certificate verification mode # Set verification mode (though libp2p typically doesn't verify)
config.verify_mode = tls_config.verify_mode config.verify_mode = tls_config.verify_mode
if tls_config.is_client_config:
config.verify_mode = ssl.CERT_NONE
else:
config.verify_mode = ssl.CERT_REQUIRED
logger.debug("Successfully applied TLS configuration to QUIC config") logger.debug("Successfully applied TLS configuration to QUIC config")
except Exception as e: except Exception as e:

View File

@ -6,6 +6,7 @@ Based on go-libp2p and js-libp2p QUIC implementations.
import ipaddress import ipaddress
import logging import logging
import ssl
from aioquic.quic.configuration import QuicConfiguration from aioquic.quic.configuration import QuicConfiguration
import multiaddr import multiaddr
@ -302,6 +303,7 @@ def create_server_config_from_base(
try: try:
# Create new server configuration from scratch # Create new server configuration from scratch
server_config = QuicConfiguration(is_client=False) server_config = QuicConfiguration(is_client=False)
server_config.verify_mode = ssl.CERT_REQUIRED
# Copy basic configuration attributes (these are safe to copy) # Copy basic configuration attributes (these are safe to copy)
copyable_attrs = [ copyable_attrs = [
@ -343,18 +345,14 @@ def create_server_config_from_base(
server_tls_config = security_manager.create_server_config() server_tls_config = security_manager.create_server_config()
# Override with security manager's TLS configuration # Override with security manager's TLS configuration
if "certificate" in server_tls_config: if server_tls_config.certificate:
server_config.certificate = server_tls_config["certificate"] server_config.certificate = server_tls_config.certificate
if "private_key" in server_tls_config: if server_tls_config.private_key:
server_config.private_key = server_tls_config["private_key"] server_config.private_key = server_tls_config.private_key
if "certificate_chain" in server_tls_config: if server_tls_config.certificate_chain:
# type: ignore server_config.certificate_chain = server_tls_config.certificate_chain
server_config.certificate_chain = server_tls_config[ # type: ignore if server_tls_config.alpn_protocols:
"certificate_chain" # type: ignore server_config.alpn_protocols = server_tls_config.alpn_protocols
]
if "alpn_protocols" in server_tls_config:
# type: ignore
server_config.alpn_protocols = server_tls_config["alpn_protocols"] # type: ignore
except Exception as e: except Exception as e:
logger.warning(f"Failed to apply security manager config: {e}") logger.warning(f"Failed to apply security manager config: {e}")