|
| 1 | +//! Process-wide TLS crypto provider setup. |
| 2 | +//! |
| 3 | +//! # Background |
| 4 | +//! |
| 5 | +//! `rustls` 0.23 requires a "crypto provider" (the backend that implements |
| 6 | +//! AES, SHA, ECDSA, RNG, etc.) to be selected before any TLS connection is |
| 7 | +//! built. When exactly one provider feature is compiled in, `rustls` picks |
| 8 | +//! it automatically. When **multiple** providers are linked, `rustls` |
| 9 | +//! refuses to guess and panics on the first TLS use with: |
| 10 | +//! |
| 11 | +//! > no process-level CryptoProvider available -- |
| 12 | +//! > call CryptoProvider::install_default() before this point |
| 13 | +//! |
| 14 | +//! # Why we hit this |
| 15 | +//! |
| 16 | +//! Our dependency graph pulls in two providers: |
| 17 | +//! |
| 18 | +//! - `alloy-transport-ws` (alloy 2.0+) enables `rustls`'s `aws_lc_rs` feature. |
| 19 | +//! - `object_store` (via `reqwest`'s `rustls-tls-native-roots`) enables |
| 20 | +//! `rustls`'s `ring` feature. |
| 21 | +//! |
| 22 | +//! Cargo features are additive, so `rustls` ends up compiled with **both** |
| 23 | +//! `aws_lc_rs` and `ring`. We can't disable either without forking an |
| 24 | +//! upstream crate, so we resolve the ambiguity by explicitly installing |
| 25 | +//! `aws_lc_rs` as the process-wide default at startup. |
| 26 | +//! |
| 27 | +//! # Where to call this |
| 28 | +//! |
| 29 | +//! This must be called **once per process**, as early as possible, before |
| 30 | +//! any code opens a TLS connection. In practice that means: |
| 31 | +//! |
| 32 | +//! - At the top of every binary's `main()` (`graph-node`, `graphman`, `gnd`). |
| 33 | +//! - From a function that every test harness touches before using TLS |
| 34 | +//! (we hook into `test-store`'s `build_store()` and `graph-tests`' |
| 35 | +//! `fixture::stores()`). |
| 36 | +//! |
| 37 | +//! Each Rust binary (including each `cargo test` binary) is a separate |
| 38 | +//! process, so every entry point needs its own call. There is no single |
| 39 | +//! "Rust process startup hook" short of pulling in the `ctor` crate. |
| 40 | +//! |
| 41 | +//! # Safety / idempotency |
| 42 | +//! |
| 43 | +//! `install_default` only succeeds on the first call per process. Subsequent |
| 44 | +//! calls return an error, which we deliberately ignore. This makes the |
| 45 | +//! helper safe to call from many places without coordination. |
| 46 | +
|
| 47 | +/// Install `aws_lc_rs` as the process-wide default `rustls` crypto provider. |
| 48 | +/// |
| 49 | +/// Idempotent: safe to call multiple times per process. Only the first call |
| 50 | +/// actually installs; later calls are no-ops. Must be called before any |
| 51 | +/// TLS connection is built. See the module docs for why this exists. |
| 52 | +pub fn install_default_crypto_provider() { |
| 53 | + // If a provider is already installed (by an earlier call, or by another |
| 54 | + // crate), `install_default` returns Err. That's fine -- as long as some |
| 55 | + // provider is set, `rustls` will not panic. We deliberately do not |
| 56 | + // require that `aws_lc_rs` specifically wins, only that a default |
| 57 | + // exists. |
| 58 | + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); |
| 59 | +} |
0 commit comments