Skip to main content

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.
151    #[error("invalid JWS payload: {0}")]
152    InvalidPayload(String),
153    /// The header `alg` differs from the algorithm of the signer.
154    #[error("header `alg` {header} does not match the signer's {signer}")]
155    AlgorithmMismatch {
156        /// The `alg` in the header.
157        header: JwsAlgorithm,
158        /// The algorithm of the signer.
159        signer: JwsAlgorithm,
160    },
161    /// The signer failed.
162    #[error("signing failed: {0}")]
163    Signer(#[source] SignError),
164}
165
166/// An error from a [`Signer`](super::Signer).
167///
168/// Signers live in key stores, HSMs and cloud services with their own error types; this wraps any
169/// of them.
170#[derive(Debug)]
171pub struct SignError(Box<dyn Error + Send + Sync + 'static>);
172
173impl SignError {
174    /// Wraps `error`.
175    pub fn new<E: Error + Send + Sync + 'static>(error: E) -> Self {
176        Self(Box::new(error))
177    }
178
179    /// Wraps a message.
180    pub fn msg<M: fmt::Display>(message: M) -> Self {
181        Self(message.to_string().into())
182    }
183
184    /// The wrapped error.
185    pub fn inner(&self) -> &(dyn Error + Send + Sync + 'static) {
186        self.0.as_ref()
187    }
188}
189
190impl fmt::Display for SignError {
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        fmt::Display::fmt(&self.0, f)
193    }
194}
195
196impl Error for SignError {
197    fn source(&self) -> Option<&(dyn Error + 'static)> {
198        self.0.source()
199    }
200}
201
202impl From<Box<dyn Error + Send + Sync + 'static>> for SignError {
203    fn from(error: Box<dyn Error + Send + Sync + 'static>) -> Self {
204        Self(error)
205    }
206}