hyper_rustls/
config.rs

1#[cfg(feature = "rustls-native-certs")]
2use std::io;
3#[cfg(feature = "rustls-platform-verifier")]
4use std::sync::Arc;
5
6#[cfg(any(
7    feature = "rustls-platform-verifier",
8    feature = "rustls-native-certs",
9    feature = "webpki-roots"
10))]
11use rustls::client::WantsClientCert;
12use rustls::{ClientConfig, ConfigBuilder, WantsVerifier};
13#[cfg(feature = "rustls-native-certs")]
14use rustls_native_certs::CertificateResult;
15
16/// Methods for configuring roots
17///
18/// This adds methods (gated by crate features) for easily configuring
19/// TLS server roots a rustls ClientConfig will trust.
20pub trait ConfigBuilderExt {
21    /// Use the platform's native verifier to verify server certificates.
22    ///
23    /// See the documentation for [rustls-platform-verifier] for more details.
24    ///
25    /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier
26    #[cfg(feature = "rustls-platform-verifier")]
27    fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
28
29    /// This configures the platform's trusted certs, as implemented by
30    /// rustls-native-certs
31    ///
32    /// This will return an error if no valid certs were found. In that case,
33    /// it's recommended to use `with_webpki_roots`.
34    #[cfg(feature = "rustls-native-certs")]
35    fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error>;
36
37    /// This configures the webpki roots, which are Mozilla's set of
38    /// trusted roots as packaged by webpki-roots.
39    #[cfg(feature = "webpki-roots")]
40    fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
41}
42
43impl ConfigBuilderExt for ConfigBuilder<ClientConfig, WantsVerifier> {
44    #[cfg(feature = "rustls-platform-verifier")]
45    fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
46        let provider = self.crypto_provider().clone();
47        self.dangerous()
48            .with_custom_certificate_verifier(Arc::new(
49                rustls_platform_verifier::Verifier::new().with_provider(provider),
50            ))
51    }
52
53    #[cfg(feature = "rustls-native-certs")]
54    #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
55    fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error> {
56        let mut roots = rustls::RootCertStore::empty();
57        let mut valid_count = 0;
58        let mut invalid_count = 0;
59
60        let CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs();
61        if !errors.is_empty() {
62            crate::log::warn!("native root CA certificate loading errors: {errors:?}");
63        }
64
65        if certs.is_empty() {
66            return Err(io::Error::new(
67                io::ErrorKind::NotFound,
68                format!("no native root CA certificates found (errors: {errors:?})"),
69            ));
70        }
71
72        for cert in certs {
73            match roots.add(cert) {
74                Ok(_) => valid_count += 1,
75                Err(err) => {
76                    crate::log::debug!("certificate parsing failed: {:?}", err);
77                    invalid_count += 1
78                }
79            }
80        }
81
82        crate::log::debug!(
83            "with_native_roots processed {} valid and {} invalid certs",
84            valid_count,
85            invalid_count
86        );
87        if roots.is_empty() {
88            crate::log::debug!("no valid native root CA certificates found");
89            Err(io::Error::new(
90                io::ErrorKind::NotFound,
91                format!("no valid native root CA certificates found ({invalid_count} invalid)"),
92            ))?
93        }
94
95        Ok(self.with_root_certificates(roots))
96    }
97
98    #[cfg(feature = "webpki-roots")]
99    fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
100        let mut roots = rustls::RootCertStore::empty();
101        roots.extend(
102            webpki_roots::TLS_SERVER_ROOTS
103                .iter()
104                .cloned(),
105        );
106        self.with_root_certificates(roots)
107    }
108}