use crate::algorithms::Algorithm;
use crate::errors::Result;
use crate::jwk::{EllipticCurve, ThumbprintHash};
use crate::{DecodingKey, EncodingKey};
#[cfg(feature = "aws_lc_rs")]
pub mod aws_lc;
#[cfg(feature = "rust_crypto")]
pub mod rust_crypto;
use crate::serialization::{b64_decode, b64_encode};
use signature::{Signer, Verifier};
pub trait JwtSigner: Signer<Vec<u8>> {
fn algorithm(&self) -> Algorithm;
}
pub trait JwtVerifier: Verifier<Vec<u8>> {
fn algorithm(&self) -> Algorithm;
}
pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
let provider = (CryptoProvider::get_default().signer_factory)(&algorithm, key)?;
Ok(b64_encode(provider.try_sign(message)?))
}
pub fn verify(
signature: &str,
message: &[u8],
key: &DecodingKey,
algorithm: Algorithm,
) -> Result<bool> {
let provider = (CryptoProvider::get_default().verifier_factory)(&algorithm, key)?;
Ok(provider.verify(message, &b64_decode(signature)?).is_ok())
}
#[derive(Clone, Debug)]
pub struct CryptoProvider {
pub signer_factory: fn(&Algorithm, &EncodingKey) -> Result<Box<dyn JwtSigner>>,
pub verifier_factory: fn(&Algorithm, &DecodingKey) -> Result<Box<dyn JwtVerifier>>,
pub jwk_utils: JwkUtils,
}
impl CryptoProvider {
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
}
}
}
#[derive(Clone, Debug)]
pub struct JwkUtils {
#[allow(clippy::type_complexity)]
pub extract_rsa_public_key_components: fn(&[u8]) -> Result<(Vec<u8>, Vec<u8>)>,
#[allow(clippy::type_complexity)]
pub extract_ec_public_key_coordinates:
fn(&[u8], Algorithm) -> Result<(EllipticCurve, Vec<u8>, Vec<u8>)>,
pub compute_digest: fn(&[u8], ThumbprintHash) -> Vec<u8>,
}
impl JwkUtils {
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)
}
}