use alloc::boxed::Box;
use core::marker::PhantomData;
use crate::client::ClientSide;
use crate::enums::ProtocolVersion;
use crate::error::ApiMisuse;
use crate::msgs::{Codec, NewSessionTicketPayloadTls13};
use crate::tls13::key_schedule::KeyScheduleTrafficSend;
use crate::{ConnectionOutputs, ConnectionTrafficSecrets, Error, SupportedCipherSuite};
pub struct KernelConnection<Side> {
state: Box<dyn KernelState>,
tls13_key_schedule: Option<Box<KeyScheduleTrafficSend>>,
negotiated_version: ProtocolVersion,
suite: SupportedCipherSuite,
_side: PhantomData<Side>,
}
impl<Side> KernelConnection<Side> {
pub(crate) fn new(
state: Box<dyn KernelState>,
outputs: ConnectionOutputs,
tls13_key_schedule: Option<Box<KeyScheduleTrafficSend>>,
) -> Result<Self, Error> {
let (negotiated_version, suite) = outputs
.into_kernel_parts()
.ok_or(Error::HandshakeNotComplete)?;
Ok(Self {
state,
tls13_key_schedule,
negotiated_version,
suite,
_side: PhantomData,
})
}
pub fn negotiated_cipher_suite(&self) -> SupportedCipherSuite {
self.suite
}
pub fn protocol_version(&self) -> ProtocolVersion {
self.negotiated_version
}
pub fn update_tx_secret(&mut self) -> Result<(u64, ConnectionTrafficSecrets), Error> {
match &mut self.tls13_key_schedule {
Some(ks) => ks
.refresh_traffic_secret()
.map(|secret| (0, secret)),
None => Err(ApiMisuse::KeyUpdateNotAvailableForTls12.into()),
}
}
pub fn update_rx_secret(&mut self) -> Result<(u64, ConnectionTrafficSecrets), Error> {
self.state
.update_rx_secret()
.map(|secret| (0, secret))
}
}
impl KernelConnection<ClientSide> {
pub fn handle_new_session_ticket(&mut self, payload: &[u8]) -> Result<(), Error> {
if self.protocol_version() != ProtocolVersion::TLSv1_3 {
return Err(Error::General(
"TLS 1.2 session tickets may not be sent once the handshake has completed".into(),
));
}
let nst = NewSessionTicketPayloadTls13::read_bytes(payload)?;
self.state
.handle_new_session_ticket(&nst)
}
}
pub(crate) trait KernelState: Send + Sync {
fn update_rx_secret(&mut self) -> Result<ConnectionTrafficSecrets, Error>;
fn handle_new_session_ticket(
&self,
message: &NewSessionTicketPayloadTls13,
) -> Result<(), Error>;
}