/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 | | } |