Skip to content

Commit

Permalink
crypto/boringssl: don't overwrite mask
Browse files Browse the repository at this point in the history
`AES_ecb_encrypt()` will always write 16 bytes (an AES block length),
but the new header protection code was passing in only 5 bytes... fun
ensued.

This also refactors the header protection methods somewhat to not
hard-code the mask length all over the place.

Closes #1924.
  • Loading branch information
ghedo committed Jan 24, 2025
1 parent d5b9509 commit a9e7d47
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 24 deletions.
62 changes: 40 additions & 22 deletions quiche/src/crypto/boringssl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use super::*;

use std::convert::TryFrom;

use std::mem::MaybeUninit;

use libc::c_int;
Expand Down Expand Up @@ -195,38 +197,54 @@ impl HeaderProtectionKey {
}
}

pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
let mut new_mask = [0_u8; 5];

pub fn new_mask(&self, sample: &[u8]) -> Result<HeaderProtectionMask> {
match self {
Self::Aes(aes_key) => unsafe {
AES_ecb_encrypt(
sample.as_ptr(),
new_mask.as_mut_ptr(),
aes_key as _,
1,
);
Self::Aes(aes_key) => {
let mut block = [0_u8; 16];

unsafe {
AES_ecb_encrypt(
sample.as_ptr(),
block.as_mut_ptr(),
aes_key as _,
1,
)
};

// Downsize the encrypted block to the size of the header
// protection mask.
//
// The length of the slice will always match the size of
// `HeaderProtectionMask` so the `unwrap()` is safe.
let new_mask =
HeaderProtectionMask::try_from(&block[..HP_MASK_LEN])
.unwrap();
Ok(new_mask)
},

Self::ChaCha(key) => unsafe {
const PLAINTEXT: &[u8; 5] = &[0_u8; 5];
Self::ChaCha(key) => {
const PLAINTEXT: &[u8; HP_MASK_LEN] = &[0_u8; HP_MASK_LEN];

let mut new_mask = HeaderProtectionMask::default();

let counter = u32::from_le_bytes([
sample[0], sample[1], sample[2], sample[3],
]);

CRYPTO_chacha_20(
new_mask.as_mut_ptr(),
PLAINTEXT.as_ptr(),
PLAINTEXT.len(),
key.as_ptr(),
sample[std::mem::size_of::<u32>()..].as_ptr(),
counter,
);
unsafe {
CRYPTO_chacha_20(
new_mask.as_mut_ptr(),
PLAINTEXT.as_ptr(),
PLAINTEXT.len(),
key.as_ptr(),
sample[std::mem::size_of::<u32>()..].as_ptr(),
counter,
);
};

Ok(new_mask)
},
}

Ok(new_mask)
}
}

Expand Down
5 changes: 5 additions & 0 deletions quiche/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ use crate::packet;
// All the AEAD algorithms we support use 96-bit nonces.
pub const MAX_NONCE_LEN: usize = 12;

// Length of header protection mask.
pub const HP_MASK_LEN: usize = 5;

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Level {
Expand Down Expand Up @@ -120,6 +123,8 @@ struct EVP_MD {
_unused: c_void,
}

type HeaderProtectionMask = [u8; HP_MASK_LEN];

pub struct Open {
alg: Algorithm,

Expand Down
4 changes: 2 additions & 2 deletions quiche/src/crypto/openssl_quictls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,10 @@ impl HeaderProtectionKey {
})
}

pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
pub fn new_mask(&self, sample: &[u8]) -> Result<HeaderProtectionMask> {
const PLAINTEXT: &[u8; 5] = &[0_u8; 5];

let mut new_mask = [0_u8; 5];
let mut new_mask = HeaderProtectionMask::default();

// Set IV (i.e. the sample).
let rc = unsafe {
Expand Down

0 comments on commit a9e7d47

Please sign in to comment.