diff --git a/Cargo.lock b/Cargo.lock index 0c0d8ee8..96b8d49f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1227,7 +1227,6 @@ version = "0.15.0" dependencies = [ "libc", "log", - "rand", "regex", "rustls", "rustls-platform-verifier", diff --git a/Cargo.toml b/Cargo.toml index 761afe6f..565ea673 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ webpki = { package = "rustls-webpki", version = "0.102.0", default-features = fa libc = "0.2" log = "0.4.22" rustls-platform-verifier = "0.5" -rand = "0.8" regex = "1.9.6" toml = { version = "0.6.0", default-features = false, features = ["parse"] } hickory-resolver = { version = "=0.25.0-alpha.4", features = ["dns-over-https-rustls", "webpki-roots"] } diff --git a/librustls/Cargo.toml b/librustls/Cargo.toml index f3b03507..61a5c50e 100644 --- a/librustls/Cargo.toml +++ b/librustls/Cargo.toml @@ -33,7 +33,6 @@ webpki = { workspace = true } libc = { workspace = true } log = { workspace = true } rustls-platform-verifier = { workspace = true } -rand = { workspace = true } [lib] name = "rustls_ffi" diff --git a/librustls/src/client.rs b/librustls/src/client.rs index 3de52ee8..e7d85f05 100644 --- a/librustls/src/client.rs +++ b/librustls/src/client.rs @@ -454,7 +454,12 @@ impl rustls_client_config_builder { let builder = try_mut_from_ptr!(builder); let hpke = try_ref_from_ptr!(hpke); - let Some((suite, placeholder_pk)) = hpke.grease_public_key() else { + let provider = match &builder.provider { + Some(provider) => provider, + None => return rustls_result::NoDefaultCryptoProvider, + }; + + let Some((suite, placeholder_pk)) = hpke.grease_public_key(provider) else { return rustls_result::HpkeError; }; diff --git a/librustls/src/crypto_provider.rs b/librustls/src/crypto_provider.rs index 3ce5606f..d6fd3759 100644 --- a/librustls/src/crypto_provider.rs +++ b/librustls/src/crypto_provider.rs @@ -2,7 +2,6 @@ use std::slice; use std::sync::Arc; use libc::size_t; -use rand::seq::SliceRandom; #[cfg(feature = "aws-lc-rs")] use rustls::crypto::aws_lc_rs; @@ -509,10 +508,28 @@ impl Hpke { /// /// Returns both the selected Rustls `hpke::Hpke` suite and the `hpke::HpkePublicKey` /// or `None` if an error occurs. - pub(crate) fn grease_public_key(&self) -> Option<(&dyn hpke::Hpke, hpke::HpkePublicKey)> { - let suite = self.suites.choose(&mut rand::thread_rng())?; + pub(crate) fn grease_public_key( + &self, + provider: &CryptoProvider, + ) -> Option<(&dyn hpke::Hpke, hpke::HpkePublicKey)> { + let num_suites = self.suites.len(); + if num_suites == 0 { + return None; + } + debug_assert!(num_suites < u32::MAX as usize); + + let mut buf = [0u8; 4]; + let threshold = u32::MAX - (u32::MAX % num_suites as u32); + let suite = loop { + provider.secure_random.fill(&mut buf).ok()?; + let value = u32::from_ne_bytes(buf); + if value < threshold { + break self.suites[value as usize / (threshold as usize / num_suites)]; + } + }; + let pk = suite.generate_key_pair().map(|pair| pair.0).ok()?; - Some((*suite, pk)) + Some((suite, pk)) } } @@ -625,13 +642,17 @@ mod tests { #[test] #[cfg(feature = "aws-lc-rs")] fn test_hpke_aws_lc_rs() { + let provider = rustls_crypto_provider_default(); + assert!(!provider.is_null()); + let provider = try_clone_arc!(provider); + let hpke = rustls_supported_hpke(); assert!(!hpke.is_null()); let hpke = try_ref_from_ptr!(hpke); // We should be able to pick an HPKE suite and a pubkey for ECH GREASE. - let (suite, pk) = hpke.grease_public_key().unwrap(); + let (suite, pk) = hpke.grease_public_key(&provider).unwrap(); // The PK and the suite should be compatible. Setup a sealer to check. let (_, _) = suite.setup_sealer(&[0xC0, 0xFF, 0xEE], &pk).unwrap(); }