1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::fmt;
4use core::ops::{Deref, DerefMut, Range};
5
6use pki_types::{DnsName, FipsStatus};
7
8use crate::client::EchStatus;
9use crate::conn::{DataKind, Exporter, KeyingMaterialExporter, ReceivePath, SendOutput, SendPath};
10use crate::crypto::cipher::{EncodableVersion, Payload};
11use crate::crypto::kx::SupportedKxGroup;
12use crate::enums::{ApplicationProtocol, ProtocolVersion};
13use crate::error::{AlertDescription, ApiMisuse, Error};
14use crate::hash_hs::HandshakeHash;
15use crate::msgs::{
16 AlertLevel, Codec, Delocator, HandshakeMessagePayload, Locator, Message, MessagePayload,
17};
18use crate::quic::{self, QuicOutput};
19use crate::suites::SupportedCipherSuite;
20use crate::verify::VerifiedIdentity;
21
22pub struct CommonState {
24 pub(crate) outputs: ConnectionOutputs,
25 pub(crate) send: SendPath,
26 pub(crate) recv: ReceivePath,
27 pub(crate) fips: FipsStatus,
28}
29
30impl CommonState {
31 pub(crate) fn new(side: Side, fips: FipsStatus) -> Self {
32 Self {
33 outputs: ConnectionOutputs::default(),
34 send: SendPath::default(),
35 recv: ReceivePath::new(side),
36 fips,
37 }
38 }
39
40 pub fn send_close_notify(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
45 self.send.send_close_notify(tls)
46 }
47
48 pub fn is_handshaking(&self) -> bool {
56 !(self.send.may_send_application_data && self.recv.may_receive_application_data)
57 }
58}
59
60impl Deref for CommonState {
61 type Target = ConnectionOutputs;
62
63 fn deref(&self) -> &Self::Target {
64 &self.outputs
65 }
66}
67
68impl DerefMut for CommonState {
69 fn deref_mut(&mut self) -> &mut Self::Target {
70 &mut self.outputs
71 }
72}
73
74impl fmt::Debug for CommonState {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 f.debug_struct("CommonState")
77 .finish_non_exhaustive()
78 }
79}
80
81#[derive(Default)]
83pub struct ConnectionOutputs {
84 negotiated_version: Option<ProtocolVersion>,
85 handshake_kind: Option<HandshakeKind>,
86 suite: Option<SupportedCipherSuite>,
87 negotiated_kx_group: Option<&'static dyn SupportedKxGroup>,
88 alpn_protocol: Option<ApplicationProtocol<'static>>,
89 peer_identity: Option<VerifiedIdentity<'static>>,
90 extended_main_secret: Option<bool>,
91 exporter: Option<Box<dyn Exporter>>,
92 pub(crate) early_exporter: Option<Box<dyn Exporter>>,
93}
94
95impl ConnectionOutputs {
96 pub fn peer_identity(&self) -> Option<&VerifiedIdentity<'static>> {
105 self.peer_identity.as_ref()
106 }
107
108 pub fn alpn_protocol(&self) -> Option<&ApplicationProtocol<'static>> {
114 self.alpn_protocol.as_ref()
115 }
116
117 pub fn negotiated_cipher_suite(&self) -> Option<SupportedCipherSuite> {
121 self.suite
122 }
123
124 pub fn negotiated_key_exchange_group(&self) -> Option<&'static dyn SupportedKxGroup> {
134 self.negotiated_kx_group
135 }
136
137 pub fn protocol_version(&self) -> Option<ProtocolVersion> {
141 self.negotiated_version
142 }
143
144 pub fn extended_main_secret(&self) -> Option<bool> {
152 self.extended_main_secret
153 }
154
155 pub fn handshake_kind(&self) -> Option<HandshakeKind> {
162 self.handshake_kind
163 }
164
165 #[doc = include_str!("doc/early_exporter.md")]
166 pub fn early_exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
167 match self.early_exporter.take() {
168 Some(inner) => Ok(KeyingMaterialExporter { inner }),
169 None => Err(ApiMisuse::ExporterNotAvailable.into()),
170 }
171 }
172
173 #[doc = include_str!("doc/exporter.md")]
174 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
175 match self.exporter.take() {
176 Some(inner) => Ok(KeyingMaterialExporter { inner }),
177 None => Err(ApiMisuse::ExporterNotAvailable.into()),
178 }
179 }
180
181 pub(super) fn into_kernel_parts(self) -> Option<(ProtocolVersion, SupportedCipherSuite)> {
182 let Self {
183 negotiated_version,
184 suite,
185 ..
186 } = self;
187
188 match (negotiated_version, suite) {
189 (Some(version), Some(suite)) => Some((version, suite)),
190 _ => None,
191 }
192 }
193}
194
195impl ConnectionOutput for ConnectionOutputs {
196 fn handle(&mut self, ev: OutputEvent<'_>) {
197 match ev {
198 OutputEvent::ApplicationProtocol(protocol) => {
199 self.alpn_protocol = Some(ApplicationProtocol::from(protocol.as_ref()).to_owned())
200 }
201 OutputEvent::CipherSuite(suite) => self.suite = Some(suite),
202 OutputEvent::EarlyExporter(exporter) => self.early_exporter = Some(exporter),
203 OutputEvent::Exporter(exporter) => self.exporter = Some(exporter),
204 OutputEvent::ExtendedMainSecret(ems) => self.extended_main_secret = Some(ems),
205 OutputEvent::HandshakeKind(hk) => {
206 assert!(self.handshake_kind.is_none());
207 self.handshake_kind = Some(hk);
208 }
209 OutputEvent::KeyExchangeGroup(kxg) => {
210 assert!(self.negotiated_kx_group.is_none());
211 self.negotiated_kx_group = Some(kxg);
212 }
213 OutputEvent::PeerIdentity(identity) => self.peer_identity = Some(identity),
214 OutputEvent::ProtocolVersion(ver) => {
215 self.negotiated_version = Some(ver);
216 }
217 }
218 }
219}
220
221impl fmt::Debug for ConnectionOutputs {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 let Self {
224 negotiated_version,
225 handshake_kind,
226 suite,
227 negotiated_kx_group,
228 alpn_protocol,
229 peer_identity,
230 extended_main_secret,
231 exporter: _,
232 early_exporter: _,
233 } = self;
234 f.debug_struct("ConnectionOutputs")
235 .field("negotiated_version", negotiated_version)
236 .field("handshake_kind", handshake_kind)
237 .field("suite", suite)
238 .field("negotiated_kx_group", negotiated_kx_group)
239 .field("alpn_protocol", alpn_protocol)
240 .field("peer_identity", peer_identity)
241 .field("extended_main_secret", extended_main_secret)
242 .finish_non_exhaustive()
243 }
244}
245
246pub(crate) fn maybe_send_fatal_alert(
248 send: &mut dyn SendOutput,
249 error: &Error,
250 tls: &mut Vec<u8>,
251) -> Result<(), Error> {
252 let Ok(alert) = AlertDescription::try_from(error) else {
253 return Ok(());
254 };
255 send.send_alert(AlertLevel::Fatal, alert, tls)
256}
257
258#[derive(Debug, PartialEq, Clone, Copy)]
260#[non_exhaustive]
261pub enum HandshakeKind {
262 Full,
267
268 FullWithHelloRetryRequest,
274
275 Resumed,
281
282 ResumedWithHelloRetryRequest,
288}
289
290pub(crate) trait Output<'m> {
292 fn emit(&mut self, ev: Event);
293
294 fn output(&mut self, ev: OutputEvent<'_>);
295
296 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) -> Result<(), Error>;
297
298 fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
299 None
300 }
301
302 fn received_plaintext(&mut self, _payload: DataKind<Payload<'m>>) {}
303
304 fn start_traffic(&mut self);
305
306 fn receive(&mut self) -> &mut ReceivePath;
307
308 fn send(&mut self) -> &mut dyn SendOutput;
309}
310
311pub(crate) trait ConnectionOutput {
312 fn handle(&mut self, ev: OutputEvent<'_>);
313}
314
315pub(crate) enum Event {
317 EarlyData(EarlyDataEvent),
318 EchStatus(EchStatus),
319 ReceivedServerName(Option<DnsName<'static>>),
320 ResumptionData(Vec<u8>),
321}
322
323pub(crate) enum OutputEvent<'a> {
324 ApplicationProtocol(ApplicationProtocol<'a>),
325 CipherSuite(SupportedCipherSuite),
326 EarlyExporter(Box<dyn Exporter>),
327 Exporter(Box<dyn Exporter>),
328 ExtendedMainSecret(bool),
329 HandshakeKind(HandshakeKind),
330 KeyExchangeGroup(&'static dyn SupportedKxGroup),
331 PeerIdentity(VerifiedIdentity<'static>),
332 ProtocolVersion(ProtocolVersion),
333}
334
335pub(crate) enum EarlyDataEvent {
336 Enable(usize),
338 Start,
340 Finished,
342 Accepted,
344 Rejected,
346}
347
348pub(crate) enum UnborrowedPayload {
353 Unborrowed(Range<usize>),
354 Owned(Vec<u8>),
355}
356
357impl UnborrowedPayload {
358 pub(crate) fn unborrow(locator: &Locator, payload: Payload<'_>) -> Self {
367 match payload {
368 Payload::Borrowed(payload) => Self::Unborrowed(locator.locate(payload)),
369 Payload::Owned(payload) => Self::Owned(payload),
370 }
371 }
372
373 pub(crate) fn reborrow<'b>(self, delocator: &Delocator<'b>) -> Payload<'b> {
380 match self {
381 Self::Unborrowed(range) => Payload::Borrowed(delocator.slice_from_range(&range)),
382 Self::Owned(payload) => Payload::Owned(payload),
383 }
384 }
385}
386
387#[expect(clippy::exhaustive_enums)]
389#[derive(Clone, Copy, Debug, PartialEq)]
390pub enum Side {
391 Client,
393 Server,
395}
396
397#[derive(Copy, Clone, Eq, PartialEq, Debug)]
399#[non_exhaustive]
400pub enum Protocol {
401 Tcp,
403 Quic(quic::Version),
405}
406
407impl Protocol {
408 pub(crate) fn is_quic(&self) -> bool {
409 matches!(self, Self::Quic(_))
410 }
411
412 pub(crate) fn supports_version(&self, version: ProtocolVersion) -> bool {
413 match self {
414 Self::Quic(_) => version == ProtocolVersion::TLSv1_3,
415 Self::Tcp => true,
416 }
417 }
418}
419
420pub(crate) struct HandshakeFlight<'a, const TLS13: bool> {
421 pub(crate) transcript: &'a mut HandshakeHash,
422 body: Vec<u8>,
423}
424
425impl<'a, const TLS13: bool> HandshakeFlight<'a, TLS13> {
426 pub(crate) fn new(transcript: &'a mut HandshakeHash) -> Self {
427 Self {
428 transcript,
429 body: Vec::new(),
430 }
431 }
432
433 pub(crate) fn add(&mut self, hs: HandshakeMessagePayload<'_>) {
434 let start_len = self.body.len();
435 hs.encode(&mut self.body);
436 self.transcript
437 .add(&self.body[start_len..]);
438 }
439
440 pub(crate) fn finish(self, output: &mut dyn Output<'_>) -> Result<(), Error> {
441 let m = Message {
442 version: EncodableVersion::Legacy(match TLS13 {
443 true => ProtocolVersion::TLSv1_3,
444 false => ProtocolVersion::TLSv1_2,
445 }),
446 payload: MessagePayload::HandshakeFlight(Payload::new(self.body)),
447 };
448
449 output.send_msg(m, TLS13)
450 }
451}
452
453pub(crate) type HandshakeFlightTls12<'a> = HandshakeFlight<'a, false>;
454pub(crate) type HandshakeFlightTls13<'a> = HandshakeFlight<'a, true>;