| 1 | #[cfg (feature = "rustls-native-certs" )] |
| 2 | use std::io; |
| 3 | #[cfg (feature = "rustls-platform-verifier" )] |
| 4 | use std::sync::Arc; |
| 5 | |
| 6 | #[cfg (any( |
| 7 | feature = "rustls-platform-verifier" , |
| 8 | feature = "rustls-native-certs" , |
| 9 | feature = "webpki-roots" |
| 10 | ))] |
| 11 | use rustls::client::WantsClientCert; |
| 12 | use rustls::{ClientConfig, ConfigBuilder, WantsVerifier}; |
| 13 | #[cfg (feature = "rustls-native-certs" )] |
| 14 | use rustls_native_certs::CertificateResult; |
| 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. |
| 20 | pub trait ConfigBuilderExt { |
| 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 | /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier |
| 26 | #[cfg (feature = "rustls-platform-verifier" )] |
| 27 | fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert>; |
| 28 | |
| 29 | /// This configures the platform's trusted certs, as implemented by |
| 30 | /// rustls-native-certs |
| 31 | /// |
| 32 | /// This will return an error if no valid certs were found. In that case, |
| 33 | /// it's recommended to use `with_webpki_roots`. |
| 34 | #[cfg (feature = "rustls-native-certs" )] |
| 35 | fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error>; |
| 36 | |
| 37 | /// This configures the webpki roots, which are Mozilla's set of |
| 38 | /// trusted roots as packaged by webpki-roots. |
| 39 | #[cfg (feature = "webpki-roots" )] |
| 40 | fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert>; |
| 41 | } |
| 42 | |
| 43 | impl 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 | } |
| 109 | |