1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use std::sync::Arc;

use once_cell::sync::Lazy;

#[cfg(feature = "rustls-native-certs")]
pub static NATIVE_ROOTS: Lazy<Arc<[rustls::pki_types::CertificateDer<'static>]>> =
    Lazy::new(|| match rustls_native_certs::load_native_certs() {
        Ok(certs) => certs.into(),
        Err(err) => {
            tracing::warn!(?err, "failed to load native root certificate store");
            Arc::new([])
        }
    });

#[cfg(all(feature = "rustls-native-certs", feature = "oci-distribution"))]
pub static NATIVE_ROOTS_OCI: Lazy<Arc<[oci_distribution::client::Certificate]>> = Lazy::new(|| {
    NATIVE_ROOTS
        .iter()
        .map(|cert| oci_distribution::client::Certificate {
            encoding: oci_distribution::client::CertificateEncoding::Der,
            data: cert.to_vec(),
        })
        .collect()
});

#[cfg(all(feature = "rustls-native-certs", feature = "reqwest"))]
pub static NATIVE_ROOTS_REQWEST: Lazy<Arc<[reqwest::tls::Certificate]>> = Lazy::new(|| {
    NATIVE_ROOTS
        .iter()
        .filter_map(|cert| reqwest::tls::Certificate::from_der(cert.as_ref()).ok())
        .collect()
});

pub static DEFAULT_ROOTS: Lazy<Arc<rustls::RootCertStore>> = Lazy::new(|| {
    #[allow(unused_mut)]
    let mut ca = rustls::RootCertStore::empty();
    #[cfg(feature = "rustls-native-certs")]
    {
        let (added, ignored) = ca.add_parsable_certificates(NATIVE_ROOTS.iter().cloned());
        tracing::debug!(added, ignored, "loaded native root certificate store");
    }
    #[cfg(feature = "webpki-roots")]
    ca.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
    Arc::new(ca)
});

pub static DEFAULT_CLIENT_CONFIG: Lazy<rustls::ClientConfig> = Lazy::new(|| {
    rustls::ClientConfig::builder()
        .with_root_certificates(Arc::clone(&DEFAULT_ROOTS))
        .with_no_client_auth()
});

#[cfg(feature = "hyper-rustls")]
pub static DEFAULT_HYPER_CONNECTOR: Lazy<
    hyper_rustls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>,
> = Lazy::new(|| {
    hyper_rustls::HttpsConnectorBuilder::new()
        .with_tls_config(DEFAULT_CLIENT_CONFIG.clone())
        .https_or_http()
        .enable_all_versions()
        .build()
});

#[cfg(all(feature = "reqwest", feature = "rustls-native-certs"))]
pub static DEFAULT_REQWEST_CLIENT: Lazy<reqwest::Client> = Lazy::new(|| {
    reqwest::ClientBuilder::default()
        .with_native_certificates()
        .build()
        .expect("failed to build HTTP client")
});

#[cfg(feature = "rustls-native-certs")]
pub trait NativeRootsExt {
    fn with_native_certificates(self) -> Self;
}

#[cfg(all(feature = "reqwest", feature = "rustls-native-certs"))]
impl NativeRootsExt for reqwest::ClientBuilder {
    fn with_native_certificates(self) -> Self {
        NATIVE_ROOTS_REQWEST
            .iter()
            .cloned()
            .fold(self, reqwest::ClientBuilder::add_root_certificate)
    }
}