biscuit/
errors.rs

1//! Errors returned will be converted to one of the structs in this module.
2use crate::SingleOrMultiple;
3use chrono::Duration;
4use std::{error, fmt, io, str, string};
5
6#[derive(Debug)]
7/// All the errors we can encounter while signing/verifying tokens
8/// and a couple of custom one for when the token we are trying
9/// to verify is invalid
10pub enum Error {
11    /// A generic error which is described by the contained string
12    GenericError(String),
13    /// Error returned from failed token decoding
14    DecodeError(DecodeError),
15    /// Error returned from failed token validation
16    ValidationError(ValidationError),
17    /// Error during the serialization or deserialization of tokens
18    JsonError(serde_json::error::Error),
19    /// Error during base64 encoding or decoding
20    DecodeBase64(data_encoding::DecodeError),
21    /// Error when decoding bytes to UTF8 string
22    Utf8(str::Utf8Error),
23    /// Errors related to IO
24    IOError(io::Error),
25    /// Key was rejected by Ring
26    KeyRejected(ring::error::KeyRejected),
27
28    /// Wrong key type was provided for the cryptographic operation
29    WrongKeyType {
30        /// Expected type of key
31        expected: String,
32        /// Actual type of key
33        actual: String,
34    },
35
36    /// Wrong variant of `EncryptionOptions` was provided for the encryption operation
37    WrongEncryptionOptions {
38        /// Expected variant of options
39        expected: String,
40        /// Actual variant of options
41        actual: String,
42    },
43
44    /// An unknown cryptographic error
45    UnspecifiedCryptographicError,
46    /// An unsupported or invalid operation
47    UnsupportedOperation,
48}
49
50#[derive(Debug)]
51/// Errors from decoding tokens
52pub enum DecodeError {
53    /// Token is invalid in structure or form
54    InvalidToken,
55    /// The number of compact parts is incorrect
56    PartsLengthError {
57        /// Expected number of parts
58        expected: usize,
59        /// Actual number of parts
60        actual: usize,
61    },
62}
63
64#[derive(Debug, Eq, PartialEq, Clone)]
65/// Errors from validating tokens
66pub enum ValidationError {
67    /// Token has an invalid signature (RFC7523 3.9)
68    InvalidSignature,
69    /// Token provided was signed or encrypted with an unexpected algorithm
70    WrongAlgorithmHeader,
71    /// A field required is missing from the token
72    /// The parameter shows the name of the missing claim
73    MissingRequiredClaims(Vec<String>),
74    /// The token's expiry has passed (exp check failed, RFC7523 3.4)
75    /// The parameter show how long the token has expired
76    Expired(Duration),
77    /// The token is not yet valid (nbf check failed, RFC7523 3.5)
78    /// The parameter show how much longer the token will start to be valid
79    NotYetValid(Duration),
80    /// The token has been created too far in the past (iat check failed, RFC7523 3.6)
81    /// This is different from Expired because the token may not be expired yet, but the
82    /// acceptor of the token may impose more strict requirement for the age of the token for
83    /// some more sensitive operations.
84    /// The parameter show how much older the token is than required
85    TooOld(Duration),
86    /// The token does not have or has the wrong issuer (iss check failed, RFC7523 3.1)
87    InvalidIssuer(String),
88    /// The token does not have or has the wrong audience (aud check failed, RFC7523 3.3
89    InvalidAudience(SingleOrMultiple<String>),
90    /// The token doesn't contains the Kid claim in the header
91    KidMissing,
92    /// The by the Kid specified key, wasn't found in the KeySet
93    KeyNotFound,
94    /// The algorithm of the JWK is not supported for validating JWTs
95    UnsupportedKeyAlgorithm,
96    /// An algorithm is needed for verification but was not provided
97    MissingAlgorithm,
98}
99
100macro_rules! impl_from_error {
101    ($f:ty, $e:expr) => {
102        impl From<$f> for Error {
103            fn from(f: $f) -> Error {
104                $e(f)
105            }
106        }
107    };
108}
109
110impl_from_error!(String, Error::GenericError);
111impl_from_error!(serde_json::error::Error, Error::JsonError);
112impl_from_error!(data_encoding::DecodeError, Error::DecodeBase64);
113impl_from_error!(str::Utf8Error, Error::Utf8);
114impl_from_error!(ValidationError, Error::ValidationError);
115impl_from_error!(DecodeError, Error::DecodeError);
116impl_from_error!(io::Error, Error::IOError);
117impl_from_error!(ring::error::KeyRejected, Error::KeyRejected);
118
119impl From<ring::error::Unspecified> for Error {
120    fn from(_: ring::error::Unspecified) -> Self {
121        Error::UnspecifiedCryptographicError
122    }
123}
124
125impl From<string::FromUtf8Error> for Error {
126    fn from(e: string::FromUtf8Error) -> Self {
127        Error::Utf8(e.utf8_error())
128    }
129}
130
131impl fmt::Display for Error {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        use crate::Error::*;
134
135        match *self {
136            GenericError(ref err) => fmt::Display::fmt(err, f),
137            JsonError(ref err) => fmt::Display::fmt(err, f),
138            DecodeBase64(ref err) => fmt::Display::fmt(err, f),
139            Utf8(ref err) => fmt::Display::fmt(err, f),
140            DecodeError(ref err) => fmt::Display::fmt(err, f),
141            ValidationError(ref err) => fmt::Display::fmt(err, f),
142            IOError(ref err) => fmt::Display::fmt(err, f),
143            KeyRejected(ref err) => fmt::Display::fmt(err, f),
144            WrongKeyType {
145                ref actual,
146                ref expected,
147            } => write!(
148                f,
149                "{} was expected for this cryptographic operation but {} was provided",
150                expected, actual
151            ),
152            WrongEncryptionOptions {
153                ref actual,
154                ref expected,
155            } => write!(
156                f,
157                "{} was expected for this cryptographic operation but {} was provided",
158                expected, actual
159            ),
160            UnspecifiedCryptographicError => write!(f, "An unspecified cryptographic error"),
161            UnsupportedOperation => write!(f, "This operation is not supported"),
162        }
163    }
164}
165
166impl error::Error for Error {
167    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
168        use crate::Error::*;
169
170        match *self {
171            JsonError(ref err) => Some(err),
172            DecodeBase64(ref err) => Some(err),
173            Utf8(ref err) => Some(err),
174            DecodeError(ref err) => Some(err),
175            ValidationError(ref err) => Some(err),
176            IOError(ref err) => Some(err),
177            _ => None,
178        }
179    }
180}
181
182impl fmt::Display for DecodeError {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        use self::DecodeError::*;
185
186        match *self {
187            InvalidToken => write!(f, "Invalid token"),
188            PartsLengthError { expected, actual } => write!(
189                f,
190                "Expected {} parts in Compact JSON representation but got {}",
191                expected, actual
192            ),
193        }
194    }
195}
196
197impl error::Error for DecodeError {
198    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
199        None
200    }
201}
202
203impl fmt::Display for ValidationError {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        use crate::ValidationError::*;
206
207        match *self {
208            MissingRequiredClaims(ref fields) => write!(
209                f,
210                "The following claims are required, but missing: {:?}",
211                fields
212            ),
213            Expired(ago) => write!(f, "Token expired {} seconds ago", ago.num_seconds()),
214            NotYetValid(nyv_for) => write!(
215                f,
216                "Token will be valid in {} seconds",
217                nyv_for.num_seconds()
218            ),
219            TooOld(duration) => write!(
220                f,
221                "Token has been considered too old for {} seconds",
222                duration.num_seconds()
223            ),
224            InvalidIssuer(ref iss) => write!(f, "Issuer of token is invalid: {:?}", iss),
225            InvalidAudience(ref aud) => write!(f, "Audience of token is invalid: {:?}", aud),
226            InvalidSignature => write!(f, "Invalid signature"),
227            WrongAlgorithmHeader => write!(
228                f,
229                "Token provided was signed or encrypted with an unexpected algorithm"
230            ),
231            KidMissing => write!(f, "Header is missing kid"),
232            KeyNotFound => write!(f, "Key not found in JWKS"),
233            UnsupportedKeyAlgorithm => write!(f, "Algorithm of JWK not supported"),
234            MissingAlgorithm => write!(
235                f,
236                "An algorithm is needed for verification but was not provided"
237            ),
238        }
239    }
240}
241
242impl error::Error for ValidationError {
243    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
244        None
245    }
246}