aiortc / aioquic

QUIC and HTTP/3 implementation in Python
BSD 3-Clause "New" or "Revised" License
1.6k stars 229 forks source link

`unable to get local issuer certificate` when attempting to connect to `QUIC` server #489

Closed ReeceHumphreys closed 3 months ago

ReeceHumphreys commented 3 months ago

Using the latest version of aioquic. Hello, I have a QUIC server built with msquic configured with a Let's Encrypt certificate. I'm unable to establish a TLS connection to this sever with aioquic despite being able to create a successful connection in C# and Go. Here is a minimal example of my code.

import asyncio
import logging
import ssl
from aioquic.asyncio import connect
from aioquic.quic.configuration import QuicConfiguration
import certifi

logging.basicConfig(level=logging.DEBUG)

async def main():
    try:
        configuration = QuicConfiguration(alpn_protocols=["icerpc"], is_client=True)
        configuration.load_verify_locations()

        async def stream_handler(reader, writer):
            # Handle the bidirectional stream
            data = await reader.read()
            print(f"Received from server: {data.decode()}")

        async with connect(
            "hello.icerpc.dev",
            4062,
            configuration=configuration,
            stream_handler=stream_handler,
        ) as protocol:
            print("Connected to hello.icerpc.dev via QUIC")
            await asyncio.sleep(5)
            print("Connection closed")
    except Exception as e:
        print("An error occurred:", repr(e))

asyncio.run(main())

I am getting the following error (reason unable to get local issuer certificate):

DEBUG:asyncio:Using selector: KqueueSelector
DEBUG:quic:[94d267d6aa6472c0] TLS State.CLIENT_HANDSHAKE_START -> State.CLIENT_EXPECT_SERVER_HELLO
DEBUG:quic:[94d267d6aa6472c0] QuicConnectionState.FIRSTFLIGHT -> QuicConnectionState.CONNECTED
DEBUG:quic:[94d267d6aa6472c0] TLS State.CLIENT_EXPECT_SERVER_HELLO -> State.CLIENT_EXPECT_ENCRYPTED_EXTENSIONS
DEBUG:quic:[94d267d6aa6472c0] TLS State.CLIENT_EXPECT_ENCRYPTED_EXTENSIONS -> State.CLIENT_EXPECT_CERTIFICATE_REQUEST_OR_CERTIFICATE
DEBUG:quic:[94d267d6aa6472c0] Discarding epoch Epoch.INITIAL
DEBUG:quic:[94d267d6aa6472c0] TLS State.CLIENT_EXPECT_CERTIFICATE_REQUEST_OR_CERTIFICATE -> State.CLIENT_EXPECT_CERTIFICATE_VERIFY
WARNING:quic:[94d267d6aa6472c0] Error: 298, reason: unable to get local issuer certificate, frame_type: 6
INFO:quic:[94d267d6aa6472c0] Connection close sent (code 0x12A, reason unable to get local issuer certificate)
DEBUG:quic:[94d267d6aa6472c0] QuicConnectionState.CONNECTED -> QuicConnectionState.CLOSING
DEBUG:quic:[94d267d6aa6472c0] Discarding epoch Epoch.HANDSHAKE
DEBUG:quic:[94d267d6aa6472c0] Discarding epoch Epoch.ONE_RTT
DEBUG:quic:[94d267d6aa6472c0] QuicConnectionState.CLOSING -> QuicConnectionState.TERMINATED
An error occurred: ConnectionError()

I am hoping someone can give me some guidance as to what may be going wrong! Im happy to provide any additional information too. It seems that the default certifi.where() path does indeed contain the isrg root x1 cert needed for Let's Encrypt and the server is indeed sending the correct certs when inspecting with openssl s_client -connect hello.icerpc.dev:4062

ReeceHumphreys commented 3 months ago

Looked more into it. Looks like an issue with the .NET QUIC server I am running not sending the intermediary certificate!

rthalley commented 3 months ago

I use Let's Encrypt certs for all my testing with no problems, so if you can get your peer to give the whole chain, it should work.