1use crate::crypto;
14use rustls::pki_types::pem::PemObject;
15use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime};
16use std::path::{Path, PathBuf};
17use std::sync::{Arc, RwLock};
18use std::{fs, io};
19
20#[cfg(all(
21 any(feature = "quinn", feature = "noq", feature = "quiche"),
22 any(feature = "aws-lc-rs", feature = "ring")
23))]
24use rustls::pki_types::PrivatePkcs8KeyDer;
25#[derive(Debug, thiserror::Error)]
30#[non_exhaustive]
31pub enum Error {
32 #[error("failed to open certificate file")]
34 Open(#[source] std::io::Error),
35
36 #[error("failed to read file")]
38 ReadFile(#[source] std::io::Error),
39
40 #[error("failed to read certificates")]
42 Read(#[source] rustls::pki_types::pem::Error),
43
44 #[error("failed to parse private key")]
46 Key(#[source] rustls::pki_types::pem::Error),
47
48 #[error("no certificates found")]
50 Empty,
51
52 #[error("no roots found in {}", .0.display())]
54 EmptyRoots(PathBuf),
55
56 #[error(
58 "no trusted roots: provide --client-tls-root, enable --client-tls-system-roots, or use --client-tls-fingerprint / --client-tls-disable-verify"
59 )]
60 NoRoots,
61
62 #[error("invalid TLS fingerprint (expected hex-encoded SHA-256)")]
64 Fingerprint(#[source] hex::FromHexError),
65
66 #[error("invalid TLS fingerprint length: expected 32 bytes (SHA-256), got {0}")]
68 FingerprintLength(usize),
69
70 #[error(
73 "--client-tls-fingerprint cannot be combined with --client-tls-root or --client-tls-system-roots: fingerprint pinning bypasses CA verification"
74 )]
75 FingerprintWithRoots,
76
77 #[error(
79 "--client-tls-disable-verify cannot be combined with --client-tls-fingerprint, --client-tls-root or --client-tls-system-roots: it accepts every certificate, so the trust material would be ignored"
80 )]
81 DisableVerifyWithTrust,
82
83 #[error("failed to add root certificate")]
85 AddRoot(#[source] rustls::Error),
86
87 #[cfg(target_os = "android")]
89 #[error("failed to initialize the Android platform verifier")]
90 AndroidInit(#[source] jni::errors::Error),
91
92 #[error("failed to configure client certificate")]
94 ClientAuth(#[source] rustls::Error),
95
96 #[error("both --client-tls-cert and --client-tls-key must be provided")]
98 IncompleteClientAuth,
99
100 #[error("must provide both cert and key")]
102 CertKeyCountMismatch,
103
104 #[error("must provide at least one cert/key pair or generate entry")]
106 NoCertSource,
107
108 #[error("private key {} doesn't match certificate {}", key.display(), cert.display())]
110 KeyMismatch {
111 key: PathBuf,
113 cert: PathBuf,
115 #[source]
117 source: rustls::Error,
118 },
119
120 #[error(transparent)]
122 Rustls(#[from] rustls::Error),
123
124 #[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
126 #[error("failed to build client certificate verifier")]
127 ClientVerifier(#[source] rustls::server::VerifierBuilderError),
128
129 #[error("failed to build server certificate verifier")]
131 ServerVerifier(#[source] rustls::client::VerifierBuilderError),
132
133 #[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
135 #[error(transparent)]
136 Rcgen(#[from] rcgen::Error),
137
138 #[error("no crypto provider available; enable aws-lc-rs or ring feature")]
140 NoCryptoProvider,
141}
142
143pub type Result<T> = std::result::Result<T, Error>;
145
146pub fn parse_fingerprint(value: &str) -> Result<[u8; 32]> {
148 let bytes = hex::decode(value.trim()).map_err(Error::Fingerprint)?;
149 bytes.try_into().map_err(|v: Vec<u8>| Error::FingerprintLength(v.len()))
150}
151
152pub(crate) fn read_certs(path: &Path) -> Result<Vec<CertificateDer<'static>>> {
154 let file = fs::File::open(path).map_err(Error::Open)?;
155 let mut reader = io::BufReader::new(file);
156 CertificateDer::pem_reader_iter(&mut reader)
157 .collect::<std::result::Result<_, _>>()
158 .map_err(Error::Read)
159}
160
161fn read_roots(paths: &[PathBuf]) -> Result<Vec<CertificateDer<'static>>> {
163 let mut roots = Vec::new();
164 for path in paths {
165 let certs = read_certs(path)?;
166 if certs.is_empty() {
167 return Err(Error::EmptyRoots(path.clone()));
168 }
169 roots.extend(certs);
170 }
171 Ok(roots)
172}
173
174#[serde_with::serde_as]
178#[derive(Clone, Default, Debug, clap::Args, serde::Serialize, serde::Deserialize)]
179#[serde(default, deny_unknown_fields)]
180#[group(id = "tls-client")]
181#[non_exhaustive]
182pub struct Client {
183 #[serde(skip_serializing_if = "Vec::is_empty")]
195 #[arg(id = "client-tls-root", long = "client-tls-root", env = "MOQ_CLIENT_TLS_ROOT")]
196 #[serde_as(as = "serde_with::OneOrMany<_>")]
197 pub root: Vec<PathBuf>,
198
199 #[serde(skip_serializing_if = "Option::is_none")]
206 #[arg(
207 id = "client-tls-system-roots",
208 long = "client-tls-system-roots",
209 env = "MOQ_CLIENT_TLS_SYSTEM_ROOTS",
210 default_missing_value = "true",
211 num_args = 0..=1,
212 require_equals = true,
213 value_parser = clap::value_parser!(bool),
214 )]
215 pub system_roots: Option<bool>,
216
217 #[serde(skip_serializing_if = "Vec::is_empty")]
228 #[arg(
229 id = "client-tls-fingerprint",
230 long = "client-tls-fingerprint",
231 env = "MOQ_CLIENT_TLS_FINGERPRINT"
232 )]
233 #[serde_as(as = "serde_with::OneOrMany<_>")]
234 pub fingerprint: Vec<String>,
235
236 #[serde(skip_serializing_if = "Option::is_none")]
241 #[arg(id = "client-tls-cert", long = "client-tls-cert", env = "MOQ_CLIENT_TLS_CERT")]
242 pub cert: Option<PathBuf>,
243
244 #[serde(skip_serializing_if = "Option::is_none")]
249 #[arg(id = "client-tls-key", long = "client-tls-key", env = "MOQ_CLIENT_TLS_KEY")]
250 pub key: Option<PathBuf>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
256 #[arg(
257 id = "client-tls-disable-verify",
258 long = "client-tls-disable-verify",
259 env = "MOQ_CLIENT_TLS_DISABLE_VERIFY",
260 default_missing_value = "true",
261 num_args = 0..=1,
262 require_equals = true,
263 value_parser = clap::value_parser!(bool),
264 )]
265 pub disable_verify: Option<bool>,
266
267 #[serde(skip_serializing_if = "Option::is_none")]
272 #[arg(
273 id = "client-tls-host-name",
274 long = "client-tls-host-name",
275 env = "MOQ_CLIENT_TLS_HOST_NAME"
276 )]
277 pub host_name: Option<String>,
278
279 #[command(flatten)]
283 #[serde(skip)]
284 deprecated: Deprecated,
285}
286
287#[derive(Clone, Default, Debug, clap::Args)]
292struct Deprecated {
293 #[arg(long = "tls-root", hide = true)]
294 root: Vec<PathBuf>,
295
296 #[arg(
297 long = "tls-system-roots",
298 hide = true,
299 default_missing_value = "true",
300 num_args = 0..=1,
301 require_equals = true,
302 value_parser = clap::value_parser!(bool),
303 )]
304 system_roots: Option<bool>,
305
306 #[arg(long = "tls-fingerprint", hide = true)]
307 fingerprint: Vec<String>,
308
309 #[arg(
310 long = "tls-disable-verify",
311 hide = true,
312 default_missing_value = "true",
313 num_args = 0..=1,
314 require_equals = true,
315 value_parser = clap::value_parser!(bool),
316 )]
317 disable_verify: Option<bool>,
318}
319
320#[derive(Clone)]
327pub(crate) struct CustomRoots {
328 paths: Vec<PathBuf>,
329 current: Arc<RwLock<Vec<CertificateDer<'static>>>>,
330}
331
332impl CustomRoots {
333 fn new(paths: Vec<PathBuf>) -> Result<Self> {
334 let current = read_roots(&paths)?;
335 Ok(Self {
336 paths,
337 current: Arc::new(RwLock::new(current)),
338 })
339 }
340
341 fn load(&self) -> Result<Vec<CertificateDer<'static>>> {
342 read_roots(&self.paths)
343 }
344
345 fn replace(&self, roots: Vec<CertificateDer<'static>>) {
346 *self.current.write().unwrap_or_else(std::sync::PoisonError::into_inner) = roots;
347 }
348
349 pub(crate) fn current(&self) -> Vec<CertificateDer<'static>> {
350 self.current
351 .read()
352 .unwrap_or_else(std::sync::PoisonError::into_inner)
353 .clone()
354 }
355
356 #[cfg(feature = "quiche")]
358 pub(crate) fn refresh(&self) -> Vec<CertificateDer<'static>> {
359 self.refresh_with(|| self.load())
360 }
361
362 #[cfg(feature = "quiche")]
363 fn refresh_with(
364 &self,
365 load: impl FnOnce() -> Result<Vec<CertificateDer<'static>>>,
366 ) -> Vec<CertificateDer<'static>> {
367 let mut current = self.current.write().unwrap_or_else(std::sync::PoisonError::into_inner);
368 match load().and_then(|roots| {
369 root_store(&roots)?;
370 Ok(roots)
371 }) {
372 Ok(roots) => {
373 *current = roots.clone();
374 roots
375 }
376 Err(err) => {
377 tracing::warn!(%err, "failed to reload client root certificates; retaining previous roots");
378 current.clone()
379 }
380 }
381 }
382}
383
384#[cfg(feature = "watch")]
385struct ReloadState<T: ?Sized + Send + Sync + 'static> {
386 current: RwLock<Arc<T>>,
387 build: Box<dyn Fn() -> Result<Arc<T>> + Send + Sync>,
388 role: &'static str,
389}
390
391#[cfg(feature = "watch")]
392impl<T: ?Sized + Send + Sync + 'static> ReloadState<T> {
393 fn reload(&self) {
394 match (self.build)() {
395 Ok(next) => {
396 *self.current.write().unwrap_or_else(std::sync::PoisonError::into_inner) = next;
397 tracing::info!(role = self.role, "reloaded TLS root certificates");
398 }
399 Err(err) => {
400 tracing::warn!(%err, role = self.role, "failed to reload TLS root certificates; retaining previous roots");
401 }
402 }
403 }
404
405 fn current(&self) -> Arc<T> {
406 self.current
407 .read()
408 .unwrap_or_else(std::sync::PoisonError::into_inner)
409 .clone()
410 }
411}
412
413#[cfg(feature = "watch")]
415struct Reloading<T: ?Sized + Send + Sync + 'static> {
416 state: Arc<ReloadState<T>>,
417 _watcher: Option<notify::RecommendedWatcher>,
419}
420
421#[cfg(feature = "watch")]
422impl<T: ?Sized + Send + Sync + 'static> Reloading<T> {
423 fn new(
424 paths: &[PathBuf],
425 initial: Arc<T>,
426 role: &'static str,
427 build: impl Fn() -> Result<Arc<T>> + Send + Sync + 'static,
428 ) -> Self {
429 let state = Arc::new(ReloadState {
430 current: RwLock::new(initial),
431 build: Box::new(build),
432 role,
433 });
434
435 let reload = state.clone();
436 let watcher = match crate::watch::callback(paths, move || reload.reload()) {
437 Ok(watcher) => Some(watcher),
438 Err(err) => {
439 tracing::error!(%err, role, "failed to watch TLS root certificates; hot reload disabled");
440 None
441 }
442 };
443
444 Self {
445 state,
446 _watcher: watcher,
447 }
448 }
449
450 fn current(&self) -> Arc<T> {
451 self.state.current()
452 }
453}
454
455#[cfg(feature = "watch")]
456impl<T: ?Sized + Send + Sync + 'static> std::fmt::Debug for Reloading<T> {
457 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
458 f.debug_struct("Reloading").field("role", &self.state.role).finish()
459 }
460}
461
462#[derive(Clone)]
469pub(crate) enum Verification {
470 Disabled,
472
473 Fingerprints(Vec<[u8; 32]>),
476
477 Roots { custom: CustomRoots, system: bool },
482}
483
484impl Client {
485 pub(crate) fn warn_deprecated(&self) {
488 if !self.deprecated.root.is_empty() {
489 tracing::warn!("--tls-root is deprecated; use --client-tls-root");
490 }
491 if self.deprecated.system_roots.is_some() {
492 tracing::warn!("--tls-system-roots is deprecated; use --client-tls-system-roots");
493 }
494 if !self.deprecated.fingerprint.is_empty() {
495 tracing::warn!("--tls-fingerprint is deprecated; use --client-tls-fingerprint");
496 }
497 if self.deprecated.disable_verify.is_some() {
498 tracing::warn!("--tls-disable-verify is deprecated; use --client-tls-disable-verify");
499 }
500 }
501
502 pub(crate) fn effective_root(&self) -> Vec<PathBuf> {
504 let mut root = self.root.clone();
505 root.extend(self.deprecated.root.iter().cloned());
506 root
507 }
508
509 pub(crate) fn effective_fingerprint(&self) -> Vec<String> {
511 let mut fp = self.fingerprint.clone();
512 fp.extend(self.deprecated.fingerprint.iter().cloned());
513 fp
514 }
515
516 pub(crate) fn effective_system_roots(&self) -> Option<bool> {
518 self.system_roots.or(self.deprecated.system_roots)
519 }
520
521 pub(crate) fn effective_disable_verify(&self) -> Option<bool> {
523 self.disable_verify.or(self.deprecated.disable_verify)
524 }
525
526 pub(crate) fn verification(&self) -> Result<Verification> {
543 self.warn_deprecated();
544
545 let fingerprints = self.fingerprints()?;
546 let roots = self.effective_root();
547 let system_roots = self.effective_system_roots();
548
549 if self.effective_disable_verify().unwrap_or_default() {
550 if !fingerprints.is_empty() || !roots.is_empty() || system_roots == Some(true) {
551 return Err(Error::DisableVerifyWithTrust);
552 }
553 return Ok(Verification::Disabled);
554 }
555
556 if !fingerprints.is_empty() {
557 if !roots.is_empty() || system_roots == Some(true) {
558 return Err(Error::FingerprintWithRoots);
559 }
560 return Ok(Verification::Fingerprints(fingerprints));
561 }
562
563 let system = system_roots.unwrap_or(roots.is_empty());
566
567 let custom = CustomRoots::new(roots)?;
568
569 if !system && custom.current().is_empty() {
574 return Err(Error::NoRoots);
575 }
576
577 Ok(Verification::Roots { custom, system })
578 }
579
580 #[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
589 pub(crate) fn allows_http_bootstrap(&self) -> bool {
590 self.effective_fingerprint().is_empty() && !self.effective_disable_verify().unwrap_or_default()
591 }
592
593 fn fingerprints(&self) -> Result<Vec<[u8; 32]>> {
595 self.effective_fingerprint()
596 .iter()
597 .map(|fp| parse_fingerprint(fp))
598 .collect()
599 }
600
601 pub fn build(&self) -> Result<rustls::ClientConfig> {
606 let provider = crypto::provider();
607 let verification = self.verification()?;
608 let reloadable_roots = cfg!(feature = "watch")
609 && matches!(&verification, Verification::Roots { custom, .. } if !custom.paths.is_empty());
610
611 let builder = rustls::ClientConfig::builder_with_provider(provider.clone())
614 .with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])?;
615
616 let verifier: Arc<dyn rustls::client::danger::ServerCertVerifier> = match verification {
617 Verification::Disabled => {
618 tracing::warn!(
619 "TLS server certificate verification is disabled; A man-in-the-middle attack is possible."
620 );
621 Arc::new(NoCertificateVerification(provider))
622 }
623 Verification::Fingerprints(fingerprints) => {
624 let fingerprints = fingerprints.into_iter().map(|fp| fp.to_vec()).collect();
625 Arc::new(FingerprintVerifier::new(provider, fingerprints))
626 }
627 Verification::Roots { custom, system } => Self::root_server_verifier(custom, system, provider)?,
628 };
629
630 let builder = builder.dangerous().with_custom_certificate_verifier(verifier);
631 let mut tls = self.with_client_auth(builder)?;
632
633 if reloadable_roots {
637 tls.resumption = rustls::client::Resumption::disabled();
638 }
639
640 Ok(tls)
641 }
642
643 fn root_server_verifier(
651 custom: CustomRoots,
652 system: bool,
653 provider: crypto::Provider,
654 ) -> Result<Arc<dyn rustls::client::danger::ServerCertVerifier>> {
655 let initial = Self::build_root_server_verifier(&custom.current(), system, &provider)?;
656
657 #[cfg(feature = "watch")]
658 if !custom.paths.is_empty() {
659 let paths = custom.paths.clone();
660 let reload = custom.clone();
661 let reload_provider = provider.clone();
662 let verifier = ReloadingServerVerifier::new(&paths, initial, move || {
663 let roots = reload.load()?;
664 let verifier = Self::build_root_server_verifier(&roots, system, &reload_provider)?;
665 reload.replace(roots);
666 Ok(verifier)
667 });
668 return Ok(Arc::new(verifier));
669 }
670
671 Ok(initial)
672 }
673
674 fn build_root_server_verifier(
675 custom: &[CertificateDer<'static>],
676 system: bool,
677 provider: &crypto::Provider,
678 ) -> Result<Arc<dyn rustls::client::danger::ServerCertVerifier>> {
679 if !system {
680 let roots = root_store(custom)?;
681 let verifier =
682 rustls::client::WebPkiServerVerifier::builder_with_provider(Arc::new(roots), provider.clone())
683 .build()
684 .map_err(Error::ServerVerifier)?;
685 return Ok(verifier);
686 }
687
688 #[cfg(target_os = "android")]
693 {
694 if ANDROID_INITIALIZED.load(std::sync::atomic::Ordering::Acquire) && custom.is_empty() {
695 let verifier = rustls_platform_verifier::Verifier::new(provider.clone())?;
696 return Ok(Arc::new(verifier));
697 }
698
699 let mut roots = rustls::RootCertStore::empty();
700 roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
701 for cert in custom {
702 roots.add(cert.clone()).map_err(Error::AddRoot)?;
703 }
704 let verifier =
705 rustls::client::WebPkiServerVerifier::builder_with_provider(Arc::new(roots), provider.clone())
706 .build()
707 .map_err(Error::ServerVerifier)?;
708 Ok(verifier)
709 }
710
711 #[cfg(not(target_os = "android"))]
712 {
713 let verifier = if custom.is_empty() {
714 rustls_platform_verifier::Verifier::new(provider.clone())?
715 } else {
716 rustls_platform_verifier::Verifier::new_with_extra_roots(custom.iter().cloned(), provider.clone())?
717 };
718 Ok(Arc::new(verifier))
719 }
720 }
721
722 fn with_client_auth(
724 &self,
725 builder: rustls::ConfigBuilder<rustls::ClientConfig, rustls::client::WantsClientCert>,
726 ) -> Result<rustls::ClientConfig> {
727 Ok(match (&self.cert, &self.key) {
728 (Some(cert_path), Some(key_path)) => {
729 let cert_pem = fs::read(cert_path).map_err(Error::ReadFile)?;
730 let chain: Vec<CertificateDer<'static>> = CertificateDer::pem_slice_iter(&cert_pem)
731 .collect::<std::result::Result<_, _>>()
732 .map_err(Error::Read)?;
733 if chain.is_empty() {
734 return Err(Error::Empty);
735 }
736 let key_pem = fs::read(key_path).map_err(Error::ReadFile)?;
737 let key = PrivateKeyDer::from_pem_slice(&key_pem).map_err(Error::Key)?;
738 builder.with_client_auth_cert(chain, key).map_err(Error::ClientAuth)?
739 }
740 (None, None) => builder.with_no_client_auth(),
741 _ => return Err(Error::IncompleteClientAuth),
742 })
743 }
744}
745
746fn root_store(custom: &[CertificateDer<'static>]) -> Result<rustls::RootCertStore> {
748 let mut roots = rustls::RootCertStore::empty();
749 for cert in custom {
750 roots.add(cert.clone()).map_err(Error::AddRoot)?;
751 }
752 Ok(roots)
753}
754
755#[cfg(target_os = "android")]
757static ANDROID_INITIALIZED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
758
759#[cfg(target_os = "android")]
771pub fn init_android(env: &mut jni::Env, context: jni::objects::JObject) -> Result<()> {
772 rustls_platform_verifier::android::init_with_env(env, context).map_err(Error::AndroidInit)?;
773 ANDROID_INITIALIZED.store(true, std::sync::atomic::Ordering::Release);
774 Ok(())
775}
776
777#[serde_with::serde_as]
786#[derive(clap::Args, Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
787#[serde(deny_unknown_fields)]
788#[group(id = "tls-server")]
789#[non_exhaustive]
790pub struct Server {
791 #[arg(long = "tls-cert", id = "tls-cert", env = "MOQ_SERVER_TLS_CERT")]
793 #[serde(default, skip_serializing_if = "Vec::is_empty")]
794 #[serde_as(as = "serde_with::OneOrMany<_>")]
795 pub cert: Vec<PathBuf>,
796
797 #[arg(long = "tls-key", id = "tls-key", env = "MOQ_SERVER_TLS_KEY")]
799 #[serde(default, skip_serializing_if = "Vec::is_empty")]
800 #[serde_as(as = "serde_with::OneOrMany<_>")]
801 pub key: Vec<PathBuf>,
802
803 #[arg(
806 long = "tls-generate",
807 id = "tls-generate",
808 value_delimiter = ',',
809 env = "MOQ_SERVER_TLS_GENERATE"
810 )]
811 #[serde(default, skip_serializing_if = "Vec::is_empty")]
812 #[serde_as(as = "serde_with::OneOrMany<_>")]
813 pub generate: Vec<String>,
814
815 #[arg(
827 long = "server-tls-root",
828 id = "server-tls-root",
829 value_delimiter = ',',
830 env = "MOQ_SERVER_TLS_ROOT"
831 )]
832 #[serde(default, skip_serializing_if = "Vec::is_empty")]
833 #[serde_as(as = "serde_with::OneOrMany<_>")]
834 pub root: Vec<PathBuf>,
835}
836
837impl Server {
838 #[cfg(feature = "watch")]
840 pub(crate) fn disable_resumption(&self, tls: &mut rustls::ServerConfig) {
841 if !self.root.is_empty() {
842 tls.session_storage = Arc::new(rustls::server::NoServerSessionStorage {});
843 tls.send_tls13_tickets = 0;
844 }
845 }
846
847 pub fn load_roots(&self) -> Result<rustls::RootCertStore> {
849 root_store(&read_roots(&self.root)?)
850 }
851
852 #[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
854 pub(crate) fn client_verifier(
855 &self,
856 provider: crypto::Provider,
857 ) -> Result<Arc<dyn rustls::server::danger::ClientCertVerifier>> {
858 let initial = Self::build_client_verifier(&self.root, &provider)?;
859
860 #[cfg(feature = "watch")]
861 {
862 let paths = self.root.clone();
863 let reload_paths = paths.clone();
864 let reload_provider = provider.clone();
865 let verifier = ReloadingClientVerifier::new(&paths, initial, move || {
866 Self::build_client_verifier(&reload_paths, &reload_provider)
867 });
868 Ok(Arc::new(verifier))
869 }
870
871 #[cfg(not(feature = "watch"))]
872 Ok(initial)
873 }
874
875 #[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
876 fn build_client_verifier(
877 paths: &[PathBuf],
878 provider: &crypto::Provider,
879 ) -> Result<Arc<dyn rustls::server::danger::ClientCertVerifier>> {
880 let roots = root_store(&read_roots(paths)?)?;
881 rustls::server::WebPkiClientVerifier::builder_with_provider(Arc::new(roots), provider.clone())
882 .allow_unauthenticated()
883 .build()
884 .map_err(Error::ClientVerifier)
885 }
886
887 #[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
896 pub fn server_config(&self, alpn: Vec<Vec<u8>>) -> Result<Arc<rustls::ServerConfig>> {
897 server_config(self, alpn)
898 }
899}
900
901#[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
903fn server_config(config: &Server, alpn: Vec<Vec<u8>>) -> Result<Arc<rustls::ServerConfig>> {
904 let provider = crypto::provider();
905
906 let certs = ServeCerts::new(provider.clone());
907 certs.load_certs(config)?;
908 let certs = Arc::new(certs);
909
910 let builder =
912 rustls::ServerConfig::builder_with_provider(provider.clone()).with_safe_default_protocol_versions()?;
913
914 let mut tls = if config.root.is_empty() {
915 builder.with_no_client_auth().with_cert_resolver(certs)
916 } else {
917 let verifier = config.client_verifier(provider)?;
918 builder.with_client_cert_verifier(verifier).with_cert_resolver(certs)
919 };
920
921 tls.alpn_protocols = alpn;
922 config.disable_resumption(&mut tls);
923 Ok(Arc::new(tls))
924}
925
926#[derive(Clone)]
933pub struct PeerIdentity {
934 chain: Vec<CertificateDer<'static>>,
935}
936
937impl PeerIdentity {
938 #[cfg(any(feature = "quinn", feature = "noq"))]
942 pub(crate) fn from_any(identity: Option<Box<dyn std::any::Any>>) -> Option<Self> {
943 let chain = identity?.downcast::<Vec<CertificateDer<'static>>>().ok()?;
944 Some(Self { chain: *chain })
945 }
946
947 #[cfg(feature = "quiche")]
949 pub(crate) fn from_chain(chain: Vec<CertificateDer<'static>>) -> Self {
950 Self { chain }
951 }
952
953 pub fn chain(&self) -> &[CertificateDer<'static>] {
959 &self.chain
960 }
961
962 pub fn expiry(&self) -> Option<std::time::SystemTime> {
965 use std::time::{Duration, UNIX_EPOCH};
966
967 let leaf = self.chain.first()?;
968 let (_, cert) = x509_parser::parse_x509_certificate(leaf).ok()?;
969 let secs = u64::try_from(cert.validity().not_after.timestamp()).ok()?;
970 Some(UNIX_EPOCH + Duration::from_secs(secs))
971 }
972}
973
974#[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
978#[derive(Debug, Default)]
979pub(crate) struct Info {
980 pub(crate) certs: Vec<Arc<rustls::sign::CertifiedKey>>,
981 pub(crate) fingerprints: Vec<String>,
982}
983
984#[derive(Clone, Debug)]
990pub struct Certificates {
991 #[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
992 info: Arc<RwLock<Info>>,
993}
994
995impl Certificates {
996 #[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
997 pub(crate) fn new(info: Arc<RwLock<Info>>) -> Self {
998 Self { info }
999 }
1000
1001 pub(crate) fn empty() -> Self {
1003 Self {
1004 #[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
1005 info: Arc::new(RwLock::new(Info::default())),
1006 }
1007 }
1008
1009 pub fn fingerprints(&self) -> Vec<String> {
1015 #[cfg(any(feature = "noq", feature = "quinn", feature = "quiche"))]
1016 {
1017 let info = self.info.read().unwrap_or_else(std::sync::PoisonError::into_inner);
1020 info.fingerprints.clone()
1021 }
1022 #[cfg(not(any(feature = "noq", feature = "quinn", feature = "quiche")))]
1023 Vec::new()
1024 }
1025}
1026
1027#[cfg(feature = "watch")]
1029#[derive(Debug)]
1030struct ReloadingServerVerifier {
1031 inner: Reloading<dyn rustls::client::danger::ServerCertVerifier>,
1032}
1033
1034#[cfg(feature = "watch")]
1035impl ReloadingServerVerifier {
1036 fn new(
1037 paths: &[PathBuf],
1038 initial: Arc<dyn rustls::client::danger::ServerCertVerifier>,
1039 build: impl Fn() -> Result<Arc<dyn rustls::client::danger::ServerCertVerifier>> + Send + Sync + 'static,
1040 ) -> Self {
1041 Self {
1042 inner: Reloading::new(paths, initial, "client", build),
1043 }
1044 }
1045}
1046
1047#[cfg(feature = "watch")]
1048impl rustls::client::danger::ServerCertVerifier for ReloadingServerVerifier {
1049 fn verify_server_cert(
1050 &self,
1051 end_entity: &CertificateDer<'_>,
1052 intermediates: &[CertificateDer<'_>],
1053 server_name: &ServerName<'_>,
1054 ocsp_response: &[u8],
1055 now: UnixTime,
1056 ) -> std::result::Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
1057 self.inner
1058 .current()
1059 .verify_server_cert(end_entity, intermediates, server_name, ocsp_response, now)
1060 }
1061
1062 fn verify_tls12_signature(
1063 &self,
1064 message: &[u8],
1065 cert: &CertificateDer<'_>,
1066 dss: &rustls::DigitallySignedStruct,
1067 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1068 self.inner.current().verify_tls12_signature(message, cert, dss)
1069 }
1070
1071 fn verify_tls13_signature(
1072 &self,
1073 message: &[u8],
1074 cert: &CertificateDer<'_>,
1075 dss: &rustls::DigitallySignedStruct,
1076 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1077 self.inner.current().verify_tls13_signature(message, cert, dss)
1078 }
1079
1080 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
1081 self.inner.current().supported_verify_schemes()
1082 }
1083
1084 fn requires_raw_public_keys(&self) -> bool {
1085 self.inner.current().requires_raw_public_keys()
1086 }
1087}
1088
1089#[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1091#[derive(Debug)]
1092struct ReloadingClientVerifier {
1093 inner: Reloading<dyn rustls::server::danger::ClientCertVerifier>,
1094}
1095
1096#[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1097impl ReloadingClientVerifier {
1098 fn new(
1099 paths: &[PathBuf],
1100 initial: Arc<dyn rustls::server::danger::ClientCertVerifier>,
1101 build: impl Fn() -> Result<Arc<dyn rustls::server::danger::ClientCertVerifier>> + Send + Sync + 'static,
1102 ) -> Self {
1103 Self {
1104 inner: Reloading::new(paths, initial, "server", build),
1105 }
1106 }
1107}
1108
1109#[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1110impl rustls::server::danger::ClientCertVerifier for ReloadingClientVerifier {
1111 fn offer_client_auth(&self) -> bool {
1112 self.inner.current().offer_client_auth()
1113 }
1114
1115 fn client_auth_mandatory(&self) -> bool {
1116 self.inner.current().client_auth_mandatory()
1117 }
1118
1119 fn root_hint_subjects(&self) -> &[rustls::DistinguishedName] {
1120 &[]
1124 }
1125
1126 fn verify_client_cert(
1127 &self,
1128 end_entity: &CertificateDer<'_>,
1129 intermediates: &[CertificateDer<'_>],
1130 now: UnixTime,
1131 ) -> std::result::Result<rustls::server::danger::ClientCertVerified, rustls::Error> {
1132 self.inner.current().verify_client_cert(end_entity, intermediates, now)
1133 }
1134
1135 fn verify_tls12_signature(
1136 &self,
1137 message: &[u8],
1138 cert: &CertificateDer<'_>,
1139 dss: &rustls::DigitallySignedStruct,
1140 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1141 self.inner.current().verify_tls12_signature(message, cert, dss)
1142 }
1143
1144 fn verify_tls13_signature(
1145 &self,
1146 message: &[u8],
1147 cert: &CertificateDer<'_>,
1148 dss: &rustls::DigitallySignedStruct,
1149 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1150 self.inner.current().verify_tls13_signature(message, cert, dss)
1151 }
1152
1153 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
1154 self.inner.current().supported_verify_schemes()
1155 }
1156
1157 fn requires_raw_public_keys(&self) -> bool {
1158 self.inner.current().requires_raw_public_keys()
1159 }
1160}
1161
1162#[derive(Debug)]
1165struct NoCertificateVerification(crypto::Provider);
1166
1167impl rustls::client::danger::ServerCertVerifier for NoCertificateVerification {
1168 fn verify_server_cert(
1169 &self,
1170 _end_entity: &CertificateDer<'_>,
1171 _intermediates: &[CertificateDer<'_>],
1172 _server_name: &ServerName<'_>,
1173 _ocsp: &[u8],
1174 _now: UnixTime,
1175 ) -> std::result::Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
1176 Ok(rustls::client::danger::ServerCertVerified::assertion())
1177 }
1178
1179 fn verify_tls12_signature(
1180 &self,
1181 message: &[u8],
1182 cert: &CertificateDer<'_>,
1183 dss: &rustls::DigitallySignedStruct,
1184 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1185 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.0.signature_verification_algorithms)
1186 }
1187
1188 fn verify_tls13_signature(
1189 &self,
1190 message: &[u8],
1191 cert: &CertificateDer<'_>,
1192 dss: &rustls::DigitallySignedStruct,
1193 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1194 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.0.signature_verification_algorithms)
1195 }
1196
1197 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
1198 self.0.signature_verification_algorithms.supported_schemes()
1199 }
1200}
1201
1202#[derive(Debug)]
1205pub(crate) struct FingerprintVerifier {
1206 provider: crypto::Provider,
1207 fingerprints: Vec<Vec<u8>>,
1208}
1209
1210impl FingerprintVerifier {
1211 pub fn new(provider: crypto::Provider, fingerprints: Vec<Vec<u8>>) -> Self {
1212 Self { provider, fingerprints }
1213 }
1214}
1215
1216impl rustls::client::danger::ServerCertVerifier for FingerprintVerifier {
1217 fn verify_server_cert(
1218 &self,
1219 end_entity: &CertificateDer<'_>,
1220 _intermediates: &[CertificateDer<'_>],
1221 _server_name: &ServerName<'_>,
1222 _ocsp: &[u8],
1223 _now: UnixTime,
1224 ) -> std::result::Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
1225 let fingerprint = crypto::sha256(&self.provider, end_entity);
1226 if self.fingerprints.iter().any(|fp| fingerprint.as_ref() == fp.as_slice()) {
1227 Ok(rustls::client::danger::ServerCertVerified::assertion())
1228 } else {
1229 Err(rustls::Error::General("fingerprint mismatch".into()))
1230 }
1231 }
1232
1233 fn verify_tls12_signature(
1234 &self,
1235 message: &[u8],
1236 cert: &CertificateDer<'_>,
1237 dss: &rustls::DigitallySignedStruct,
1238 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1239 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.provider.signature_verification_algorithms)
1240 }
1241
1242 fn verify_tls13_signature(
1243 &self,
1244 message: &[u8],
1245 cert: &CertificateDer<'_>,
1246 dss: &rustls::DigitallySignedStruct,
1247 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
1248 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.provider.signature_verification_algorithms)
1249 }
1250
1251 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
1252 self.provider.signature_verification_algorithms.supported_schemes()
1253 }
1254}
1255
1256#[cfg(test)]
1257#[cfg(all(any(feature = "quinn", feature = "noq", feature = "quiche"), feature = "aws-lc-rs"))]
1258mod tests {
1259 #[test]
1262 fn disable_verify_rejects_trust_material() {
1263 let insecure = Client {
1264 disable_verify: Some(true),
1265 ..Default::default()
1266 };
1267 assert!(matches!(insecure.verification(), Ok(Verification::Disabled)));
1268
1269 let with_fingerprint = Client {
1270 disable_verify: Some(true),
1271 fingerprint: vec!["ab".repeat(32)],
1272 ..Default::default()
1273 };
1274 assert!(matches!(
1275 with_fingerprint.verification(),
1276 Err(Error::DisableVerifyWithTrust)
1277 ));
1278
1279 let with_root = Client {
1280 disable_verify: Some(true),
1281 root: vec!["/tmp/root.pem".into()],
1282 ..Default::default()
1283 };
1284 assert!(matches!(with_root.verification(), Err(Error::DisableVerifyWithTrust)));
1285
1286 let with_system_roots = Client {
1287 disable_verify: Some(true),
1288 system_roots: Some(true),
1289 ..Default::default()
1290 };
1291 assert!(matches!(
1292 with_system_roots.verification(),
1293 Err(Error::DisableVerifyWithTrust)
1294 ));
1295
1296 let without_system_roots = Client {
1297 disable_verify: Some(true),
1298 system_roots: Some(false),
1299 ..Default::default()
1300 };
1301 assert!(matches!(
1302 without_system_roots.verification(),
1303 Ok(Verification::Disabled)
1304 ));
1305 }
1306
1307 use super::*;
1308 use rustls::client::danger::ServerCertVerifier;
1309 use rustls::pki_types::ServerName;
1310 #[cfg(feature = "watch")]
1311 use rustls::server::danger::ClientCertVerifier;
1312
1313 fn self_signed() -> CertificateDer<'static> {
1314 let key = rcgen::KeyPair::generate().unwrap();
1315 let params = rcgen::CertificateParams::new(vec!["localhost".to_string()]).unwrap();
1316 params.self_signed(&key).unwrap().into()
1317 }
1318
1319 #[cfg(any(feature = "quinn", feature = "noq"))]
1320 #[test]
1321 fn peer_identity_expiry_reads_not_after() {
1322 let not_after = ::time::OffsetDateTime::from_unix_timestamp(2_000_000_000).unwrap();
1324
1325 let key = rcgen::KeyPair::generate().unwrap();
1326 let mut params = rcgen::CertificateParams::new(vec!["localhost".to_string()]).unwrap();
1327 params.not_after = not_after;
1328 let cert: CertificateDer<'static> = params.self_signed(&key).unwrap().into();
1329
1330 let identity: Box<dyn std::any::Any> = Box::new(vec![cert]);
1332 let parsed = PeerIdentity::from_any(Some(identity)).expect("chain parsed");
1333 let expiry = parsed.expiry().expect("expiry parsed");
1334 assert_eq!(
1335 expiry.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
1336 2_000_000_000
1337 );
1338 }
1339
1340 #[cfg(any(feature = "quinn", feature = "noq"))]
1341 #[test]
1342 fn peer_identity_none_without_chain() {
1343 assert!(PeerIdentity::from_any(None).is_none());
1344 let bogus: Box<dyn std::any::Any> = Box::new(42u32);
1346 assert!(PeerIdentity::from_any(Some(bogus)).is_none());
1347 }
1348
1349 #[test]
1350 fn fingerprint_verifier_matches_and_rejects() {
1351 let provider = crypto::provider();
1352 let cert = self_signed();
1353 let fingerprint = crypto::sha256(&provider, cert.as_ref()).as_ref().to_vec();
1354
1355 let name = ServerName::try_from("localhost").unwrap();
1356 let now = UnixTime::now();
1357
1358 let verifier = FingerprintVerifier::new(provider.clone(), vec![fingerprint]);
1359 assert!(verifier.verify_server_cert(&cert, &[], &name, &[], now).is_ok());
1360
1361 let other = self_signed();
1363 assert!(verifier.verify_server_cert(&other, &[], &name, &[], now).is_err());
1364 }
1365
1366 #[test]
1367 fn build_installs_fingerprint_verifier() {
1368 let cert = self_signed();
1369 let fingerprint = hex::encode(crypto::sha256(&crypto::provider(), cert.as_ref()));
1370
1371 let config = Client {
1373 fingerprint: vec![fingerprint],
1374 ..Default::default()
1375 };
1376 assert!(config.build().is_ok());
1377 }
1378
1379 #[test]
1380 fn build_rejects_invalid_fingerprint_hex() {
1381 let config = Client {
1382 fingerprint: vec!["not-hex".to_string()],
1383 ..Default::default()
1384 };
1385 assert!(matches!(config.build(), Err(Error::Fingerprint(_))));
1386 }
1387
1388 #[test]
1389 fn build_rejects_wrong_length_fingerprint() {
1390 let config = Client {
1392 fingerprint: vec!["abcd".to_string()],
1393 ..Default::default()
1394 };
1395 assert!(matches!(config.build(), Err(Error::FingerprintLength(2))));
1396 }
1397
1398 #[test]
1399 fn build_rejects_no_roots() {
1400 let config = Client {
1403 system_roots: Some(false),
1404 ..Default::default()
1405 };
1406 assert!(matches!(config.build(), Err(Error::NoRoots)));
1407 }
1408
1409 #[test]
1410 fn build_allows_no_roots_when_verification_overridden() {
1411 let config = Client {
1413 system_roots: Some(false),
1414 disable_verify: Some(true),
1415 ..Default::default()
1416 };
1417 assert!(config.build().is_ok());
1418
1419 let cert = self_signed();
1421 let fingerprint = hex::encode(crypto::sha256(&crypto::provider(), cert.as_ref()));
1422 let config = Client {
1423 system_roots: Some(false),
1424 fingerprint: vec![fingerprint],
1425 ..Default::default()
1426 };
1427 assert!(config.build().is_ok());
1428 }
1429
1430 #[test]
1431 fn build_rejects_fingerprint_with_roots() {
1432 let cert = self_signed();
1433 let fingerprint = hex::encode(crypto::sha256(&crypto::provider(), cert.as_ref()));
1434
1435 let with_system = Client {
1438 fingerprint: vec![fingerprint.clone()],
1439 system_roots: Some(true),
1440 ..Default::default()
1441 };
1442 assert!(matches!(with_system.build(), Err(Error::FingerprintWithRoots)));
1443
1444 let with_custom = Client {
1447 fingerprint: vec![fingerprint],
1448 root: vec![PathBuf::from("/does-not-exist.pem")],
1449 ..Default::default()
1450 };
1451 assert!(matches!(with_custom.build(), Err(Error::FingerprintWithRoots)));
1452 }
1453
1454 fn self_signed_root() -> (tempfile::NamedTempFile, PathBuf) {
1457 use std::io::Write;
1458 let key = rcgen::KeyPair::generate().unwrap();
1459 let params = rcgen::CertificateParams::new(vec!["localhost".to_string()]).unwrap();
1460 let cert = params.self_signed(&key).unwrap();
1461 let mut file = tempfile::NamedTempFile::new().unwrap();
1462 file.write_all(cert.pem().as_bytes()).unwrap();
1463 let path = file.path().to_path_buf();
1464 (file, path)
1465 }
1466
1467 #[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1468 fn signed_certificates() -> (
1469 String,
1470 CertificateDer<'static>,
1471 PrivateKeyDer<'static>,
1472 CertificateDer<'static>,
1473 PrivateKeyDer<'static>,
1474 ) {
1475 use rcgen::{BasicConstraints, ExtendedKeyUsagePurpose, IsCa, Issuer};
1476
1477 let ca_key = rcgen::KeyPair::generate().unwrap();
1478 let mut ca_params = rcgen::CertificateParams::new(Vec::<String>::new()).unwrap();
1479 ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
1480 let ca = ca_params.self_signed(&ca_key).unwrap();
1481 let issuer = Issuer::from_params(&ca_params, &ca_key);
1482
1483 let server_key = rcgen::KeyPair::generate().unwrap();
1484 let server_key_der = PrivatePkcs8KeyDer::from(server_key.serialize_der());
1485 let mut server_params = rcgen::CertificateParams::new(vec!["localhost".to_string()]).unwrap();
1486 server_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth];
1487 let server = server_params.signed_by(&server_key, &issuer).unwrap();
1488
1489 let client_key = rcgen::KeyPair::generate().unwrap();
1490 let client_key_der = PrivatePkcs8KeyDer::from(client_key.serialize_der());
1491 let mut client_params = rcgen::CertificateParams::new(Vec::<String>::new()).unwrap();
1492 client_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth];
1493 let client = client_params.signed_by(&client_key, &issuer).unwrap();
1494
1495 (
1496 ca.pem(),
1497 server.into(),
1498 server_key_der.into(),
1499 client.into(),
1500 client_key_der.into(),
1501 )
1502 }
1503
1504 #[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1505 fn handshake_kinds(
1506 client: Arc<rustls::ClientConfig>,
1507 server: Arc<rustls::ServerConfig>,
1508 ) -> std::result::Result<(rustls::HandshakeKind, rustls::HandshakeKind), rustls::Error> {
1509 let name = ServerName::try_from("localhost").unwrap();
1510 let mut client = rustls::ClientConnection::new(client, name).unwrap();
1511 let mut server = rustls::ServerConnection::new(server).unwrap();
1512
1513 for _ in 0..100 {
1514 let mut client_data = Vec::new();
1515 client.write_tls(&mut client_data).unwrap();
1516 if !client_data.is_empty() {
1517 server.read_tls(&mut client_data.as_slice()).unwrap();
1518 server.process_new_packets()?;
1519 }
1520
1521 let mut server_data = Vec::new();
1522 server.write_tls(&mut server_data).unwrap();
1523 if !server_data.is_empty() {
1524 client.read_tls(&mut server_data.as_slice()).unwrap();
1525 client.process_new_packets()?;
1526 }
1527
1528 if !client.is_handshaking() && !server.is_handshaking() && !client.wants_write() && !server.wants_write() {
1529 return Ok((client.handshake_kind().unwrap(), server.handshake_kind().unwrap()));
1530 }
1531 }
1532
1533 panic!("TLS handshake did not settle");
1534 }
1535
1536 #[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1537 #[test]
1538 fn reloadable_roots_disable_session_resumption() {
1539 use std::io::Write;
1540
1541 let (ca, server_cert, server_key, _, _) = signed_certificates();
1542 let mut root_file = tempfile::NamedTempFile::new().unwrap();
1543 root_file.write_all(ca.as_bytes()).unwrap();
1544 let roots = read_roots(&[root_file.path().to_path_buf()]).unwrap();
1545 let provider = crypto::provider();
1546
1547 let control = rustls::ClientConfig::builder_with_provider(provider.clone())
1548 .with_safe_default_protocol_versions()
1549 .unwrap()
1550 .with_root_certificates(root_store(&roots).unwrap())
1551 .with_no_client_auth();
1552 let reloadable = Client {
1553 root: vec![root_file.path().to_path_buf()],
1554 ..Default::default()
1555 }
1556 .build()
1557 .unwrap();
1558 let server = rustls::ServerConfig::builder_with_provider(provider)
1559 .with_safe_default_protocol_versions()
1560 .unwrap()
1561 .with_no_client_auth()
1562 .with_single_cert(vec![server_cert], server_key)
1563 .unwrap();
1564 let server = Arc::new(server);
1565
1566 let control = Arc::new(control);
1567 assert_eq!(
1568 handshake_kinds(control.clone(), server.clone()).unwrap().0,
1569 rustls::HandshakeKind::Full
1570 );
1571 assert_eq!(
1572 handshake_kinds(control, server.clone()).unwrap().0,
1573 rustls::HandshakeKind::Resumed
1574 );
1575
1576 let reloadable = Arc::new(reloadable);
1577 assert_eq!(
1578 handshake_kinds(reloadable.clone(), server.clone()).unwrap().0,
1579 rustls::HandshakeKind::Full
1580 );
1581 assert_eq!(
1582 handshake_kinds(reloadable, server).unwrap().0,
1583 rustls::HandshakeKind::Full
1584 );
1585 }
1586
1587 #[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1588 #[test]
1589 fn reloadable_client_roots_disable_server_resumption() {
1590 use std::io::Write;
1591
1592 let (ca_a, server_cert, server_key, client_cert, client_key) = signed_certificates();
1593 let (ca_b, _, _, _, _) = signed_certificates();
1594 let mut root_file = tempfile::NamedTempFile::new().unwrap();
1595 root_file.write_all(ca_a.as_bytes()).unwrap();
1596 let paths = vec![root_file.path().to_path_buf()];
1597 let provider = crypto::provider();
1598
1599 let build_client = |cert, key| {
1600 rustls::ClientConfig::builder_with_provider(provider.clone())
1601 .with_safe_default_protocol_versions()
1602 .unwrap()
1603 .dangerous()
1604 .with_custom_certificate_verifier(Arc::new(NoCertificateVerification(provider.clone())))
1605 .with_client_auth_cert(vec![cert], key)
1606 .unwrap()
1607 };
1608 let control_client = Arc::new(build_client(client_cert.clone(), client_key.clone_key()));
1609 let reloadable_client = Arc::new(build_client(client_cert, client_key));
1610
1611 let verifier = Server::build_client_verifier(&paths, &provider).unwrap();
1612 let control = rustls::ServerConfig::builder_with_provider(provider.clone())
1613 .with_safe_default_protocol_versions()
1614 .unwrap()
1615 .with_client_cert_verifier(verifier)
1616 .with_single_cert(vec![server_cert.clone()], server_key.clone_key())
1617 .unwrap();
1618
1619 let initial = Server::build_client_verifier(&paths, &provider).unwrap();
1620 let reload_paths = paths.clone();
1621 let reload_provider = provider.clone();
1622 let verifier = Arc::new(ReloadingClientVerifier::new(&paths, initial, move || {
1623 Server::build_client_verifier(&reload_paths, &reload_provider)
1624 }));
1625 let reload = verifier.inner.state.clone();
1626 let mut reloadable = rustls::ServerConfig::builder_with_provider(provider)
1627 .with_safe_default_protocol_versions()
1628 .unwrap()
1629 .with_client_cert_verifier(verifier)
1630 .with_single_cert(vec![server_cert], server_key)
1631 .unwrap();
1632 Server {
1633 root: paths,
1634 ..Default::default()
1635 }
1636 .disable_resumption(&mut reloadable);
1637
1638 let control = Arc::new(control);
1639 assert_eq!(
1640 handshake_kinds(control_client.clone(), control.clone()).unwrap().1,
1641 rustls::HandshakeKind::Full
1642 );
1643 assert_eq!(
1644 handshake_kinds(control_client, control).unwrap().1,
1645 rustls::HandshakeKind::Resumed
1646 );
1647
1648 let reloadable = Arc::new(reloadable);
1649 assert_eq!(
1650 handshake_kinds(reloadable_client.clone(), reloadable.clone())
1651 .unwrap()
1652 .1,
1653 rustls::HandshakeKind::Full
1654 );
1655
1656 std::fs::write(root_file.path(), ca_b).unwrap();
1657 reload.reload();
1658 assert!(handshake_kinds(reloadable_client, reloadable).is_err());
1659 }
1660
1661 #[cfg(all(feature = "watch", any(feature = "quinn", feature = "noq", feature = "quiche")))]
1662 #[test]
1663 fn custom_roots_reload_for_new_client_and_server_handshakes() {
1664 use std::io::Write;
1665
1666 let (ca_a, server_a, _, client_a, _) = signed_certificates();
1667 let (ca_b, server_b, _, client_b, _) = signed_certificates();
1668 let mut root_file = tempfile::NamedTempFile::new().unwrap();
1669 root_file.write_all(ca_a.as_bytes()).unwrap();
1670 let paths = vec![root_file.path().to_path_buf()];
1671 let provider = crypto::provider();
1672
1673 let custom = CustomRoots::new(paths.clone()).unwrap();
1674 let initial = Client::build_root_server_verifier(&custom.current(), false, &provider).unwrap();
1675 let reload_custom = custom.clone();
1676 let reload_provider = provider.clone();
1677 let server_verifier = ReloadingServerVerifier::new(&paths, initial, move || {
1678 let roots = reload_custom.load()?;
1679 let verifier = Client::build_root_server_verifier(&roots, false, &reload_provider)?;
1680 reload_custom.replace(roots);
1681 Ok(verifier)
1682 });
1683
1684 let initial = Server::build_client_verifier(&paths, &provider).unwrap();
1685 let reload_paths = paths.clone();
1686 let reload_provider = provider.clone();
1687 let client_verifier = ReloadingClientVerifier::new(&paths, initial, move || {
1688 Server::build_client_verifier(&reload_paths, &reload_provider)
1689 });
1690
1691 let name = ServerName::try_from("localhost").unwrap();
1692 let now = UnixTime::now();
1693 assert!(
1694 server_verifier
1695 .verify_server_cert(&server_a, &[], &name, &[], now)
1696 .is_ok()
1697 );
1698 assert!(
1699 server_verifier
1700 .verify_server_cert(&server_b, &[], &name, &[], now)
1701 .is_err()
1702 );
1703 assert!(client_verifier.verify_client_cert(&client_a, &[], now).is_ok());
1704 assert!(client_verifier.verify_client_cert(&client_b, &[], now).is_err());
1705
1706 std::fs::write(root_file.path(), ca_b).unwrap();
1707 server_verifier.inner.state.reload();
1708 client_verifier.inner.state.reload();
1709
1710 assert!(
1711 server_verifier
1712 .verify_server_cert(&server_a, &[], &name, &[], now)
1713 .is_err()
1714 );
1715 assert!(client_verifier.verify_client_cert(&client_a, &[], now).is_err());
1716
1717 std::fs::write(root_file.path(), "not a PEM certificate").unwrap();
1719 server_verifier.inner.state.reload();
1720 client_verifier.inner.state.reload();
1721 assert!(
1722 server_verifier
1723 .verify_server_cert(&server_b, &[], &name, &[], now)
1724 .is_ok()
1725 );
1726 assert!(client_verifier.verify_client_cert(&client_b, &[], now).is_ok());
1727 }
1728
1729 #[cfg(all(feature = "quiche", feature = "watch"))]
1730 #[test]
1731 fn custom_root_refresh_retains_last_valid_bundle() {
1732 use std::io::Write;
1733
1734 let (ca_a, _, _, _, _) = signed_certificates();
1735 let (ca_b, _, _, _, _) = signed_certificates();
1736 let mut root_file = tempfile::NamedTempFile::new().unwrap();
1737 root_file.write_all(ca_a.as_bytes()).unwrap();
1738 let roots = CustomRoots::new(vec![root_file.path().to_path_buf()]).unwrap();
1739 let initial = roots.current();
1740
1741 std::fs::write(root_file.path(), "not a PEM certificate").unwrap();
1742 assert_eq!(roots.refresh(), initial);
1743
1744 std::fs::write(
1745 root_file.path(),
1746 "-----BEGIN CERTIFICATE-----\nAQID\n-----END CERTIFICATE-----\n",
1747 )
1748 .unwrap();
1749 assert_eq!(roots.refresh(), initial);
1750
1751 std::fs::write(root_file.path(), ca_b).unwrap();
1752 let rotated = roots.refresh();
1753 assert_ne!(rotated, initial);
1754 assert_eq!(roots.current(), rotated);
1755 }
1756
1757 #[cfg(all(feature = "quiche", feature = "watch"))]
1758 #[test]
1759 fn custom_root_refresh_serializes_cache_updates() {
1760 let (ca_a, _, _, _, _) = signed_certificates();
1761 let (ca_b, _, _, _, _) = signed_certificates();
1762 let (ca_c, _, _, _, _) = signed_certificates();
1763 let parse = |pem: &str| {
1764 CertificateDer::pem_slice_iter(pem.as_bytes())
1765 .collect::<std::result::Result<Vec<_>, _>>()
1766 .unwrap()
1767 };
1768 let initial = parse(&ca_a);
1769 let bundle_b = parse(&ca_b);
1770 let bundle_c = parse(&ca_c);
1771 let roots = CustomRoots {
1772 paths: Vec::new(),
1773 current: Arc::new(RwLock::new(initial)),
1774 };
1775
1776 let (first_loaded_tx, first_loaded_rx) = std::sync::mpsc::sync_channel(0);
1777 let (release_first_tx, release_first_rx) = std::sync::mpsc::sync_channel(0);
1778 let first_roots = roots.clone();
1779 let first = std::thread::spawn(move || {
1780 first_roots.refresh_with(|| {
1781 first_loaded_tx.send(()).unwrap();
1782 release_first_rx.recv().unwrap();
1783 Ok(bundle_b)
1784 })
1785 });
1786 first_loaded_rx.recv().unwrap();
1787
1788 let (second_ready_tx, second_ready_rx) = std::sync::mpsc::sync_channel(0);
1789 let (second_loaded_tx, second_loaded_rx) = std::sync::mpsc::channel();
1790 let second_roots = roots.clone();
1791 let expected = bundle_c.clone();
1792 let second = std::thread::spawn(move || {
1793 second_ready_tx.send(()).unwrap();
1794 second_roots.refresh_with(|| {
1795 second_loaded_tx.send(()).unwrap();
1796 Ok(bundle_c)
1797 })
1798 });
1799 second_ready_rx.recv().unwrap();
1800 let overlapped = second_loaded_rx
1801 .recv_timeout(std::time::Duration::from_millis(100))
1802 .is_ok();
1803
1804 release_first_tx.send(()).unwrap();
1805 first.join().unwrap();
1806 second.join().unwrap();
1807 assert!(!overlapped, "root cache refresh transactions must not overlap");
1808 assert_eq!(roots.current(), expected);
1809 }
1810
1811 #[test]
1812 fn build_uses_platform_verifier_by_default() {
1813 assert!(Client::default().build().is_ok());
1816 }
1817
1818 #[test]
1819 fn build_with_custom_roots_only() {
1820 let (_keep, path) = self_signed_root();
1823 let config = Client {
1824 root: vec![path],
1825 ..Default::default()
1826 };
1827 assert!(config.build().is_ok());
1828 }
1829
1830 #[test]
1831 fn build_with_custom_and_system_roots() {
1832 let (_keep, path) = self_signed_root();
1835 let config = Client {
1836 root: vec![path],
1837 system_roots: Some(true),
1838 ..Default::default()
1839 };
1840 assert!(config.build().is_ok());
1841 }
1842}
1843
1844#[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
1847#[derive(Debug)]
1848pub(crate) struct ServeCerts {
1849 pub info: Arc<RwLock<Info>>,
1850 provider: crypto::Provider,
1851}
1852
1853#[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
1854impl ServeCerts {
1855 pub fn new(provider: crypto::Provider) -> Self {
1856 Self {
1857 info: Arc::new(RwLock::new(Info::default())),
1858 provider,
1859 }
1860 }
1861
1862 pub fn load_certs(&self, config: &Server) -> Result<()> {
1863 if config.cert.len() != config.key.len() {
1864 return Err(Error::CertKeyCountMismatch);
1865 }
1866 if config.cert.is_empty() && config.generate.is_empty() {
1867 return Err(Error::NoCertSource);
1868 }
1869
1870 let mut certs = Vec::new();
1871
1872 for (cert, key) in config.cert.iter().zip(config.key.iter()) {
1874 certs.push(Arc::new(self.load(cert, key)?));
1875 }
1876
1877 if !config.generate.is_empty() {
1879 certs.push(Arc::new(self.generate(&config.generate)?));
1880 }
1881
1882 self.set_certs(certs);
1883 Ok(())
1884 }
1885
1886 fn load(&self, chain_path: &Path, key_path: &Path) -> Result<rustls::sign::CertifiedKey> {
1888 let chain = read_certs(chain_path)?;
1889 if chain.is_empty() {
1890 return Err(Error::Empty);
1891 }
1892
1893 let key = PrivateKeyDer::from_pem_file(key_path).map_err(Error::Key)?;
1895 let key = self.provider.key_provider.load_private_key(key)?;
1896
1897 let certified_key = rustls::sign::CertifiedKey::new(chain, key);
1898
1899 certified_key.keys_match().map_err(|source| Error::KeyMismatch {
1900 key: key_path.to_path_buf(),
1901 cert: chain_path.to_path_buf(),
1902 source,
1903 })?;
1904
1905 Ok(certified_key)
1906 }
1907
1908 #[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
1909 fn generate(&self, hostnames: &[String]) -> Result<rustls::sign::CertifiedKey> {
1910 let key_pair = rcgen::KeyPair::generate()?;
1911
1912 let mut params = rcgen::CertificateParams::new(hostnames)?;
1913
1914 params.not_before = ::time::OffsetDateTime::now_utc() - ::time::Duration::days(1);
1917 params.not_after = params.not_before + ::time::Duration::days(14);
1918
1919 let cert = params.self_signed(&key_pair)?;
1921
1922 let key_der = key_pair.serialized_der().to_vec();
1924 let key_der = PrivatePkcs8KeyDer::from(key_der);
1925 let key = self.provider.key_provider.load_private_key(key_der.into())?;
1926
1927 Ok(rustls::sign::CertifiedKey::new(vec![cert.into()], key))
1929 }
1930
1931 #[cfg(not(any(feature = "aws-lc-rs", feature = "ring")))]
1932 fn generate(&self, _hostnames: &[String]) -> Result<rustls::sign::CertifiedKey> {
1933 Err(Error::NoCryptoProvider)
1934 }
1935
1936 pub fn set_certs(&self, certs: Vec<Arc<rustls::sign::CertifiedKey>>) {
1938 let fingerprints = certs
1939 .iter()
1940 .map(|ck| {
1941 let fingerprint = crate::crypto::sha256(&self.provider, ck.cert[0].as_ref());
1942 hex::encode(fingerprint)
1943 })
1944 .collect();
1945
1946 let mut info = self.info.write().expect("info write lock poisoned");
1947 info.certs = certs;
1948 info.fingerprints = fingerprints;
1949 }
1950
1951 fn best_certificate(
1953 &self,
1954 client_hello: &rustls::server::ClientHello<'_>,
1955 ) -> Option<Arc<rustls::sign::CertifiedKey>> {
1956 let server_name = client_hello.server_name()?;
1957 let dns_name = rustls::pki_types::ServerName::try_from(server_name).ok()?;
1958
1959 for ck in self.info.read().expect("info read lock poisoned").certs.iter() {
1960 let leaf: webpki::EndEntityCert = ck
1961 .end_entity_cert()
1962 .expect("missing certificate")
1963 .try_into()
1964 .expect("failed to parse certificate");
1965
1966 if leaf.verify_is_valid_for_subject_name(&dns_name).is_ok() {
1967 return Some(ck.clone());
1968 }
1969 }
1970
1971 None
1972 }
1973}
1974
1975#[cfg(any(feature = "quinn", feature = "noq", feature = "quiche"))]
1976impl rustls::server::ResolvesServerCert for ServeCerts {
1977 fn resolve(&self, client_hello: rustls::server::ClientHello<'_>) -> Option<Arc<rustls::sign::CertifiedKey>> {
1978 if let Some(cert) = self.best_certificate(&client_hello) {
1979 return Some(cert);
1980 }
1981
1982 tracing::warn!(server_name = ?client_hello.server_name(), "no SNI certificate found");
1985
1986 self.info
1987 .read()
1988 .expect("info read lock poisoned")
1989 .certs
1990 .first()
1991 .cloned()
1992 }
1993}
1994
1995#[cfg(any(feature = "quinn", feature = "noq"))]
2003pub(crate) async fn reload_certs(certs: Arc<ServeCerts>, tls_config: Server) {
2004 let paths: Vec<PathBuf> = tls_config.cert.iter().chain(tls_config.key.iter()).cloned().collect();
2005 if paths.is_empty() {
2006 return;
2007 }
2008
2009 let mut watcher = match crate::watch::FileWatcher::new(&paths) {
2010 Ok(watcher) => watcher,
2011 Err(err) => {
2012 tracing::error!(%err, "failed to watch certificate files; hot reload disabled");
2013 return;
2014 }
2015 };
2016
2017 loop {
2018 watcher.changed().await;
2019 tracing::info!("reloading server certificates");
2020
2021 if let Err(err) = certs.load_certs(&tls_config) {
2022 tracing::warn!(%err, "failed to reload server certificates");
2023 }
2024 }
2025}