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 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}