From 6341199f06554603cb247e3d590c82a9ca3f9fc1 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Mon, 1 Dec 2025 18:27:21 +0000 Subject: [PATCH 01/25] Add feature gated boringssl harness --- .../standard/tls-harness/.cargo/config.toml | 3 + bindings/rust/standard/tls-harness/Cargo.toml | 11 +- .../tls-harness/src/cohort/boringssl.rs | 219 ++++++++++++++++++ .../standard/tls-harness/src/cohort/mod.rs | 6 + .../standard/tls-harness/src/harness/io.rs | 11 +- bindings/rust/standard/tls-harness/src/lib.rs | 1 + 6 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 bindings/rust/standard/tls-harness/.cargo/config.toml create mode 100644 bindings/rust/standard/tls-harness/src/cohort/boringssl.rs diff --git a/bindings/rust/standard/tls-harness/.cargo/config.toml b/bindings/rust/standard/tls-harness/.cargo/config.toml new file mode 100644 index 00000000000..0850c6255ba --- /dev/null +++ b/bindings/rust/standard/tls-harness/.cargo/config.toml @@ -0,0 +1,3 @@ +[env] +BORING_BSSL_FIPS = "0" +BORING_BSSL_PREFIX = "BORING_TLS_HARNESS" diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index 45783415a4e..77cb975f4b8 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -4,6 +4,11 @@ version = "0.1.0" edition = "2021" publish = false +[features] +default = ["openssl"] +openssl = ["dep:openssl", "dep:openssl-sys"] +boringssl = ["dep:boring", "dep:boring-sys"] + [dependencies] s2n-tls = { path = "../../extended/s2n-tls" } errno = "0.3.13" @@ -11,8 +16,10 @@ libc = "0.2.174" strum = { version = "0.27", features = ["derive"] } rustls = "0.23.31" rustls-pemfile = "2.2.0" -openssl = { version = "0.10.73", features = ["vendored"] } -openssl-sys = "0.9.109" +openssl = { version = "0.10.73", features = ["vendored"], optional = true } +openssl-sys = { version = "0.9.109", optional = true } +boring = { version = "4", optional = true } +boring-sys = { version = "4", optional = true } byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" diff --git a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs new file mode 100644 index 00000000000..c2e66e555ab --- /dev/null +++ b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs @@ -0,0 +1,219 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + get_cert_path, + harness::{self, Mode, TlsConfigBuilder, TlsConnection, TlsInfo, ViewIO}, + PemType +}; +use boring::ssl::{ + ErrorCode, ShutdownResult, Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, + SslSession, SslStream, SslVersion +}; +use std::{ + error::Error, + io::{Read, Write}, + sync::{Arc, Mutex} +}; + +// Creates session ticket callback handler +#[derive(Clone, Default)] +pub struct BoringSessionTicketStorage { + pub stored_ticket: Arc>>, +} + +pub struct BoringSslConnection { + connection: SslStream, +} + +pub struct BoringSslConfig { + pub config: SslContext, + pub session_ticket_storage: BoringSessionTicketStorage, +} + +impl From for BoringSslConfig { + fn from(value: SslContext) -> Self { + BoringSslConfig { + config: value, + session_ticket_storage: Default::default(), + } + } +} + +impl TlsConnection for BoringSslConnection { + type Config = BoringSslConfig; + + fn new_from_config( + mode: harness::Mode, + config: &Self::Config, + io: &harness::TestPairIO, + ) -> Result> { + // check if there is a session ticket available + // a session ticket will only be available if the Config was created + // with session resumption enabled + let maybe_ticket = config + .session_ticket_storage + .stored_ticket + .lock() + .unwrap() + .take(); + if let Some(ticket) = &maybe_ticket { + let _result = unsafe { config.config.add_session(ticket) }; + } + + let mut connection = Ssl::new(&config.config)?; + if let Some(ticket) = &maybe_ticket { + unsafe { connection.set_session(ticket)? }; + } + + let io = match mode { + Mode::Client => io.client_view(), + Mode::Server => io.server_view(), + }; + + let connection = SslStream::new(connection, io)?; + Ok(Self { connection }) + } + + fn handshake(&mut self) -> Result<(), Box> { + let result = if self.connection.ssl().is_server() { + self.connection.accept() + } else { + self.connection.connect() + }; + + // treat blocking (`ErrorCode::WANT_READ`) as `Ok`, expected during handshake + match result { + Ok(_) => Ok(()), + Err(err) => { + if err.code() != ErrorCode::WANT_READ { + Err(err.into()) + } else { + Ok(()) + } + } + } + } + + fn handshake_completed(&self) -> bool { + self.connection.ssl().is_init_finished() + } + + fn send(&mut self, data: &[u8]) { + let mut write_offset = 0; + while write_offset < data.len() { + write_offset += self + .connection + .write(&data[write_offset..data.len()]) + .unwrap(); + self.connection.flush().unwrap(); // make sure internal buffers don't fill up + } + } + + fn recv(&mut self, data: &mut [u8]) -> std::io::Result<()> { + let data_len = data.len(); + let mut read_offset = 0; + while read_offset < data.len() { + read_offset += self.connection.read(&mut data[read_offset..data_len])? + } + Ok(()) + } + + fn shutdown_send(&mut self) { + // this method will not read in a CloseNotify + assert_eq!(self.connection.shutdown().unwrap(), ShutdownResult::Sent); + } + + fn shutdown_finish(&mut self) -> bool { + self.connection.shutdown().unwrap() == ShutdownResult::Received + } +} + +impl TlsInfo for BoringSslConnection { + fn name() -> String { + // boring doesn't expose an OpenSSL-style numeric version; just use a simple tag + "boringssl".to_string() + } + + fn get_negotiated_cipher_suite(&self) -> String { + let cipher_suite = self + .connection + .ssl() + .current_cipher() + .expect("Handshake not completed") + .name(); + cipher_suite.to_string() + } + + fn negotiated_tls13(&self) -> bool { + self.connection + .ssl() + .version2() // same enum-style API as openssl + .expect("Handshake not completed") + == SslVersion::TLS1_3 + } + + fn resumed_connection(&self) -> bool { + self.connection.ssl().session_reused() + } + + fn mutual_auth(&self) -> bool { + let ssl = self.connection.ssl(); + + let has_chain = ssl.peer_cert_chain().is_some(); + let ok = ssl.verify_result().is_ok(); + + has_chain && ok + } +} + +impl TlsConfigBuilder for SslContextBuilder { + type Config = BoringSslConfig; + + fn new_test_config(mode: Mode) -> Self { + let mut builder = match mode { + Mode::Client => SslContext::builder(SslMethod::tls_client()).unwrap(), + Mode::Server => SslContext::builder(SslMethod::tls_server()).unwrap(), + }; + builder + } + + fn set_chain(&mut self, sig_type: crate::SigType) { + self.set_certificate_chain_file(get_cert_path(PemType::ServerCertChain, sig_type)) + .unwrap(); + self.set_private_key_file( + get_cert_path(PemType::ServerKey, sig_type), + SslFiletype::PEM, + ) + .unwrap(); + } + + fn set_trust(&mut self, sig_type: crate::SigType) { + self.set_ca_file(get_cert_path(PemType::CACert, sig_type)) + .unwrap(); + } + + fn build(self) -> Self::Config { + BoringSslConfig { + config: self.build(), + session_ticket_storage: BoringSessionTicketStorage::default(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::test_utilities; + + use super::*; + + #[test] + fn handshake() { + test_utilities::handshake::(); + } + + #[test] + fn transfer() { + test_utilities::transfer::(); + } +} \ No newline at end of file diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index cd4e5e15e49..82a1b2720a1 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -9,10 +9,16 @@ //! Modules are also public so that utility structs can be accessed, like //! `cohort::s2n_tls::SessionTicketStorage`. +#[cfg(feature = "openssl")] pub mod openssl; +#[cfg(feature = "boringssl")] +pub mod boringssl; pub mod rustls; pub mod s2n_tls; +#[cfg(feature = "openssl")] pub use openssl::{OpenSslConfig, OpenSslConnection}; +#[cfg(feature = "boringssl")] +pub use boringssl::{BoringSslConfig, BoringSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; pub use s2n_tls::{S2NConfig, S2NConnection}; diff --git a/bindings/rust/standard/tls-harness/src/harness/io.rs b/bindings/rust/standard/tls-harness/src/harness/io.rs index 590547a53e5..f50c4bd7b78 100644 --- a/bindings/rust/standard/tls-harness/src/harness/io.rs +++ b/bindings/rust/standard/tls-harness/src/harness/io.rs @@ -176,14 +176,18 @@ impl std::io::Write for ViewIO { mod tests { use std::collections::HashMap; + #[cfg(feature = "openssl")] use openssl::ssl::SslContextBuilder; use crate::{ - cohort::{rustls::RustlsConfigBuilder, OpenSslConnection, RustlsConnection, S2NConnection}, + cohort::{rustls::RustlsConfigBuilder, RustlsConnection, S2NConnection}, harness::TlsConfigBuilderPair, TlsConnPair, }; + #[cfg(feature = "openssl")] + use crate::cohort::OpenSslConnection; + use super::*; #[test] @@ -210,10 +214,13 @@ mod tests { #[test] fn implementation_record_size() { const S2N_RECORD_DEFAULT: u16 = 8104; - const OPENSSL_RECORD_DEFAULT: u16 = 16401; const RUSTLS_RECORD_DEFAULT: u16 = 16401; + #[cfg(feature = "openssl")] + const OPENSSL_RECORD_DEFAULT: u16 = 16401; + // openssl & s2n + #[cfg(feature = "openssl")] { let mut pair: TlsConnPair = { let configs = diff --git a/bindings/rust/standard/tls-harness/src/lib.rs b/bindings/rust/standard/tls-harness/src/lib.rs index 6685e0ec503..c894ddeee26 100644 --- a/bindings/rust/standard/tls-harness/src/lib.rs +++ b/bindings/rust/standard/tls-harness/src/lib.rs @@ -3,6 +3,7 @@ pub mod cohort; pub mod harness; +#[cfg(feature = "openssl")] pub mod openssl_extension; #[cfg(test)] pub mod test_utilities; From 57a190abaa5254c16913ef250ae9abbfa9c3dca1 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Mon, 8 Dec 2025 21:01:46 +0000 Subject: [PATCH 02/25] Add boringssl harness --- bindings/rust/standard/tls-harness/Cargo.toml | 8 +- .../tls-harness/src/cohort/boringssl.rs | 95 +++++++++---------- .../standard/tls-harness/src/cohort/mod.rs | 4 +- 3 files changed, 49 insertions(+), 58 deletions(-) diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index 77cb975f4b8..c4fc726ff61 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -7,7 +7,6 @@ publish = false [features] default = ["openssl"] openssl = ["dep:openssl", "dep:openssl-sys"] -boringssl = ["dep:boring", "dep:boring-sys"] [dependencies] s2n-tls = { path = "../../extended/s2n-tls" } @@ -18,13 +17,16 @@ rustls = "0.23.31" rustls-pemfile = "2.2.0" openssl = { version = "0.10.73", features = ["vendored"], optional = true } openssl-sys = { version = "0.9.109", optional = true } -boring = { version = "4", optional = true } -boring-sys = { version = "4", optional = true } byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" brass-aphid-wire-messages = "0.0.1" +[dependencies.boring] +git = "https://github.com/kaukabrizvi/boring.git" +branch = "symbol-prefixing" +features = ["prefix-symbols"] + [dev-dependencies] # env_logger and log are used to enable logging for rustls, which can help with # debugging interop failures diff --git a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs index c2e66e555ab..ddaaeb3ad7c 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs @@ -4,37 +4,38 @@ use crate::{ get_cert_path, harness::{self, Mode, TlsConfigBuilder, TlsConnection, TlsInfo, ViewIO}, - PemType + PemType, }; use boring::ssl::{ ErrorCode, ShutdownResult, Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, - SslSession, SslStream, SslVersion + SslSession, SslStream, SslVersion, }; use std::{ error::Error, io::{Read, Write}, - sync::{Arc, Mutex} + sync::{Arc, Mutex}, }; // Creates session ticket callback handler #[derive(Clone, Default)] -pub struct BoringSessionTicketStorage { +pub struct SessionTicketStorage { pub stored_ticket: Arc>>, } pub struct BoringSslConnection { + mode: Mode, connection: SslStream, } pub struct BoringSslConfig { pub config: SslContext, - pub session_ticket_storage: BoringSessionTicketStorage, + pub session_ticket_storage: SessionTicketStorage, } impl From for BoringSslConfig { - fn from(value: SslContext) -> Self { + fn from(ctx: SslContext) -> Self { BoringSslConfig { - config: value, + config: ctx, session_ticket_storage: Default::default(), } } @@ -48,50 +49,42 @@ impl TlsConnection for BoringSslConnection { config: &Self::Config, io: &harness::TestPairIO, ) -> Result> { - // check if there is a session ticket available - // a session ticket will only be available if the Config was created - // with session resumption enabled - let maybe_ticket = config - .session_ticket_storage - .stored_ticket - .lock() - .unwrap() - .take(); - if let Some(ticket) = &maybe_ticket { - let _result = unsafe { config.config.add_session(ticket) }; - } - - let mut connection = Ssl::new(&config.config)?; - if let Some(ticket) = &maybe_ticket { - unsafe { connection.set_session(ticket)? }; - } + // No tickets/resumption yet: keep it simple + let ssl = Ssl::new(&config.config)?; - let io = match mode { + let view = match mode { Mode::Client => io.client_view(), Mode::Server => io.server_view(), }; - let connection = SslStream::new(connection, io)?; - Ok(Self { connection }) + let stream = SslStream::new(ssl, view)?; + Ok(Self { + mode, + connection: stream, + }) } - fn handshake(&mut self) -> Result<(), Box> { - let result = if self.connection.ssl().is_server() { - self.connection.accept() - } else { - self.connection.connect() + fn handshake(&mut self) -> Result<(), Box> { + // If the handshake is already complete, no further work is needed. + if self.connection.ssl().is_init_finished() { + return Ok(()); + } + + // Drive handshake based on configured mode. + let result = match self.mode { + Mode::Server => self.connection.accept(), + Mode::Client => self.connection.connect(), }; - // treat blocking (`ErrorCode::WANT_READ`) as `Ok`, expected during handshake match result { + // Completed a handshake step — not necessarily “done” yet. Ok(_) => Ok(()), - Err(err) => { - if err.code() != ErrorCode::WANT_READ { - Err(err.into()) - } else { - Ok(()) - } - } + + // Nonblocking WANT_READ / WANT_WRITE are normal while handshaking. + Err(err) => match err.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Ok(()), + _ => Err(err.into()), + }, } } @@ -131,7 +124,8 @@ impl TlsConnection for BoringSslConnection { impl TlsInfo for BoringSslConnection { fn name() -> String { - // boring doesn't expose an OpenSSL-style numeric version; just use a simple tag + // BoringSSL doesn't expose a version number in the same way as OpenSSL + // It's typically identified just as "boringssl" "boringssl".to_string() } @@ -148,7 +142,7 @@ impl TlsInfo for BoringSslConnection { fn negotiated_tls13(&self) -> bool { self.connection .ssl() - .version2() // same enum-style API as openssl + .version2() .expect("Handshake not completed") == SslVersion::TLS1_3 } @@ -158,12 +152,8 @@ impl TlsInfo for BoringSslConnection { } fn mutual_auth(&self) -> bool { - let ssl = self.connection.ssl(); - - let has_chain = ssl.peer_cert_chain().is_some(); - let ok = ssl.verify_result().is_ok(); - - has_chain && ok + assert!(self.connection.ssl().is_server()); + self.connection.ssl().peer_certificate().is_some() } } @@ -171,10 +161,11 @@ impl TlsConfigBuilder for SslContextBuilder { type Config = BoringSslConfig; fn new_test_config(mode: Mode) -> Self { - let mut builder = match mode { + let builder = match mode { Mode::Client => SslContext::builder(SslMethod::tls_client()).unwrap(), Mode::Server => SslContext::builder(SslMethod::tls_server()).unwrap(), }; + // Note: BoringSSL doesn't have set_security_level like OpenSSL builder } @@ -196,7 +187,7 @@ impl TlsConfigBuilder for SslContextBuilder { fn build(self) -> Self::Config { BoringSslConfig { config: self.build(), - session_ticket_storage: BoringSessionTicketStorage::default(), + session_ticket_storage: SessionTicketStorage::default(), } } } @@ -206,7 +197,7 @@ mod tests { use crate::test_utilities; use super::*; - + #[test] fn handshake() { test_utilities::handshake::(); @@ -216,4 +207,4 @@ mod tests { fn transfer() { test_utilities::transfer::(); } -} \ No newline at end of file +} diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index 82a1b2720a1..6a4ed26f57f 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -11,14 +11,12 @@ #[cfg(feature = "openssl")] pub mod openssl; -#[cfg(feature = "boringssl")] pub mod boringssl; pub mod rustls; pub mod s2n_tls; #[cfg(feature = "openssl")] pub use openssl::{OpenSslConfig, OpenSslConnection}; -#[cfg(feature = "boringssl")] pub use boringssl::{BoringSslConfig, BoringSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; -pub use s2n_tls::{S2NConfig, S2NConnection}; +pub use s2n_tls::{S2NConfig, S2NConnection}; \ No newline at end of file From fad110fc76ea811c9b196be4ee1691afa66fb0e2 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Mon, 8 Dec 2025 23:27:18 +0000 Subject: [PATCH 03/25] Type changes since rebase --- bindings/rust/standard/tls-harness/src/cohort/boringssl.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs index ddaaeb3ad7c..bfac9bc6e76 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs @@ -13,6 +13,7 @@ use boring::ssl::{ use std::{ error::Error, io::{Read, Write}, + rc::Rc, sync::{Arc, Mutex}, }; @@ -47,7 +48,7 @@ impl TlsConnection for BoringSslConnection { fn new_from_config( mode: harness::Mode, config: &Self::Config, - io: &harness::TestPairIO, + io: &Rc, ) -> Result> { // No tickets/resumption yet: keep it simple let ssl = Ssl::new(&config.config)?; From feeff694a511463dfa51a02bde7929fae877d9b9 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 01:01:22 +0000 Subject: [PATCH 04/25] Add mtls tests cases for boringssl --- bindings/rust/standard/integration/Cargo.toml | 5 + .../rust/standard/integration/src/mtls/mod.rs | 230 +++++++++++++++++- 2 files changed, 228 insertions(+), 7 deletions(-) diff --git a/bindings/rust/standard/integration/Cargo.toml b/bindings/rust/standard/integration/Cargo.toml index 9bd4e9007af..dc94deb3999 100644 --- a/bindings/rust/standard/integration/Cargo.toml +++ b/bindings/rust/standard/integration/Cargo.toml @@ -48,6 +48,11 @@ hyper-util = "0.1" dhat = "0.3.3" tabled = "0.20.0" +[dev-dependencies.boring] +git = "https://github.com/kaukabrizvi/boring.git" +branch = "symbol-prefixing" +features = ["prefix-symbols"] + [build-dependencies] # The ML-DSA tests require the ML-DSA support added in Openssl-3.5 # Since this overrides the dependency from the openssl-src crate, diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index c4d37ed780d..bc6d0b80cd1 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -41,7 +41,7 @@ use s2n_tls_sys::{ }; use tls_harness::{ - cohort::{RustlsConfig, RustlsConnection, S2NConfig, S2NConnection}, + cohort::{BoringSslConfig, BoringSslConnection, RustlsConfig, RustlsConnection, S2NConfig, S2NConnection}, harness::{read_to_bytes, TlsConfigBuilder}, PemType, SigType, TlsConnPair, TlsConnection, }; @@ -210,6 +210,44 @@ fn rustls_mtls_server( server.into() } +fn boringssl_mtls_client(sig_type: SigType) -> BoringSslConfig { + use tls_harness::harness::{Mode, TlsConfigBuilder}; + + let mut builder = boring::ssl::SslContextBuilder::new_test_config(Mode::Client); + builder.set_trust(sig_type); + + // Set client certificate and key + builder + .set_certificate_chain_file(tls_harness::get_cert_path(PemType::ClientCertChain, sig_type)) + .unwrap(); + builder + .set_private_key_file( + tls_harness::get_cert_path(PemType::ClientKey, sig_type), + boring::ssl::SslFiletype::PEM, + ) + .unwrap(); + builder.set_verify(boring::ssl::SslVerifyMode::PEER); + + BoringSslConfig { + config: builder.build(), + session_ticket_storage: Default::default(), + } +} + +fn boringssl_mtls_server(sig_type: SigType) -> BoringSslConfig { + use tls_harness::harness::{Mode, TlsConfigBuilder}; + + let mut builder = boring::ssl::SslContextBuilder::new_test_config(Mode::Server); + builder.set_chain(sig_type); + builder.set_trust(sig_type); + builder.set_verify(boring::ssl::SslVerifyMode::PEER | boring::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT); + + BoringSslConfig { + config: builder.build(), + session_ticket_storage: Default::default(), + } +} + // ============================================================================ // Basic mTLS tests // ============================================================================ @@ -227,7 +265,7 @@ where // s2n client, rustls server #[test] -fn s2n_client_basic() { +fn rustls_server_basic() { // TLS 1.2 let client = { let builder = s2n_mtls_base_builder(SigType::Rsa2048); @@ -252,7 +290,7 @@ fn s2n_client_basic() { // rustls client, s2n server #[test] -fn s2n_server_basic() { +fn rustls_client_basic() { // TLS 1.2 let client = rustls_mtls_client(SigType::Rsa2048, &rustls::version::TLS12); let server = { @@ -275,6 +313,56 @@ fn s2n_server_basic() { ); } +// s2n client, boringssl server +#[test] +fn boringssl_server_basic() { + // TLS 1.2 + let client = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + S2NConfig::from(builder.build().unwrap()) + }; + let server = boringssl_mtls_server(SigType::Rsa2048); + test_basic::(&client, &server); + + // TLS 1.3 + crate::capability_check::required_capability( + &[crate::capability_check::Capability::Tls13], + || { + let client = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + S2NConfig::from(builder.build().unwrap()) + }; + let server = boringssl_mtls_server(SigType::Rsa2048); + test_basic::(&client, &server); + }, + ); +} + +// boringssl client, s2n server +#[test] +fn boringssl_client_basic() { + // TLS 1.2 + let client = boringssl_mtls_client(SigType::Rsa2048); + let server = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + S2NConfig::from(builder.build().unwrap()) + }; + test_basic::(&client, &server); + + // TLS 1.3 + crate::capability_check::required_capability( + &[crate::capability_check::Capability::Tls13], + || { + let client = boringssl_mtls_client(SigType::Rsa2048); + let server = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + S2NConfig::from(builder.build().unwrap()) + }; + test_basic::(&client, &server); + }, + ); +} + // ============================================================================ // Sync callback tests // ============================================================================ @@ -294,7 +382,7 @@ where // s2n client with sync callback, rustls server #[test] -fn s2n_client_sync_callback() { +fn rustls_server_sync_callback() { // TLS 1.2 let (client, handle) = { let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); @@ -326,7 +414,7 @@ fn s2n_client_sync_callback() { // rustls client, s2n server with sync callback #[test] -fn s2n_server_sync_callback() { +fn rustls_client_sync_callback() { // TLS 1.2 let client = rustls_mtls_client(SigType::Rsa2048, &rustls::version::TLS12); let (server, handle) = { @@ -357,6 +445,68 @@ fn s2n_server_sync_callback() { ); } +// s2n client with sync callback, boringssl server +#[test] +fn boringssl_server_sync_callback() { + // TLS 1.2 + let (client, handle) = { + let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); + let cb = TestCertValidationCallback::new_sync(); + let invoked = Arc::clone(cb.invoked_count()); + builder.set_cert_validation_callback_sync(cb).unwrap(); + (S2NConfig::from(builder.build().unwrap()), invoked) + }; + let server = boringssl_mtls_server(SigType::Rsa2048); + test_sync_callback::(&client, &server, handle); + + // TLS 1.3 + crate::capability_check::required_capability( + &[crate::capability_check::Capability::Tls13], + || { + let (client, handle) = { + let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); + let cb = TestCertValidationCallback::new_sync(); + let invoked = Arc::clone(cb.invoked_count()); + builder.set_cert_validation_callback_sync(cb).unwrap(); + (S2NConfig::from(builder.build().unwrap()), invoked) + }; + let server = boringssl_mtls_server(SigType::Rsa2048); + test_sync_callback::(&client, &server, handle); + }, + ); +} + +// boringssl client, s2n server with sync callback +#[test] +fn boringssl_client_sync_callback() { + // TLS 1.2 + let client = boringssl_mtls_client(SigType::Rsa2048); + let (server, handle) = { + let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); + let cb = TestCertValidationCallback::new_sync(); + let invoked = Arc::clone(cb.invoked_count()); + builder.set_cert_validation_callback_sync(cb).unwrap(); + (S2NConfig::from(builder.build().unwrap()), invoked) + }; + test_sync_callback::(&client, &server, handle); + + // TLS 1.3 + crate::capability_check::required_capability( + &[crate::capability_check::Capability::Tls13], + || { + let client = boringssl_mtls_client(SigType::Rsa2048); + let (server, handle) = { + let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); + let cb = TestCertValidationCallback::new_sync(); + let invoked = Arc::clone(cb.invoked_count()); + builder.set_cert_validation_callback_sync(cb).unwrap(); + (S2NConfig::from(builder.build().unwrap()), invoked) + }; + test_sync_callback::(&client, &server, handle); + }, + ); +} + // ============================================================================ // Async callback tests // ============================================================================ @@ -430,7 +580,7 @@ where // s2n client with async callback, rustls server #[test] -fn s2n_client_async_callback() { +fn rustls_server_async_callback() { // TLS 1.2 let (client, handle, rx) = { let builder = s2n_mtls_base_builder(SigType::Rsa2048); @@ -462,7 +612,7 @@ fn s2n_client_async_callback() { // rustls client, s2n server with async callback #[test] -fn s2n_server_async_callback() { +fn rustls_client_async_callback() { // TLS 1.2 let client = rustls_mtls_client(SigType::Rsa2048, &rustls::version::TLS12); let (server, handle, rx) = { @@ -493,6 +643,72 @@ fn s2n_server_async_callback() { ); } +// s2n client with async callback, boringssl server +#[test] +fn boringssl_server_async_callback() { + // TLS 1.2 + let (client, handle, rx) = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + let mut s2n_cfg = S2NConfig::from(builder.build().unwrap()); + let (invoked, rx) = register_async_cert_callback(&mut s2n_cfg); + (s2n_cfg, invoked, rx) + }; + let server = boringssl_mtls_server(SigType::Rsa2048); + let _pair = test_async_client_callback::( + &client, &server, handle, rx, + ); + + // TLS 1.3 + crate::capability_check::required_capability( + &[crate::capability_check::Capability::Tls13], + || { + let (client, handle, rx) = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + let mut s2n_cfg = S2NConfig::from(builder.build().unwrap()); + let (invoked, rx) = register_async_cert_callback(&mut s2n_cfg); + (s2n_cfg, invoked, rx) + }; + let server = boringssl_mtls_server(SigType::Rsa2048); + let _pair = test_async_client_callback::( + &client, &server, handle, rx, + ); + }, + ); +} + +// boringssl client, s2n server with async callback +#[test] +fn boringssl_client_async_callback() { + // TLS 1.2 + let client = boringssl_mtls_client(SigType::Rsa2048); + let (server, handle, rx) = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + let mut s2n_cfg = S2NConfig::from(builder.build().unwrap()); + let (invoked, rx) = register_async_cert_callback(&mut s2n_cfg); + (s2n_cfg, invoked, rx) + }; + let _pair = test_async_server_callback::( + &client, &server, handle, rx, + ); + + // TLS 1.3 + crate::capability_check::required_capability( + &[crate::capability_check::Capability::Tls13], + || { + let client = boringssl_mtls_client(SigType::Rsa2048); + let (server, handle, rx) = { + let builder = s2n_mtls_base_builder(SigType::Rsa2048); + let mut s2n_cfg = S2NConfig::from(builder.build().unwrap()); + let (invoked, rx) = register_async_cert_callback(&mut s2n_cfg); + (s2n_cfg, invoked, rx) + }; + let _pair = test_async_server_callback::( + &client, &server, handle, rx, + ); + }, + ); +} + // s2n client, s2n server with async callback #[test] fn s2n_s2n_mtls_async_callback() { From b34de8381b0d602255e9677063ae611f88d9ad2b Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 18:55:56 +0000 Subject: [PATCH 05/25] Remove unused imports --- bindings/rust/standard/tls-harness/src/cohort/mod.rs | 4 +--- bindings/rust/standard/tls-harness/src/harness/io.rs | 11 ++--------- bindings/rust/standard/tls-harness/src/lib.rs | 1 - 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index 6a4ed26f57f..3690848cd4c 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -9,14 +9,12 @@ //! Modules are also public so that utility structs can be accessed, like //! `cohort::s2n_tls::SessionTicketStorage`. -#[cfg(feature = "openssl")] pub mod openssl; pub mod boringssl; pub mod rustls; pub mod s2n_tls; -#[cfg(feature = "openssl")] pub use openssl::{OpenSslConfig, OpenSslConnection}; pub use boringssl::{BoringSslConfig, BoringSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; -pub use s2n_tls::{S2NConfig, S2NConnection}; \ No newline at end of file +pub use s2n_tls::{S2NConfig, S2NConnection}; diff --git a/bindings/rust/standard/tls-harness/src/harness/io.rs b/bindings/rust/standard/tls-harness/src/harness/io.rs index f50c4bd7b78..02675635b88 100644 --- a/bindings/rust/standard/tls-harness/src/harness/io.rs +++ b/bindings/rust/standard/tls-harness/src/harness/io.rs @@ -180,14 +180,11 @@ mod tests { use openssl::ssl::SslContextBuilder; use crate::{ - cohort::{rustls::RustlsConfigBuilder, RustlsConnection, S2NConnection}, + cohort::{rustls::RustlsConfigBuilder, OpenSslConnection, RustlsConnection, S2NConnection}, harness::TlsConfigBuilderPair, TlsConnPair, }; - #[cfg(feature = "openssl")] - use crate::cohort::OpenSslConnection; - use super::*; #[test] @@ -214,13 +211,9 @@ mod tests { #[test] fn implementation_record_size() { const S2N_RECORD_DEFAULT: u16 = 8104; - const RUSTLS_RECORD_DEFAULT: u16 = 16401; - - #[cfg(feature = "openssl")] const OPENSSL_RECORD_DEFAULT: u16 = 16401; + const RUSTLS_RECORD_DEFAULT: u16 = 16401; - // openssl & s2n - #[cfg(feature = "openssl")] { let mut pair: TlsConnPair = { let configs = diff --git a/bindings/rust/standard/tls-harness/src/lib.rs b/bindings/rust/standard/tls-harness/src/lib.rs index c894ddeee26..6685e0ec503 100644 --- a/bindings/rust/standard/tls-harness/src/lib.rs +++ b/bindings/rust/standard/tls-harness/src/lib.rs @@ -3,7 +3,6 @@ pub mod cohort; pub mod harness; -#[cfg(feature = "openssl")] pub mod openssl_extension; #[cfg(test)] pub mod test_utilities; From 49ae2a1bf4baffc3cf36281c0871fd4f670d6693 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 19:54:20 +0000 Subject: [PATCH 06/25] cleanup PR --- bindings/rust/standard/tls-harness/Cargo.toml | 8 ++------ bindings/rust/standard/tls-harness/src/harness/io.rs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index c4fc726ff61..b99ffd9ab56 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = "2021" publish = false -[features] -default = ["openssl"] -openssl = ["dep:openssl", "dep:openssl-sys"] - [dependencies] s2n-tls = { path = "../../extended/s2n-tls" } errno = "0.3.13" @@ -15,8 +11,8 @@ libc = "0.2.174" strum = { version = "0.27", features = ["derive"] } rustls = "0.23.31" rustls-pemfile = "2.2.0" -openssl = { version = "0.10.73", features = ["vendored"], optional = true } -openssl-sys = { version = "0.9.109", optional = true } +openssl = { version = "0.10.73", features = ["vendored"] } +openssl-sys = { version = "0.9.109" } byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" diff --git a/bindings/rust/standard/tls-harness/src/harness/io.rs b/bindings/rust/standard/tls-harness/src/harness/io.rs index 02675635b88..590547a53e5 100644 --- a/bindings/rust/standard/tls-harness/src/harness/io.rs +++ b/bindings/rust/standard/tls-harness/src/harness/io.rs @@ -176,7 +176,6 @@ impl std::io::Write for ViewIO { mod tests { use std::collections::HashMap; - #[cfg(feature = "openssl")] use openssl::ssl::SslContextBuilder; use crate::{ @@ -214,6 +213,7 @@ mod tests { const OPENSSL_RECORD_DEFAULT: u16 = 16401; const RUSTLS_RECORD_DEFAULT: u16 = 16401; + // openssl & s2n { let mut pair: TlsConnPair = { let configs = From 8eac659bde488add54a04d0e3dbb69e9fa17e9dc Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 20:53:55 +0000 Subject: [PATCH 07/25] additional cleanup --- bindings/rust/standard/tls-harness/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index b99ffd9ab56..cdf04ab7fac 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -12,7 +12,7 @@ strum = { version = "0.27", features = ["derive"] } rustls = "0.23.31" rustls-pemfile = "2.2.0" openssl = { version = "0.10.73", features = ["vendored"] } -openssl-sys = { version = "0.9.109" } +openssl-sys = "0.9.109" byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" From dd658cc46eeb2bc04f79724ce9300cd444cf9cc6 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 21:22:40 +0000 Subject: [PATCH 08/25] Add comment for cargo config --- bindings/rust/standard/tls-harness/.cargo/config.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/rust/standard/tls-harness/.cargo/config.toml b/bindings/rust/standard/tls-harness/.cargo/config.toml index 0850c6255ba..457209020d4 100644 --- a/bindings/rust/standard/tls-harness/.cargo/config.toml +++ b/bindings/rust/standard/tls-harness/.cargo/config.toml @@ -1,3 +1,4 @@ +# Ensure the symbol-prefixed BoringSSL build is used in tests, and FIPS is disabled. [env] BORING_BSSL_FIPS = "0" BORING_BSSL_PREFIX = "BORING_TLS_HARNESS" From d6a7e49dc587060f3fd2fa4822a0efab5995570d Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 22:01:17 +0000 Subject: [PATCH 09/25] Apply formatting rules --- .../rust/standard/integration/src/mtls/mod.rs | 24 ++++++++++++------- .../tls-harness/src/cohort/boringssl.rs | 4 ++-- .../standard/tls-harness/src/cohort/mod.rs | 4 ++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index bc6d0b80cd1..973d47db5f0 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -41,7 +41,10 @@ use s2n_tls_sys::{ }; use tls_harness::{ - cohort::{BoringSslConfig, BoringSslConnection, RustlsConfig, RustlsConnection, S2NConfig, S2NConnection}, + cohort::{ + BoringSslConfig, BoringSslConnection, RustlsConfig, RustlsConnection, S2NConfig, + S2NConnection, + }, harness::{read_to_bytes, TlsConfigBuilder}, PemType, SigType, TlsConnPair, TlsConnection, }; @@ -212,13 +215,16 @@ fn rustls_mtls_server( fn boringssl_mtls_client(sig_type: SigType) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; - + let mut builder = boring::ssl::SslContextBuilder::new_test_config(Mode::Client); builder.set_trust(sig_type); - + // Set client certificate and key builder - .set_certificate_chain_file(tls_harness::get_cert_path(PemType::ClientCertChain, sig_type)) + .set_certificate_chain_file(tls_harness::get_cert_path( + PemType::ClientCertChain, + sig_type, + )) .unwrap(); builder .set_private_key_file( @@ -227,7 +233,7 @@ fn boringssl_mtls_client(sig_type: SigType) -> BoringSslConfig { ) .unwrap(); builder.set_verify(boring::ssl::SslVerifyMode::PEER); - + BoringSslConfig { config: builder.build(), session_ticket_storage: Default::default(), @@ -236,12 +242,14 @@ fn boringssl_mtls_client(sig_type: SigType) -> BoringSslConfig { fn boringssl_mtls_server(sig_type: SigType) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; - + let mut builder = boring::ssl::SslContextBuilder::new_test_config(Mode::Server); builder.set_chain(sig_type); builder.set_trust(sig_type); - builder.set_verify(boring::ssl::SslVerifyMode::PEER | boring::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT); - + builder.set_verify( + boring::ssl::SslVerifyMode::PEER | boring::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT, + ); + BoringSslConfig { config: builder.build(), session_ticket_storage: Default::default(), diff --git a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs index bfac9bc6e76..e5d581f0ac7 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs @@ -50,7 +50,7 @@ impl TlsConnection for BoringSslConnection { config: &Self::Config, io: &Rc, ) -> Result> { - // No tickets/resumption yet: keep it simple + // No tickets/resumption yet: keep it simple let ssl = Ssl::new(&config.config)?; let view = match mode { @@ -198,7 +198,7 @@ mod tests { use crate::test_utilities; use super::*; - + #[test] fn handshake() { test_utilities::handshake::(); diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index 3690848cd4c..e88c246212d 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -9,12 +9,12 @@ //! Modules are also public so that utility structs can be accessed, like //! `cohort::s2n_tls::SessionTicketStorage`. -pub mod openssl; pub mod boringssl; +pub mod openssl; pub mod rustls; pub mod s2n_tls; -pub use openssl::{OpenSslConfig, OpenSslConnection}; pub use boringssl::{BoringSslConfig, BoringSslConnection}; +pub use openssl::{OpenSslConfig, OpenSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; pub use s2n_tls::{S2NConfig, S2NConnection}; From bee00275f66ef94e75dc26c95ded77397c9ba85b Mon Sep 17 00:00:00 2001 From: Kaukab Date: Tue, 9 Dec 2025 23:59:42 +0000 Subject: [PATCH 10/25] clippy fix and macOS CI debug --- .github/workflows/ci_rust.yml | 16 ++++++++++++++++ .../rust/standard/tls-harness/.cargo/config.toml | 3 ++- .../standard/tls-harness/src/cohort/boringssl.rs | 6 ++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index 13ef655ad7a..cc79b898f47 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -51,6 +51,22 @@ jobs: - uses: camshaft/rust-cache@v1 + - name: Debug nm/objcopy on macOS + if: runner.os == 'macOS' + run: | + echo "PATH=$PATH" + which nm || echo "nm not found" + which objcopy || echo "objcopy not found" + which llvm-nm || echo "llvm-nm not found" + which llvm-objcopy || echo "llvm-objcopy not found" + echo "--- listing /usr/bin" + ls /usr/bin | grep -E 'nm|objcopy|llvm' || true + echo "--- listing /usr/local/bin" + ls /usr/local/bin | grep -E 'nm|objcopy|llvm' || true + echo "--- listing Homebrew dirs" + ls /opt/homebrew/bin | grep -E 'nm|objcopy|llvm' || true + ls /usr/local/opt/llvm/bin | grep -E 'nm|objcopy|llvm' || true + - name: Generate run: ${{env.ROOT_PATH}}/generate.sh diff --git a/bindings/rust/standard/tls-harness/.cargo/config.toml b/bindings/rust/standard/tls-harness/.cargo/config.toml index 457209020d4..60db100157a 100644 --- a/bindings/rust/standard/tls-harness/.cargo/config.toml +++ b/bindings/rust/standard/tls-harness/.cargo/config.toml @@ -1,4 +1,5 @@ -# Ensure the symbol-prefixed BoringSSL build is used in tests, and FIPS is disabled. +# Ensure the symbol-prefixed BoringSSL build is used in tests +# to avoid collisions with OpenSSL, and FIPS is disabled. [env] BORING_BSSL_FIPS = "0" BORING_BSSL_PREFIX = "BORING_TLS_HARNESS" diff --git a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs index e5d581f0ac7..e41ee36a6c8 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs @@ -162,12 +162,10 @@ impl TlsConfigBuilder for SslContextBuilder { type Config = BoringSslConfig; fn new_test_config(mode: Mode) -> Self { - let builder = match mode { + match mode { Mode::Client => SslContext::builder(SslMethod::tls_client()).unwrap(), Mode::Server => SslContext::builder(SslMethod::tls_server()).unwrap(), - }; - // Note: BoringSSL doesn't have set_security_level like OpenSSL - builder + } } fn set_chain(&mut self, sig_type: crate::SigType) { From b17e48c7bf2e9079eb66891b822108d968aaa985 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 00:08:38 +0000 Subject: [PATCH 11/25] install binutils in macOS runner --- .github/workflows/ci_rust.yml | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index cc79b898f47..aef0d9d28a4 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -51,22 +51,18 @@ jobs: - uses: camshaft/rust-cache@v1 - - name: Debug nm/objcopy on macOS + - name: Install binutils (for objcopy) if: runner.os == 'macOS' run: | - echo "PATH=$PATH" - which nm || echo "nm not found" - which objcopy || echo "objcopy not found" - which llvm-nm || echo "llvm-nm not found" - which llvm-objcopy || echo "llvm-objcopy not found" - echo "--- listing /usr/bin" - ls /usr/bin | grep -E 'nm|objcopy|llvm' || true - echo "--- listing /usr/local/bin" - ls /usr/local/bin | grep -E 'nm|objcopy|llvm' || true - echo "--- listing Homebrew dirs" - ls /opt/homebrew/bin | grep -E 'nm|objcopy|llvm' || true - ls /usr/local/opt/llvm/bin | grep -E 'nm|objcopy|llvm' || true - + brew update + brew install binutils + + - name: Configure nm/objcopy for symbol prefixing + if: runner.os == 'macOS' + run: | + echo "BORING_PREFIX_NM=nm" >> $GITHUB_ENV + echo "BORING_PREFIX_OBJCOPY=gobjcopy" >> $GITHUB_ENV + - name: Generate run: ${{env.ROOT_PATH}}/generate.sh From 59895bca520996e7dd11ae53efb7314396c04dd9 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 00:33:43 +0000 Subject: [PATCH 12/25] set objocpy env var for macOS build --- .github/workflows/ci_rust.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index aef0d9d28a4..190af4817ac 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -51,17 +51,13 @@ jobs: - uses: camshaft/rust-cache@v1 - - name: Install binutils (for objcopy) + - name: Install binutils (for boringssl symbol prefixing on macOS) if: runner.os == 'macOS' run: | brew update brew install binutils - - - name: Configure nm/objcopy for symbol prefixing - if: runner.os == 'macOS' - run: | echo "BORING_PREFIX_NM=nm" >> $GITHUB_ENV - echo "BORING_PREFIX_OBJCOPY=gobjcopy" >> $GITHUB_ENV + echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/binutils/bin/gobjcopy" >> $GITHUB_ENV - name: Generate run: ${{env.ROOT_PATH}}/generate.sh @@ -280,6 +276,14 @@ jobs: - uses: camshaft/rust-cache@v1 + - name: Install binutils (for boringssl symbol prefixing on macOS) + if: runner.os == 'macOS' + run: | + brew update + brew install binutils + echo "BORING_PREFIX_NM=nm" >> $GITHUB_ENV + echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/binutils/bin/gobjcopy" >> $GITHUB_ENV + - name: Generate run: ./${{env.ROOT_PATH}}/generate.sh From 5636273e6fae0d71f984479fb438c63b4db837c0 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 00:57:08 +0000 Subject: [PATCH 13/25] try LLVM instead of bin utils --- .github/workflows/ci_rust.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index 190af4817ac..755f698feeb 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -51,13 +51,12 @@ jobs: - uses: camshaft/rust-cache@v1 - - name: Install binutils (for boringssl symbol prefixing on macOS) + - name: Install llvm (for symbol prefixing BoringSSL in macOS) if: runner.os == 'macOS' run: | - brew update - brew install binutils - echo "BORING_PREFIX_NM=nm" >> $GITHUB_ENV - echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/binutils/bin/gobjcopy" >> $GITHUB_ENV + brew install llvm + echo "BORING_PREFIX_NM=/opt/homebrew/opt/llvm/bin/llvm-nm" >> $GITHUB_ENV + echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/llvm/bin/llvm-objcopy" >> $GITHUB_ENV - name: Generate run: ${{env.ROOT_PATH}}/generate.sh @@ -276,13 +275,12 @@ jobs: - uses: camshaft/rust-cache@v1 - - name: Install binutils (for boringssl symbol prefixing on macOS) + - name: Install llvm (for symbol prefixing BoringSSL in macOS) if: runner.os == 'macOS' run: | - brew update - brew install binutils - echo "BORING_PREFIX_NM=nm" >> $GITHUB_ENV - echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/binutils/bin/gobjcopy" >> $GITHUB_ENV + brew install llvm + echo "BORING_PREFIX_NM=/opt/homebrew/opt/llvm/bin/llvm-nm" >> $GITHUB_ENV + echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/llvm/bin/llvm-objcopy" >> $GITHUB_ENV - name: Generate run: ./${{env.ROOT_PATH}}/generate.sh From 96ce5cfa370e7bb53362d3a246c9161213b066bc Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 01:00:46 +0000 Subject: [PATCH 14/25] Add go to nix packages --- nix/devshells.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/devshells.nix b/nix/devshells.nix index cd0357b4856..0b4df5fca6d 100644 --- a/nix/devshells.nix +++ b/nix/devshells.nix @@ -44,6 +44,7 @@ let pkgs.rustc pkgs.rustup pkgs.cargo + pkgs.go ]; # Helper function to create base shell configurations From c8e52ca0f3ca7219ea95ac8f85c6d3df98e7a79c Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 01:33:04 +0000 Subject: [PATCH 15/25] Add protocol versions to boring mTLS tests --- .../rust/standard/integration/src/mtls/mod.rs | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index 973d47db5f0..e70ce6b88fe 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -27,6 +27,8 @@ use std::{ use rustls::ClientConfig; +use boring::ssl::SslVersion; + use s2n_tls::{ callbacks::{CertValidationCallbackSync, CertValidationInfo, VerifyHostNameCallback}, config::{Builder, Config}, @@ -213,18 +215,16 @@ fn rustls_mtls_server( server.into() } -fn boringssl_mtls_client(sig_type: SigType) -> BoringSslConfig { +fn boringssl_mtls_client(sig_type: SigType, version: SslVersion) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; let mut builder = boring::ssl::SslContextBuilder::new_test_config(Mode::Client); builder.set_trust(sig_type); - // Set client certificate and key builder - .set_certificate_chain_file(tls_harness::get_cert_path( - PemType::ClientCertChain, - sig_type, - )) + .set_certificate_chain_file( + tls_harness::get_cert_path(PemType::ClientCertChain, sig_type), + ) .unwrap(); builder .set_private_key_file( @@ -234,13 +234,17 @@ fn boringssl_mtls_client(sig_type: SigType) -> BoringSslConfig { .unwrap(); builder.set_verify(boring::ssl::SslVerifyMode::PEER); + // Pin the protocol version + builder.set_min_proto_version(Some(version)).unwrap(); + builder.set_max_proto_version(Some(version)).unwrap(); + BoringSslConfig { config: builder.build(), session_ticket_storage: Default::default(), } } -fn boringssl_mtls_server(sig_type: SigType) -> BoringSslConfig { +fn boringssl_mtls_server(sig_type: SigType, version: SslVersion) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; let mut builder = boring::ssl::SslContextBuilder::new_test_config(Mode::Server); @@ -250,6 +254,10 @@ fn boringssl_mtls_server(sig_type: SigType) -> BoringSslConfig { boring::ssl::SslVerifyMode::PEER | boring::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT, ); + // Pin the protocol version + builder.set_min_proto_version(Some(version)).unwrap(); + builder.set_max_proto_version(Some(version)).unwrap(); + BoringSslConfig { config: builder.build(), session_ticket_storage: Default::default(), @@ -329,7 +337,7 @@ fn boringssl_server_basic() { let builder = s2n_mtls_base_builder(SigType::Rsa2048); S2NConfig::from(builder.build().unwrap()) }; - let server = boringssl_mtls_server(SigType::Rsa2048); + let server = boringssl_mtls_server(SigType::Rsa2048, SslVersion::TLS1_2); test_basic::(&client, &server); // TLS 1.3 @@ -340,7 +348,7 @@ fn boringssl_server_basic() { let builder = s2n_mtls_base_builder(SigType::Rsa2048); S2NConfig::from(builder.build().unwrap()) }; - let server = boringssl_mtls_server(SigType::Rsa2048); + let server = boringssl_mtls_server(SigType::Rsa2048, SslVersion::TLS1_3); test_basic::(&client, &server); }, ); @@ -350,7 +358,7 @@ fn boringssl_server_basic() { #[test] fn boringssl_client_basic() { // TLS 1.2 - let client = boringssl_mtls_client(SigType::Rsa2048); + let client = boringssl_mtls_client(SigType::Rsa2048, SslVersion::TLS1_2); let server = { let builder = s2n_mtls_base_builder(SigType::Rsa2048); S2NConfig::from(builder.build().unwrap()) @@ -361,7 +369,7 @@ fn boringssl_client_basic() { crate::capability_check::required_capability( &[crate::capability_check::Capability::Tls13], || { - let client = boringssl_mtls_client(SigType::Rsa2048); + let client = boringssl_mtls_client(SigType::Rsa2048, SslVersion::TLS1_3); let server = { let builder = s2n_mtls_base_builder(SigType::Rsa2048); S2NConfig::from(builder.build().unwrap()) @@ -464,7 +472,7 @@ fn boringssl_server_sync_callback() { builder.set_cert_validation_callback_sync(cb).unwrap(); (S2NConfig::from(builder.build().unwrap()), invoked) }; - let server = boringssl_mtls_server(SigType::Rsa2048); + let server = boringssl_mtls_server(SigType::Rsa2048, SslVersion::TLS1_2); test_sync_callback::(&client, &server, handle); // TLS 1.3 @@ -478,7 +486,7 @@ fn boringssl_server_sync_callback() { builder.set_cert_validation_callback_sync(cb).unwrap(); (S2NConfig::from(builder.build().unwrap()), invoked) }; - let server = boringssl_mtls_server(SigType::Rsa2048); + let server = boringssl_mtls_server(SigType::Rsa2048, SslVersion::TLS1_3); test_sync_callback::(&client, &server, handle); }, ); @@ -488,7 +496,7 @@ fn boringssl_server_sync_callback() { #[test] fn boringssl_client_sync_callback() { // TLS 1.2 - let client = boringssl_mtls_client(SigType::Rsa2048); + let client = boringssl_mtls_client(SigType::Rsa2048, SslVersion::TLS1_2); let (server, handle) = { let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); let cb = TestCertValidationCallback::new_sync(); @@ -502,7 +510,7 @@ fn boringssl_client_sync_callback() { crate::capability_check::required_capability( &[crate::capability_check::Capability::Tls13], || { - let client = boringssl_mtls_client(SigType::Rsa2048); + let client = boringssl_mtls_client(SigType::Rsa2048, SslVersion::TLS1_3); let (server, handle) = { let mut builder = s2n_mtls_base_builder(SigType::Rsa2048); let cb = TestCertValidationCallback::new_sync(); @@ -661,7 +669,7 @@ fn boringssl_server_async_callback() { let (invoked, rx) = register_async_cert_callback(&mut s2n_cfg); (s2n_cfg, invoked, rx) }; - let server = boringssl_mtls_server(SigType::Rsa2048); + let server = boringssl_mtls_server(SigType::Rsa2048, SslVersion::TLS1_2); let _pair = test_async_client_callback::( &client, &server, handle, rx, ); @@ -676,7 +684,7 @@ fn boringssl_server_async_callback() { let (invoked, rx) = register_async_cert_callback(&mut s2n_cfg); (s2n_cfg, invoked, rx) }; - let server = boringssl_mtls_server(SigType::Rsa2048); + let server = boringssl_mtls_server(SigType::Rsa2048, SslVersion::TLS1_3); let _pair = test_async_client_callback::( &client, &server, handle, rx, ); @@ -688,7 +696,7 @@ fn boringssl_server_async_callback() { #[test] fn boringssl_client_async_callback() { // TLS 1.2 - let client = boringssl_mtls_client(SigType::Rsa2048); + let client = boringssl_mtls_client(SigType::Rsa2048, SslVersion::TLS1_2); let (server, handle, rx) = { let builder = s2n_mtls_base_builder(SigType::Rsa2048); let mut s2n_cfg = S2NConfig::from(builder.build().unwrap()); @@ -703,7 +711,7 @@ fn boringssl_client_async_callback() { crate::capability_check::required_capability( &[crate::capability_check::Capability::Tls13], || { - let client = boringssl_mtls_client(SigType::Rsa2048); + let client = boringssl_mtls_client(SigType::Rsa2048, SslVersion::TLS1_3); let (server, handle, rx) = { let builder = s2n_mtls_base_builder(SigType::Rsa2048); let mut s2n_cfg = S2NConfig::from(builder.build().unwrap()); From 689b5b0f41c4c861a8a65f28c018ae55ca444000 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 18:56:42 +0000 Subject: [PATCH 16/25] Apply cargo format --- bindings/rust/standard/integration/src/mtls/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index e70ce6b88fe..86b9c8d3ce4 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -222,9 +222,10 @@ fn boringssl_mtls_client(sig_type: SigType, version: SslVersion) -> BoringSslCon builder.set_trust(sig_type); builder - .set_certificate_chain_file( - tls_harness::get_cert_path(PemType::ClientCertChain, sig_type), - ) + .set_certificate_chain_file(tls_harness::get_cert_path( + PemType::ClientCertChain, + sig_type, + )) .unwrap(); builder .set_private_key_file( From 429db6051165072feadbc96304435c1c261c66e5 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 19:32:14 +0000 Subject: [PATCH 17/25] Debug message to print macOS symbols --- .github/workflows/ci_rust.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index 755f698feeb..e5595ac38cd 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -61,6 +61,19 @@ jobs: - name: Generate run: ${{env.ROOT_PATH}}/generate.sh + - name: Sanity-check BoringSSL symbol prefixing (macOS) + if: runner.os == 'macOS' + run: | + echo "Checking for prefixed symbols…" + NM_TOOL="${BORING_PREFIX_NM:-nm}" + echo "Using NM_TOOL=$NM_TOOL" + + for lib in $(find bindings -name "libssl.a" -o -name "libcrypto.a"); do + echo "--- $lib ---" + "$NM_TOOL" "$lib" | grep BSSL_TLS_client_method || echo "missing BSSL_TLS_client_method" + "$NM_TOOL" "$lib" | grep BSSL_SSL_write || echo "missing BSSL_SSL_write" + done + # Ensure that all tests pass with the default feature set - name: Default Tests working-directory: ${{env.ROOT_PATH}} From a082354990e7afdf7075ba92d2802950069fd82e Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 22:08:24 +0000 Subject: [PATCH 18/25] Feature gate boringssl to not build on macOS --- .github/workflows/ci_rust.yml | 27 ------------------- bindings/rust/standard/integration/Cargo.toml | 1 + .../rust/standard/integration/src/mtls/mod.rs | 20 +++++++++++--- bindings/rust/standard/tls-harness/Cargo.toml | 1 + .../standard/tls-harness/src/cohort/mod.rs | 5 +++- 5 files changed, 23 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index e5595ac38cd..13ef655ad7a 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -51,29 +51,9 @@ jobs: - uses: camshaft/rust-cache@v1 - - name: Install llvm (for symbol prefixing BoringSSL in macOS) - if: runner.os == 'macOS' - run: | - brew install llvm - echo "BORING_PREFIX_NM=/opt/homebrew/opt/llvm/bin/llvm-nm" >> $GITHUB_ENV - echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/llvm/bin/llvm-objcopy" >> $GITHUB_ENV - - name: Generate run: ${{env.ROOT_PATH}}/generate.sh - - name: Sanity-check BoringSSL symbol prefixing (macOS) - if: runner.os == 'macOS' - run: | - echo "Checking for prefixed symbols…" - NM_TOOL="${BORING_PREFIX_NM:-nm}" - echo "Using NM_TOOL=$NM_TOOL" - - for lib in $(find bindings -name "libssl.a" -o -name "libcrypto.a"); do - echo "--- $lib ---" - "$NM_TOOL" "$lib" | grep BSSL_TLS_client_method || echo "missing BSSL_TLS_client_method" - "$NM_TOOL" "$lib" | grep BSSL_SSL_write || echo "missing BSSL_SSL_write" - done - # Ensure that all tests pass with the default feature set - name: Default Tests working-directory: ${{env.ROOT_PATH}} @@ -288,13 +268,6 @@ jobs: - uses: camshaft/rust-cache@v1 - - name: Install llvm (for symbol prefixing BoringSSL in macOS) - if: runner.os == 'macOS' - run: | - brew install llvm - echo "BORING_PREFIX_NM=/opt/homebrew/opt/llvm/bin/llvm-nm" >> $GITHUB_ENV - echo "BORING_PREFIX_OBJCOPY=/opt/homebrew/opt/llvm/bin/llvm-objcopy" >> $GITHUB_ENV - - name: Generate run: ./${{env.ROOT_PATH}}/generate.sh diff --git a/bindings/rust/standard/integration/Cargo.toml b/bindings/rust/standard/integration/Cargo.toml index dc94deb3999..627df0589ba 100644 --- a/bindings/rust/standard/integration/Cargo.toml +++ b/bindings/rust/standard/integration/Cargo.toml @@ -48,6 +48,7 @@ hyper-util = "0.1" dhat = "0.3.3" tabled = "0.20.0" +[target.'cfg(not(target_os = "macos"))'.dependencies] [dev-dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" branch = "symbol-prefixing" diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index 86b9c8d3ce4..7b967c2d524 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -26,7 +26,7 @@ use std::{ }; use rustls::ClientConfig; - +#[cfg(not(target_os = "macos"))] use boring::ssl::SslVersion; use s2n_tls::{ @@ -44,13 +44,19 @@ use s2n_tls_sys::{ use tls_harness::{ cohort::{ - BoringSslConfig, BoringSslConnection, RustlsConfig, RustlsConnection, S2NConfig, - S2NConnection, + RustlsConfig, RustlsConnection, S2NConfig, S2NConnection, }, harness::{read_to_bytes, TlsConfigBuilder}, PemType, SigType, TlsConnPair, TlsConnection, }; +#[cfg(not(target_os = "macos"))] +use tls_harness::{ + cohort::{ + BoringSslConfig, BoringSslConnection, + } +}; + const APP_DATA_SIZE: usize = 100_000; /// A wrapper around a raw pointer to `s2n_cert_validation_info` that can be sent across threads. @@ -215,6 +221,7 @@ fn rustls_mtls_server( server.into() } +#[cfg(not(target_os = "macos"))] fn boringssl_mtls_client(sig_type: SigType, version: SslVersion) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; @@ -245,6 +252,7 @@ fn boringssl_mtls_client(sig_type: SigType, version: SslVersion) -> BoringSslCon } } +#[cfg(not(target_os = "macos"))] fn boringssl_mtls_server(sig_type: SigType, version: SslVersion) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; @@ -331,6 +339,7 @@ fn rustls_client_basic() { } // s2n client, boringssl server +#[cfg(not(target_os = "macos"))] #[test] fn boringssl_server_basic() { // TLS 1.2 @@ -356,6 +365,7 @@ fn boringssl_server_basic() { } // boringssl client, s2n server +#[cfg(not(target_os = "macos"))] #[test] fn boringssl_client_basic() { // TLS 1.2 @@ -463,6 +473,7 @@ fn rustls_client_sync_callback() { } // s2n client with sync callback, boringssl server +#[cfg(not(target_os = "macos"))] #[test] fn boringssl_server_sync_callback() { // TLS 1.2 @@ -494,6 +505,7 @@ fn boringssl_server_sync_callback() { } // boringssl client, s2n server with sync callback +#[cfg(not(target_os = "macos"))] #[test] fn boringssl_client_sync_callback() { // TLS 1.2 @@ -661,6 +673,7 @@ fn rustls_client_async_callback() { } // s2n client with async callback, boringssl server +#[cfg(not(target_os = "macos"))] #[test] fn boringssl_server_async_callback() { // TLS 1.2 @@ -694,6 +707,7 @@ fn boringssl_server_async_callback() { } // boringssl client, s2n server with async callback +#[cfg(not(target_os = "macos"))] #[test] fn boringssl_client_async_callback() { // TLS 1.2 diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index cdf04ab7fac..182cefeeab2 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -18,6 +18,7 @@ byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" brass-aphid-wire-messages = "0.0.1" +[target.'cfg(target_os = "macos")'.dependencies] [dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" branch = "symbol-prefixing" diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index e88c246212d..6411a26968c 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -8,13 +8,16 @@ //! so that they can be accessed as `cohort::OpenSslConnection` or `cohort::S2NConnection`. //! Modules are also public so that utility structs can be accessed, like //! `cohort::s2n_tls::SessionTicketStorage`. - +#[cfg(not(target_os = "macos"))] pub mod boringssl; + pub mod openssl; pub mod rustls; pub mod s2n_tls; +#[cfg(not(target_os = "macos"))] pub use boringssl::{BoringSslConfig, BoringSslConnection}; + pub use openssl::{OpenSslConfig, OpenSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; pub use s2n_tls::{S2NConfig, S2NConnection}; From 24aff57b10c0e28e253afaf6987a8d182bd8b2c3 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 22:09:34 +0000 Subject: [PATCH 19/25] Apply cargo fmt --- bindings/rust/standard/integration/src/mtls/mod.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index 7b967c2d524..9d518e0c408 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -25,9 +25,9 @@ use std::{ }, }; -use rustls::ClientConfig; #[cfg(not(target_os = "macos"))] use boring::ssl::SslVersion; +use rustls::ClientConfig; use s2n_tls::{ callbacks::{CertValidationCallbackSync, CertValidationInfo, VerifyHostNameCallback}, @@ -43,19 +43,13 @@ use s2n_tls_sys::{ }; use tls_harness::{ - cohort::{ - RustlsConfig, RustlsConnection, S2NConfig, S2NConnection, - }, + cohort::{RustlsConfig, RustlsConnection, S2NConfig, S2NConnection}, harness::{read_to_bytes, TlsConfigBuilder}, PemType, SigType, TlsConnPair, TlsConnection, }; #[cfg(not(target_os = "macos"))] -use tls_harness::{ - cohort::{ - BoringSslConfig, BoringSslConnection, - } -}; +use tls_harness::cohort::{BoringSslConfig, BoringSslConnection}; const APP_DATA_SIZE: usize = 100_000; From df0ed605b77ff57e81e2b2f3939de7620d92172b Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 22:26:01 +0000 Subject: [PATCH 20/25] adjust cargo.toml for OS gating --- bindings/rust/standard/integration/Cargo.toml | 3 +-- bindings/rust/standard/tls-harness/Cargo.toml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bindings/rust/standard/integration/Cargo.toml b/bindings/rust/standard/integration/Cargo.toml index 627df0589ba..e110a56367f 100644 --- a/bindings/rust/standard/integration/Cargo.toml +++ b/bindings/rust/standard/integration/Cargo.toml @@ -48,8 +48,7 @@ hyper-util = "0.1" dhat = "0.3.3" tabled = "0.20.0" -[target.'cfg(not(target_os = "macos"))'.dependencies] -[dev-dependencies.boring] +[target.'cfg(not(target_os = "macos"))'.dev-dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" branch = "symbol-prefixing" features = ["prefix-symbols"] diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index 182cefeeab2..34246f53de7 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -18,8 +18,7 @@ byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" brass-aphid-wire-messages = "0.0.1" -[target.'cfg(target_os = "macos")'.dependencies] -[dependencies.boring] +[target.'cfg(not(target_os = "macos"))'.dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" branch = "symbol-prefixing" features = ["prefix-symbols"] From 638d454287321d3450fb0362d1cc0dd26cd174ad Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 23:23:19 +0000 Subject: [PATCH 21/25] Add comments to explain broginssl gating --- bindings/rust/standard/integration/Cargo.toml | 2 ++ bindings/rust/standard/integration/src/mtls/mod.rs | 2 ++ bindings/rust/standard/tls-harness/.cargo/config.toml | 5 ----- bindings/rust/standard/tls-harness/Cargo.toml | 2 ++ bindings/rust/standard/tls-harness/src/cohort/mod.rs | 9 ++++++--- 5 files changed, 12 insertions(+), 8 deletions(-) delete mode 100644 bindings/rust/standard/tls-harness/.cargo/config.toml diff --git a/bindings/rust/standard/integration/Cargo.toml b/bindings/rust/standard/integration/Cargo.toml index e110a56367f..94999c67494 100644 --- a/bindings/rust/standard/integration/Cargo.toml +++ b/bindings/rust/standard/integration/Cargo.toml @@ -48,6 +48,8 @@ hyper-util = "0.1" dhat = "0.3.3" tabled = "0.20.0" +# NOTE: BoringSSL is disabled on macOS to avoid symbol collisions with +# OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. [target.'cfg(not(target_os = "macos"))'.dev-dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" branch = "symbol-prefixing" diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index 9d518e0c408..768509a0d1a 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -25,6 +25,8 @@ use std::{ }, }; +// NOTE: BoringSSL tests are disabled on macOS to avoid symbol collisions with +// OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. #[cfg(not(target_os = "macos"))] use boring::ssl::SslVersion; use rustls::ClientConfig; diff --git a/bindings/rust/standard/tls-harness/.cargo/config.toml b/bindings/rust/standard/tls-harness/.cargo/config.toml deleted file mode 100644 index 60db100157a..00000000000 --- a/bindings/rust/standard/tls-harness/.cargo/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -# Ensure the symbol-prefixed BoringSSL build is used in tests -# to avoid collisions with OpenSSL, and FIPS is disabled. -[env] -BORING_BSSL_FIPS = "0" -BORING_BSSL_PREFIX = "BORING_TLS_HARNESS" diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index 34246f53de7..f17b3f077e4 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -18,6 +18,8 @@ byteorder = "1.5.0" brass-aphid-wire-decryption = "0.0.1" brass-aphid-wire-messages = "0.0.1" +# NOTE: BoringSSL is disabled on macOS to avoid symbol collisions with +# OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. [target.'cfg(not(target_os = "macos"))'.dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" branch = "symbol-prefixing" diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index 6411a26968c..2decbb1f4ee 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -8,16 +8,19 @@ //! so that they can be accessed as `cohort::OpenSslConnection` or `cohort::S2NConnection`. //! Modules are also public so that utility structs can be accessed, like //! `cohort::s2n_tls::SessionTicketStorage`. -#[cfg(not(target_os = "macos"))] -pub mod boringssl; pub mod openssl; pub mod rustls; pub mod s2n_tls; +// NOTE: BoringSSL is disabled on macOS to avoid symbol collisions with +// OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. #[cfg(not(target_os = "macos"))] -pub use boringssl::{BoringSslConfig, BoringSslConnection}; +pub mod boringssl; pub use openssl::{OpenSslConfig, OpenSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; pub use s2n_tls::{S2NConfig, S2NConnection}; + +#[cfg(not(target_os = "macos"))] +pub use boringssl::{BoringSslConfig, BoringSslConnection}; \ No newline at end of file From 24cce5f1d3f4ae8feb1903c1ced467a96eab8cb6 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 10 Dec 2025 23:24:44 +0000 Subject: [PATCH 22/25] Apply cargo fmt --- bindings/rust/standard/tls-harness/src/cohort/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index 2decbb1f4ee..b88ad3ff85f 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -23,4 +23,4 @@ pub use rustls::{RustlsConfig, RustlsConnection}; pub use s2n_tls::{S2NConfig, S2NConnection}; #[cfg(not(target_os = "macos"))] -pub use boringssl::{BoringSslConfig, BoringSslConnection}; \ No newline at end of file +pub use boringssl::{BoringSslConfig, BoringSslConnection}; From cc22199a742edb0b9a67758097d5bf5e06f6063f Mon Sep 17 00:00:00 2001 From: Kaukab Date: Fri, 12 Dec 2025 00:05:16 +0000 Subject: [PATCH 23/25] More closely match openssl harness --- .../tls-harness/src/cohort/boringssl.rs | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs index e41ee36a6c8..a1536883bc4 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/boringssl.rs @@ -50,8 +50,27 @@ impl TlsConnection for BoringSslConnection { config: &Self::Config, io: &Rc, ) -> Result> { - // No tickets/resumption yet: keep it simple - let ssl = Ssl::new(&config.config)?; + // Check if there is a session ticket available. + // A session ticket will only be available if the Config was created + // with session resumption enabled (and a previous handshake stored it). + let maybe_ticket = config + .session_ticket_storage + .stored_ticket + .lock() + .unwrap() + .take(); + + // Populate the internal session cache (mirrors the OpenSSL harness pattern). + if let Some(ticket) = &maybe_ticket { + let _ = unsafe { config.config.add_session(ticket) }; + } + + let mut ssl = Ssl::new(&config.config)?; + + // If we have a ticket, attempt to resume with it. + if let Some(ticket) = &maybe_ticket { + unsafe { ssl.set_session(ticket)? }; + } let view = match mode { Mode::Client => io.client_view(), @@ -65,7 +84,7 @@ impl TlsConnection for BoringSslConnection { }) } - fn handshake(&mut self) -> Result<(), Box> { + fn handshake(&mut self) -> Result<(), Box> { // If the handshake is already complete, no further work is needed. if self.connection.ssl().is_init_finished() { return Ok(()); @@ -96,10 +115,7 @@ impl TlsConnection for BoringSslConnection { fn send(&mut self, data: &[u8]) { let mut write_offset = 0; while write_offset < data.len() { - write_offset += self - .connection - .write(&data[write_offset..data.len()]) - .unwrap(); + write_offset += self.connection.write(&data[write_offset..]).unwrap(); self.connection.flush().unwrap(); // make sure internal buffers don't fill up } } @@ -107,7 +123,7 @@ impl TlsConnection for BoringSslConnection { fn recv(&mut self, data: &mut [u8]) -> std::io::Result<()> { let data_len = data.len(); let mut read_offset = 0; - while read_offset < data.len() { + while read_offset < data_len { read_offset += self.connection.read(&mut data[read_offset..data_len])? } Ok(()) @@ -125,19 +141,16 @@ impl TlsConnection for BoringSslConnection { impl TlsInfo for BoringSslConnection { fn name() -> String { - // BoringSSL doesn't expose a version number in the same way as OpenSSL - // It's typically identified just as "boringssl" "boringssl".to_string() } fn get_negotiated_cipher_suite(&self) -> String { - let cipher_suite = self - .connection + self.connection .ssl() .current_cipher() .expect("Handshake not completed") - .name(); - cipher_suite.to_string() + .name() + .to_string() } fn negotiated_tls13(&self) -> bool { @@ -155,6 +168,7 @@ impl TlsInfo for BoringSslConnection { fn mutual_auth(&self) -> bool { assert!(self.connection.ssl().is_server()); self.connection.ssl().peer_certificate().is_some() + && self.connection.ssl().verify_result().is_ok() } } From 5f5cf653dc1bed22c4fca843b5af12bf268150ac Mon Sep 17 00:00:00 2001 From: Kaukab Date: Thu, 18 Dec 2025 19:55:22 +0000 Subject: [PATCH 24/25] Feature gate boringssl --- bindings/rust/standard/integration/Cargo.toml | 2 ++ .../rust/standard/integration/src/mtls/mod.rs | 20 +++++++++---------- bindings/rust/standard/tls-harness/Cargo.toml | 5 +++++ .../standard/tls-harness/src/cohort/mod.rs | 4 ++-- nix/shell.sh | 2 +- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/bindings/rust/standard/integration/Cargo.toml b/bindings/rust/standard/integration/Cargo.toml index 94999c67494..b95625597c8 100644 --- a/bindings/rust/standard/integration/Cargo.toml +++ b/bindings/rust/standard/integration/Cargo.toml @@ -18,6 +18,8 @@ no-sensitive-tests = [] # can be disabled by turning off this feature. pq = [ "s2n-tls/pq" ] +boringssl = ["tls-harness/boringssl"] + [dependencies] s2n-tls = { path = "../../extended/s2n-tls", features = ["unstable-testing", "unstable-crl"]} s2n-tls-hyper = { path = "../s2n-tls-hyper" } diff --git a/bindings/rust/standard/integration/src/mtls/mod.rs b/bindings/rust/standard/integration/src/mtls/mod.rs index 768509a0d1a..9200ae8a634 100644 --- a/bindings/rust/standard/integration/src/mtls/mod.rs +++ b/bindings/rust/standard/integration/src/mtls/mod.rs @@ -27,7 +27,7 @@ use std::{ // NOTE: BoringSSL tests are disabled on macOS to avoid symbol collisions with // OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] use boring::ssl::SslVersion; use rustls::ClientConfig; @@ -50,7 +50,7 @@ use tls_harness::{ PemType, SigType, TlsConnPair, TlsConnection, }; -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] use tls_harness::cohort::{BoringSslConfig, BoringSslConnection}; const APP_DATA_SIZE: usize = 100_000; @@ -217,7 +217,7 @@ fn rustls_mtls_server( server.into() } -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] fn boringssl_mtls_client(sig_type: SigType, version: SslVersion) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; @@ -248,7 +248,7 @@ fn boringssl_mtls_client(sig_type: SigType, version: SslVersion) -> BoringSslCon } } -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] fn boringssl_mtls_server(sig_type: SigType, version: SslVersion) -> BoringSslConfig { use tls_harness::harness::{Mode, TlsConfigBuilder}; @@ -335,7 +335,7 @@ fn rustls_client_basic() { } // s2n client, boringssl server -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] #[test] fn boringssl_server_basic() { // TLS 1.2 @@ -361,7 +361,7 @@ fn boringssl_server_basic() { } // boringssl client, s2n server -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] #[test] fn boringssl_client_basic() { // TLS 1.2 @@ -469,7 +469,7 @@ fn rustls_client_sync_callback() { } // s2n client with sync callback, boringssl server -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] #[test] fn boringssl_server_sync_callback() { // TLS 1.2 @@ -501,7 +501,7 @@ fn boringssl_server_sync_callback() { } // boringssl client, s2n server with sync callback -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] #[test] fn boringssl_client_sync_callback() { // TLS 1.2 @@ -669,7 +669,7 @@ fn rustls_client_async_callback() { } // s2n client with async callback, boringssl server -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] #[test] fn boringssl_server_async_callback() { // TLS 1.2 @@ -703,7 +703,7 @@ fn boringssl_server_async_callback() { } // boringssl client, s2n server with async callback -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] #[test] fn boringssl_client_async_callback() { // TLS 1.2 diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index f17b3f077e4..198140142f3 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -1,3 +1,7 @@ +[features] +default = [] +boringssl = ["dep:boring"] + [package] name = "tls-harness" version = "0.1.0" @@ -14,6 +18,7 @@ rustls-pemfile = "2.2.0" openssl = { version = "0.10.73", features = ["vendored"] } openssl-sys = "0.9.109" byteorder = "1.5.0" +boring = { git = "https://github.com/kaukabrizvi/boring.git", branch = "symbol-prefixing", features = ["prefix-symbols"], optional = true } brass-aphid-wire-decryption = "0.0.1" brass-aphid-wire-messages = "0.0.1" diff --git a/bindings/rust/standard/tls-harness/src/cohort/mod.rs b/bindings/rust/standard/tls-harness/src/cohort/mod.rs index b88ad3ff85f..1864a93f5b3 100644 --- a/bindings/rust/standard/tls-harness/src/cohort/mod.rs +++ b/bindings/rust/standard/tls-harness/src/cohort/mod.rs @@ -15,12 +15,12 @@ pub mod s2n_tls; // NOTE: BoringSSL is disabled on macOS to avoid symbol collisions with // OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] pub mod boringssl; pub use openssl::{OpenSslConfig, OpenSslConnection}; pub use rustls::{RustlsConfig, RustlsConnection}; pub use s2n_tls::{S2NConfig, S2NConnection}; -#[cfg(not(target_os = "macos"))] +#[cfg(all(feature = "boringssl", not(target_os = "macos")))] pub use boringssl::{BoringSslConfig, BoringSslConnection}; diff --git a/nix/shell.sh b/nix/shell.sh index 96ca7cc9c75..938d555ea37 100644 --- a/nix/shell.sh +++ b/nix/shell.sh @@ -256,5 +256,5 @@ function rust_test {(set -e export S2N_TLS_LIB_DIR=$(pwd)/build/lib export S2N_TLS_INCLUDE_DIR=$(pwd)/api echo "rust_test: Running Rust integration tests" - cargo test --manifest-path bindings/rust/standard/integration/Cargo.toml + cargo test --manifest-path bindings/rust/standard/integration/Cargo.toml --features boringssl )} From 3c784519ce3c990cccc6dfe8410f1249e69a4186 Mon Sep 17 00:00:00 2001 From: Kaukab Date: Wed, 31 Dec 2025 18:33:13 +0000 Subject: [PATCH 25/25] Point to fork's main branch --- bindings/rust/standard/integration/Cargo.toml | 1 - bindings/rust/standard/tls-harness/Cargo.toml | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bindings/rust/standard/integration/Cargo.toml b/bindings/rust/standard/integration/Cargo.toml index b95625597c8..214a589423b 100644 --- a/bindings/rust/standard/integration/Cargo.toml +++ b/bindings/rust/standard/integration/Cargo.toml @@ -54,7 +54,6 @@ tabled = "0.20.0" # OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. [target.'cfg(not(target_os = "macos"))'.dev-dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" -branch = "symbol-prefixing" features = ["prefix-symbols"] [build-dependencies] diff --git a/bindings/rust/standard/tls-harness/Cargo.toml b/bindings/rust/standard/tls-harness/Cargo.toml index 198140142f3..01fd06a3c23 100644 --- a/bindings/rust/standard/tls-harness/Cargo.toml +++ b/bindings/rust/standard/tls-harness/Cargo.toml @@ -18,7 +18,7 @@ rustls-pemfile = "2.2.0" openssl = { version = "0.10.73", features = ["vendored"] } openssl-sys = "0.9.109" byteorder = "1.5.0" -boring = { git = "https://github.com/kaukabrizvi/boring.git", branch = "symbol-prefixing", features = ["prefix-symbols"], optional = true } +boring = { git = "https://github.com/kaukabrizvi/boring.git", features = ["prefix-symbols"], optional = true } brass-aphid-wire-decryption = "0.0.1" brass-aphid-wire-messages = "0.0.1" @@ -27,7 +27,6 @@ brass-aphid-wire-messages = "0.0.1" # OpenSSL; see https://github.com/aws/s2n-tls/pull/5659 for details. [target.'cfg(not(target_os = "macos"))'.dependencies.boring] git = "https://github.com/kaukabrizvi/boring.git" -branch = "symbol-prefixing" features = ["prefix-symbols"] [dev-dependencies]