From f875f63b8c277a1dca46552a27899686381d0a86 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 15:46:57 +0100 Subject: [PATCH 01/10] expand SecureRandom to catch all type of Failures/Errors, and not only WcError:Failure --- rustls-wolfcrypt-provider/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/lib.rs b/rustls-wolfcrypt-provider/src/lib.rs index 3c5aa8b..aa6c592 100644 --- a/rustls-wolfcrypt-provider/src/lib.rs +++ b/rustls-wolfcrypt-provider/src/lib.rs @@ -77,10 +77,9 @@ struct Provider; impl rustls::crypto::SecureRandom for Provider { fn fill(&self, bytes: &mut [u8]) -> Result<(), rustls::crypto::GetRandomFailed> { - if let Err(error::WCError::Failure) = random::wolfcrypt_random_buffer_generator(bytes) { - Err(rustls::crypto::GetRandomFailed) - } else { - Ok(()) + match random::wolfcrypt_random_buffer_generator(bytes) { + Ok(()) => Ok(()), + Err(_) => Err(rustls::crypto::GetRandomFailed), } } } From a18d5b1eed83d2d660ac5cf5946ddd501c29858c Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 15:51:01 +0100 Subject: [PATCH 02/10] added lenght validation in x25519 matching pattern that is present in the nist curves files when doing the kx --- rustls-wolfcrypt-provider/src/kx/x25519.rs | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/kx/x25519.rs b/rustls-wolfcrypt-provider/src/kx/x25519.rs index b5ce310..e65293f 100644 --- a/rustls-wolfcrypt-provider/src/kx/x25519.rs +++ b/rustls-wolfcrypt-provider/src/kx/x25519.rs @@ -53,7 +53,13 @@ impl KeyExchangeX25519 { } } - pub fn derive_shared_secret(&self, peer_pub_key: &[u8]) -> Box<[u8]> { + pub fn derive_shared_secret(&self, peer_pub_key: &[u8]) -> Result, rustls::Error> { + if peer_pub_key.len() != 32 { + return Err(rustls::Error::General( + "Invalid peer public key length".into(), + )); + } + let mut ret; let endian: u32 = EC25519_LITTLE_ENDIAN; let mut pub_key_provided: curve25519_key = unsafe { mem::zeroed() }; @@ -66,7 +72,11 @@ impl KeyExchangeX25519 { // This function checks that a public key buffer holds a valid // Curve25519 key value given the endian ordering. ret = unsafe { - wc_curve25519_check_public(peer_pub_key.as_ptr(), 32, endian.try_into().unwrap()) + wc_curve25519_check_public( + peer_pub_key.as_ptr(), + peer_pub_key.len() as word32, + endian.try_into().unwrap(), + ) }; check_if_zero(ret).unwrap(); @@ -78,7 +88,7 @@ impl KeyExchangeX25519 { ret = unsafe { wc_curve25519_import_public_ex( peer_pub_key.as_ptr(), - 32, + peer_pub_key.len() as word32, &mut pub_key_provided, endian.try_into().unwrap(), ) @@ -93,7 +103,7 @@ impl KeyExchangeX25519 { ret = unsafe { wc_curve25519_import_private_ex( self.priv_key_bytes.as_ptr(), - 32, + self.priv_key_bytes.len() as word32, private_key_object.as_ptr(), endian.try_into().unwrap(), ) @@ -113,7 +123,7 @@ impl KeyExchangeX25519 { }; check_if_zero(ret).unwrap(); - Box::new(out) + Ok(Box::new(out)) } } @@ -124,7 +134,7 @@ impl rustls::crypto::ActiveKeyExchange for KeyExchangeX25519 { ) -> Result { // We derive the shared secret with our private key and // the received public key. - let secret = self.derive_shared_secret(peer_pub_key); + let secret = self.derive_shared_secret(peer_pub_key)?; Ok(rustls::crypto::SharedSecret::from(&*secret)) } @@ -149,8 +159,8 @@ mod tests { let bob = Box::new(KeyExchangeX25519::use_curve25519()); assert_eq!( - alice.derive_shared_secret(bob.pub_key().try_into().unwrap()), - bob.derive_shared_secret(alice.pub_key().try_into().unwrap()), + alice.derive_shared_secret(bob.pub_key()).unwrap(), + bob.derive_shared_secret(alice.pub_key()).unwrap(), ) } } From 8075c7ab84880c41915c635c964adfb9813c9412 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 15:55:28 +0100 Subject: [PATCH 03/10] fix potential data race in rsa signing by re-importing key per sign() call instead of sharing mutable C struct via Arc --- rustls-wolfcrypt-provider/src/sign/rsa.rs | 140 ++++++++++------------ 1 file changed, 60 insertions(+), 80 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/sign/rsa.rs b/rustls-wolfcrypt-provider/src/sign/rsa.rs index 624e599..932a470 100644 --- a/rustls-wolfcrypt-provider/src/sign/rsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/rsa.rs @@ -12,6 +12,7 @@ use rustls::{SignatureAlgorithm, SignatureScheme}; use core::ptr; use wolfcrypt_rs::*; +use zeroize::Zeroizing; const ALL_RSA_SCHEMES: &[SignatureScheme] = &[ SignatureScheme::RSA_PSS_SHA256, @@ -31,101 +32,78 @@ const MGF1_SHA256: u32 = WC_MGF1SHA256; const MGF1_SHA384: u32 = WC_MGF1SHA384; const MGF1_SHA512: u32 = WC_MGF1SHA512; -/// Owns a heap-allocated RsaKey along with the RsaKeyObject wrapper. -/// The Box keeps the heap memory alive while RsaKeyObject holds the pointer. -/// Fields are ordered so that rsa_key_object drops first (calling wc_FreeRsaKey -/// to clean up wolfSSL internals), then _rsa_key_box drops to free the heap memory. -#[derive(Debug)] -struct OwnedRsaKey { - rsa_key_object: RsaKeyObject, - _rsa_key_box: Box, +/// Which DER format the stored key bytes are in. +#[derive(Clone, Debug)] +enum RsaKeyFormat { + Pkcs8, + Pkcs1, } -unsafe impl Send for OwnedRsaKey {} -unsafe impl Sync for OwnedRsaKey {} #[derive(Clone, Debug)] pub struct RsaPrivateKey { - key: Arc, + /// Raw DER-encoded private key bytes. + der_bytes: Arc>>, + format: RsaKeyFormat, algo: SignatureAlgorithm, } -impl RsaPrivateKey { - pub fn get_rsa_key_object(&self) -> &RsaKeyObject { - &self.key.rsa_key_object - } +/// Import the stored DER bytes into a fresh RsaKey C struct. +/// Returns the boxed RsaKey (to keep memory alive) and the RsaKeyObject wrapper. +fn import_rsa_key( + der_bytes: &[u8], + format: &RsaKeyFormat, +) -> Result<(Box, RsaKeyObject), rustls::Error> { + let mut rsa_key_box = Box::new(unsafe { mem::zeroed::() }); + let rsa_key_object = unsafe { RsaKeyObject::from_ptr(&mut *rsa_key_box) }; + + let ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; + check_if_zero(ret) + .map_err(|_| rustls::Error::General("wc_InitRsaKey failed".into()))?; + + let mut idx: u32 = 0; + + let decode_ret = match format { + RsaKeyFormat::Pkcs8 | RsaKeyFormat::Pkcs1 => unsafe { + wc_RsaPrivateKeyDecode( + der_bytes.as_ptr() as *mut u8, + &mut idx, + rsa_key_object.as_ptr(), + der_bytes.len() as word32, + ) + }, + }; + check_if_zero(decode_ret) + .map_err(|_| rustls::Error::General("wc_RsaPrivateKeyDecode failed".into()))?; + + Ok((rsa_key_box, rsa_key_object)) } impl TryFrom<&PrivateKeyDer<'_>> for RsaPrivateKey { type Error = rustls::Error; fn try_from(value: &PrivateKeyDer<'_>) -> Result { - match value { + let (der_bytes, format) = match value { PrivateKeyDer::Pkcs8(der) => { - let pkcs8: &[u8] = der.secret_pkcs8_der(); - let pkcs8_sz: word32 = pkcs8.len() as word32; - let mut ret; - let mut rsa_key_box = Box::new(unsafe { mem::zeroed::() }); - let rsa_key_object = unsafe { RsaKeyObject::from_ptr(&mut *rsa_key_box) }; - - ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); - - let mut idx: u32 = 0; - - ret = unsafe { - wc_RsaPrivateKeyDecode( - pkcs8.as_ptr() as *mut u8, - &mut idx, - rsa_key_object.as_ptr(), - pkcs8_sz, - ) - }; - check_if_zero(ret) - .map_err(|_| rustls::Error::General("FFI function failed".into()))?; - - Ok(Self { - key: Arc::new(OwnedRsaKey { - rsa_key_object, - _rsa_key_box: rsa_key_box, - }), - algo: SignatureAlgorithm::RSA, - }) + (der.secret_pkcs8_der().to_vec(), RsaKeyFormat::Pkcs8) } PrivateKeyDer::Pkcs1(der) => { - let pkcs1: &[u8] = der.secret_pkcs1_der(); - let pkcs1_sz: word32 = pkcs1.len() as word32; - let mut ret; - let mut rsa_key_box = Box::new(unsafe { mem::zeroed::() }); - let rsa_key_object = unsafe { RsaKeyObject::from_ptr(&mut *rsa_key_box) }; - - ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + (der.secret_pkcs1_der().to_vec(), RsaKeyFormat::Pkcs1) + } + _ => { + return Err(rustls::Error::General( + "Unsupported private key format".into(), + )) + } + }; - let mut idx: u32 = 0; + // Validate that the key can be decoded before accepting it. + let (_rsa_key_box, _rsa_key_object) = import_rsa_key(&der_bytes, &format)?; - ret = unsafe { - wc_RsaPrivateKeyDecode( - pkcs1.as_ptr() as *mut u8, - &mut idx, - rsa_key_object.as_ptr(), - pkcs1_sz, - ) - }; - check_if_zero(ret) - .map_err(|_| rustls::Error::General("FFI function failed".into()))?; - - Ok(Self { - key: Arc::new(OwnedRsaKey { - rsa_key_object, - _rsa_key_box: rsa_key_box, - }), - algo: SignatureAlgorithm::RSA, - }) - } - _ => Err(rustls::Error::General( - "Unsupported private key format".into(), - )), - } + Ok(Self { + der_bytes: Arc::new(Zeroizing::new(der_bytes)), + format, + algo: SignatureAlgorithm::RSA, + }) } } @@ -135,7 +113,8 @@ impl SigningKey for RsaPrivateKey { ALL_RSA_SCHEMES.iter().find_map(|&scheme| { if offered.contains(&scheme) { Some(Box::new(RsaSigner { - key: Arc::clone(&self.key), + der_bytes: Arc::clone(&self.der_bytes), + format: self.format.clone(), scheme, }) as Box) } else { @@ -151,13 +130,14 @@ impl SigningKey for RsaPrivateKey { #[derive(Clone, Debug)] pub struct RsaSigner { - key: Arc, + der_bytes: Arc>>, + format: RsaKeyFormat, scheme: SignatureScheme, } impl Signer for RsaSigner { fn sign(&self, message: &[u8]) -> Result, rustls::Error> { - let rsa_key_object = &self.key.rsa_key_object; + let (_rsa_key_box, rsa_key_object) = import_rsa_key(&self.der_bytes, &self.format)?; // Prepare a random generator let mut rng: WC_RNG = unsafe { mem::zeroed() }; From 719c0f1b4769945344d1dcc7fccfc07ce53ad52e Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 15:58:57 +0100 Subject: [PATCH 04/10] add missing hmac_free in hmac finalization fixing potential leaks --- rustls-wolfcrypt-provider/src/hmac/mod.rs | 2 +- rustls-wolfcrypt-provider/src/hmac/sha256hmac.rs | 6 ++++-- rustls-wolfcrypt-provider/src/hmac/sha384hmac.rs | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/hmac/mod.rs b/rustls-wolfcrypt-provider/src/hmac/mod.rs index 2e9e87d..f6351e2 100644 --- a/rustls-wolfcrypt-provider/src/hmac/mod.rs +++ b/rustls-wolfcrypt-provider/src/hmac/mod.rs @@ -110,8 +110,8 @@ impl WCHmacKey { let ret = unsafe { wc_HmacFinal(hmac_ptr, digest.as_mut_ptr()) }; check_if_zero(ret).unwrap(); - // Free the heap-allocated Hmac struct. unsafe { + wc_HmacFree(hmac_ptr); drop(Box::from_raw(hmac_ptr)); } diff --git a/rustls-wolfcrypt-provider/src/hmac/sha256hmac.rs b/rustls-wolfcrypt-provider/src/hmac/sha256hmac.rs index 85de4e2..a4e180b 100644 --- a/rustls-wolfcrypt-provider/src/hmac/sha256hmac.rs +++ b/rustls-wolfcrypt-provider/src/hmac/sha256hmac.rs @@ -79,8 +79,10 @@ impl WCHmac256Key { let ret = unsafe { wc_HmacFinal(hmac_ptr, digest.as_mut_ptr()) }; check_if_zero(ret).unwrap(); - // Free the heap-allocated Hmac struct. - unsafe { drop(Box::from_raw(hmac_ptr)); } + unsafe { + wc_HmacFree(hmac_ptr); + drop(Box::from_raw(hmac_ptr)); + } digest } diff --git a/rustls-wolfcrypt-provider/src/hmac/sha384hmac.rs b/rustls-wolfcrypt-provider/src/hmac/sha384hmac.rs index fb5fa1e..af2ce78 100644 --- a/rustls-wolfcrypt-provider/src/hmac/sha384hmac.rs +++ b/rustls-wolfcrypt-provider/src/hmac/sha384hmac.rs @@ -80,8 +80,10 @@ impl WCHmac384Key { check_if_zero(ret).unwrap(); - // Free the heap-allocated Hmac struct. - unsafe { drop(Box::from_raw(hmac_ptr)); } + unsafe { + wc_HmacFree(hmac_ptr); + drop(Box::from_raw(hmac_ptr)); + } digest } From 030ff28aba0a6c56f579a9b233dff5416bd969d9 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 16:02:47 +0100 Subject: [PATCH 05/10] remove clone from the foreign types macros to avoid (potential but still likely) double-free of C resources when dorp-enabled types are cloned --- rustls-wolfcrypt-provider/src/types/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/types/mod.rs b/rustls-wolfcrypt-provider/src/types/mod.rs index c61b09b..06b80fe 100644 --- a/rustls-wolfcrypt-provider/src/types/mod.rs +++ b/rustls-wolfcrypt-provider/src/types/mod.rs @@ -12,7 +12,7 @@ macro_rules! define_foreign_type { type CType = $c_type; } - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct $struct_name(NonNull<$c_type>); unsafe impl Sync for $struct_name {} unsafe impl Send for $struct_name {} @@ -141,7 +141,7 @@ macro_rules! define_foreign_type_no_copy { type CType = $c_type; } - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct $struct_name(NonNull<$c_type>); unsafe impl Sync for $struct_name {} unsafe impl Send for $struct_name {} From 1a487d00683936375bccc6f7ea5756c760f16e76 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 16:07:00 +0100 Subject: [PATCH 06/10] remove all unwraps calls on ffi calls in verify_signature methods to return InvalidSignature instead of panicking when parsing malformed peer certificates --- rustls-wolfcrypt-provider/src/verify/ecdsa.rs | 4 ++-- rustls-wolfcrypt-provider/src/verify/eddsa.rs | 4 ++-- .../src/verify/rsapkcs1.rs | 12 ++++++------ rustls-wolfcrypt-provider/src/verify/rsapss.rs | 18 +++++++++--------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs index 2563ff4..8b8c626 100644 --- a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs @@ -101,7 +101,7 @@ impl SignatureVerificationAlgorithm for EcdsaVerifier { ptr::null_mut(), // Private "d" (optional) curve_id, ); - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // This function returns the size of the digest (output) for a hash_type. // The returned size is used to make sure the output buffer is large enough. @@ -118,7 +118,7 @@ impl SignatureVerificationAlgorithm for EcdsaVerifier { digest.as_mut_ptr(), digest_sz as word32, ); - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // Finally, verify the signature against the digest ret = wc_ecc_verify_hash( diff --git a/rustls-wolfcrypt-provider/src/verify/eddsa.rs b/rustls-wolfcrypt-provider/src/verify/eddsa.rs index 960dcc6..433d134 100644 --- a/rustls-wolfcrypt-provider/src/verify/eddsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/eddsa.rs @@ -30,14 +30,14 @@ impl SignatureVerificationAlgorithm for Ed25519 { let mut stat: i32 = 0; ed25519_key_object.init(); - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; ret = wc_ed25519_import_public( public_key.as_ptr(), public_key.len() as word32, ed25519_key_object.as_ptr(), ); - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; ret = wc_ed25519_verify_msg( signature.as_ptr(), diff --git a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs index b2e6e01..eafbd7c 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs @@ -34,7 +34,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha256Verify { let mut ret; ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let mut idx = 0; ret = unsafe { @@ -45,7 +45,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha256Verify { public_key.len() as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let derefenced_rsa_key_c_type = unsafe { *(rsa_key_object.as_ptr()) }; @@ -100,7 +100,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha384Verify { let mut ret; ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let mut idx = 0; ret = unsafe { @@ -111,7 +111,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha384Verify { public_key.len() as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let dereferenced_rsa_key_c_type = unsafe { *(rsa_key_object.as_ptr()) }; @@ -166,7 +166,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha512Verify { let mut ret; ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let mut idx = 0; ret = unsafe { @@ -177,7 +177,7 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha512Verify { public_key.len() as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let dereferenced_rsa_key_c_type = unsafe { *(rsa_key_object.as_ptr()) }; diff --git a/rustls-wolfcrypt-provider/src/verify/rsapss.rs b/rustls-wolfcrypt-provider/src/verify/rsapss.rs index b59d7fb..8de73ba 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapss.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapss.rs @@ -36,7 +36,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha256Verify { let mut ret; ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // This function returns the size of the digest (output) for a hash_type. // The returns size is used to make sure the output buffer @@ -56,7 +56,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha256Verify { digest_sz as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let mut idx = 0; ret = unsafe { @@ -67,7 +67,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha256Verify { public_key.len() as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // Verify the message signed with RSA-PSS. // In this case 'message' has been, supposedly, @@ -119,7 +119,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha384Verify { let mut ret; ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // This function returns the size of the digest (output) for a hash_type. // The returns size is used to make sure the output buffer @@ -139,7 +139,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha384Verify { digest_sz as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let mut idx = 0; ret = unsafe { @@ -150,7 +150,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha384Verify { public_key.len() as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // Verify the message signed with RSA-PSS. // In this case 'message' has been, supposedly, @@ -202,7 +202,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha512Verify { let mut ret; ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // This function returns the size of the digest (output) for a hash_type. // The returns size is used to make sure the output buffer @@ -222,7 +222,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha512Verify { digest_sz as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; let mut idx = 0; ret = unsafe { @@ -233,7 +233,7 @@ impl SignatureVerificationAlgorithm for RsaPssSha512Verify { public_key.len() as word32, ) }; - check_if_zero(ret).unwrap(); + check_if_zero(ret).map_err(|_| InvalidSignature)?; // Verify the message signed with RSA-PSS. // In this case 'message' has been, supposedly, From 9d8a4e302f356407ffcef4233762b3f8f645b8e5 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 16:08:51 +0100 Subject: [PATCH 07/10] remove duplicate entries for *_PSS_SHA512 and *_PKCS1_SHA512 in verify.rs mapping array --- rustls-wolfcrypt-provider/src/verify.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/verify.rs b/rustls-wolfcrypt-provider/src/verify.rs index cae95ad..c03938b 100644 --- a/rustls-wolfcrypt-provider/src/verify.rs +++ b/rustls-wolfcrypt-provider/src/verify.rs @@ -31,8 +31,6 @@ pub static ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { (SignatureScheme::ECDSA_NISTP384_SHA384, &[ECDSA_P384_SHA384]), (SignatureScheme::ECDSA_NISTP521_SHA512, &[ECDSA_P521_SHA512]), (SignatureScheme::ED25519, &[ED25519]), - (SignatureScheme::RSA_PSS_SHA512, &[RSA_PSS_SHA512]), - (SignatureScheme::RSA_PKCS1_SHA512, &[RSA_PKCS1_SHA512]), ], }; From 9d94183b3ccbdaeb63cbcd20305ea159d423470f Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 16:12:34 +0100 Subject: [PATCH 08/10] replaced derived Debug with manual impls that redacts the private key material to prevent leakage when debug logging the library --- rustls-wolfcrypt-provider/src/sign/ecdsa.rs | 11 +++++++++- rustls-wolfcrypt-provider/src/sign/eddsa.rs | 21 +++++++++++++++++-- rustls-wolfcrypt-provider/src/sign/rsa.rs | 23 +++++++++++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/sign/ecdsa.rs b/rustls-wolfcrypt-provider/src/sign/ecdsa.rs index b275577..f747bd8 100644 --- a/rustls-wolfcrypt-provider/src/sign/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/ecdsa.rs @@ -6,6 +6,7 @@ use alloc::format; use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; +use core::fmt; use core::mem; use core::ptr; use foreign_types::ForeignType; @@ -19,7 +20,7 @@ use zeroize::Zeroizing; /// A unified ECDSA signing key that supports P-256, P-384, P-521. /// Internally, we store the raw private key bytes plus /// which scheme we should use (determined by WolfSSL after decode). -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct EcdsaSigningKey { /// Raw private key bytes exported from WolfSSL (`wc_ecc_export_private_only`) /// in big-endian format. @@ -28,6 +29,14 @@ pub struct EcdsaSigningKey { scheme: SignatureScheme, } +impl fmt::Debug for EcdsaSigningKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EcdsaSigningKey") + .field("scheme", &self.scheme) + .finish_non_exhaustive() + } +} + impl TryFrom<&PrivateKeyDer<'_>> for EcdsaSigningKey { type Error = rustls::Error; diff --git a/rustls-wolfcrypt-provider/src/sign/eddsa.rs b/rustls-wolfcrypt-provider/src/sign/eddsa.rs index 5e1e5b3..54f74ea 100644 --- a/rustls-wolfcrypt-provider/src/sign/eddsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/eddsa.rs @@ -4,6 +4,7 @@ use alloc::boxed::Box; use alloc::format; use alloc::sync::Arc; use alloc::vec::Vec; +use core::fmt; use core::mem; use foreign_types::ForeignType; use rustls::pki_types::PrivateKeyDer; @@ -15,13 +16,21 @@ use zeroize::Zeroizing; const ALL_EDDSA_SCHEMES: &[SignatureScheme] = &[SignatureScheme::ED25519]; -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Ed25519PrivateKey { priv_key: Arc>>, pub_key: Arc>, algo: SignatureAlgorithm, } +impl fmt::Debug for Ed25519PrivateKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Ed25519PrivateKey") + .field("algo", &self.algo) + .finish_non_exhaustive() + } +} + impl TryFrom<&PrivateKeyDer<'_>> for Ed25519PrivateKey { type Error = rustls::Error; @@ -112,13 +121,21 @@ impl SigningKey for Ed25519PrivateKey { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Ed25519Signer { priv_key: Arc>>, pub_key: Arc>, scheme: SignatureScheme, } +impl fmt::Debug for Ed25519Signer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Ed25519Signer") + .field("scheme", &self.scheme) + .finish_non_exhaustive() + } +} + impl Signer for Ed25519Signer { fn sign(&self, message: &[u8]) -> Result, rustls::Error> { let mut ret; diff --git a/rustls-wolfcrypt-provider/src/sign/rsa.rs b/rustls-wolfcrypt-provider/src/sign/rsa.rs index 932a470..6daa374 100644 --- a/rustls-wolfcrypt-provider/src/sign/rsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/rsa.rs @@ -4,6 +4,7 @@ use alloc::boxed::Box; use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; +use core::fmt; use core::mem; use foreign_types::ForeignType; use rustls::pki_types::PrivateKeyDer; @@ -39,7 +40,7 @@ enum RsaKeyFormat { Pkcs1, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RsaPrivateKey { /// Raw DER-encoded private key bytes. der_bytes: Arc>>, @@ -47,6 +48,15 @@ pub struct RsaPrivateKey { algo: SignatureAlgorithm, } +impl fmt::Debug for RsaPrivateKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RsaPrivateKey") + .field("format", &self.format) + .field("algo", &self.algo) + .finish_non_exhaustive() + } +} + /// Import the stored DER bytes into a fresh RsaKey C struct. /// Returns the boxed RsaKey (to keep memory alive) and the RsaKeyObject wrapper. fn import_rsa_key( @@ -128,13 +138,22 @@ impl SigningKey for RsaPrivateKey { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RsaSigner { der_bytes: Arc>>, format: RsaKeyFormat, scheme: SignatureScheme, } +impl fmt::Debug for RsaSigner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RsaSigner") + .field("format", &self.format) + .field("scheme", &self.scheme) + .finish_non_exhaustive() + } +} + impl Signer for RsaSigner { fn sign(&self, message: &[u8]) -> Result, rustls::Error> { let (_rsa_key_box, rsa_key_object) = import_rsa_key(&self.der_bytes, &self.format)?; From 7c078b5fb4436c05e529ee4ba44d1c983fef2d04 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 16:13:56 +0100 Subject: [PATCH 09/10] removed reduddant check_if_zero call in ed25519 verify_signaure --- rustls-wolfcrypt-provider/src/verify/eddsa.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/verify/eddsa.rs b/rustls-wolfcrypt-provider/src/verify/eddsa.rs index 433d134..b7c132a 100644 --- a/rustls-wolfcrypt-provider/src/verify/eddsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/eddsa.rs @@ -26,13 +26,11 @@ impl SignatureVerificationAlgorithm for Ed25519 { unsafe { let mut ed25519_c_type: ed25519_key = mem::zeroed(); let ed25519_key_object = ED25519KeyObject::from_ptr(&mut ed25519_c_type); - let mut ret = 0; let mut stat: i32 = 0; ed25519_key_object.init(); - check_if_zero(ret).map_err(|_| InvalidSignature)?; - ret = wc_ed25519_import_public( + let mut ret = wc_ed25519_import_public( public_key.as_ptr(), public_key.len() as word32, ed25519_key_object.as_ptr(), From d077f145f0756420a2f2c30b216636caa3cef478 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Mon, 23 Mar 2026 16:31:38 +0100 Subject: [PATCH 10/10] fix formatting reports from cargo fmt --- rustls-wolfcrypt-provider/src/sign/rsa.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/sign/rsa.rs b/rustls-wolfcrypt-provider/src/sign/rsa.rs index 6daa374..ab725f6 100644 --- a/rustls-wolfcrypt-provider/src/sign/rsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/rsa.rs @@ -67,8 +67,7 @@ fn import_rsa_key( let rsa_key_object = unsafe { RsaKeyObject::from_ptr(&mut *rsa_key_box) }; let ret = unsafe { wc_InitRsaKey(rsa_key_object.as_ptr(), ptr::null_mut()) }; - check_if_zero(ret) - .map_err(|_| rustls::Error::General("wc_InitRsaKey failed".into()))?; + check_if_zero(ret).map_err(|_| rustls::Error::General("wc_InitRsaKey failed".into()))?; let mut idx: u32 = 0; @@ -93,12 +92,8 @@ impl TryFrom<&PrivateKeyDer<'_>> for RsaPrivateKey { fn try_from(value: &PrivateKeyDer<'_>) -> Result { let (der_bytes, format) = match value { - PrivateKeyDer::Pkcs8(der) => { - (der.secret_pkcs8_der().to_vec(), RsaKeyFormat::Pkcs8) - } - PrivateKeyDer::Pkcs1(der) => { - (der.secret_pkcs1_der().to_vec(), RsaKeyFormat::Pkcs1) - } + PrivateKeyDer::Pkcs8(der) => (der.secret_pkcs8_der().to_vec(), RsaKeyFormat::Pkcs8), + PrivateKeyDer::Pkcs1(der) => (der.secret_pkcs1_der().to_vec(), RsaKeyFormat::Pkcs1), _ => { return Err(rustls::Error::General( "Unsupported private key format".into(),