-
Notifications
You must be signed in to change notification settings - Fork 724
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into bindings-s2n-tls-ut-cleanup
- Loading branch information
Showing
21 changed files
with
688 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
bindings/rust-examples/client-hello-config-resolution/src/bin/async_load_server.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use s2n_tls::{ | ||
callbacks::{ClientHelloCallback, ConfigResolver, ConnectionFuture}, | ||
security::{Policy, DEFAULT_TLS13}, | ||
}; | ||
use s2n_tls_tokio::TlsAcceptor; | ||
use std::{error::Error, pin::Pin}; | ||
use tokio::{io::AsyncWriteExt, net::*, try_join}; | ||
|
||
const PORT: u16 = 1738; | ||
|
||
#[derive(Clone)] | ||
pub struct AsyncAnimalConfigResolver { | ||
// the directory that contains the relevant certs | ||
cert_directory: String, | ||
} | ||
|
||
impl AsyncAnimalConfigResolver { | ||
fn new(cert_directory: String) -> Self { | ||
AsyncAnimalConfigResolver { cert_directory } | ||
} | ||
} | ||
|
||
impl ClientHelloCallback for AsyncAnimalConfigResolver { | ||
fn on_client_hello( | ||
&self, | ||
connection: &mut s2n_tls::connection::Connection, | ||
) -> Result<Option<Pin<Box<dyn ConnectionFuture>>>, s2n_tls::error::Error> { | ||
let sni = match connection.server_name() { | ||
Some(sni) => sni, | ||
None => { | ||
println!("connection contained no SNI"); | ||
return Err(s2n_tls::error::Error::application("no sni".into())); | ||
} | ||
}; | ||
|
||
// simple, limited logic to parse "animal" from "www.animal.com". | ||
let mut tokens = sni.split('.'); | ||
tokens.next(); // "www" | ||
let animal = match tokens.next() { | ||
Some(animal) => animal.to_owned(), // "animal" | ||
None => { | ||
println!("unable to parse sni"); | ||
return Err(s2n_tls::error::Error::application( | ||
format!("unable to parse sni: {}", sni).into(), | ||
)); | ||
} | ||
}; | ||
|
||
let config_future = server_config(animal, self.cert_directory.clone()); | ||
let config_resolver = ConfigResolver::new(config_future); | ||
connection.server_name_extension_used(); | ||
Ok(Some(Box::pin(config_resolver))) | ||
} | ||
} | ||
|
||
// This method will lookup the appropriate certificates and read them from disk | ||
// in an async manner which won't block the tokio task. | ||
// | ||
// Note that this method takes `String` instead of `&str` like the synchronous | ||
// version in server.rs. ConfigResolver requires a future that is `'static`. | ||
async fn server_config( | ||
animal: String, | ||
cert_directory: String, | ||
) -> Result<s2n_tls::config::Config, s2n_tls::error::Error> { | ||
println!("asynchronously setting connection config associated with {animal}"); | ||
|
||
let cert_path = format!("{}/{}-chain.pem", cert_directory, animal); | ||
let key_path = format!("{}/{}-key.pem", cert_directory, animal); | ||
// we asynchronously read the cert chain and key from disk | ||
let (cert, key) = try_join!(tokio::fs::read(cert_path), tokio::fs::read(key_path)) | ||
// we map any IO errors to the s2n-tls Error type, as required by the ConfigResolver bounds. | ||
.map_err(|io_error| s2n_tls::error::Error::application(Box::new(io_error)))?; | ||
|
||
let mut config = s2n_tls::config::Builder::new(); | ||
// we can set different policies for different configs. "20190214" doesn't | ||
// support TLS 1.3, so any customer requesting www.wombat.com won't be able | ||
// to negotiate TLS 1.3 | ||
let security_policy = match animal.as_str() { | ||
"wombat" => Policy::from_version("20190214")?, | ||
_ => DEFAULT_TLS13, | ||
}; | ||
config.set_security_policy(&security_policy)?; | ||
config.load_pem(&cert, &key)?; | ||
config.build() | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn Error>> { | ||
let cert_directory = format!("{}/certs", env!("CARGO_MANIFEST_DIR")); | ||
let resolver = AsyncAnimalConfigResolver::new(cert_directory); | ||
let mut initial_config = s2n_tls::config::Builder::new(); | ||
initial_config.set_client_hello_callback(resolver)?; | ||
|
||
let server = TlsAcceptor::new(initial_config.build()?); | ||
|
||
let listener = TcpListener::bind(&format!("0.0.0.0:{PORT}")).await?; | ||
loop { | ||
let server = server.clone(); | ||
let (stream, _) = listener.accept().await?; | ||
tokio::spawn(async move { | ||
// handshake with the client | ||
let handshake = server.accept(stream).await; | ||
let mut tls = match handshake { | ||
Ok(tls) => tls, | ||
Err(e) => { | ||
println!("error during handshake: {:?}", e); | ||
return Ok(()); | ||
} | ||
}; | ||
|
||
let connection = tls.as_ref(); | ||
let offered_sni = connection.server_name().unwrap(); | ||
let _ = tls | ||
.write(format!("Hello, you are speaking to {offered_sni}").as_bytes()) | ||
.await?; | ||
tls.shutdown().await?; | ||
Ok::<(), Box<dyn Error + Send + Sync>>(()) | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target/ | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "pcap" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[dependencies] | ||
anyhow = "1.0.86" | ||
hex = "0.4.3" | ||
rtshark = "2.7.1" | ||
|
||
[dev-dependencies] | ||
# We want to test against the latest, local version of s2n | ||
s2n-tls-sys = { path = "../../bindings/rust/s2n-tls-sys" } | ||
s2n-tls = { path = "../../bindings/rust/s2n-tls", features = ["unstable-fingerprint"] } |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::handshake_message::HandshakeMessage; | ||
use anyhow::*; | ||
use std::option::Option; | ||
|
||
#[derive(Debug, Clone, Default)] | ||
pub struct ClientHello(HandshakeMessage); | ||
|
||
impl ClientHello { | ||
/// ClientHello message type, as defined in the TLS RFC. | ||
/// See https://datatracker.ietf.org/doc/html/rfc8446#section-4 | ||
const MESSAGE_TYPE: u8 = 1; | ||
|
||
const JA3_HASH: &'static str = "tls.handshake.ja3"; | ||
pub fn ja3_hash(&self) -> Option<String> { | ||
self.0.packet.metadata(Self::JA3_HASH).map(str::to_owned) | ||
} | ||
|
||
const JA3_STR: &'static str = "tls.handshake.ja3_full"; | ||
pub fn ja3_string(&self) -> Option<String> { | ||
self.0.packet.metadata(Self::JA3_STR).map(str::to_owned) | ||
} | ||
|
||
pub fn message(&self) -> &HandshakeMessage { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl crate::handshake_message::Builder { | ||
pub fn build_client_hellos(mut self) -> Result<Vec<ClientHello>> { | ||
self.set_type(ClientHello::MESSAGE_TYPE); | ||
let client_hellos = self.build()?.into_iter().map(ClientHello).collect(); | ||
Ok(client_hellos) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::handshake_message::Builder; | ||
|
||
#[test] | ||
fn multiple_hellos() -> Result<()> { | ||
let mut builder = Builder::default(); | ||
builder.set_capture_file("data/multiple_hellos.pcap"); | ||
let hellos = builder.build_client_hellos().unwrap(); | ||
assert_eq!(hellos.len(), 5); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn from_pcaps() -> Result<()> { | ||
let pcaps = crate::all_pcaps(); | ||
for pcap in pcaps { | ||
let mut builder = Builder::default(); | ||
builder.set_capture_file(&pcap); | ||
let hellos = builder.build_client_hellos().unwrap(); | ||
assert!(!hellos.is_empty()); | ||
} | ||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.