Skip to content

Rust fenrir fixes#10205

Merged
gasbytes merged 20 commits intowolfSSL:masterfrom
holtrop-wolfssl:rust-fenrir-fixes
Apr 17, 2026
Merged

Rust fenrir fixes#10205
gasbytes merged 20 commits intowolfSSL:masterfrom
holtrop-wolfssl:rust-fenrir-fixes

Conversation

@holtrop-wolfssl
Copy link
Copy Markdown
Contributor

Description

This branch fixes all Fenrir findings against the Rust crate.
It also adds zeroize functionality to zeroize all structs on drop.

Testing

Unit/CI tests.

Checklist

  • added tests
  • updated/added doxygen
  • updated appropriate READMEs
  • Updated manual and documentation

@holtrop-wolfssl holtrop-wolfssl self-assigned this Apr 13, 2026
Copilot AI review requested due to automatic review settings April 13, 2026 17:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses Fenrir findings in the wolfssl-wolfcrypt Rust wrapper by hardening FFI boundary handling (size conversions), introducing zeroization behavior for sensitive contexts on drop, and adjusting some APIs/tests accordingly.

Changes:

  • Replaced many len() as u32/i32 casts with checked conversions (buffer_len_to_u32 / buffer_len_to_i32) before calling into the C API.
  • Added zeroize support and explicit zeroization in Drop implementations across multiple crypto/RNG/key wrapper types.
  • Updated LMS Key ID retrieval API (get_kid) and adapted the LMS unit test.

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
wrapper/rust/wolfssl-wolfcrypt/tests/test_lms.rs Updates LMS test to use the new get_kid(&mut [u8]) API.
wrapper/rust/wolfssl-wolfcrypt/src/sha.rs Adds checked length conversions and zeroization-on-drop for SHA/SHA3/SHAKE contexts.
wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs Adds checked length conversions and zeroization behavior for RSA wrapper.
wrapper/rust/wolfssl-wolfcrypt/src/random.rs Fixes RNG initialization pattern and adds checked size conversions + zeroization-on-drop.
wrapper/rust/wolfssl-wolfcrypt/src/prf.rs Uses checked size conversions for PRF sizes passed to C.
wrapper/rust/wolfssl-wolfcrypt/src/mlkem.rs Uses checked size conversions, documents thread-safety, and adds zeroization/drop behavior for ML-KEM wrapper.
wrapper/rust/wolfssl-wolfcrypt/src/lms.rs Uses checked size conversions; changes get_kid API; adds zeroization-on-drop for LMS key.
wrapper/rust/wolfssl-wolfcrypt/src/lib.rs Introduces zeroize_raw helper and size conversion helpers (buffer_len_to_u32/i32).
wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs Uses checked size conversions; adds SRTP KDF argument validation.
wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs Uses checked size conversions and adds zeroization-on-drop for HMAC context.
wrapper/rust/wolfssl-wolfcrypt/src/hkdf.rs Uses checked size conversions for HKDF input/output sizes.
wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs Uses checked size conversions; validates Ed448 context length; adds zeroization-on-drop.
wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs Uses checked size conversions; validates Ed25519 context length; adds zeroization-on-drop.
wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs Uses checked size conversions; refactors init/error paths; adds zeroization-on-drop for ECC/ECCPoint.
wrapper/rust/wolfssl-wolfcrypt/src/dilithium.rs Uses checked size conversions; simplifies cfg usage; adds zeroization-on-drop.
wrapper/rust/wolfssl-wolfcrypt/src/dh.rs Uses checked size conversions and adds zeroization-on-drop for DH context; adds overflow guards in compare helper.
wrapper/rust/wolfssl-wolfcrypt/src/curve25519.rs Uses checked size conversions and adds zeroization-on-drop for Curve25519 key wrapper.
wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs Uses checked size conversions and adds zeroization-on-drop for CMAC context.
wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs Uses checked size conversions; adds key zeroization via derive for AEAD key-holder structs.
wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs Uses checked size conversions; adds zeroization-on-drop; prevents empty finalize buffer edge-case.
wrapper/rust/wolfssl-wolfcrypt/src/aes.rs Uses checked size conversions; tightens APIs to &[u8]; adds zeroization-on-drop; adds bounds checks in AEAD helpers.
wrapper/rust/wolfssl-wolfcrypt/build.rs Removes cfg scanning for Dilithium seed constants.
wrapper/rust/wolfssl-wolfcrypt/Cargo.toml Adds zeroize dependency.
wrapper/rust/wolfssl-wolfcrypt/Cargo.lock Locks zeroize (and derive) dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wrapper/rust/wolfssl-wolfcrypt/src/mlkem.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/tests/test_lms.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/lms.rs
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/aes.rs
Copilot AI review requested due to automatic review settings April 13, 2026 19:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (5)

wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs:600

  • wc_SRTP_KDF always treats the SRTP index as WC_SRTP_INDEX_LEN bytes (6) on the C side, regardless of kdr_index (see wolfcrypt/src/kdf.c where WC_SRTP_INDEX_LEN is passed). The current validation based on idx.len() * 8 doesn't prevent passing a shorter idx slice, which can lead to out-of-bounds reads in the C code. Please validate idx.len() == WC_SRTP_INDEX_LEN (or at least >=) before calling into C (and adjust/remove the bit-based check accordingly).
    if !(kdr_index == -1 || (0 <= kdr_index && (kdr_index as usize) <= idx.len() * 8)) {
        // The kdr_index value must be either -1 or the number of bits that
        // will be read from the idx slice.
        return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG);
    }
    let key_size = crate::buffer_len_to_u32(key.len())?;
    let salt_size = crate::buffer_len_to_u32(salt.len())?;
    let key1_size = crate::buffer_len_to_u32(key1.len())?;
    let key2_size = crate::buffer_len_to_u32(key2.len())?;
    let key3_size = crate::buffer_len_to_u32(key3.len())?;
    let rc = unsafe {
        sys::wc_SRTP_KDF(key.as_ptr(), key_size, salt.as_ptr(), salt_size,
            kdr_index, idx.as_ptr(), key1.as_mut_ptr(), key1_size,
            key2.as_mut_ptr(), key2_size, key3.as_mut_ptr(), key3_size)

wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs:706

  • Same issue as srtp_kdf: wc_SRTCP_KDF uses a fixed index length (WC_SRTCP_INDEX_LEN, 4 bytes) internally in C, so the current idx.len() * 8 validation doesn't ensure the slice is long enough. Passing a short idx can cause out-of-bounds reads in the C implementation. Validate idx.len() == WC_SRTCP_INDEX_LEN (or at least >=) before calling into C.
    if !(kdr_index == -1 || (0 <= kdr_index && (kdr_index as usize) <= idx.len() * 8)) {
        // The kdr_index value must be either -1 or the number of bits that
        // will be read from the idx slice.
        return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG);
    }
    let key_size = crate::buffer_len_to_u32(key.len())?;
    let salt_size = crate::buffer_len_to_u32(salt.len())?;
    let key1_size = crate::buffer_len_to_u32(key1.len())?;
    let key2_size = crate::buffer_len_to_u32(key2.len())?;
    let key3_size = crate::buffer_len_to_u32(key3.len())?;
    let rc = unsafe {
        sys::wc_SRTCP_KDF(key.as_ptr(), key_size, salt.as_ptr(), salt_size,
            kdr_index, idx.as_ptr(), key1.as_mut_ptr(), key1_size,
            key2.as_mut_ptr(), key2_size, key3.as_mut_ptr(), key3_size)
    };

wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs:648

  • wc_SRTP_KDF_label assumes an SRTP index of WC_SRTP_INDEX_LEN bytes (6) on the C side. This wrapper doesn't validate idx length before passing idx.as_ptr(), so a too-short slice can trigger out-of-bounds reads in C. Please enforce the required index length (e.g., idx.len() == WC_SRTP_INDEX_LEN).
pub fn srtp_kdf_label(key: &[u8], salt: &[u8], kdr_index: i32, idx: &[u8],
        label: u8, keyout: &mut [u8]) -> Result<(), i32> {
    let key_size = crate::buffer_len_to_u32(key.len())?;
    let salt_size = crate::buffer_len_to_u32(salt.len())?;
    let keyout_size = crate::buffer_len_to_u32(keyout.len())?;
    let rc = unsafe {
        sys::wc_SRTP_KDF_label(key.as_ptr(), key_size, salt.as_ptr(), salt_size,
            kdr_index, idx.as_ptr(), label, keyout.as_mut_ptr(), keyout_size)
    };

wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs:753

  • wc_SRTCP_KDF_label assumes an SRTCP index of WC_SRTCP_INDEX_LEN bytes (4) on the C side. This wrapper doesn't validate idx length before passing idx.as_ptr(), so a too-short slice can trigger out-of-bounds reads in C. Please enforce the required index length (e.g., idx.len() == WC_SRTCP_INDEX_LEN).
pub fn srtcp_kdf_label(key: &[u8], salt: &[u8], kdr_index: i32, idx: &[u8],
        label: u8, keyout: &mut [u8]) -> Result<(), i32> {
    let key_size = crate::buffer_len_to_u32(key.len())?;
    let salt_size = crate::buffer_len_to_u32(salt.len())?;
    let keyout_size = crate::buffer_len_to_u32(keyout.len())?;
    let rc = unsafe {
        sys::wc_SRTCP_KDF_label(key.as_ptr(), key_size, salt.as_ptr(), salt_size,
            kdr_index, idx.as_ptr(), label, keyout.as_mut_ptr(), keyout_size)
    };

wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs:96

  • digest_size is still cast with as u32 here. If a caller passes a digest_size > u32::MAX, this will truncate and pass an unexpected value into the C API. Consider converting with buffer_len_to_u32(digest_size) (and ideally also validating it against the algorithm's allowed digest sizes) to avoid silent truncation.
    pub fn new_with_key(digest_size: usize, key: &[u8]) -> Result<Self, i32> {
        let key_size = crate::buffer_len_to_u32(key.len())?;
        let digest_size = digest_size as u32;
        let mut wc_blake2b: MaybeUninit<sys::Blake2b> = MaybeUninit::uninit();
        let rc = unsafe {
            sys::wc_InitBlake2b_WithKey(wc_blake2b.as_mut_ptr(), digest_size,
                key.as_ptr(), key_size)
        };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wrapper/rust/wolfssl-wolfcrypt/src/mlkem.rs
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs
@holtrop-wolfssl
Copy link
Copy Markdown
Contributor Author

retest this please (job removed)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs
Fix F-1062.

If wolfSSL returns an error after initializing ECC struct with
wc_ecc_init_ex(), wc_ecc_free() might not have been called in all cases.

Move construction of the ECC struct earlier ahead of further wolfSSL
calls after wc_ecc_init_ex() so if those subsequent wolfSSL calls return
an error the Drop impl for ECC will be called to deinitialize.
This is related to F-1070 but not the same. We do not need to check
that hash_size being passed in matches the initialized digest size
because the C function will use the passed-in size as long as it is
non-zero.
Fixes F-1071.
This is an API-breaking change, so will lead to a new crate major
version.
Copilot AI review requested due to automatic review settings April 15, 2026 00:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs:648

  • srtp_kdf_label() forwards kdr_index/idx directly into wc_SRTP_KDF_label(), which in wolfCrypt expects an SRTP index of fixed length (WC_SRTP_INDEX_LEN = 6) and a kdrIdx in range -1..=24. Unlike srtp_kdf(), this wrapper currently does no pre-validation of kdr_index or idx length, so a short idx slice can cause the C code to read out of bounds. Add the same kdr_index range and idx length validation here as in srtp_kdf() (but aligned to wolfCrypt’s documented constraints).
pub fn srtp_kdf_label(key: &[u8], salt: &[u8], kdr_index: i32, idx: &[u8],
        label: u8, keyout: &mut [u8]) -> Result<(), i32> {
    let key_size = crate::buffer_len_to_u32(key.len())?;
    let salt_size = crate::buffer_len_to_u32(salt.len())?;
    let keyout_size = crate::buffer_len_to_u32(keyout.len())?;
    let rc = unsafe {
        sys::wc_SRTP_KDF_label(key.as_ptr(), key_size, salt.as_ptr(), salt_size,
            kdr_index, idx.as_ptr(), label, keyout.as_mut_ptr(), keyout_size)
    };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs Outdated
Comment thread wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs Outdated
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 15, 2026

MemBrowse Memory Report

No memory changes detected for:

@holtrop-wolfssl
Copy link
Copy Markdown
Contributor Author

retest this please (ERROR: No build record wolfSSL/PRB-140-3-tests#10085 could be located)

@gasbytes gasbytes merged commit fb64844 into wolfSSL:master Apr 17, 2026
534 of 537 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants