From 163c801aa8ecbc5b037a8c19267893a2bc636f87 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Mon, 25 Nov 2024 10:43:05 +0100 Subject: support wildcard certificate autoselection --- src/certs.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/certs.rs b/src/certs.rs index 84d0fca..05a25c7 100644 --- a/src/certs.rs +++ b/src/certs.rs @@ -19,6 +19,7 @@ use webpki::EndEntityCert; pub struct CertPool { provider: &'static Arc, domains: HashMap>, + wildcards: HashMap>, fallback: Option>, } @@ -27,6 +28,7 @@ impl Default for CertPool { Self { provider: CryptoProvider::get_default().unwrap(), domains: Default::default(), + wildcards: Default::default(), fallback: None, } } @@ -77,9 +79,14 @@ impl CertPool { for c in &certs { let eec = EndEntityCert::try_from(c).unwrap(); for name in eec.valid_dns_names() { - debug!("loaded key for {name:?}"); let ck = CertifiedKey::new(certs.clone(), skey.clone()); - self.domains.insert(name.to_owned(), Arc::new(ck)); + if let Some(name) = name.strip_prefix("*.") { + debug!("loaded wildcard key for {name:?}"); + self.wildcards.insert(name.to_owned(), Arc::new(ck)); + } else { + debug!("loaded key for {name:?}"); + self.domains.insert(name.to_owned(), Arc::new(ck)); + } } } } @@ -89,9 +96,16 @@ impl CertPool { impl ResolvesServerCert for CertPool { fn resolve(&self, client_hello: ClientHello<'_>) -> Option> { + let sname = client_hello.server_name()?; Some( self.domains - .get(client_hello.server_name()?) + .get(sname) + .or_else(|| { + // Removing first label seems fine since wildcards are not recursive. + sname + .split_once(".") + .and_then(|(_, sname)| self.wildcards.get(sname)) + }) .or(self.fallback.as_ref())? .clone(), ) -- cgit v1.2.3-70-g09d2