hyper_rustls/
config.rs

1#[cfg(feature = "rustls-native-certs")]
2use std::io;
3
4#[cfg(any(
5    feature = "rustls-platform-verifier",
6    feature = "rustls-native-certs",
7    feature = "webpki-roots"
8))]
9use rustls::client::WantsClientCert;
10use rustls::{ClientConfig, ConfigBuilder, WantsVerifier};
11#[cfg(feature = "rustls-native-certs")]
12use rustls_native_certs::CertificateResult;
13#[cfg(feature = "rustls-platform-verifier")]
14use rustls_platform_verifier::BuilderVerifierExt;
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: sealed::Sealed {
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    /// # Panics
26    ///
27    /// Since 0.27.7, this method will panic if the platform verifier cannot be initialized.
28    /// Use `try_with_platform_verifier()` instead to handle errors gracefully.
29    ///
30    /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier
31    #[deprecated(since = "0.27.7", note = "use `try_with_platform_verifier` instead")]
32    #[cfg(feature = "rustls-platform-verifier")]
33    fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
34
35    /// Use the platform's native verifier to verify server certificates.
36    ///
37    /// See the documentation for [rustls-platform-verifier] for more details.
38    ///
39    /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier
40    #[cfg(feature = "rustls-platform-verifier")]
41    fn try_with_platform_verifier(
42        self,
43    ) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, rustls::Error>;
44
45    /// This configures the platform's trusted certs, as implemented by
46    /// rustls-native-certs
47    ///
48    /// This will return an error if no valid certs were found. In that case,
49    /// it's recommended to use `with_webpki_roots`.
50    #[cfg(feature = "rustls-native-certs")]
51    fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error>;
52
53    /// This configures the webpki roots, which are Mozilla's set of
54    /// trusted roots as packaged by webpki-roots.
55    #[cfg(feature = "webpki-roots")]
56    fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
57}
58
59impl ConfigBuilderExt for ConfigBuilder<ClientConfig, WantsVerifier> {
60    #[cfg(feature = "rustls-platform-verifier")]
61    fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
62        self.try_with_platform_verifier()
63            .expect("failure to initialize platform verifier")
64    }
65
66    #[cfg(feature = "rustls-platform-verifier")]
67    fn try_with_platform_verifier(
68        self,
69    ) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, rustls::Error> {
70        BuilderVerifierExt::with_platform_verifier(self)
71    }
72
73    #[cfg(feature = "rustls-native-certs")]
74    #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
75    fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error> {
76        let mut roots = rustls::RootCertStore::empty();
77        let mut valid_count = 0;
78        let mut invalid_count = 0;
79
80        let CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs();
81        if !errors.is_empty() {
82            crate::log::warn!("native root CA certificate loading errors: {errors:?}");
83        }
84
85        if certs.is_empty() {
86            return Err(io::Error::new(
87                io::ErrorKind::NotFound,
88                format!("no native root CA certificates found (errors: {errors:?})"),
89            ));
90        }
91
92        for cert in certs {
93            match roots.add(cert) {
94                Ok(_) => valid_count += 1,
95                Err(err) => {
96                    crate::log::debug!("certificate parsing failed: {:?}", err);
97                    invalid_count += 1
98                }
99            }
100        }
101
102        crate::log::debug!(
103            "with_native_roots processed {} valid and {} invalid certs",
104            valid_count,
105            invalid_count
106        );
107        if roots.is_empty() {
108            crate::log::debug!("no valid native root CA certificates found");
109            Err(io::Error::new(
110                io::ErrorKind::NotFound,
111                format!("no valid native root CA certificates found ({invalid_count} invalid)"),
112            ))?
113        }
114
115        Ok(self.with_root_certificates(roots))
116    }
117
118    #[cfg(feature = "webpki-roots")]
119    fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
120        let mut roots = rustls::RootCertStore::empty();
121        roots.extend(
122            webpki_roots::TLS_SERVER_ROOTS
123                .iter()
124                .cloned(),
125        );
126        self.with_root_certificates(roots)
127    }
128}
129
130mod sealed {
131    use super::*;
132
133    pub trait Sealed {}
134
135    impl Sealed for ConfigBuilder<ClientConfig, WantsVerifier> {}
136}