use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt::{self, Debug};
use core::ops::{Deref, DerefMut};
use std::io::{self, BufRead, Read};
use kernel::KernelConnection;
use pki_types::FipsStatus;
use crate::common_state::{
CommonState, ConnectionOutput, ConnectionOutputs, Event, Output, OutputEvent,
};
use crate::error::{ApiMisuse, Error};
use crate::kernel::KernelState;
use crate::msgs::{Delocator, Message, Random, ServerExtensionsInput};
use crate::quic::QuicOutput;
use crate::server::{ChooseConfig, ServerConfig, ServerSide};
use crate::suites::{ExtractedSecrets, PartiallyExtractedSecrets};
use crate::sync::Arc;
use crate::tls13::key_schedule::KeyScheduleTrafficSend;
use crate::vecbuf::ChunkVecBuffer;
pub mod kernel;
mod receive;
pub(crate) use receive::{Input, MessageIter, ReceivePath, TrafficTemperCounters};
pub use receive::{SliceInput, TlsInputBuffer, VecInput};
mod send;
use send::DEFAULT_BUFFER_LIMIT;
pub use send::WrittenInto;
pub(crate) use send::{SendOutput, SendPath};
pub(crate) mod split;
use split::SplitConnection;
use crate::crypto::cipher::OutboundPlain;
pub trait Connection: Debug + Deref<Target = ConnectionOutputs> {
fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error>;
fn wants_read(&self) -> bool;
fn wants_write(&self) -> bool;
fn reader(&mut self) -> Reader<'_>;
fn writer(&mut self) -> Writer<'_>;
fn process_new_packets(&mut self, input: &mut dyn TlsInputBuffer) -> Result<IoState, Error>;
fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error>;
fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error>;
fn set_buffer_limit(&mut self, limit: Option<usize>);
fn set_plaintext_buffer_limit(&mut self, limit: Option<usize>);
fn refresh_traffic_keys(&mut self) -> Result<(), Error>;
fn send_close_notify(&mut self);
fn is_handshaking(&self) -> bool;
fn fips(&self) -> FipsStatus;
}
pub(crate) struct ConnectionCommon<Side: SideData> {
pub(crate) core: ConnectionCore<Side>,
buffers: Buffers,
}
impl<Side: SideData> ConnectionCommon<Side> {
pub(crate) fn new(core: ConnectionCore<Side>) -> Self {
Self {
core,
buffers: Buffers::new(),
}
}
#[inline]
pub(crate) fn process_new_packets(
&mut self,
input: &mut dyn TlsInputBuffer,
) -> Result<IoState, Error> {
if input.has_seen_eof() {
self.buffers.has_seen_eof = true;
} else if self
.buffers
.received_plaintext
.is_full()
{
return Err(ApiMisuse::ReceivedPlaintextBufferFull.into());
}
let mut iter = MessageIter::new(input, None, &mut self.core);
while let Some(result) = iter.next() {
let payload = result?.reborrow(&Delocator::new(iter.input().slice_mut()));
self.buffers
.received_plaintext
.append(payload.into_vec());
}
input.discard(
self.core
.common
.recv
.deframer
.take_discard(),
);
if self.send.may_send_application_data
&& !self
.buffers
.sendable_plaintext
.is_empty()
{
self.core
.common
.send
.send_buffered_plaintext(&mut self.buffers.sendable_plaintext);
}
Ok(IoState::new(
&self.core.common.send,
&self.core.common.recv,
&self.buffers,
))
}
pub(crate) fn wants_read(&self) -> bool {
self.buffers
.received_plaintext
.is_empty()
&& !self.recv.has_received_close_notify
&& (self.send.may_send_application_data || self.send.sendable_tls.is_empty())
}
pub(crate) fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
self.core.exporter()
}
pub(crate) fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
self.core.dangerous_extract_secrets()
}
pub(crate) fn set_buffer_limit(&mut self, limit: Option<usize>) {
self.buffers
.sendable_plaintext
.set_limit(limit);
self.send.sendable_tls.set_limit(limit);
}
pub(crate) fn set_plaintext_buffer_limit(&mut self, limit: Option<usize>) {
self.buffers
.received_plaintext
.set_limit(limit);
}
pub(crate) fn refresh_traffic_keys(&mut self) -> Result<(), Error> {
self.core
.common
.send
.refresh_traffic_keys()
}
pub(crate) fn split(self) -> Result<SplitConnection<Side>, Error> {
if self.is_handshaking() {
return Err(ApiMisuse::SplitDuringHandshake.into());
}
if !self.buffers.is_empty() {
return Err(ApiMisuse::SplitWithPendingBuffers.into());
}
SplitConnection::try_from(self.core)
}
}
impl<Side: SideData> ConnectionCommon<Side> {
pub(crate) fn reader(&mut self) -> Reader<'_> {
let common = &mut self.core.common;
let has_received_close_notify = common.recv.has_received_close_notify;
Reader {
received_plaintext: &mut self.buffers.received_plaintext,
has_received_close_notify,
has_seen_eof: self.buffers.has_seen_eof,
}
}
pub(crate) fn writer(&mut self) -> Writer<'_> {
Writer::new(self)
}
pub(crate) fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> {
self.send.sendable_tls.write_to(wr)
}
}
impl<Side: SideData> Deref for ConnectionCommon<Side> {
type Target = CommonState;
fn deref(&self) -> &Self::Target {
&self.core.common
}
}
impl<Side: SideData> DerefMut for ConnectionCommon<Side> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.core.common
}
}
pub(crate) struct ConnectionCore<Side: SideData> {
pub(crate) state: Result<Side::State, Error>,
pub(crate) side: Side::Data,
pub(crate) common: CommonState,
}
impl<Side: SideData> ConnectionCore<Side> {
pub(crate) fn new(state: Side::State, side: Side::Data, common: CommonState) -> Self {
Self {
state: Ok(state),
side,
common,
}
}
pub(crate) fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
Ok(self
.dangerous_into_kernel_connection()?
.0)
}
pub(crate) fn dangerous_into_kernel_connection(
mut self,
) -> Result<(ExtractedSecrets, KernelConnection<Side>), Error> {
if self.common.is_handshaking() {
return Err(Error::HandshakeNotComplete);
}
Self::from_parts_into_kernel_connection(
&mut self.common.send,
self.common.recv,
self.common.outputs,
self.state?,
)
}
pub(crate) fn from_parts_into_kernel_connection(
send: &mut SendPath,
recv: ReceivePath,
outputs: ConnectionOutputs,
state: Side::State,
) -> Result<(ExtractedSecrets, KernelConnection<Side>), Error> {
if !send.sendable_tls.is_empty() {
return Err(ApiMisuse::SecretExtractionWithPendingSendableData.into());
}
let read_seq = recv.decrypt_state.read_seq();
let write_seq = send.encrypt_state.write_seq();
let tls13_key_schedule = send.tls13_key_schedule.take();
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(crate) fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
match self.common.exporter.take() {
Some(inner) => Ok(KeyingMaterialExporter { inner }),
None if self.common.is_handshaking() => Err(Error::HandshakeNotComplete),
None => Err(ApiMisuse::ExporterAlreadyUsed.into()),
}
}
pub(crate) fn early_exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
match self.common.early_exporter.take() {
Some(inner) => Ok(KeyingMaterialExporter { inner }),
None => Err(ApiMisuse::ExporterAlreadyUsed.into()),
}
}
}
impl ConnectionCore<ServerSide> {
pub(crate) fn accepted(
&mut self,
choose: Box<ChooseConfig>,
exts: ServerExtensionsInput,
quic: Option<&mut dyn QuicOutput>,
config: Arc<ServerConfig>,
) -> 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,
common: &mut self.common,
};
self.state = Ok(choose.use_config(config, exts, &mut output)?);
Ok(())
}
}
pub(crate) struct Buffers {
pub(crate) received_plaintext: ChunkVecBuffer,
pub(crate) sendable_plaintext: ChunkVecBuffer,
pub(crate) has_seen_eof: bool,
}
impl Buffers {
fn new() -> Self {
Self {
received_plaintext: ChunkVecBuffer::new(Some(DEFAULT_RECEIVED_PLAINTEXT_LIMIT)),
sendable_plaintext: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)),
has_seen_eof: false,
}
}
fn is_empty(&self) -> bool {
self.received_plaintext.is_empty() && self.sendable_plaintext.is_empty()
}
}
pub struct Reader<'a> {
pub(super) received_plaintext: &'a mut ChunkVecBuffer,
pub(super) has_received_close_notify: bool,
pub(super) has_seen_eof: bool,
}
impl<'a> Reader<'a> {
fn check_no_bytes_state(&self) -> io::Result<()> {
match (self.has_received_close_notify, self.has_seen_eof) {
(true, _) => Ok(()),
(false, true) => Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
UNEXPECTED_EOF_MESSAGE,
)),
(false, false) => Err(io::ErrorKind::WouldBlock.into()),
}
}
pub fn into_first_chunk(self) -> io::Result<&'a [u8]> {
match self.received_plaintext.chunk() {
Some(chunk) => Ok(chunk),
None => {
self.check_no_bytes_state()?;
Ok(&[])
}
}
}
}
impl Read for Reader<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = self.received_plaintext.read(buf);
if len > 0 || buf.is_empty() {
return Ok(len);
}
self.check_no_bytes_state()
.map(|()| len)
}
}
impl BufRead for Reader<'_> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Reader {
received_plaintext: self.received_plaintext,
..*self
}
.into_first_chunk()
}
fn consume(&mut self, amt: usize) {
self.received_plaintext
.consume_first_chunk(amt)
}
}
const UNEXPECTED_EOF_MESSAGE: &str = "peer closed connection without sending TLS close_notify: \
https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#unexpected-eof";
pub struct Writer<'a> {
sink: &'a mut dyn PlaintextSink,
}
impl<'a> Writer<'a> {
pub(crate) fn new(sink: &'a mut dyn PlaintextSink) -> Self {
Writer { sink }
}
}
impl io::Write for Writer<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.sink.write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.sink.write_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
self.sink.flush()
}
}
pub(crate) trait PlaintextSink {
fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>;
fn flush(&mut self) -> io::Result<()>;
}
impl<Side: SideData> PlaintextSink for ConnectionCommon<Side> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let len = self
.core
.common
.send
.buffer_plaintext(buf.into(), &mut self.buffers.sendable_plaintext);
self.send.maybe_refresh_traffic_keys();
Ok(len)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
let payload_owner: Vec<&[u8]>;
let payload = match bufs.len() {
0 => return Ok(0),
1 => OutboundPlain::Single(bufs[0].deref()),
_ => {
payload_owner = bufs
.iter()
.map(|io_slice| io_slice.deref())
.collect();
OutboundPlain::new(&payload_owner)
}
};
let len = self
.core
.common
.send
.buffer_plaintext(payload, &mut self.buffers.sendable_plaintext);
self.send.maybe_refresh_traffic_keys();
Ok(len)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
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 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 {
tls_bytes_to_write: usize,
plaintext_bytes_to_read: usize,
peer_has_closed: bool,
}
impl IoState {
pub(crate) fn new(send: &SendPath, recv: &ReceivePath, buffers: &Buffers) -> Self {
Self {
tls_bytes_to_write: send.sendable_tls.len(),
plaintext_bytes_to_read: buffers.received_plaintext.len(),
peer_has_closed: recv.has_received_close_notify,
}
}
pub fn tls_bytes_to_write(&self) -> usize {
self.tls_bytes_to_write
}
pub fn plaintext_bytes_to_read(&self) -> usize {
self.plaintext_bytes_to_read
}
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,
}
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) {
match self.quic() {
Some(quic) => quic.send_msg(m, must_encrypt),
None => self
.common
.send
.send_msg(m, must_encrypt),
}
}
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: private::Side {}
pub(crate) mod private {
use super::*;
pub(crate) trait Side: Debug {
type Data: SideOutput;
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 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 DEFAULT_RECEIVED_PLAINTEXT_LIMIT: usize = 16 * 1024;