11//! The cryptography of the `jsonwebtoken` crate is decoupled behind
2- //! [`JwtSigner`] and [`JwtVerifier`] traits. These make use of `RustCrypto `'s
2+ //! [`JwtSigner`] and [`JwtVerifier`] traits. These make use of `signature `'s
33//! [`Signer`] and [`Verifier`] traits respectively.
4+ //! Crypto provider selection is handled by [`CryptoProvider`].
45//!
56//! [`JwtSigner`]: crate::crypto::JwtSigner
67//! [`JwtVerifier`]: crate::crypto::JwtVerifier
78//! [`Signer`]: signature::Signer
89//! [`Verifier`]: signature::Verifier
10+ //! [`CryptoProvider`]: crate::crypto::CryptoProvider
11+
12+ use std:: sync:: Arc ;
913
1014use crate :: algorithms:: Algorithm ;
1115use crate :: errors:: Result ;
16+ use crate :: jwk:: { EllipticCurve , ThumbprintHash } ;
1217use crate :: { DecodingKey , EncodingKey } ;
1318
19+ /// `aws_lc_rs` based CryptoProvider.
1420#[ cfg( feature = "aws_lc_rs" ) ]
15- pub ( crate ) mod aws_lc;
21+ pub mod aws_lc;
22+
23+ /// `RustCrypto` based CryptoProvider.
1624#[ cfg( feature = "rust_crypto" ) ]
17- pub ( crate ) mod rust_crypto;
25+ pub mod rust_crypto;
1826
1927use crate :: serialization:: { b64_decode, b64_encode} ;
2028use signature:: { Signer , Verifier } ;
@@ -40,7 +48,9 @@ pub trait JwtVerifier: Verifier<Vec<u8>> {
4048///
4149/// If you just want to encode a JWT, use `encode` instead.
4250pub fn sign ( message : & [ u8 ] , key : & EncodingKey , algorithm : Algorithm ) -> Result < String > {
43- let provider = crate :: encoding:: jwt_signer_factory ( & algorithm, key) ?;
51+ let provider = ( CryptoProvider :: get_default_or_install_from_crate_features ( ) . signer_factory ) (
52+ & algorithm, key,
53+ ) ?;
4454 Ok ( b64_encode ( provider. sign ( message) ) )
4555}
4656
@@ -58,6 +68,121 @@ pub fn verify(
5868 key : & DecodingKey ,
5969 algorithm : Algorithm ,
6070) -> Result < bool > {
61- let provider = crate :: decoding:: jwt_verifier_factory ( & algorithm, key) ?;
71+ let provider = ( CryptoProvider :: get_default_or_install_from_crate_features ( ) . verifier_factory ) (
72+ & algorithm, key,
73+ ) ?;
6274 Ok ( provider. verify ( message, & b64_decode ( signature) ?) . is_ok ( ) )
6375}
76+
77+ /// Controls the cryptography used by jsonwebtoken.
78+ ///
79+ /// You can either install one of the built-in options:
80+ /// - [`crypto::aws_lc::DEFAULT_PROVIDER`]: (behind the `aws_lc_rs` crate feature).
81+ /// This provider uses the [aws-lc-rs](https://github.com/aws/aws-lc-rs) crate.
82+ /// - [`crypto::rust_crypto::DEFAULT_PROVIDER`]: (behind the `rust_crypto` crate feature)
83+ /// This provider uses crates from the [Rust Crypto](https://github.com/RustCrypto) project.
84+ ///
85+ /// or provide your own custom custom implementation of `CryptoProvider`.
86+ // This implementation appropriates a good chunk of code from the `rustls` CryptoProvider,
87+ // and is very much inspired by it.
88+ #[ derive( Clone , Debug ) ]
89+ pub struct CryptoProvider {
90+ /// A function that produces a [`JwtSigner`] for a given [`Algorithm`]
91+ pub signer_factory : fn ( & Algorithm , & EncodingKey ) -> Result < Box < dyn JwtSigner > > ,
92+ /// A function that produces a [`JwtVerifier`] for a given [`Algorithm`]
93+ pub verifier_factory : fn ( & Algorithm , & DecodingKey ) -> Result < Box < dyn JwtVerifier > > ,
94+ /// Struct with utility functions for JWK processing.
95+ pub jwk_utils : JwkUtils ,
96+ }
97+
98+ impl CryptoProvider {
99+ /// Set this `CryptoProvider` as the default for this process.
100+ ///
101+ /// This can be called successfully at most once in any process execution.
102+ pub fn install_default ( self ) -> std:: result:: Result < ( ) , Arc < Self > > {
103+ static_default:: install_default ( self )
104+ }
105+
106+ /// Get the default `CryptoProvider` for this process.
107+ ///
108+ /// This will be `None` if no default has been set yet.
109+ pub fn get_default ( ) -> Option < & ' static Arc < Self > > {
110+ static_default:: get_default ( )
111+ }
112+
113+ /// Get the default if it has been set yet, or determine one from the crate features if possible.
114+ pub ( crate ) fn get_default_or_install_from_crate_features ( ) -> & ' static Arc < Self > {
115+ if let Some ( provider) = Self :: get_default ( ) {
116+ return provider;
117+ }
118+
119+ let provider = Self :: from_crate_features ( )
120+ . expect ( r###"
121+ Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features.
122+ 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.
123+ See the documentation of the CryptoProvider type for more information.
124+ "### ) ;
125+ let _ = provider. install_default ( ) ;
126+ Self :: get_default ( ) . unwrap ( )
127+ }
128+
129+ /// Determine a `CryptoProvider` based on crate features.
130+ pub fn from_crate_features ( ) -> Option < Self > {
131+ #[ cfg( all( feature = "rust_crypto" , not( feature = "aws_lc_rs" ) ) ) ]
132+ {
133+ return Some ( rust_crypto:: DEFAULT_PROVIDER ) ;
134+ }
135+
136+ #[ cfg( all( feature = "aws_lc_rs" , not( feature = "rust_crypto" ) ) ) ]
137+ {
138+ return Some ( aws_lc:: DEFAULT_PROVIDER ) ;
139+ }
140+
141+ #[ allow( unreachable_code) ]
142+ None
143+ }
144+ }
145+
146+ /// Holds utility functions required for JWK processing.
147+ /// The `Default` implementation initializes all functions to `unimplemented!()`.
148+ #[ derive( Clone , Debug ) ]
149+ pub struct JwkUtils {
150+ /// Given a DER encoded private key, extract the RSA public key components (n, e)
151+ #[ allow( clippy:: type_complexity) ]
152+ pub extract_rsa_public_key_components : fn ( & [ u8 ] ) -> Result < ( Vec < u8 > , Vec < u8 > ) > ,
153+ /// Given a DER encoded private key and an algorithm, extract the associated curve
154+ /// and the EC public key components (x, y)
155+ #[ allow( clippy:: type_complexity) ]
156+ pub extract_ec_public_key_coordinates :
157+ fn ( & [ u8 ] , Algorithm ) -> Result < ( EllipticCurve , Vec < u8 > , Vec < u8 > ) > ,
158+ /// Given some data and a name of a hash function, compute hash_function(data)
159+ pub compute_digest : fn ( & [ u8 ] , ThumbprintHash ) -> Vec < u8 > ,
160+ }
161+
162+ impl Default for JwkUtils {
163+ fn default ( ) -> Self {
164+ Self {
165+ extract_rsa_public_key_components : |_| unimplemented ! ( ) ,
166+ extract_ec_public_key_coordinates : |_, _| unimplemented ! ( ) ,
167+ compute_digest : |_, _| unimplemented ! ( ) ,
168+ }
169+ }
170+ }
171+
172+ mod static_default {
173+ use std:: sync:: { Arc , OnceLock } ;
174+
175+ use super :: CryptoProvider ;
176+
177+ static PROCESS_DEFAULT_PROVIDER : OnceLock < Arc < CryptoProvider > > = OnceLock :: new ( ) ;
178+
179+ pub ( crate ) fn install_default (
180+ default_provider : CryptoProvider ,
181+ ) -> Result < ( ) , Arc < CryptoProvider > > {
182+ PROCESS_DEFAULT_PROVIDER . set ( Arc :: new ( default_provider) )
183+ }
184+
185+ pub ( crate ) fn get_default ( ) -> Option < & ' static Arc < CryptoProvider > > {
186+ PROCESS_DEFAULT_PROVIDER . get ( )
187+ }
188+ }
0 commit comments