From 2ada1a3629ecde2bd272739ae61a5dba1f9ad892 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 18 Feb 2026 16:28:45 -0500 Subject: [PATCH] Rust wrapper: add compatibility with older FIPS v5 package --- wrapper/rust/wolfssl-wolfcrypt/build.rs | 41 +++++++++++++--- wrapper/rust/wolfssl-wolfcrypt/src/aes.rs | 13 +++-- wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs | 48 +++++++++++++++++++ wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs | 4 ++ wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs | 30 ++++++++---- wrapper/rust/wolfssl-wolfcrypt/src/sys.rs | 5 ++ .../rust/wolfssl-wolfcrypt/tests/test_hmac.rs | 7 +++ 7 files changed, 127 insertions(+), 21 deletions(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 9580b1608b9..d7e2b5f7212 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -124,7 +124,11 @@ fn generate_fips_aliases() -> Result<()> { if non_fips_re.is_match(&binding) { // Add any new known names defined with both a _fips suffix and not // here. Warn if any new ones are discovered. - if base_name != "wc_AesGcmEncrypt" { + let known_both = &[ + "wc_AesGcmEncrypt", + "wc_AesCcmEncrypt", + ]; + if !known_both.contains(&base_name) { println!("cargo:warning=Skipping FIPS symbols alias for {}", base_name); } } else { @@ -166,18 +170,21 @@ fn read_file(path: String) -> Result { Ok(content) } -fn check_cfg(binding: &str, function_name: &str, cfg_name: &str) { +fn check_cfg(binding: &str, function_name: &str, cfg_name: &str) -> bool { let pattern = format!(r"\b{}(_fips)?\b", function_name); let re = match Regex::new(&pattern) { Ok(r) => r, Err(e) => { eprintln!("Error compiling regex '{}': {}", pattern, e); - return; + std::process::exit(1); } }; println!("cargo::rustc-check-cfg=cfg({})", cfg_name); if re.is_match(binding) { println!("cargo:rustc-cfg={}", cfg_name); + true + } else { + false } } @@ -199,6 +206,7 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_AesOfbEncrypt", "aes_ofb"); check_cfg(&binding, "wc_AesXtsInit", "aes_xts"); check_cfg(&binding, "wc_AesXtsEncryptInit", "aes_xts_stream"); + check_cfg(&binding, "WC_AES_BLOCK_SIZE", "aes_wc_block_size"); /* blake2 */ check_cfg(&binding, "wc_InitBlake2b", "blake2b"); @@ -234,10 +242,19 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_ecc_verify_hash", "ecc_verify"); check_cfg(&binding, "wc_ecc_export_x963", "ecc_export"); check_cfg(&binding, "wc_ecc_import_x963", "ecc_import"); - check_cfg(&binding, "ecc_curve_ids_ECC_X25519", "ecc_curve_25519"); - check_cfg(&binding, "ecc_curve_ids_ECC_X448", "ecc_curve_448"); - check_cfg(&binding, "ecc_curve_ids_ECC_SAKKE_1", "ecc_curve_sakke"); - check_cfg(&binding, "ecc_curve_ids_ECC_CURVE_CUSTOM", "ecc_custom_curves"); + if check_cfg(&binding, "ecc_curve_ids_ECC_CURVE_INVALID", "ecc_curve_ids") { + check_cfg(&binding, "ecc_curve_ids_ECC_SM2P256V1", "ecc_curve_sm2p256v1"); + check_cfg(&binding, "ecc_curve_ids_ECC_X25519", "ecc_curve_25519"); + check_cfg(&binding, "ecc_curve_ids_ECC_X448", "ecc_curve_448"); + check_cfg(&binding, "ecc_curve_ids_ECC_SAKKE_1", "ecc_curve_sakke"); + check_cfg(&binding, "ecc_curve_ids_ECC_CURVE_CUSTOM", "ecc_custom_curves"); + } else { + check_cfg(&binding, "ecc_curve_id_ECC_SM2P256V1", "ecc_curve_sm2p256v1"); + check_cfg(&binding, "ecc_curve_id_ECC_X25519", "ecc_curve_25519"); + check_cfg(&binding, "ecc_curve_id_ECC_X448", "ecc_curve_448"); + check_cfg(&binding, "ecc_curve_id_ECC_SAKKE_1", "ecc_curve_sakke"); + check_cfg(&binding, "ecc_curve_id_ECC_CURVE_CUSTOM", "ecc_custom_curves"); + } /* ed25519 */ check_cfg(&binding, "wc_ed25519_init", "ed25519"); @@ -263,6 +280,7 @@ fn scan_cfg() -> Result<()> { /* hmac */ check_cfg(&binding, "wc_HmacSetKey", "hmac"); + check_cfg(&binding, "wc_HmacSetKey_ex", "hmac_setkey_ex"); /* kdf */ check_cfg(&binding, "wc_PBKDF2", "kdf_pbkdf2"); @@ -283,6 +301,15 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_RsaDirect", "rsa_direct"); check_cfg(&binding, "wc_MakeRsaKey", "rsa_keygen"); check_cfg(&binding, "wc_RsaPSS_Sign", "rsa_pss"); + check_cfg(&binding, "wc_RsaSetRNG", "rsa_setrng"); + check_cfg(&binding, "WC_MGF1SHA512_224", "rsa_mgf1sha512_224"); + check_cfg(&binding, "WC_MGF1SHA512_256", "rsa_mgf1sha512_256"); + // Detect whether wc_RsaExportKey takes a const first arg (new API) or non-const (old API) + let re = Regex::new(r"pub fn wc_RsaExportKey(_fips)?\s*\(\s*\w+\s*:\s*\*\s*const").unwrap(); + println!("cargo::rustc-check-cfg=cfg(rsa_const_api)"); + if re.is_match(&binding) { + println!("cargo:rustc-cfg=rsa_const_api"); + } /* sha */ check_cfg(&binding, "wc_InitSha", "sha"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs index e5b1b23c5ab..765a068f383 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs @@ -28,6 +28,11 @@ Encryption Standard (AES) functionality. use crate::sys; use std::mem::{size_of_val, MaybeUninit}; +#[cfg(aes_wc_block_size)] +pub const AES_BLOCK_SIZE: usize = sys::WC_AES_BLOCK_SIZE as usize; +#[cfg(not(aes_wc_block_size))] +pub const AES_BLOCK_SIZE: usize = sys::AES_BLOCK_SIZE as usize; + /// AES Cipher Block Chaining (CBC) mode. /// /// # Example @@ -91,7 +96,7 @@ impl CBC { fn init(&mut self, key: &[u8], iv: &[u8], dir: i32) -> Result<(), i32> { let key_size = key.len() as u32; - if iv.len() as u32 != sys::WC_AES_BLOCK_SIZE { + if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { @@ -506,7 +511,7 @@ impl CFB { /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = key.len() as u32; - if iv.len() as u32 != sys::WC_AES_BLOCK_SIZE { + if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { @@ -812,7 +817,7 @@ impl CTR { /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = key.len() as u32; - if iv.len() as u32 != sys::WC_AES_BLOCK_SIZE { + if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { @@ -1769,7 +1774,7 @@ impl OFB { /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = key.len() as u32; - if iv.len() as u32 != sys::WC_AES_BLOCK_SIZE { + if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs index 3817eb25f68..0f8d732925a 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs @@ -290,6 +290,7 @@ pub struct ECC { wc_ecc_key: sys::ecc_key, } +#[cfg(ecc_curve_ids)] impl ECC { pub const CURVE_INVALID: i32 = sys::ecc_curve_ids_ECC_CURVE_INVALID; pub const CURVE_DEF: i32 = sys::ecc_curve_ids_ECC_CURVE_DEF; @@ -320,6 +321,7 @@ impl ECC { pub const BRAINPOOLP320R1: i32 = sys::ecc_curve_ids_ECC_BRAINPOOLP320R1; pub const BRAINPOOLP384R1: i32 = sys::ecc_curve_ids_ECC_BRAINPOOLP384R1; pub const BRAINPOOLP512R1: i32 = sys::ecc_curve_ids_ECC_BRAINPOOLP512R1; + #[cfg(ecc_curve_sm2p256v1)] pub const SM2P256V1: i32 = sys::ecc_curve_ids_ECC_SM2P256V1; #[cfg(ecc_curve_25519)] pub const X25519: i32 = sys::ecc_curve_ids_ECC_X25519; @@ -330,7 +332,53 @@ impl ECC { #[cfg(ecc_custom_curves)] pub const CURVE_CUSTOM: i32 = sys::ecc_curve_ids_ECC_CURVE_CUSTOM; pub const CURVE_MAX: i32 = sys::ecc_curve_ids_ECC_CURVE_MAX; +} +#[cfg(not(ecc_curve_ids))] +impl ECC { + pub const CURVE_INVALID: i32 = sys::ecc_curve_id_ECC_CURVE_INVALID; + pub const CURVE_DEF: i32 = sys::ecc_curve_id_ECC_CURVE_DEF; + pub const SECP192R1: i32 = sys::ecc_curve_id_ECC_SECP192R1; + pub const PRIME192V2: i32 = sys::ecc_curve_id_ECC_PRIME192V2; + pub const PRIME192V3: i32 = sys::ecc_curve_id_ECC_PRIME192V3; + pub const PRIME239V1: i32 = sys::ecc_curve_id_ECC_PRIME239V1; + pub const PRIME239V2: i32 = sys::ecc_curve_id_ECC_PRIME239V2; + pub const PRIME239V3: i32 = sys::ecc_curve_id_ECC_PRIME239V3; + pub const SECP256R1: i32 = sys::ecc_curve_id_ECC_SECP256R1; + pub const SECP112R1: i32 = sys::ecc_curve_id_ECC_SECP112R1; + pub const SECP112R2: i32 = sys::ecc_curve_id_ECC_SECP112R2; + pub const SECP128R1: i32 = sys::ecc_curve_id_ECC_SECP128R1; + pub const SECP128R2: i32 = sys::ecc_curve_id_ECC_SECP128R2; + pub const SECP160R1: i32 = sys::ecc_curve_id_ECC_SECP160R1; + pub const SECP160R2: i32 = sys::ecc_curve_id_ECC_SECP160R2; + pub const SECP224R1: i32 = sys::ecc_curve_id_ECC_SECP224R1; + pub const SECP384R1: i32 = sys::ecc_curve_id_ECC_SECP384R1; + pub const SECP521R1: i32 = sys::ecc_curve_id_ECC_SECP521R1; + pub const SECP160K1: i32 = sys::ecc_curve_id_ECC_SECP160K1; + pub const SECP192K1: i32 = sys::ecc_curve_id_ECC_SECP192K1; + pub const SECP224K1: i32 = sys::ecc_curve_id_ECC_SECP224K1; + pub const SECP256K1: i32 = sys::ecc_curve_id_ECC_SECP256K1; + pub const BRAINPOOLP160R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP160R1; + pub const BRAINPOOLP192R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP192R1; + pub const BRAINPOOLP224R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP224R1; + pub const BRAINPOOLP256R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP256R1; + pub const BRAINPOOLP320R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP320R1; + pub const BRAINPOOLP384R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP384R1; + pub const BRAINPOOLP512R1: i32 = sys::ecc_curve_id_ECC_BRAINPOOLP512R1; + #[cfg(ecc_curve_sm2p256v1)] + pub const SM2P256V1: i32 = sys::ecc_curve_id_ECC_SM2P256V1; + #[cfg(ecc_curve_25519)] + pub const X25519: i32 = sys::ecc_curve_id_ECC_X25519; + #[cfg(ecc_curve_448)] + pub const X448: i32 = sys::ecc_curve_id_ECC_X448; + #[cfg(ecc_curve_sakke)] + pub const SAKKE_1: i32 = sys::ecc_curve_id_ECC_SAKKE_1; + #[cfg(ecc_custom_curves)] + pub const CURVE_CUSTOM: i32 = sys::ecc_curve_id_ECC_CURVE_CUSTOM; + pub const CURVE_MAX: i32 = sys::ecc_curve_id_ECC_CURVE_MAX; +} + +impl ECC { pub const FLAG_NONE: i32 = sys::WC_ECC_FLAG_NONE as i32; pub const FLAG_COFACTOR: i32 = sys::WC_ECC_FLAG_COFACTOR as i32; pub const FLAG_DEC_SIGN: i32 = sys::WC_ECC_FLAG_DEC_SIGN as i32; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs b/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs index 1c30adfd5d7..b31686c1594 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs @@ -156,10 +156,12 @@ impl HMAC { /// # Example /// /// ```rust + /// #![cfg(hmac_setkey_ex)] /// use wolfssl_wolfcrypt::hmac::HMAC; /// let key = [0x42u8; 3]; /// let mut hmac = HMAC::new_allow_short_key(HMAC::TYPE_SHA256, &key).expect("Error with new_allow_short_key()"); /// ``` + #[cfg(hmac_setkey_ex)] pub fn new_allow_short_key(typ: i32, key: &[u8]) -> Result { Self::new_allow_short_key_ex(typ, key, None, None) } @@ -182,10 +184,12 @@ impl HMAC { /// # Example /// /// ```rust + /// #![cfg(hmac_setkey_ex)] /// use wolfssl_wolfcrypt::hmac::HMAC; /// let key = [0x42u8; 3]; /// let mut hmac = HMAC::new_allow_short_key_ex(HMAC::TYPE_SHA256, &key, None, None).expect("Error with new_allow_short_key_ex()"); /// ``` + #[cfg(hmac_setkey_ex)] pub fn new_allow_short_key_ex(typ: i32, key: &[u8], heap: Option<*mut std::os::raw::c_void>, dev_id: Option) -> Result { let key_size = key.len() as u32; let mut wc_hmac: MaybeUninit = MaybeUninit::uninit(); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs index e49e415a8a9..ea1fa814426 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs @@ -116,7 +116,9 @@ impl RSA { pub const MGF1SHA256 : i32 = sys::WC_MGF1SHA256 as i32; pub const MGF1SHA384 : i32 = sys::WC_MGF1SHA384 as i32; pub const MGF1SHA512 : i32 = sys::WC_MGF1SHA512 as i32; + #[cfg(rsa_mgf1sha512_224)] pub const MGF1SHA512_224 : i32 = sys::WC_MGF1SHA512_224 as i32; + #[cfg(rsa_mgf1sha512_256)] pub const MGF1SHA512_256 : i32 = sys::WC_MGF1SHA512_256 as i32; // Type constants used for `rsa_direct()`. @@ -525,8 +527,12 @@ impl RSA { *d_size = d.len() as u32; *p_size = p.len() as u32; *q_size = q.len() as u32; + #[cfg(rsa_const_api)] + let key_ptr = &self.wc_rsakey; + #[cfg(not(rsa_const_api))] + let key_ptr = &mut self.wc_rsakey; let rc = unsafe { - sys::wc_RsaExportKey(&self.wc_rsakey, + sys::wc_RsaExportKey(key_ptr, e.as_mut_ptr(), e_size, n.as_mut_ptr(), n_size, d.as_mut_ptr(), d_size, @@ -575,8 +581,12 @@ impl RSA { n: &mut [u8], n_size: &mut u32) -> Result<(), i32> { *e_size = e.len() as u32; *n_size = n.len() as u32; + #[cfg(rsa_const_api)] + let key = &self.wc_rsakey; + #[cfg(not(rsa_const_api))] + let key = &mut self.wc_rsakey; let rc = unsafe { - sys::wc_RsaFlattenPublicKey(&self.wc_rsakey, + sys::wc_RsaFlattenPublicKey(key, e.as_mut_ptr(), e_size, n.as_mut_ptr(), n_size) }; if rc != 0 { @@ -843,7 +853,7 @@ impl RSA { /// # Example /// /// ```rust - /// #[cfg(all(random, rsa_pss))] + /// #[cfg(all(random, rsa_pss, rsa_const_api))] /// { /// use std::fs; /// use wolfssl_wolfcrypt::random::RNG; @@ -873,7 +883,7 @@ impl RSA { /// rsa.pss_verify_check(signature, &mut verify_out, msg, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256).expect("Error with pss_verify_check()"); /// } /// ``` - #[cfg(rsa_pss)] + #[cfg(all(rsa_pss, rsa_const_api))] pub fn pss_check_padding(&mut self, din: &[u8], sig: &[u8], hash_algo: u32) -> Result<(), i32> { let din_size = din.len() as u32; let sig_size = sig.len() as u32; @@ -909,7 +919,7 @@ impl RSA { /// # Example /// /// ```rust - /// #[cfg(all(random, rsa_pss))] + /// #[cfg(all(random, rsa_pss, rsa_const_api))] /// { /// use std::fs; /// use wolfssl_wolfcrypt::random::RNG; @@ -939,7 +949,7 @@ impl RSA { /// rsa.pss_verify_check(signature, &mut verify_out, msg, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256).expect("Error with pss_verify_check()"); /// } /// ``` - #[cfg(rsa_pss)] + #[cfg(all(rsa_pss, rsa_const_api))] pub fn pss_verify(&mut self, din: &[u8], dout: &mut [u8], hash_algo: u32, mgf: i32) -> Result { let din_size = din.len() as u32; let dout_size = dout.len() as u32; @@ -980,7 +990,7 @@ impl RSA { /// # Example /// /// ```rust - /// #[cfg(all(random, rsa_pss))] + /// #[cfg(all(random, rsa_pss, rsa_const_api))] /// { /// use std::fs; /// use wolfssl_wolfcrypt::random::RNG; @@ -1010,7 +1020,7 @@ impl RSA { /// rsa.pss_verify_check(signature, &mut verify_out, msg, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256).expect("Error with pss_verify_check()"); /// } /// ``` - #[cfg(rsa_pss)] + #[cfg(all(rsa_pss, rsa_const_api))] pub fn pss_verify_check(&mut self, din: &[u8], dout: &mut [u8], digest: &[u8], hash_algo: u32, mgf: i32) -> Result { let din_size = din.len() as u32; let dout_size = dout.len() as u32; @@ -1050,7 +1060,7 @@ impl RSA { /// # Example /// /// ```rust - /// #[cfg(rsa_direct)] + /// #[cfg(all(rsa_direct, rsa_const_api))] /// { /// use std::fs; /// use wolfssl_wolfcrypt::random::RNG; @@ -1073,7 +1083,7 @@ impl RSA { /// assert_eq!(plain_out, plain); /// } /// ``` - #[cfg(rsa_direct)] + #[cfg(all(rsa_direct, rsa_const_api))] pub fn rsa_direct(&mut self, din: &[u8], dout: &mut [u8], typ: i32, rng: &mut RNG) -> Result { let din_size = din.len() as u32; let mut dout_size = dout.len() as u32; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs b/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs index 5b90a342f93..f05728c04e1 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/sys.rs @@ -17,3 +17,8 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs")); /* Include generated FIPS symbol aliases. */ include!(concat!(env!("OUT_DIR"), "/fips_aliases.rs")); + +#[cfg(not(rsa_setrng))] +unsafe extern "C" { + pub fn wc_RsaSetRNG(key: *mut RsaKey, rng: *mut WC_RNG) -> core::ffi::c_int; +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac.rs index 6af78e1cc06..b896d904406 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac.rs @@ -33,6 +33,13 @@ fn test_hmac_sha256() { ]; for i in 0..keys.len() { + #[cfg(not(hmac_setkey_ex))] + if keys[i].len() < 14 { + continue; + } + #[cfg(not(hmac_setkey_ex))] + let mut hmac = HMAC::new(HMAC::TYPE_SHA256, keys[i]).expect("Error with new()"); + #[cfg(hmac_setkey_ex)] let mut hmac = if keys[i].len() < 14 { HMAC::new_allow_short_key(HMAC::TYPE_SHA256, keys[i]).expect("Error with new_allow_short_key()")