1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
/*
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
*
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/
use std::net::IpAddr;
use crate::{dkim::Canonicalization, Error, IprevOutput, IprevResult, Resolver};
use super::crypto::{Algorithm, VerifyingKey};
pub struct DomainKey {
pub(crate) p: Box<dyn VerifyingKey + Send + Sync>,
pub(crate) f: u64,
}
impl Resolver {
pub async fn verify_iprev(&self, addr: IpAddr) -> IprevOutput {
match self.ptr_lookup(addr).await {
Ok(ptr) => {
let mut last_err = None;
for host in ptr.iter().take(2) {
match &addr {
IpAddr::V4(ip) => match self.ipv4_lookup(host).await {
Ok(ips) => {
if ips.iter().any(|cip| cip == ip) {
return IprevOutput {
result: IprevResult::Pass,
ptr: ptr.into(),
};
}
}
Err(err) => {
last_err = err.into();
}
},
IpAddr::V6(ip) => match self.ipv6_lookup(host).await {
Ok(ips) => {
if ips.iter().any(|cip| cip == ip) {
return IprevOutput {
result: IprevResult::Pass,
ptr: ptr.into(),
};
}
}
Err(err) => {
last_err = err.into();
}
},
}
}
IprevOutput {
result: if let Some(err) = last_err {
err.into()
} else {
IprevResult::Fail(Error::NotAligned)
},
ptr: ptr.into(),
}
}
Err(err) => IprevOutput {
result: err.into(),
ptr: None,
},
}
}
}
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
}
}