diff --git a/boring/src/ssl/connector.rs b/boring/src/ssl/connector.rs index 5f4759c2..a51e5818 100644 --- a/boring/src/ssl/connector.rs +++ b/boring/src/ssl/connector.rs @@ -269,6 +269,7 @@ impl ConnectConfiguration { /// # Safety /// /// This function is unsafe because it calls an FFI function. + #[cfg(not(feature = "fips"))] #[corresponds(SSL_set_enable_ech_grease)] pub fn set_enable_ech_grease(&mut self, enable: bool) { unsafe { ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable as _) } diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index c0216525..abf92716 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -3658,6 +3658,17 @@ impl SslRef { pub fn ech_accepted(&self) -> bool { unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 } } + + // Whether or not to enable ECH grease on `SSL`. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_set_enable_ech_grease)] + pub fn set_enable_ech_grease(&self, enable: bool) { + let enable = if enable { 1 } else { 0 }; + + unsafe { + ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable); + } + } } /// An SSL stream midway through the handshake process. diff --git a/boring/src/ssl/test/ech.rs b/boring/src/ssl/test/ech.rs index 7413240e..c94a842d 100644 --- a/boring/src/ssl/test/ech.rs +++ b/boring/src/ssl/test/ech.rs @@ -1,6 +1,6 @@ use crate::hpke::HpkeKey; use crate::ssl::ech::SslEchKeys; -use crate::ssl::test::Server; +use crate::ssl::test::server::{ClientSslBuilder, Server}; use crate::ssl::HandshakeError; // 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"); static ECH_CONFIG_2: &[u8] = include_bytes!("../../../test/echconfig-2"); static ECH_KEY_2: &[u8] = include_bytes!("../../../test/echkey-2"); -#[test] -fn ech() { +fn bootstrap_ech(config: &[u8], key: &[u8], list: &[u8]) -> (Server, ClientSslBuilder) { let server = { - let key = HpkeKey::dhkem_p256_sha256(ECH_KEY).unwrap(); + let key = HpkeKey::dhkem_p256_sha256(key).unwrap(); let mut ech_keys = SslEchKeys::new().unwrap(); - ech_keys.add_key(true, ECH_CONFIG, key).unwrap(); + ech_keys.add_key(true, config, key).unwrap(); let mut builder = Server::builder(); builder.ctx().set_ech_keys(ech_keys).unwrap(); @@ -29,35 +28,29 @@ fn ech() { }; let mut client = server.client_with_root_ca().build().builder(); - client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap(); + client.ssl().set_ech_config_list(list).unwrap(); client.ssl().set_hostname("foobar.com").unwrap(); + (server, client) +} + +#[test] +fn ech() { + let (_server, client) = bootstrap_ech(ECH_CONFIG, ECH_KEY, ECH_CONFIG_LIST); + let ssl_stream = client.connect(); assert!(ssl_stream.ssl().ech_accepted()) } #[test] fn ech_rejection() { - let server = { - let key = HpkeKey::dhkem_p256_sha256(ECH_KEY_2).unwrap(); - let mut ech_keys = SslEchKeys::new().unwrap(); - ech_keys.add_key(true, ECH_CONFIG_2, key).unwrap(); - - let mut builder = Server::builder(); - builder.ctx().set_ech_keys(ech_keys).unwrap(); - - builder.build() - }; - - let mut client = server.client_with_root_ca().build().builder(); // Server is initialized using `ECH_CONFIG_2`, so using `ECH_CONFIG_LIST` instead of // `ECH_CONFIG_LIST_2` should trigger rejection. - client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap(); - client.ssl().set_hostname("foobar.com").unwrap(); + let (_server, client) = bootstrap_ech(ECH_CONFIG_2, ECH_KEY_2, ECH_CONFIG_LIST); + let HandshakeError::Failure(failed_ssl_stream) = client.connect_err() else { panic!("wrong HandshakeError failure variant!"); }; - assert_eq!( failed_ssl_stream.ssl().get_ech_name_override(), Some(b"ech.com".to_vec().as_ref()) @@ -65,3 +58,15 @@ fn ech_rejection() { assert!(failed_ssl_stream.ssl().get_ech_retry_configs().is_some()); assert!(!failed_ssl_stream.ssl().ech_accepted()) } + +#[test] +fn ech_grease() { + let server = Server::builder().build(); + + let mut client = server.client_with_root_ca().build().builder(); + // Verified with a pcap locally that the ECH extension gets sent due to GREASE + client.ssl().set_enable_ech_grease(true); + + let ssl_stream = client.connect(); + assert!(!ssl_stream.ssl().ech_accepted()) +}