diff --git a/Cargo.toml b/Cargo.toml index 4a9568e7..7be34952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,13 +40,16 @@ ed25519-dalek = { version = "2.1.1", optional = true, features = ["pkcs8"] } hmac = { version = "0.12.1", optional = true } p256 = { version = "0.13.2", optional = true, features = ["ecdsa"] } p384 = { version = "0.13.0", optional = true, features = ["ecdsa"] } -rand = { version = "0.8.5", optional = true, features = ["std"], default-features = false } -rsa = { version = "0.9.6", optional = true } +rand10 = { package = "rand", version = "0.10", optional = true, features = ["std", "thread_rng"], default-features = false } +rsa = { version = "0.10.0-rc.17", optional = true, features = ["sha2"] } sha2 = { version = "0.10.7", optional = true, features = ["oid"] } [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = "0.3" getrandom = "0.2" +# rand 0.10 pulls getrandom 0.4 on wasm; enable wasm_js there +# while keeping the existing wasm-pack CI feature invocation unchanged. +getrandom_04 = { package = "getrandom", version = "0.4", features = ["wasm_js"] } [dev-dependencies] wasm-bindgen-test = "0.3.1" @@ -66,7 +69,7 @@ criterion = { version = "0.8", default-features = false } [features] default = ["use_pem"] use_pem = ["pem", "simple_asn1"] -rust_crypto = ["ed25519-dalek", "hmac", "p256", "p384", "rand", "rsa", "sha2"] +rust_crypto = ["ed25519-dalek", "hmac", "p256", "p384", "rand10", "rsa", "sha2"] aws_lc_rs = ["aws-lc-rs"] [[bench]] diff --git a/src/crypto/rust_crypto/ecdsa.rs b/src/crypto/rust_crypto/ecdsa.rs index 9aad882e..eaef544e 100644 --- a/src/crypto/rust_crypto/ecdsa.rs +++ b/src/crypto/rust_crypto/ecdsa.rs @@ -8,10 +8,10 @@ use crate::{Algorithm, DecodingKey, EncodingKey}; use p256::ecdsa::{ Signature as Signature256, SigningKey as SigningKey256, VerifyingKey as VerifyingKey256, }; +use p256::pkcs8::DecodePrivateKey; use p384::ecdsa::{ Signature as Signature384, SigningKey as SigningKey384, VerifyingKey as VerifyingKey384, }; -use rsa::pkcs8::DecodePrivateKey; use signature::{Error, Signer, Verifier}; macro_rules! define_ecdsa_signer { diff --git a/src/crypto/rust_crypto/mod.rs b/src/crypto/rust_crypto/mod.rs index cd0c9bdc..09236863 100644 --- a/src/crypto/rust_crypto/mod.rs +++ b/src/crypto/rust_crypto/mod.rs @@ -15,11 +15,21 @@ mod eddsa; mod hmac; mod rsa; +fn trim_leading_zeroes(bytes: &[u8]) -> Vec { + match bytes.iter().position(|byte| *byte != 0) { + Some(first_non_zero) => bytes[first_non_zero..].to_vec(), + None => vec![0], + } +} + 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())) + Ok(( + trim_leading_zeroes(public_key.n().to_be_bytes().as_ref()), + trim_leading_zeroes(public_key.e().to_be_bytes().as_ref()), + )) } fn extract_ec_public_key_coordinates( diff --git a/src/crypto/rust_crypto/rsa.rs b/src/crypto/rust_crypto/rsa.rs index ba0af0fe..d569a315 100644 --- a/src/crypto/rust_crypto/rsa.rs +++ b/src/crypto/rust_crypto/rsa.rs @@ -1,17 +1,19 @@ //! Implementations of the [`JwtSigner`] and [`JwtVerifier`] traits for the //! RSA family of algorithms using RustCrypto. -use hmac::digest::FixedOutputReset; +// Use the hash types re-exported by `rsa` so this backend stays in the same +// digest ecosystem as the 0.10 RC line without a crate-wide sha2 migration. use rsa::{ - BigUint, Pkcs1v15Sign, Pss, RsaPublicKey, + BoxedUint, Pkcs1v15Sign, Pss, RsaPrivateKey, RsaPublicKey, pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, - pkcs1v15::SigningKey, pkcs8::AssociatedOid, - pss::BlindedSigningKey, + sha2::{ + Sha256, Sha384, Sha512, + digest::{Digest, FixedOutputReset}, + }, traits::SignatureScheme, }; -use sha2::{Digest, Sha256, Sha384, Sha512}; -use signature::{RandomizedSigner, SignatureEncoding, Signer, Verifier}; +use signature::{Signer, Verifier}; use crate::algorithms::AlgorithmFamily; use crate::crypto::{JwtSigner, JwtVerifier}; @@ -19,6 +21,12 @@ use crate::decoding::DecodingKeyKind; use crate::errors::{ErrorKind, Result, new_error}; use crate::{Algorithm, DecodingKey, EncodingKey}; +fn to_boxed_uint(bytes: &[u8]) -> std::result::Result { + let bits_precision = + u32::try_from(bytes.len().saturating_mul(8)).map_err(signature::Error::from_source)?; + BoxedUint::from_be_slice(bytes, bits_precision).map_err(signature::Error::from_source) +} + fn try_sign_rsa( encoding_key: &EncodingKey, msg: &[u8], @@ -27,21 +35,22 @@ fn try_sign_rsa( where H: Digest + AssociatedOid + FixedOutputReset, { - let mut rng = rand::thread_rng(); - if pss { - let private_key = rsa::RsaPrivateKey::from_pkcs1_der(encoding_key.inner()) - .map_err(signature::Error::from_source)?; - let signing_key = BlindedSigningKey::::new(private_key); - Ok(signing_key.sign_with_rng(&mut rng, msg).to_vec()) + let mut rng = rand10::rng(); + let private_key = RsaPrivateKey::from_pkcs1_der(encoding_key.inner()) + .map_err(signature::Error::from_source)?; + let digest = H::digest(msg); + + let signature = if pss { + private_key.sign_with_rng(&mut rng, Pss::::new(), digest.as_ref()) } else { - let private_key = rsa::RsaPrivateKey::from_pkcs1_der(encoding_key.inner()) - .map_err(signature::Error::from_source)?; - let signing_key = SigningKey::::new(private_key); - Ok(signing_key.sign_with_rng(&mut rng, msg).to_vec()) + private_key.sign_with_rng(&mut rng, Pkcs1v15Sign::new::(), digest.as_ref()) } + .map_err(signature::Error::from_source)?; + + Ok(signature) } -fn verify_rsa( +fn verify_rsa( scheme: S, decoding_key: &DecodingKey, msg: &[u8], @@ -53,12 +62,13 @@ fn verify_rsa( DecodingKeyKind::SecretOrDer(bytes) => { RsaPublicKey::from_pkcs1_der(bytes) .map_err(signature::Error::from_source)? - .verify(scheme, &digest, signature) + .verify(scheme, digest.as_ref(), signature) .map_err(signature::Error::from_source)?; } DecodingKeyKind::RsaModulusExponent { n, e } => { - RsaPublicKey::new(BigUint::from_bytes_be(n), BigUint::from_bytes_be(e))? - .verify(scheme, &digest, signature) + RsaPublicKey::new(to_boxed_uint(n)?, to_boxed_uint(e)?) + .map_err(signature::Error::from_source)? + .verify(scheme, digest.as_ref(), signature) .map_err(signature::Error::from_source)?; } }; @@ -115,7 +125,7 @@ macro_rules! define_rsa_verifier { signature: &Vec, ) -> std::result::Result<(), signature::Error> { if $pss { - verify_rsa::(Pss::new::<$hash>(), &self.0, msg, signature) + verify_rsa::<_, $hash>(Pss::<$hash>::new(), &self.0, msg, signature) } else { verify_rsa::<_, $hash>(Pkcs1v15Sign::new::<$hash>(), &self.0, msg, signature) }