From bf80ab4e117051070e365ed3dea216fa029393fb Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 25 Mar 2024 13:53:13 -0700 Subject: [PATCH 1/9] Made Client Hello methods public --- bindings/rust/s2n-tls/Cargo.toml | 3 +- bindings/rust/s2n-tls/src/client_hello.rs | 56 ++++++++++++++--------- bindings/rust/s2n-tls/src/connection.rs | 1 - bindings/rust/s2n-tls/src/lib.rs | 1 - 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/bindings/rust/s2n-tls/Cargo.toml b/bindings/rust/s2n-tls/Cargo.toml index bf59ff742f6..8a6a57906a9 100644 --- a/bindings/rust/s2n-tls/Cargo.toml +++ b/bindings/rust/s2n-tls/Cargo.toml @@ -10,7 +10,6 @@ license = "Apache-2.0" [features] default = [] -unstable-fingerprint = ["s2n-tls-sys/unstable-fingerprint"] quic = ["s2n-tls-sys/quic"] pq = ["s2n-tls-sys/pq"] testing = ["bytes"] @@ -19,7 +18,7 @@ testing = ["bytes"] bytes = { version = "1", optional = true } errno = { version = "0.3" } libc = "0.2" -s2n-tls-sys = { version = "=0.2.0", path = "../s2n-tls-sys", features = ["internal"] } +s2n-tls-sys = { version = "=0.2.0", path = "../s2n-tls-sys", features = ["internal", "unstable-fingerprint"] } pin-project-lite = "0.2" hex = "0.4" diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index dab6e2444db..11d62944d7f 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -147,7 +147,7 @@ impl ClientHello { Ok(()) } - fn session_id(&self) -> Result, Error> { + pub fn session_id(&self) -> Result, Error> { let mut session_id_length = 0; unsafe { s2n_client_hello_get_session_id_length(self.deref_mut_ptr(), &mut session_id_length) @@ -168,7 +168,7 @@ impl ClientHello { Ok(session_id) } - fn server_name(&self) -> Result, Error> { + pub fn server_name(&self) -> Result, Error> { let mut server_name_length = 0; unsafe { s2n_client_hello_get_server_name_length(self.deref_mut_ptr(), &mut server_name_length) @@ -278,6 +278,29 @@ mod tests { ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap() } + fn known_value_client_hello() -> Vec{ + vec![ + 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, + 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, + 0x8c, 0xc7, 0xbd, 0x0a, 0x06, 0xc2, 0xa5, 0x14, 0xfc, 0x34, 0x20, 0xaf, 0x72, 0xbf, + 0x39, 0x99, 0xfb, 0x20, 0x70, 0xc3, 0x10, 0x83, 0x0c, 0xee, 0xfb, 0xfa, 0x72, 0xcc, + 0x5d, 0xa8, 0x99, 0xb4, 0xc5, 0x53, 0xd6, 0x3d, 0xa0, 0x53, 0x7a, 0x5c, 0xbc, 0xf5, + 0x0b, 0x00, 0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, + 0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, + 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x21, 0x00, 0x00, 0x1e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c, + 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, + 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, + 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, + 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, + 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, + 0x40, 0x00, + ] + } + // test that a fingerprint can successfully be calculated from ClientHellos // returned from a connection #[checkers::test] @@ -343,26 +366,7 @@ mod tests { // known value test case copied from s2n_fingerprint_ja3_test.c #[checkers::test] fn valid_client_bytes() { - let raw_client_hello = vec![ - 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, - 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, - 0x8c, 0xc7, 0xbd, 0x0a, 0x06, 0xc2, 0xa5, 0x14, 0xfc, 0x34, 0x20, 0xaf, 0x72, 0xbf, - 0x39, 0x99, 0xfb, 0x20, 0x70, 0xc3, 0x10, 0x83, 0x0c, 0xee, 0xfb, 0xfa, 0x72, 0xcc, - 0x5d, 0xa8, 0x99, 0xb4, 0xc5, 0x53, 0xd6, 0x3d, 0xa0, 0x53, 0x7a, 0x5c, 0xbc, 0xf5, - 0x0b, 0x00, 0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, - 0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, - 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x23, 0x00, - 0x21, 0x00, 0x00, 0x1e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c, - 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, - 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, - 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, - 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, - 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, - 0x40, 0x00, - ]; + let raw_client_hello= known_value_client_hello(); let expected_fingerprint = "771,49195-49199-52393-52392-49196-49200-\ 49162-49161-49171-49172-51-57-47-53-10,0-\ 23-65281-10-11-35-16-5-13-28,29-23-24-25,0"; @@ -404,4 +408,12 @@ mod tests { let client_hello_debug = format!("{:?}", client_hello); assert!(client_hello_debug.contains(&hex::encode(hash))); } + + #[test] + fn server_name() { + let raw_client_hello = known_value_client_hello(); + let client_hello = ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap(); + let server_name = client_hello.server_name().unwrap(); + assert_eq!("incoming.telemetry.mozilla.org".as_bytes(), server_name); + } } diff --git a/bindings/rust/s2n-tls/src/connection.rs b/bindings/rust/s2n-tls/src/connection.rs index 90126ed4cc5..1a945f7d570 100644 --- a/bindings/rust/s2n-tls/src/connection.rs +++ b/bindings/rust/s2n-tls/src/connection.rs @@ -752,7 +752,6 @@ impl Connection { /// client_hello.fingerprint_hash(FingerprintType::JA3, &mut hash); /// drop(conn); /// ``` - #[cfg(feature = "unstable-fingerprint")] pub fn client_hello(&self) -> Result<&crate::client_hello::ClientHello, Error> { let mut handle = unsafe { s2n_connection_get_client_hello(self.connection.as_ptr()).into_result()? }; diff --git a/bindings/rust/s2n-tls/src/lib.rs b/bindings/rust/s2n-tls/src/lib.rs index 78b4e81c572..40bbb6dd1ff 100644 --- a/bindings/rust/s2n-tls/src/lib.rs +++ b/bindings/rust/s2n-tls/src/lib.rs @@ -15,7 +15,6 @@ pub mod error; pub mod callbacks; pub mod cert_chain; -#[cfg(feature = "unstable-fingerprint")] pub mod client_hello; pub mod config; pub mod connection; From 6b1384c42941128619028ad1da4d972b68580056 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 25 Mar 2024 13:56:25 -0700 Subject: [PATCH 2/9] cargo fmt --- bindings/rust/s2n-tls/src/client_hello.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 11d62944d7f..e554984ac28 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -278,7 +278,7 @@ mod tests { ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap() } - fn known_value_client_hello() -> Vec{ + fn known_value_client_hello() -> Vec { vec![ 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, @@ -366,7 +366,7 @@ mod tests { // known value test case copied from s2n_fingerprint_ja3_test.c #[checkers::test] fn valid_client_bytes() { - let raw_client_hello= known_value_client_hello(); + let raw_client_hello = known_value_client_hello(); let expected_fingerprint = "771,49195-49199-52393-52392-49196-49200-\ 49162-49161-49171-49172-51-57-47-53-10,0-\ 23-65281-10-11-35-16-5-13-28,29-23-24-25,0"; From 70fa9b5ef7e91a015dd41c90a2cb02015fccad2f Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 25 Mar 2024 16:40:02 -0700 Subject: [PATCH 3/9] PR feedback --- bindings/rust/s2n-tls/Cargo.toml | 3 ++- bindings/rust/s2n-tls/src/client_hello.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/bindings/rust/s2n-tls/Cargo.toml b/bindings/rust/s2n-tls/Cargo.toml index 8a6a57906a9..bf59ff742f6 100644 --- a/bindings/rust/s2n-tls/Cargo.toml +++ b/bindings/rust/s2n-tls/Cargo.toml @@ -10,6 +10,7 @@ license = "Apache-2.0" [features] default = [] +unstable-fingerprint = ["s2n-tls-sys/unstable-fingerprint"] quic = ["s2n-tls-sys/quic"] pq = ["s2n-tls-sys/pq"] testing = ["bytes"] @@ -18,7 +19,7 @@ testing = ["bytes"] bytes = { version = "1", optional = true } errno = { version = "0.3" } libc = "0.2" -s2n-tls-sys = { version = "=0.2.0", path = "../s2n-tls-sys", features = ["internal", "unstable-fingerprint"] } +s2n-tls-sys = { version = "=0.2.0", path = "../s2n-tls-sys", features = ["internal"] } pin-project-lite = "0.2" hex = "0.4" diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index e554984ac28..5bc1eac8dc7 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -6,6 +6,7 @@ use s2n_tls_sys::*; use std::fmt; #[derive(Copy, Clone)] +#[cfg(feature = "unstable-fingerprint")] pub enum FingerprintType { JA3, } @@ -13,6 +14,7 @@ pub enum FingerprintType { // this is the size of the MD5 hash digest that is used for the JA3 fingerprint const MD5_HASH_SIZE: u32 = 16; +#[cfg(feature = "unstable-fingerprint")] impl From for s2n_tls_sys::s2n_fingerprint_type::Type { fn from(value: FingerprintType) -> Self { match value { @@ -94,6 +96,7 @@ impl ClientHello { /// to construct a string of appropriate capacity to call /// `fingerprint_string`. `output` will be extended if necessary to store /// the full hash. + #[cfg(feature = "unstable-fingerprint")] pub fn fingerprint_hash( &self, hash: FingerprintType, @@ -125,6 +128,7 @@ impl ClientHello { /// `fingerprint_string` will try to calculate the fingerprint and store the /// resulting string in `output`. If `output` does not have sufficient /// capacity an Error of `ErrorType::UsageError` will be returned. + #[cfg(feature = "unstable-fingerprint")] pub fn fingerprint_string( &self, hash: FingerprintType, @@ -189,7 +193,7 @@ impl ClientHello { Ok(server_name) } - fn raw_message(&self) -> Result, Error> { + pub fn raw_message(&self) -> Result, Error> { let message_length = unsafe { s2n_client_hello_get_raw_message_length(self.deref_mut_ptr()).into_result()? }; @@ -217,6 +221,7 @@ impl Drop for ClientHello { } } +#[cfg(feature = "unstable-fingerprint")] impl fmt::Debug for ClientHello { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let session_id = self.session_id().map_err(|_| fmt::Error)?; @@ -304,6 +309,7 @@ mod tests { // test that a fingerprint can successfully be calculated from ClientHellos // returned from a connection #[checkers::test] + #[cfg(feature = "unstable-fingerprint")] fn io_fingerprint_test() { let config = crate::testing::config_builder(&security::DEFAULT_TLS13) .unwrap() @@ -333,6 +339,7 @@ mod tests { assert!(check_client_hello(client_conn).is_ok()); } + #[cfg(feature = "unstable-fingerprint")] fn known_test_case( raw_client_hello: Vec, expected_string: &str, @@ -365,6 +372,7 @@ mod tests { // known value test case copied from s2n_fingerprint_ja3_test.c #[checkers::test] + #[cfg(feature = "unstable-fingerprint")] fn valid_client_bytes() { let raw_client_hello = known_value_client_hello(); let expected_fingerprint = "771,49195-49199-52393-52392-49196-49200-\ @@ -375,6 +383,7 @@ mod tests { } #[test] + #[cfg(feature = "unstable-fingerprint")] fn hash_output_resizing() { let client_hello = get_client_hello(); let hash_capacities = vec![0, MD5_HASH_SIZE, 1_000]; @@ -388,6 +397,7 @@ mod tests { } #[test] + #[cfg(feature = "unstable-fingerprint")] fn string_output_too_small() { let client_hello = get_client_hello(); let mut fingerprint_string = String::with_capacity(0); @@ -399,6 +409,7 @@ mod tests { // make sure that debug doesn't panic and seems reasonable #[test] + #[cfg(feature = "unstable-fingerprint")] fn debug() { let client_hello = get_client_hello(); let mut hash = Vec::new(); From 328381bd141c943d4d9fef7b2efaa22104779706 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 25 Mar 2024 17:30:03 -0700 Subject: [PATCH 4/9] Appease clippy --- bindings/rust/s2n-tls/src/client_hello.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 5bc1eac8dc7..71c5adc7727 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -12,6 +12,7 @@ pub enum FingerprintType { } // this is the size of the MD5 hash digest that is used for the JA3 fingerprint +#[cfg(feature = "unstable-fingerprint")] const MD5_HASH_SIZE: u32 = 16; #[cfg(feature = "unstable-fingerprint")] @@ -221,19 +222,14 @@ impl Drop for ClientHello { } } -#[cfg(feature = "unstable-fingerprint")] impl fmt::Debug for ClientHello { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let session_id = self.session_id().map_err(|_| fmt::Error)?; let session_id = hex::encode(session_id); let message_head = self.raw_message().map_err(|_| fmt::Error)?; - let mut hash = Vec::new(); - self.fingerprint_hash(FingerprintType::JA3, &mut hash) - .map_err(|_| fmt::Error)?; f.debug_struct("ClientHello") .field("session_id", &session_id) .field("message_len", &(message_head.len())) - .field("ja3_fingerprint", &hex::encode(hash)) .finish_non_exhaustive() } } From 7bdd3529f3e6aa2f6e2b53c51dbec538d53f9e35 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 25 Mar 2024 20:24:18 -0700 Subject: [PATCH 5/9] Split fingerprint code into modul --- bindings/rust/s2n-tls/src/client_hello.rs | 495 +++++++++++----------- 1 file changed, 254 insertions(+), 241 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 71c5adc7727..17545e9c329 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -5,25 +5,6 @@ use crate::error::{Error, Fallible}; use s2n_tls_sys::*; use std::fmt; -#[derive(Copy, Clone)] -#[cfg(feature = "unstable-fingerprint")] -pub enum FingerprintType { - JA3, -} - -// this is the size of the MD5 hash digest that is used for the JA3 fingerprint -#[cfg(feature = "unstable-fingerprint")] -const MD5_HASH_SIZE: u32 = 16; - -#[cfg(feature = "unstable-fingerprint")] -impl From for s2n_tls_sys::s2n_fingerprint_type::Type { - fn from(value: FingerprintType) -> Self { - match value { - FingerprintType::JA3 => s2n_tls_sys::s2n_fingerprint_type::FINGERPRINT_JA3, - } - } -} - // ClientHello is an opaque wrapper struct around `s2n_client_hello`. Note that // the size of this type is not known, and as such it can only be used through // references and pointers. @@ -92,66 +73,6 @@ impl ClientHello { &self.0 as *const s2n_client_hello as *mut s2n_client_hello } - /// `fingerprint_hash` calculates the hash, and also returns the size - /// required for the full fingerprint string. The return value can be used - /// to construct a string of appropriate capacity to call - /// `fingerprint_string`. `output` will be extended if necessary to store - /// the full hash. - #[cfg(feature = "unstable-fingerprint")] - pub fn fingerprint_hash( - &self, - hash: FingerprintType, - output: &mut Vec, - ) -> Result { - let mut hash_size: u32 = 0; - let mut str_size: u32 = 0; - // make sure the vec has sufficient space for the hash - if output.capacity() < MD5_HASH_SIZE as usize { - output.reserve_exact(MD5_HASH_SIZE as usize - output.len()); - } - unsafe { - s2n_client_hello_get_fingerprint_hash( - self.deref_mut_ptr(), - hash.into(), - MD5_HASH_SIZE, - output.as_mut_ptr(), - &mut hash_size, - &mut str_size, - ) - .into_result()?; - // SAFETY: we wrote to the raw vec (using the mut pointer), and need - // to update the state of the vec to reflect the changes we made. - output.set_len(hash_size as usize); - }; - Ok(str_size) - } - - /// `fingerprint_string` will try to calculate the fingerprint and store the - /// resulting string in `output`. If `output` does not have sufficient - /// capacity an Error of `ErrorType::UsageError` will be returned. - #[cfg(feature = "unstable-fingerprint")] - pub fn fingerprint_string( - &self, - hash: FingerprintType, - output: &mut String, - ) -> Result<(), Error> { - let mut output_size = 0; - unsafe { - s2n_tls_sys::s2n_client_hello_get_fingerprint_string( - self.deref_mut_ptr(), - hash.into(), - output.capacity() as u32, - output.as_mut_ptr(), - &mut output_size, - ) - .into_result()?; - // SAFETY: update internal state of string to match the data written - // into it. - output.as_mut_vec().set_len(output_size as usize); - }; - Ok(()) - } - pub fn session_id(&self) -> Result, Error> { let mut session_id_length = 0; unsafe { @@ -211,6 +132,249 @@ impl ClientHello { } } +// Fingerprinting is an unstable feature. This module can be removed and added +// to the client_hello module once we have settled on an implementation. +#[cfg(feature = "unstable-fingerprint")] +pub mod fingerprint { + use crate::error::{Error, Fallible}; + use s2n_tls_sys::*; + + use super::ClientHello; + + #[derive(Copy, Clone)] + pub enum FingerprintType { + JA3, + } + + // this is the size of the MD5 hash digest that is used for the JA3 fingerprint + const MD5_HASH_SIZE: u32 = 16; + + impl From for s2n_tls_sys::s2n_fingerprint_type::Type { + fn from(value: FingerprintType) -> Self { + match value { + FingerprintType::JA3 => s2n_tls_sys::s2n_fingerprint_type::FINGERPRINT_JA3, + } + } + } + + impl ClientHello { + /// `fingerprint_hash` calculates the hash, and also returns the size + /// required for the full fingerprint string. The return value can be used + /// to construct a string of appropriate capacity to call + /// `fingerprint_string`. `output` will be extended if necessary to store + /// the full hash. + pub fn fingerprint_hash( + &self, + hash: FingerprintType, + output: &mut Vec, + ) -> Result { + let mut hash_size: u32 = 0; + let mut str_size: u32 = 0; + // make sure the vec has sufficient space for the hash + if output.capacity() < MD5_HASH_SIZE as usize { + output.reserve_exact(MD5_HASH_SIZE as usize - output.len()); + } + unsafe { + s2n_client_hello_get_fingerprint_hash( + self.deref_mut_ptr(), + hash.into(), + MD5_HASH_SIZE, + output.as_mut_ptr(), + &mut hash_size, + &mut str_size, + ) + .into_result()?; + // SAFETY: we wrote to the raw vec (using the mut pointer), and need + // to update the state of the vec to reflect the changes we made. + output.set_len(hash_size as usize); + }; + Ok(str_size) + } + + /// `fingerprint_string` will try to calculate the fingerprint and store the + /// resulting string in `output`. If `output` does not have sufficient + /// capacity an Error of `ErrorType::UsageError` will be returned. + pub fn fingerprint_string( + &self, + hash: FingerprintType, + output: &mut String, + ) -> Result<(), Error> { + let mut output_size = 0; + unsafe { + s2n_tls_sys::s2n_client_hello_get_fingerprint_string( + self.deref_mut_ptr(), + hash.into(), + output.capacity() as u32, + output.as_mut_ptr(), + &mut output_size, + ) + .into_result()?; + // SAFETY: update internal state of string to match the data written + // into it. + output.as_mut_vec().set_len(output_size as usize); + }; + Ok(()) + } + } + + #[cfg(test)] + mod tests { + use crate::{ + client_hello::{ + fingerprint::{FingerprintType, MD5_HASH_SIZE}, + ClientHello, + }, + connection::Connection, + error::{Error, ErrorType}, + security, + testing::{poll_tls_pair, tls_pair}, + }; + + /// This function is a test fixture used a generate a valid ClientHello so + /// that we don't have to copy and paste the raw bytes for test fixtures + fn get_client_hello_bytes() -> Vec { + let config = crate::testing::config_builder(&security::DEFAULT_TLS13) + .unwrap() + .build() + .unwrap(); + let pair = tls_pair(config); + let pair = poll_tls_pair(pair); + // this doesn't have the handshake header + let client_hello_message = pair + .server + .0 + .connection() + .client_hello() + .unwrap() + .raw_message() + .unwrap(); + // handshake header is {tag: u8, client_hello_length: u24} + let mut client_hello = vec![0; 4]; + // As long as the client hello is small, no bit fiddling is required + assert!(client_hello_message.len() < u8::MAX as usize); + // tag for handshake header + client_hello[0] = 1; + client_hello[3] = client_hello_message.len() as u8; + client_hello.extend(client_hello_message.iter()); + client_hello + } + + fn known_test_case( + raw_client_hello: Vec, + expected_string: &str, + expected_hash_hex: &str, + ) -> Result<(), Error> { + let expected_hash: Vec = hex::decode(expected_hash_hex).unwrap(); + let client_hello = + ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap(); + + let mut hash = Vec::new(); + let string_size = client_hello + .fingerprint_hash(FingerprintType::JA3, &mut hash) + .unwrap(); + assert_eq!(hash, expected_hash); + + let mut string = String::with_capacity(string_size as usize); + client_hello + .fingerprint_string(FingerprintType::JA3, &mut string) + .unwrap(); + assert_eq!(string, expected_string); + Ok(()) + } + + fn get_client_hello() -> Box { + // sets up connection and handshakes + let raw_client_hello = get_client_hello_bytes(); + ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap() + } + + // test that a fingerprint can successfully be calculated from ClientHellos + // returned from a connection + #[checkers::test] + fn io_fingerprint_test() { + let config = crate::testing::config_builder(&security::DEFAULT_TLS13) + .unwrap() + .build() + .unwrap(); + let pair = crate::testing::tls_pair(config); + + // client_hellos can not be accessed before the handshake + assert!(pair.client.0.connection().client_hello().is_err()); + assert!(pair.server.0.connection().client_hello().is_err()); + + let pair = poll_tls_pair(pair); + let server_conn = pair.server.0.connection(); + let client_conn = pair.server.0.connection(); + + let check_client_hello = |conn: &Connection| -> Result<(), Error> { + let client_hello = conn.client_hello().unwrap(); + let mut hash = Vec::new(); + let fingerprint_size = + client_hello.fingerprint_hash(FingerprintType::JA3, &mut hash)?; + let mut string = String::with_capacity(fingerprint_size as usize); + client_hello.fingerprint_string(FingerprintType::JA3, &mut string)?; + Ok(()) + }; + + assert!(check_client_hello(server_conn).is_ok()); + assert!(check_client_hello(client_conn).is_ok()); + } + + // known value test case copied from s2n_fingerprint_ja3_test.c + #[checkers::test] + fn valid_client_bytes() { + let raw_client_hello = vec![ + 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, + 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, + 0x8c, 0xc7, 0xbd, 0x0a, 0x06, 0xc2, 0xa5, 0x14, 0xfc, 0x34, 0x20, 0xaf, 0x72, 0xbf, + 0x39, 0x99, 0xfb, 0x20, 0x70, 0xc3, 0x10, 0x83, 0x0c, 0xee, 0xfb, 0xfa, 0x72, 0xcc, + 0x5d, 0xa8, 0x99, 0xb4, 0xc5, 0x53, 0xd6, 0x3d, 0xa0, 0x53, 0x7a, 0x5c, 0xbc, 0xf5, + 0x0b, 0x00, 0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, + 0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, + 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x21, 0x00, 0x00, 0x1e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c, + 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, + 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, + 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, + 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, + 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, + 0x40, 0x00, + ]; + let expected_fingerprint = "771,49195-49199-52393-52392-49196-49200-\ + 49162-49161-49171-49172-51-57-47-53-10,0-\ + 23-65281-10-11-35-16-5-13-28,29-23-24-25,0"; + let expected_hash_hex = "839bbe3ed07fed922ded5aaf714d6842"; + known_test_case(raw_client_hello, expected_fingerprint, expected_hash_hex).unwrap(); + } + + #[test] + fn hash_output_resizing() { + let client_hello = get_client_hello(); + let hash_capacities = vec![0, MD5_HASH_SIZE, 1_000]; + for initial_size in hash_capacities { + let mut hash = Vec::with_capacity(initial_size as usize); + client_hello + .fingerprint_hash(FingerprintType::JA3, &mut hash) + .unwrap(); + assert_eq!(hash.len(), MD5_HASH_SIZE as usize); + } + } + + #[test] + fn string_output_too_small() { + let client_hello = get_client_hello(); + let mut fingerprint_string = String::with_capacity(0); + let fingerprint_err = client_hello + .fingerprint_string(FingerprintType::JA3, &mut fingerprint_string) + .unwrap_err(); + assert_eq!(fingerprint_err.kind(), ErrorType::UsageError); + } + } +} + impl Drop for ClientHello { fn drop(&mut self) { let mut client_hello: *mut s2n_client_hello = &mut self.0; @@ -236,51 +400,19 @@ impl fmt::Debug for ClientHello { #[cfg(test)] mod tests { - use super::*; - use crate::{ - connection::Connection, - error::{Error, ErrorType}, - security, - testing::{poll_tls_pair, tls_pair}, - }; - - /// This function is a test fixture used a generate a valid ClientHello so - /// that we don't have to copy and paste the raw bytes for test fixtures - fn get_client_hello_bytes() -> Vec { - let config = crate::testing::config_builder(&security::DEFAULT_TLS13) - .unwrap() - .build() - .unwrap(); - let pair = tls_pair(config); - let pair = poll_tls_pair(pair); - // this doesn't have the handshake header - let client_hello_message = pair - .server - .0 - .connection() - .client_hello() - .unwrap() - .raw_message() - .unwrap(); - // handshake header is {tag: u8, client_hello_length: u24} - let mut client_hello = vec![0; 4]; - // As long as the client hello is small, no bit fiddling is required - assert!(client_hello_message.len() < u8::MAX as usize); - // tag for handshake header - client_hello[0] = 1; - client_hello[3] = client_hello_message.len() as u8; - client_hello.extend(client_hello_message.iter()); - client_hello - } + use crate::client_hello::ClientHello; - fn get_client_hello() -> Box { - // sets up connection and handshakes - let raw_client_hello = get_client_hello_bytes(); - ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap() + #[test] + fn invalid_client_bytes() { + let raw_client_hello_bytes = + "random_value_that_is_unlikely_to_be_valid_client_hello".as_bytes(); + let result = ClientHello::parse_client_hello(raw_client_hello_bytes); + assert!(result.is_err()); } - fn known_value_client_hello() -> Vec { - vec![ + #[test] + fn server_name() { + let raw_client_hello = vec![ 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, 0x8c, 0xc7, 0xbd, 0x0a, 0x06, 0xc2, 0xa5, 0x14, 0xfc, 0x34, 0x20, 0xaf, 0x72, 0xbf, @@ -299,126 +431,7 @@ mod tests { 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x00, - ] - } - - // test that a fingerprint can successfully be calculated from ClientHellos - // returned from a connection - #[checkers::test] - #[cfg(feature = "unstable-fingerprint")] - fn io_fingerprint_test() { - let config = crate::testing::config_builder(&security::DEFAULT_TLS13) - .unwrap() - .build() - .unwrap(); - let pair = crate::testing::tls_pair(config); - - // client_hellos can not be accessed before the handshake - assert!(pair.client.0.connection().client_hello().is_err()); - assert!(pair.server.0.connection().client_hello().is_err()); - - let pair = poll_tls_pair(pair); - let server_conn = pair.server.0.connection(); - let client_conn = pair.server.0.connection(); - - let check_client_hello = |conn: &Connection| -> Result<(), Error> { - let client_hello = conn.client_hello().unwrap(); - let mut hash = Vec::new(); - let fingerprint_size = - client_hello.fingerprint_hash(FingerprintType::JA3, &mut hash)?; - let mut string = String::with_capacity(fingerprint_size as usize); - client_hello.fingerprint_string(FingerprintType::JA3, &mut string)?; - Ok(()) - }; - - assert!(check_client_hello(server_conn).is_ok()); - assert!(check_client_hello(client_conn).is_ok()); - } - - #[cfg(feature = "unstable-fingerprint")] - fn known_test_case( - raw_client_hello: Vec, - expected_string: &str, - expected_hash_hex: &str, - ) -> Result<(), Error> { - let expected_hash: Vec = hex::decode(expected_hash_hex).unwrap(); - let client_hello = ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap(); - - let mut hash = Vec::new(); - let string_size = client_hello - .fingerprint_hash(FingerprintType::JA3, &mut hash) - .unwrap(); - assert_eq!(hash, expected_hash); - - let mut string = String::with_capacity(string_size as usize); - client_hello - .fingerprint_string(FingerprintType::JA3, &mut string) - .unwrap(); - assert_eq!(string, expected_string); - Ok(()) - } - - #[test] - fn invalid_client_bytes() { - let raw_client_hello_bytes = - "random_value_that_is_unlikely_to_be_valid_client_hello".as_bytes(); - let result = ClientHello::parse_client_hello(raw_client_hello_bytes); - assert!(result.is_err()); - } - - // known value test case copied from s2n_fingerprint_ja3_test.c - #[checkers::test] - #[cfg(feature = "unstable-fingerprint")] - fn valid_client_bytes() { - let raw_client_hello = known_value_client_hello(); - let expected_fingerprint = "771,49195-49199-52393-52392-49196-49200-\ - 49162-49161-49171-49172-51-57-47-53-10,0-\ - 23-65281-10-11-35-16-5-13-28,29-23-24-25,0"; - let expected_hash_hex = "839bbe3ed07fed922ded5aaf714d6842"; - known_test_case(raw_client_hello, expected_fingerprint, expected_hash_hex).unwrap(); - } - - #[test] - #[cfg(feature = "unstable-fingerprint")] - fn hash_output_resizing() { - let client_hello = get_client_hello(); - let hash_capacities = vec![0, MD5_HASH_SIZE, 1_000]; - for initial_size in hash_capacities { - let mut hash = Vec::with_capacity(initial_size as usize); - client_hello - .fingerprint_hash(FingerprintType::JA3, &mut hash) - .unwrap(); - assert_eq!(hash.len(), MD5_HASH_SIZE as usize); - } - } - - #[test] - #[cfg(feature = "unstable-fingerprint")] - fn string_output_too_small() { - let client_hello = get_client_hello(); - let mut fingerprint_string = String::with_capacity(0); - let fingerprint_err = client_hello - .fingerprint_string(FingerprintType::JA3, &mut fingerprint_string) - .unwrap_err(); - assert_eq!(fingerprint_err.kind(), ErrorType::UsageError); - } - - // make sure that debug doesn't panic and seems reasonable - #[test] - #[cfg(feature = "unstable-fingerprint")] - fn debug() { - let client_hello = get_client_hello(); - let mut hash = Vec::new(); - client_hello - .fingerprint_hash(FingerprintType::JA3, &mut hash) - .unwrap(); - let client_hello_debug = format!("{:?}", client_hello); - assert!(client_hello_debug.contains(&hex::encode(hash))); - } - - #[test] - fn server_name() { - let raw_client_hello = known_value_client_hello(); + ]; let client_hello = ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap(); let server_name = client_hello.server_name().unwrap(); assert_eq!("incoming.telemetry.mozilla.org".as_bytes(), server_name); From 4ea0dc5b316da3dbeb20591780a367f3cb339290 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 25 Mar 2024 20:34:02 -0700 Subject: [PATCH 6/9] Fixes documentation --- bindings/rust/s2n-tls/src/client_hello.rs | 2 +- bindings/rust/s2n-tls/src/connection.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 17545e9c329..00202aa1ffc 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -20,7 +20,7 @@ use std::fmt; // lifetime of the `Connection` struct. /// ```no_run -/// use s2n_tls::client_hello::{ClientHello, FingerprintType}; +/// use s2n_tls::client_hello::{fingerprint::FingerprintType, ClientHello}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// diff --git a/bindings/rust/s2n-tls/src/connection.rs b/bindings/rust/s2n-tls/src/connection.rs index 1a945f7d570..63ebf773c3c 100644 --- a/bindings/rust/s2n-tls/src/connection.rs +++ b/bindings/rust/s2n-tls/src/connection.rs @@ -728,7 +728,7 @@ impl Connection { // /// Returns a reference to the ClientHello associated with the connection. /// ```compile_fail - /// use s2n_tls::client_hello::{ClientHello, FingerprintType}; + /// use s2n_tls::client_hello::{fingerprint::FingerprintType, ClientHello}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// @@ -742,7 +742,7 @@ impl Connection { /// The compilation could be failing for a variety of reasons, so make sure /// that the test case is actually good. /// ```no_run - /// use s2n_tls::client_hello::{ClientHello, FingerprintType}; + /// use s2n_tls::client_hello::{fingerprint::FingerprintType, ClientHello}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// From 3ab0e4678f3ebd39295055a0fb83bb10de502d4a Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 26 Mar 2024 13:27:43 -0700 Subject: [PATCH 7/9] PR feedback --- bindings/rust/s2n-tls/src/client_hello.rs | 55 +++++++++++++---------- bindings/rust/s2n-tls/src/connection.rs | 4 +- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 00202aa1ffc..03207e602c5 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -20,7 +20,7 @@ use std::fmt; // lifetime of the `Connection` struct. /// ```no_run -/// use s2n_tls::client_hello::{fingerprint::FingerprintType, ClientHello}; +/// use s2n_tls::client_hello::{ClientHello, Fingerprint}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// @@ -132,6 +132,9 @@ impl ClientHello { } } +#[cfg(feature = "unstable-fingerprint")] +pub use self::fingerprint::*; + // Fingerprinting is an unstable feature. This module can be removed and added // to the client_hello module once we have settled on an implementation. #[cfg(feature = "unstable-fingerprint")] @@ -218,7 +221,7 @@ pub mod fingerprint { } #[cfg(test)] - mod tests { + pub mod fingerprint_tests { use crate::{ client_hello::{ fingerprint::{FingerprintType, MD5_HASH_SIZE}, @@ -282,12 +285,35 @@ pub mod fingerprint { Ok(()) } - fn get_client_hello() -> Box { + pub fn get_client_hello() -> Box { // sets up connection and handshakes let raw_client_hello = get_client_hello_bytes(); ClientHello::parse_client_hello(raw_client_hello.as_slice()).unwrap() } + pub fn client_hello_bytes() -> Vec { + vec![ + 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, + 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, + 0x8c, 0xc7, 0xbd, 0x0a, 0x06, 0xc2, 0xa5, 0x14, 0xfc, 0x34, 0x20, 0xaf, 0x72, 0xbf, + 0x39, 0x99, 0xfb, 0x20, 0x70, 0xc3, 0x10, 0x83, 0x0c, 0xee, 0xfb, 0xfa, 0x72, 0xcc, + 0x5d, 0xa8, 0x99, 0xb4, 0xc5, 0x53, 0xd6, 0x3d, 0xa0, 0x53, 0x7a, 0x5c, 0xbc, 0xf5, + 0x0b, 0x00, 0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, + 0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, + 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x21, 0x00, 0x00, 0x1e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c, + 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, + 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, + 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, + 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, + 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, + 0x40, 0x00, + ] + } + // test that a fingerprint can successfully be calculated from ClientHellos // returned from a connection #[checkers::test] @@ -323,26 +349,7 @@ pub mod fingerprint { // known value test case copied from s2n_fingerprint_ja3_test.c #[checkers::test] fn valid_client_bytes() { - let raw_client_hello = vec![ - 0x01, 0x00, 0x00, 0xEC, 0x03, 0x03, 0x90, 0xe8, 0xcc, 0xee, 0xe5, 0x70, 0xa2, 0xa1, - 0x2f, 0x6b, 0x69, 0xd2, 0x66, 0x96, 0x0f, 0xcf, 0x20, 0xd5, 0x32, 0x6e, 0xc4, 0xb2, - 0x8c, 0xc7, 0xbd, 0x0a, 0x06, 0xc2, 0xa5, 0x14, 0xfc, 0x34, 0x20, 0xaf, 0x72, 0xbf, - 0x39, 0x99, 0xfb, 0x20, 0x70, 0xc3, 0x10, 0x83, 0x0c, 0xee, 0xfb, 0xfa, 0x72, 0xcc, - 0x5d, 0xa8, 0x99, 0xb4, 0xc5, 0x53, 0xd6, 0x3d, 0xa0, 0x53, 0x7a, 0x5c, 0xbc, 0xf5, - 0x0b, 0x00, 0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, - 0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, - 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x23, 0x00, - 0x21, 0x00, 0x00, 0x1e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c, - 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, - 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, - 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, - 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, - 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x1c, 0x00, 0x02, - 0x40, 0x00, - ]; + let raw_client_hello = client_hello_bytes(); let expected_fingerprint = "771,49195-49199-52393-52392-49196-49200-\ 49162-49161-49171-49172-51-57-47-53-10,0-\ 23-65281-10-11-35-16-5-13-28,29-23-24-25,0"; @@ -390,10 +397,12 @@ impl fmt::Debug for ClientHello { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let session_id = self.session_id().map_err(|_| fmt::Error)?; let session_id = hex::encode(session_id); + let server_name = self.server_name().map_err(|_| fmt::Error)?; let message_head = self.raw_message().map_err(|_| fmt::Error)?; f.debug_struct("ClientHello") .field("session_id", &session_id) .field("message_len", &(message_head.len())) + .field("server_name", &server_name) .finish_non_exhaustive() } } diff --git a/bindings/rust/s2n-tls/src/connection.rs b/bindings/rust/s2n-tls/src/connection.rs index 63ebf773c3c..377902fe7eb 100644 --- a/bindings/rust/s2n-tls/src/connection.rs +++ b/bindings/rust/s2n-tls/src/connection.rs @@ -728,7 +728,7 @@ impl Connection { // /// Returns a reference to the ClientHello associated with the connection. /// ```compile_fail - /// use s2n_tls::client_hello::{fingerprint::FingerprintType, ClientHello}; + /// use s2n_tls::client_hello::{ClientHello, Fingerprint}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// @@ -742,7 +742,7 @@ impl Connection { /// The compilation could be failing for a variety of reasons, so make sure /// that the test case is actually good. /// ```no_run - /// use s2n_tls::client_hello::{fingerprint::FingerprintType, ClientHello}; + /// use s2n_tls::client_hello::{ClientHello, Fingerprint}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// From f0eba397dfdf8075b5bbb9e7d45803a4b83d083a Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 26 Mar 2024 13:29:27 -0700 Subject: [PATCH 8/9] Fixing doc comment --- bindings/rust/s2n-tls/src/client_hello.rs | 2 +- bindings/rust/s2n-tls/src/connection.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 03207e602c5..96a53974362 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -20,7 +20,7 @@ use std::fmt; // lifetime of the `Connection` struct. /// ```no_run -/// use s2n_tls::client_hello::{ClientHello, Fingerprint}; +/// use s2n_tls::client_hello::{ClientHello, FingerprintType}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// diff --git a/bindings/rust/s2n-tls/src/connection.rs b/bindings/rust/s2n-tls/src/connection.rs index 377902fe7eb..1a945f7d570 100644 --- a/bindings/rust/s2n-tls/src/connection.rs +++ b/bindings/rust/s2n-tls/src/connection.rs @@ -728,7 +728,7 @@ impl Connection { // /// Returns a reference to the ClientHello associated with the connection. /// ```compile_fail - /// use s2n_tls::client_hello::{ClientHello, Fingerprint}; + /// use s2n_tls::client_hello::{ClientHello, FingerprintType}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// @@ -742,7 +742,7 @@ impl Connection { /// The compilation could be failing for a variety of reasons, so make sure /// that the test case is actually good. /// ```no_run - /// use s2n_tls::client_hello::{ClientHello, Fingerprint}; + /// use s2n_tls::client_hello::{ClientHello, FingerprintType}; /// use s2n_tls::connection::Connection; /// use s2n_tls::enums::Mode; /// From 202cc71097452932f1dd32f78f682e08c76bdf52 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Thu, 28 Mar 2024 11:45:22 -0700 Subject: [PATCH 9/9] Revert --- bindings/rust/s2n-tls/src/client_hello.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/bindings/rust/s2n-tls/src/client_hello.rs b/bindings/rust/s2n-tls/src/client_hello.rs index 96a53974362..0414c15c73e 100644 --- a/bindings/rust/s2n-tls/src/client_hello.rs +++ b/bindings/rust/s2n-tls/src/client_hello.rs @@ -397,12 +397,10 @@ impl fmt::Debug for ClientHello { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let session_id = self.session_id().map_err(|_| fmt::Error)?; let session_id = hex::encode(session_id); - let server_name = self.server_name().map_err(|_| fmt::Error)?; let message_head = self.raw_message().map_err(|_| fmt::Error)?; f.debug_struct("ClientHello") .field("session_id", &session_id) .field("message_len", &(message_head.len())) - .field("server_name", &server_name) .finish_non_exhaustive() } }