1use std::{io, sync::Arc};
4
5use rustls::{
6 client::{ClientConfig, WebPkiServerVerifier, danger::ServerCertVerifier},
7 crypto::CryptoProvider,
8};
9use webpki_types::CertificateDer;
10
11#[derive(Debug, Clone)]
22pub struct CaRootsConfig {
23 mode: Mode,
24 extra_roots: Vec<CertificateDer<'static>>,
25}
26
27#[derive(Debug, Clone)]
28enum Mode {
29 EmbeddedWebPki,
33 #[cfg(feature = "platform-verifier")]
37 System,
38 ExtraRootsOnly,
40 #[cfg(any(test, feature = "test-utils"))]
44 InsecureSkipVerify,
45}
46
47impl Default for CaRootsConfig {
48 fn default() -> Self {
49 Self {
50 mode: Mode::EmbeddedWebPki,
51 extra_roots: vec![],
52 }
53 }
54}
55
56impl CaRootsConfig {
57 #[cfg(feature = "platform-verifier")]
64 pub fn system() -> Self {
65 Self {
66 mode: Mode::System,
67 extra_roots: Vec::new(),
68 }
69 }
70
71 pub fn embedded() -> Self {
75 Self {
76 mode: Mode::EmbeddedWebPki,
77 extra_roots: Vec::new(),
78 }
79 }
80
81 #[cfg(any(test, feature = "test-utils"))]
85 pub fn insecure_skip_verify() -> Self {
86 Self {
87 mode: Mode::InsecureSkipVerify,
88 extra_roots: Vec::new(),
89 }
90 }
91
92 pub fn custom(roots: impl IntoIterator<Item = CertificateDer<'static>>) -> Self {
94 Self {
95 mode: Mode::ExtraRootsOnly,
96 extra_roots: roots.into_iter().collect(),
97 }
98 }
99
100 pub fn with_extra_roots(
102 mut self,
103 extra_roots: impl IntoIterator<Item = CertificateDer<'static>>,
104 ) -> Self {
105 self.extra_roots.extend(extra_roots);
106 self
107 }
108
109 pub fn server_cert_verifier(
111 &self,
112 crypto_provider: Arc<CryptoProvider>,
113 ) -> io::Result<Arc<dyn ServerCertVerifier>> {
114 Ok(match self.mode {
115 #[cfg(feature = "platform-verifier")]
116 Mode::System => {
117 #[cfg(not(target_os = "android"))]
118 let verifier = rustls_platform_verifier::Verifier::new_with_extra_roots(
119 self.extra_roots.clone(),
120 crypto_provider,
121 );
122 #[cfg(target_os = "android")]
123 let verifier = rustls_platform_verifier::Verifier::new(crypto_provider);
124 Arc::new(verifier.map_err(io::Error::other)?)
125 }
126
127 Mode::EmbeddedWebPki => {
128 let mut root_store = rustls::RootCertStore {
129 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
130 };
131 root_store.add_parsable_certificates(self.extra_roots.clone());
132 WebPkiServerVerifier::builder_with_provider(Arc::new(root_store), crypto_provider)
133 .build()
134 .map_err(io::Error::other)?
135 }
136 Mode::ExtraRootsOnly => {
137 let mut root_store = rustls::RootCertStore { roots: vec![] };
138 root_store.add_parsable_certificates(self.extra_roots.clone());
139 WebPkiServerVerifier::builder_with_provider(Arc::new(root_store), crypto_provider)
140 .build()
141 .map_err(io::Error::other)?
142 }
143 #[cfg(any(test, feature = "test-utils"))]
144 Mode::InsecureSkipVerify => Arc::new(self::no_cert_verifier::NoCertVerifier),
145 })
146 }
147
148 pub fn client_config(&self, crypto_provider: Arc<CryptoProvider>) -> io::Result<ClientConfig> {
150 let verifier = self.server_cert_verifier(crypto_provider.clone())?;
151 let config = ClientConfig::builder_with_provider(crypto_provider)
152 .with_safe_default_protocol_versions()
153 .expect("protocols supported by ring")
154 .dangerous()
155 .with_custom_certificate_verifier(verifier)
156 .with_no_client_auth();
157 Ok(config)
158 }
159}
160
161pub fn default_provider() -> Arc<CryptoProvider> {
165 Arc::new(rustls::crypto::ring::default_provider())
166}
167
168#[cfg(any(test, feature = "test-utils"))]
169mod no_cert_verifier {
170 use rustls::{
171 client::danger::{ServerCertVerified, ServerCertVerifier},
172 pki_types::{CertificateDer, ServerName},
173 };
174
175 #[derive(Debug)]
177 pub(super) struct NoCertVerifier;
178
179 impl ServerCertVerifier for NoCertVerifier {
180 fn verify_server_cert(
181 &self,
182 _end_entity: &CertificateDer,
183 _intermediates: &[CertificateDer],
184 _server_name: &ServerName,
185 _ocsp_response: &[u8],
186 _now: rustls::pki_types::UnixTime,
187 ) -> Result<ServerCertVerified, rustls::Error> {
188 Ok(ServerCertVerified::assertion())
189 }
190 fn verify_tls12_signature(
191 &self,
192 _message: &[u8],
193 _cert: &CertificateDer<'_>,
194 _dss: &rustls::DigitallySignedStruct,
195 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
196 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
197 }
198
199 fn verify_tls13_signature(
200 &self,
201 _message: &[u8],
202 _cert: &CertificateDer<'_>,
203 _dss: &rustls::DigitallySignedStruct,
204 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
205 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
206 }
207
208 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
209 super::default_provider()
210 .signature_verification_algorithms
211 .supported_schemes()
212 }
213 }
214}