use super::{
cache::NoCache,
crypto::{Algorithm, VerifyingKey},
};
use crate::{
Error, IprevOutput, IprevResult, MX, MessageAuthenticator, Parameters, RecordSet,
ResolverCache, Txt, dkim::Canonicalization,
};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub struct DomainKey {
pub p: Box<dyn VerifyingKey + Send + Sync>,
pub f: u64,
}
impl MessageAuthenticator {
pub async fn verify_iprev<'x, TXT, MXX, IPV4, IPV6, PTR>(
&self,
params: impl Into<Parameters<'x, IpAddr, TXT, MXX, IPV4, IPV6, PTR>>,
) -> IprevOutput
where
TXT: ResolverCache<Box<str>, Txt> + 'x,
MXX: ResolverCache<Box<str>, RecordSet<MX>> + 'x,
IPV4: ResolverCache<Box<str>, RecordSet<Ipv4Addr>> + 'x,
IPV6: ResolverCache<Box<str>, RecordSet<Ipv6Addr>> + 'x,
PTR: ResolverCache<IpAddr, RecordSet<Box<str>>> + 'x,
{
let params = params.into();
match self.ptr_lookup(params.params, params.cache_ptr).await {
Ok(ptr) => {
let mut last_err = None;
for host in ptr.rrset.iter().take(2) {
match ¶ms.params {
IpAddr::V4(ip) => match self.ipv4_lookup(host, params.cache_ipv4).await {
Ok(ips) => {
if ips.rrset.iter().any(|cip| cip == ip) {
return IprevOutput {
result: IprevResult::Pass,
ptr: Some(ptr.rrset.clone()),
};
}
}
Err(err) => {
last_err = err.into();
}
},
IpAddr::V6(ip) => match self.ipv6_lookup(host, params.cache_ipv6).await {
Ok(ips) => {
if ips.rrset.iter().any(|cip| cip == ip) {
return IprevOutput {
result: IprevResult::Pass,
ptr: Some(ptr.rrset.clone()),
};
}
}
Err(err) => {
last_err = err.into();
}
},
}
}
IprevOutput {
result: if let Some(err) = last_err {
err.into()
} else {
IprevResult::Fail(Error::NotAligned)
},
ptr: Some(ptr.rrset.clone()),
}
}
Err(err) => IprevOutput {
result: err.into(),
ptr: None,
},
}
}
}
impl From<IpAddr>
for Parameters<
'_,
IpAddr,
NoCache<Box<str>, Txt>,
NoCache<Box<str>, RecordSet<MX>>,
NoCache<Box<str>, RecordSet<Ipv4Addr>>,
NoCache<Box<str>, RecordSet<Ipv6Addr>>,
NoCache<IpAddr, RecordSet<Box<str>>>,
>
{
fn from(params: IpAddr) -> Self {
Parameters::new(params)
}
}
impl IprevOutput {
pub fn result(&self) -> &IprevResult {
&self.result
}
}
impl DomainKey {
pub(crate) fn verify<'a>(
&self,
headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
input: &impl VerifySignature,
canonicalization: Canonicalization,
) -> crate::Result<()> {
self.p.verify(
headers,
input.signature(),
canonicalization,
input.algorithm(),
)
}
}
pub trait VerifySignature {
fn selector(&self) -> &str;
fn domain(&self) -> &str;
fn signature(&self) -> &[u8];
fn algorithm(&self) -> Algorithm;
fn domain_key(&self) -> String {
let s = self.selector();
let d = self.domain();
let mut key = String::with_capacity(s.len() + d.len() + 13);
key.push_str(s);
key.push_str("._domainkey.");
key.push_str(d);
key.push('.');
key
}
}