diff options
-rw-r--r-- | src/certs.rs | 20 |
1 files 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<CryptoProvider>, domains: HashMap<String, Arc<CertifiedKey>>, + wildcards: HashMap<String, Arc<CertifiedKey>>, fallback: Option<Arc<CertifiedKey>>, } @@ -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<Arc<CertifiedKey>> { + 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(), ) |