Harden key material zeroization paths
Reduce secret lifetime in HKDF and HMAC internals, avoid extra shared-secret copying in key exchange, and add SHA384 HMAC coverage to guard output sizing.
This commit is contained in:
parent
c71d5bbfd8
commit
bbd0ccf0b8
3 changed files with 32 additions and 12 deletions
|
|
@ -2,6 +2,7 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
use boring::hash::MessageDigest;
|
use boring::hash::MessageDigest;
|
||||||
use rustls::crypto::tls13::{self, Hkdf as RustlsHkdf};
|
use rustls::crypto::tls13::{self, Hkdf as RustlsHkdf};
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use crate::helper::{cvt, cvt_p};
|
use crate::helper::{cvt, cvt_p};
|
||||||
|
|
||||||
|
|
@ -67,7 +68,7 @@ impl<T: BoringHash> RustlsHkdf for Hkdf<T> {
|
||||||
let digest = T::new_hash();
|
let digest = T::new_hash();
|
||||||
let hash_size = digest.size();
|
let hash_size = digest.size();
|
||||||
|
|
||||||
let mut prk = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize];
|
let mut prk = Zeroizing::new([0u8; boring_sys::EVP_MAX_MD_SIZE as usize]);
|
||||||
let mut prk_len = 0;
|
let mut prk_len = 0;
|
||||||
|
|
||||||
// if salt isn't set we usen these bytes here as salt
|
// if salt isn't set we usen these bytes here as salt
|
||||||
|
|
@ -103,7 +104,7 @@ impl<T: BoringHash> RustlsHkdf for Hkdf<T> {
|
||||||
okm: &rustls::crypto::tls13::OkmBlock,
|
okm: &rustls::crypto::tls13::OkmBlock,
|
||||||
) -> Box<dyn rustls::crypto::tls13::HkdfExpander> {
|
) -> Box<dyn rustls::crypto::tls13::HkdfExpander> {
|
||||||
let okm = okm.as_ref();
|
let okm = okm.as_ref();
|
||||||
let mut prk = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize];
|
let mut prk = Zeroizing::new([0u8; boring_sys::EVP_MAX_MD_SIZE as usize]);
|
||||||
let prk_len = okm.len();
|
let prk_len = okm.len();
|
||||||
|
|
||||||
prk[..prk_len].copy_from_slice(okm);
|
prk[..prk_len].copy_from_slice(okm);
|
||||||
|
|
@ -121,7 +122,7 @@ impl<T: BoringHash> RustlsHkdf for Hkdf<T> {
|
||||||
message: &[u8],
|
message: &[u8],
|
||||||
) -> rustls::crypto::hmac::Tag {
|
) -> rustls::crypto::hmac::Tag {
|
||||||
let digest = T::new_hash();
|
let digest = T::new_hash();
|
||||||
let mut hash = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize];
|
let mut hash = Zeroizing::new([0u8; boring_sys::EVP_MAX_MD_SIZE as usize]);
|
||||||
let mut hash_len = 0u32;
|
let mut hash_len = 0u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
cvt_p(boring_sys::HMAC(
|
cvt_p(boring_sys::HMAC(
|
||||||
|
|
@ -140,7 +141,7 @@ impl<T: BoringHash> RustlsHkdf for Hkdf<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HkdfExpander {
|
struct HkdfExpander {
|
||||||
prk: [u8; boring_sys::EVP_MAX_MD_SIZE as usize],
|
prk: Zeroizing<[u8; boring_sys::EVP_MAX_MD_SIZE as usize]>,
|
||||||
prk_len: usize,
|
prk_len: usize,
|
||||||
digest: MessageDigest,
|
digest: MessageDigest,
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +188,7 @@ impl tls13::HkdfExpander for HkdfExpander {
|
||||||
/// This is infallible, because by definition `OkmBlock` is always exactly
|
/// This is infallible, because by definition `OkmBlock` is always exactly
|
||||||
/// `HashLen` bytes long.
|
/// `HashLen` bytes long.
|
||||||
fn expand_block(&self, info: &[&[u8]]) -> tls13::OkmBlock {
|
fn expand_block(&self, info: &[&[u8]]) -> tls13::OkmBlock {
|
||||||
let mut output = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize];
|
let mut output = Zeroizing::new([0u8; boring_sys::EVP_MAX_MD_SIZE as usize]);
|
||||||
let output_len = self.hash_len();
|
let output_len = self.hash_len();
|
||||||
|
|
||||||
self.expand_slice(info, &mut output[..output_len])
|
self.expand_slice(info, &mut output[..output_len])
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use boring::hash::MessageDigest;
|
||||||
use boring_additions::hmac::HmacCtx;
|
use boring_additions::hmac::HmacCtx;
|
||||||
use foreign_types::ForeignType;
|
use foreign_types::ForeignType;
|
||||||
use rustls::crypto;
|
use rustls::crypto;
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use crate::helper::{cvt, cvt_p};
|
use crate::helper::{cvt, cvt_p};
|
||||||
|
|
||||||
|
|
@ -30,7 +31,7 @@ impl crypto::hmac::Hmac for BoringHmac {
|
||||||
Box::new(BoringHmacKey {
|
Box::new(BoringHmacKey {
|
||||||
ctx,
|
ctx,
|
||||||
md,
|
md,
|
||||||
key: key.to_vec(),
|
key: Zeroizing::new(key.to_vec()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,11 +42,10 @@ impl crypto::hmac::Hmac for BoringHmac {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct BoringHmacKey {
|
struct BoringHmacKey {
|
||||||
ctx: HmacCtx,
|
ctx: HmacCtx,
|
||||||
md: MessageDigest,
|
md: MessageDigest,
|
||||||
key: Vec<u8>,
|
key: Zeroizing<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoringHmacKey {
|
impl BoringHmacKey {
|
||||||
|
|
@ -99,8 +99,8 @@ impl crypto::hmac::Key for BoringHmacKey {
|
||||||
|
|
||||||
self.update(last);
|
self.update(last);
|
||||||
|
|
||||||
let mut out = [0u8; 32];
|
let mut out = Zeroizing::new([0u8; boring_sys::EVP_MAX_MD_SIZE as usize]);
|
||||||
let out_len = self.finish(&mut out);
|
let out_len = self.finish(&mut out[..]);
|
||||||
|
|
||||||
crypto::hmac::Tag::new(&out[..out_len])
|
crypto::hmac::Tag::new(&out[..out_len])
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +112,7 @@ impl crypto::hmac::Key for BoringHmacKey {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::SHA256;
|
use super::{SHA256, SHA384};
|
||||||
use hex_literal::hex;
|
use hex_literal::hex;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -141,4 +141,23 @@ mod tests {
|
||||||
hex!("11fa4a6ee97bebfad9e1087145c556fec9a786cad0659aa10702d21bd2968305")
|
hex!("11fa4a6ee97bebfad9e1087145c556fec9a786cad0659aa10702d21bd2968305")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sha384_hmac_len() {
|
||||||
|
let hasher = SHA384.with_key("Very Secret".as_bytes());
|
||||||
|
|
||||||
|
let tag = hasher.sign_concat(
|
||||||
|
&[],
|
||||||
|
&[
|
||||||
|
"yay".as_bytes(),
|
||||||
|
"this".as_bytes(),
|
||||||
|
"works".as_bytes(),
|
||||||
|
"well".as_bytes(),
|
||||||
|
],
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(tag.as_ref().len(), hasher.tag_len());
|
||||||
|
assert_eq!(tag.as_ref().len(), 48);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ impl crypto::ActiveKeyExchange for KeyExchange {
|
||||||
peer_pub_key: &[u8],
|
peer_pub_key: &[u8],
|
||||||
) -> Result<crypto::SharedSecret, rustls::Error> {
|
) -> Result<crypto::SharedSecret, rustls::Error> {
|
||||||
self.diffie_hellman(peer_pub_key)
|
self.diffie_hellman(peer_pub_key)
|
||||||
.map(|x| crypto::SharedSecret::from(x.as_slice()))
|
.map(crypto::SharedSecret::from)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
log_and_map(
|
log_and_map(
|
||||||
"ex::KeyExchange::diffie_hellman",
|
"ex::KeyExchange::diffie_hellman",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue