VYPR
Critical severity9.8NVD Advisory· Published Apr 24, 2026· Updated Apr 28, 2026

CVE-2026-41678

CVE-2026-41678

Description

rust-openssl provides OpenSSL bindings for the Rust programming language. From to before 0.10.78, aes::unwrap_key() contains an incorrect assertion: it checks that out.len() + 8 <= in_.len(), but this condition is reversed. The intended invariant is out.len() >= in_.len() - 8, ensuring the output buffer is large enough. Because of the inverted check, the function only accepts buffers at or below the minimum required size and rejects larger ones. If a smaller buffer is provided the function will write past the end of out by in_.len() - 8 - out.len() bytes, causing an out-of-bounds write from a safe public function. This vulnerability is fixed in 0.10.78.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
opensslcrates.io
>= 0.10.24, < 0.10.780.10.78

Affected products

1

Patches

1
718d07ff8ff7

fix inverted bounds assertion in AES key unwrap (#2604)

https://github.com/rust-openssl/rust-opensslPaul KehrerApr 19, 2026via ghsa
1 file changed · +69 1
  • openssl/src/aes.rs+69 1 modified
    @@ -243,7 +243,7 @@ pub fn unwrap_key(
         in_: &[u8],
     ) -> Result<usize, KeyError> {
         unsafe {
    -        assert!(out.len() + 8 <= in_.len());
    +        assert!(out.len() + 8 >= in_.len());
     
             let written = ffi::AES_unwrap_key(
                 &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer.
    @@ -296,6 +296,74 @@ mod test {
             assert_eq!(pt_actual, pt);
         }
     
    +    // out is larger than in_.len() - 8 but still valid; should succeed.
    +    #[test]
    +    fn test_unwrap_key_out_oversized() {
    +        let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
    +        let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
    +        let wrapped = Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
    +        let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
    +
    +        let mut out = vec![0u8; 32]; // larger than the 16 bytes that will be written
    +        let n = unwrap_key(&dec_key, None, &mut out, &wrapped).unwrap();
    +        assert_eq!(n, 16);
    +        assert_eq!(&out[..16], &key_data[..]);
    +    }
    +
    +    // out is smaller than in_.len() - 8; must panic.
    +    #[test]
    +    #[should_panic]
    +    fn test_unwrap_key_out_too_small_panics() {
    +        let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
    +        let wrapped = Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
    +        let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
    +
    +        let mut out = vec![0u8; 8]; // too small: needs 16 bytes
    +        let _ = unwrap_key(&dec_key, None, &mut out, &wrapped);
    +    }
    +
    +    // Verify that unwrap_key returns Err when the ciphertext has been tampered with.
    +    #[test]
    +    fn test_unwrap_key_tampered_ciphertext() {
    +        let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
    +        let mut wrapped =
    +            Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
    +        // Flip a byte so the integrity check fails
    +        wrapped[0] ^= 0xFF;
    +
    +        let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
    +        let mut out = [0u8; 16];
    +        assert!(
    +            unwrap_key(&dec_key, None, &mut out, &wrapped).is_err(),
    +            "expected Err for tampered ciphertext"
    +        );
    +    }
    +
    +    // Verify that wrap/unwrap round-trips correctly with an explicit IV.
    +    #[test]
    +    fn test_wrap_unwrap_with_iv() {
    +        let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
    +        let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
    +        let iv: [u8; 8] = [0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6];
    +
    +        let enc_key = AesKey::new_encrypt(&raw_key).unwrap();
    +        let mut wrapped = [0u8; 24];
    +        wrap_key(&enc_key, Some(iv), &mut wrapped, &key_data).unwrap();
    +
    +        let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
    +        let mut unwrapped = [0u8; 16];
    +        unwrap_key(&dec_key, Some(iv), &mut unwrapped, &wrapped).unwrap();
    +        assert_eq!(&unwrapped[..], &key_data[..]);
    +
    +        // Using a different IV must fail
    +        let wrong_iv: [u8; 8] = [0x00; 8];
    +        let mut unwrapped2 = [0u8; 16];
    +        assert!(
    +            unwrap_key(&dec_key, Some(wrong_iv), &mut unwrapped2, &wrapped).is_err(),
    +            "expected Err when IV does not match"
    +        );
    +    }
    +
         // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3
         #[test]
         fn test_wrap_unwrap() {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.