diff --git a/CHANGELOG.md b/CHANGELOG.md index fbd56675..65f1310f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- Breaking: Add lifetimes to `EncodingKey` and `DecodingKey`/`DecodingKeyKind` + ## 10.3.0 (2026-01-27) - Export everything needed to define your own CryptoProvider @@ -72,7 +76,7 @@ ## 8.0.0 (2022-02-02) - + - Add EdDSA algorithm - `sign`/`verify` now takes a `&[u8]` instead of `&str` to be more flexible - `DecodingKey` now own its data @@ -109,7 +113,7 @@ - Add support for PS256, PS384 and PS512 - Add support for verifying with modulus/exponent components for RSA - Update to 2018 edition -- Changed aud field type in Validation to `Option>`. Audience +- Changed aud field type in Validation to `Option>`. Audience validation now tests for "any-of-these" audience membership. - Add support for keys in PEM format - Add EncodingKey/DecodingKey API to improve performance and UX diff --git a/src/crypto/aws_lc/ecdsa.rs b/src/crypto/aws_lc/ecdsa.rs index 5a5b364e..d8395dee 100644 --- a/src/crypto/aws_lc/ecdsa.rs +++ b/src/crypto/aws_lc/ecdsa.rs @@ -17,7 +17,7 @@ macro_rules! define_ecdsa_signer { pub struct $name(EcdsaKeyPair); impl $name { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { if encoding_key.family() != AlgorithmFamily::Ec { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -50,7 +50,7 @@ macro_rules! define_ecdsa_verifier { pub struct $name(DecodingKey); impl $name { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { 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 085bf7c3..fdc7c1b5 100644 --- a/src/crypto/aws_lc/eddsa.rs +++ b/src/crypto/aws_lc/eddsa.rs @@ -10,7 +10,7 @@ use signature::{Error, Signer, Verifier}; pub struct EdDSASigner(Ed25519KeyPair); impl EdDSASigner { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { if encoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -37,7 +37,7 @@ impl JwtSigner for EdDSASigner { pub struct EdDSAVerifier(DecodingKey); impl EdDSAVerifier { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { if decoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/aws_lc/hmac.rs b/src/crypto/aws_lc/hmac.rs index 2997e491..f0cc0f34 100644 --- a/src/crypto/aws_lc/hmac.rs +++ b/src/crypto/aws_lc/hmac.rs @@ -13,7 +13,7 @@ macro_rules! define_hmac_signer { pub struct $name(hmac::Key); impl $name { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { Ok(Self(hmac::Key::new($hmac_alg, encoding_key.try_get_hmac_secret()?))) } } @@ -37,7 +37,7 @@ macro_rules! define_hmac_verifier { pub struct $name(hmac::Key); impl $name { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { Ok(Self(hmac::Key::new($hmac_alg, decoding_key.try_get_hmac_secret()?))) } } diff --git a/src/crypto/aws_lc/mod.rs b/src/crypto/aws_lc/mod.rs index 76f8a2c3..1badf836 100644 --- a/src/crypto/aws_lc/mod.rs +++ b/src/crypto/aws_lc/mod.rs @@ -57,7 +57,7 @@ fn compute_digest(data: &[u8], hash_function: ThumbprintHash) -> Vec { digest::digest(algorithm, data).as_ref().to_vec() } -fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result, Error> { +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, @@ -78,7 +78,7 @@ fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result, ) -> Result, Error> { let jwt_verifier = match algorithm { Algorithm::HS256 => Box::new(hmac::Hs256Verifier::new(key)?) as Box, diff --git a/src/crypto/aws_lc/rsa.rs b/src/crypto/aws_lc/rsa.rs index d72b0680..edff89dc 100644 --- a/src/crypto/aws_lc/rsa.rs +++ b/src/crypto/aws_lc/rsa.rs @@ -13,7 +13,7 @@ use crate::{Algorithm, DecodingKey, EncodingKey}; /// Try to sign the `message` using an `RSA` `algorithm`. fn try_sign_rsa( algorithm: &'static dyn crypto_sig::RsaEncoding, - encoding_key: &EncodingKey, + encoding_key: &EncodingKey<'_>, msg: &[u8], ) -> std::result::Result, signature::Error> { let key_pair = crypto_sig::RsaKeyPair::from_der(encoding_key.inner()) @@ -33,7 +33,7 @@ fn try_sign_rsa( /// - If `decoding_key` is not from the RSA family. fn verify_rsa( algorithm: &'static crypto_sig::RsaParameters, - decoding_key: &DecodingKey, + decoding_key: &DecodingKey<'_>, msg: &[u8], signature: &[u8], ) -> std::result::Result<(), signature::Error> { @@ -56,7 +56,7 @@ macro_rules! define_rsa_signer { pub struct $name(EncodingKey); impl $name { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { if encoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -84,7 +84,7 @@ macro_rules! define_rsa_verifier { pub struct $name(DecodingKey); impl $name { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { 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 2be728b1..36c9499f 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -45,7 +45,7 @@ pub trait JwtVerifier: Verifier> { /// the base64 url safe encoded of the result. /// /// If you just want to encode a JWT, use `encode` instead. -pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result { +pub fn sign(message: &[u8], key: &EncodingKey<'_>, algorithm: Algorithm) -> Result { let provider = (CryptoProvider::get_default().signer_factory)(&algorithm, key)?; Ok(b64_encode(provider.try_sign(message)?)) } @@ -61,7 +61,7 @@ pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result, algorithm: Algorithm, ) -> Result { let provider = (CryptoProvider::get_default().verifier_factory)(&algorithm, key)?; diff --git a/src/crypto/rust_crypto/ecdsa.rs b/src/crypto/rust_crypto/ecdsa.rs index 9aad882e..54fc919a 100644 --- a/src/crypto/rust_crypto/ecdsa.rs +++ b/src/crypto/rust_crypto/ecdsa.rs @@ -19,7 +19,7 @@ macro_rules! define_ecdsa_signer { pub struct $name($signing_key); impl $name { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { if encoding_key.family() != AlgorithmFamily::Ec { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -51,7 +51,7 @@ macro_rules! define_ecdsa_verifier { pub struct $name($verifying_key); impl $name { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { 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 9b77a9f8..2e50eeed 100644 --- a/src/crypto/rust_crypto/eddsa.rs +++ b/src/crypto/rust_crypto/eddsa.rs @@ -11,7 +11,7 @@ use signature::{Error, Signer, Verifier}; pub struct EdDSASigner(SigningKey); impl EdDSASigner { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { if encoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -38,7 +38,7 @@ impl JwtSigner for EdDSASigner { pub struct EdDSAVerifier(VerifyingKey); impl EdDSAVerifier { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { if decoding_key.family() != AlgorithmFamily::Ed { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/crypto/rust_crypto/hmac.rs b/src/crypto/rust_crypto/hmac.rs index 2dc034b1..0117d96c 100644 --- a/src/crypto/rust_crypto/hmac.rs +++ b/src/crypto/rust_crypto/hmac.rs @@ -19,7 +19,7 @@ macro_rules! define_hmac_signer { pub struct $name($hmac_type); impl $name { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { let inner = <$hmac_type>::new_from_slice(encoding_key.try_get_hmac_secret()?) .map_err(|_e| crate::errors::ErrorKind::InvalidKeyFormat)?; @@ -51,7 +51,7 @@ macro_rules! define_hmac_verifier { pub struct $name($hmac_type); impl $name { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { let inner = <$hmac_type>::new_from_slice(decoding_key.try_get_hmac_secret()?) .map_err(|_e| crate::errors::ErrorKind::InvalidKeyFormat)?; diff --git a/src/crypto/rust_crypto/mod.rs b/src/crypto/rust_crypto/mod.rs index cd0c9bdc..77dbdf42 100644 --- a/src/crypto/rust_crypto/mod.rs +++ b/src/crypto/rust_crypto/mod.rs @@ -63,7 +63,7 @@ fn compute_digest(data: &[u8], hash_function: ThumbprintHash) -> Vec { } } -fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result, Error> { +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, @@ -84,7 +84,7 @@ fn new_signer(algorithm: &Algorithm, key: &EncodingKey) -> Result, ) -> Result, Error> { let jwt_verifier = match algorithm { Algorithm::HS256 => Box::new(hmac::Hs256Verifier::new(key)?) as Box, diff --git a/src/crypto/rust_crypto/rsa.rs b/src/crypto/rust_crypto/rsa.rs index ba0af0fe..61a6f8d4 100644 --- a/src/crypto/rust_crypto/rsa.rs +++ b/src/crypto/rust_crypto/rsa.rs @@ -20,7 +20,7 @@ use crate::errors::{ErrorKind, Result, new_error}; use crate::{Algorithm, DecodingKey, EncodingKey}; fn try_sign_rsa( - encoding_key: &EncodingKey, + encoding_key: &EncodingKey<'_>, msg: &[u8], pss: bool, ) -> std::result::Result, signature::Error> @@ -43,7 +43,7 @@ where fn verify_rsa( scheme: S, - decoding_key: &DecodingKey, + decoding_key: &DecodingKey<'_>, msg: &[u8], signature: &[u8], ) -> std::result::Result<(), signature::Error> { @@ -71,7 +71,7 @@ macro_rules! define_rsa_signer { pub struct $name(EncodingKey); impl $name { - pub(crate) fn new(encoding_key: &EncodingKey) -> Result { + pub(crate) fn new(encoding_key: &EncodingKey<'_>) -> Result { if encoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } @@ -99,7 +99,7 @@ macro_rules! define_rsa_verifier { pub struct $name(DecodingKey); impl $name { - pub(crate) fn new(decoding_key: &DecodingKey) -> Result { + pub(crate) fn new(decoding_key: &DecodingKey<'_>) -> Result { if decoding_key.family() != AlgorithmFamily::Rsa { return Err(new_error(ErrorKind::InvalidKeyFormat)); } diff --git a/src/decoding.rs b/src/decoding.rs index 216138f3..144283ec 100644 --- a/src/decoding.rs +++ b/src/decoding.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::fmt::{Debug, Formatter}; use base64::{Engine, engine::general_purpose::STANDARD}; @@ -45,9 +46,9 @@ macro_rules! expect_two { #[derive(Clone)] /// Different kinds of decoding keys. -pub enum DecodingKeyKind { +pub enum DecodingKeyKind<'a> { /// A raw public key. - SecretOrDer(Vec), + SecretOrDer(Cow<'a, [u8]>), /// RSA public key components. RsaModulusExponent { /// The modulus of the public key. @@ -57,7 +58,7 @@ pub enum DecodingKeyKind { }, } -impl Debug for DecodingKeyKind { +impl Debug for DecodingKeyKind<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::SecretOrDer(_) => f.debug_tuple("SecretOrDer").field(&"[redacted]").finish(), @@ -73,50 +74,45 @@ impl Debug for DecodingKeyKind { /// All the different kind of keys we can use to decode a JWT. /// 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 struct DecodingKey<'a> { family: AlgorithmFamily, - kind: DecodingKeyKind, + kind: DecodingKeyKind<'a>, } -impl DecodingKey { +impl DecodingKey<'_> { /// The algorithm family this key is for. pub fn family(&self) -> AlgorithmFamily { self.family } /// The kind of decoding key. - pub fn kind(&self) -> &DecodingKeyKind { + pub fn kind(&self) -> &DecodingKeyKind<'_> { &self.kind } - /// If you're using HMAC, use this. - pub fn from_secret(secret: &[u8]) -> Self { - DecodingKey { - family: AlgorithmFamily::Hmac, - kind: DecodingKeyKind::SecretOrDer(secret.to_vec()), - } - } - /// If you're using HMAC with a base64 encoded secret, use this. - pub fn from_base64_secret(secret: &str) -> Result { + pub fn from_base64_secret(secret: &str) -> Result> { let out = STANDARD.decode(secret)?; - Ok(DecodingKey { family: AlgorithmFamily::Hmac, kind: DecodingKeyKind::SecretOrDer(out) }) + Ok(DecodingKey { + family: AlgorithmFamily::Hmac, + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(out)), + }) } /// If you are loading a public RSA key in a PEM format, use this. /// Only exists if the feature `use_pem` is enabled. #[cfg(feature = "use_pem")] - pub fn from_rsa_pem(key: &[u8]) -> Result { + pub fn from_rsa_pem(key: &[u8]) -> Result> { let pem_key = PemEncodedKey::new(key)?; let content = pem_key.as_rsa_key()?; Ok(DecodingKey { family: AlgorithmFamily::Rsa, - kind: DecodingKeyKind::SecretOrDer(content.to_vec()), + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())), }) } /// If you have (n, e) RSA public key components as strings, use this. - pub fn from_rsa_components(modulus: &str, exponent: &str) -> Result { + pub fn from_rsa_components(modulus: &str, exponent: &str) -> Result> { let n = b64_decode(modulus)?; let e = b64_decode(exponent)?; Ok(DecodingKey { @@ -126,7 +122,7 @@ impl DecodingKey { } /// If you have (n, e) RSA public key components already decoded, use this. - pub fn from_rsa_raw_components(modulus: &[u8], exponent: &[u8]) -> Self { + pub fn from_rsa_raw_components(modulus: &[u8], exponent: &[u8]) -> DecodingKey<'static> { DecodingKey { family: AlgorithmFamily::Rsa, kind: DecodingKeyKind::RsaModulusExponent { n: modulus.to_vec(), e: exponent.to_vec() }, @@ -136,17 +132,17 @@ impl DecodingKey { /// If you have a ECDSA public key in PEM format, use this. /// Only exists if the feature `use_pem` is enabled. #[cfg(feature = "use_pem")] - pub fn from_ec_pem(key: &[u8]) -> Result { + pub fn from_ec_pem(key: &[u8]) -> Result> { let pem_key = PemEncodedKey::new(key)?; let content = pem_key.as_ec_public_key()?; Ok(DecodingKey { family: AlgorithmFamily::Ec, - kind: DecodingKeyKind::SecretOrDer(content.to_vec()), + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())), }) } /// If you have (x,y) ECDSA key components - pub fn from_ec_components(x: &str, y: &str) -> Result { + pub fn from_ec_components(x: &str, y: &str) -> Result> { let x_cmp = b64_decode(x)?; let y_cmp = b64_decode(y)?; @@ -157,57 +153,33 @@ impl DecodingKey { Ok(DecodingKey { family: AlgorithmFamily::Ec, - kind: DecodingKeyKind::SecretOrDer(public_key), + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(public_key)), }) } /// If you have a EdDSA public key in PEM format, use this. /// Only exists if the feature `use_pem` is enabled. #[cfg(feature = "use_pem")] - pub fn from_ed_pem(key: &[u8]) -> Result { + pub fn from_ed_pem(key: &[u8]) -> Result> { let pem_key = PemEncodedKey::new(key)?; let content = pem_key.as_ed_public_key()?; Ok(DecodingKey { family: AlgorithmFamily::Ed, - kind: DecodingKeyKind::SecretOrDer(content.to_vec()), + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(content.to_vec())), }) } - /// If you know what you're doing and have a RSA DER encoded public key, use this. - pub fn from_rsa_der(der: &[u8]) -> Self { - DecodingKey { - family: AlgorithmFamily::Rsa, - kind: DecodingKeyKind::SecretOrDer(der.to_vec()), - } - } - - /// If you know what you're doing and have a RSA EC encoded public key, use this. - pub fn from_ec_der(der: &[u8]) -> Self { - DecodingKey { - family: AlgorithmFamily::Ec, - kind: DecodingKeyKind::SecretOrDer(der.to_vec()), - } - } - - /// If you know what you're doing and have a Ed DER encoded public key, use this. - pub fn from_ed_der(der: &[u8]) -> Self { - DecodingKey { - family: AlgorithmFamily::Ed, - kind: DecodingKeyKind::SecretOrDer(der.to_vec()), - } - } - /// From x part (base64 encoded) of the JWK encoding - pub fn from_ed_components(x: &str) -> Result { + pub fn from_ed_components(x: &str) -> Result> { let x_decoded = b64_decode(x)?; Ok(DecodingKey { family: AlgorithmFamily::Ed, - kind: DecodingKeyKind::SecretOrDer(x_decoded), + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(x_decoded)), }) } /// If you have a key in Jwk format - pub fn from_jwk(jwk: &Jwk) -> Result { + pub fn from_jwk(jwk: &Jwk) -> Result> { match &jwk.algorithm { AlgorithmParameters::RSA(params) => { DecodingKey::from_rsa_components(¶ms.n, ¶ms.e) @@ -220,7 +192,7 @@ impl DecodingKey { let out = b64_decode(¶ms.value)?; Ok(DecodingKey { family: AlgorithmFamily::Hmac, - kind: DecodingKeyKind::SecretOrDer(out), + kind: DecodingKeyKind::SecretOrDer(Cow::Owned(out)), }) } } @@ -244,7 +216,41 @@ impl DecodingKey { } } -impl TryFrom<&Jwk> for DecodingKey { +impl<'a> DecodingKey<'a> { + /// If you're using HMAC, use this. + pub fn from_secret(secret: &'a [u8]) -> Self { + DecodingKey { + family: AlgorithmFamily::Hmac, + kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(secret)), + } + } + + /// If you know what you're doing and have a RSA DER encoded public key, use this. + pub fn from_rsa_der(der: &'a [u8]) -> Self { + DecodingKey { + family: AlgorithmFamily::Rsa, + kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)), + } + } + + /// If you know what you're doing and have a RSA EC encoded public key, use this. + pub fn from_ec_der(der: &'a [u8]) -> Self { + DecodingKey { + family: AlgorithmFamily::Ec, + kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)), + } + } + + /// If you know what you're doing and have a Ed DER encoded public key, use this. + pub fn from_ed_der(der: &'a [u8]) -> Self { + DecodingKey { + family: AlgorithmFamily::Ed, + kind: DecodingKeyKind::SecretOrDer(Cow::Borrowed(der)), + } + } +} + +impl TryFrom<&Jwk> for DecodingKey<'static> { type Error = crate::errors::Error; fn try_from(jwk: &Jwk) -> Result { @@ -272,7 +278,7 @@ impl TryFrom<&Jwk> for DecodingKey { /// ``` pub fn decode( token: impl AsRef<[u8]>, - key: &DecodingKey, + key: &DecodingKey<'_>, validation: &Validation, ) -> Result> { let token = token.as_ref(); diff --git a/src/encoding.rs b/src/encoding.rs index dd512fd1..9df746a6 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -1,4 +1,7 @@ -use std::fmt::{Debug, Formatter}; +use std::{ + borrow::Cow, + fmt::{Debug, Formatter}, +}; use base64::{ Engine, @@ -17,32 +20,27 @@ use crate::serialization::{b64_encode, b64_encode_part}; /// 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 struct EncodingKey<'a> { family: AlgorithmFamily, - content: Vec, + content: Cow<'a, [u8]>, } -impl EncodingKey { +impl EncodingKey<'_> { /// The algorithm family this key is for. pub fn family(&self) -> AlgorithmFamily { self.family } - /// If you're using a HMAC secret that is not base64, use that. - pub fn from_secret(secret: &[u8]) -> Self { - EncodingKey { family: AlgorithmFamily::Hmac, content: secret.to_vec() } - } - /// If you have a base64 HMAC secret, use that. - pub fn from_base64_secret(secret: &str) -> Result { + pub fn from_base64_secret(secret: &str) -> Result> { let out = STANDARD.decode(secret)?; - Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: out }) + Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: Cow::Owned(out) }) } /// For loading websafe base64 HMAC secrets, ex: ACME EAB credentials. - pub fn from_urlsafe_base64_secret(secret: &str) -> Result { + pub fn from_urlsafe_base64_secret(secret: &str) -> Result> { let out = URL_SAFE.decode(secret)?; - Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: out }) + Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: Cow::Owned(out) }) } /// If you are loading a RSA key from a .pem file. @@ -55,10 +53,10 @@ impl EncodingKey { /// the key should be at least 2047 bits. /// #[cfg(feature = "use_pem")] - pub fn from_rsa_pem(key: &[u8]) -> Result { + pub fn from_rsa_pem(key: &[u8]) -> Result> { let pem_key = PemEncodedKey::new(key)?; let content = pem_key.as_rsa_key()?; - Ok(EncodingKey { family: AlgorithmFamily::Rsa, content: content.to_vec() }) + Ok(EncodingKey { family: AlgorithmFamily::Rsa, content: Cow::Owned(content.to_vec()) }) } /// If you are loading a ECDSA key from a .pem file @@ -76,35 +74,20 @@ impl EncodingKey { /// | openssl pkcs8 -topk8 -nocrypt -out ec-private.pem /// ``` #[cfg(feature = "use_pem")] - pub fn from_ec_pem(key: &[u8]) -> Result { + pub fn from_ec_pem(key: &[u8]) -> Result> { let pem_key = PemEncodedKey::new(key)?; let content = pem_key.as_ec_private_key()?; - Ok(EncodingKey { family: AlgorithmFamily::Ec, content: content.to_vec() }) + Ok(EncodingKey { family: AlgorithmFamily::Ec, content: Cow::Owned(content.to_vec()) }) } /// If you are loading a EdDSA key from a .pem file /// This errors if the key is not a valid private Ed key /// Only exists if the feature `use_pem` is enabled. #[cfg(feature = "use_pem")] - pub fn from_ed_pem(key: &[u8]) -> Result { + pub fn from_ed_pem(key: &[u8]) -> Result> { let pem_key = PemEncodedKey::new(key)?; let content = pem_key.as_ed_private_key()?; - Ok(EncodingKey { family: AlgorithmFamily::Ed, content: content.to_vec() }) - } - - /// If you know what you're doing and have the DER-encoded key, for RSA only - pub fn from_rsa_der(der: &[u8]) -> Self { - EncodingKey { family: AlgorithmFamily::Rsa, content: der.to_vec() } - } - - /// If you know what you're doing and have the DER-encoded key, for ECDSA - pub fn from_ec_der(der: &[u8]) -> Self { - EncodingKey { family: AlgorithmFamily::Ec, content: der.to_vec() } - } - - /// If you know what you're doing and have the DER-encoded key, for EdDSA - pub fn from_ed_der(der: &[u8]) -> Self { - EncodingKey { family: AlgorithmFamily::Ed, content: der.to_vec() } + Ok(EncodingKey { family: AlgorithmFamily::Ed, content: Cow::Owned(content.to_vec()) }) } /// Get the value of the key. @@ -122,7 +105,29 @@ impl EncodingKey { } } -impl Debug for EncodingKey { +impl<'a> EncodingKey<'a> { + /// If you're using a HMAC secret that is not base64, use that. + pub fn from_secret(secret: &'a [u8]) -> Self { + EncodingKey { family: AlgorithmFamily::Hmac, content: Cow::Borrowed(secret) } + } + + /// If you know what you're doing and have the DER-encoded key, for RSA only + pub fn from_rsa_der(der: &'a [u8]) -> Self { + EncodingKey { family: AlgorithmFamily::Rsa, content: Cow::Borrowed(der) } + } + + /// If you know what you're doing and have the DER-encoded key, for ECDSA + pub fn from_ec_der(der: &'a [u8]) -> Self { + EncodingKey { family: AlgorithmFamily::Ec, content: Cow::Borrowed(der) } + } + + /// If you know what you're doing and have the DER-encoded key, for EdDSA + pub fn from_ed_der(der: &'a [u8]) -> Self { + EncodingKey { family: AlgorithmFamily::Ed, content: Cow::Borrowed(der) } + } +} + +impl Debug for EncodingKey<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("EncodingKey") .field("family", &self.family) @@ -153,7 +158,7 @@ impl Debug for EncodingKey { /// // This will create a JWT using HS256 as algorithm /// let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref())).unwrap(); /// ``` -pub fn encode(header: &Header, claims: &T, key: &EncodingKey) -> Result { +pub fn encode(header: &Header, claims: &T, key: &EncodingKey<'_>) -> Result { if key.family != header.alg.family() { return Err(new_error(ErrorKind::InvalidAlgorithm)); } diff --git a/src/jwk.rs b/src/jwk.rs index a6ab15cc..ae36e776 100644 --- a/src/jwk.rs +++ b/src/jwk.rs @@ -435,7 +435,7 @@ impl Jwk { _ => false, } } - pub fn from_encoding_key(key: &EncodingKey, alg: Algorithm) -> crate::errors::Result { + pub fn from_encoding_key(key: &EncodingKey<'_>, alg: Algorithm) -> crate::errors::Result { Ok(Self { common: CommonParameters { key_algorithm: Some(match alg { diff --git a/src/jws.rs b/src/jws.rs index 057d3669..e46ab9d0 100644 --- a/src/jws.rs +++ b/src/jws.rs @@ -37,7 +37,7 @@ pub struct Jws { pub fn encode( header: &Header, claims: Option<&T>, - key: &EncodingKey, + key: &EncodingKey<'_>, ) -> Result> { if key.family() != header.alg.family() { return Err(new_error(ErrorKind::InvalidAlgorithm)); @@ -61,7 +61,7 @@ pub fn encode( /// Validate a received JWS and decode into the header and claims. pub fn decode( jws: &Jws, - key: &DecodingKey, + key: &DecodingKey<'_>, validation: &Validation, ) -> Result> { let header = Header::from_encoded(&jws.protected)?;