Skip to content

Commit 497b08a

Browse files
committed
fix(error): return TLS 1.2 PRF setup errors
1 parent 794a6dc commit 497b08a

2 files changed

Lines changed: 58 additions & 28 deletions

File tree

src/alg.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,21 @@ pub(crate) fn ecdh_x25519() -> Result<BCRYPT_ALG_HANDLE, Error> {
3939
}
4040

4141
#[cfg(feature = "tls12")]
42-
pub(crate) fn tls12_kdf() -> BCRYPT_ALG_HANDLE {
43-
static ALG_HANDLE: OnceCell<Handle> = OnceCell::new();
42+
pub(crate) fn tls12_kdf() -> Result<BCRYPT_ALG_HANDLE, Error> {
43+
static ALG_HANDLE: OnceCell<Option<Handle>> = OnceCell::new();
4444
ALG_HANDLE
4545
.get_or_init(|| {
46-
Handle(
47-
load_algorithm(
48-
BCRYPT_TLS1_2_KDF_ALGORITHM,
49-
BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS::default(),
50-
None,
51-
)
52-
.unwrap(),
46+
load_algorithm(
47+
BCRYPT_TLS1_2_KDF_ALGORITHM,
48+
BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS::default(),
49+
None,
5350
)
51+
.ok()
52+
.map(Handle)
5453
})
55-
.0
54+
.as_ref()
55+
.map(|handle| handle.0)
56+
.ok_or_else(|| Error::General("CNG TLS 1.2 KDF algorithm provider unavailable".into()))
5657
}
5758

5859
/// Load an algorithm provider with specified flags, and optional property.

src/prf.rs

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,42 @@ use windows::{
1616

1717
pub(crate) struct Prf<const HASH_SIZE: usize>(pub(crate) Algorithm<HASH_SIZE>);
1818

19-
impl<const HASH_SIZE: usize> rustls::crypto::tls12::Prf for Prf<HASH_SIZE> {
20-
fn for_key_exchange(
19+
fn u32_len(len: usize, name: &str) -> Result<u32, rustls::Error> {
20+
u32::try_from(len).map_err(|_| rustls::Error::General(format!("{name} is too large for CNG")))
21+
}
22+
23+
impl<const HASH_SIZE: usize> Prf<HASH_SIZE> {
24+
fn try_for_secret(
2125
&self,
22-
output: &mut [u8; 48],
23-
kx: Box<dyn ActiveKeyExchange>,
24-
peer_pub_key: &[u8],
26+
output: &mut [u8],
27+
secret: &[u8],
2528
label: &[u8],
2629
seed: &[u8],
2730
) -> Result<(), rustls::Error> {
28-
let secret = kx.complete(peer_pub_key)?;
29-
self.for_secret(output, secret.secret_bytes(), label, seed);
30-
Ok(())
31-
}
32-
33-
fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) {
3431
let mut key = Owned::default();
32+
let tls12_kdf = tls12_kdf()?;
3533

3634
unsafe {
37-
BCryptGenerateSymmetricKey(tls12_kdf(), &mut *key, None, secret, 0)
35+
BCryptGenerateSymmetricKey(tls12_kdf, &mut *key, None, secret, 0)
3836
.ok()
39-
.unwrap();
37+
.map_err(|e| {
38+
rustls::Error::General(format!("TLS 1.2 PRF key import failed: {e}"))
39+
})?;
4040
}
4141

4242
let buffers = [
4343
BCryptBuffer {
44-
cbBuffer: label.len() as u32,
44+
cbBuffer: u32_len(label.len(), "TLS 1.2 PRF label")?,
4545
BufferType: KDF_TLS_PRF_LABEL,
4646
pvBuffer: label.as_ptr() as *mut _,
4747
},
4848
BCryptBuffer {
49-
cbBuffer: seed.len() as u32,
49+
cbBuffer: u32_len(seed.len(), "TLS 1.2 PRF seed")?,
5050
BufferType: KDF_TLS_PRF_SEED,
5151
pvBuffer: seed.as_ptr() as *mut _,
5252
},
5353
BCryptBuffer {
54-
cbBuffer: self.0.id_bytes.len() as u32,
54+
cbBuffer: u32_len(self.0.id_bytes.len(), "TLS 1.2 PRF hash algorithm id")?,
5555
BufferType: KDF_HASH_ALGORITHM,
5656
pvBuffer: self.0.id_bytes.as_ptr() as *mut _,
5757
},
@@ -67,8 +67,31 @@ impl<const HASH_SIZE: usize> rustls::crypto::tls12::Prf for Prf<HASH_SIZE> {
6767
unsafe {
6868
BCryptKeyDerivation(*key, Some(&params), output, &mut size, 0)
6969
.ok()
70-
.unwrap();
70+
.map_err(|e| {
71+
rustls::Error::General(format!("TLS 1.2 PRF derivation failed: {e}"))
72+
})?;
7173
};
74+
75+
Ok(())
76+
}
77+
}
78+
79+
impl<const HASH_SIZE: usize> rustls::crypto::tls12::Prf for Prf<HASH_SIZE> {
80+
fn for_key_exchange(
81+
&self,
82+
output: &mut [u8; 48],
83+
kx: Box<dyn ActiveKeyExchange>,
84+
peer_pub_key: &[u8],
85+
label: &[u8],
86+
seed: &[u8],
87+
) -> Result<(), rustls::Error> {
88+
let secret = kx.complete(peer_pub_key)?;
89+
self.try_for_secret(output, secret.secret_bytes(), label, seed)
90+
}
91+
92+
fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) {
93+
self.try_for_secret(output, secret, label, seed)
94+
.expect("rustls only calls TLS 1.2 PRF for advertised CNG-backed cipher suites")
7295
}
7396

7497
fn fips(&self) -> bool {
@@ -83,7 +106,13 @@ mod test {
83106

84107
use super::super::hash::{SHA256, SHA384};
85108

86-
use super::Prf;
109+
use super::{u32_len, Prf};
110+
111+
#[test]
112+
fn cng_buffer_lengths_fit_in_u32() {
113+
assert_eq!(u32_len(42, "test").unwrap(), 42);
114+
assert!(u32_len(usize::MAX, "test").is_err());
115+
}
87116

88117
#[test]
89118
fn test_sha256() {

0 commit comments

Comments
 (0)