diff --git a/README.md b/README.md index 09b9f719..363387fe 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,10 @@ jsonwebtoken = { version = "10", features = ["aws_lc_rs"] } serde = {version = "1.0", features = ["derive"] } ``` -Two crypto backends are available via features, `aws_lc_rs` and `rust_crypto`, exactly one of which must be enabled. +Two crypto backends are available via features, `aws_lc_rs` and `rust_crypto`, at most one of which must be enabled. If you select neither feature, you need to provide your own `CryptoProvider`. + +For examples of how to implement a `CryptoProvider`, see +- [arckoor/jsonwebtoken-botan](https://github.com/arckoor/jsonwebtoken-botan) The minimum required Rust version (MSRV) is specified in the `rust-version` field in this project's [Cargo.toml](Cargo.toml). diff --git a/src/algorithms.rs b/src/algorithms.rs index 94eb3637..edb1d3ab 100644 --- a/src/algorithms.rs +++ b/src/algorithms.rs @@ -5,10 +5,15 @@ use serde::{Deserialize, Serialize}; use crate::errors::{Error, ErrorKind, Result}; #[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] +/// Supported families of algorithms. pub enum AlgorithmFamily { + /// HMAC shared secret family. Hmac, + /// RSA-based public key family. Rsa, + /// Edwards curve public key family. Ec, + /// Elliptic curve public key family. Ed, } diff --git a/src/crypto/aws_lc/ecdsa.rs b/src/crypto/aws_lc/ecdsa.rs index c278b934..5a5b364e 100644 --- a/src/crypto/aws_lc/ecdsa.rs +++ b/src/crypto/aws_lc/ecdsa.rs @@ -18,7 +18,7 @@ macro_rules! define_ecdsa_signer { impl $name { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { - if encoding_key.family != AlgorithmFamily::Ec { + if encoding_key.family() != AlgorithmFamily::Ec { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -51,7 +51,7 @@ macro_rules! define_ecdsa_verifier { impl $name { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { - if decoding_key.family != AlgorithmFamily::Ec { + if decoding_key.family() != AlgorithmFamily::Ec { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/aws_lc/eddsa.rs b/src/crypto/aws_lc/eddsa.rs index d6e60a50..085bf7c3 100644 --- a/src/crypto/aws_lc/eddsa.rs +++ b/src/crypto/aws_lc/eddsa.rs @@ -11,7 +11,7 @@ pub struct EdDSASigner(Ed25519KeyPair); impl EdDSASigner { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { - if encoding_key.family != AlgorithmFamily::Ed { + if encoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -38,7 +38,7 @@ pub struct EdDSAVerifier(DecodingKey); impl EdDSAVerifier { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { - if decoding_key.family != AlgorithmFamily::Ed { + if decoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/aws_lc/mod.rs b/src/crypto/aws_lc/mod.rs index 16f66b5f..76f8a2c3 100644 --- a/src/crypto/aws_lc/mod.rs +++ b/src/crypto/aws_lc/mod.rs @@ -1,4 +1,110 @@ -pub(crate) mod ecdsa; -pub(crate) mod eddsa; -pub(crate) mod hmac; -pub(crate) mod rsa; +use aws_lc_rs::{ + digest, + signature::{ + self as aws_sig, ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING, + EcdsaKeyPair, KeyPair, + }, +}; + +use crate::{ + Algorithm, DecodingKey, EncodingKey, + crypto::{CryptoProvider, JwkUtils, JwtSigner, JwtVerifier}, + errors::{self, Error, ErrorKind}, + jwk::{EllipticCurve, ThumbprintHash}, +}; + +mod ecdsa; +mod eddsa; +mod hmac; +mod rsa; + +fn extract_rsa_public_key_components(key_content: &[u8]) -> errors::Result<(Vec, Vec)> { + let key_pair = aws_sig::RsaKeyPair::from_der(key_content) + .map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?; + let public = key_pair.public_key(); + let components = aws_sig::RsaPublicKeyComponents::>::from(public); + Ok((components.n, components.e)) +} + +fn extract_ec_public_key_coordinates( + key_content: &[u8], + alg: Algorithm, +) -> errors::Result<(EllipticCurve, Vec, Vec)> { + let (signing_alg, curve, pub_elem_bytes) = match alg { + Algorithm::ES256 => (&ECDSA_P256_SHA256_FIXED_SIGNING, EllipticCurve::P256, 32), + Algorithm::ES384 => (&ECDSA_P384_SHA384_FIXED_SIGNING, EllipticCurve::P384, 48), + _ => return Err(ErrorKind::InvalidEcdsaKey.into()), + }; + + let key_pair = EcdsaKeyPair::from_pkcs8(signing_alg, key_content) + .map_err(|_| ErrorKind::InvalidEcdsaKey)?; + + let pub_bytes = key_pair.public_key().as_ref(); + if pub_bytes[0] != 4 { + return Err(ErrorKind::InvalidEcdsaKey.into()); + } + + let (x, y) = pub_bytes[1..].split_at(pub_elem_bytes); + Ok((curve, x.to_vec(), y.to_vec())) +} + +fn compute_digest(data: &[u8], hash_function: ThumbprintHash) -> Vec { + let algorithm = match hash_function { + ThumbprintHash::SHA256 => &digest::SHA256, + ThumbprintHash::SHA384 => &digest::SHA384, + ThumbprintHash::SHA512 => &digest::SHA512, + }; + digest::digest(algorithm, data).as_ref().to_vec() +} + +fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result, Error> { + let jwt_signer = match algorithm { + Algorithm::HS256 => Box::new(hmac::Hs256Signer::new(key)?) as Box, + Algorithm::HS384 => Box::new(hmac::Hs384Signer::new(key)?) as Box, + Algorithm::HS512 => Box::new(hmac::Hs512Signer::new(key)?) as Box, + Algorithm::ES256 => Box::new(ecdsa::Es256Signer::new(key)?) as Box, + Algorithm::ES384 => Box::new(ecdsa::Es384Signer::new(key)?) as Box, + Algorithm::RS256 => Box::new(rsa::Rsa256Signer::new(key)?) as Box, + Algorithm::RS384 => Box::new(rsa::Rsa384Signer::new(key)?) as Box, + Algorithm::RS512 => Box::new(rsa::Rsa512Signer::new(key)?) as Box, + Algorithm::PS256 => Box::new(rsa::RsaPss256Signer::new(key)?) as Box, + Algorithm::PS384 => Box::new(rsa::RsaPss384Signer::new(key)?) as Box, + Algorithm::PS512 => Box::new(rsa::RsaPss512Signer::new(key)?) as Box, + Algorithm::EdDSA => Box::new(eddsa::EdDSASigner::new(key)?) as Box, + }; + + Ok(jwt_signer) +} + +fn new_verifier( + algorithm: &Algorithm, + key: &DecodingKey, +) -> Result, Error> { + let jwt_verifier = match algorithm { + Algorithm::HS256 => Box::new(hmac::Hs256Verifier::new(key)?) as Box, + Algorithm::HS384 => Box::new(hmac::Hs384Verifier::new(key)?) as Box, + Algorithm::HS512 => Box::new(hmac::Hs512Verifier::new(key)?) as Box, + Algorithm::ES256 => Box::new(ecdsa::Es256Verifier::new(key)?) as Box, + Algorithm::ES384 => Box::new(ecdsa::Es384Verifier::new(key)?) as Box, + Algorithm::RS256 => Box::new(rsa::Rsa256Verifier::new(key)?) as Box, + Algorithm::RS384 => Box::new(rsa::Rsa384Verifier::new(key)?) as Box, + Algorithm::RS512 => Box::new(rsa::Rsa512Verifier::new(key)?) as Box, + Algorithm::PS256 => Box::new(rsa::RsaPss256Verifier::new(key)?) as Box, + Algorithm::PS384 => Box::new(rsa::RsaPss384Verifier::new(key)?) as Box, + Algorithm::PS512 => Box::new(rsa::RsaPss512Verifier::new(key)?) as Box, + Algorithm::EdDSA => Box::new(eddsa::EdDSAVerifier::new(key)?) as Box, + }; + + Ok(jwt_verifier) +} + +/// The default [`CryptoProvider`] backed by [`aws_lc_rs`]. +pub static DEFAULT_PROVIDER: CryptoProvider = CryptoProvider { + signer_factory: new_signer, + verifier_factory: new_verifier, + jwk_utils: JwkUtils { + extract_rsa_public_key_components, + extract_ec_public_key_coordinates, + compute_digest, + }, +}; diff --git a/src/crypto/aws_lc/rsa.rs b/src/crypto/aws_lc/rsa.rs index 7e74eebf..d72b0680 100644 --- a/src/crypto/aws_lc/rsa.rs +++ b/src/crypto/aws_lc/rsa.rs @@ -37,7 +37,7 @@ fn verify_rsa( msg: &[u8], signature: &[u8], ) -> std::result::Result<(), signature::Error> { - match &decoding_key.kind { + match decoding_key.kind() { DecodingKeyKind::SecretOrDer(bytes) => { let public_key = crypto_sig::UnparsedPublicKey::new(algorithm, bytes); public_key.verify(msg, signature).map_err(signature::Error::from_source)?; @@ -57,7 +57,7 @@ macro_rules! define_rsa_signer { impl $name { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { - if encoding_key.family != AlgorithmFamily::Rsa { + if encoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -85,7 +85,7 @@ macro_rules! define_rsa_verifier { impl $name { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { - if decoding_key.family != AlgorithmFamily::Rsa { + if decoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index adec0d0b..d681bde7 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -1,20 +1,26 @@ //! The cryptography of the `jsonwebtoken` crate is decoupled behind -//! [`JwtSigner`] and [`JwtVerifier`] traits. These make use of `RustCrypto`'s +//! [`JwtSigner`] and [`JwtVerifier`] traits. These make use of `signature`'s //! [`Signer`] and [`Verifier`] traits respectively. +//! Crypto provider selection is handled by [`CryptoProvider`]. //! //! [`JwtSigner`]: crate::crypto::JwtSigner //! [`JwtVerifier`]: crate::crypto::JwtVerifier //! [`Signer`]: signature::Signer //! [`Verifier`]: signature::Verifier +//! [`CryptoProvider`]: crate::crypto::CryptoProvider use crate::algorithms::Algorithm; use crate::errors::Result; +use crate::jwk::{EllipticCurve, ThumbprintHash}; use crate::{DecodingKey, EncodingKey}; +/// `aws_lc_rs` based CryptoProvider. #[cfg(feature = "aws_lc_rs")] -pub(crate) mod aws_lc; +pub mod aws_lc; + +/// `RustCrypto` based CryptoProvider. #[cfg(feature = "rust_crypto")] -pub(crate) mod rust_crypto; +pub mod rust_crypto; use crate::serialization::{b64_decode, b64_encode}; use signature::{Signer, Verifier}; @@ -40,7 +46,7 @@ pub trait JwtVerifier: Verifier> { /// /// If you just want to encode a JWT, use `encode` instead. pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result { - let provider = crate::encoding::jwt_signer_factory(&algorithm, key)?; + let provider = (CryptoProvider::get_default().signer_factory)(&algorithm, key)?; Ok(b64_encode(provider.sign(message))) } @@ -58,6 +64,124 @@ pub fn verify( key: &DecodingKey, algorithm: Algorithm, ) -> Result { - let provider = crate::decoding::jwt_verifier_factory(&algorithm, key)?; + let provider = (CryptoProvider::get_default().verifier_factory)(&algorithm, key)?; Ok(provider.verify(message, &b64_decode(signature)?).is_ok()) } + +/// Controls the cryptography used by jsonwebtoken. +/// +/// You can either install one of the built-in options: +/// - [`crypto::aws_lc::DEFAULT_PROVIDER`]: (behind the `aws_lc_rs` crate feature). +/// This provider uses the [aws-lc-rs](https://github.com/aws/aws-lc-rs) crate. +/// - [`crypto::rust_crypto::DEFAULT_PROVIDER`]: (behind the `rust_crypto` crate feature) +/// This provider uses crates from the [Rust Crypto](https://github.com/RustCrypto) project. +/// +/// or provide your own custom custom implementation of `CryptoProvider`. +// This implementation appropriates a good chunk of code from the `rustls` CryptoProvider, +// and is very much inspired by it. +#[derive(Clone, Debug)] +pub struct CryptoProvider { + /// A function that produces a [`JwtSigner`] for a given [`Algorithm`] + pub signer_factory: fn(&Algorithm, &EncodingKey) -> Result>, + /// A function that produces a [`JwtVerifier`] for a given [`Algorithm`] + pub verifier_factory: fn(&Algorithm, &DecodingKey) -> Result>, + /// Struct with utility functions for JWK processing. + pub jwk_utils: JwkUtils, +} + +impl CryptoProvider { + /// Set this `CryptoProvider` as the default for this process. + /// + /// This can be called successfully at most once in any process execution. + pub fn install_default(&'static self) -> std::result::Result<(), &'static Self> { + static_default::install_default(self) + } + + pub(crate) fn get_default() -> &'static Self { + static_default::get_default() + } + + fn from_crate_features() -> &'static Self { + #[cfg(all(feature = "rust_crypto", not(feature = "aws_lc_rs")))] + { + return &rust_crypto::DEFAULT_PROVIDER; + } + + #[cfg(all(feature = "aws_lc_rs", not(feature = "rust_crypto")))] + { + return &aws_lc::DEFAULT_PROVIDER; + } + + #[allow(unreachable_code)] + { + const NOT_INSTALLED_ERROR: &str = r###" +Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features. +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. +See the documentation of the CryptoProvider type for more information. +"###; + + static INSTANCE: CryptoProvider = CryptoProvider { + signer_factory: |_, _| panic!("{}", NOT_INSTALLED_ERROR), + verifier_factory: |_, _| panic!("{}", NOT_INSTALLED_ERROR), + jwk_utils: JwkUtils::new_unimplemented(), + }; + + &INSTANCE + } + } +} + +/// Holds utility functions required for JWK processing. +/// Use the [`JwkUtils::new_unimplemented`] function to initialize all values to dummies. +#[derive(Clone, Debug)] +pub struct JwkUtils { + /// Given a DER encoded private key, extract the RSA public key components (n, e) + #[allow(clippy::type_complexity)] + pub extract_rsa_public_key_components: fn(&[u8]) -> Result<(Vec, Vec)>, + /// Given a DER encoded private key and an algorithm, extract the associated curve + /// and the EC public key components (x, y) + #[allow(clippy::type_complexity)] + pub extract_ec_public_key_coordinates: + fn(&[u8], Algorithm) -> Result<(EllipticCurve, Vec, Vec)>, + /// Given some data and a name of a hash function, compute hash_function(data) + pub compute_digest: fn(&[u8], ThumbprintHash) -> Vec, +} + +impl JwkUtils { + /// Initialises all values to dummies. + /// Will lead to a panic when JWKs are required, so only use it if you don't want to support JWKs. + pub const fn new_unimplemented() -> Self { + const NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR: &str = r###" +Could not automatically determine the process-level CryptoProvider from jsonwebtoken crate features, or your CryptoProvider does not support JWKs. +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. +See the documentation of the CryptoProvider type for more information. +"###; + Self { + extract_rsa_public_key_components: |_| { + panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR) + }, + extract_ec_public_key_coordinates: |_, _| { + panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR) + }, + compute_digest: |_, _| panic!("{}", NOT_INSTALLED_OR_UNIMPLEMENTED_ERROR), + } + } +} + +mod static_default { + use std::sync::OnceLock; + + use super::CryptoProvider; + + static PROCESS_DEFAULT_PROVIDER: OnceLock<&'static CryptoProvider> = OnceLock::new(); + + pub(crate) fn install_default( + default_provider: &'static CryptoProvider, + ) -> Result<(), &'static CryptoProvider> { + PROCESS_DEFAULT_PROVIDER.set(default_provider) + } + + pub(crate) fn get_default() -> &'static CryptoProvider { + PROCESS_DEFAULT_PROVIDER.get_or_init(CryptoProvider::from_crate_features) + } +} diff --git a/src/crypto/rust_crypto/ecdsa.rs b/src/crypto/rust_crypto/ecdsa.rs index f192adea..9aad882e 100644 --- a/src/crypto/rust_crypto/ecdsa.rs +++ b/src/crypto/rust_crypto/ecdsa.rs @@ -20,7 +20,7 @@ macro_rules! define_ecdsa_signer { impl $name { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { - if encoding_key.family != AlgorithmFamily::Ec { + if encoding_key.family() != AlgorithmFamily::Ec { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -52,7 +52,7 @@ macro_rules! define_ecdsa_verifier { impl $name { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { - if decoding_key.family != AlgorithmFamily::Ec { + if decoding_key.family() != AlgorithmFamily::Ec { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/rust_crypto/eddsa.rs b/src/crypto/rust_crypto/eddsa.rs index dc0fcecd..9b77a9f8 100644 --- a/src/crypto/rust_crypto/eddsa.rs +++ b/src/crypto/rust_crypto/eddsa.rs @@ -12,7 +12,7 @@ pub struct EdDSASigner(SigningKey); impl EdDSASigner { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { - if encoding_key.family != AlgorithmFamily::Ed { + if encoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -39,7 +39,7 @@ pub struct EdDSAVerifier(VerifyingKey); impl EdDSAVerifier { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { - if decoding_key.family != AlgorithmFamily::Ed { + if decoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/rust_crypto/mod.rs b/src/crypto/rust_crypto/mod.rs index 16f66b5f..cd0c9bdc 100644 --- a/src/crypto/rust_crypto/mod.rs +++ b/src/crypto/rust_crypto/mod.rs @@ -1,4 +1,116 @@ -pub(crate) mod ecdsa; -pub(crate) mod eddsa; -pub(crate) mod hmac; -pub(crate) mod rsa; +use ::rsa::{RsaPrivateKey, pkcs1::DecodeRsaPrivateKey, traits::PublicKeyParts}; +use p256::{ecdsa::SigningKey as P256SigningKey, pkcs8::DecodePrivateKey}; +use p384::ecdsa::SigningKey as P384SigningKey; +use sha2::{Digest, Sha256, Sha384, Sha512}; + +use crate::{ + Algorithm, DecodingKey, EncodingKey, + crypto::{CryptoProvider, JwkUtils, JwtSigner, JwtVerifier}, + errors::{self, Error, ErrorKind}, + jwk::{EllipticCurve, ThumbprintHash}, +}; + +mod ecdsa; +mod eddsa; +mod hmac; +mod rsa; + +fn extract_rsa_public_key_components(key_content: &[u8]) -> errors::Result<(Vec, Vec)> { + let private_key = RsaPrivateKey::from_pkcs1_der(key_content) + .map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?; + let public_key = private_key.to_public_key(); + Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be())) +} + +fn extract_ec_public_key_coordinates( + key_content: &[u8], + alg: Algorithm, +) -> errors::Result<(EllipticCurve, Vec, Vec)> { + match alg { + Algorithm::ES256 => { + let signing_key = P256SigningKey::from_pkcs8_der(key_content) + .map_err(|_| ErrorKind::InvalidEcdsaKey)?; + let public_key = signing_key.verifying_key(); + let encoded = public_key.to_encoded_point(false); + match encoded.coordinates() { + p256::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => { + Ok((EllipticCurve::P256, x.to_vec(), y.to_vec())) + } + _ => Err(ErrorKind::InvalidEcdsaKey.into()), + } + } + Algorithm::ES384 => { + let signing_key = P384SigningKey::from_pkcs8_der(key_content) + .map_err(|_| ErrorKind::InvalidEcdsaKey)?; + let public_key = signing_key.verifying_key(); + let encoded = public_key.to_encoded_point(false); + match encoded.coordinates() { + p384::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => { + Ok((EllipticCurve::P384, x.to_vec(), y.to_vec())) + } + _ => Err(ErrorKind::InvalidEcdsaKey.into()), + } + } + _ => Err(ErrorKind::InvalidEcdsaKey.into()), + } +} + +fn compute_digest(data: &[u8], hash_function: ThumbprintHash) -> Vec { + match hash_function { + ThumbprintHash::SHA256 => Sha256::digest(data).to_vec(), + ThumbprintHash::SHA384 => Sha384::digest(data).to_vec(), + ThumbprintHash::SHA512 => Sha512::digest(data).to_vec(), + } +} + +fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result, Error> { + let jwt_signer = match algorithm { + Algorithm::HS256 => Box::new(hmac::Hs256Signer::new(key)?) as Box, + Algorithm::HS384 => Box::new(hmac::Hs384Signer::new(key)?) as Box, + Algorithm::HS512 => Box::new(hmac::Hs512Signer::new(key)?) as Box, + Algorithm::ES256 => Box::new(ecdsa::Es256Signer::new(key)?) as Box, + Algorithm::ES384 => Box::new(ecdsa::Es384Signer::new(key)?) as Box, + Algorithm::RS256 => Box::new(rsa::Rsa256Signer::new(key)?) as Box, + Algorithm::RS384 => Box::new(rsa::Rsa384Signer::new(key)?) as Box, + Algorithm::RS512 => Box::new(rsa::Rsa512Signer::new(key)?) as Box, + Algorithm::PS256 => Box::new(rsa::RsaPss256Signer::new(key)?) as Box, + Algorithm::PS384 => Box::new(rsa::RsaPss384Signer::new(key)?) as Box, + Algorithm::PS512 => Box::new(rsa::RsaPss512Signer::new(key)?) as Box, + Algorithm::EdDSA => Box::new(eddsa::EdDSASigner::new(key)?) as Box, + }; + + Ok(jwt_signer) +} + +fn new_verifier( + algorithm: &Algorithm, + key: &DecodingKey, +) -> Result, Error> { + let jwt_verifier = match algorithm { + Algorithm::HS256 => Box::new(hmac::Hs256Verifier::new(key)?) as Box, + Algorithm::HS384 => Box::new(hmac::Hs384Verifier::new(key)?) as Box, + Algorithm::HS512 => Box::new(hmac::Hs512Verifier::new(key)?) as Box, + Algorithm::ES256 => Box::new(ecdsa::Es256Verifier::new(key)?) as Box, + Algorithm::ES384 => Box::new(ecdsa::Es384Verifier::new(key)?) as Box, + Algorithm::RS256 => Box::new(rsa::Rsa256Verifier::new(key)?) as Box, + Algorithm::RS384 => Box::new(rsa::Rsa384Verifier::new(key)?) as Box, + Algorithm::RS512 => Box::new(rsa::Rsa512Verifier::new(key)?) as Box, + Algorithm::PS256 => Box::new(rsa::RsaPss256Verifier::new(key)?) as Box, + Algorithm::PS384 => Box::new(rsa::RsaPss384Verifier::new(key)?) as Box, + Algorithm::PS512 => Box::new(rsa::RsaPss512Verifier::new(key)?) as Box, + Algorithm::EdDSA => Box::new(eddsa::EdDSAVerifier::new(key)?) as Box, + }; + + Ok(jwt_verifier) +} + +/// The default [`CryptoProvider`] backed by [`rust_crypto`](https://github.com/RustCrypto). +pub static DEFAULT_PROVIDER: CryptoProvider = CryptoProvider { + signer_factory: new_signer, + verifier_factory: new_verifier, + jwk_utils: JwkUtils { + extract_rsa_public_key_components, + extract_ec_public_key_coordinates, + compute_digest, + }, +}; diff --git a/src/crypto/rust_crypto/rsa.rs b/src/crypto/rust_crypto/rsa.rs index b73797e8..ba0af0fe 100644 --- a/src/crypto/rust_crypto/rsa.rs +++ b/src/crypto/rust_crypto/rsa.rs @@ -49,7 +49,7 @@ fn verify_rsa( ) -> std::result::Result<(), signature::Error> { let digest = H::digest(msg); - match &decoding_key.kind { + match decoding_key.kind() { DecodingKeyKind::SecretOrDer(bytes) => { RsaPublicKey::from_pkcs1_der(bytes) .map_err(signature::Error::from_source)? @@ -72,7 +72,7 @@ macro_rules! define_rsa_signer { impl $name { pub(crate) fn new(encoding_key: &EncodingKey) -> Result { - if encoding_key.family != AlgorithmFamily::Rsa { + if encoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -100,7 +100,7 @@ macro_rules! define_rsa_verifier { impl $name { pub(crate) fn new(decoding_key: &DecodingKey) -> Result { - if decoding_key.family != AlgorithmFamily::Rsa { + if decoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/decoding.rs b/src/decoding.rs index 51d793e7..216138f3 100644 --- a/src/decoding.rs +++ b/src/decoding.rs @@ -3,9 +3,8 @@ use std::fmt::{Debug, Formatter}; use base64::{Engine, engine::general_purpose::STANDARD}; use serde::de::DeserializeOwned; -use crate::Algorithm; use crate::algorithms::AlgorithmFamily; -use crate::crypto::JwtVerifier; +use crate::crypto::{CryptoProvider, JwtVerifier}; use crate::errors::{ErrorKind, Result, new_error}; use crate::header::Header; use crate::jwk::{AlgorithmParameters, Jwk}; @@ -13,27 +12,6 @@ use crate::jwk::{AlgorithmParameters, Jwk}; use crate::pem::decoder::PemEncodedKey; use crate::serialization::{DecodedJwtPartClaims, b64_decode}; use crate::validation::{Validation, validate}; -// Crypto -#[cfg(feature = "aws_lc_rs")] -use crate::crypto::aws_lc::{ - ecdsa::{Es256Verifier, Es384Verifier}, - eddsa::EdDSAVerifier, - hmac::{Hs256Verifier, Hs384Verifier, Hs512Verifier}, - rsa::{ - Rsa256Verifier, Rsa384Verifier, Rsa512Verifier, RsaPss256Verifier, RsaPss384Verifier, - RsaPss512Verifier, - }, -}; -#[cfg(feature = "rust_crypto")] -use crate::crypto::rust_crypto::{ - ecdsa::{Es256Verifier, Es384Verifier}, - eddsa::EdDSAVerifier, - hmac::{Hs256Verifier, Hs384Verifier, Hs512Verifier}, - rsa::{ - Rsa256Verifier, Rsa384Verifier, Rsa512Verifier, RsaPss256Verifier, RsaPss384Verifier, - RsaPss512Verifier, - }, -}; /// The return type of a successful call to [decode](fn.decode.html). #[derive(Debug)] @@ -66,9 +44,17 @@ macro_rules! expect_two { } #[derive(Clone)] -pub(crate) enum DecodingKeyKind { +/// Different kinds of decoding keys. +pub enum DecodingKeyKind { + /// A raw public key. SecretOrDer(Vec), - RsaModulusExponent { n: Vec, e: Vec }, + /// RSA public key components. + RsaModulusExponent { + /// The modulus of the public key. + n: Vec, + /// The exponent of the public key. + e: Vec, + }, } impl Debug for DecodingKeyKind { @@ -88,8 +74,8 @@ impl Debug for DecodingKeyKind { /// This key can be re-used so make sure you only initialize it once if you can for better performance. #[derive(Clone, Debug)] pub struct DecodingKey { - pub(crate) family: AlgorithmFamily, - pub(crate) kind: DecodingKeyKind, + family: AlgorithmFamily, + kind: DecodingKeyKind, } impl DecodingKey { @@ -98,6 +84,11 @@ impl DecodingKey { self.family } + /// The kind of decoding key. + pub fn kind(&self) -> &DecodingKeyKind { + &self.kind + } + /// If you're using HMAC, use this. pub fn from_secret(secret: &[u8]) -> Self { DecodingKey { @@ -235,14 +226,16 @@ impl DecodingKey { } } - pub(crate) fn as_bytes(&self) -> &[u8] { + /// Get the value of the key. + pub fn as_bytes(&self) -> &[u8] { match &self.kind { DecodingKeyKind::SecretOrDer(b) => b, DecodingKeyKind::RsaModulusExponent { .. } => unreachable!(), } } - pub(crate) fn try_get_hmac_secret(&self) -> Result<&[u8]> { + /// Try to get the HMAC secret from a key. + pub fn try_get_hmac_secret(&self) -> Result<&[u8]> { if self.family == AlgorithmFamily::Hmac { Ok(self.as_bytes()) } else { @@ -289,7 +282,7 @@ pub fn decode( return Err(new_error(ErrorKind::InvalidAlgorithm)); } - let verifying_provider = jwt_verifier_factory(&header.alg, key)?; + let verifying_provider = (CryptoProvider::get_default().verifier_factory)(&header.alg, key)?; let (header, claims) = verify_signature(token, validation, verifying_provider)?; @@ -315,29 +308,6 @@ pub fn insecure_decode(token: impl AsRef<[u8]>) -> Result Result> { - let jwt_encoder = match algorithm { - Algorithm::HS256 => Box::new(Hs256Verifier::new(key)?) as Box, - Algorithm::HS384 => Box::new(Hs384Verifier::new(key)?) as Box, - Algorithm::HS512 => Box::new(Hs512Verifier::new(key)?) as Box, - Algorithm::ES256 => Box::new(Es256Verifier::new(key)?) as Box, - Algorithm::ES384 => Box::new(Es384Verifier::new(key)?) as Box, - Algorithm::RS256 => Box::new(Rsa256Verifier::new(key)?) as Box, - Algorithm::RS384 => Box::new(Rsa384Verifier::new(key)?) as Box, - Algorithm::RS512 => Box::new(Rsa512Verifier::new(key)?) as Box, - Algorithm::PS256 => Box::new(RsaPss256Verifier::new(key)?) as Box, - Algorithm::PS384 => Box::new(RsaPss384Verifier::new(key)?) as Box, - Algorithm::PS512 => Box::new(RsaPss512Verifier::new(key)?) as Box, - Algorithm::EdDSA => Box::new(EdDSAVerifier::new(key)?) as Box, - }; - - Ok(jwt_encoder) -} - /// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html). /// /// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error. diff --git a/src/encoding.rs b/src/encoding.rs index 30a31953..b6b27203 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -6,40 +6,20 @@ use base64::{ }; use serde::ser::Serialize; -use crate::Algorithm; use crate::algorithms::AlgorithmFamily; -use crate::crypto::JwtSigner; +use crate::crypto::CryptoProvider; use crate::errors::{ErrorKind, Result, new_error}; use crate::header::Header; #[cfg(feature = "use_pem")] use crate::pem::decoder::PemEncodedKey; use crate::serialization::{b64_encode, b64_encode_part}; -// Crypto -#[cfg(feature = "aws_lc_rs")] -use crate::crypto::aws_lc::{ - ecdsa::{Es256Signer, Es384Signer}, - eddsa::EdDSASigner, - hmac::{Hs256Signer, Hs384Signer, Hs512Signer}, - rsa::{ - Rsa256Signer, Rsa384Signer, Rsa512Signer, RsaPss256Signer, RsaPss384Signer, RsaPss512Signer, - }, -}; -#[cfg(feature = "rust_crypto")] -use crate::crypto::rust_crypto::{ - ecdsa::{Es256Signer, Es384Signer}, - eddsa::EdDSASigner, - hmac::{Hs256Signer, Hs384Signer, Hs512Signer}, - rsa::{ - Rsa256Signer, Rsa384Signer, Rsa512Signer, RsaPss256Signer, RsaPss384Signer, RsaPss512Signer, - }, -}; /// A key to encode a JWT with. Can be a secret, a PEM-encoded key or a DER-encoded key. /// This key can be re-used so make sure you only initialize it once if you can for better performance. #[derive(Clone)] pub struct EncodingKey { - pub(crate) family: AlgorithmFamily, - pub(crate) content: Vec, + family: AlgorithmFamily, + content: Vec, } impl EncodingKey { @@ -127,11 +107,13 @@ impl EncodingKey { EncodingKey { family: AlgorithmFamily::Ed, content: der.to_vec() } } - pub(crate) fn inner(&self) -> &[u8] { + /// Get the value of the key. + pub fn inner(&self) -> &[u8] { &self.content } - pub(crate) fn try_get_hmac_secret(&self) -> Result<&[u8]> { + /// Try to get the HMAC secret from a key. + pub fn try_get_hmac_secret(&self) -> Result<&[u8]> { if self.family == AlgorithmFamily::Hmac { Ok(self.inner()) } else { @@ -176,7 +158,7 @@ pub fn encode(header: &Header, claims: &T, key: &EncodingKey) -> R return Err(new_error(ErrorKind::InvalidAlgorithm)); } - let signing_provider = jwt_signer_factory(&header.alg, key)?; + let signing_provider = (CryptoProvider::get_default().signer_factory)(&header.alg, key)?; if signing_provider.algorithm() != header.alg { return Err(new_error(ErrorKind::InvalidAlgorithm)); @@ -190,26 +172,3 @@ pub fn encode(header: &Header, claims: &T, key: &EncodingKey) -> R Ok([message, signature].join(".")) } - -/// Return the correct [`JwtSigner`] based on the `algorithm`. -pub(crate) fn jwt_signer_factory( - algorithm: &Algorithm, - key: &EncodingKey, -) -> Result> { - let jwt_signer = match algorithm { - Algorithm::HS256 => Box::new(Hs256Signer::new(key)?) as Box, - Algorithm::HS384 => Box::new(Hs384Signer::new(key)?) as Box, - Algorithm::HS512 => Box::new(Hs512Signer::new(key)?) as Box, - Algorithm::ES256 => Box::new(Es256Signer::new(key)?) as Box, - Algorithm::ES384 => Box::new(Es384Signer::new(key)?) as Box, - Algorithm::RS256 => Box::new(Rsa256Signer::new(key)?) as Box, - Algorithm::RS384 => Box::new(Rsa384Signer::new(key)?) as Box, - Algorithm::RS512 => Box::new(Rsa512Signer::new(key)?) as Box, - Algorithm::PS256 => Box::new(RsaPss256Signer::new(key)?) as Box, - Algorithm::PS384 => Box::new(RsaPss384Signer::new(key)?) as Box, - Algorithm::PS512 => Box::new(RsaPss512Signer::new(key)?) as Box, - Algorithm::EdDSA => Box::new(EdDSASigner::new(key)?) as Box, - }; - - Ok(jwt_signer) -} diff --git a/src/errors.rs b/src/errors.rs index 7ad913f3..3d4963f4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -3,8 +3,9 @@ use std::fmt; use std::result; use std::sync::Arc; -/// A crate private constructor for `Error`. -pub(crate) fn new_error(kind: ErrorKind) -> Error { +/// A constructor for `Error`. +/// Intended for use in custom crypto providers. +pub fn new_error(kind: ErrorKind) -> Error { Error(Box::new(kind)) } @@ -78,6 +79,8 @@ pub enum ErrorKind { Json(Arc), /// Some of the text was invalid UTF-8 Utf8(::std::string::FromUtf8Error), + /// An error happened in a custom provider + Provider(String), } impl StdError for Error { @@ -102,6 +105,7 @@ impl StdError for Error { ErrorKind::Base64(err) => Some(err), ErrorKind::Json(err) => Some(err.as_ref()), ErrorKind::Utf8(err) => Some(err), + ErrorKind::Provider(_) => None, } } } @@ -128,6 +132,7 @@ impl fmt::Display for Error { ErrorKind::Json(err) => write!(f, "JSON error: {}", err), ErrorKind::Utf8(err) => write!(f, "UTF-8 error: {}", err), ErrorKind::Base64(err) => write!(f, "Base64 error: {}", err), + ErrorKind::Provider(msg) => write!(f, "Custom provider error: {}", msg), } } } diff --git a/src/jwk.rs b/src/jwk.rs index 31f944d2..200bd043 100644 --- a/src/jwk.rs +++ b/src/jwk.rs @@ -8,25 +8,13 @@ use std::{fmt, str::FromStr}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; +use crate::crypto::CryptoProvider; use crate::serialization::b64_encode; use crate::{ Algorithm, EncodingKey, errors::{self, Error, ErrorKind}, }; -#[cfg(feature = "aws_lc_rs")] -use aws_lc_rs::{digest, signature as aws_sig}; -#[cfg(feature = "aws_lc_rs")] -use aws_sig::KeyPair; -#[cfg(feature = "rust_crypto")] -use p256::{ecdsa::SigningKey as P256SigningKey, pkcs8::DecodePrivateKey}; -#[cfg(feature = "rust_crypto")] -use p384::ecdsa::SigningKey as P384SigningKey; -#[cfg(feature = "rust_crypto")] -use rsa::{RsaPrivateKey, pkcs1::DecodeRsaPrivateKey, traits::PublicKeyParts}; -#[cfg(feature = "rust_crypto")] -use sha2::{Digest, Sha256, Sha384, Sha512}; - /// The intended usage of the public `KeyType`. This enum is serialized `untagged` #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum PublicKeyUse { @@ -439,103 +427,6 @@ pub struct Jwk { pub algorithm: AlgorithmParameters, } -#[cfg(feature = "aws_lc_rs")] -fn extract_rsa_public_key_components(key_content: &[u8]) -> errors::Result<(Vec, Vec)> { - let key_pair = aws_sig::RsaKeyPair::from_der(key_content) - .map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?; - let public = key_pair.public_key(); - let components = aws_sig::RsaPublicKeyComponents::>::from(public); - Ok((components.n, components.e)) -} - -#[cfg(feature = "rust_crypto")] -fn extract_rsa_public_key_components(key_content: &[u8]) -> errors::Result<(Vec, Vec)> { - let private_key = RsaPrivateKey::from_pkcs1_der(key_content) - .map_err(|e| ErrorKind::InvalidRsaKey(e.to_string()))?; - let public_key = private_key.to_public_key(); - Ok((public_key.n().to_bytes_be(), public_key.e().to_bytes_be())) -} - -#[cfg(feature = "aws_lc_rs")] -fn extract_ec_public_key_coordinates( - key_content: &[u8], - alg: Algorithm, -) -> errors::Result<(EllipticCurve, Vec, Vec)> { - use aws_lc_rs::signature::{ - ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED_SIGNING, EcdsaKeyPair, - }; - - let (signing_alg, curve, pub_elem_bytes) = match alg { - Algorithm::ES256 => (&ECDSA_P256_SHA256_FIXED_SIGNING, EllipticCurve::P256, 32), - Algorithm::ES384 => (&ECDSA_P384_SHA384_FIXED_SIGNING, EllipticCurve::P384, 48), - _ => return Err(ErrorKind::InvalidEcdsaKey.into()), - }; - - let key_pair = EcdsaKeyPair::from_pkcs8(signing_alg, key_content) - .map_err(|_| ErrorKind::InvalidEcdsaKey)?; - - let pub_bytes = key_pair.public_key().as_ref(); - if pub_bytes[0] != 4 { - return Err(ErrorKind::InvalidEcdsaKey.into()); - } - - let (x, y) = pub_bytes[1..].split_at(pub_elem_bytes); - Ok((curve, x.to_vec(), y.to_vec())) -} - -#[cfg(feature = "rust_crypto")] -fn extract_ec_public_key_coordinates( - key_content: &[u8], - alg: Algorithm, -) -> errors::Result<(EllipticCurve, Vec, Vec)> { - match alg { - Algorithm::ES256 => { - let signing_key = P256SigningKey::from_pkcs8_der(key_content) - .map_err(|_| ErrorKind::InvalidEcdsaKey)?; - let public_key = signing_key.verifying_key(); - let encoded = public_key.to_encoded_point(false); - match encoded.coordinates() { - p256::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => { - Ok((EllipticCurve::P256, x.to_vec(), y.to_vec())) - } - _ => Err(ErrorKind::InvalidEcdsaKey.into()), - } - } - Algorithm::ES384 => { - let signing_key = P384SigningKey::from_pkcs8_der(key_content) - .map_err(|_| ErrorKind::InvalidEcdsaKey)?; - let public_key = signing_key.verifying_key(); - let encoded = public_key.to_encoded_point(false); - match encoded.coordinates() { - p384::elliptic_curve::sec1::Coordinates::Uncompressed { x, y } => { - Ok((EllipticCurve::P384, x.to_vec(), y.to_vec())) - } - _ => Err(ErrorKind::InvalidEcdsaKey.into()), - } - } - _ => Err(ErrorKind::InvalidEcdsaKey.into()), - } -} - -#[cfg(feature = "aws_lc_rs")] -fn compute_digest(data: &[u8], hash_function: ThumbprintHash) -> Vec { - let algorithm = match hash_function { - ThumbprintHash::SHA256 => &digest::SHA256, - ThumbprintHash::SHA384 => &digest::SHA384, - ThumbprintHash::SHA512 => &digest::SHA512, - }; - digest::digest(algorithm, data).as_ref().to_vec() -} - -#[cfg(feature = "rust_crypto")] -fn compute_digest(data: &[u8], hash_function: ThumbprintHash) -> Vec { - match hash_function { - ThumbprintHash::SHA256 => Sha256::digest(data).to_vec(), - ThumbprintHash::SHA384 => Sha384::digest(data).to_vec(), - ThumbprintHash::SHA512 => Sha512::digest(data).to_vec(), - } -} - impl Jwk { /// Find whether the Algorithm is implemented and supported pub fn is_supported(&self) -> bool { @@ -563,15 +454,19 @@ impl Jwk { }), ..Default::default() }, - algorithm: match key.family { + algorithm: match key.family() { crate::algorithms::AlgorithmFamily::Hmac => { AlgorithmParameters::OctetKey(OctetKeyParameters { key_type: OctetKeyType::Octet, - value: b64_encode(&key.content), + value: b64_encode(key.inner()), }) } crate::algorithms::AlgorithmFamily::Rsa => { - let (n, e) = extract_rsa_public_key_components(&key.content)?; + let (n, e) = (CryptoProvider::get_default() + .jwk_utils + .extract_rsa_public_key_components)( + key.inner() + )?; AlgorithmParameters::RSA(RSAKeyParameters { key_type: RSAKeyType::RSA, n: b64_encode(n), @@ -579,7 +474,11 @@ impl Jwk { }) } crate::algorithms::AlgorithmFamily::Ec => { - let (curve, x, y) = extract_ec_public_key_coordinates(&key.content, alg)?; + let (curve, x, y) = (CryptoProvider::get_default() + .jwk_utils + .extract_ec_public_key_coordinates)( + key.inner(), alg + )?; AlgorithmParameters::EllipticCurve(EllipticCurveKeyParameters { key_type: EllipticCurveKeyType::EC, curve, @@ -640,7 +539,11 @@ impl Jwk { } }, }; - b64_encode(compute_digest(pre.as_bytes(), hash_function)) + + b64_encode((CryptoProvider::get_default().jwk_utils.compute_digest)( + pre.as_bytes(), + hash_function, + )) } } diff --git a/src/jws.rs b/src/jws.rs index 57dc02a2..057d3669 100644 --- a/src/jws.rs +++ b/src/jws.rs @@ -1,13 +1,13 @@ //! JSON Web Signatures data type. use std::marker::PhantomData; -use crate::crypto::sign; +use crate::crypto::{CryptoProvider, sign}; use crate::errors::{ErrorKind, Result, new_error}; use crate::serialization::{DecodedJwtPartClaims, b64_encode_part}; use crate::validation::validate; use crate::{DecodingKey, EncodingKey, Header, TokenData, Validation}; -use crate::decoding::{jwt_verifier_factory, verify_signature_body}; +use crate::decoding::verify_signature_body; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -39,7 +39,7 @@ pub fn encode( claims: Option<&T>, key: &EncodingKey, ) -> Result> { - if key.family != header.alg.family() { + if key.family() != header.alg.family() { return Err(new_error(ErrorKind::InvalidAlgorithm)); } let encoded_header = b64_encode_part(header)?; @@ -67,7 +67,7 @@ pub fn decode( let header = Header::from_encoded(&jws.protected)?; let message = [jws.protected.as_str(), jws.payload.as_str()].join("."); - let verifying_provider = jwt_verifier_factory(&header.alg, key)?; + let verifying_provider = (CryptoProvider::get_default().verifier_factory)(&header.alg, key)?; verify_signature_body( message.as_bytes(), jws.signature.as_bytes(), diff --git a/src/lib.rs b/src/lib.rs index 920b996b..2c8ff253 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,18 +5,11 @@ #![deny(missing_docs)] -#[cfg(all(feature = "rust_crypto", feature = "aws_lc_rs"))] -compile_error!( - "feature \"rust_crypto\" and feature \"aws_lc_rs\" cannot be enabled at the same time" -); - -#[cfg(not(any(feature = "rust_crypto", feature = "aws_lc_rs")))] -compile_error!("at least one of the features \"rust_crypto\" or \"aws_lc_rs\" must be enabled"); - -pub use algorithms::Algorithm; -pub use decoding::{DecodingKey, TokenData, decode, decode_header}; +pub use algorithms::{Algorithm, AlgorithmFamily}; +pub use decoding::{DecodingKey, DecodingKeyKind, TokenData, decode, decode_header}; pub use encoding::{EncodingKey, encode}; pub use header::Header; +pub use signature; pub use validation::{Validation, get_current_timestamp}; /// Dangerous decoding functions that should be audited and used with extreme care. diff --git a/src/validation.rs b/src/validation.rs index 96ae3ac7..fc7e9f71 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -200,10 +200,11 @@ pub(crate) struct ClaimsForValidation<'a> { aud: TryParse>, } -#[derive(Debug)] +#[derive(Default, Debug)] enum TryParse { Parsed(T), FailedToParse, + #[default] NotPresent, } @@ -219,12 +220,6 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for TryParse { } } -impl Default for TryParse { - fn default() -> Self { - Self::NotPresent - } -} - #[derive(Deserialize)] #[serde(untagged)] enum Audience<'a> {