Skip to main content

pubhubs/misc/
rustls_ext.rs

1//! Helpers related to [`rustls`](https://docs.rs/rustls).
2
3/// Ensures the process-wide default rustls `CryptoProvider` prefers the post-quantum
4/// hybrid key exchange `X25519MLKEM768`, installing aws-lc-rs if no default is set yet.
5///
6/// This sets the key exchange offered by all our outbound TLS — `awc` (server-to-server
7/// and Yivi) and `object_store`'s `reqwest` (the S3 store) — which build their configs
8/// via `rustls::ClientConfig::builder`.  Call it once before any client is built (e.g.
9/// first thing in `main`): with both the `ring` and `aws_lc_rs` providers compiled,
10/// `ClientConfig::builder` panics unless a default is installed.  Idempotent.
11///
12/// # Panics
13///
14/// If the resulting default provider does not prefer `X25519MLKEM768`.
15pub fn ensure_pq_default_crypto_provider() {
16    use rustls::crypto::aws_lc_rs;
17
18    match aws_lc_rs::default_provider().install_default() {
19        Ok(()) => assert!(
20            provider_prefers_mlkem(&aws_lc_rs::default_provider()),
21            "aws-lc-rs's default rustls provider does not prefer X25519MLKEM768",
22        ),
23        Err(existing) => assert!(
24            provider_prefers_mlkem(&existing),
25            "another rustls CryptoProvider was already installed as the process default \
26             and does not prefer X25519MLKEM768; ensure_pq_default_crypto_provider() must \
27             run before any other provider is installed",
28        ),
29    }
30}
31
32/// Whether `provider` prefers `X25519MLKEM768`, i.e. lists it first — rustls orders
33/// `kx_groups` by preference.
34fn provider_prefers_mlkem(provider: &rustls::crypto::CryptoProvider) -> bool {
35    provider
36        .kx_groups
37        .first()
38        .is_some_and(|kx| kx.name() == rustls::NamedGroup::X25519MLKEM768)
39}