#[cfg(feature = "rustls-native-certs")] use std::io; #[cfg(any( feature = "rustls-platform-verifier", feature = "rustls-native-certs", feature = "webpki-roots" ))] use rustls::client::WantsClientCert; use rustls::{ClientConfig, ConfigBuilder, WantsVerifier}; #[cfg(feature = "rustls-native-certs")] use rustls_native_certs::CertificateResult; #[cfg(feature = "rustls-platform-verifier")] use rustls_platform_verifier::BuilderVerifierExt; /// Methods for configuring roots /// /// This adds methods (gated by crate features) for easily configuring /// TLS server roots a rustls ClientConfig will trust. pub trait ConfigBuilderExt: sealed::Sealed { /// Use the platform's native verifier to verify server certificates. /// /// See the documentation for [rustls-platform-verifier] for more details. /// /// # Panics /// /// Since 0.27.7, this method will panic if the platform verifier cannot be initialized. /// Use `try_with_platform_verifier()` instead to handle errors gracefully. /// /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier #[deprecated(since = "0.27.7", note = "use `try_with_platform_verifier` instead")] #[cfg(feature = "rustls-platform-verifier")] fn with_platform_verifier(self) -> ConfigBuilder; /// Use the platform's native verifier to verify server certificates. /// /// See the documentation for [rustls-platform-verifier] for more details. /// /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier #[cfg(feature = "rustls-platform-verifier")] fn try_with_platform_verifier( self, ) -> Result, rustls::Error>; /// This configures the platform's trusted certs, as implemented by /// rustls-native-certs /// /// This will return an error if no valid certs were found. In that case, /// it's recommended to use `with_webpki_roots`. #[cfg(feature = "rustls-native-certs")] fn with_native_roots(self) -> Result, io::Error>; /// This configures the webpki roots, which are Mozilla's set of /// trusted roots as packaged by webpki-roots. #[cfg(feature = "webpki-roots")] fn with_webpki_roots(self) -> ConfigBuilder; } impl ConfigBuilderExt for ConfigBuilder { #[cfg(feature = "rustls-platform-verifier")] fn with_platform_verifier(self) -> ConfigBuilder { self.try_with_platform_verifier() .expect("failure to initialize platform verifier") } #[cfg(feature = "rustls-platform-verifier")] fn try_with_platform_verifier( self, ) -> Result, rustls::Error> { BuilderVerifierExt::with_platform_verifier(self) } #[cfg(feature = "rustls-native-certs")] #[cfg_attr(not(feature = "logging"), allow(unused_variables))] fn with_native_roots(self) -> Result, io::Error> { let mut roots = rustls::RootCertStore::empty(); let mut valid_count = 0; let mut invalid_count = 0; let CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs(); if !errors.is_empty() { crate::log::warn!("native root CA certificate loading errors: {errors:?}"); } if certs.is_empty() { return Err(io::Error::new( io::ErrorKind::NotFound, format!("no native root CA certificates found (errors: {errors:?})"), )); } for cert in certs { match roots.add(cert) { Ok(_) => valid_count += 1, Err(err) => { crate::log::debug!("certificate parsing failed: {:?}", err); invalid_count += 1 } } } crate::log::debug!( "with_native_roots processed {} valid and {} invalid certs", valid_count, invalid_count ); if roots.is_empty() { crate::log::debug!("no valid native root CA certificates found"); Err(io::Error::new( io::ErrorKind::NotFound, format!("no valid native root CA certificates found ({invalid_count} invalid)"), ))? } Ok(self.with_root_certificates(roots)) } #[cfg(feature = "webpki-roots")] fn with_webpki_roots(self) -> ConfigBuilder { let mut roots = rustls::RootCertStore::empty(); roots.extend( webpki_roots::TLS_SERVER_ROOTS .iter() .cloned(), ); self.with_root_certificates(roots) } } mod sealed { use super::*; pub trait Sealed {} impl Sealed for ConfigBuilder {} }