Skip to main content

mailrs_arc/
error.rs

1//! Error type for ARC parsing + verification.
2
3/// Errors returned by ARC parsers and the chain verifier.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum ArcError {
6    /// Header value missing a required tag.
7    MissingTag(String),
8    /// Tag value malformed.
9    InvalidTag(String),
10    /// `cv=` value not one of `none` / `pass` / `fail`.
11    InvalidCv(String),
12    /// `i=` instance value out of range (must be 1-50 per RFC 8617 §4.2.1).
13    InvalidInstance(u32),
14    /// `a=` algorithm not supported.
15    UnsupportedAlgorithm(String),
16    /// Sets in a chain are not contiguous from `i=1`.
17    NonContiguousChain {
18        /// First missing instance.
19        missing: u32,
20    },
21    /// Chain has more than 50 sets (RFC 8617 §4.2.1 limit).
22    ChainTooLong(usize),
23    /// One of AAR / AMS / AS is missing for an instance number that
24    /// appeared on another header.
25    IncompleteSet {
26        /// Instance whose triplet is incomplete.
27        instance: u32,
28        /// Which header type is missing (`"aar"` / `"ams"` / `"seal"`).
29        missing: &'static str,
30    },
31    /// DNS lookup for the public key TXT record failed.
32    Dns(String),
33    /// Public-key TXT record present but unparseable.
34    InvalidPublicKey(String),
35    /// Cryptographic verification of an AMS or AS failed.
36    SignatureMismatch {
37        /// Which header type's signature failed.
38        header: &'static str,
39        /// Instance number whose signature failed.
40        instance: u32,
41    },
42    /// AMS body hash (`bh=`) did not match the recomputed hash of the
43    /// canonicalized body.
44    BodyHashMismatch,
45    /// A base64 tag (`b=` / `bh=`) failed to decode.
46    InvalidBase64(String),
47    /// The raw message has no detectable end-of-headers terminator
48    /// (no CRLF CRLF, no LF LF).
49    MalformedMessage,
50}
51
52impl std::fmt::Display for ArcError {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        match self {
55            Self::MissingTag(t) => write!(f, "missing required tag: {t}"),
56            Self::InvalidTag(t) => write!(f, "invalid tag: {t}"),
57            Self::InvalidCv(v) => write!(f, "invalid cv= value: {v}"),
58            Self::InvalidInstance(i) => {
59                write!(f, "invalid i= value: {i} (must be 1..=50)")
60            }
61            Self::UnsupportedAlgorithm(a) => write!(f, "unsupported algorithm: {a}"),
62            Self::NonContiguousChain { missing } => {
63                write!(f, "chain not contiguous from i=1; missing i={missing}")
64            }
65            Self::ChainTooLong(n) => {
66                write!(f, "chain too long: {n} sets (max 50 per RFC 8617 §4.2.1)")
67            }
68            Self::IncompleteSet { instance, missing } => {
69                write!(f, "incomplete ARC set i={instance}: missing {missing}")
70            }
71            Self::Dns(msg) => write!(f, "DNS lookup failed: {msg}"),
72            Self::InvalidPublicKey(msg) => write!(f, "invalid public key: {msg}"),
73            Self::SignatureMismatch { header, instance } => {
74                write!(f, "signature mismatch on {header} i={instance}")
75            }
76            Self::BodyHashMismatch => write!(f, "body hash (bh=) mismatch"),
77            Self::InvalidBase64(tag) => write!(f, "invalid base64 in tag: {tag}"),
78            Self::MalformedMessage => write!(f, "malformed message: no end-of-headers"),
79        }
80    }
81}
82
83impl std::error::Error for ArcError {}