Coverage Report

Created: 2026-09-19 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jsonwebtoken-10.3.0/src/crypto/mod.rs
Line
Count
Source
1
//! The cryptography of the `jsonwebtoken` crate is decoupled behind
2
//! [`JwtSigner`] and [`JwtVerifier`] traits. These make use of `signature`'s
3
//! [`Signer`] and [`Verifier`] traits respectively.
4
//! Crypto provider selection is handled by [`CryptoProvider`].
5
//!
6
//! [`JwtSigner`]: crate::crypto::JwtSigner
7
//! [`JwtVerifier`]: crate::crypto::JwtVerifier
8
//! [`Signer`]: signature::Signer
9
//! [`Verifier`]: signature::Verifier
10
//! [`CryptoProvider`]: crate::crypto::CryptoProvider
11
12
use crate::algorithms::Algorithm;
13
use crate::errors::Result;
14
use crate::jwk::{EllipticCurve, ThumbprintHash};
15
use crate::{DecodingKey, EncodingKey};
16
17
/// `aws_lc_rs` based CryptoProvider.
18
#[cfg(feature = "aws_lc_rs")]
19
pub mod aws_lc;
20
21
/// `RustCrypto` based CryptoProvider.
22
#[cfg(feature = "rust_crypto")]
23
pub mod rust_crypto;
24
25
use crate::serialization::{b64_decode, b64_encode};
26
use signature::{Signer, Verifier};
27
28
/// Trait providing the functionality to sign a JWT.
29
///
30
/// Allows an arbitrary crypto backend to be provided.
31
pub trait JwtSigner: Signer<Vec<u8>> {
32
    /// Return the [`Algorithm`] corresponding to the signing module.
33
    fn algorithm(&self) -> Algorithm;
34
}
35
36
/// Trait providing the functionality to verify a JWT.
37
///
38
/// Allows an arbitrary crypto backend to be provided.
39
pub trait JwtVerifier: Verifier<Vec<u8>> {
40
    /// Return the [`Algorithm`] corresponding to the signing module.
41
    fn algorithm(&self) -> Algorithm;
42
}
43
44
/// Take the payload of a JWT, sign it using the algorithm given and return
45
/// the base64 url safe encoded of the result.
46
///
47
/// If you just want to encode a JWT, use `encode` instead.
48
0
pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
49
0
    let provider = (CryptoProvider::get_default().signer_factory)(&algorithm, key)?;
50
0
    Ok(b64_encode(provider.try_sign(message)?))
51
0
}
52
53
/// Compares the signature given with a re-computed signature for HMAC or using the public key
54
/// for RSA/EC.
55
///
56
/// If you just want to decode a JWT, use `decode` instead.
57
///
58
/// `signature` is the signature part of a jwt (text after the second '.')
59
///
60
/// `message` is base64(header) + "." + base64(claims)
61
0
pub fn verify(
62
0
    signature: &str,
63
0
    message: &[u8],
64
0
    key: &DecodingKey,
65
0
    algorithm: Algorithm,
66
0
) -> Result<bool> {
67
0
    let provider = (CryptoProvider::get_default().verifier_factory)(&algorithm, key)?;
68
0
    Ok(provider.verify(message, &b64_decode(signature)?).is_ok())
69
0
}
70
71
/// Controls the cryptography used by jsonwebtoken.
72
///
73
/// You can either install one of the built-in options:
74
/// - [`crypto::aws_lc::DEFAULT_PROVIDER`]: (behind the `aws_lc_rs` crate feature).
75
///   This provider uses the [aws-lc-rs](https://github.com/aws/aws-lc-rs) crate.
76
/// - [`crypto::rust_crypto::DEFAULT_PROVIDER`]: (behind the `rust_crypto` crate feature)
77
///   This provider uses crates from the [Rust Crypto](https://github.com/RustCrypto) project.
78
///
79
/// or provide your own custom custom implementation of `CryptoProvider`.
80
// This implementation appropriates a good chunk of code from the `rustls` CryptoProvider,
81
// and is very much inspired by it.
82
#[derive(Clone, Debug)]
83
pub struct CryptoProvider {
84
    /// A function that produces a [`JwtSigner`] for a given [`Algorithm`]
85
    pub signer_factory: fn(&Algorithm, &EncodingKey) -> Result<Box<dyn JwtSigner>>,
86
    /// A function that produces a [`JwtVerifier`] for a given [`Algorithm`]
87
    pub verifier_factory: fn(&Algorithm, &DecodingKey) -> Result<Box<dyn JwtVerifier>>,
88
    /// Struct with utility functions for JWK processing.
89
    pub jwk_utils: JwkUtils,
90
}
91
92
impl CryptoProvider {
93
    /// Set this `CryptoProvider` as the default for this process.
94
    ///
95
    /// This can be called successfully at most once in any process execution.
96
0
    pub fn install_default(&'static self) -> std::result::Result<(), &'static Self> {
97
0
        static_default::install_default(self)
98
0
    }
99
100
0
    pub(crate) fn get_default() -> &'static Self {
101
0
        static_default::get_default()
102
0
    }
103
104
0
    fn from_crate_features() -> &'static Self {
105
        #[cfg(all(feature = "rust_crypto", not(feature = "aws_lc_rs")))]
106
        {
107
            return &rust_crypto::DEFAULT_PROVIDER;
108
        }
109
110
        #[cfg(all(feature = "aws_lc_rs", not(feature = "rust_crypto")))]
111
        {
112
0
            return &aws_lc::DEFAULT_PROVIDER;
113
        }
114
115
        #[allow(unreachable_code)]
116
        {
117
            const NOT_INSTALLED_ERROR: &str = r###"
118
Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.
119
Call CryptoProvider::install_default() before this point to select a provider manually, or make sure exactly one of the 'rust_crypto' and 'aws_lc_rs' features is enabled.
120
See the documentation of the CryptoProvider type for more information.
121
"###;
122
123
            static INSTANCE: CryptoProvider = CryptoProvider {
124
0
                signer_factory: |_, _| panic!("{}", NOT_INSTALLED_ERROR),
125
0
                verifier_factory: |_, _| panic!("{}", NOT_INSTALLED_ERROR),
126
                jwk_utils: JwkUtils::new_unimplemented(),
127
            };
128
129
            &INSTANCE
130
        }
131
0
    }
132
}
133
134
/// Holds utility functions required for JWK processing.
135
/// Use the [`JwkUtils::new_unimplemented`] function to initialize all values to dummies.
136
#[derive(Clone, Debug)]
137
pub struct JwkUtils {
138
    /// Given a DER encoded private key, extract the RSA public key components (n, e)
139
    #[allow(clippy::type_complexity)]
140
    pub extract_rsa_public_key_components: fn(&[u8]) -> Result<(Vec<u8>, Vec<u8>)>,
141
    /// Given a DER encoded private key and an algorithm, extract the associated curve
142
    /// and the EC public key components (x, y)
143
    #[allow(clippy::type_complexity)]
144
    pub extract_ec_public_key_coordinates:
145
        fn(&[u8], Algorithm) -> Result<(EllipticCurve, Vec<u8>, Vec<u8>)>,
146
    /// Given some data and a name of a hash function, compute hash_function(data)
147
    pub compute_digest: fn(&[u8], ThumbprintHash) -> Vec<u8>,
148
}
149
150
impl JwkUtils {
151
    /// Initialises all values to dummies.
152
    /// Will lead to a panic when JWKs are required, so only use it if you don't want to support JWKs.
153
0
    pub const fn new_unimplemented() -> Self {
154
        const NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR: &str = r###"
155
Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features, or your CryptoProvider does not support JWKs.
156
Call CryptoProvider::install_default() before this point to select a provider manually, or make sure exactly one of the 'rust_crypto' and 'aws_lc_rs' features is enabled.
157
See the documentation of the CryptoProvider type for more information.
158
"###;
159
        Self {
160
0
            extract_rsa_public_key_components: |_| {
161
0
                panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR)
162
            },
163
0
            extract_ec_public_key_coordinates: |_, _| {
164
0
                panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR)
165
            },
166
0
            compute_digest: |_, _| panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR),
167
        }
168
0
    }
169
}
170
171
mod static_default {
172
    use std::sync::OnceLock;
173
174
    use super::CryptoProvider;
175
176
    static PROCESS_DEFAULT_PROVIDER: OnceLock<&'static CryptoProvider> = OnceLock::new();
177
178
0
    pub(crate) fn install_default(
179
0
        default_provider: &'static CryptoProvider,
180
0
    ) -> Result<(), &'static CryptoProvider> {
181
0
        PROCESS_DEFAULT_PROVIDER.set(default_provider)
182
0
    }
183
184
0
    pub(crate) fn get_default() -> &'static CryptoProvider {
185
0
        PROCESS_DEFAULT_PROVIDER.get_or_init(CryptoProvider::from_crate_features)
186
0
    }
187
}