Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion wolfcrypt/src/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -1147,7 +1147,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz,
rng->drbg_scratch = NULL;
#endif
}
/* else swc_RNG_HealthTestLocal was successful */
/* else wc_RNG_HealthTestLocal was successful */

if (ret == DRBG_SUCCESS) {
#ifdef WOLFSSL_CHECK_MEM_ZERO
Expand Down
4 changes: 4 additions & 0 deletions wrapper/rust/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ all:
test:
+$(MAKE) -C wolfssl-wolfcrypt test

.PHONY: testfips
testfips:
+$(MAKE) -C wolfssl-wolfcrypt testfips

.PHONY: clean
clean:
+$(MAKE) -C wolfssl-wolfcrypt clean
6 changes: 5 additions & 1 deletion wrapper/rust/wolfssl-wolfcrypt/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ all:

.PHONY: test
test:
cargo test
cargo test -- --test-threads=1

.PHONY: testfips
testfips:
cargo test --lib --bins --tests -- --test-threads=1

.PHONY: clean
clean:
Expand Down
81 changes: 80 additions & 1 deletion wrapper/rust/wolfssl-wolfcrypt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fn main() {
/// Returns `Ok(())` if successful, or an error if any step fails.
fn run_build() -> Result<()> {
generate_bindings()?;
generate_fips_aliases()?;
setup_wolfssl_link()?;
scan_cfg()?;
Ok(())
Expand Down Expand Up @@ -64,6 +65,79 @@ fn generate_bindings() -> Result<()> {
})
}

/// Generate FIPS symbol aliases.
///
/// Since Rust can't use fips.h's #defines which map the "regular" wc function
/// name to the _fips variant, and since bindgen has only seen the _fips
/// variant, we will generate aliases that allow the non-_fips variant function
/// name to be called without the _fips prefix by Rust sources in a manner
/// similar to which C sources would be able to call the non-_fips variant
/// function name.
///
/// Returns `Ok(())` if successful, or an error if generation fails.
fn generate_fips_aliases() -> Result<()> {
let binding = read_file(bindings_path())?;
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let aliases_path = out_dir.join("fips_aliases.rs");

let mut aliases = String::new();

// Find all _fips symbol names
let fips_sym_re = Regex::new(r"pub fn (wc_\w+)_fips\s*\(").unwrap();

for cap in fips_sym_re.captures_iter(&binding) {
let mut base_name = &cap[1];
let fips_name = format!("{}_fips", base_name);

// Exception mappings: (standard_name, fips_name)
// For cases where FIPS name doesn't follow the simple <name>_fips pattern
let exceptions: &[(&str, &str)] = &[
// _ex suffix changed to Ex before _fips
("wc_InitRsaKey_ex", "wc_InitRsaKeyEx_fips"),
("wc_RsaPublicEncrypt_ex", "wc_RsaPublicEncryptEx_fips"),
("wc_RsaPrivateDecryptInline_ex", "wc_RsaPrivateDecryptInlineEx_fips"),
("wc_RsaPrivateDecrypt_ex", "wc_RsaPrivateDecryptEx_fips"),
("wc_RsaPSS_Sign_ex", "wc_RsaPSS_SignEx_fips"),
("wc_RsaPSS_VerifyInline_ex", "wc_RsaPSS_VerifyInlineEx_fips"),
("wc_RsaPSS_Verify_ex", "wc_RsaPSS_VerifyEx_fips"),
("wc_RsaPSS_CheckPadding_ex", "wc_RsaPSS_CheckPaddingEx_fips"),
("wc_DhSetKey_ex", "wc_DhSetKeyEx_fips"),
("wc_DhCheckPubKey_ex", "wc_DhCheckPubKeyEx_fips"),
("wc_DhCheckPrivKey_ex", "wc_DhCheckPrivKeyEx_fips"),

// Name change
("wc_PRF_TLS", "wc_PRF_TLSv12_fips"),
];

// Handle exceptions
for (exc_base_name, exc_fips_name) in exceptions {
if fips_name == *exc_fips_name {
base_name = exc_base_name;
break;
}
}

// Check if the non-_fips version exists in bindings
let non_fips_pattern = format!(r"pub fn {}\s*\(", regex::escape(base_name));
let non_fips_re = Regex::new(&non_fips_pattern).unwrap();

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" {
println!("cargo:warning=Skipping FIPS symbols alias for {}", base_name);
}
} else {
// Only alias if the base name doesn't already exist
aliases.push_str(&format!("pub use {} as {};\n", fips_name, base_name));
}
}

fs::write(&aliases_path, aliases)?;

Ok(())
}

/// Instruct cargo to link against wolfssl C library
///
/// Returns `Ok(())` if successful, or an error if any step fails.
Expand Down Expand Up @@ -93,7 +167,7 @@ fn read_file(path: String) -> Result<String> {
}

fn check_cfg(binding: &str, function_name: &str, cfg_name: &str) {
let pattern = format!(r"\b{}\b", function_name);
let pattern = format!(r"\b{}(_fips)?\b", function_name);
let re = match Regex::new(&pattern) {
Ok(r) => r,
Err(e) => {
Expand Down Expand Up @@ -181,6 +255,9 @@ fn scan_cfg() -> Result<()> {
check_cfg(&binding, "wc_ed448_verify_msg_ex", "ed448_verify");
check_cfg(&binding, "wc_ed448_verify_msg_init", "ed448_streaming_verify");

/* fips */
check_cfg(&binding, "wc_SetSeed_Cb_fips", "fips");

/* hkdf */
check_cfg(&binding, "wc_HKDF_Extract_ex", "hkdf");

Expand Down Expand Up @@ -213,6 +290,8 @@ fn scan_cfg() -> Result<()> {
check_cfg(&binding, "wc_InitSha256", "sha256");
check_cfg(&binding, "wc_InitSha384", "sha384");
check_cfg(&binding, "wc_InitSha512", "sha512");
check_cfg(&binding, "wc_HashType_WC_HASH_TYPE_SHA512_224", "sha512_224");
check_cfg(&binding, "wc_HashType_WC_HASH_TYPE_SHA512_256", "sha512_256");
check_cfg(&binding, "wc_InitSha3_224", "sha3");
check_cfg(&binding, "wc_InitShake128", "shake128");
check_cfg(&binding, "wc_InitShake256", "shake256");
Expand Down
4 changes: 2 additions & 2 deletions wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ impl ECC {
}
let mut wc_ecc_key = unsafe { wc_ecc_key.assume_init() };
let priv_size = priv_buf.len() as u32;
let pub_ptr = if pub_buf.len() == 0 {core::ptr::null()} else {pub_buf.as_ptr()};
let pub_ptr = if pub_buf.is_empty() {core::ptr::null()} else {pub_buf.as_ptr()};
let pub_size = pub_buf.len() as u32;
let rc = unsafe {
sys::wc_ecc_import_private_key(priv_buf.as_ptr(), priv_size,
Expand Down Expand Up @@ -785,7 +785,7 @@ impl ECC {
}
let mut wc_ecc_key = unsafe { wc_ecc_key.assume_init() };
let priv_size = priv_buf.len() as u32;
let pub_ptr = if pub_buf.len() == 0 {core::ptr::null()} else {pub_buf.as_ptr()};
let pub_ptr = if pub_buf.is_empty() {core::ptr::null()} else {pub_buf.as_ptr()};
let pub_size = pub_buf.len() as u32;
let rc = unsafe {
sys::wc_ecc_import_private_key_ex(priv_buf.as_ptr(), priv_size,
Expand Down
34 changes: 34 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/src/fips.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![cfg(fips)]

use crate::sys;

/// Enables or disables the ability to read private key data in FIPS mode.
///
/// In FIPS mode, private keys are protected and cannot be read by default.
/// This function allows temporarily enabling private key reads for operations
/// that require access to the raw key material, such as key export or backup.
///
/// # Arguments
///
/// * `enabled` - Set to `1` to enable private key reads, or `0` to disable.
///
/// # Returns
///
/// * `Ok(())` - The operation succeeded.
/// * `Err(i32)` - The operation failed, returning the wolfSSL error code.
///
/// # Note
///
/// This function applies to all key types (`WC_KEYTYPE_ALL`). Private key
/// reading should be disabled again after the required operation is complete
/// to maintain FIPS compliance.
pub fn set_private_key_read_enable(enabled: i32) -> Result<(), i32> {
let rc = unsafe {
sys::wolfCrypt_SetPrivateKeyReadEnable_fips(enabled, sys::wc_KeyType_WC_KEYTYPE_ALL)
};
if rc != 0 {
Err(rc)
} else {
Ok(())
}
}
2 changes: 2 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ impl HMAC {
pub const TYPE_SHA: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA as i32;
pub const TYPE_SHA256: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA256 as i32;
pub const TYPE_SHA512: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA512 as i32;
#[cfg(sha512_224)]
pub const TYPE_SHA512_224: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_224 as i32;
#[cfg(sha512_256)]
pub const TYPE_SHA512_256: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_256 as i32;
pub const TYPE_SHA384: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA384 as i32;
pub const TYPE_SHA224: i32 = sys::wc_HashType_WC_HASH_TYPE_SHA224 as i32;
Expand Down
1 change: 1 addition & 0 deletions wrapper/rust/wolfssl-wolfcrypt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub mod dh;
pub mod ecc;
pub mod ed25519;
pub mod ed448;
pub mod fips;
pub mod hkdf;
pub mod hmac;
pub mod kdf;
Expand Down
18 changes: 18 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/src/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ impl RNG {
/// A Result which is Ok(RNG) on success or an Err containing the wolfSSL
/// library return code on failure.
pub fn new_ex(heap: Option<*mut std::os::raw::c_void>, dev_id: Option<i32>) -> Result<Self, i32> {
#[cfg(fips)]
{
let rc = unsafe {
sys::wc_SetSeed_Cb_fips(Some(sys::wc_GenerateSeed))
};
if rc != 0 {
return Err(rc);
}
}
let mut rng: MaybeUninit<RNG> = MaybeUninit::uninit();
let heap = match heap {
Some(heap) => heap,
Expand Down Expand Up @@ -137,6 +146,15 @@ impl RNG {
/// A Result which is Ok(RNG) on success or an Err containing the wolfSSL
/// library return code on failure.
pub fn new_with_nonce_ex<T>(nonce: &mut [T], heap: Option<*mut std::os::raw::c_void>, dev_id: Option<i32>) -> Result<Self, i32> {
#[cfg(fips)]
{
let rc = unsafe {
sys::wc_SetSeed_Cb_fips(Some(sys::wc_GenerateSeed))
};
if rc != 0 {
return Err(rc);
}
}
let ptr = nonce.as_mut_ptr() as *mut u8;
let size: u32 = size_of_val(nonce) as u32;
let mut rng: MaybeUninit<RNG> = MaybeUninit::uninit();
Expand Down
2 changes: 2 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ impl RSA {
pub const HASH_TYPE_SHA3_512 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHA3_512;
pub const HASH_TYPE_BLAKE2B : u32 = sys::wc_HashType_WC_HASH_TYPE_BLAKE2B;
pub const HASH_TYPE_BLAKE2S : u32 = sys::wc_HashType_WC_HASH_TYPE_BLAKE2S;
#[cfg(sha512_224)]
pub const HASH_TYPE_SHA512_224 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_224;
#[cfg(sha512_256)]
pub const HASH_TYPE_SHA512_256 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHA512_256;
#[cfg(shake128)]
pub const HASH_TYPE_SHAKE128 : u32 = sys::wc_HashType_WC_HASH_TYPE_SHAKE128;
Expand Down
3 changes: 3 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/src/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@
#![allow(unnecessary_transmutes)]
#![allow(unsafe_op_in_unsafe_fn)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

/* Include generated FIPS symbol aliases. */
include!(concat!(env!("OUT_DIR"), "/fips_aliases.rs"));
12 changes: 12 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[cfg(fips)]
fn setup_fips()
{
use wolfssl_wolfcrypt::fips;
fips::set_private_key_read_enable(1).expect("Error with set_private_key_read_enable()");
}

pub fn setup()
{
#[cfg(fips)]
setup_fips();
}
42 changes: 20 additions & 22 deletions wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,41 +780,39 @@ fn test_xts_consecutive_sectors() {
#[cfg(aes_xts_stream)]
fn test_xtsstream() {
let keys: [u8; 32] = [
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x39, 0x25, 0x79, 0x05, 0xdf, 0xcc, 0x77, 0x76,
0x6c, 0x87, 0x0a, 0x80, 0x6a, 0x60, 0xe3, 0xc0,
0x93, 0xd1, 0x2a, 0xcf, 0xcb, 0x51, 0x42, 0xfa,
0x09, 0x69, 0x89, 0x62, 0x5b, 0x60, 0xdb, 0x16
];
let tweak: [u8; 16] = [
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x5c, 0xf7, 0x9d, 0xb6, 0xc5, 0xcd, 0x99, 0x1a,
0x1c, 0x78, 0x81, 0x42, 0x24, 0x95, 0x1e, 0x84
];
let plain: [u8; 40] = [
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
let plain: [u8; 32] = [
0xbd, 0xc5, 0x46, 0x8f, 0xbc, 0x8d, 0x50, 0xa1,
0x0d, 0x1c, 0x85, 0x7f, 0x79, 0x1c, 0x5c, 0xba,
0xb3, 0x81, 0x0d, 0x0d, 0x73, 0xcf, 0x8f, 0x20,
0x46, 0xb1, 0xd1, 0x9e, 0x7d, 0x5d, 0x8a, 0x56
];
let expected_cipher: [u8; 40] = [
0xA2, 0x07, 0x47, 0x76, 0x3F, 0xEC, 0x0C, 0x23,
0x1B, 0xD0, 0xBD, 0x46, 0x9A, 0x27, 0x38, 0x12,
0x95, 0x02, 0x3D, 0x5D, 0xC6, 0x94, 0x51, 0x36,
0xA0, 0x85, 0xD2, 0x69, 0x6E, 0x87, 0x0A, 0xBF,
0xB5, 0x5A, 0xDD, 0xCB, 0x80, 0xE0, 0xFC, 0xCD
let expected_cipher: [u8; 32] = [
0xd6, 0xbe, 0x04, 0x6d, 0x41, 0xf2, 0x3b, 0x5e,
0xd7, 0x0b, 0x6b, 0x3d, 0x5c, 0x8e, 0x66, 0x23,
0x2b, 0xe6, 0xb8, 0x07, 0xd4, 0xdc, 0xc6, 0x0e,
0xff, 0x8d, 0xbc, 0x1d, 0x9f, 0x7f, 0xc8, 0x22
];

let mut xtsstream = XTSStream::new().expect("Failed to create XTSStream");
xtsstream.init_encrypt(&keys, &tweak).expect("Error with init_encrypt()");
let mut cipher: [u8; 40] = [0; 40];
let mut cipher: [u8; 32] = [0; 32];
xtsstream.encrypt_update(&plain[0..16], &mut cipher[0..16]).expect("Error with encrypt_update()");
xtsstream.encrypt_final(&plain[16..40], &mut cipher[16..40]).expect("Error with encrypt_final()");
xtsstream.encrypt_final(&plain[16..32], &mut cipher[16..32]).expect("Error with encrypt_final()");
assert_eq!(cipher, expected_cipher);

xtsstream.init_decrypt(&keys, &tweak).expect("Error with init_decrypt()");
let mut plain_out: [u8; 40] = [0; 40];
let mut plain_out: [u8; 32] = [0; 32];
xtsstream.decrypt_update(&cipher[0..16], &mut plain_out[0..16]).expect("Error with decrypt_update()");
xtsstream.decrypt_final(&cipher[16..40], &mut plain_out[16..40]).expect("Error with decrypt_final()");
xtsstream.decrypt_final(&cipher[16..32], &mut plain_out[16..32]).expect("Error with decrypt_final()");
assert_eq!(plain_out, plain);
}

Expand Down
4 changes: 4 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![cfg(dh)]

mod common;

#[cfg(any(all(dh_keygen, dh_ffdhe_2048), random))]
use wolfssl_wolfcrypt::dh::DH;
#[cfg(random)]
Expand Down Expand Up @@ -31,6 +33,7 @@ fn test_dh_named_parameters() {
#[test]
#[cfg(all(dh_keygen, random))]
fn test_generate_params() {
common::setup();
let mut rng = RNG::new().expect("Error with RNG::new()");
let mut dh = DH::generate(&mut rng, 2048).expect("Error with generate()");

Expand Down Expand Up @@ -75,6 +78,7 @@ fn test_generate_key_pair() {
#[test]
#[cfg(random)]
fn test_dh_checks() {
common::setup();
let p = [
0xc5u8, 0x7c, 0xa2, 0x4f, 0x4b, 0xd6, 0x8c, 0x3c,
0xda, 0xc7, 0xba, 0xaa, 0xea, 0x2e, 0x5c, 0x1e,
Expand Down
Loading