fix(SECURITY): return error on failed DANE verification

and add raw cert caching in DANE verificator
This commit is contained in:
DarkCat09 2024-08-28 17:02:56 +04:00
parent c3b50e4ecc
commit 32b888b3c1
Signed by: DarkCat09
GPG key ID: BD3CE9B65916CD82
2 changed files with 18 additions and 10 deletions

View file

@ -149,8 +149,7 @@ impl SelfsignedCertVerifier for CertVerifier {
CertFingerprint::new_sha256(cert) CertFingerprint::new_sha256(cert)
} }
Err(e) => { Err(e) => {
// some other problem (e.g. DNS server rejected the request), // cert not matched, DNS server rejected request, etc.
// we shouldn't continue
eprintln!("DANE verification failed: {:?}", e); eprintln!("DANE verification failed: {:?}", e);
return Err(e); return Err(e);
} }

View file

@ -4,6 +4,8 @@ use crate::{
LibError, LibError,
}; };
use tokio_rustls::rustls;
pub async fn dane( pub async fn dane(
dns: &DnsClient, dns: &DnsClient,
cert: &CertificateDer<'_>, cert: &CertificateDer<'_>,
@ -12,8 +14,11 @@ pub async fn dane(
) -> Result<CertFingerprint, LibError> { ) -> Result<CertFingerprint, LibError> {
let mut dns = dns.clone(); let mut dns = dns.clone();
// TODO: maybe kinda Iterator or HashMap?
// what if we needed one more algorithm to add?
let mut sha256: Option<CertFingerprint> = None; let mut sha256: Option<CertFingerprint> = None;
let mut sha512: Option<CertFingerprint> = None; let mut sha512: Option<CertFingerprint> = None;
let mut raw: Option<CertFingerprint> = None;
for tlsa_fp in dns.query_tlsa(host, port).await? { for tlsa_fp in dns.query_tlsa(host, port).await? {
match tlsa_fp { match tlsa_fp {
@ -36,19 +41,23 @@ pub async fn dane(
} }
} }
CertFingerprint::Raw(_) => { CertFingerprint::Raw(_) => {
let this_fp = CertFingerprint::new_raw(cert); if raw.is_none() {
if this_fp == tlsa_fp { raw = Some(CertFingerprint::new_raw(cert));
return Ok(CertFingerprint::new_sha256(cert)); }
let this_fp = raw.as_ref().unwrap();
if this_fp == &tlsa_fp {
return Ok(sha256.unwrap_or_else(|| CertFingerprint::new_sha256(cert)));
} }
} }
} }
} }
if let Some(sha256) = sha256 { if sha256.is_some() || sha512.is_some() || raw.is_some() {
Ok(sha256) // we have a hash => we tried to match a cert at least once,
} else if let Some(sha512) = sha512 { // i.e. query_tlsa did not return an empty iterator
Ok(sha512) Err(rustls::CertificateError::ApplicationVerificationFailure.into())
} else { } else {
Ok(CertFingerprint::new_sha256(cert)) // iterator was empty, we can't do any verification
Err(LibError::HostLookupError)
} }
} }