diff --git a/Cargo.lock b/Cargo.lock index 75955e32..19024475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -896,6 +896,16 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +dependencies = [ + "memchr", + "serde_core", +] + [[package]] name = "btoi" version = "0.4.3" @@ -4379,9 +4389,7 @@ dependencies = [ [[package]] name = "mail-auth" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e533fed1dd496906478a2ebf4700525da7579ef116f3e90812ca5832aedd158" +version = "0.11.0" dependencies = [ "aws-lc-rs", "flate2", @@ -4396,6 +4404,7 @@ dependencies = [ "rustls-pki-types", "serde", "serde_json", + "similar", "zip", ] @@ -7502,6 +7511,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "similar" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6505efef05804732ed8a3f2d4f279429eb485bd69d5b0cc6b19cc02005cda16" +dependencies = [ + "bstr", +] + [[package]] name = "simple_asn1" version = "0.6.4" diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 66f8c99d..5ce83ab8 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -18,7 +18,7 @@ imap_proto = { path = "../imap-proto" } sieve-rs = { version = "0.7", features = ["rkyv", "serde"] } mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.10", features = ["generate"] } +mail-auth = { path = "/Users/me/code/mail-auth", features = ["generate", "arc"] } smtp-proto = { version = "0.2", features = ["rkyv"] } dns-update = { version = "0.5" } calcard = { version = "0.3", features = ["rkyv"] } diff --git a/crates/common/src/config/smtp/auth.rs b/crates/common/src/config/smtp/auth.rs index a0901271..e4f313b1 100644 --- a/crates/common/src/config/smtp/auth.rs +++ b/crates/common/src/config/smtp/auth.rs @@ -172,6 +172,9 @@ impl DkimSigner { domain, signature, key, ))) } + DkimSignature::Dkim2Ed25519Sha256(_) | DkimSignature::Dkim2RsaSha256(_) => { + todo!() + } } } } diff --git a/crates/common/src/network/dkim.rs b/crates/common/src/network/dkim.rs index 8372cf1d..ad154c4f 100644 --- a/crates/common/src/network/dkim.rs +++ b/crates/common/src/network/dkim.rs @@ -21,10 +21,10 @@ pub async fn generate_dkim_private_key( key_type: DkimSignatureType, ) -> trc::Result> { let private_key = tokio::task::spawn_blocking(move || match key_type { - DkimSignatureType::Dkim1RsaSha256 => { + DkimSignatureType::Dkim1RsaSha256 | DkimSignatureType::Dkim2RsaSha256 => { DkimKeyPair::generate_rsa(2048).map(|key| (key, "RSA PRIVATE KEY")) } - DkimSignatureType::Dkim1Ed25519Sha256 => { + DkimSignatureType::Dkim1Ed25519Sha256 | DkimSignatureType::Dkim2Ed25519Sha256 => { DkimKeyPair::generate_ed25519().map(|key| (key, "PRIVATE KEY")) } }) @@ -58,13 +58,18 @@ pub async fn generate_dkim_private_key( } pub async fn generate_dkim_public_key(key: &DkimSignature) -> trc::Result { - match key { - DkimSignature::Dkim1RsaSha256(key) => key - .private_key - .secret() - .await - .map_err(|err| trc::DkimEvent::BuildError.reason(err)) - .and_then(|pem| rsa_key_parse(pem.as_bytes())) + let is_rsa = matches!( + key, + DkimSignature::Dkim1RsaSha256(_) | DkimSignature::Dkim2RsaSha256(_) + ); + let pem = key + .private_key() + .secret() + .await + .map_err(|err| trc::DkimEvent::BuildError.reason(err))?; + + if is_rsa { + rsa_key_parse(pem.as_bytes()) .and_then(|pk| { Document::from_pkcs1_der(&pk.public_key()).map_err(|err| { trc::EventType::Dkim(trc::DkimEvent::BuildError) @@ -75,18 +80,13 @@ pub async fn generate_dkim_public_key(key: &DkimSignature) -> trc::Result key - .private_key - .secret() - .await - .map_err(|err| trc::DkimEvent::BuildError.reason(err)) - .and_then(|pem| { - simple_pem_parse(&pem).ok_or_else(|| { - trc::EventType::Dkim(trc::DkimEvent::BuildError) - .into_err() - .details("Failed to parse private key PEM") - }) + }) + } else { + simple_pem_parse(&pem) + .ok_or_else(|| { + trc::EventType::Dkim(trc::DkimEvent::BuildError) + .into_err() + .details("Failed to parse private key PEM") }) .and_then(|der| { Ed25519Key::from_pkcs8_maybe_unchecked_der(&der).map_err(|err| { @@ -98,7 +98,7 @@ pub async fn generate_dkim_public_key(key: &DkimSignature) -> trc::Result ( + &sign.selector, + format!("v=DKIM1; k=ed25519; h=sha256; p={public_key}"), + ), DkimSignature::Dkim1RsaSha256(sign) => ( &sign.selector, format!("v=DKIM1; k=rsa; h=sha256; p={public_key}"), ), + DkimSignature::Dkim2RsaSha256(sign) => ( + &sign.selector, + format!("v=DKIM1; k=rsa; h=sha256; p={public_key}"), + ), }; Ok(NamedDnsRecord { diff --git a/crates/common/src/network/dns/resolve.rs b/crates/common/src/network/dns/resolve.rs index 94c56c28..4364937f 100644 --- a/crates/common/src/network/dns/resolve.rs +++ b/crates/common/src/network/dns/resolve.rs @@ -19,7 +19,7 @@ impl Server { .await { Ok(result) => Ok(result.rrset.iter().any(|mx| !mx.exchanges.is_empty())), - Err(Error::DnsRecordNotFound(_)) => Ok(false), + Err(Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => Ok(false), Err(err) => Err(err.into()), } } @@ -40,7 +40,7 @@ impl Server { .await { Ok(result) => Ok(!result.is_empty()), - Err(Error::DnsRecordNotFound(_)) => Ok(false), + Err(Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => Ok(false), Err(err) => Err(err.into()), } } @@ -56,7 +56,7 @@ impl Server { .await { Ok(result) => Ok(!result.rrset.is_empty()), - Err(Error::DnsRecordNotFound(_)) => Ok(false), + Err(Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => Ok(false), Err(err) => Err(err.into()), } } else { @@ -74,7 +74,7 @@ impl Server { .await { Ok(result) => Ok(!result.rrset.is_empty()), - Err(Error::DnsRecordNotFound(_)) => Ok(false), + Err(Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => Ok(false), Err(err) => Err(err.into()), } } @@ -89,7 +89,7 @@ impl Server { .await { Ok(result) => Ok(!result.rrset.is_empty()), - Err(Error::DnsRecordNotFound(_)) => Ok(false), + Err(Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => Ok(false), Err(err) => Err(err.into()), } } diff --git a/crates/common/src/scripts/plugins/dns.rs b/crates/common/src/scripts/plugins/dns.rs index 9301b553..ba48877d 100644 --- a/crates/common/src/scripts/plugins/dns.rs +++ b/crates/common/src/scripts/plugins/dns.rs @@ -194,10 +194,10 @@ trait ShortError { impl ShortError for mail_auth::Error { fn short_error(&self) -> &'static str { match self { - mail_auth::Error::DnsError(_) => "temp_fail", - mail_auth::Error::DnsRecordNotFound(_) => "not_found", + mail_auth::Error::Dns(mail_auth::DnsError::Resolver(_)) => "temp_fail", + mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_)) => "not_found", mail_auth::Error::Io(_) => "io_error", - mail_auth::Error::InvalidRecordType => "invalid_record", + mail_auth::Error::Dns(mail_auth::DnsError::InvalidRecordType) => "invalid_record", _ => "unknown_error", } } diff --git a/crates/http/Cargo.toml b/crates/http/Cargo.toml index b37d9099..172c7eb9 100644 --- a/crates/http/Cargo.toml +++ b/crates/http/Cargo.toml @@ -23,7 +23,7 @@ registry = { path = "../registry" } smtp-proto = { version = "0.2" } mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.10", features = ["generate"] } +mail-auth = { path = "/Users/me/code/mail-auth", features = ["generate", "arc"] } tokio = { version = "1.47", features = ["rt"] } hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } hyper-util = { version = "0.1.1", features = ["tokio"] } diff --git a/crates/http/src/api/diagnose.rs b/crates/http/src/api/diagnose.rs index 6e64a364..9c11e2e1 100644 --- a/crates/http/src/api/diagnose.rs +++ b/crates/http/src/api/diagnose.rs @@ -296,7 +296,7 @@ async fn delivery_diagnose( Err(err) => { if matches!( &err, - smtp::outbound::mta_sts::Error::Dns(mail_auth::Error::DnsRecordNotFound(_)) + smtp::outbound::mta_sts::Error::Dns(mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) ) { tx.send(DeliveryStage::MtaStsNotFound { elapsed: now.elapsed_ms(), @@ -346,7 +346,7 @@ async fn delivery_diagnose( .await?; } Err(err) => { - if matches!(&err, mail_auth::Error::DnsRecordNotFound(_)) { + if matches!(&err, mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) { tx.send(DeliveryStage::TlsRptNotFound { elapsed: now.elapsed_ms(), }) @@ -426,7 +426,7 @@ async fn delivery_diagnose( None } Err(err) => { - if matches!(&err, mail_auth::Error::DnsRecordNotFound(_)) { + if matches!(&err, mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) { tx.send(DeliveryStage::TlsaNotFound { elapsed: now.elapsed_ms(), reason: "No TLSA records found for MX".to_string(), diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index e674567b..1d660bbf 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -23,7 +23,7 @@ calcard = { version = "0.3" } smtp-proto = { version = "0.2" } mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.10", features = ["generate"] } +mail-auth = { path = "/Users/me/code/mail-auth", features = ["generate", "arc"] } sieve-rs = { version = "0.7", features = ["rkyv"] } jmap-tools = { version = "0.1", features = ["rkyv"] } serde = { version = "1.0", features = ["derive"]} diff --git a/crates/registry/Cargo.toml b/crates/registry/Cargo.toml index 243fdefa..32133738 100644 --- a/crates/registry/Cargo.toml +++ b/crates/registry/Cargo.toml @@ -13,7 +13,7 @@ hashify = "0.2.7" ahash = { version = "0.8" } jmap-tools = { version = "0.1" } xxhash-rust = { version = "0.8.5", features = ["xxh3"] } -mail-auth = { version = "0.10" } +mail-auth = { path = "/Users/me/code/mail-auth" } tokio = { version = "1.47", features = ["fs"] } lz4_flex = { version = "0.13", default-features = false } diff --git a/crates/registry/src/schema/enums.rs b/crates/registry/src/schema/enums.rs index b749e8aa..e182fe9d 100644 --- a/crates/registry/src/schema/enums.rs +++ b/crates/registry/src/schema/enums.rs @@ -345,6 +345,15 @@ pub enum DirectoryType { Oidc = 2, } +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Dkim2Flag { + #[default] + Donotmodify = 0, + Donotexplode = 1, + Feedback = 2, +} + #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] #[repr(u16)] pub enum DkimAuthResult { @@ -400,6 +409,8 @@ pub enum DkimSignatureType { #[default] Dkim1Ed25519Sha256 = 0, Dkim1RsaSha256 = 1, + Dkim2Ed25519Sha256 = 2, + Dkim2RsaSha256 = 3, } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] diff --git a/crates/registry/src/schema/enums_impl.rs b/crates/registry/src/schema/enums_impl.rs index 93d045ac..955cfa55 100644 --- a/crates/registry/src/schema/enums_impl.rs +++ b/crates/registry/src/schema/enums_impl.rs @@ -1857,6 +1857,59 @@ impl<'de> serde::Deserialize<'de> for DirectoryType { } } +impl EnumImpl for Dkim2Flag { + fn parse(value: &str) -> Option { + hashify::tiny_map! { + value.as_bytes(), + b"donotmodify" => Dkim2Flag::Donotmodify, + b"donotexplode" => Dkim2Flag::Donotexplode, + b"feedback" => Dkim2Flag::Feedback, + } + } + + fn as_str(&self) -> &'static str { + match self { + Dkim2Flag::Donotmodify => "donotmodify", + Dkim2Flag::Donotexplode => "donotexplode", + Dkim2Flag::Feedback => "feedback", + } + } + + fn to_id(&self) -> u16 { + *self as u16 + } + + fn from_id(id: u16) -> Option { + match id { + 0 => Some(Dkim2Flag::Donotmodify), + 1 => Some(Dkim2Flag::Donotexplode), + 2 => Some(Dkim2Flag::Feedback), + _ => None, + } + } + + const COUNT: usize = 3; +} + +impl serde::Serialize for Dkim2Flag { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +impl<'de> serde::Deserialize<'de> for Dkim2Flag { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = Cow::::deserialize(deserializer)?; + Self::parse(&s).ok_or_else(|| serde::de::Error::unknown_variant(&s, &[])) + } +} + impl EnumImpl for DkimAuthResult { fn parse(value: &str) -> Option { hashify::tiny_map! { @@ -2140,6 +2193,8 @@ impl EnumImpl for DkimSignatureType { value.as_bytes(), b"Dkim1Ed25519Sha256" => DkimSignatureType::Dkim1Ed25519Sha256, b"Dkim1RsaSha256" => DkimSignatureType::Dkim1RsaSha256, + b"Dkim2Ed25519Sha256" => DkimSignatureType::Dkim2Ed25519Sha256, + b"Dkim2RsaSha256" => DkimSignatureType::Dkim2RsaSha256, } } @@ -2147,6 +2202,8 @@ impl EnumImpl for DkimSignatureType { match self { DkimSignatureType::Dkim1Ed25519Sha256 => "Dkim1Ed25519Sha256", DkimSignatureType::Dkim1RsaSha256 => "Dkim1RsaSha256", + DkimSignatureType::Dkim2Ed25519Sha256 => "Dkim2Ed25519Sha256", + DkimSignatureType::Dkim2RsaSha256 => "Dkim2RsaSha256", } } @@ -2158,11 +2215,13 @@ impl EnumImpl for DkimSignatureType { match id { 0 => Some(DkimSignatureType::Dkim1Ed25519Sha256), 1 => Some(DkimSignatureType::Dkim1RsaSha256), + 2 => Some(DkimSignatureType::Dkim2Ed25519Sha256), + 3 => Some(DkimSignatureType::Dkim2RsaSha256), _ => None, } } - const COUNT: usize = 2; + const COUNT: usize = 4; } impl serde::Serialize for DkimSignatureType { diff --git a/crates/registry/src/schema/properties_impl.rs b/crates/registry/src/schema/properties_impl.rs index 8ffc914a..40003eb5 100644 --- a/crates/registry/src/schema/properties_impl.rs +++ b/crates/registry/src/schema/properties_impl.rs @@ -4355,6 +4355,10 @@ impl ObjectInner { obj.member_tenant_id } ObjectInner::DkimSignature(DkimSignature::Dkim1RsaSha256(obj)) => obj.member_tenant_id, + ObjectInner::DkimSignature(DkimSignature::Dkim2Ed25519Sha256(obj)) => { + obj.member_tenant_id + } + ObjectInner::DkimSignature(DkimSignature::Dkim2RsaSha256(obj)) => obj.member_tenant_id, ObjectInner::DmarcExternalReport(obj) => obj.member_tenant_id, ObjectInner::DnsServer(DnsServer::Tsig(obj)) => obj.member_tenant_id, ObjectInner::DnsServer(DnsServer::Cloudflare(obj)) => obj.member_tenant_id, @@ -4449,6 +4453,12 @@ impl ObjectInner { ObjectInner::DkimSignature(DkimSignature::Dkim1RsaSha256(obj)) => { obj.member_tenant_id = Some(id) } + ObjectInner::DkimSignature(DkimSignature::Dkim2Ed25519Sha256(obj)) => { + obj.member_tenant_id = Some(id) + } + ObjectInner::DkimSignature(DkimSignature::Dkim2RsaSha256(obj)) => { + obj.member_tenant_id = Some(id) + } ObjectInner::DmarcExternalReport(obj) => obj.member_tenant_id = Some(id), ObjectInner::DnsServer(DnsServer::Tsig(obj)) => obj.member_tenant_id = Some(id), ObjectInner::DnsServer(DnsServer::Cloudflare(obj)) => obj.member_tenant_id = Some(id), diff --git a/crates/registry/src/schema/structs.rs b/crates/registry/src/schema/structs.rs index 7060358e..1d796b97 100644 --- a/crates/registry/src/schema/structs.rs +++ b/crates/registry/src/schema/structs.rs @@ -968,6 +968,27 @@ pub struct Dkim1Signature { pub stage: DkimRotationStage, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct Dkim2Signature { + #[serde(rename = "flags")] + pub flags: Map, + #[serde(rename = "privateKey")] + pub private_key: SecretText, + #[serde(rename = "domainId")] + pub domain_id: Id, + #[serde(rename = "memberTenantId")] + pub member_tenant_id: Option, + #[serde(rename = "selector")] + pub selector: String, + #[serde(rename = "createdAt")] + pub created_at: UTCDateTime, + #[serde(rename = "nextTransitionAt")] + pub next_transition_at: Option, + #[serde(rename = "stage")] + pub stage: DkimRotationStage, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "@type")] pub enum DkimManagement { @@ -1010,6 +1031,8 @@ pub struct DkimReportSettings { pub enum DkimSignature { Dkim1Ed25519Sha256(Dkim1Signature), Dkim1RsaSha256(Dkim1Signature), + Dkim2Ed25519Sha256(Dkim2Signature), + Dkim2RsaSha256(Dkim2Signature), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/crates/registry/src/schema/structs_impl.rs b/crates/registry/src/schema/structs_impl.rs index cc947584..42dd04a4 100644 --- a/crates/registry/src/schema/structs_impl.rs +++ b/crates/registry/src/schema/structs_impl.rs @@ -7397,6 +7397,134 @@ impl RegistryJsonPropertyPatch for Dkim1Signature { } } +impl Dkim2Signature { + fn validate(&self, errors: &mut Vec) -> bool { + let neb = errors.len(); + let value = &self.private_key; + value.validate(errors); + let value = &self.domain_id; + if !value.is_valid() { + errors.push(ValidationError::required(Property::DomainId)); + } + if let Some(value) = &self.member_tenant_id { + if !value.is_valid() { + errors.push(ValidationError::required(Property::MemberTenantId)); + } + } + let value = &self.selector; + if value.is_empty() { + errors.push(ValidationError::required(Property::Selector)); + } + let value = &self.created_at; + if !value.is_valid() { + errors.push(ValidationError::invalid(Property::CreatedAt, value)); + } + if let Some(value) = &self.next_transition_at { + if !value.is_valid() { + errors.push(ValidationError::invalid(Property::NextTransitionAt, value)); + } + } + errors.len() == neb + } + + fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) { + i.foreign_key(ObjectType::Domain, self.domain_id.into(), None); + i.search(Property::DomainId, &self.domain_id); + i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None); + if let Some(value) = &self.member_tenant_id { + i.search(Property::MemberTenantId, value); + } + } +} + +impl Pickle for Dkim2Signature { + fn pickle(&self, out: &mut Vec) { + self.flags.pickle(out); + self.private_key.pickle(out); + self.domain_id.pickle(out); + self.member_tenant_id.pickle(out); + self.selector.pickle(out); + self.created_at.pickle(out); + self.next_transition_at.pickle(out); + self.stage.pickle(out); + } + + fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option { + let mut this = Self::default(); + this.flags = Pickle::unpickle(stream)?; + this.private_key = Pickle::unpickle(stream)?; + this.domain_id = Pickle::unpickle(stream)?; + this.member_tenant_id = Pickle::unpickle(stream)?; + this.selector = Pickle::unpickle(stream)?; + this.created_at = Pickle::unpickle(stream)?; + this.next_transition_at = Pickle::unpickle(stream)?; + this.stage = Pickle::unpickle(stream)?; + Some(this) + } +} + +impl Default for Dkim2Signature { + fn default() -> Self { + Self { + flags: Default::default(), + private_key: Default::default(), + domain_id: Default::default(), + member_tenant_id: Default::default(), + selector: Default::default(), + created_at: Default::default(), + next_transition_at: Default::default(), + stage: DkimRotationStage::Active, + } + } +} + +impl IntoValue for Dkim2Signature { + fn into_value(self) -> JmapValue<'static> { + let mut map = jmap_tools::Map::with_capacity(10); + map.insert_unchecked(Property::Flags, self.flags.into_value()); + map.insert_unchecked(Property::PrivateKey, self.private_key.into_value()); + map.insert_unchecked(Property::DomainId, self.domain_id.into_value()); + map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value()); + map.insert_unchecked(Property::Selector, self.selector.into_value()); + map.insert_unchecked(Property::CreatedAt, self.created_at.into_value()); + map.insert_unchecked( + Property::NextTransitionAt, + self.next_transition_at.into_value(), + ); + map.insert_unchecked(Property::Stage, self.stage.into_value()); + JmapValue::Object(map) + } +} + +impl RegistryJsonPropertyPatch for Dkim2Signature { + fn patch_property<'x>( + &mut self, + mut pointer: JsonPointerPatch<'_>, + value: JmapValue<'x>, + ) -> PatchResult<'x> { + match pointer.next_property() { + Some(Property::Flags) => self.flags.patch(pointer, value), + Some(Property::PrivateKey) => self.private_key.patch(pointer, value), + Some(Property::PublicKey) => pointer.assert_server_set(), + Some(Property::DomainId) => self.domain_id.patch(pointer, value), + Some(Property::MemberTenantId) => self + .member_tenant_id + .patch(pointer.assert_can_set_tenant()?, value), + Some(Property::Selector) => self + .selector + .patch(pointer.with_validators(&[StringValidator::Trim]), value), + Some(Property::CreatedAt) => pointer.assert_server_set(), + Some(Property::NextTransitionAt) => self.next_transition_at.patch(pointer, value), + Some(Property::Stage) => self.stage.patch(pointer, value), + Some(Property::Type) => Ok(MaybeUnpatched::Unpatched { + property: Property::Type, + value, + }), + _ => Err(PatchError::new(pointer, "Invalid property")), + } + } +} + impl DkimManagement { fn validate(&self, errors: &mut Vec) -> bool { match self { @@ -7756,6 +7884,8 @@ impl ObjectImpl for DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(inner) => inner.validate(errors), DkimSignature::Dkim1RsaSha256(inner) => inner.validate(errors), + DkimSignature::Dkim2Ed25519Sha256(inner) => inner.validate(errors), + DkimSignature::Dkim2RsaSha256(inner) => inner.validate(errors), } } @@ -7767,6 +7897,12 @@ impl ObjectImpl for DkimSignature { DkimSignature::Dkim1RsaSha256(object) => { object.index(i); } + DkimSignature::Dkim2Ed25519Sha256(object) => { + object.index(i); + } + DkimSignature::Dkim2RsaSha256(object) => { + object.index(i); + } } } } @@ -7788,6 +7924,14 @@ impl Pickle for DkimSignature { 1u16.pickle(out); inner.pickle(out); } + DkimSignature::Dkim2Ed25519Sha256(inner) => { + 2u16.pickle(out); + inner.pickle(out); + } + DkimSignature::Dkim2RsaSha256(inner) => { + 3u16.pickle(out); + inner.pickle(out); + } } } @@ -7795,6 +7939,8 @@ impl Pickle for DkimSignature { match u16::unpickle(stream)? { 0 => Pickle::unpickle(stream).map(DkimSignature::Dkim1Ed25519Sha256), 1 => Pickle::unpickle(stream).map(DkimSignature::Dkim1RsaSha256), + 2 => Pickle::unpickle(stream).map(DkimSignature::Dkim2Ed25519Sha256), + 3 => Pickle::unpickle(stream).map(DkimSignature::Dkim2RsaSha256), _ => None, } } @@ -7817,6 +7963,20 @@ impl IntoValue for DkimSignature { .insert_unchecked(Property::Type, JmapValue::Str("Dkim1RsaSha256".into())); obj } + DkimSignature::Dkim2Ed25519Sha256(obj) => { + let mut obj = obj.into_value(); + obj.as_object_mut() + .unwrap() + .insert_unchecked(Property::Type, JmapValue::Str("Dkim2Ed25519Sha256".into())); + obj + } + DkimSignature::Dkim2RsaSha256(obj) => { + let mut obj = obj.into_value(); + obj.as_object_mut() + .unwrap() + .insert_unchecked(Property::Type, JmapValue::Str("Dkim2RsaSha256".into())); + obj + } } } } @@ -7835,11 +7995,19 @@ impl RegistryJsonPatch for DkimSignature { DkimSignatureType::Dkim1RsaSha256 => { *self = DkimSignature::Dkim1RsaSha256(Default::default()) } + DkimSignatureType::Dkim2Ed25519Sha256 => { + *self = DkimSignature::Dkim2Ed25519Sha256(Default::default()) + } + DkimSignatureType::Dkim2RsaSha256 => { + *self = DkimSignature::Dkim2RsaSha256(Default::default()) + } } } match self { DkimSignature::Dkim1Ed25519Sha256(inner) => inner.patch(pointer, value), DkimSignature::Dkim1RsaSha256(inner) => inner.patch(pointer, value), + DkimSignature::Dkim2Ed25519Sha256(inner) => inner.patch(pointer, value), + DkimSignature::Dkim2RsaSha256(inner) => inner.patch(pointer, value), } } } @@ -7849,6 +8017,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(_) => DkimSignatureType::Dkim1Ed25519Sha256, DkimSignature::Dkim1RsaSha256(_) => DkimSignatureType::Dkim1RsaSha256, + DkimSignature::Dkim2Ed25519Sha256(_) => DkimSignatureType::Dkim2Ed25519Sha256, + DkimSignature::Dkim2RsaSha256(_) => DkimSignatureType::Dkim2RsaSha256, } } } diff --git a/crates/registry/src/utils/dkim.rs b/crates/registry/src/utils/dkim.rs index c8a61572..c2196402 100644 --- a/crates/registry/src/utils/dkim.rs +++ b/crates/registry/src/utils/dkim.rs @@ -15,6 +15,8 @@ impl DkimSignature { let (stage, next_transition) = match self { DkimSignature::Dkim1Ed25519Sha256(sign) => (sign.stage, sign.next_transition_at), DkimSignature::Dkim1RsaSha256(sign) => (sign.stage, sign.next_transition_at), + DkimSignature::Dkim2Ed25519Sha256(sign) => (sign.stage, sign.next_transition_at), + DkimSignature::Dkim2RsaSha256(sign) => (sign.stage, sign.next_transition_at), }; next_transition.and_then(|next_transition| { if next_transition <= UTCDateTime::now() { @@ -29,6 +31,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(sign) => sign.next_transition_at, DkimSignature::Dkim1RsaSha256(sign) => sign.next_transition_at, + DkimSignature::Dkim2Ed25519Sha256(sign) => sign.next_transition_at, + DkimSignature::Dkim2RsaSha256(sign) => sign.next_transition_at, } } @@ -38,6 +42,10 @@ impl DkimSignature { sign.next_transition_at = Some(next_transition) } DkimSignature::Dkim1RsaSha256(sign) => sign.next_transition_at = Some(next_transition), + DkimSignature::Dkim2Ed25519Sha256(sign) => { + sign.next_transition_at = Some(next_transition) + } + DkimSignature::Dkim2RsaSha256(sign) => sign.next_transition_at = Some(next_transition), } } @@ -45,6 +53,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage, DkimSignature::Dkim1RsaSha256(sign) => sign.stage, + DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage, + DkimSignature::Dkim2RsaSha256(sign) => sign.stage, } } @@ -52,6 +62,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage = stage, DkimSignature::Dkim1RsaSha256(sign) => sign.stage = stage, + DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage = stage, + DkimSignature::Dkim2RsaSha256(sign) => sign.stage = stage, } } @@ -59,6 +71,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage == DkimRotationStage::Active, DkimSignature::Dkim1RsaSha256(sign) => sign.stage == DkimRotationStage::Active, + DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage == DkimRotationStage::Active, + DkimSignature::Dkim2RsaSha256(sign) => sign.stage == DkimRotationStage::Active, } } @@ -66,6 +80,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(sign) => &sign.selector, DkimSignature::Dkim1RsaSha256(sign) => &sign.selector, + DkimSignature::Dkim2Ed25519Sha256(sign) => &sign.selector, + DkimSignature::Dkim2RsaSha256(sign) => &sign.selector, } } @@ -73,6 +89,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(sign) => sign.domain_id, DkimSignature::Dkim1RsaSha256(sign) => sign.domain_id, + DkimSignature::Dkim2Ed25519Sha256(sign) => sign.domain_id, + DkimSignature::Dkim2RsaSha256(sign) => sign.domain_id, } } } @@ -80,20 +98,19 @@ impl DkimSignature { impl DkimSignatureType { pub const fn algorithm(self) -> &'static str { match self { - Self::Dkim1Ed25519Sha256 => "ed25519", - Self::Dkim1RsaSha256 => "rsa", + Self::Dkim1Ed25519Sha256 | Self::Dkim2Ed25519Sha256 => "ed25519", + Self::Dkim1RsaSha256 | Self::Dkim2RsaSha256 => "rsa", } } pub const fn hash(self) -> &'static str { - match self { - Self::Dkim1Ed25519Sha256 | Self::Dkim1RsaSha256 => "sha256", - } + "sha256" } pub const fn version(self) -> &'static str { match self { Self::Dkim1Ed25519Sha256 | Self::Dkim1RsaSha256 => "1", + Self::Dkim2Ed25519Sha256 | Self::Dkim2RsaSha256 => "2", } } } diff --git a/crates/registry/src/utils/mod.rs b/crates/registry/src/utils/mod.rs index 2502d348..94c21c6b 100644 --- a/crates/registry/src/utils/mod.rs +++ b/crates/registry/src/utils/mod.rs @@ -30,6 +30,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(signature) => &signature.private_key, DkimSignature::Dkim1RsaSha256(signature) => &signature.private_key, + DkimSignature::Dkim2Ed25519Sha256(signature) => &signature.private_key, + DkimSignature::Dkim2RsaSha256(signature) => &signature.private_key, } } @@ -37,6 +39,8 @@ impl DkimSignature { match self { DkimSignature::Dkim1Ed25519Sha256(signature) => &mut signature.private_key, DkimSignature::Dkim1RsaSha256(signature) => &mut signature.private_key, + DkimSignature::Dkim2Ed25519Sha256(signature) => &mut signature.private_key, + DkimSignature::Dkim2RsaSha256(signature) => &mut signature.private_key, } } } diff --git a/crates/services/src/task_manager/dkim.rs b/crates/services/src/task_manager/dkim.rs index 093bdae8..d5673d4d 100644 --- a/crates/services/src/task_manager/dkim.rs +++ b/crates/services/src/task_manager/dkim.rs @@ -150,6 +150,8 @@ async fn dkim_management(server: &Server, task: &TaskDomainManagement) -> trc::R match algorithm { DkimSignatureType::Dkim1Ed25519Sha256 => TEST_ED25519_KEY.to_string(), DkimSignatureType::Dkim1RsaSha256 => TEST_RSA_KEY.to_string(), + DkimSignatureType::Dkim2Ed25519Sha256 + | DkimSignatureType::Dkim2RsaSha256 => todo!(), } } else { generate_dkim_private_key(algorithm).await.unwrap().unwrap() @@ -186,6 +188,7 @@ async fn dkim_management(server: &Server, task: &TaskDomainManagement) -> trc::R let mut signature = match algorithm { DkimSignatureType::Dkim1Ed25519Sha256 => DkimSignature::Dkim1Ed25519Sha256(signature), DkimSignatureType::Dkim1RsaSha256 => DkimSignature::Dkim1RsaSha256(signature), + DkimSignatureType::Dkim2Ed25519Sha256 | DkimSignatureType::Dkim2RsaSha256 => todo!(), }; // Publish key diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml index 8bd988b5..b20bd5ff 100644 --- a/crates/smtp/Cargo.toml +++ b/crates/smtp/Cargo.toml @@ -21,7 +21,7 @@ email = { path = "../email" } registry = { path = "../registry" } spam-filter = { path = "../spam-filter" } trc = { path = "../trc" } -mail-auth = { version = "0.10", features = ["rkyv"] } +mail-auth = { path = "/Users/me/code/mail-auth", features = ["rkyv"] } mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } smtp-proto = { version = "0.2", features = ["rkyv", "serde"] } diff --git a/crates/smtp/src/inbound/data.rs b/crates/smtp/src/inbound/data.rs index 3f5896bb..44cfcbf6 100644 --- a/crates/smtp/src/inbound/data.rs +++ b/crates/smtp/src/inbound/data.rs @@ -30,7 +30,12 @@ use common::{ }; use mail_auth::{ AuthenticatedMessage, AuthenticationResults, DkimResult, DmarcResult, ReceivedSpf, - common::{crypto::Algorithm, headers::HeaderWriter, verify::VerifySignature}, + common::{ + crypto::Algorithm, + headers::{Header, HeaderWriter}, + verify::VerifySignature, + }, + dkim::DkimError, dmarc::{self, verify::DmarcParameters}, }; use mail_builder::headers::{date::Date, message_id::generate_message_id_header}; @@ -108,17 +113,22 @@ impl Session { .unwrap_or(VerifyStrategy::Relaxed); let dkim_output = if dkim.verify() || dmarc.verify() { // Remove insecure DKIM signatures before verification - for header in &mut auth_message.dkim_headers { - if let Ok(signature) = &mut header.header - && (signature.algorithm() == Algorithm::RsaSha1 - || (signature.algorithm() == Algorithm::RsaSha256 - && signature.b.len() < 128)) + auth_message.dkim_headers.retain(|header| { + let signature = &header.header; + if signature.algorithm() == Algorithm::RsaSha1 + || (signature.algorithm() == Algorithm::RsaSha256 && signature.b.len() < 128) { - header.header = Err(mail_auth::Error::CryptoError( - "Insecure DKIM signature".into(), - )); + auth_message.errors.push(Header { + name: header.name, + value: header.value, + header: mail_auth::Error::Dkim(DkimError::UnsupportedAlgorithm), + }); + auth_message.has_dkim_errors = true; + false + } else { + true } - } + }); let time = Instant::now(); let dkim_output = self diff --git a/crates/smtp/src/outbound/delivery.rs b/crates/smtp/src/outbound/delivery.rs index 8e0ebfb5..c1c6d1b4 100644 --- a/crates/smtp/src/outbound/delivery.rs +++ b/crates/smtp/src/outbound/delivery.rs @@ -345,7 +345,7 @@ impl QueuedMessage { TlsRptOptions { record, interval }.into() } - Err(mail_auth::Error::DnsRecordNotFound(_)) => { + Err(mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => { trc::event!( TlsRpt(TlsRptEvent::RecordNotFound), SpanId = message.span_id, @@ -400,7 +400,7 @@ impl QueuedMessage { let strict = tls_strategy.is_mta_sts_required(); if let Some(tls_report) = &tls_report { match &err { - mta_sts::Error::Dns(mail_auth::Error::DnsRecordNotFound(_)) => { + mta_sts::Error::Dns(mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => { if strict { server.schedule_report(TlsEvent { policy: PolicyType::Sts(None), @@ -417,7 +417,7 @@ impl QueuedMessage { .await; } } - mta_sts::Error::Dns(mail_auth::Error::DnsError(_)) => (), + mta_sts::Error::Dns(mail_auth::Error::Dns(mail_auth::DnsError::Resolver(_))) => (), _ => { server .schedule_report(TlsEvent { @@ -436,7 +436,7 @@ impl QueuedMessage { } match &err { - mta_sts::Error::Dns(mail_auth::Error::DnsRecordNotFound(_)) => { + mta_sts::Error::Dns(mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => { trc::event!( MtaSts(MtaStsEvent::PolicyNotFound), SpanId = message.span_id, @@ -499,7 +499,7 @@ impl QueuedMessage { let time = Instant::now(); mx_list = match server.mx_lookup(domain).await { Ok(mx) => mx, - Err(mail_auth::Error::DnsRecordNotFound(_)) => { + Err(mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => { trc::event!( Delivery(DeliveryEvent::MxLookupFailed), SpanId = message.span_id, @@ -822,7 +822,7 @@ impl QueuedMessage { } Err(err) => { let not_found = - matches!(&err, mail_auth::Error::DnsRecordNotFound(_)); + matches!(&err, mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_))); if not_found { trc::event!( diff --git a/crates/smtp/src/outbound/lookup.rs b/crates/smtp/src/outbound/lookup.rs index f9fb9328..62498432 100644 --- a/crates/smtp/src/outbound/lookup.rs +++ b/crates/smtp/src/outbound/lookup.rs @@ -116,7 +116,7 @@ impl DnsLookup for Server { ) .await .map_err(|err| { - if let mail_auth::Error::DnsRecordNotFound(_) = &err { + if let mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(_)) = &err { if matches!( remote_host, NextHop::MX { diff --git a/crates/smtp/src/outbound/mod.rs b/crates/smtp/src/outbound/mod.rs index 22064995..2c61c0f7 100644 --- a/crates/smtp/src/outbound/mod.rs +++ b/crates/smtp/src/outbound/mod.rs @@ -156,10 +156,14 @@ impl Status>, ErrorDetails> { pub fn from_mail_auth_error(entity: &str, err: mail_auth::Error) -> Self { match &err { - mail_auth::Error::DnsRecordNotFound(code) => Status::PermanentFailure(ErrorDetails { - entity: entity.into(), - details: Error::DnsError(format!("Domain not found: {code:?}").into_boxed_str()), - }), + mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(code)) => { + Status::PermanentFailure(ErrorDetails { + entity: entity.into(), + details: Error::DnsError( + format!("Domain not found: {code:?}").into_boxed_str(), + ), + }) + } _ => Status::TemporaryFailure(ErrorDetails { entity: entity.into(), details: Error::DnsError(err.to_string().into_boxed_str()), @@ -170,7 +174,7 @@ impl Status>, ErrorDetails> { pub fn from_mta_sts_error(entity: &str, err: mta_sts::Error) -> Self { match &err { mta_sts::Error::Dns(err) => match err { - mail_auth::Error::DnsRecordNotFound(code) => { + mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(code)) => { Status::PermanentFailure(ErrorDetails { entity: entity.into(), details: Error::MtaStsError( @@ -178,10 +182,12 @@ impl Status>, ErrorDetails> { ), }) } - mail_auth::Error::InvalidRecordType => Status::PermanentFailure(ErrorDetails { - entity: entity.into(), - details: Error::MtaStsError("Failed to parse MTA-STS DNS record.".into()), - }), + mail_auth::Error::Dns(mail_auth::DnsError::InvalidRecordType) => { + Status::PermanentFailure(ErrorDetails { + entity: entity.into(), + details: Error::MtaStsError("Failed to parse MTA-STS DNS record.".into()), + }) + } _ => Status::TemporaryFailure(ErrorDetails { entity: entity.into(), details: Error::MtaStsError( diff --git a/crates/smtp/src/outbound/mta_sts/lookup.rs b/crates/smtp/src/outbound/mta_sts/lookup.rs index d6ede094..cbc2f7a8 100644 --- a/crates/smtp/src/outbound/mta_sts/lookup.rs +++ b/crates/smtp/src/outbound/mta_sts/lookup.rs @@ -114,10 +114,10 @@ impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::Dns(err) => match err { - mail_auth::Error::DnsRecordNotFound(code) => { + mail_auth::Error::Dns(mail_auth::DnsError::RecordNotFound(code)) => { write!(f, "Record not found: {code:?}") } - mail_auth::Error::InvalidRecordType => { + mail_auth::Error::Dns(mail_auth::DnsError::InvalidRecordType) => { f.write_str("Failed to parse MTA-STS DNS record.") } _ => write!(f, "DNS lookup error: {err}"), diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml index b545c182..7bf839ba 100644 --- a/crates/spam-filter/Cargo.toml +++ b/crates/spam-filter/Cargo.toml @@ -14,7 +14,7 @@ registry = { path = "../registry" } smtp-proto = { version = "0.2", features = ["rkyv"] } mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.10" } +mail-auth = { path = "/Users/me/code/mail-auth" } tokio = { version = "1.47", features = ["net", "macros"] } psl = "2" hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } diff --git a/crates/spam-filter/src/modules/dnsbl.rs b/crates/spam-filter/src/modules/dnsbl.rs index ab90d763..e0e4f146 100644 --- a/crates/spam-filter/src/modules/dnsbl.rs +++ b/crates/spam-filter/src/modules/dnsbl.rs @@ -154,7 +154,7 @@ async fn is_dnsbl( entry } - Err(Error::DnsRecordNotFound(_)) => { + Err(Error::Dns(mail_auth::DnsError::RecordNotFound(_))) => { trc::event!( Spam(SpamEvent::Dnsbl), Hostname = zone.clone(), diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml index 2bbe2282..cbcbbe71 100644 --- a/crates/trc/Cargo.toml +++ b/crates/trc/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] event_macro = { path = "./event-macro" } -mail-auth = { version = "0.10" } -mail-parser = { version = "0.11", features = ["full_encoding"] } +mail-auth = { path = "/Users/me/code/mail-auth", features = ["arc"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } base64 = "0.22.1" serde = "1.0" serde_json = "1.0.120" diff --git a/crates/trc/src/event/conv.rs b/crates/trc/src/event/conv.rs index cb5b25e8..ddfab62d 100644 --- a/crates/trc/src/event/conv.rs +++ b/crates/trc/src/event/conv.rs @@ -235,67 +235,188 @@ impl From for Error { mail_auth::Error::NoHeadersFound => { EventType::MailAuth(MailAuthEvent::NoHeadersFound).into_err() } - mail_auth::Error::CryptoError(details) => EventType::MailAuth(MailAuthEvent::Crypto) - .into_err() - .details(CompactString::from(details)), mail_auth::Error::Io(details) => EventType::MailAuth(MailAuthEvent::Io) .into_err() .details(CompactString::from(details)), mail_auth::Error::Base64 => EventType::MailAuth(MailAuthEvent::Base64).into_err(), - mail_auth::Error::UnsupportedVersion => { - EventType::Dkim(DkimEvent::UnsupportedVersion).into_err() - } - mail_auth::Error::UnsupportedAlgorithm => { - EventType::Dkim(DkimEvent::UnsupportedAlgorithm).into_err() - } - mail_auth::Error::UnsupportedCanonicalization => { - EventType::Dkim(DkimEvent::UnsupportedCanonicalization).into_err() - } - mail_auth::Error::UnsupportedKeyType => { - EventType::Dkim(DkimEvent::UnsupportedKeyType).into_err() - } - mail_auth::Error::FailedBodyHashMatch => { - EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err() - } - mail_auth::Error::FailedVerification => { - EventType::Dkim(DkimEvent::FailedVerification).into_err() - } - mail_auth::Error::FailedAuidMatch => { - EventType::Dkim(DkimEvent::FailedAuidMatch).into_err() - } - mail_auth::Error::RevokedPublicKey => { - EventType::Dkim(DkimEvent::RevokedPublicKey).into_err() - } - mail_auth::Error::IncompatibleAlgorithms => { - EventType::Dkim(DkimEvent::IncompatibleAlgorithms).into_err() - } - mail_auth::Error::SignatureExpired => { - EventType::Dkim(DkimEvent::SignatureExpired).into_err() - } - mail_auth::Error::SignatureLength => { - EventType::Dkim(DkimEvent::SignatureLength).into_err() - } - mail_auth::Error::DnsError(details) => EventType::MailAuth(MailAuthEvent::DnsError) - .into_err() - .details(CompactString::from(details)), - mail_auth::Error::DnsRecordNotFound(code) => { - EventType::MailAuth(MailAuthEvent::DnsRecordNotFound) - .into_err() - .code(code.to_str()) - } - mail_auth::Error::ArcChainTooLong => EventType::Arc(ArcEvent::ChainTooLong).into_err(), - mail_auth::Error::ArcInvalidInstance(instance) => { - EventType::Arc(ArcEvent::InvalidInstance).ctx(Key::Id, instance) - } - mail_auth::Error::ArcInvalidCV => EventType::Arc(ArcEvent::InvalidCv).into_err(), - mail_auth::Error::ArcHasHeaderTag => EventType::Arc(ArcEvent::HasHeaderTag).into_err(), - mail_auth::Error::ArcBrokenChain => EventType::Arc(ArcEvent::BrokenChain).into_err(), mail_auth::Error::NotAligned => { EventType::MailAuth(MailAuthEvent::PolicyNotAligned).into_err() } - mail_auth::Error::InvalidRecordType => { - EventType::MailAuth(MailAuthEvent::DnsInvalidRecordType).into_err() - } + mail_auth::Error::Crypto(err) => match err { + mail_auth::common::crypto::CryptoError::Library(details) => { + EventType::MailAuth(MailAuthEvent::Crypto) + .into_err() + .details(CompactString::from(details)) + } + mail_auth::common::crypto::CryptoError::FailedVerification => { + EventType::Dkim(DkimEvent::FailedVerification).into_err() + } + mail_auth::common::crypto::CryptoError::IncompatibleAlgorithms => { + EventType::Dkim(DkimEvent::IncompatibleAlgorithms).into_err() + } + }, + mail_auth::Error::Dns(err) => match err { + mail_auth::DnsError::Resolver(details) => { + EventType::MailAuth(MailAuthEvent::DnsError) + .into_err() + .details(CompactString::from(details)) + } + mail_auth::DnsError::RecordNotFound(code) => { + EventType::MailAuth(MailAuthEvent::DnsRecordNotFound) + .into_err() + .code(code.to_str()) + } + mail_auth::DnsError::InvalidRecordType => { + EventType::MailAuth(MailAuthEvent::DnsInvalidRecordType).into_err() + } + }, + mail_auth::Error::Dkim(err) => match err { + mail_auth::dkim::DkimError::UnsupportedVersion => { + EventType::Dkim(DkimEvent::UnsupportedVersion).into_err() + } + mail_auth::dkim::DkimError::UnsupportedAlgorithm => { + EventType::Dkim(DkimEvent::UnsupportedAlgorithm).into_err() + } + mail_auth::dkim::DkimError::UnsupportedCanonicalization => { + EventType::Dkim(DkimEvent::UnsupportedCanonicalization).into_err() + } + mail_auth::dkim::DkimError::UnsupportedKeyType => { + EventType::Dkim(DkimEvent::UnsupportedKeyType).into_err() + } + mail_auth::dkim::DkimError::FailedBodyHashMatch => { + EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err() + } + mail_auth::dkim::DkimError::FailedAuidMatch => { + EventType::Dkim(DkimEvent::FailedAuidMatch).into_err() + } + mail_auth::dkim::DkimError::RevokedPublicKey => { + EventType::Dkim(DkimEvent::RevokedPublicKey).into_err() + } + mail_auth::dkim::DkimError::SignatureExpired => { + EventType::Dkim(DkimEvent::SignatureExpired).into_err() + } + mail_auth::dkim::DkimError::SignatureLength => { + EventType::Dkim(DkimEvent::SignatureLength).into_err() + } + }, + mail_auth::Error::Arc(err) => match err { + mail_auth::arc::ArcError::ChainTooLong => { + EventType::Arc(ArcEvent::ChainTooLong).into_err() + } + mail_auth::arc::ArcError::InvalidInstance(instance) => { + EventType::Arc(ArcEvent::InvalidInstance).ctx(Key::Id, instance) + } + mail_auth::arc::ArcError::InvalidCV => { + EventType::Arc(ArcEvent::InvalidCv).into_err() + } + mail_auth::arc::ArcError::HasHeaderTag => { + EventType::Arc(ArcEvent::HasHeaderTag).into_err() + } + mail_auth::arc::ArcError::BrokenChain => { + EventType::Arc(ArcEvent::BrokenChain).into_err() + } + mail_auth::arc::ArcError::FailedBodyHashMatch => { + EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err() + } + mail_auth::arc::ArcError::SignatureExpired => { + EventType::Dkim(DkimEvent::SignatureExpired).into_err() + } + mail_auth::arc::ArcError::SignatureLength => { + EventType::Dkim(DkimEvent::SignatureLength).into_err() + } + }, + mail_auth::Error::Dkim2(err) => match err { + mail_auth::dkim2::Dkim2Error::InstanceMissing(m) => { + EventType::Dkim(DkimEvent::InstanceMissing).ctx(Key::Id, m) + } + mail_auth::dkim2::Dkim2Error::InstanceSyntax(m) => { + EventType::Dkim(DkimEvent::InstanceSyntax).ctx(Key::Id, m) + } + mail_auth::dkim2::Dkim2Error::InstanceTagMissing { m, tag } => { + EventType::Dkim(DkimEvent::InstanceTagMissing) + .ctx(Key::Id, m) + .details(tag) + } + mail_auth::dkim2::Dkim2Error::InstanceNotSigned(m) => { + EventType::Dkim(DkimEvent::InstanceNotSigned).ctx(Key::Id, m) + } + mail_auth::dkim2::Dkim2Error::InstanceAboveSignature(m) => { + EventType::Dkim(DkimEvent::InstanceAboveSignature).ctx(Key::Id, m) + } + mail_auth::dkim2::Dkim2Error::SignatureMissing(i) => { + EventType::Dkim(DkimEvent::SignatureMissing).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::SignatureSyntax(i) => { + EventType::Dkim(DkimEvent::SignatureSyntax).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::SignatureTagMissing { i, tag } => { + EventType::Dkim(DkimEvent::SignatureTagMissing) + .ctx(Key::Id, i) + .details(tag) + } + mail_auth::dkim2::Dkim2Error::SignatureTagUnexpected { i, tag } => { + EventType::Dkim(DkimEvent::SignatureTagUnexpected) + .ctx(Key::Id, i) + .details(tag) + } + mail_auth::dkim2::Dkim2Error::SequenceGap => { + EventType::Dkim(DkimEvent::SequenceGap).into_err() + } + mail_auth::dkim2::Dkim2Error::SequenceOverflow => { + EventType::Dkim(DkimEvent::SequenceOverflow).into_err() + } + mail_auth::dkim2::Dkim2Error::SignatureExpired(i) => { + EventType::Dkim(DkimEvent::SignatureExpired).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::MailFromMismatch(i) => { + EventType::Dkim(DkimEvent::MailFromMismatch).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::RcptToMismatch(i) => { + EventType::Dkim(DkimEvent::RcptToMismatch).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::MailFromDomainMismatch(i) => { + EventType::Dkim(DkimEvent::MailFromDomainMismatch).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::NextDomainMismatch(i) => { + EventType::Dkim(DkimEvent::NextDomainMismatch).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::PublicKeyFetch(i) => { + EventType::Dkim(DkimEvent::PublicKeyFetch).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::PublicKeyMissing(i) => { + EventType::Dkim(DkimEvent::PublicKeyMissing).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::PublicKeyMultiple(i) => { + EventType::Dkim(DkimEvent::PublicKeyMultiple).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::PublicKeySyntax(i) => { + EventType::Dkim(DkimEvent::PublicKeySyntax).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::PublicKeyAlgorithmMismatch(i) => { + EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::PublicKeyRevoked(i) => { + EventType::Dkim(DkimEvent::RevokedPublicKey).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::IncorrectSignature(i) => { + EventType::Dkim(DkimEvent::FailedVerification).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::NoValidAlgorithm(i) => { + EventType::Dkim(DkimEvent::NoValidAlgorithm).ctx(Key::Id, i) + } + mail_auth::dkim2::Dkim2Error::HeaderHashMismatch(m) => { + EventType::Dkim(DkimEvent::HeaderHashMismatch).ctx(Key::Id, m) + } + mail_auth::dkim2::Dkim2Error::BodyHashMismatch(m) => { + EventType::Dkim(DkimEvent::FailedBodyHashMatch).ctx(Key::Id, m) + } + mail_auth::dkim2::Dkim2Error::Modified => { + EventType::Dkim(DkimEvent::Modified).into_err() + } + mail_auth::dkim2::Dkim2Error::Exploded => { + EventType::Dkim(DkimEvent::Exploded).into_err() + } + }, } } } diff --git a/crates/trc/src/event/enums.rs b/crates/trc/src/event/enums.rs index 53d883df..aa4523ae 100644 --- a/crates/trc/src/event/enums.rs +++ b/crates/trc/src/event/enums.rs @@ -6,8 +6,8 @@ // This file is auto-generated. Do not edit directly. -pub const TOTAL_EVENT_COUNT: usize = 606; -pub const TOTAL_METRIC_COUNT: usize = 340; +pub const TOTAL_EVENT_COUNT: usize = 630; +pub const TOTAL_METRIC_COUNT: usize = 364; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum EventType { @@ -229,6 +229,30 @@ pub enum DkimEvent { SignatureRetiring = 598, SignatureRetired = 599, SignatureDeleted = 600, + InstanceMissing = 606, + InstanceSyntax = 607, + InstanceTagMissing = 608, + InstanceNotSigned = 609, + InstanceAboveSignature = 610, + SignatureMissing = 611, + SignatureSyntax = 612, + SignatureTagMissing = 613, + SignatureTagUnexpected = 614, + SequenceGap = 615, + SequenceOverflow = 616, + MailFromMismatch = 617, + RcptToMismatch = 618, + MailFromDomainMismatch = 619, + NextDomainMismatch = 620, + PublicKeyFetch = 621, + PublicKeyMissing = 622, + PublicKeyMultiple = 623, + PublicKeySyntax = 624, + PublicKeyAlgorithmMismatch = 625, + NoValidAlgorithm = 626, + HeaderHashMismatch = 627, + Modified = 628, + Exploded = 629, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -959,6 +983,30 @@ pub enum MetricType { DkimSignatureExpired = 103, DkimSignatureLength = 104, DkimSignerNotFound = 105, + DkimInstanceMissing = 340, + DkimInstanceSyntax = 341, + DkimInstanceTagMissing = 342, + DkimInstanceNotSigned = 343, + DkimInstanceAboveSignature = 344, + DkimSignatureMissing = 345, + DkimSignatureSyntax = 346, + DkimSignatureTagMissing = 347, + DkimSignatureTagUnexpected = 348, + DkimSequenceGap = 349, + DkimSequenceOverflow = 350, + DkimMailFromMismatch = 351, + DkimRcptToMismatch = 352, + DkimMailFromDomainMismatch = 353, + DkimNextDomainMismatch = 354, + DkimPublicKeyFetch = 355, + DkimPublicKeyMissing = 356, + DkimPublicKeyMultiple = 357, + DkimPublicKeySyntax = 358, + DkimPublicKeyAlgorithmMismatch = 359, + DkimNoValidAlgorithm = 360, + DkimHeaderHashMismatch = 361, + DkimModified = 362, + DkimExploded = 363, DmarcPass = 106, DmarcFail = 107, DmarcPermError = 108, diff --git a/crates/trc/src/event/enums_impl.rs b/crates/trc/src/event/enums_impl.rs index 56e1c715..e3cec6d6 100644 --- a/crates/trc/src/event/enums_impl.rs +++ b/crates/trc/src/event/enums_impl.rs @@ -144,6 +144,30 @@ impl EventType { b"dkim.signature-retiring" => EventType::Dkim(DkimEvent::SignatureRetiring), b"dkim.signature-retired" => EventType::Dkim(DkimEvent::SignatureRetired), b"dkim.signature-deleted" => EventType::Dkim(DkimEvent::SignatureDeleted), + b"dkim.instance-missing" => EventType::Dkim(DkimEvent::InstanceMissing), + b"dkim.instance-syntax" => EventType::Dkim(DkimEvent::InstanceSyntax), + b"dkim.instance-tag-missing" => EventType::Dkim(DkimEvent::InstanceTagMissing), + b"dkim.instance-not-signed" => EventType::Dkim(DkimEvent::InstanceNotSigned), + b"dkim.instance-above-signature" => EventType::Dkim(DkimEvent::InstanceAboveSignature), + b"dkim.signature-missing" => EventType::Dkim(DkimEvent::SignatureMissing), + b"dkim.signature-syntax" => EventType::Dkim(DkimEvent::SignatureSyntax), + b"dkim.signature-tag-missing" => EventType::Dkim(DkimEvent::SignatureTagMissing), + b"dkim.signature-tag-unexpected" => EventType::Dkim(DkimEvent::SignatureTagUnexpected), + b"dkim.sequence-gap" => EventType::Dkim(DkimEvent::SequenceGap), + b"dkim.sequence-overflow" => EventType::Dkim(DkimEvent::SequenceOverflow), + b"dkim.mail-from-mismatch" => EventType::Dkim(DkimEvent::MailFromMismatch), + b"dkim.rcpt-to-mismatch" => EventType::Dkim(DkimEvent::RcptToMismatch), + b"dkim.mail-from-domain-mismatch" => EventType::Dkim(DkimEvent::MailFromDomainMismatch), + b"dkim.next-domain-mismatch" => EventType::Dkim(DkimEvent::NextDomainMismatch), + b"dkim.public-key-fetch" => EventType::Dkim(DkimEvent::PublicKeyFetch), + b"dkim.public-key-missing" => EventType::Dkim(DkimEvent::PublicKeyMissing), + b"dkim.public-key-multiple" => EventType::Dkim(DkimEvent::PublicKeyMultiple), + b"dkim.public-key-syntax" => EventType::Dkim(DkimEvent::PublicKeySyntax), + b"dkim.public-key-algorithm-mismatch" => EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch), + b"dkim.no-valid-algorithm" => EventType::Dkim(DkimEvent::NoValidAlgorithm), + b"dkim.header-hash-mismatch" => EventType::Dkim(DkimEvent::HeaderHashMismatch), + b"dkim.modified" => EventType::Dkim(DkimEvent::Modified), + b"dkim.exploded" => EventType::Dkim(DkimEvent::Exploded), b"dmarc.pass" => EventType::Dmarc(DmarcEvent::Pass), b"dmarc.fail" => EventType::Dmarc(DmarcEvent::Fail), b"dmarc.perm-error" => EventType::Dmarc(DmarcEvent::PermError), @@ -776,6 +800,32 @@ impl EventType { EventType::Dkim(DkimEvent::SignatureRetiring) => "dkim.signature-retiring", EventType::Dkim(DkimEvent::SignatureRetired) => "dkim.signature-retired", EventType::Dkim(DkimEvent::SignatureDeleted) => "dkim.signature-deleted", + EventType::Dkim(DkimEvent::InstanceMissing) => "dkim.instance-missing", + EventType::Dkim(DkimEvent::InstanceSyntax) => "dkim.instance-syntax", + EventType::Dkim(DkimEvent::InstanceTagMissing) => "dkim.instance-tag-missing", + EventType::Dkim(DkimEvent::InstanceNotSigned) => "dkim.instance-not-signed", + EventType::Dkim(DkimEvent::InstanceAboveSignature) => "dkim.instance-above-signature", + EventType::Dkim(DkimEvent::SignatureMissing) => "dkim.signature-missing", + EventType::Dkim(DkimEvent::SignatureSyntax) => "dkim.signature-syntax", + EventType::Dkim(DkimEvent::SignatureTagMissing) => "dkim.signature-tag-missing", + EventType::Dkim(DkimEvent::SignatureTagUnexpected) => "dkim.signature-tag-unexpected", + EventType::Dkim(DkimEvent::SequenceGap) => "dkim.sequence-gap", + EventType::Dkim(DkimEvent::SequenceOverflow) => "dkim.sequence-overflow", + EventType::Dkim(DkimEvent::MailFromMismatch) => "dkim.mail-from-mismatch", + EventType::Dkim(DkimEvent::RcptToMismatch) => "dkim.rcpt-to-mismatch", + EventType::Dkim(DkimEvent::MailFromDomainMismatch) => "dkim.mail-from-domain-mismatch", + EventType::Dkim(DkimEvent::NextDomainMismatch) => "dkim.next-domain-mismatch", + EventType::Dkim(DkimEvent::PublicKeyFetch) => "dkim.public-key-fetch", + EventType::Dkim(DkimEvent::PublicKeyMissing) => "dkim.public-key-missing", + EventType::Dkim(DkimEvent::PublicKeyMultiple) => "dkim.public-key-multiple", + EventType::Dkim(DkimEvent::PublicKeySyntax) => "dkim.public-key-syntax", + EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch) => { + "dkim.public-key-algorithm-mismatch" + } + EventType::Dkim(DkimEvent::NoValidAlgorithm) => "dkim.no-valid-algorithm", + EventType::Dkim(DkimEvent::HeaderHashMismatch) => "dkim.header-hash-mismatch", + EventType::Dkim(DkimEvent::Modified) => "dkim.modified", + EventType::Dkim(DkimEvent::Exploded) => "dkim.exploded", EventType::Dmarc(DmarcEvent::Pass) => "dmarc.pass", EventType::Dmarc(DmarcEvent::Fail) => "dmarc.fail", EventType::Dmarc(DmarcEvent::PermError) => "dmarc.perm-error", @@ -1501,6 +1551,30 @@ impl EventType { EventType::Dkim(DkimEvent::SignatureRetiring) => 598, EventType::Dkim(DkimEvent::SignatureRetired) => 599, EventType::Dkim(DkimEvent::SignatureDeleted) => 600, + EventType::Dkim(DkimEvent::InstanceMissing) => 606, + EventType::Dkim(DkimEvent::InstanceSyntax) => 607, + EventType::Dkim(DkimEvent::InstanceTagMissing) => 608, + EventType::Dkim(DkimEvent::InstanceNotSigned) => 609, + EventType::Dkim(DkimEvent::InstanceAboveSignature) => 610, + EventType::Dkim(DkimEvent::SignatureMissing) => 611, + EventType::Dkim(DkimEvent::SignatureSyntax) => 612, + EventType::Dkim(DkimEvent::SignatureTagMissing) => 613, + EventType::Dkim(DkimEvent::SignatureTagUnexpected) => 614, + EventType::Dkim(DkimEvent::SequenceGap) => 615, + EventType::Dkim(DkimEvent::SequenceOverflow) => 616, + EventType::Dkim(DkimEvent::MailFromMismatch) => 617, + EventType::Dkim(DkimEvent::RcptToMismatch) => 618, + EventType::Dkim(DkimEvent::MailFromDomainMismatch) => 619, + EventType::Dkim(DkimEvent::NextDomainMismatch) => 620, + EventType::Dkim(DkimEvent::PublicKeyFetch) => 621, + EventType::Dkim(DkimEvent::PublicKeyMissing) => 622, + EventType::Dkim(DkimEvent::PublicKeyMultiple) => 623, + EventType::Dkim(DkimEvent::PublicKeySyntax) => 624, + EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch) => 625, + EventType::Dkim(DkimEvent::NoValidAlgorithm) => 626, + EventType::Dkim(DkimEvent::HeaderHashMismatch) => 627, + EventType::Dkim(DkimEvent::Modified) => 628, + EventType::Dkim(DkimEvent::Exploded) => 629, EventType::Dmarc(DmarcEvent::Pass) => 134, EventType::Dmarc(DmarcEvent::Fail) => 132, EventType::Dmarc(DmarcEvent::PermError) => 135, @@ -2112,6 +2186,30 @@ impl EventType { 598 => Some(EventType::Dkim(DkimEvent::SignatureRetiring)), 599 => Some(EventType::Dkim(DkimEvent::SignatureRetired)), 600 => Some(EventType::Dkim(DkimEvent::SignatureDeleted)), + 606 => Some(EventType::Dkim(DkimEvent::InstanceMissing)), + 607 => Some(EventType::Dkim(DkimEvent::InstanceSyntax)), + 608 => Some(EventType::Dkim(DkimEvent::InstanceTagMissing)), + 609 => Some(EventType::Dkim(DkimEvent::InstanceNotSigned)), + 610 => Some(EventType::Dkim(DkimEvent::InstanceAboveSignature)), + 611 => Some(EventType::Dkim(DkimEvent::SignatureMissing)), + 612 => Some(EventType::Dkim(DkimEvent::SignatureSyntax)), + 613 => Some(EventType::Dkim(DkimEvent::SignatureTagMissing)), + 614 => Some(EventType::Dkim(DkimEvent::SignatureTagUnexpected)), + 615 => Some(EventType::Dkim(DkimEvent::SequenceGap)), + 616 => Some(EventType::Dkim(DkimEvent::SequenceOverflow)), + 617 => Some(EventType::Dkim(DkimEvent::MailFromMismatch)), + 618 => Some(EventType::Dkim(DkimEvent::RcptToMismatch)), + 619 => Some(EventType::Dkim(DkimEvent::MailFromDomainMismatch)), + 620 => Some(EventType::Dkim(DkimEvent::NextDomainMismatch)), + 621 => Some(EventType::Dkim(DkimEvent::PublicKeyFetch)), + 622 => Some(EventType::Dkim(DkimEvent::PublicKeyMissing)), + 623 => Some(EventType::Dkim(DkimEvent::PublicKeyMultiple)), + 624 => Some(EventType::Dkim(DkimEvent::PublicKeySyntax)), + 625 => Some(EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch)), + 626 => Some(EventType::Dkim(DkimEvent::NoValidAlgorithm)), + 627 => Some(EventType::Dkim(DkimEvent::HeaderHashMismatch)), + 628 => Some(EventType::Dkim(DkimEvent::Modified)), + 629 => Some(EventType::Dkim(DkimEvent::Exploded)), 134 => Some(EventType::Dmarc(DmarcEvent::Pass)), 132 => Some(EventType::Dmarc(DmarcEvent::Fail)), 135 => Some(EventType::Dmarc(DmarcEvent::PermError)), @@ -3139,6 +3237,34 @@ impl EventType { EventType::Dkim(DkimEvent::SignatureRetiring) => "DKIM signature retiring", EventType::Dkim(DkimEvent::SignatureRetired) => "DKIM signature retired", EventType::Dkim(DkimEvent::SignatureDeleted) => "DKIM signature deleted", + EventType::Dkim(DkimEvent::InstanceMissing) => "DKIM2 message-instance missing", + EventType::Dkim(DkimEvent::InstanceSyntax) => "DKIM2 message-instance syntax error", + EventType::Dkim(DkimEvent::InstanceTagMissing) => "DKIM2 message-instance tag missing", + EventType::Dkim(DkimEvent::InstanceNotSigned) => "DKIM2 message-instance not signed", + EventType::Dkim(DkimEvent::InstanceAboveSignature) => { + "DKIM2 message-instance above signature" + } + EventType::Dkim(DkimEvent::SignatureMissing) => "DKIM2 signature missing", + EventType::Dkim(DkimEvent::SignatureSyntax) => "DKIM2 signature syntax error", + EventType::Dkim(DkimEvent::SignatureTagMissing) => "DKIM2 signature tag missing", + EventType::Dkim(DkimEvent::SignatureTagUnexpected) => "DKIM2 signature unexpected tag", + EventType::Dkim(DkimEvent::SequenceGap) => "DKIM2 sequence gap", + EventType::Dkim(DkimEvent::SequenceOverflow) => "DKIM2 sequence overflow", + EventType::Dkim(DkimEvent::MailFromMismatch) => "DKIM2 MAIL FROM mismatch", + EventType::Dkim(DkimEvent::RcptToMismatch) => "DKIM2 RCPT TO mismatch", + EventType::Dkim(DkimEvent::MailFromDomainMismatch) => "DKIM2 MAIL FROM domain mismatch", + EventType::Dkim(DkimEvent::NextDomainMismatch) => "DKIM2 next domain mismatch", + EventType::Dkim(DkimEvent::PublicKeyFetch) => "DKIM2 public key fetch error", + EventType::Dkim(DkimEvent::PublicKeyMissing) => "DKIM2 public key missing", + EventType::Dkim(DkimEvent::PublicKeyMultiple) => "DKIM2 multiple public keys", + EventType::Dkim(DkimEvent::PublicKeySyntax) => "DKIM2 public key syntax error", + EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch) => { + "DKIM2 public key algorithm mismatch" + } + EventType::Dkim(DkimEvent::NoValidAlgorithm) => "DKIM2 no valid algorithm", + EventType::Dkim(DkimEvent::HeaderHashMismatch) => "DKIM2 header hash mismatch", + EventType::Dkim(DkimEvent::Modified) => "DKIM2 message modified", + EventType::Dkim(DkimEvent::Exploded) => "DKIM2 message exploded", EventType::Dmarc(DmarcEvent::Pass) => "DMARC check passed", EventType::Dmarc(DmarcEvent::Fail) => "DMARC check failed", EventType::Dmarc(DmarcEvent::PermError) => "DMARC permanent error", @@ -4141,6 +4267,30 @@ impl EventType { EventType::Dkim(DkimEvent::SignatureRetiring), EventType::Dkim(DkimEvent::SignatureRetired), EventType::Dkim(DkimEvent::SignatureDeleted), + EventType::Dkim(DkimEvent::InstanceMissing), + EventType::Dkim(DkimEvent::InstanceSyntax), + EventType::Dkim(DkimEvent::InstanceTagMissing), + EventType::Dkim(DkimEvent::InstanceNotSigned), + EventType::Dkim(DkimEvent::InstanceAboveSignature), + EventType::Dkim(DkimEvent::SignatureMissing), + EventType::Dkim(DkimEvent::SignatureSyntax), + EventType::Dkim(DkimEvent::SignatureTagMissing), + EventType::Dkim(DkimEvent::SignatureTagUnexpected), + EventType::Dkim(DkimEvent::SequenceGap), + EventType::Dkim(DkimEvent::SequenceOverflow), + EventType::Dkim(DkimEvent::MailFromMismatch), + EventType::Dkim(DkimEvent::RcptToMismatch), + EventType::Dkim(DkimEvent::MailFromDomainMismatch), + EventType::Dkim(DkimEvent::NextDomainMismatch), + EventType::Dkim(DkimEvent::PublicKeyFetch), + EventType::Dkim(DkimEvent::PublicKeyMissing), + EventType::Dkim(DkimEvent::PublicKeyMultiple), + EventType::Dkim(DkimEvent::PublicKeySyntax), + EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch), + EventType::Dkim(DkimEvent::NoValidAlgorithm), + EventType::Dkim(DkimEvent::HeaderHashMismatch), + EventType::Dkim(DkimEvent::Modified), + EventType::Dkim(DkimEvent::Exploded), EventType::Dmarc(DmarcEvent::Pass), EventType::Dmarc(DmarcEvent::Fail), EventType::Dmarc(DmarcEvent::PermError), @@ -4705,6 +4855,30 @@ impl MetricType { b"dkim.signature-expired" => MetricType::DkimSignatureExpired, b"dkim.signature-length" => MetricType::DkimSignatureLength, b"dkim.signer-not-found" => MetricType::DkimSignerNotFound, + b"dkim.instance-missing" => MetricType::DkimInstanceMissing, + b"dkim.instance-syntax" => MetricType::DkimInstanceSyntax, + b"dkim.instance-tag-missing" => MetricType::DkimInstanceTagMissing, + b"dkim.instance-not-signed" => MetricType::DkimInstanceNotSigned, + b"dkim.instance-above-signature" => MetricType::DkimInstanceAboveSignature, + b"dkim.signature-missing" => MetricType::DkimSignatureMissing, + b"dkim.signature-syntax" => MetricType::DkimSignatureSyntax, + b"dkim.signature-tag-missing" => MetricType::DkimSignatureTagMissing, + b"dkim.signature-tag-unexpected" => MetricType::DkimSignatureTagUnexpected, + b"dkim.sequence-gap" => MetricType::DkimSequenceGap, + b"dkim.sequence-overflow" => MetricType::DkimSequenceOverflow, + b"dkim.mail-from-mismatch" => MetricType::DkimMailFromMismatch, + b"dkim.rcpt-to-mismatch" => MetricType::DkimRcptToMismatch, + b"dkim.mail-from-domain-mismatch" => MetricType::DkimMailFromDomainMismatch, + b"dkim.next-domain-mismatch" => MetricType::DkimNextDomainMismatch, + b"dkim.public-key-fetch" => MetricType::DkimPublicKeyFetch, + b"dkim.public-key-missing" => MetricType::DkimPublicKeyMissing, + b"dkim.public-key-multiple" => MetricType::DkimPublicKeyMultiple, + b"dkim.public-key-syntax" => MetricType::DkimPublicKeySyntax, + b"dkim.public-key-algorithm-mismatch" => MetricType::DkimPublicKeyAlgorithmMismatch, + b"dkim.no-valid-algorithm" => MetricType::DkimNoValidAlgorithm, + b"dkim.header-hash-mismatch" => MetricType::DkimHeaderHashMismatch, + b"dkim.modified" => MetricType::DkimModified, + b"dkim.exploded" => MetricType::DkimExploded, b"dmarc.pass" => MetricType::DmarcPass, b"dmarc.fail" => MetricType::DmarcFail, b"dmarc.perm-error" => MetricType::DmarcPermError, @@ -5051,6 +5225,30 @@ impl MetricType { MetricType::DkimSignatureExpired => "dkim.signature-expired", MetricType::DkimSignatureLength => "dkim.signature-length", MetricType::DkimSignerNotFound => "dkim.signer-not-found", + MetricType::DkimInstanceMissing => "dkim.instance-missing", + MetricType::DkimInstanceSyntax => "dkim.instance-syntax", + MetricType::DkimInstanceTagMissing => "dkim.instance-tag-missing", + MetricType::DkimInstanceNotSigned => "dkim.instance-not-signed", + MetricType::DkimInstanceAboveSignature => "dkim.instance-above-signature", + MetricType::DkimSignatureMissing => "dkim.signature-missing", + MetricType::DkimSignatureSyntax => "dkim.signature-syntax", + MetricType::DkimSignatureTagMissing => "dkim.signature-tag-missing", + MetricType::DkimSignatureTagUnexpected => "dkim.signature-tag-unexpected", + MetricType::DkimSequenceGap => "dkim.sequence-gap", + MetricType::DkimSequenceOverflow => "dkim.sequence-overflow", + MetricType::DkimMailFromMismatch => "dkim.mail-from-mismatch", + MetricType::DkimRcptToMismatch => "dkim.rcpt-to-mismatch", + MetricType::DkimMailFromDomainMismatch => "dkim.mail-from-domain-mismatch", + MetricType::DkimNextDomainMismatch => "dkim.next-domain-mismatch", + MetricType::DkimPublicKeyFetch => "dkim.public-key-fetch", + MetricType::DkimPublicKeyMissing => "dkim.public-key-missing", + MetricType::DkimPublicKeyMultiple => "dkim.public-key-multiple", + MetricType::DkimPublicKeySyntax => "dkim.public-key-syntax", + MetricType::DkimPublicKeyAlgorithmMismatch => "dkim.public-key-algorithm-mismatch", + MetricType::DkimNoValidAlgorithm => "dkim.no-valid-algorithm", + MetricType::DkimHeaderHashMismatch => "dkim.header-hash-mismatch", + MetricType::DkimModified => "dkim.modified", + MetricType::DkimExploded => "dkim.exploded", MetricType::DmarcPass => "dmarc.pass", MetricType::DmarcFail => "dmarc.fail", MetricType::DmarcPermError => "dmarc.perm-error", @@ -5408,6 +5606,30 @@ impl MetricType { MetricType::DkimSignatureExpired => 103, MetricType::DkimSignatureLength => 104, MetricType::DkimSignerNotFound => 105, + MetricType::DkimInstanceMissing => 340, + MetricType::DkimInstanceSyntax => 341, + MetricType::DkimInstanceTagMissing => 342, + MetricType::DkimInstanceNotSigned => 343, + MetricType::DkimInstanceAboveSignature => 344, + MetricType::DkimSignatureMissing => 345, + MetricType::DkimSignatureSyntax => 346, + MetricType::DkimSignatureTagMissing => 347, + MetricType::DkimSignatureTagUnexpected => 348, + MetricType::DkimSequenceGap => 349, + MetricType::DkimSequenceOverflow => 350, + MetricType::DkimMailFromMismatch => 351, + MetricType::DkimRcptToMismatch => 352, + MetricType::DkimMailFromDomainMismatch => 353, + MetricType::DkimNextDomainMismatch => 354, + MetricType::DkimPublicKeyFetch => 355, + MetricType::DkimPublicKeyMissing => 356, + MetricType::DkimPublicKeyMultiple => 357, + MetricType::DkimPublicKeySyntax => 358, + MetricType::DkimPublicKeyAlgorithmMismatch => 359, + MetricType::DkimNoValidAlgorithm => 360, + MetricType::DkimHeaderHashMismatch => 361, + MetricType::DkimModified => 362, + MetricType::DkimExploded => 363, MetricType::DmarcPass => 106, MetricType::DmarcFail => 107, MetricType::DmarcPermError => 108, @@ -5753,6 +5975,30 @@ impl MetricType { 103 => Some(MetricType::DkimSignatureExpired), 104 => Some(MetricType::DkimSignatureLength), 105 => Some(MetricType::DkimSignerNotFound), + 340 => Some(MetricType::DkimInstanceMissing), + 341 => Some(MetricType::DkimInstanceSyntax), + 342 => Some(MetricType::DkimInstanceTagMissing), + 343 => Some(MetricType::DkimInstanceNotSigned), + 344 => Some(MetricType::DkimInstanceAboveSignature), + 345 => Some(MetricType::DkimSignatureMissing), + 346 => Some(MetricType::DkimSignatureSyntax), + 347 => Some(MetricType::DkimSignatureTagMissing), + 348 => Some(MetricType::DkimSignatureTagUnexpected), + 349 => Some(MetricType::DkimSequenceGap), + 350 => Some(MetricType::DkimSequenceOverflow), + 351 => Some(MetricType::DkimMailFromMismatch), + 352 => Some(MetricType::DkimRcptToMismatch), + 353 => Some(MetricType::DkimMailFromDomainMismatch), + 354 => Some(MetricType::DkimNextDomainMismatch), + 355 => Some(MetricType::DkimPublicKeyFetch), + 356 => Some(MetricType::DkimPublicKeyMissing), + 357 => Some(MetricType::DkimPublicKeyMultiple), + 358 => Some(MetricType::DkimPublicKeySyntax), + 359 => Some(MetricType::DkimPublicKeyAlgorithmMismatch), + 360 => Some(MetricType::DkimNoValidAlgorithm), + 361 => Some(MetricType::DkimHeaderHashMismatch), + 362 => Some(MetricType::DkimModified), + 363 => Some(MetricType::DkimExploded), 106 => Some(MetricType::DmarcPass), 107 => Some(MetricType::DmarcFail), 108 => Some(MetricType::DmarcPermError), @@ -6096,6 +6342,30 @@ impl MetricType { MetricType::DkimSignatureExpired => 124, MetricType::DkimSignatureLength => 125, MetricType::DkimSignerNotFound => 126, + MetricType::DkimInstanceMissing => 606, + MetricType::DkimInstanceSyntax => 607, + MetricType::DkimInstanceTagMissing => 608, + MetricType::DkimInstanceNotSigned => 609, + MetricType::DkimInstanceAboveSignature => 610, + MetricType::DkimSignatureMissing => 611, + MetricType::DkimSignatureSyntax => 612, + MetricType::DkimSignatureTagMissing => 613, + MetricType::DkimSignatureTagUnexpected => 614, + MetricType::DkimSequenceGap => 615, + MetricType::DkimSequenceOverflow => 616, + MetricType::DkimMailFromMismatch => 617, + MetricType::DkimRcptToMismatch => 618, + MetricType::DkimMailFromDomainMismatch => 619, + MetricType::DkimNextDomainMismatch => 620, + MetricType::DkimPublicKeyFetch => 621, + MetricType::DkimPublicKeyMissing => 622, + MetricType::DkimPublicKeyMultiple => 623, + MetricType::DkimPublicKeySyntax => 624, + MetricType::DkimPublicKeyAlgorithmMismatch => 625, + MetricType::DkimNoValidAlgorithm => 626, + MetricType::DkimHeaderHashMismatch => 627, + MetricType::DkimModified => 628, + MetricType::DkimExploded => 629, MetricType::DmarcPass => 134, MetricType::DmarcFail => 132, MetricType::DmarcPermError => 135, @@ -6420,6 +6690,30 @@ impl MetricType { MetricType::DkimSignatureExpired => "DKIM signature expired", MetricType::DkimSignatureLength => "DKIM signature length issue", MetricType::DkimSignerNotFound => "DKIM signer not found", + MetricType::DkimInstanceMissing => "DKIM2 message-instance missing", + MetricType::DkimInstanceSyntax => "DKIM2 message-instance syntax error", + MetricType::DkimInstanceTagMissing => "DKIM2 message-instance tag missing", + MetricType::DkimInstanceNotSigned => "DKIM2 message-instance not signed", + MetricType::DkimInstanceAboveSignature => "DKIM2 message-instance above signature", + MetricType::DkimSignatureMissing => "DKIM2 signature missing", + MetricType::DkimSignatureSyntax => "DKIM2 signature syntax error", + MetricType::DkimSignatureTagMissing => "DKIM2 signature tag missing", + MetricType::DkimSignatureTagUnexpected => "DKIM2 signature unexpected tag", + MetricType::DkimSequenceGap => "DKIM2 sequence gap", + MetricType::DkimSequenceOverflow => "DKIM2 sequence overflow", + MetricType::DkimMailFromMismatch => "DKIM2 MAIL FROM mismatch", + MetricType::DkimRcptToMismatch => "DKIM2 RCPT TO mismatch", + MetricType::DkimMailFromDomainMismatch => "DKIM2 MAIL FROM domain mismatch", + MetricType::DkimNextDomainMismatch => "DKIM2 next domain mismatch", + MetricType::DkimPublicKeyFetch => "DKIM2 public key fetch error", + MetricType::DkimPublicKeyMissing => "DKIM2 public key missing", + MetricType::DkimPublicKeyMultiple => "DKIM2 multiple public keys", + MetricType::DkimPublicKeySyntax => "DKIM2 public key syntax error", + MetricType::DkimPublicKeyAlgorithmMismatch => "DKIM2 public key algorithm mismatch", + MetricType::DkimNoValidAlgorithm => "DKIM2 no valid algorithm", + MetricType::DkimHeaderHashMismatch => "DKIM2 header hash mismatch", + MetricType::DkimModified => "DKIM2 message modified", + MetricType::DkimExploded => "DKIM2 message exploded", MetricType::DmarcPass => "DMARC check passed", MetricType::DmarcFail => "DMARC check failed", MetricType::DmarcPermError => "DMARC permanent error", @@ -6782,6 +7076,30 @@ impl MetricType { | MetricType::DkimSignatureExpired | MetricType::DkimSignatureLength | MetricType::DkimSignerNotFound + | MetricType::DkimInstanceMissing + | MetricType::DkimInstanceSyntax + | MetricType::DkimInstanceTagMissing + | MetricType::DkimInstanceNotSigned + | MetricType::DkimInstanceAboveSignature + | MetricType::DkimSignatureMissing + | MetricType::DkimSignatureSyntax + | MetricType::DkimSignatureTagMissing + | MetricType::DkimSignatureTagUnexpected + | MetricType::DkimSequenceGap + | MetricType::DkimSequenceOverflow + | MetricType::DkimMailFromMismatch + | MetricType::DkimRcptToMismatch + | MetricType::DkimMailFromDomainMismatch + | MetricType::DkimNextDomainMismatch + | MetricType::DkimPublicKeyFetch + | MetricType::DkimPublicKeyMissing + | MetricType::DkimPublicKeyMultiple + | MetricType::DkimPublicKeySyntax + | MetricType::DkimPublicKeyAlgorithmMismatch + | MetricType::DkimNoValidAlgorithm + | MetricType::DkimHeaderHashMismatch + | MetricType::DkimModified + | MetricType::DkimExploded | MetricType::DmarcPass | MetricType::DmarcFail | MetricType::DmarcPermError @@ -7120,6 +7438,30 @@ impl MetricType { MetricType::DkimSignatureExpired, MetricType::DkimSignatureLength, MetricType::DkimSignerNotFound, + MetricType::DkimInstanceMissing, + MetricType::DkimInstanceSyntax, + MetricType::DkimInstanceTagMissing, + MetricType::DkimInstanceNotSigned, + MetricType::DkimInstanceAboveSignature, + MetricType::DkimSignatureMissing, + MetricType::DkimSignatureSyntax, + MetricType::DkimSignatureTagMissing, + MetricType::DkimSignatureTagUnexpected, + MetricType::DkimSequenceGap, + MetricType::DkimSequenceOverflow, + MetricType::DkimMailFromMismatch, + MetricType::DkimRcptToMismatch, + MetricType::DkimMailFromDomainMismatch, + MetricType::DkimNextDomainMismatch, + MetricType::DkimPublicKeyFetch, + MetricType::DkimPublicKeyMissing, + MetricType::DkimPublicKeyMultiple, + MetricType::DkimPublicKeySyntax, + MetricType::DkimPublicKeyAlgorithmMismatch, + MetricType::DkimNoValidAlgorithm, + MetricType::DkimHeaderHashMismatch, + MetricType::DkimModified, + MetricType::DkimExploded, MetricType::DmarcPass, MetricType::DmarcFail, MetricType::DmarcPermError, diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index b4863371..7b95f671 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -12,7 +12,7 @@ rustls-platform-verifier = "0.7" tokio = { version = "1.47", features = ["net", "macros", "signal"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "tls12"] } serde = { version = "1.0", features = ["derive"]} -mail-auth = { version = "0.10" } +mail-auth = { path = "/Users/me/code/mail-auth" } smtp-proto = { version = "0.2" } ahash = { version = "0.8", features = ["serde"] } chrono = "0.4" diff --git a/resources/schema/schema.json.gz b/resources/schema/schema.json.gz index 634bb244..d46002f8 100644 Binary files a/resources/schema/schema.json.gz and b/resources/schema/schema.json.gz differ diff --git a/resources/schema/schema.json.sha256 b/resources/schema/schema.json.sha256 index d8237afb..017aae52 100644 --- a/resources/schema/schema.json.sha256 +++ b/resources/schema/schema.json.sha256 @@ -1 +1 @@ -zeYWlKx8i_-qA0NG_5jMhgD9U2mcTmGFevxlNBSDDoI \ No newline at end of file +FLxK3azkzVxELInWViuc-_dg8JEbSF7YkWZfH-PjzeA \ No newline at end of file diff --git a/tests/Cargo.toml b/tests/Cargo.toml index f594adc5..de8e3fc8 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -45,7 +45,7 @@ migration = { path = "../crates/migration", features = ["test_mode", "enterprise trc = { path = "../crates/trc", features = ["enterprise"] } managesieve = { path = "../crates/managesieve", features = ["test_mode", "enterprise"] } smtp-proto = { version = "0.2" } -mail-auth = { version = "0.10", features = ["test"] } +mail-auth = { path = "/Users/me/code/mail-auth", features = ["test"] } mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-builder = "0.4.4" sieve-rs = { version = "0.7", features = ["rkyv"] } diff --git a/tests/src/automation/dkim.rs b/tests/src/automation/dkim.rs index b7257873..bbdd2fa4 100644 --- a/tests/src/automation/dkim.rs +++ b/tests/src/automation/dkim.rs @@ -254,6 +254,7 @@ impl Account { match signature { DkimSignature::Dkim1RsaSha256(sig) => v1_rsa.push(sig), DkimSignature::Dkim1Ed25519Sha256(sig) => v1_ed25519.push(sig), + DkimSignature::Dkim2Ed25519Sha256(_) | DkimSignature::Dkim2RsaSha256(_) => todo!(), } }