pub(crate) fn client_config(
options: &QuicDialOptions,
alpn: Vec<Vec<u8>>,
) -> Result<ClientConfig, DialError>Expand description
The one place either transport decides what a server certificate is checked against.
Shared, and that is the whole point of it. Two transports answering this
question apart from each other answer it differently: a RootCertStore
seeded from the webpki-roots bundle with ca_certs added to it on one
side, wtransport’s with_native_certs() — the OS trust store, which
never sees ca_certs — on the other. Two consequences, both of which a
conformance run publishes as facts about the relay:
- The bundled Mozilla set and a machine’s own set are not the same set. They diverge on newly-added roots, on roots a distribution has retired early, and on whatever a corporate MITM appliance installed. A relay would therefore pass over QUIC and fail over WebTransport with nothing about the relay differing between the two dials.
- A caller supplying a private CA would have it honoured on one transport and silently dropped on the other. Not an error, not a warning — a handshake failure that looks exactly like a relay presenting a bad chain.
Bundled roots for both, rather than native for both, because a published
measurement has to be reproducible: webpki-roots is a fixed set compiled
into the binary, so two runs on two machines validate against the same
anchors and any difference in the outcome is a difference in the relay. The
cost is that a peer whose chain the operator trusts only via the OS store is
not trusted here — that operator passes the CA in ca_certs, which is what
the field is for and why it reaches both transports.
alpn is a parameter and not read off options because it is the one part
of the handshake the two transports do not share: a QUIC dial offers the
draft ALPNs it wants the server to choose between, a WebTransport session
offers h3 and nothing else. Everything a certificate is judged by comes
from options.
Returns DialError::TlsConfig for a ca_certs entry that is not a
parseable certificate, and for a crypto provider without the AES-128-GCM
suite QUIC’s initial packets are obliged to use.
§The initial suite is separate from the offered suites
QUIC encrypts its Initial packets with AES-128-GCM and has no say in the
matter (RFC 9001 §5.2), which normally makes that suite impossible to leave
out of an offer — and therefore makes “does this peer accept only
ChaCha20” unaskable. QuicClientConfig::with_initial exists for exactly
this: it takes the initial keys from one suite and lets the TLS config offer
another. So when QuicDialOptions::cipher_suites excludes AES-128-GCM,
the initial suite is taken from the process default provider and only the
traffic suites are restricted.