mail_auth/common/
verify.rs1use super::{
8 cache::NoCache,
9 crypto::{Algorithm, VerifyingKey},
10};
11use crate::{
12 Error, IprevOutput, IprevResult, MX, MessageAuthenticator, Parameters, RecordSet,
13 ResolverCache, Txt, dkim::Canonicalization,
14};
15use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
16
17pub struct DomainKey {
18 pub p: Box<dyn VerifyingKey + Send + Sync>,
19 pub f: u64,
20}
21
22impl MessageAuthenticator {
23 pub async fn verify_iprev<'x, TXT, MXX, IPV4, IPV6, PTR>(
24 &self,
25 params: impl Into<Parameters<'x, IpAddr, TXT, MXX, IPV4, IPV6, PTR>>,
26 ) -> IprevOutput
27 where
28 TXT: ResolverCache<Box<str>, Txt> + 'x,
29 MXX: ResolverCache<Box<str>, RecordSet<MX>> + 'x,
30 IPV4: ResolverCache<Box<str>, RecordSet<Ipv4Addr>> + 'x,
31 IPV6: ResolverCache<Box<str>, RecordSet<Ipv6Addr>> + 'x,
32 PTR: ResolverCache<IpAddr, RecordSet<Box<str>>> + 'x,
33 {
34 let params = params.into();
35 match self.ptr_lookup(params.params, params.cache_ptr).await {
36 Ok(ptr) => {
37 let mut last_err = None;
38 for host in ptr.rrset.iter().take(2) {
39 match ¶ms.params {
40 IpAddr::V4(ip) => match self.ipv4_lookup(host, params.cache_ipv4).await {
41 Ok(ips) => {
42 if ips.rrset.iter().any(|cip| cip == ip) {
43 return IprevOutput {
44 result: IprevResult::Pass,
45 ptr: Some(ptr.rrset.clone()),
46 };
47 }
48 }
49 Err(err) => {
50 last_err = err.into();
51 }
52 },
53 IpAddr::V6(ip) => match self.ipv6_lookup(host, params.cache_ipv6).await {
54 Ok(ips) => {
55 if ips.rrset.iter().any(|cip| cip == ip) {
56 return IprevOutput {
57 result: IprevResult::Pass,
58 ptr: Some(ptr.rrset.clone()),
59 };
60 }
61 }
62 Err(err) => {
63 last_err = err.into();
64 }
65 },
66 }
67 }
68
69 IprevOutput {
70 result: if let Some(err) = last_err {
71 err.into()
72 } else {
73 IprevResult::Fail(Error::NotAligned)
74 },
75 ptr: Some(ptr.rrset.clone()),
76 }
77 }
78 Err(err) => IprevOutput {
79 result: err.into(),
80 ptr: None,
81 },
82 }
83 }
84}
85
86impl From<IpAddr>
87 for Parameters<
88 '_,
89 IpAddr,
90 NoCache<Box<str>, Txt>,
91 NoCache<Box<str>, RecordSet<MX>>,
92 NoCache<Box<str>, RecordSet<Ipv4Addr>>,
93 NoCache<Box<str>, RecordSet<Ipv6Addr>>,
94 NoCache<IpAddr, RecordSet<Box<str>>>,
95 >
96{
97 fn from(params: IpAddr) -> Self {
98 Parameters::new(params)
99 }
100}
101
102impl IprevOutput {
103 pub fn result(&self) -> &IprevResult {
104 &self.result
105 }
106}
107
108impl DomainKey {
109 pub(crate) fn verify<'a>(
110 &self,
111 headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
112 input: &impl VerifySignature,
113 canonicalization: Canonicalization,
114 ) -> crate::Result<()> {
115 self.p.verify(
116 headers,
117 input.signature(),
118 canonicalization,
119 input.algorithm(),
120 )
121 }
122}
123
124pub trait VerifySignature {
125 fn selector(&self) -> &str;
126
127 fn domain(&self) -> &str;
128
129 fn signature(&self) -> &[u8];
130
131 fn algorithm(&self) -> Algorithm;
132
133 fn domain_key(&self) -> String {
134 let s = self.selector();
135 let d = self.domain();
136 let mut key = String::with_capacity(s.len() + d.len() + 13);
137 key.push_str(s);
138 key.push_str("._domainkey.");
139 key.push_str(d);
140 key.push('.');
141 key
142 }
143}