Generate TLSA Records for DANE (closes #397)

This commit is contained in:
mdecimus 2024-05-07 10:36:57 +02:00
parent ede21dbfe8
commit 3e9d0ae5d2
5 changed files with 54 additions and 0 deletions

1
Cargo.lock generated
View file

@ -2951,6 +2951,7 @@ dependencies = [
"tracing",
"tungstenite",
"utils",
"x509-parser 0.16.0",
]
[[package]]

View file

@ -167,6 +167,9 @@ impl Default for QueueConfig {
),
invalid_certs: IfBlock::new::<()>(
"queue.outbound.tls.allow-invalid-certs",
#[cfg(not(feature = "test_mode"))]
[("retry_num > 0 && last_error == 'tls'", "true")],
#[cfg(feature = "test_mode")]
[],
"false",
),

View file

@ -365,6 +365,11 @@ impl TokenMap {
V_PRIORITY,
V_PROTOCOL,
V_TLS,
V_QUEUE_RETRY_NUM,
V_QUEUE_NOTIFY_NUM,
V_QUEUE_EXPIRES_IN,
V_QUEUE_LAST_STATUS,
V_QUEUE_LAST_ERROR,
])
}

View file

@ -55,6 +55,7 @@ rsa = "0.9.2"
async-trait = "0.1.68"
lz4_flex = { version = "0.11", default-features = false }
rev_lines = "0.3.0"
x509-parser = "0.16.0"
[dev-dependencies]
ece = "2.2"

View file

@ -27,8 +27,10 @@ use hyper::Method;
use jmap_proto::error::request::RequestError;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sha1::Digest;
use store::ahash::AHashMap;
use utils::url_params::UrlParams;
use x509_parser::parse_x509_certificate;
use crate::{
api::{
@ -229,6 +231,48 @@ impl JMAP {
content: format!("v=DMARC1; p=reject; rua=mailto:postmaster@{domain_name}; ruf=mailto:postmaster@{domain_name}",),
});
// Add TLSA records
for (name, key) in self.core.tls.certificates.load().iter() {
if !name.ends_with(domain_name) {
continue;
}
let cert = if let Some(cert) = key.cert.first().map(|cert| cert.as_ref()) {
cert
} else {
tracing::debug!("No certificate found for domain: {}", domain_name);
continue;
};
let parsed_cert = match parse_x509_certificate(cert) {
Ok((_, parsed_cert)) => parsed_cert,
Err(err) => {
tracing::debug!("Failed to parse certificate: {}", err);
continue;
}
};
let name = if !name.starts_with('.') {
format!("_25._tcp.{name}.")
} else {
format!("_25._tcp.mail.{name}.")
};
for (s, cert) in [cert, parsed_cert.subject_pki.raw].into_iter().enumerate() {
for (m, hash) in [
format!("{:x}", sha2::Sha256::digest(cert)),
format!("{:x}", sha2::Sha512::digest(cert)),
]
.into_iter()
.enumerate()
{
records.push(DnsRecord {
typ: "TLSA".to_string(),
name: name.clone(),
content: format!("3 {} {} {}", s, m + 1, hash),
});
}
}
}
Ok(records)
}
}