Skip to content

Commit e82939f

Browse files
0x676e67bwesterbghedoevanrittenhousekornelski
authored
Expose SSL_set_enable_ech_grease (#49)
* RTG-3333 Support X25519MLKEM768 by default, but don't sent it as client X25519MLKEM768 is the standardised successor of the preliminary X25519Kyber768Draft00. Latest browsers have switched to X25519MLKEM768. Cloudflare supports both on the edge. We've had support for X25519MLKEM768 in this crate for a while, but didn't enable by default. We're now enabling serverside support by default. We also let clients advertise support when set to kx-client-pq-supported. We don't enable support by default yet for clients set to kx-client-pq-preferred, as that would cause an extra round-trip due to HelloRetryRequest if the server doesn't support X25519MLKEM768 yet. BoringSSL against which we build must support X25519MLKEM768, otherwise this will fail. * replace once_cell with LazyLock We can drop the once_cell dependency since the same functionality is implemented in std now. Requires bumping MSRV to 1.80. * fix manual_c_str_literals clippy warning * chore: Fix docs on SslRef::replace_ex_data * Detailed error codes * Clean up boring_sys::init() We don't need the workaround that was initially introduced for a bug in openssl, and OPENSSL_init_ssl always calls into CRYPTO_library_init on boringssl, so just call it explicitly. * Expose EVP_HPKE_KEY * Expose client/server-side ECH Resolves cloudflare/boring#282 * Clean up ECH tests * Expose SSL_set_enable_ech_grease * update --------- Co-authored-by: Bas Westerbaan <[email protected]> Co-authored-by: Alessandro Ghedini <[email protected]> Co-authored-by: Evan Rittenhouse <[email protected]> Co-authored-by: Kornel <[email protected]> Co-authored-by: Rushil Mehra <[email protected]>
1 parent d1f73a9 commit e82939f

File tree

3 files changed

+38
-21
lines changed

3 files changed

+38
-21
lines changed

boring/src/ssl/connector.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ impl ConnectConfiguration {
269269
/// # Safety
270270
///
271271
/// This function is unsafe because it calls an FFI function.
272+
#[cfg(not(feature = "fips"))]
272273
#[corresponds(SSL_set_enable_ech_grease)]
273274
pub fn set_enable_ech_grease(&mut self, enable: bool) {
274275
unsafe { ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable as _) }

boring/src/ssl/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,6 +3658,17 @@ impl SslRef {
36583658
pub fn ech_accepted(&self) -> bool {
36593659
unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 }
36603660
}
3661+
3662+
// Whether or not to enable ECH grease on `SSL`.
3663+
#[cfg(not(feature = "fips"))]
3664+
#[corresponds(SSL_set_enable_ech_grease)]
3665+
pub fn set_enable_ech_grease(&self, enable: bool) {
3666+
let enable = if enable { 1 } else { 0 };
3667+
3668+
unsafe {
3669+
ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable);
3670+
}
3671+
}
36613672
}
36623673

36633674
/// An SSL stream midway through the handshake process.

boring/src/ssl/test/ech.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::hpke::HpkeKey;
22
use crate::ssl::ech::SslEchKeys;
3-
use crate::ssl::test::Server;
3+
use crate::ssl::test::server::{ClientSslBuilder, Server};
44
use crate::ssl::HandshakeError;
55

66
// For future reference, these configs are generated by building the bssl tool (the binary is built
@@ -15,12 +15,11 @@ static ECH_KEY: &[u8] = include_bytes!("../../../test/echkey");
1515
static ECH_CONFIG_2: &[u8] = include_bytes!("../../../test/echconfig-2");
1616
static ECH_KEY_2: &[u8] = include_bytes!("../../../test/echkey-2");
1717

18-
#[test]
19-
fn ech() {
18+
fn bootstrap_ech(config: &[u8], key: &[u8], list: &[u8]) -> (Server, ClientSslBuilder) {
2019
let server = {
21-
let key = HpkeKey::dhkem_p256_sha256(ECH_KEY).unwrap();
20+
let key = HpkeKey::dhkem_p256_sha256(key).unwrap();
2221
let mut ech_keys = SslEchKeys::new().unwrap();
23-
ech_keys.add_key(true, ECH_CONFIG, key).unwrap();
22+
ech_keys.add_key(true, config, key).unwrap();
2423

2524
let mut builder = Server::builder();
2625
builder.ctx().set_ech_keys(ech_keys).unwrap();
@@ -29,39 +28,45 @@ fn ech() {
2928
};
3029

3130
let mut client = server.client_with_root_ca().build().builder();
32-
client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap();
31+
client.ssl().set_ech_config_list(list).unwrap();
3332
client.ssl().set_hostname("foobar.com").unwrap();
3433

34+
(server, client)
35+
}
36+
37+
#[test]
38+
fn ech() {
39+
let (_server, client) = bootstrap_ech(ECH_CONFIG, ECH_KEY, ECH_CONFIG_LIST);
40+
3541
let ssl_stream = client.connect();
3642
assert!(ssl_stream.ssl().ech_accepted())
3743
}
3844

3945
#[test]
4046
fn ech_rejection() {
41-
let server = {
42-
let key = HpkeKey::dhkem_p256_sha256(ECH_KEY_2).unwrap();
43-
let mut ech_keys = SslEchKeys::new().unwrap();
44-
ech_keys.add_key(true, ECH_CONFIG_2, key).unwrap();
45-
46-
let mut builder = Server::builder();
47-
builder.ctx().set_ech_keys(ech_keys).unwrap();
48-
49-
builder.build()
50-
};
51-
52-
let mut client = server.client_with_root_ca().build().builder();
5347
// Server is initialized using `ECH_CONFIG_2`, so using `ECH_CONFIG_LIST` instead of
5448
// `ECH_CONFIG_LIST_2` should trigger rejection.
55-
client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap();
56-
client.ssl().set_hostname("foobar.com").unwrap();
49+
let (_server, client) = bootstrap_ech(ECH_CONFIG_2, ECH_KEY_2, ECH_CONFIG_LIST);
50+
5751
let HandshakeError::Failure(failed_ssl_stream) = client.connect_err() else {
5852
panic!("wrong HandshakeError failure variant!");
5953
};
60-
6154
assert_eq!(
6255
failed_ssl_stream.ssl().get_ech_name_override(),
6356
Some(b"ech.com".to_vec().as_ref())
6457
);
6558
assert!(failed_ssl_stream.ssl().get_ech_retry_configs().is_some());
6659
assert!(!failed_ssl_stream.ssl().ech_accepted())
6760
}
61+
62+
#[test]
63+
fn ech_grease() {
64+
let server = Server::builder().build();
65+
66+
let mut client = server.client_with_root_ca().build().builder();
67+
// Verified with a pcap locally that the ECH extension gets sent due to GREASE
68+
client.ssl().set_enable_ech_grease(true);
69+
70+
let ssl_stream = client.connect();
71+
assert!(!ssl_stream.ssl().ech_accepted())
72+
}

0 commit comments

Comments
 (0)