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 CaTlsConfig {
23 mode: Mode,
24 extra_roots: Vec<CertificateDer<'static>>,
25}
26
27#[deprecated(since = "1.0.0", note = "Renamed to `CaTlsConfig`")]
29pub type CaRootsConfig = CaTlsConfig;
30
31#[derive(derive_more::Debug, Clone)]
32enum Mode {
33 EmbeddedWebPki,
37 #[cfg(feature = "platform-verifier")]
41 System,
42 ExtraRootsOnly,
44 CustomServerCertVerifier {
46 #[debug("Arc<dyn Fn>")]
47 builder: ServerCertVerifierBuilder,
48 },
49 #[cfg(any(test, feature = "test-utils"))]
53 InsecureSkipVerify,
54}
55
56impl Default for CaTlsConfig {
57 fn default() -> Self {
58 Self {
59 mode: Mode::EmbeddedWebPki,
60 extra_roots: vec![],
61 }
62 }
63}
64
65impl CaTlsConfig {
66 #[cfg(feature = "platform-verifier")]
73 pub fn system() -> Self {
74 Self {
75 mode: Mode::System,
76 extra_roots: Vec::new(),
77 }
78 }
79
80 pub fn embedded() -> Self {
84 Self {
85 mode: Mode::EmbeddedWebPki,
86 extra_roots: Vec::new(),
87 }
88 }
89
90 #[cfg(any(test, feature = "test-utils"))]
94 pub fn insecure_skip_verify() -> Self {
95 Self {
96 mode: Mode::InsecureSkipVerify,
97 extra_roots: Vec::new(),
98 }
99 }
100
101 pub fn custom_roots(roots: impl IntoIterator<Item = CertificateDer<'static>>) -> Self {
103 Self {
104 mode: Mode::ExtraRootsOnly,
105 extra_roots: roots.into_iter().collect(),
106 }
107 }
108
109 #[deprecated(since = "1.0.0", note = "Renamed to `custom_roots`")]
111 pub fn custom(roots: impl IntoIterator<Item = CertificateDer<'static>>) -> Self {
112 Self::custom_roots(roots)
113 }
114
115 pub fn custom_server_cert_verifier(builder: ServerCertVerifierBuilder) -> Self {
142 Self {
143 mode: Mode::CustomServerCertVerifier { builder },
144 extra_roots: Vec::new(),
145 }
146 }
147
148 pub fn with_extra_roots(
152 mut self,
153 extra_roots: impl IntoIterator<Item = CertificateDer<'static>>,
154 ) -> Self {
155 self.extra_roots.extend(extra_roots);
156 self
157 }
158
159 pub fn server_cert_verifier(
161 &self,
162 crypto_provider: Arc<CryptoProvider>,
163 ) -> io::Result<Arc<dyn ServerCertVerifier>> {
164 Ok(match self.mode {
165 #[cfg(feature = "platform-verifier")]
166 Mode::System => {
167 #[cfg(not(target_os = "android"))]
168 let verifier = rustls_platform_verifier::Verifier::new_with_extra_roots(
169 self.extra_roots.clone(),
170 crypto_provider,
171 );
172 #[cfg(target_os = "android")]
173 let verifier = rustls_platform_verifier::Verifier::new(crypto_provider);
174 Arc::new(verifier.map_err(io::Error::other)?)
175 }
176 Mode::EmbeddedWebPki => {
177 let mut root_store = rustls::RootCertStore {
178 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
179 };
180 root_store.add_parsable_certificates(self.extra_roots.clone());
181 WebPkiServerVerifier::builder_with_provider(Arc::new(root_store), crypto_provider)
182 .build()
183 .map_err(io::Error::other)?
184 }
185 Mode::ExtraRootsOnly => {
186 let mut root_store = rustls::RootCertStore { roots: vec![] };
187 root_store.add_parsable_certificates(self.extra_roots.clone());
188 WebPkiServerVerifier::builder_with_provider(Arc::new(root_store), crypto_provider)
189 .build()
190 .map_err(io::Error::other)?
191 }
192 Mode::CustomServerCertVerifier { ref builder } => builder(crypto_provider)?,
193 #[cfg(any(test, feature = "test-utils"))]
194 Mode::InsecureSkipVerify => {
195 tracing::warn!(
196 "Insecure TLS config: server certificates will be trusted without verification"
197 );
198 Arc::new(no_cert_verifier::NoCertVerifier { crypto_provider })
199 }
200 })
201 }
202
203 pub fn client_config(&self, crypto_provider: Arc<CryptoProvider>) -> io::Result<ClientConfig> {
205 let verifier = self.server_cert_verifier(crypto_provider.clone())?;
206 let config = ClientConfig::builder_with_provider(crypto_provider)
207 .with_safe_default_protocol_versions()
208 .expect(
209 "configured crypto provider is missing support for required TLS protocol versions",
210 )
211 .dangerous()
212 .with_custom_certificate_verifier(verifier)
213 .with_no_client_auth();
214 Ok(config)
215 }
216}
217
218pub type ServerCertVerifierBuilder = Arc<
222 dyn Fn(Arc<CryptoProvider>) -> io::Result<Arc<dyn ServerCertVerifier>> + Send + Sync + 'static,
223>;
224
225#[cfg(feature = "tls-ring")]
229pub fn default_provider() -> Arc<CryptoProvider> {
230 Arc::new(rustls::crypto::ring::default_provider())
231}
232
233#[cfg(all(feature = "tls-aws-lc-rs", not(feature = "tls-ring")))]
237pub fn default_provider() -> Arc<CryptoProvider> {
238 Arc::new(rustls::crypto::aws_lc_rs::default_provider())
239}
240
241#[cfg(all(any(test, feature = "test-utils"), with_crypto_provider))]
245pub fn make_dangerous_client_config() -> ClientConfig {
246 CaTlsConfig::insecure_skip_verify()
247 .client_config(default_provider())
248 .expect("infallible")
249}
250
251#[cfg(any(test, feature = "test-utils"))]
252mod no_cert_verifier {
253 use std::sync::Arc;
254
255 use rustls::{
256 client::danger::{ServerCertVerified, ServerCertVerifier},
257 crypto::CryptoProvider,
258 pki_types::{CertificateDer, ServerName},
259 };
260
261 #[derive(Debug)]
263 pub(super) struct NoCertVerifier {
264 pub(super) crypto_provider: Arc<CryptoProvider>,
265 }
266
267 impl ServerCertVerifier for NoCertVerifier {
268 fn verify_server_cert(
269 &self,
270 _end_entity: &CertificateDer,
271 _intermediates: &[CertificateDer],
272 _server_name: &ServerName,
273 _ocsp_response: &[u8],
274 _now: rustls::pki_types::UnixTime,
275 ) -> Result<ServerCertVerified, rustls::Error> {
276 Ok(ServerCertVerified::assertion())
277 }
278
279 fn verify_tls12_signature(
280 &self,
281 _message: &[u8],
282 _cert: &CertificateDer<'_>,
283 _dss: &rustls::DigitallySignedStruct,
284 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
285 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
286 }
287
288 fn verify_tls13_signature(
289 &self,
290 _message: &[u8],
291 _cert: &CertificateDer<'_>,
292 _dss: &rustls::DigitallySignedStruct,
293 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
294 Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
295 }
296
297 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
298 self.crypto_provider
299 .signature_verification_algorithms
300 .supported_schemes()
301 }
302 }
303}