Skip to main content

nym_http_api_client/
tls.rs

1// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4//! Shared rustls crypto provider and client configuration.
5//!
6//! A binary can end up with more than one rustls crypto provider compiled in, and
7//! `rustls::ClientConfig::builder()` panics when it cannot pick one. rustls users without an
8//! explicit provider, reqwest among them, fall back to the process-wide default instead, so this
9//! module installs ring as that default and builds explicit configurations from it.
10
11use rustls::crypto::CryptoProvider;
12use rustls::{ClientConfig, RootCertStore};
13use std::sync::{Arc, LazyLock};
14
15static CLIENT_CONFIG: LazyLock<Arc<ClientConfig>> = LazyLock::new(|| {
16    let mut roots = RootCertStore::empty();
17    roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
18    let config = ClientConfig::builder_with_provider(crypto_provider())
19        .with_safe_default_protocol_versions()
20        .expect("the crypto provider supports the default TLS protocol versions")
21        .with_root_certificates(roots)
22        .with_no_client_auth();
23    Arc::new(config)
24});
25
26/// Installs ring as the process-wide default crypto provider unless one is already set.
27pub fn install_default_crypto_provider() {
28    if CryptoProvider::get_default().is_none() {
29        // losing the race to another installer is fine; whichever won is the default
30        let _ = rustls::crypto::ring::default_provider().install_default();
31    }
32}
33
34/// The process-wide default crypto provider, installing ring if none is set.
35pub fn crypto_provider() -> Arc<CryptoProvider> {
36    install_default_crypto_provider();
37    CryptoProvider::get_default()
38        .expect("a default crypto provider has just been installed")
39        .clone()
40}
41
42/// Client configuration trusting the Mozilla root certificates.
43pub fn rustls_client_config() -> Arc<ClientConfig> {
44    CLIENT_CONFIG.clone()
45}