identity_kit/jose/error.rs
1//! Error types of the `jose` module.
2
3use core::fmt;
4use std::error::Error;
5
6use super::{JwsAlgorithm, KeyType};
7
8/// Why a [`Jwk`](super::Jwk) cannot be built, or cannot be used the way it was asked to.
9#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
10#[non_exhaustive]
11pub enum JwkError {
12 /// A member the key type requires is absent.
13 #[error("missing JWK member `{0}`")]
14 MissingMember(&'static str),
15 /// A member is not valid base64url without padding.
16 #[error("JWK member `{0}` is not valid base64url")]
17 InvalidBase64Url(&'static str),
18 /// The key has a different type than the operation needs, for example an RSA key where an
19 /// Ed25519 key was expected.
20 #[error("expected {expected} key, found `kty` {kty:?} with `crv` {crv:?}")]
21 UnexpectedKeyType {
22 /// The key type the operation needs, such as `Ed25519` or `RSA`.
23 expected: &'static str,
24 /// The `kty` of the key.
25 kty: String,
26 /// The `crv` of the key, if any.
27 crv: Option<String>,
28 },
29 /// The key type or curve is not one this crate supports.
30 #[error("unsupported key type: `kty` {kty:?} with `crv` {crv:?}")]
31 UnsupportedKeyType {
32 /// The `kty` of the key.
33 kty: String,
34 /// The `crv` of the key, if any.
35 crv: Option<String>,
36 },
37 /// The key material does not decode to a valid key: wrong length, not on the curve, even
38 /// modulus, and so on.
39 #[error("invalid {key} key: {reason}")]
40 InvalidKey {
41 /// The key type, such as `P-256`.
42 key: &'static str,
43 /// What is wrong with it.
44 reason: String,
45 },
46 /// The key material has the wrong length for its type: a 31-byte Ed25519 key, say.
47 #[error("invalid {key} key: expected {expected} bytes, found {actual}")]
48 InvalidKeyLength {
49 /// The key type, such as `Ed25519`.
50 key: &'static str,
51 /// The length the key type requires.
52 expected: usize,
53 /// The length found.
54 actual: usize,
55 },
56 /// A Multikey (`publicKeyMultibase`) value is not base58btc multibase with a complete
57 /// multicodec header.
58 #[error("invalid Multikey: {0}")]
59 InvalidMultikey(String),
60 /// A Multikey value carries a public key type this crate cannot read.
61 #[error("unsupported multicodec 0x{0:x}")]
62 UnsupportedMulticodec(u64),
63 /// The encoded key is valid but not of the [`KeyType`] that was expected.
64 #[error("key is not a {expected:?} key")]
65 KeyMismatch {
66 /// The key type the caller expected.
67 expected: KeyType,
68 },
69 /// Support for this key type is compiled out; enable the named Cargo feature.
70 #[error("support for {key} keys requires the `{feature}` feature")]
71 FeatureDisabled {
72 /// The key type, such as `secp256k1`.
73 key: &'static str,
74 /// The Cargo feature that enables it.
75 feature: &'static str,
76 },
77 /// `jsonwebtoken` rejected the key material.
78 #[error("cannot build a jsonwebtoken decoding key: {0}")]
79 DecodingKey(String),
80}
81
82/// Why a JWS signature did not verify.
83#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
84#[non_exhaustive]
85pub enum VerificationError {
86 /// The verifier has no implementation of this algorithm, possibly because the Cargo feature
87 /// that provides it is off.
88 #[error("algorithm {0} is not supported by this verifier")]
89 UnsupportedAlgorithm(JwsAlgorithm),
90 /// The key's `alg` member names a different algorithm than the one being verified.
91 #[error("key `alg` {key_alg:?} does not match {alg}")]
92 AlgorithmMismatch {
93 /// The algorithm being verified.
94 alg: JwsAlgorithm,
95 /// The `alg` member of the key.
96 key_alg: String,
97 },
98 /// The key's `use` or `key_ops` member excludes signature verification.
99 #[error("key is not meant for signature verification: {0}")]
100 KeyUse(&'static str),
101 /// The key cannot be used with this algorithm.
102 #[error(transparent)]
103 Key(#[from] JwkError),
104 /// The signature does not have the length the algorithm requires.
105 #[error("signature is {actual} bytes, expected {expected}")]
106 InvalidSignatureLength {
107 /// The length the algorithm requires.
108 expected: usize,
109 /// The length that was given.
110 actual: usize,
111 },
112 /// An ECDSA signature was given in ASN.1 DER instead of the raw `r || s` form JWS requires.
113 #[error("ECDSA signature appears to be DER-encoded; JWS requires the raw `r || s` form")]
114 DerEncodedSignature,
115 /// The signature is well-formed but does not verify under the key.
116 #[error("signature verification failed")]
117 InvalidSignature,
118}
119
120/// Why a compact JWS could not be decoded or produced.
121#[derive(Debug, thiserror::Error)]
122#[non_exhaustive]
123pub enum JwsError {
124 /// The input is not three base64url parts separated by `.`.
125 #[error("compact JWS must have exactly three parts separated by `.`, found {parts}")]
126 InvalidFormat {
127 /// The number of `.`-separated parts found.
128 parts: usize,
129 },
130 /// A part is not valid base64url without padding.
131 #[error("JWS {part} is not valid base64url")]
132 InvalidBase64Url {
133 /// Which part: `header`, `payload` or `signature`.
134 part: &'static str,
135 },
136 /// The protected header is not a JSON object with the expected members.
137 #[error("invalid JWS protected header: {0}")]
138 InvalidHeader(String),
139 /// The header `alg` is missing or not a [`JwsAlgorithm`].
140 #[error("unsupported JWS algorithm {0:?}")]
141 UnsupportedAlgorithm(String),
142 /// The header has a `crit` member; this crate understands no extensions, so it must reject
143 /// every one of them (RFC 7515 ยง4.1.11).
144 #[error("unsupported critical header parameters {0:?}")]
145 UnsupportedCritical(Vec<String>),
146 /// The header sets `b64` to `false` (RFC 7797); only base64url-encoded payloads are supported.
147 #[error("unencoded payloads (`b64: false`) are not supported")]
148 UnencodedPayload,
149 /// The payload cannot be signed as given (a claims set that holds a registered claim under
150 /// `additional` next to its field, say), or is not the JSON
151 /// [`CompactJws::claims`](super::CompactJws::claims) was asked to read it as.
152 #[error("invalid JWS payload: {0}")]
153 InvalidPayload(String),
154 /// The header `alg` differs from the algorithm of the signer.
155 #[error("header `alg` {header} does not match the signer's {signer}")]
156 AlgorithmMismatch {
157 /// The `alg` in the header.
158 header: JwsAlgorithm,
159 /// The algorithm of the signer.
160 signer: JwsAlgorithm,
161 },
162 /// The signer failed.
163 #[error("signing failed: {0}")]
164 Signer(#[source] SignError),
165}
166
167/// An error from a [`Signer`](super::Signer).
168///
169/// Signers live in key stores, HSMs and cloud services with their own error types; this wraps any
170/// of them.
171#[derive(Debug)]
172pub struct SignError(Box<dyn Error + Send + Sync + 'static>);
173
174impl SignError {
175 /// Wraps `error`.
176 pub fn new<E: Error + Send + Sync + 'static>(error: E) -> Self {
177 Self(Box::new(error))
178 }
179
180 /// Wraps a message.
181 pub fn msg<M: fmt::Display>(message: M) -> Self {
182 Self(message.to_string().into())
183 }
184
185 /// The wrapped error.
186 pub fn inner(&self) -> &(dyn Error + Send + Sync + 'static) {
187 self.0.as_ref()
188 }
189}
190
191impl fmt::Display for SignError {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 fmt::Display::fmt(&self.0, f)
194 }
195}
196
197impl Error for SignError {
198 fn source(&self) -> Option<&(dyn Error + 'static)> {
199 self.0.source()
200 }
201}
202
203impl From<Box<dyn Error + Send + Sync + 'static>> for SignError {
204 fn from(error: Box<dyn Error + Send + Sync + 'static>) -> Self {
205 Self(error)
206 }
207}
208
209/// Why an ECDSA signature cannot be put in its JWS form; see
210/// [`ecdsa_signature_from_der`](super::ecdsa_signature_from_der) and
211/// [`normalize_ecdsa_signature`](super::normalize_ecdsa_signature).
212#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
213#[non_exhaustive]
214pub enum EcdsaSignatureError {
215 /// The algorithm is not ECDSA.
216 #[error("{0} is not an ECDSA algorithm")]
217 NotEcdsa(JwsAlgorithm),
218 /// The algorithm needs a feature this build does not have: ES256K without `secp256k1`.
219 #[error("{0} signatures need the `secp256k1` feature")]
220 Unsupported(JwsAlgorithm),
221 /// The input is not a strict DER `ECDSA-Sig-Value`.
222 #[error("invalid DER ECDSA signature: {0}")]
223 InvalidDer(&'static str),
224 /// `r` or `s` is longer than the curve's size.
225 #[error("ECDSA signature component of {len} bytes is too long for {alg}")]
226 ComponentTooLong {
227 /// The algorithm.
228 alg: JwsAlgorithm,
229 /// The length of the component, without its sign byte.
230 len: usize,
231 },
232 /// A raw signature is not twice the curve's size.
233 #[error("{alg} signature must be {expected} bytes, got {actual}")]
234 InvalidLength {
235 /// The algorithm.
236 alg: JwsAlgorithm,
237 /// Twice the curve's size.
238 expected: usize,
239 /// The length of the signature.
240 actual: usize,
241 },
242 /// `r` or `s` is zero or not below the group order.
243 #[error("{0} signature component is out of range")]
244 OutOfRange(JwsAlgorithm),
245}