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
16pub trait ConfigBuilderExt {
21 #[cfg(feature = "rustls-platform-verifier")]
27 fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
28
29 #[cfg(feature = "rustls-native-certs")]
35 fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error>;
36
37 #[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}