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