Skip to content

Commit

Permalink
Support exporting from TLS sessions
Browse files Browse the repository at this point in the history
This also bumps s2n-tls dependency to 0.0.39 so that we can make use of
the new TLS-Exporter functionality in s2n-tls, not just in rustls.
  • Loading branch information
Mark-Simulacrum committed Oct 11, 2023
1 parent 85001e4 commit c810a4e
Show file tree
Hide file tree
Showing 13 changed files with 329 additions and 4 deletions.
2 changes: 1 addition & 1 deletion examples/resumption/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ edition = "2021"

[dependencies]
s2n-quic = { version = "1", path = "../../quic/s2n-quic", features = ["provider-tls-s2n", "unstable_resumption"]}
s2n-tls = { version = "=0.0.36", features = ["quic"] }
s2n-tls = { version = "=0.0.39", features = ["quic"] }
tokio = { version = "1", features = ["full"] }
4 changes: 2 additions & 2 deletions netbench/netbench-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ netbench = { version = "0.1", path = "../netbench" }
probe = "0.5"
s2n-quic = { path = "../../quic/s2n-quic", features = ["provider-tls-s2n"] }
s2n-quic-core = { path = "../../quic/s2n-quic-core", features = ["testing"] }
s2n-tls = { version = "0.0.36" }
s2n-tls-tokio = { version = "0.0.36" }
s2n-tls = { version = "0.0.39" }
s2n-tls-tokio = { version = "0.0.39" }
structopt = "0.3"
tokio = { version = "1", features = ["io-util", "net", "time", "rt-multi-thread"] }
tokio-native-tls = "0.3"
Expand Down
28 changes: 28 additions & 0 deletions quic/s2n-quic-core/src/crypto/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ pub struct ApplicationParameters<'a> {
pub transport_parameters: &'a [u8],
}

#[derive(Debug)]
#[non_exhaustive]
pub enum TlsExportError {
#[non_exhaustive]
Failure,
}

impl TlsExportError {
pub fn failure() -> Self {
TlsExportError::Failure
}
}

pub trait TlsSession: Send + Sync {
/// See <https://datatracker.ietf.org/doc/html/rfc5705> and <https://www.rfc-editor.org/rfc/rfc8446>.
fn tls_exporter(
&self,
label: &[u8],
context: &[u8],
output: &mut [u8],
) -> Result<(), TlsExportError>;
}

//= https://www.rfc-editor.org/rfc/rfc9000#section-4
//= type=TODO
//= tracking-issue=332
Expand Down Expand Up @@ -64,6 +87,11 @@ pub trait Context<Crypto: crate::crypto::CryptoSuite> {
//# peer's Finished message.
fn on_handshake_complete(&mut self) -> Result<(), crate::transport::Error>;

fn on_tls_exporter_ready(
&mut self,
session: &impl TlsSession,
) -> Result<(), crate::transport::Error>;

/// Receives data from the initial packet space
///
/// A `max_len` may be provided to indicate how many bytes the TLS implementation
Expand Down
7 changes: 7 additions & 0 deletions quic/s2n-quic-core/src/crypto/tls/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,13 @@ where
Ok(())
}

fn on_tls_exporter_ready(
&mut self,
_: &impl super::TlsSession,
) -> Result<(), crate::transport::Error> {
Ok(())
}

fn receive_initial(&mut self, max_len: Option<usize>) -> Option<Bytes> {
self.log("rx initial");
self.initial.rx(max_len)
Expand Down
34 changes: 34 additions & 0 deletions quic/s2n-quic-core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,37 @@ impl IntoEvent<Timestamp> for crate::time::Timestamp {
Timestamp(self)
}
}

#[derive(Clone)]
pub struct TlsSession<'a> {
session: &'a dyn crate::crypto::tls::TlsSession,
}

impl<'a> TlsSession<'a> {
#[doc(hidden)]
pub fn new(session: &'a dyn crate::crypto::tls::TlsSession) -> TlsSession<'a> {
TlsSession { session }
}

pub fn tls_exporter(
&self,
label: &[u8],
context: &[u8],
output: &mut [u8],
) -> Result<(), crate::crypto::tls::TlsExportError> {
self.session.tls_exporter(label, context, output)
}
}

impl<'a> crate::event::IntoEvent<TlsSession<'a>> for TlsSession<'a> {
#[inline]
fn into_event(self) -> Self {
self
}
}

impl core::fmt::Debug for TlsSession<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TlsSession").finish_non_exhaustive()
}
}
87 changes: 87 additions & 0 deletions quic/s2n-quic-core/src/event/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,14 @@ pub mod api {
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct TlsExporterReady<'a> {
pub session: crate::event::TlsSession<'a>,
}
impl<'a> Event for TlsExporterReady<'a> {
const NAME: &'static str = "connectivity:tls_exporter_ready";
}
#[derive(Clone, Debug)]
#[non_exhaustive]
#[doc = " Path challenge updated"]
pub struct PathChallengeUpdated<'a> {
pub path_challenge_status: PathChallengeStatus,
Expand Down Expand Up @@ -2012,6 +2020,17 @@ pub mod tracing {
tracing :: event ! (target : "handshake_status_updated" , parent : id , tracing :: Level :: DEBUG , status = tracing :: field :: debug (status));
}
#[inline]
fn on_tls_exporter_ready(
&mut self,
context: &mut Self::ConnectionContext,
_meta: &api::ConnectionMeta,
event: &api::TlsExporterReady,
) {
let id = context.id();
let api::TlsExporterReady { session } = event;
tracing :: event ! (target : "tls_exporter_ready" , parent : id , tracing :: Level :: DEBUG , session = tracing :: field :: debug (session));
}
#[inline]
fn on_path_challenge_updated(
&mut self,
context: &mut Self::ConnectionContext,
Expand Down Expand Up @@ -3910,6 +3929,19 @@ pub mod builder {
}
}
#[derive(Clone, Debug)]
pub struct TlsExporterReady<'a> {
pub session: crate::event::TlsSession<'a>,
}
impl<'a> IntoEvent<api::TlsExporterReady<'a>> for TlsExporterReady<'a> {
#[inline]
fn into_event(self) -> api::TlsExporterReady<'a> {
let TlsExporterReady { session } = self;
api::TlsExporterReady {
session: session.into_event(),
}
}
}
#[derive(Clone, Debug)]
#[doc = " Path challenge updated"]
pub struct PathChallengeUpdated<'a> {
pub path_challenge_status: PathChallengeStatus,
Expand Down Expand Up @@ -4898,6 +4930,18 @@ mod traits {
let _ = meta;
let _ = event;
}
#[doc = "Called when the `TlsExporterReady` event is triggered"]
#[inline]
fn on_tls_exporter_ready(
&mut self,
context: &mut Self::ConnectionContext,
meta: &ConnectionMeta,
event: &TlsExporterReady,
) {
let _ = context;
let _ = meta;
let _ = event;
}
#[doc = "Called when the `PathChallengeUpdated` event is triggered"]
#[inline]
fn on_path_challenge_updated(
Expand Down Expand Up @@ -5532,6 +5576,16 @@ mod traits {
(self.1).on_handshake_status_updated(&mut context.1, meta, event);
}
#[inline]
fn on_tls_exporter_ready(
&mut self,
context: &mut Self::ConnectionContext,
meta: &ConnectionMeta,
event: &TlsExporterReady,
) {
(self.0).on_tls_exporter_ready(&mut context.0, meta, event);
(self.1).on_tls_exporter_ready(&mut context.1, meta, event);
}
#[inline]
fn on_path_challenge_updated(
&mut self,
context: &mut Self::ConnectionContext,
Expand Down Expand Up @@ -6000,6 +6054,8 @@ mod traits {
fn on_connection_migration_denied(&mut self, event: builder::ConnectionMigrationDenied);
#[doc = "Publishes a `HandshakeStatusUpdated` event to the publisher's subscriber"]
fn on_handshake_status_updated(&mut self, event: builder::HandshakeStatusUpdated);
#[doc = "Publishes a `TlsExporterReady` event to the publisher's subscriber"]
fn on_tls_exporter_ready(&mut self, event: builder::TlsExporterReady);
#[doc = "Publishes a `PathChallengeUpdated` event to the publisher's subscriber"]
fn on_path_challenge_updated(&mut self, event: builder::PathChallengeUpdated);
#[doc = "Publishes a `TlsClientHello` event to the publisher's subscriber"]
Expand Down Expand Up @@ -6327,6 +6383,15 @@ mod traits {
self.subscriber.on_event(&self.meta, &event);
}
#[inline]
fn on_tls_exporter_ready(&mut self, event: builder::TlsExporterReady) {
let event = event.into_event();
self.subscriber
.on_tls_exporter_ready(self.context, &self.meta, &event);
self.subscriber
.on_connection_event(self.context, &self.meta, &event);
self.subscriber.on_event(&self.meta, &event);
}
#[inline]
fn on_path_challenge_updated(&mut self, event: builder::PathChallengeUpdated) {
let event = event.into_event();
self.subscriber
Expand Down Expand Up @@ -6471,6 +6536,7 @@ pub mod testing {
pub ecn_state_changed: u32,
pub connection_migration_denied: u32,
pub handshake_status_updated: u32,
pub tls_exporter_ready: u32,
pub path_challenge_updated: u32,
pub tls_client_hello: u32,
pub tls_server_hello: u32,
Expand Down Expand Up @@ -6549,6 +6615,7 @@ pub mod testing {
ecn_state_changed: 0,
connection_migration_denied: 0,
handshake_status_updated: 0,
tls_exporter_ready: 0,
path_challenge_updated: 0,
tls_client_hello: 0,
tls_server_hello: 0,
Expand Down Expand Up @@ -6905,6 +6972,17 @@ pub mod testing {
self.output.push(format!("{meta:?} {event:?}"));
}
}
fn on_tls_exporter_ready(
&mut self,
_context: &mut Self::ConnectionContext,
meta: &api::ConnectionMeta,
event: &api::TlsExporterReady,
) {
self.tls_exporter_ready += 1;
if self.location.is_some() {
self.output.push(format!("{meta:?} {event:?}"));
}
}
fn on_path_challenge_updated(
&mut self,
_context: &mut Self::ConnectionContext,
Expand Down Expand Up @@ -7156,6 +7234,7 @@ pub mod testing {
pub ecn_state_changed: u32,
pub connection_migration_denied: u32,
pub handshake_status_updated: u32,
pub tls_exporter_ready: u32,
pub path_challenge_updated: u32,
pub tls_client_hello: u32,
pub tls_server_hello: u32,
Expand Down Expand Up @@ -7224,6 +7303,7 @@ pub mod testing {
ecn_state_changed: 0,
connection_migration_denied: 0,
handshake_status_updated: 0,
tls_exporter_ready: 0,
path_challenge_updated: 0,
tls_client_hello: 0,
tls_server_hello: 0,
Expand Down Expand Up @@ -7541,6 +7621,13 @@ pub mod testing {
self.output.push(format!("{event:?}"));
}
}
fn on_tls_exporter_ready(&mut self, event: builder::TlsExporterReady) {
self.tls_exporter_ready += 1;
let event = event.into_event();
if self.location.is_some() {
self.output.push(format!("{event:?}"));
}
}
fn on_path_challenge_updated(&mut self, event: builder::PathChallengeUpdated) {
self.path_challenge_updated += 1;
let event = event.into_event();
Expand Down
5 changes: 5 additions & 0 deletions quic/s2n-quic-events/events/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ struct HandshakeStatusUpdated {
status: HandshakeStatus,
}

#[event("connectivity:tls_exporter_ready")]
struct TlsExporterReady<'a> {
session: crate::event::TlsSession<'a>,
}

#[event("connectivity:path_challenge_updated")]
/// Path challenge updated
struct PathChallengeUpdated<'a> {
Expand Down
18 changes: 18 additions & 0 deletions quic/s2n-quic-rustls/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ pub struct Session {
server_name: Option<ServerName>,
}

impl tls::TlsSession for Session {
fn tls_exporter(
&self,
label: &[u8],
context: &[u8],
output: &mut [u8],
) -> Result<(), tls::TlsExportError> {
match self
.connection
.export_keying_material(output, label, Some(context))
{
Ok(_) => Ok(()),
Err(_) => Err(tls::TlsExportError::failure()),
}
}
}

impl fmt::Debug for Session {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Session")
Expand Down Expand Up @@ -149,6 +166,7 @@ impl Session {
if !self.emitted_handshake_complete {
self.rx_phase.transition();
context.on_handshake_complete()?;
context.on_tls_exporter_ready(self)?;
}

self.emitted_handshake_complete = true;
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 @@ -21,7 +21,7 @@ libc = "0.2"
s2n-codec = { version = "=0.7.0", path = "../../common/s2n-codec", default-features = false }
s2n-quic-core = { version = "=0.28.0", path = "../s2n-quic-core", default-features = false, features = ["alloc"] }
s2n-quic-crypto = { version = "=0.29.0", path = "../s2n-quic-crypto", default-features = false }
s2n-tls = { version = "=0.0.36", features = ["quic"] }
s2n-tls = { version = "=0.0.39", features = ["quic"] }

[dev-dependencies]
checkers = "0.6"
Expand Down
14 changes: 14 additions & 0 deletions quic/s2n-quic-tls/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ impl CryptoSuite for Session {
type RetryKey = <Suite as CryptoSuite>::RetryKey;
}

impl tls::TlsSession for Session {
fn tls_exporter(
&self,
label: &[u8],
context: &[u8],
output: &mut [u8],
) -> Result<(), tls::TlsExportError> {
self.connection
.tls_exporter(label, context, output)
.map_err(|_| tls::TlsExportError::failure())
}
}

impl tls::Session for Session {
fn poll<W>(&mut self, context: &mut W) -> Poll<Result<(), transport::Error>>
where
Expand Down Expand Up @@ -109,6 +122,7 @@ impl tls::Session for Session {
if !self.handshake_complete {
self.state.on_handshake_complete();
context.on_handshake_complete()?;
context.on_tls_exporter_ready(self)?;
self.handshake_complete = true;
}
Poll::Ready(Ok(()))
Expand Down
11 changes: 11 additions & 0 deletions quic/s2n-quic-transport/src/space/session_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,17 @@ impl<'a, Config: endpoint::Config, Pub: event::ConnectionPublisher>
Ok(())
}

fn on_tls_exporter_ready(
&mut self,
session: &impl tls::TlsSession,
) -> Result<(), transport::Error> {
self.publisher
.on_tls_exporter_ready(event::builder::TlsExporterReady {
session: s2n_quic_core::event::TlsSession::new(session),
});
Ok(())
}

fn on_handshake_complete(&mut self) -> Result<(), transport::Error> {
// After the handshake is complete, the handshake crypto stream should be completely
// finished
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 @@ -45,6 +45,7 @@ mod client_handshake_confirm;
#[cfg(not(target_os = "windows"))]
mod mtls;

mod exporter;
mod issue_1361;
mod issue_1427;
mod issue_1464;
Expand Down
Loading

0 comments on commit c810a4e

Please sign in to comment.