Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bindings/s2n-tls): add client_hello_version #4609

Merged
merged 9 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions bindings/rust/s2n-tls/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,13 +857,28 @@ impl Connection {
Ok(())
}

/// Access the protocol version selected for the connection.
pub fn actual_protocol_version(&self) -> Result<Version, Error> {
let version = unsafe {
s2n_connection_get_actual_protocol_version(self.connection.as_ptr()).into_result()?
};
version.try_into()
}

/// Detects if the client hello is using the SSLv2 format.
///
/// s2n-tls will not negotiate SSLv2, but will accept SSLv2 ClientHellos
/// advertising a higher protocol version like SSLv3 or TLS1.0.
/// [Connection::actual_protocol_version()] can be used to retrieve the
/// protocol version that is actually used on the connection.
pub fn client_hello_is_sslv2(&self) -> Result<bool, Error> {
let version = unsafe {
s2n_connection_get_client_hello_version(self.connection.as_ptr()).into_result()?
};
let version: Version = version.try_into()?;
Ok(version == Version::SSLV2)
}

pub fn handshake_type(&self) -> Result<&str, Error> {
let handshake = unsafe {
s2n_connection_get_handshake_type_name(self.connection.as_ptr()).into_result()?
Expand Down
59 changes: 57 additions & 2 deletions bindings/rust/s2n-tls/src/testing/s2n_tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ impl<'a, T: 'a + Context> Callback<'a, T> {
mod tests {
use crate::{
callbacks::{ClientHelloCallback, ConnectionFuture, ConnectionFutureResult},
enums::ClientAuthType,
enums::{self, ClientAuthType},
error::ErrorType,
testing::{client_hello::*, s2n_tls::*, *},
testing::{self, client_hello::*, s2n_tls::*, *},
};
use alloc::sync::Arc;
use core::sync::atomic::Ordering;
Expand Down Expand Up @@ -1025,4 +1025,59 @@ mod tests {
assert_eq!(protocol, b"h2");
Ok(())
}

#[test]
fn client_hello_sslv2_negative() -> Result<(), testing::Error> {
let config = testing::build_config(&security::DEFAULT_TLS13)?;
let mut pair = TestPair::from_config(&config);
pair.handshake()?;
assert_eq!(pair.server.client_hello_is_sslv2()?, false);
Ok(())
}

#[test]
fn client_hello_sslv2_positive() -> Result<(), testing::Error> {
// copy-pasted from s2n-tls/tests/testlib/s2n_sslv2_client_hello.h
// by concatenating these fields together, a valid SSLv2 formatted client hello
// can be assembled
const SSLV2_CLIENT_HELLO_HEADER: &[u8] = &[0x80, 0xb3, 0x01, 0x03, 0x03];
const SSLV2_CLIENT_HELLO_PREFIX: &[u8] = &[0x00, 0x8a, 0x00, 0x00, 0x00, 0x20];
const SSLV2_CLIENT_HELLO_CIPHER_SUITES: &[u8] = &[
0x00, 0xc0, 0x24, 0x00, 0xc0, 0x28, 0x00, 0x00, 0x3d, 0x00, 0xc0, 0x26, 0x00, 0xc0,
0x2a, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x6a, 0x00, 0xc0, 0x0a, 0x07, 0x00, 0xc0, 0x00,
0xc0, 0x14, 0x00, 0x00, 0x35, 0x00, 0xc0, 0x05, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x39,
0x00, 0x00, 0x38, 0x00, 0xc0, 0x23, 0x00, 0xc0, 0x27, 0x00, 0x00, 0x3c, 0x00, 0xc0,
0x25, 0x00, 0xc0, 0x29, 0x00, 0x00, 0x67, 0x00, 0x00, 0x40, 0x00, 0xc0, 0x09, 0x06,
0x00, 0x40, 0x00, 0xc0, 0x13, 0x00, 0x00, 0x2f, 0x00, 0xc0, 0x04, 0x01, 0x00, 0x80,
0x00, 0xc0, 0x0e, 0x00, 0x00, 0x33, 0x00, 0x00, 0x32, 0x00, 0xc0, 0x2c, 0x00, 0xc0,
0x2b, 0x00, 0xc0, 0x30, 0x00, 0x00, 0x9d, 0x00, 0xc0, 0x2e, 0x00, 0xc0, 0x32, 0x00,
0x00, 0x9f, 0x00, 0x00, 0xa3, 0x00, 0xc0, 0x2f, 0x00, 0x00, 0x9c, 0x00, 0xc0, 0x2d,
0x00, 0xc0, 0x31, 0x00, 0x00, 0x9e, 0x00, 0x00, 0xa2, 0x00, 0x00, 0xff,
];
const SSLV2_CLIENT_HELLO_CHALLENGE: &[u8] = &[
0x5b, 0xe9, 0xcc, 0xad, 0xd6, 0xa5, 0x20, 0xac, 0xa3, 0xf4, 0x8e, 0x88, 0x06, 0xb5,
0x95, 0x53, 0x2d, 0x53, 0xfe, 0xd7, 0xa1, 0x00, 0x57, 0xc0, 0x53, 0x9d, 0x84, 0x71,
0x80, 0x7f, 0x30, 0x7e,
];

let config = testing::build_config(&security::Policy::from_version("test_all")?)?;
// we use the pair to setup IO, but we don't want the client to write anything.
// So we drop the client and just directly write the SSLv2 header to the
// client_tx_stream
let mut pair = TestPair::from_config(&config);
drop(pair.client);

let mut client_tx_stream = pair.client_tx_stream.borrow_mut();
client_tx_stream.write_all(SSLV2_CLIENT_HELLO_HEADER)?;
client_tx_stream.write_all(SSLV2_CLIENT_HELLO_PREFIX)?;
client_tx_stream.write_all(SSLV2_CLIENT_HELLO_CIPHER_SUITES)?;
client_tx_stream.write_all(SSLV2_CLIENT_HELLO_CHALLENGE)?;
// end the exclusive borrow
drop(client_tx_stream);

// the first server.poll_negotiate causes the server to read in the client hello
assert!(pair.server.poll_negotiate()?.is_pending());
assert_eq!(pair.server.client_hello_is_sslv2()?, true);
Ok(())
}
}
Loading