1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
//! Common errors

#![allow(missing_copy_implementations)]

use std::error::Error as StdError;

use thiserror::Error;

/// The JWK cannot be used with the requested algorithm
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Error)]
#[error("key incompatible with algorithm '{alg}'")]
pub struct IncompatibleAlgorithm {
    alg: crate::jwa::Algorithm,
}

#[inline]
pub(crate) fn incompatible_algorithm(
    alg: impl Into<crate::jwa::Algorithm>,
) -> IncompatibleAlgorithm {
    IncompatibleAlgorithm { alg: alg.into() }
}

/// The JWK has a specific usage that disallows this use
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Error)]
#[error("JWK cannot be used in this way")]
pub struct JwkUsageMismatch {
    _p: (),
}

pub(crate) const fn jwk_usage_mismatch() -> JwkUsageMismatch {
    JwkUsageMismatch { _p: () }
}

/// The JWT is malformed and cannot be parsed out into header, payload, and signature sections
#[derive(Clone, Copy, Debug, Error)]
#[error("malformed JWT")]
pub struct MalformedJwt {
    _p: (),
}

pub(crate) fn malformed_jwt() -> MalformedJwt {
    MalformedJwt { _p: () }
}

/// The JWT header section is malformed
#[derive(Debug, Error)]
#[error("malformed JWT header")]
pub struct MalformedJwtHeader {
    #[from]
    source: Box<dyn StdError + Send + Sync + 'static>,
}

pub(crate) fn malformed_jwt_header(
    source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> MalformedJwtHeader {
    MalformedJwtHeader {
        source: source.into(),
    }
}
/// The JWT payload section is malformed
#[derive(Debug, Error)]
#[error("malformed JWT payload")]
pub struct MalformedJwtPayload {
    #[from]
    source: Box<dyn StdError + Send + Sync + 'static>,
}

pub(crate) fn malformed_jwt_payload(
    source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> MalformedJwtPayload {
    MalformedJwtPayload {
        source: source.into(),
    }
}

/// The JWT signature section is malformed
#[derive(Debug, Error)]
#[error("malformed JWT signature")]
pub struct MalformedJwtSignature {
    #[from]
    source: Box<dyn StdError + Send + Sync + 'static>,
}

pub(crate) fn malformed_jwt_signature(
    source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> MalformedJwtSignature {
    MalformedJwtSignature {
        source: source.into(),
    }
}

/// The signature did not match
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Error)]
#[error("signature mismatch")]
pub struct SignatureMismatch {
    _p: (),
}

pub(crate) const fn signature_mismatch() -> SignatureMismatch {
    SignatureMismatch { _p: () }
}

/// The key was rejected
#[derive(Debug, Error)]
#[error("key rejected")]
pub struct KeyRejected {
    #[from]
    source: Box<dyn StdError + Send + Sync + 'static>,
}

pub(crate) fn key_rejected(
    source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> KeyRejected {
    KeyRejected {
        source: source.into(),
    }
}

/// Missing private key
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Error)]
#[error("cannot sign without a private key")]
pub struct MissingPrivateKey {
    _p: (),
}

pub(crate) const fn missing_private_key() -> MissingPrivateKey {
    MissingPrivateKey { _p: () }
}

/// Unexpected error (possibly a bug)
#[derive(Debug, Error)]
#[error("unexpected error")]
pub struct Unexpected {
    #[from]
    source: Box<dyn StdError + Send + Sync + 'static>,
}

pub(crate) fn unexpected(
    source: impl Into<Box<dyn StdError + Send + Sync + 'static>>,
) -> Unexpected {
    Unexpected {
        source: source.into(),
    }
}

/// An error occurring while creating a signature
#[derive(Debug, Error)]
pub enum SigningError {
    /// The key cannot be used for signing operations
    #[error(transparent)]
    MissingPrivateKey(#[from] MissingPrivateKey),

    /// Algorithm be used with this algorithm
    #[error(transparent)]
    IncompatibleAlgorithm(#[from] IncompatibleAlgorithm),

    /// An unexpected error
    #[error(transparent)]
    Unexpected(#[from] Unexpected),
}

impl From<std::convert::Infallible> for SigningError {
    fn from(_: std::convert::Infallible) -> Self {
        unreachable!("infallible result")
    }
}

/// An error occurring while verifying a signature with a JWK
#[derive(Debug, Error)]
pub enum JwkVerifyError {
    /// JWT cannot be used with this algorithm
    #[error(transparent)]
    IncompatibleAlgorithm(#[from] IncompatibleAlgorithm),

    /// JWK cannot be used for signature verification
    #[error(transparent)]
    JwkUsageMismatch(#[from] JwkUsageMismatch),

    /// Signature is invalid
    #[error(transparent)]
    SignatureMismatch(#[from] SignatureMismatch),

    /// An unexpected error
    #[error(transparent)]
    Unexpected(#[from] Unexpected),
}

impl JwkVerifyError {
    /// Whether the error is due to an incompatible algorithm
    pub fn is_incompatible_alg(&self) -> bool {
        match self {
            Self::IncompatibleAlgorithm(_) => true,
            _ => false,
        }
    }

    /// Whether the error is due to a usage mismatch
    pub fn is_usage_mismatch(&self) -> bool {
        match self {
            Self::JwkUsageMismatch(_) => true,
            _ => false,
        }
    }

    /// Whether the error is due to a signature mismatch
    pub fn is_signature_mismatch(&self) -> bool {
        match self {
            Self::SignatureMismatch(_) => true,
            _ => false,
        }
    }
}

/// An error occurring while verifying a JWT
#[derive(Debug, Error)]
pub enum JwtVerifyError {
    /// The JWT was rejected by the JWK
    #[error("token rejected by JWK")]
    JwkVerifyError(#[from] JwkVerifyError),

    /// The JWT is malformed, without a discernable header, payload, and signature
    #[error(transparent)]
    MalformedToken(#[from] MalformedJwt),

    /// The JWT header is malformed
    #[error(transparent)]
    MalformedTokenHeader(#[from] MalformedJwtHeader),

    /// The JWT payload is malformed
    #[error(transparent)]
    MalformedTokenPayload(#[from] MalformedJwtPayload),

    /// The JWT signature is malformed
    #[error(transparent)]
    MalformedTokenSignature(#[from] MalformedJwtSignature),

    /// The JWT was rejected by the claims validator
    #[error("token rejected by claims validator")]
    ClaimsRejected(#[from] ClaimsRejected),

    /// An unexpected error
    #[error(transparent)]
    Unexpected(#[from] Unexpected),
}

/// An error occurring when validating the claims of a JWT
#[derive(Debug, Error)]
pub enum ClaimsRejected {
    /// The token algorithm is not acceptable
    #[error("invalid algorithm")]
    InvalidAlgorithm,

    /// The token audience is not acceptable
    #[error("invalid audience")]
    InvalidAudience,

    /// The token issuer is not acceptable
    #[error("invalid issuer")]
    InvalidIssuer,

    /// The token audience is not acceptable
    #[error("invalid subject")]
    InvalidSubject,

    /// The token is expired according to the `exp` claim
    #[error("token expired")]
    TokenExpired,

    /// The token is not yet valid according to the `nbf` claim
    #[error("token not yet valid")]
    TokenNotYetValid,

    /// A required claim is missing
    #[error("required {_0} claim missing")]
    MissingRequiredClaim(&'static str),

    /// Custom validation error
    #[error("{_0}")]
    Custom(String),
}