diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs index c174bf5d5ac..95f57d81bd5 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -33,16 +33,23 @@ RSA PKCS#1 v1.5 signing/verifying fits cleanly into `no_std` without `alloc`: Signing and verifying delegate to `wc_SignatureGenerate` and `wc_SignatureVerify` with `WC_SIGNATURE_TYPE_RSA_W_ENC`, which hash the raw message and apply the PKCS#1 v1.5 DigestInfo encoding internally. + +[`SigningKey`] requires the `random` cfg because signing needs an RNG. +[`VerifyingKey`] and [`Signature`] are available without it, so +verify-only builds do not have to pull in a random number generator. */ -#![cfg(all(feature = "signature", rsa, random))] +#![cfg(all(feature = "signature", rsa))] use core::ffi::c_void; use core::marker::PhantomData; use core::mem::size_of; -use signature::{Error, Keypair, SignatureEncoding, SignerMut, Verifier}; +use signature::{Error, SignatureEncoding, Verifier}; +#[cfg(random)] +use signature::{Keypair, SignerMut}; +#[cfg(random)] use crate::random::RNG; use crate::rsa::RSA; use crate::sys; @@ -140,12 +147,17 @@ fn check_modulus_size(rsa: &RSA, expected: usize) -> Result<(), i32> { /// /// `H` selects the hash used in DigestInfo encoding; `N` is the expected /// modulus size in bytes (e.g. `256` for RSA-2048, `384` for RSA-3072). +/// +/// Requires the `random` cfg: PKCS#1 v1.5 signing needs an RNG for +/// blinding. +#[cfg(random)] pub struct SigningKey { inner: RSA, rng: RNG, _hash: PhantomData, } +#[cfg(random)] impl SigningKey { /// Generate a fresh `N * 8`-bit RSA key with public exponent 65537. #[cfg(rsa_keygen)] @@ -173,6 +185,7 @@ impl SigningKey { } } +#[cfg(random)] impl SignerMut> for SigningKey { fn try_sign(&mut self, msg: &[u8]) -> Result, Error> { let mut sig = [0u8; N]; @@ -327,6 +340,7 @@ impl Verifier> for VerifyingKey { } } +#[cfg(random)] impl Keypair for SigningKey { type VerifyingKey = VerifyingKey; fn verifying_key(&self) -> VerifyingKey { diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs index 09f14ed0168..79447632661 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs @@ -1,12 +1,15 @@ -#![cfg(all(feature = "signature", rsa, random))] +#![cfg(all(feature = "signature", rsa))] mod common; -use signature::{Keypair, SignerMut, Verifier}; +use signature::Verifier; +#[cfg(random)] +use signature::{Keypair, SignerMut}; +#[cfg(random)] use wolfssl_wolfcrypt::random::RNG; #[test] -#[cfg(all(sha256, rsa_keygen))] +#[cfg(all(sha256, rsa_keygen, random))] fn test_rsa2048_sha256_sign_verify() { use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha256, Signature, SigningKey, VerifyingKey}; @@ -44,7 +47,7 @@ fn test_rsa2048_sha256_sign_verify() { } #[test] -#[cfg(all(sha384, rsa_keygen))] +#[cfg(all(sha384, rsa_keygen, random))] fn test_rsa3072_sha384_sign_verify() { use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha384, Signature, SigningKey, VerifyingKey}; @@ -66,7 +69,7 @@ fn test_rsa3072_sha384_sign_verify() { } #[test] -#[cfg(all(sha256, rsa_keygen))] +#[cfg(all(sha256, rsa_keygen, random))] fn test_modulus_size_mismatch_rejected() { use wolfssl_wolfcrypt::rsa::RSA; use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha256, SigningKey}; @@ -79,3 +82,27 @@ fn test_modulus_size_mismatch_rejected() { let result: Result, _> = SigningKey::from_rsa(rsa2048, rng); assert!(result.is_err(), "modulus size mismatch must be rejected"); } + +/// VerifyingKey must be usable in builds without the `random` cfg, so this +/// test deliberately avoids any RNG. +#[test] +#[cfg(all(sha256, feature = "alloc"))] +fn test_verifying_key_without_rng() { + extern crate std; + use std::fs; + use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha256, Signature, VerifyingKey}; + + common::setup(); + + let der = fs::read("../../../certs/client-keyPub.der").expect("read public key"); + let vk = VerifyingKey::::from_public_der(&der).expect("from_public_der"); + + // Round-trip through the raw components. + let vk_copy = VerifyingKey::::from_components(vk.modulus(), vk.exponent()) + .expect("from_components"); + assert_eq!(vk, vk_copy); + + // A garbage signature must not verify. + let bogus = Signature::<256>::from_bytes([0xA5u8; 256]); + assert!(vk.verify(b"message", &bogus).is_err()); +}