use crate::{
crypto::{Algorithm, HashAlgorithm, SigningKey},
signer::NeedDomain,
};
pub mod builder;
pub mod canonicalize;
#[cfg(feature = "generate")]
pub mod generate;
pub mod headers;
pub mod output;
pub mod parse;
pub mod record;
pub mod sign;
pub mod streaming;
pub mod verify;
pub use output::{DkimOutput, DkimResult};
pub use record::{AtpsRecord, DkimReportRecord, DomainKey, VerifySignature};
pub(crate) use record::{
Flag, RR_DNS, RR_EXPIRATION, RR_OTHER, RR_POLICY, RR_SIGNATURE, RR_UNKNOWN_TAG,
RR_VERIFICATION, Service,
};
pub use streaming::DkimSigningStream;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Canonicalization {
#[default]
Relaxed,
Simple,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum DkimError {
UnsupportedVersion,
UnsupportedAlgorithm,
UnsupportedCanonicalization,
UnsupportedKeyType,
BodyHashMismatch,
AuidMismatch,
PublicKeyRevoked,
SignatureExpired,
BodyLengthTag,
}
impl std::fmt::Display for DkimError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DkimError::UnsupportedVersion => write!(f, "Unsupported version in DKIM Signature"),
DkimError::UnsupportedAlgorithm => {
write!(f, "Unsupported algorithm in DKIM Signature")
}
DkimError::UnsupportedCanonicalization => {
write!(f, "Unsupported canonicalization method in DKIM Signature")
}
DkimError::UnsupportedKeyType => write!(f, "Unsupported key type in DKIM DNS record"),
DkimError::BodyHashMismatch => {
write!(f, "Calculated body hash does not match signature hash")
}
DkimError::AuidMismatch => write!(f, "AUID does not match domain name"),
DkimError::PublicKeyRevoked => {
write!(f, "Public key for this signature has been revoked")
}
DkimError::SignatureExpired => write!(f, "Signature expired"),
DkimError::BodyLengthTag => write!(f, "Insecure 'l=' tag found in Signature"),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DkimSigner<T: SigningKey, State = NeedDomain> {
_state: std::marker::PhantomData<State>,
pub(crate) key: T,
pub(crate) template: Signature,
}
impl<T: SigningKey, State> DkimSigner<T, State> {
pub fn template(&self) -> &Signature {
&self.template
}
}
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct Signature {
pub v: u32,
pub a: Algorithm,
pub d: String,
pub s: String,
pub b: Vec<u8>,
pub bh: Vec<u8>,
pub h: Vec<String>,
pub z: Vec<String>,
pub i: String,
pub l: u64,
pub x: u64,
pub t: u64,
pub r: bool,
pub atps: Option<String>,
pub atpsh: Option<HashAlgorithm>,
pub ch: Canonicalization,
pub cb: Canonicalization,
}
impl From<HashAlgorithm> for u64 {
fn from(v: HashAlgorithm) -> Self {
v as u64
}
}
impl From<Algorithm> for HashAlgorithm {
fn from(a: Algorithm) -> Self {
match a {
Algorithm::RsaSha256 | Algorithm::Ed25519Sha256 | Algorithm::MlDsa44 => {
HashAlgorithm::Sha256
}
Algorithm::RsaSha1 => HashAlgorithm::Sha1,
}
}
}
impl VerifySignature for Signature {
fn signature(&self) -> &[u8] {
&self.b
}
fn algorithm(&self) -> Algorithm {
self.a
}
fn selector(&self) -> &str {
&self.s
}
fn domain(&self) -> &str {
&self.d
}
}
impl Signature {
pub fn identity(&self) -> &str {
&self.i
}
}