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}