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(crate) fn early_exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
41 match self.early_exporter.take() {
42 Some(inner) => Ok(KeyingMaterialExporter { inner }),
43 None => Err(ApiMisuse::ExporterAlreadyUsed.into()),
44 }
45 }
46
47 pub fn send_close_notify(&mut self, tls: &mut Vec<u8>) {
52 self.send.send_close_notify(tls)
53 }
54
55 pub fn is_handshaking(&self) -> bool {
63 !(self.send.may_send_application_data && self.recv.may_receive_application_data)
64 }
65}
66
67impl Deref for CommonState {
68 type Target = ConnectionOutputs;
69
70 fn deref(&self) -> &Self::Target {
71 &self.outputs
72 }
73}
74
75impl DerefMut for CommonState {
76 fn deref_mut(&mut self) -> &mut Self::Target {
77 &mut self.outputs
78 }
79}
80
81impl fmt::Debug for CommonState {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 f.debug_struct("CommonState")
84 .finish_non_exhaustive()
85 }
86}
87
88#[derive(Default)]
90pub struct ConnectionOutputs {
91 negotiated_version: Option<ProtocolVersion>,
92 handshake_kind: Option<HandshakeKind>,
93 suite: Option<SupportedCipherSuite>,
94 negotiated_kx_group: Option<&'static dyn SupportedKxGroup>,
95 alpn_protocol: Option<ApplicationProtocol<'static>>,
96 peer_identity: Option<VerifiedIdentity<'static>>,
97 extended_main_secret: Option<bool>,
98 pub(crate) exporter: Option<Box<dyn Exporter>>,
99 pub(crate) early_exporter: Option<Box<dyn Exporter>>,
100}
101
102impl ConnectionOutputs {
103 pub fn peer_identity(&self) -> Option<&VerifiedIdentity<'static>> {
112 self.peer_identity.as_ref()
113 }
114
115 pub fn alpn_protocol(&self) -> Option<&ApplicationProtocol<'static>> {
121 self.alpn_protocol.as_ref()
122 }
123
124 pub fn negotiated_cipher_suite(&self) -> Option<SupportedCipherSuite> {
128 self.suite
129 }
130
131 pub fn negotiated_key_exchange_group(&self) -> Option<&'static dyn SupportedKxGroup> {
141 self.negotiated_kx_group
142 }
143
144 pub fn protocol_version(&self) -> Option<ProtocolVersion> {
148 self.negotiated_version
149 }
150
151 pub fn extended_main_secret(&self) -> Option<bool> {
159 self.extended_main_secret
160 }
161
162 pub fn handshake_kind(&self) -> Option<HandshakeKind> {
169 self.handshake_kind
170 }
171
172 pub(super) fn into_kernel_parts(self) -> Option<(ProtocolVersion, SupportedCipherSuite)> {
173 let Self {
174 negotiated_version,
175 suite,
176 ..
177 } = self;
178
179 match (negotiated_version, suite) {
180 (Some(version), Some(suite)) => Some((version, suite)),
181 _ => None,
182 }
183 }
184}
185
186impl ConnectionOutput for ConnectionOutputs {
187 fn handle(&mut self, ev: OutputEvent<'_>) {
188 match ev {
189 OutputEvent::ApplicationProtocol(protocol) => {
190 self.alpn_protocol = Some(ApplicationProtocol::from(protocol.as_ref()).to_owned())
191 }
192 OutputEvent::CipherSuite(suite) => self.suite = Some(suite),
193 OutputEvent::EarlyExporter(exporter) => self.early_exporter = Some(exporter),
194 OutputEvent::Exporter(exporter) => self.exporter = Some(exporter),
195 OutputEvent::ExtendedMainSecret(ems) => self.extended_main_secret = Some(ems),
196 OutputEvent::HandshakeKind(hk) => {
197 assert!(self.handshake_kind.is_none());
198 self.handshake_kind = Some(hk);
199 }
200 OutputEvent::KeyExchangeGroup(kxg) => {
201 assert!(self.negotiated_kx_group.is_none());
202 self.negotiated_kx_group = Some(kxg);
203 }
204 OutputEvent::PeerIdentity(identity) => self.peer_identity = Some(identity),
205 OutputEvent::ProtocolVersion(ver) => {
206 self.negotiated_version = Some(ver);
207 }
208 }
209 }
210}
211
212impl fmt::Debug for ConnectionOutputs {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 let Self {
215 negotiated_version,
216 handshake_kind,
217 suite,
218 negotiated_kx_group,
219 alpn_protocol,
220 peer_identity,
221 extended_main_secret,
222 exporter: _,
223 early_exporter: _,
224 } = self;
225 f.debug_struct("ConnectionOutputs")
226 .field("negotiated_version", negotiated_version)
227 .field("handshake_kind", handshake_kind)
228 .field("suite", suite)
229 .field("negotiated_kx_group", negotiated_kx_group)
230 .field("alpn_protocol", alpn_protocol)
231 .field("peer_identity", peer_identity)
232 .field("extended_main_secret", extended_main_secret)
233 .finish_non_exhaustive()
234 }
235}
236
237pub(crate) fn maybe_send_fatal_alert(send: &mut dyn SendOutput, error: &Error, tls: &mut Vec<u8>) {
239 let Ok(alert) = AlertDescription::try_from(error) else {
240 return;
241 };
242 send.send_alert(AlertLevel::Fatal, alert, tls);
243}
244
245#[derive(Debug, PartialEq, Clone, Copy)]
247#[non_exhaustive]
248pub enum HandshakeKind {
249 Full,
254
255 FullWithHelloRetryRequest,
261
262 Resumed,
268
269 ResumedWithHelloRetryRequest,
275}
276
277pub(crate) trait Output<'m> {
279 fn emit(&mut self, ev: Event);
280
281 fn output(&mut self, ev: OutputEvent<'_>);
282
283 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
284
285 fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
286 None
287 }
288
289 fn received_plaintext(&mut self, _payload: DataKind<Payload<'m>>) {}
290
291 fn start_traffic(&mut self);
292
293 fn receive(&mut self) -> &mut ReceivePath;
294
295 fn send(&mut self) -> &mut dyn SendOutput;
296}
297
298pub(crate) trait ConnectionOutput {
299 fn handle(&mut self, ev: OutputEvent<'_>);
300}
301
302pub(crate) enum Event {
304 EarlyData(EarlyDataEvent),
305 EchStatus(EchStatus),
306 ReceivedServerName(Option<DnsName<'static>>),
307 ResumptionData(Vec<u8>),
308}
309
310pub(crate) enum OutputEvent<'a> {
311 ApplicationProtocol(ApplicationProtocol<'a>),
312 CipherSuite(SupportedCipherSuite),
313 EarlyExporter(Box<dyn Exporter>),
314 Exporter(Box<dyn Exporter>),
315 ExtendedMainSecret(bool),
316 HandshakeKind(HandshakeKind),
317 KeyExchangeGroup(&'static dyn SupportedKxGroup),
318 PeerIdentity(VerifiedIdentity<'static>),
319 ProtocolVersion(ProtocolVersion),
320}
321
322pub(crate) enum EarlyDataEvent {
323 Accepted,
325 Enable(usize),
327 Start,
329 Finished,
331 Rejected,
333}
334
335pub(crate) enum UnborrowedPayload {
340 Unborrowed(Range<usize>),
341 Owned(Vec<u8>),
342}
343
344impl UnborrowedPayload {
345 pub(crate) fn unborrow(locator: &Locator, payload: Payload<'_>) -> Self {
354 match payload {
355 Payload::Borrowed(payload) => Self::Unborrowed(locator.locate(payload)),
356 Payload::Owned(payload) => Self::Owned(payload),
357 }
358 }
359
360 pub(crate) fn reborrow<'b>(self, delocator: &Delocator<'b>) -> Payload<'b> {
367 match self {
368 Self::Unborrowed(range) => Payload::Borrowed(delocator.slice_from_range(&range)),
369 Self::Owned(payload) => Payload::Owned(payload),
370 }
371 }
372}
373
374#[expect(clippy::exhaustive_enums)]
376#[derive(Clone, Copy, Debug, PartialEq)]
377pub enum Side {
378 Client,
380 Server,
382}
383
384#[derive(Copy, Clone, Eq, PartialEq, Debug)]
386#[non_exhaustive]
387pub enum Protocol {
388 Tcp,
390 Quic(quic::Version),
392}
393
394impl Protocol {
395 pub(crate) fn is_quic(&self) -> bool {
396 matches!(self, Self::Quic(_))
397 }
398
399 pub(crate) fn supports_version(&self, version: ProtocolVersion) -> bool {
400 match self {
401 Self::Quic(_) => version == ProtocolVersion::TLSv1_3,
402 Self::Tcp => true,
403 }
404 }
405}
406
407pub(crate) struct HandshakeFlight<'a, const TLS13: bool> {
408 pub(crate) transcript: &'a mut HandshakeHash,
409 body: Vec<u8>,
410}
411
412impl<'a, const TLS13: bool> HandshakeFlight<'a, TLS13> {
413 pub(crate) fn new(transcript: &'a mut HandshakeHash) -> Self {
414 Self {
415 transcript,
416 body: Vec::new(),
417 }
418 }
419
420 pub(crate) fn add(&mut self, hs: HandshakeMessagePayload<'_>) {
421 let start_len = self.body.len();
422 hs.encode(&mut self.body);
423 self.transcript
424 .add(&self.body[start_len..]);
425 }
426
427 pub(crate) fn finish(self, output: &mut dyn Output<'_>) {
428 let m = Message {
429 version: EncodableVersion::Legacy(match TLS13 {
430 true => ProtocolVersion::TLSv1_3,
431 false => ProtocolVersion::TLSv1_2,
432 }),
433 payload: MessagePayload::HandshakeFlight(Payload::new(self.body)),
434 };
435
436 output.send_msg(m, TLS13);
437 }
438}
439
440pub(crate) type HandshakeFlightTls12<'a> = HandshakeFlight<'a, false>;
441pub(crate) type HandshakeFlightTls13<'a> = HandshakeFlight<'a, true>;