Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 0 additions & 6 deletions quic/s2n-quic-core/src/crypto/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,6 @@ pub trait TlsSession: Send {
fn peer_cert_chain_der(&self) -> Result<Vec<Vec<u8>>, ChainError>;
}

//= https://www.rfc-editor.org/rfc/rfc9000#section-4
//= type=TODO
//= tracking-issue=332
//# To avoid excessive buffering at multiple layers, QUIC implementations
//# SHOULD provide an interface for the cryptographic protocol
//# implementation to communicate its buffering limits.
#[cfg(feature = "alloc")]
pub trait Context<Crypto: crate::crypto::CryptoSuite> {
/// Called when the client's application parameters are available, prior
Expand Down
2 changes: 1 addition & 1 deletion quic/s2n-quic-tls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ s2n-codec = { version = "=0.56.0", path = "../../common/s2n-codec", default-feat
s2n-quic-core = { version = "=0.56.0", path = "../s2n-quic-core", default-features = false, features = ["alloc"] }
s2n-quic-crypto = { version = "=0.56.0", path = "../s2n-quic-crypto", default-features = false }
# the `on_key_exchange_group` event relies on an API added in 0.3.15
s2n-tls = { version = "0.3.15", features = ["quic"] }
s2n-tls = { version = "0.3.16", features = ["quic"] }

[dev-dependencies]
checkers = "0.6"
Expand Down
1 change: 1 addition & 0 deletions quic/s2n-quic/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mod setup;
use setup::*;

mod blackhole;
mod buffer_limit;
mod connection_migration;
mod deduplicate;
mod handshake_cid_rotation;
Expand Down
107 changes: 107 additions & 0 deletions quic/s2n-quic/src/tests/buffer_limit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use super::*;
use crate::{
connection::Error,
provider::tls::default::{self as tls},
};
use s2n_quic_core::{crypto::tls::Error as TlsError, transport};

// It helps to expand the Client Hello size to excced 64 KB, by filling
// the alpn extension in Client Hello with 65310 bytes.
static FAKE_PROTOCOL_COUNT: u16 = 4665;
// Maximum handshake message size is 64KB in S2N-TLS.
static MAXIMUM_HANDSHAKE_MESSAGE_SIZE: usize = 65536;

//= https://www.rfc-editor.org/rfc/rfc9000#section-4
//= type=implication
//# To avoid excessive buffering at multiple layers, QUIC implementations
//# SHOULD provide an interface for the cryptographic protocol
//# implementation to communicate its buffering limits.
/// This test shows that the default TLS provider already provides
/// limits for buffering. The server will drop a giant Client Hello.
#[test]
fn buffer_limit_test() {
let model = Model::default();

let connection_closed_subscriber = recorder::ConnectionClosed::new();
let connection_closed_event = connection_closed_subscriber.events();
let client_hello_subscriber = recorder::TlsClientHello::new();
let client_hello_event = client_hello_subscriber.events();

test(model, |handle| {
let server = tls::Server::builder()
.with_application_protocols(["h3"].iter())
.unwrap()
.with_certificate(certificates::CERT_PEM, certificates::KEY_PEM)
.unwrap()
.build()
.unwrap();

let server = Server::builder()
.with_io(handle.builder().build()?)?
.with_tls(server)?
.with_event((
tracing_events(),
(client_hello_subscriber, connection_closed_subscriber),
))?
.with_random(Random::with_seed(456))?
.start()?;

let mut application_protocols: Vec<String> = Vec::new();
application_protocols.push("h3".to_string());
for _ in 0..FAKE_PROTOCOL_COUNT {
application_protocols.push("fake-protocol".to_string());
}

let client = tls::Client::builder()
.with_application_protocols(application_protocols.iter())
.unwrap()
.with_certificate(certificates::CERT_PEM)
.unwrap()
.build()
.unwrap();

let client = Client::builder()
.with_io(handle.builder().build()?)?
.with_tls(client)?
.with_event(tracing_events())?
.with_random(Random::with_seed(456))?
.start()?;

let addr = start_server(server)?;
primary::spawn(async move {
let connect = Connect::new(addr).with_server_name("localhost");
client.connect(connect).await.unwrap_err();
});

Ok(())
})
.unwrap();

// The TlsClientHello payload should be more than the maximum handshake message size.
let client_hello_handle = client_hello_event.lock().unwrap();
assert!(client_hello_handle[0] > MAXIMUM_HANDSHAKE_MESSAGE_SIZE);

let connection_closed_handle = connection_closed_event.lock().unwrap();

// Expect exactly one connection closed error because the server
// terminates the connection after receiving a Client Hello message
// that exceeds the maximum allowed handshake size.
assert_eq!(connection_closed_handle.len(), 1);

// The error message for connection closed error should be INTERNAL_ERROR.
let Error::Transport { code, .. } = connection_closed_handle[0] else {
panic!("Unexpected error type")
};

// Rustls emits INTERNAL_ERROR and S2N-TLS emits UNEXPECTED_MESSAGE error
// when the server close the connection due to large Client Hello.
let expected_error = if cfg!(target_os = "windows") {
TlsError::INTERNAL_ERROR
} else {
TlsError::UNEXPECTED_MESSAGE
};
assert_eq!(code, transport::Error::from(expected_error).code);
}
20 changes: 20 additions & 0 deletions quic/s2n-quic/src/tests/recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@ event_recorder!(
}
);

event_recorder!(
ConnectionClosed,
ConnectionClosed,
on_connection_closed,
crate::connection::Error,
|event: &events::ConnectionClosed, storage: &mut Vec<crate::connection::Error>| {
storage.push(event.error);
}
);

event_recorder!(
TlsClientHello,
TlsClientHello,
on_tls_client_hello,
usize,
|event: &events::TlsClientHello, storage: &mut Vec<usize>| {
storage.push(event.payload.iter().map(|slice| slice.len()).sum());
}
);

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PacketDropReason {
ConnectionError,
Expand Down
Loading