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