Skip to main content

actpub_httpsig/
error.rs

1//! Error types for [`actpub-httpsig`](crate).
2
3use thiserror::Error;
4
5/// Enumeration of every failure mode that this crate can surface.
6///
7/// The enum is non-exhaustive so that additional signature schemes or
8/// cryptographic algorithms can be added in minor releases without
9/// breaking downstream code.
10#[derive(Debug, Error)]
11#[non_exhaustive]
12pub enum Error {
13    /// The provided PEM document could not be parsed.
14    #[error("invalid PEM document: {0}")]
15    InvalidPem(String),
16
17    /// The PEM document had an unexpected `-----BEGIN <LABEL>-----` line.
18    #[error("unexpected PEM label `{0}`, expected one of: {1}")]
19    UnexpectedPemLabel(String, &'static str),
20
21    /// A PKCS#8 DER blob could not be decoded.
22    #[error("invalid PKCS#8 DER: {0}")]
23    InvalidPkcs8(String),
24
25    /// The key's algorithm identifier was not supported.
26    #[error("unsupported key algorithm: {0}")]
27    UnsupportedAlgorithm(String),
28
29    /// The RSA key size was outside the supported range.
30    #[error(
31        "unsupported RSA key size {0} bits; only {min}-{max} supported",
32        min = 2048,
33        max = 4096
34    )]
35    UnsupportedRsaSize(u32),
36
37    /// An underlying `aws-lc-rs` primitive failed.
38    #[error("cryptographic operation failed: {0}")]
39    Crypto(&'static str),
40
41    /// Generation of a new key failed at the RNG layer.
42    #[error("key generation failed: {0}")]
43    KeyGeneration(&'static str),
44
45    /// A signature's Base64 encoding was malformed.
46    #[error("invalid Base64 in signature: {0}")]
47    InvalidBase64(#[from] base64ct::Error),
48
49    /// Multibase decoding of a FEP-521a `publicKeyMultibase` failed.
50    #[error("invalid multibase: {0}")]
51    InvalidMultibase(#[from] multibase::Error),
52
53    /// The multicodec prefix on a Multikey was unrecognised or truncated.
54    #[error("invalid multikey codec prefix")]
55    InvalidMultikeyPrefix,
56
57    /// The raw key material following the multicodec prefix had the wrong length.
58    #[error("invalid multikey body length: expected {expected}, got {actual}")]
59    InvalidMultikeyLength {
60        /// Expected number of key bytes.
61        expected: usize,
62        /// Actual number of key bytes.
63        actual: usize,
64    },
65
66    /// A required HTTP header is missing.
67    #[error("missing HTTP header `{0}`")]
68    MissingHeader(&'static str),
69
70    /// An HTTP header's value was not valid UTF-8 or otherwise unparseable.
71    #[error("invalid HTTP header `{name}`: {reason}")]
72    InvalidHeader {
73        /// Header name that could not be parsed.
74        name: &'static str,
75        /// Human-readable reason.
76        reason: String,
77    },
78
79    /// The `Signature` header's parameter list was malformed.
80    #[error("malformed Signature header: {0}")]
81    MalformedSignatureHeader(String),
82
83    /// The signature did not verify against the provided key.
84    #[error("signature verification failed")]
85    VerificationFailed,
86
87    /// The resolver closure returned an error while fetching the signer's key.
88    #[error("key resolution failed: {0}")]
89    KeyResolution(String),
90
91    /// The `Digest` / `Content-Digest` header did not match the body.
92    #[error("digest mismatch: body SHA-256 did not match `Digest` header")]
93    DigestMismatch,
94
95    /// The requested digest algorithm is not supported.
96    #[error("unsupported digest algorithm `{0}`")]
97    UnsupportedDigestAlgorithm(String),
98
99    /// The signature-base string includes a header that the request does not carry.
100    #[error("cannot build signature base: required header `{0}` is absent from the request")]
101    RequiredHeaderAbsent(String),
102
103    /// A signature parameter required by the standard is missing.
104    #[error("required signature parameter `{0}` is missing")]
105    MissingSignatureParameter(&'static str),
106
107    /// The signature carried no `created` parameter and no `Date`
108    /// header, and the active [`VerifyPolicy`](crate::VerifyPolicy)
109    /// requires one.
110    #[error("no `created` parameter or `Date` header on a signature that requires freshness")]
111    TimestampMissing,
112
113    /// The signature is older than the policy's `max_age`.
114    #[error("signature is too old: timestamp {timestamp}, now {now}")]
115    TimestampTooOld {
116        /// The signed timestamp, either from `created` or the `Date` header.
117        timestamp: chrono::DateTime<chrono::Utc>,
118        /// The verifier's current wall-clock time.
119        now: chrono::DateTime<chrono::Utc>,
120    },
121
122    /// The signature claims to have been produced further in the future
123    /// than the policy's `max_clock_skew_future` tolerance allows.
124    #[error("signature claims a future timestamp: timestamp {timestamp}, now {now}")]
125    TimestampInFuture {
126        /// The signed timestamp.
127        timestamp: chrono::DateTime<chrono::Utc>,
128        /// The verifier's current wall-clock time.
129        now: chrono::DateTime<chrono::Utc>,
130    },
131
132    /// The signature's `expires` parameter indicates it has lapsed.
133    #[error("signature expired at {expires}, now {now}")]
134    TimestampExpired {
135        /// The `expires` parameter interpreted as a UTC timestamp.
136        expires: chrono::DateTime<chrono::Utc>,
137        /// The verifier's current wall-clock time.
138        now: chrono::DateTime<chrono::Utc>,
139    },
140}