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
16pub trait ConfigBuilderExt: sealed::Sealed {
21 #[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 #[cfg(feature = "rustls-platform-verifier")]
41 fn try_with_platform_verifier(
42 self,
43 ) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, rustls::Error>;
44
45 #[cfg(feature = "rustls-native-certs")]
51 fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error>;
52
53 #[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}