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 ///
31 /// The bounds mirror `aws-lc-rs`'s
32 /// `RSA_PKCS1_2048_8192_SHA256` verification profile: any modulus
33 /// width between 2048 and 8192 bits (inclusive) whose byte count is
34 /// whole (i.e. divisible by 8) is accepted.
35 #[error(
36 "unsupported RSA key size {0} bits; only {min}-{max} supported",
37 min = 2048,
38 max = 8192
39 )]
40 UnsupportedRsaSize(u32),
41
42 /// An underlying `aws-lc-rs` primitive failed.
43 #[error("cryptographic operation failed: {0}")]
44 Crypto(&'static str),
45
46 /// Generation of a new key failed at the RNG layer.
47 #[error("key generation failed: {0}")]
48 KeyGeneration(&'static str),
49
50 /// A signature's Base64 encoding was malformed.
51 #[error("invalid Base64 in signature: {0}")]
52 InvalidBase64(#[from] base64ct::Error),
53
54 /// Multibase decoding of a FEP-521a `publicKeyMultibase` failed.
55 #[error("invalid multibase: {0}")]
56 InvalidMultibase(#[from] multibase::Error),
57
58 /// The multicodec prefix on a Multikey was unrecognised or truncated.
59 #[error("invalid multikey codec prefix")]
60 InvalidMultikeyPrefix,
61
62 /// The raw key material following the multicodec prefix had the wrong length.
63 #[error("invalid multikey body length: expected {expected}, got {actual}")]
64 InvalidMultikeyLength {
65 /// Expected number of key bytes.
66 expected: usize,
67 /// Actual number of key bytes.
68 actual: usize,
69 },
70
71 /// A required HTTP header is missing.
72 #[error("missing HTTP header `{0}`")]
73 MissingHeader(&'static str),
74
75 /// An HTTP header's value was not valid UTF-8 or otherwise unparseable.
76 #[error("invalid HTTP header `{name}`: {reason}")]
77 InvalidHeader {
78 /// Header name that could not be parsed.
79 name: &'static str,
80 /// Human-readable reason.
81 reason: String,
82 },
83
84 /// The `Signature` header's parameter list was malformed.
85 #[error("malformed Signature header: {0}")]
86 MalformedSignatureHeader(String),
87
88 /// The signature did not verify against the provided key.
89 #[error("signature verification failed")]
90 VerificationFailed,
91
92 /// The resolver closure returned an error while fetching the signer's key.
93 #[error("key resolution failed: {0}")]
94 KeyResolution(String),
95
96 /// The `Digest` / `Content-Digest` header did not match the body.
97 #[error("digest mismatch: body SHA-256 did not match `Digest` header")]
98 DigestMismatch,
99
100 /// The requested digest algorithm is not supported.
101 #[error("unsupported digest algorithm `{0}`")]
102 UnsupportedDigestAlgorithm(String),
103
104 /// The signature-base string includes a header that the request does not carry.
105 #[error("cannot build signature base: required header `{0}` is absent from the request")]
106 RequiredHeaderAbsent(String),
107
108 /// A signature parameter required by the standard is missing.
109 #[error("required signature parameter `{0}` is missing")]
110 MissingSignatureParameter(&'static str),
111
112 /// The signature carried no `created` parameter and no `Date`
113 /// header, and the active [`VerifyPolicy`](crate::VerifyPolicy)
114 /// requires one.
115 #[error("no `created` parameter or `Date` header on a signature that requires freshness")]
116 TimestampMissing,
117
118 /// The signature is older than the policy's `max_age`.
119 #[error("signature is too old: timestamp {timestamp}, now {now}")]
120 TimestampTooOld {
121 /// The signed timestamp, either from `created` or the `Date` header.
122 timestamp: chrono::DateTime<chrono::Utc>,
123 /// The verifier's current wall-clock time.
124 now: chrono::DateTime<chrono::Utc>,
125 },
126
127 /// The signature claims to have been produced further in the future
128 /// than the policy's `max_clock_skew_future` tolerance allows.
129 #[error("signature claims a future timestamp: timestamp {timestamp}, now {now}")]
130 TimestampInFuture {
131 /// The signed timestamp.
132 timestamp: chrono::DateTime<chrono::Utc>,
133 /// The verifier's current wall-clock time.
134 now: chrono::DateTime<chrono::Utc>,
135 },
136
137 /// The signature's `expires` parameter indicates it has lapsed.
138 #[error("signature expired at {expires}, now {now}")]
139 TimestampExpired {
140 /// The `expires` parameter interpreted as a UTC timestamp.
141 expires: chrono::DateTime<chrono::Utc>,
142 /// The verifier's current wall-clock time.
143 now: chrono::DateTime<chrono::Utc>,
144 },
145}