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        self.dangerous()
47            .with_custom_certificate_verifier(Arc::new(
48                rustls_platform_verifier::Verifier::default(),
49            ))
50    }
51
52    #[cfg(feature = "rustls-native-certs")]
53    #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
54    fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error> {
55        let mut roots = rustls::RootCertStore::empty();
56        let mut valid_count = 0;
57        let mut invalid_count = 0;
58
59        let CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs();
60        if !errors.is_empty() {
61            crate::log::warn!("native root CA certificate loading errors: {errors:?}");
62        }
63
64        if certs.is_empty() {
65            return Err(io::Error::new(
66                io::ErrorKind::NotFound,
67                format!("no native root CA certificates found (errors: {errors:?})"),
68            ));
69        }
70
71        for cert in certs {
72            match roots.add(cert) {
73                Ok(_) => valid_count += 1,
74                Err(err) => {
75                    crate::log::debug!("certificate parsing failed: {:?}", err);
76                    invalid_count += 1
77                }
78            }
79        }
80
81        crate::log::debug!(
82            "with_native_roots processed {} valid and {} invalid certs",
83            valid_count,
84            invalid_count
85        );
86        if roots.is_empty() {
87            crate::log::debug!("no valid native root CA certificates found");
88            Err(io::Error::new(
89                io::ErrorKind::NotFound,
90                format!("no valid native root CA certificates found ({invalid_count} invalid)"),
91            ))?
92        }
93
94        Ok(self.with_root_certificates(roots))
95    }
96
97    #[cfg(feature = "webpki-roots")]
98    fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
99        let mut roots = rustls::RootCertStore::empty();
100        roots.extend(
101            webpki_roots::TLS_SERVER_ROOTS
102                .iter()
103                .cloned(),
104        );
105        self.with_root_certificates(roots)
106    }
107}