1#[cfg(feature = "rustls-tls")]
2pub mod rustls_tls {
3 use std::{
4 path::PathBuf,
5 sync::{Arc, RwLock},
6 time::{Duration, Instant},
7 };
8
9 #[cfg(feature = "webpki-roots")]
11 use hyper_rustls::ConfigBuilderExt;
12 use rustls::{
13 self, ClientConfig, DigitallySignedStruct, RootCertStore,
14 client::{
15 WebPkiServerVerifier,
16 danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
17 },
18 pki_types::{CertificateDer, InvalidDnsNameError, PrivateKeyDer, ServerName},
19 };
20 use thiserror::Error;
21
22 #[derive(Debug, Error)]
24 pub enum Error {
25 #[error("identity PEM is invalid: {0}")]
27 InvalidIdentityPem(#[source] rustls::pki_types::pem::Error),
28
29 #[error("identity PEM is missing a private key: the key must be PKCS8 or RSA/PKCS1")]
31 MissingPrivateKey,
32
33 #[error("identity PEM is missing certificate")]
35 MissingCertificate,
36
37 #[error("invalid private key: {0}")]
39 InvalidPrivateKey(#[source] rustls::Error),
40
41 #[error("unknown private key format")]
43 UnknownPrivateKeyFormat,
44
45 #[error("failed to add a root certificate: {0}")]
48 AddRootCertificate(#[source] Box<dyn std::error::Error + Send + Sync>),
49
50 #[error("no valid native root CA certificates found: {0}")]
52 NoValidNativeRootCA(#[source] std::io::Error),
53
54 #[error("invalid server name: {0}")]
56 InvalidServerName(#[source] InvalidDnsNameError),
57 }
58
59 pub fn rustls_client_config(
61 identity_pem: Option<&[u8]>,
62 root_certs: Option<&[Vec<u8>]>,
63 accept_invalid: bool,
64 ) -> Result<ClientConfig, Error> {
65 let config_builder = if let Some(certs) = root_certs {
66 ClientConfig::builder().with_root_certificates(root_store(certs)?)
67 } else {
68 #[cfg(feature = "webpki-roots")]
72 {
73 ClientConfig::builder().with_webpki_roots()
75 }
76 #[cfg(not(feature = "webpki-roots"))]
77 {
78 use rustls_platform_verifier::BuilderVerifierExt;
82 ClientConfig::builder()
83 .with_platform_verifier()
84 .map_err(|e| Error::AddRootCertificate(Box::new(e)))?
87 }
88 };
89
90 let mut client_config = if let Some((chain, pkey)) = identity_pem.map(client_auth).transpose()? {
91 config_builder
92 .with_client_auth_cert(chain, pkey)
93 .map_err(Error::InvalidPrivateKey)?
94 } else {
95 config_builder.with_no_client_auth()
96 };
97
98 if accept_invalid {
99 client_config
100 .dangerous()
101 .set_certificate_verifier(std::sync::Arc::new(NoCertificateVerification {}));
102 }
103 Ok(client_config)
104 }
105
106 fn root_store(root_certs: &[Vec<u8>]) -> Result<rustls::RootCertStore, Error> {
107 let mut root_store = rustls::RootCertStore::empty();
108 for der in root_certs {
109 root_store
110 .add(CertificateDer::from(der.to_owned()))
111 .map_err(|e| Error::AddRootCertificate(Box::new(e)))?;
112 }
113 Ok(root_store)
114 }
115
116 #[derive(Debug)]
129 pub(crate) struct ReloadingVerifier {
130 path: PathBuf,
131 inner: RwLock<(Arc<WebPkiServerVerifier>, Instant)>,
132 }
133
134 impl ReloadingVerifier {
135 const RELOAD_INTERVAL: Duration = Duration::from_secs(60);
136
137 pub(crate) fn new(path: PathBuf) -> Result<Self, Error> {
138 let verifier = Self::load(&path)?;
139 Ok(Self {
140 path,
141 inner: RwLock::new((verifier, Instant::now())),
142 })
143 }
144
145 fn load(path: &PathBuf) -> Result<Arc<WebPkiServerVerifier>, Error> {
146 let pem = std::fs::read(path).map_err(|e| Error::AddRootCertificate(Box::new(e)))?;
147 let ders = crate::config::certs(&pem).map_err(|e| Error::AddRootCertificate(Box::new(e)))?;
148 let mut store = RootCertStore::empty();
149 for der in ders {
150 store
151 .add(CertificateDer::from(der))
152 .map_err(|e| Error::AddRootCertificate(Box::new(e)))?;
153 }
154 WebPkiServerVerifier::builder(Arc::new(store))
155 .build()
156 .map_err(|e| Error::AddRootCertificate(Box::new(e)))
157 }
158
159 fn current(&self) -> Arc<WebPkiServerVerifier> {
160 {
161 let guard = self.inner.read().unwrap_or_else(|e| e.into_inner());
162 if guard.1.elapsed() < Self::RELOAD_INTERVAL {
163 return guard.0.clone();
164 }
165 }
166 let mut guard = self.inner.write().unwrap_or_else(|e| e.into_inner());
167 if guard.1.elapsed() < Self::RELOAD_INTERVAL {
168 return guard.0.clone();
169 }
170 if let Ok(fresh) = Self::load(&self.path) {
171 guard.0 = fresh;
172 } else {
173 tracing::warn!(path = ?self.path, "failed to reload CA bundle; keeping stale roots");
174 }
175 guard.1 = Instant::now();
176 guard.0.clone()
177 }
178 }
179
180 impl ServerCertVerifier for ReloadingVerifier {
181 fn verify_server_cert(
182 &self,
183 end_entity: &CertificateDer,
184 intermediates: &[CertificateDer],
185 server_name: &ServerName,
186 ocsp_response: &[u8],
187 now: rustls::pki_types::UnixTime,
188 ) -> Result<ServerCertVerified, rustls::Error> {
189 self.current()
190 .verify_server_cert(end_entity, intermediates, server_name, ocsp_response, now)
191 }
192
193 fn verify_tls12_signature(
194 &self,
195 message: &[u8],
196 cert: &CertificateDer,
197 dss: &DigitallySignedStruct,
198 ) -> Result<HandshakeSignatureValid, rustls::Error> {
199 self.current().verify_tls12_signature(message, cert, dss)
200 }
201
202 fn verify_tls13_signature(
203 &self,
204 message: &[u8],
205 cert: &CertificateDer,
206 dss: &DigitallySignedStruct,
207 ) -> Result<HandshakeSignatureValid, rustls::Error> {
208 self.current().verify_tls13_signature(message, cert, dss)
209 }
210
211 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
212 self.current().supported_verify_schemes()
213 }
214 }
215
216 #[cfg(test)]
217 mod tests {
218 use super::*;
219
220 const CA1: &str = "-----BEGIN CERTIFICATE-----
224MIIBgDCCASWgAwIBAgIUVrQf5d//S01a0fbXxYRIx9wc0VQwCgYIKoZIzj0EAwIw
225FDESMBAGA1UEAwwJdGVzdC1jYS0xMCAXDTI2MDMwNDEzMDk1MFoYDzIxMjYwMjA4
226MTMwOTUwWjAUMRIwEAYDVQQDDAl0ZXN0LWNhLTEwWTATBgcqhkjOPQIBBggqhkjO
227PQMBBwNCAARg57mWJPDsAIEQAgXqMOOfjMQP+PE9HqcZobycO8z94r/uRuV0wKx/
2280SvMsKFtnreut0bjgFtmZaWY+6d87Is9o1MwUTAdBgNVHQ4EFgQUjtGuhkM7LtHB
229gMPCJIxMwbY69OQwHwYDVR0jBBgwFoAUjtGuhkM7LtHBgMPCJIxMwbY69OQwDwYD
230VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEAj/WzNVJDg/cBtLqQVM77
231tkB+QyIXLG3Vi9Xj1YfW9QECIQDDFW8yFtgLeCg2Zhr4xQNq3/24r/01kI2rjFPO
232xBkDMw==
233-----END CERTIFICATE-----
234";
235 const CA2: &str = "-----BEGIN CERTIFICATE-----
236MIIBfjCCASWgAwIBAgIUZ7Qsiwan2joRz01p25/cy1XNNiwwCgYIKoZIzj0EAwIw
237FDESMBAGA1UEAwwJdGVzdC1jYS0yMCAXDTI2MDMwNDEzMDk1MFoYDzIxMjYwMjA4
238MTMwOTUwWjAUMRIwEAYDVQQDDAl0ZXN0LWNhLTIwWTATBgcqhkjOPQIBBggqhkjO
239PQMBBwNCAARJle2/yiOD5zp0UkjZg9Yy6ZHBItTLrqv/uzB2YMQg03frnqEUMzSV
240mFinosBcGpX/dPGfHNPhBMOpHmlocZu9o1MwUTAdBgNVHQ4EFgQUsqG0hSGDYsz2
241eGIsLIwJnCR5SFIwHwYDVR0jBBgwFoAUsqG0hSGDYsz2eGIsLIwJnCR5SFIwDwYD
242VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiApvLu9DIC3/K/+G9ooOm75
243a72Cjw62aM8NfPe7ILs8SgIgL0VHe6ksTyB176RECCm3MJVnlhOop6b1tNvxjrru
244FRU=
245-----END CERTIFICATE-----
246";
247
248 fn expire(v: &ReloadingVerifier) {
249 v.inner.write().unwrap().1 = Instant::now().checked_sub(Duration::from_secs(120)).unwrap();
252 }
253
254 #[test]
255 fn reloading_verifier() {
256 #[cfg(feature = "aws-lc-rs")]
257 let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
258
259 let file = tempfile::NamedTempFile::new().unwrap();
260 std::fs::write(file.path(), CA1).unwrap();
261
262 let verifier = ReloadingVerifier::new(file.path().to_path_buf()).unwrap();
263 let first = verifier.current();
264
265 std::fs::write(file.path(), CA2).unwrap();
267 assert!(Arc::ptr_eq(&verifier.current(), &first));
268
269 expire(&verifier);
271 let second = verifier.current();
272 assert!(!Arc::ptr_eq(&second, &first));
273
274 drop(file);
276 expire(&verifier);
277 assert!(Arc::ptr_eq(&verifier.current(), &second));
278 }
279 }
280
281 #[cfg(all(test, not(feature = "webpki-roots")))]
282 mod platform_verifier_tests {
283 use super::*;
284
285 #[test]
288 fn no_ca_falls_back_to_platform_verifier() {
289 #[cfg(feature = "aws-lc-rs")]
290 let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
291
292 rustls_client_config(None, None, false).expect("platform verifier config should build");
293 }
294 }
295
296 fn client_auth(data: &[u8]) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Error> {
297 use rustls::pki_types::pem::{self, SectionKind};
298
299 let mut cert_chain = Vec::new();
300 let mut pkcs8_key = None;
301 let mut pkcs1_key = None;
302 let mut sec1_key = None;
303 let mut reader = std::io::Cursor::new(data);
304 while let Some((kind, der)) = pem::from_buf(&mut reader).map_err(Error::InvalidIdentityPem)? {
305 match kind {
306 SectionKind::Certificate => cert_chain.push(der.into()),
307 SectionKind::PrivateKey => pkcs8_key = Some(PrivateKeyDer::Pkcs8(der.into())),
308 SectionKind::RsaPrivateKey => pkcs1_key = Some(PrivateKeyDer::Pkcs1(der.into())),
309 SectionKind::EcPrivateKey => sec1_key = Some(PrivateKeyDer::Sec1(der.into())),
310 _ => return Err(Error::UnknownPrivateKeyFormat),
311 }
312 }
313
314 let private_key = pkcs8_key
315 .or(pkcs1_key)
316 .or(sec1_key)
317 .ok_or(Error::MissingPrivateKey)?;
318 if cert_chain.is_empty() {
319 return Err(Error::MissingCertificate);
320 }
321 Ok((cert_chain, private_key))
322 }
323
324 #[derive(Debug)]
325 struct NoCertificateVerification {}
326
327 impl ServerCertVerifier for NoCertificateVerification {
328 fn verify_server_cert(
329 &self,
330 _end_entity: &CertificateDer,
331 _intermediates: &[CertificateDer],
332 _server_name: &ServerName,
333 _ocsp_response: &[u8],
334 _now: rustls::pki_types::UnixTime,
335 ) -> Result<ServerCertVerified, rustls::Error> {
336 tracing::warn!("Server cert bypassed");
337 Ok(ServerCertVerified::assertion())
338 }
339
340 fn verify_tls13_signature(
341 &self,
342 _message: &[u8],
343 _cert: &CertificateDer,
344 _dss: &DigitallySignedStruct,
345 ) -> Result<HandshakeSignatureValid, rustls::Error> {
346 Ok(HandshakeSignatureValid::assertion())
347 }
348
349 fn verify_tls12_signature(
350 &self,
351 _message: &[u8],
352 _cert: &CertificateDer,
353 _dss: &DigitallySignedStruct,
354 ) -> Result<HandshakeSignatureValid, rustls::Error> {
355 Ok(HandshakeSignatureValid::assertion())
356 }
357
358 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
359 use rustls::SignatureScheme;
360 vec![
361 SignatureScheme::RSA_PKCS1_SHA1,
362 SignatureScheme::ECDSA_SHA1_Legacy,
363 SignatureScheme::RSA_PKCS1_SHA256,
364 SignatureScheme::ECDSA_NISTP256_SHA256,
365 SignatureScheme::RSA_PKCS1_SHA384,
366 SignatureScheme::ECDSA_NISTP384_SHA384,
367 SignatureScheme::RSA_PKCS1_SHA512,
368 SignatureScheme::ECDSA_NISTP521_SHA512,
369 SignatureScheme::RSA_PSS_SHA256,
370 SignatureScheme::RSA_PSS_SHA384,
371 SignatureScheme::RSA_PSS_SHA512,
372 SignatureScheme::ED25519,
373 SignatureScheme::ED448,
374 ]
375 }
376 }
377}
378
379#[cfg(feature = "openssl-tls")]
380pub mod openssl_tls {
381 use openssl::{
382 pkey::PKey,
383 ssl::{SslConnector, SslConnectorBuilder, SslMethod},
384 x509::X509,
385 };
386 use thiserror::Error;
387
388 #[derive(Debug, Error)]
390 pub enum Error {
391 #[error("failed to create OpenSSL HTTPS connector: {0}")]
393 CreateHttpsConnector(#[source] openssl::error::ErrorStack),
394
395 #[error("failed to create OpenSSL SSL connector: {0}")]
397 CreateSslConnector(#[source] SslConnectorError),
398 }
399
400 #[derive(Debug, Error)]
402 pub enum SslConnectorError {
403 #[error("failed to build SslConnectorBuilder: {0}")]
405 CreateBuilder(#[source] openssl::error::ErrorStack),
406
407 #[error("failed to deserialize PEM-encoded chain of certificates: {0}")]
409 DeserializeCertificateChain(#[source] openssl::error::ErrorStack),
410
411 #[error("failed to deserialize PEM-encoded private key: {0}")]
413 DeserializePrivateKey(#[source] openssl::error::ErrorStack),
414
415 #[error("failed to set private key: {0}")]
417 SetPrivateKey(#[source] openssl::error::ErrorStack),
418
419 #[error("failed to get a leaf certificate, the certificate chain is empty")]
421 GetLeafCertificate,
422
423 #[error("failed to set the leaf certificate: {0}")]
425 SetLeafCertificate(#[source] openssl::error::ErrorStack),
426
427 #[error("failed to append a certificate to the chain: {0}")]
429 AppendCertificate(#[source] openssl::error::ErrorStack),
430
431 #[error("failed to deserialize DER-encoded root certificate: {0}")]
433 DeserializeRootCertificate(#[source] openssl::error::ErrorStack),
434
435 #[error("failed to add a root certificate: {0}")]
437 AddRootCertificate(#[source] openssl::error::ErrorStack),
438 }
439
440 pub fn ssl_connector_builder(
442 identity_pem: Option<&Vec<u8>>,
443 root_certs: Option<&Vec<Vec<u8>>>,
444 ) -> Result<SslConnectorBuilder, SslConnectorError> {
445 let mut builder =
446 SslConnector::builder(SslMethod::tls()).map_err(SslConnectorError::CreateBuilder)?;
447 if let Some(pem) = identity_pem {
448 let mut chain = X509::stack_from_pem(pem)
449 .map_err(SslConnectorError::DeserializeCertificateChain)?
450 .into_iter();
451 let leaf_cert = chain.next().ok_or(SslConnectorError::GetLeafCertificate)?;
452 builder
453 .set_certificate(&leaf_cert)
454 .map_err(SslConnectorError::SetLeafCertificate)?;
455 for cert in chain {
456 builder
457 .add_extra_chain_cert(cert)
458 .map_err(SslConnectorError::AppendCertificate)?;
459 }
460
461 let pkey = PKey::private_key_from_pem(pem).map_err(SslConnectorError::DeserializePrivateKey)?;
462 builder
463 .set_private_key(&pkey)
464 .map_err(SslConnectorError::SetPrivateKey)?;
465 }
466
467 if let Some(ders) = root_certs {
468 for der in ders {
469 let cert = X509::from_der(der).map_err(SslConnectorError::DeserializeRootCertificate)?;
470 builder
471 .cert_store_mut()
472 .add_cert(cert)
473 .map_err(SslConnectorError::AddRootCertificate)?;
474 }
475 }
476
477 Ok(builder)
478 }
479}