use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use core::ops::Deref;
use kernel::KernelConnection;
use pki_types::FipsStatus;
use crate::client::ClientSide;
use crate::common_state::{
CommonState, ConnectionOutput, ConnectionOutputs, Event, Output, OutputEvent,
};
use crate::crypto::VerifiedIdentity;
use crate::crypto::cipher::{OutboundPlain, Payload};
use crate::error::{ApiMisuse, Error};
use crate::kernel::KernelState;
use crate::msgs::{Delocator, Message, Random, ServerExtensionsInput};
use crate::quic::{self, QuicOutput};
use crate::server::{ChooseConfig, ServerConfig, ServerSide};
use crate::suites::{ExtractedSecrets, PartiallyExtractedSecrets};
use crate::sync::Arc;
use crate::tls13::key_schedule::KeyScheduleTrafficSend;
pub mod kernel;
mod handshake;
pub use handshake::{Accepted, Tcp, Transport, VerifyPeerIdentity};
pub(crate) use handshake::{ClientNext, ServerNext, sealed};
mod receive;
pub(crate) use receive::{
DataKind, Input, MessageIter, MessageIterMode, ReceivePath, TrafficTemperCounters,
};
pub use receive::{SliceInput, TlsInputBuffer, VecInput};
mod send;
pub(crate) use send::{Encrypter, SendOutput, SendPath};
pub(crate) mod split;
use split::SplitConnection;
pub struct Connection<Side: SideData, T: Transport> {
pub(crate) state: Result<Side::State, Error>,
pub(crate) side: Side,
pub(crate) common: CommonState,
pub(crate) transport: T,
}
impl<Side: SideData, T: Transport> Connection<Side, T> {
pub(crate) fn process(
&mut self,
input: &mut dyn TlsInputBuffer,
tls: &mut Vec<u8>,
) -> Result<(), Error> {
let mut iter = MessageIter::new(input, tls, self, MessageIterMode::Handshake);
let result = loop {
match iter.next(false) {
Some(Ok(_)) => {}
Some(Err(e)) => break Err(e),
None => break Ok(()),
};
};
input.discard(self.common.recv.deframer.take_discard());
result?;
Ok(())
}
#[doc = include_str!("../doc/exporter.md")]
pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
match self.common.is_handshaking() {
true => Err(Error::HandshakeNotComplete),
false => self.common.outputs.exporter(),
}
}
pub fn side(&self) -> &Side {
&self.side
}
pub fn fips(&self) -> FipsStatus {
self.common.fips
}
pub fn is_handshaking(&self) -> bool {
self.common.is_handshaking()
}
}
impl<Side: SideData> Connection<Side, Tcp> {
pub fn read_tls<'a, 'm>(
&'a mut self,
input: &'m mut dyn TlsInputBuffer,
tls: &'a mut Vec<u8>,
) -> MessageHandler<'a, 'm, Side> {
MessageHandler::new(input, tls, self)
}
pub fn write(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> Result<(), Error> {
if let Err(err) = &self.state {
return Err(err.clone());
} else if plaintext.is_empty() {
return Ok(());
}
self.common
.send
.send_appdata_encrypt(DataKind::Traffic(plaintext), tls)?;
Ok(())
}
pub fn refresh_traffic_keys(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
self.common
.send
.refresh_traffic_keys(tls)
}
pub fn split(self) -> Result<SplitConnection<Side>, Error> {
SplitConnection::try_from(self)
}
#[doc = include_str!("../doc/early_exporter.md")]
pub fn early_exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
self.common.early_exporter()
}
pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
Ok(self
.dangerous_into_kernel_connection()?
.0)
}
pub(crate) fn dangerous_into_kernel_connection(
self,
) -> Result<(ExtractedSecrets, KernelConnection<Side>), Error> {
if self.common.is_handshaking() {
return Err(Error::HandshakeNotComplete);
}
Self::from_parts_into_kernel_connection(
self.common.send,
self.common.recv,
self.common.outputs,
self.state?,
)
}
pub(crate) fn from_parts_into_kernel_connection(
send: SendPath,
recv: ReceivePath,
outputs: ConnectionOutputs,
state: Side::State,
) -> Result<(ExtractedSecrets, KernelConnection<Side>), Error> {
if send.has_queued_key_update() {
return Err(ApiMisuse::KernelConnectionWithPendingSendData.into());
}
let read_seq = recv.decrypt_state.read_seq();
let (write_seq, tls13_key_schedule) = send.export()?;
let (secrets, state) = state.into_external_state(&tls13_key_schedule)?;
let secrets = ExtractedSecrets {
tx: (write_seq, secrets.tx),
rx: (read_seq, secrets.rx),
};
let external = KernelConnection::new(state, outputs, tls13_key_schedule)?;
Ok((secrets, external))
}
pub fn send_close_notify(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
self.common.send_close_notify(tls)
}
}
impl<T: Transport> Connection<ClientSide, T> {
pub fn tls13_tickets_received(&self) -> u32 {
self.common.recv.tls13_tickets_received
}
}
impl<T: Transport> Connection<ServerSide, T> {
pub(crate) fn accepted(
&mut self,
choose: Box<ChooseConfig>,
exts: ServerExtensionsInput,
config: Arc<ServerConfig>,
tls: &mut Vec<u8>,
) -> Result<(), Error> {
self.common
.send
.set_max_fragment_size(config.max_fragment_size)?;
self.common.fips = config.fips();
let mut output = SideCommonOutput {
side: &mut self.side,
quic: self.transport.quic(),
common: &mut self.common,
tls,
};
self.state = Ok(choose.use_config(config, exts, &mut output)?);
Ok(())
}
pub fn set_resumption_data(&mut self, data: &[u8]) -> Result<(), Error> {
assert!(data.len() < 2usize.pow(15));
match &mut self.state {
Ok(st) => st.set_resumption_data(data),
Err(e) => Err(e.clone()),
}
}
}
impl<Side: SideData> Connection<Side, Tcp> {
fn into_handshake(self) -> Result<Side::Handshake, Error> {
Side::Handshake::try_from(self)
}
}
impl<S: SideData, T: Transport> fmt::Debug for Connection<S, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
state: _,
side,
common,
transport: _,
} = self;
f.debug_struct("Connection")
.field("side", side)
.field("common", common)
.finish_non_exhaustive()
}
}
impl<Side: SideData, T: Transport> Deref for Connection<Side, T> {
type Target = CommonState;
fn deref(&self) -> &Self::Target {
&self.common
}
}
#[must_use]
pub struct MessageHandler<'a, 'm, Side: SideData> {
iter: MessageIter<'a, 'm, Side, SendPath>,
done: bool,
}
impl<'a, 'm, Side: SideData> MessageHandler<'a, 'm, Side> {
pub(crate) fn new(
input: &'m mut dyn TlsInputBuffer,
tls: &'a mut Vec<u8>,
conn: &'a mut Connection<Side, impl Transport>,
) -> Self {
Self {
iter: MessageIter::new(input, tls, conn, MessageIterMode::All),
done: false,
}
}
}
impl<'a, 'm, Side: SideData> MessageHandler<'a, 'm, Side> {
pub fn handle_all(mut self, buf: &mut Vec<u8>) -> Result<IoState, Error> {
while let Some(result) = self.next_payload() {
buf.extend_from_slice(result?.bytes());
}
Ok(self.state())
}
pub fn next_payload(&mut self) -> Option<Result<Payload<'_>, Error>> {
if self.done {
return None;
}
let Some(result) = self.iter.next(false) else {
self.done = true;
return None;
};
let payload = match result {
Ok(payload) => payload,
Err(err) => {
self.done = true;
return Some(Err(err));
}
};
Some(Ok(
payload.reborrow(&Delocator::new(self.iter.input.slice_mut()))
))
}
pub fn state(self) -> IoState {
IoState::new(self.iter.recv)
}
}
impl<'a, 'm> MessageHandler<'a, 'm, ServerSide> {
pub fn next_early_data(&mut self) -> Option<Result<Payload<'_>, Error>> {
if self.done {
return None;
}
if let Ok(state) = &self.iter.state {
if state.is_traffic() {
return None; }
}
let result = self.iter.next(true)?;
let payload = match result {
Ok(payload) => payload,
Err(err) => return Some(Err(err)),
};
Some(Ok(
payload.reborrow(&Delocator::new(self.iter.input.slice_mut()))
))
}
}
impl<'a, 'm, Side: SideData + private::Side> Drop for MessageHandler<'a, 'm, Side> {
fn drop(&mut self) {
let MessageIter { input, recv, .. } = &mut self.iter;
input.discard(recv.deframer.take_discard());
}
}
impl<S: SideData> fmt::Debug for MessageHandler<'_, '_, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MessageHandler")
.field("done", &self.done)
.finish_non_exhaustive()
}
}
pub struct NeedsInput<Side: SideData>(pub(crate) Connection<Side, Tcp>);
impl<Side: SideData> NeedsInput<Side> {
pub(crate) fn new(inner: Connection<Side, Tcp>) -> Self {
Self(inner)
}
pub fn process(
mut self,
input: &mut dyn TlsInputBuffer,
tls: &mut Vec<u8>,
) -> Result<Side::Handshake, Error> {
self.0.process(input, tls)?;
self.0.into_handshake()
}
#[doc = include_str!("../doc/early_exporter.md")]
pub fn early_exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
self.0.common.early_exporter()
}
}
impl<S: SideData> fmt::Debug for NeedsInput<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NeedsInput")
.finish_non_exhaustive()
}
}
pub(crate) trait State<Side: SideData>: Send + Sync {
fn handle<'m>(
self: Box<Self>,
input: Input<'m>,
output: &mut dyn Output<'m>,
) -> Result<Side::State, Error>;
fn is_traffic(&self) -> bool {
false
}
fn handle_decrypt_error(&mut self) {}
fn into_external_state(
self: Box<Self>,
_send_keys: &Option<Box<KeyScheduleTrafficSend>>,
) -> Result<(PartiallyExtractedSecrets, Box<dyn KernelState + 'static>), Error> {
Err(Error::HandshakeNotComplete)
}
}
pub(crate) trait VerifySidePeerIdentity<Side: SideData>: Send + Sync {
fn presented_identity(&self) -> Result<Side::PeerIdentity<'_>, Error>;
fn verify_with_config(&self) -> Result<VerifiedIdentity<'static>, Error>;
fn continue_with(
self: Box<Self>,
verified: VerifiedIdentity<'static>,
output: &mut dyn Output<'_>,
) -> Result<Side::State, Error>;
}
pub struct KeyingMaterialExporter {
pub(crate) inner: Box<dyn Exporter>,
}
impl KeyingMaterialExporter {
pub fn derive<T: AsMut<[u8]>>(
&self,
label: &[u8],
context: Option<&[u8]>,
mut output: T,
) -> Result<T, Error> {
if output.as_mut().is_empty() {
return Err(ApiMisuse::ExporterOutputZeroLength.into());
}
self.inner
.derive(label, context, output.as_mut())
.map(|_| output)
}
}
impl fmt::Debug for KeyingMaterialExporter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("KeyingMaterialExporter")
.finish_non_exhaustive()
}
}
pub(crate) trait Exporter: Send + Sync {
fn derive(&self, label: &[u8], context: Option<&[u8]>, output: &mut [u8]) -> Result<(), Error>;
}
#[derive(Debug)]
pub(crate) struct ConnectionRandoms {
pub(crate) client: [u8; 32],
pub(crate) server: [u8; 32],
}
impl ConnectionRandoms {
pub(crate) fn new(client: Random, server: Random) -> Self {
Self {
client: client.0,
server: server.0,
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct IoState {
peer_has_closed: bool,
}
impl IoState {
pub(crate) fn new(recv: &ReceivePath) -> Self {
Self {
peer_has_closed: recv.has_received_close_notify,
}
}
pub fn peer_has_closed(&self) -> bool {
self.peer_has_closed
}
}
pub(crate) struct SideCommonOutput<'a, 'q> {
pub(crate) side: &'a mut dyn SideOutput,
pub(crate) quic: Option<&'q mut dyn QuicOutput>,
pub(crate) common: &'a mut CommonState,
pub(crate) tls: &'a mut Vec<u8>,
}
impl<'q> Output<'_> for SideCommonOutput<'_, 'q> {
fn emit(&mut self, ev: Event) {
self.side.emit(ev);
}
fn output(&mut self, ev: OutputEvent<'_>) {
if let OutputEvent::ProtocolVersion(ver) = ev {
self.common.recv.negotiated_version = Some(ver);
self.common.send.negotiated_version(ver);
}
self.common.outputs.handle(ev);
}
fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) -> Result<(), Error> {
match self.quic() {
Some(quic) => {
quic.send_msg(m, must_encrypt);
Ok(())
}
None => self
.common
.send
.send_msg(m, must_encrypt, self.tls),
}
}
fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
match self.quic.as_mut() {
Some(q) => Some(&mut **q),
None => None,
}
}
fn start_traffic(&mut self) {
self.common
.recv
.may_receive_application_data = true;
self.common
.send
.start_outgoing_traffic();
}
fn receive(&mut self) -> &mut ReceivePath {
&mut self.common.recv
}
fn send(&mut self) -> &mut dyn SendOutput {
&mut self.common.send
}
}
#[expect(private_bounds)]
pub trait SideData: SideOutput + fmt::Debug + private::Side + Sized + 'static {
type Handshake: TryFrom<Connection<Self, Tcp>, Error = Error>;
type QuicHandshake: quic::FromConn<Self>;
type PeerIdentity<'a>;
}
pub(crate) mod private {
use super::*;
pub(crate) trait Side: fmt::Debug {
type State: StateMachine;
}
pub(crate) trait SideOutput {
fn emit(&mut self, ev: Event);
}
}
use private::SideOutput;
pub(crate) trait StateMachine: Sized {
fn handle<'m>(self, input: Input<'m>, output: &mut dyn Output<'m>) -> Result<Self, Error>;
fn wants_input(&self) -> bool;
fn handle_without_input(self, output: &mut dyn Output<'_>) -> Result<Self, Error>;
fn is_traffic(&self) -> bool;
fn handle_decrypt_error(&mut self);
fn into_external_state(
self,
send_keys: &Option<Box<KeyScheduleTrafficSend>>,
) -> Result<(PartiallyExtractedSecrets, Box<dyn KernelState + 'static>), Error>;
}
const SEQ_SOFT_LIMIT: u64 = u64::MAX - 0xffff;
const SEQ_HARD_LIMIT: u64 = u64::MAX - 1;