Skip to content

Commit 718d07f

Browse files
authored
fix inverted bounds assertion in AES key unwrap (#2604)
* fix inverted bounds assertion in AES key unwrap This also adds several additional test cases in addition to checking the buffer lengths * fix formatting
1 parent 53cc69d commit 718d07f

1 file changed

Lines changed: 69 additions & 1 deletion

File tree

openssl/src/aes.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ pub fn unwrap_key(
243243
in_: &[u8],
244244
) -> Result<usize, KeyError> {
245245
unsafe {
246-
assert!(out.len() + 8 <= in_.len());
246+
assert!(out.len() + 8 >= in_.len());
247247

248248
let written = ffi::AES_unwrap_key(
249249
&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 {
296296
assert_eq!(pt_actual, pt);
297297
}
298298

299+
// out is larger than in_.len() - 8 but still valid; should succeed.
300+
#[test]
301+
fn test_unwrap_key_out_oversized() {
302+
let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
303+
let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
304+
let wrapped = Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
305+
let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
306+
307+
let mut out = vec![0u8; 32]; // larger than the 16 bytes that will be written
308+
let n = unwrap_key(&dec_key, None, &mut out, &wrapped).unwrap();
309+
assert_eq!(n, 16);
310+
assert_eq!(&out[..16], &key_data[..]);
311+
}
312+
313+
// out is smaller than in_.len() - 8; must panic.
314+
#[test]
315+
#[should_panic]
316+
fn test_unwrap_key_out_too_small_panics() {
317+
let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
318+
let wrapped = Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
319+
let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
320+
321+
let mut out = vec![0u8; 8]; // too small: needs 16 bytes
322+
let _ = unwrap_key(&dec_key, None, &mut out, &wrapped);
323+
}
324+
325+
// Verify that unwrap_key returns Err when the ciphertext has been tampered with.
326+
#[test]
327+
fn test_unwrap_key_tampered_ciphertext() {
328+
let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
329+
let mut wrapped =
330+
Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
331+
// Flip a byte so the integrity check fails
332+
wrapped[0] ^= 0xFF;
333+
334+
let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
335+
let mut out = [0u8; 16];
336+
assert!(
337+
unwrap_key(&dec_key, None, &mut out, &wrapped).is_err(),
338+
"expected Err for tampered ciphertext"
339+
);
340+
}
341+
342+
// Verify that wrap/unwrap round-trips correctly with an explicit IV.
343+
#[test]
344+
fn test_wrap_unwrap_with_iv() {
345+
let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
346+
let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
347+
let iv: [u8; 8] = [0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6];
348+
349+
let enc_key = AesKey::new_encrypt(&raw_key).unwrap();
350+
let mut wrapped = [0u8; 24];
351+
wrap_key(&enc_key, Some(iv), &mut wrapped, &key_data).unwrap();
352+
353+
let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
354+
let mut unwrapped = [0u8; 16];
355+
unwrap_key(&dec_key, Some(iv), &mut unwrapped, &wrapped).unwrap();
356+
assert_eq!(&unwrapped[..], &key_data[..]);
357+
358+
// Using a different IV must fail
359+
let wrong_iv: [u8; 8] = [0x00; 8];
360+
let mut unwrapped2 = [0u8; 16];
361+
assert!(
362+
unwrap_key(&dec_key, Some(wrong_iv), &mut unwrapped2, &wrapped).is_err(),
363+
"expected Err when IV does not match"
364+
);
365+
}
366+
299367
// from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3
300368
#[test]
301369
fn test_wrap_unwrap() {

0 commit comments

Comments
 (0)