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::{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>) {
54 self.send.send_close_notify(tls)
55 }
56
57 pub fn is_handshaking(&self) -> bool {
65 !(self.send.may_send_application_data && self.recv.may_receive_application_data)
66 }
67}
68
69impl Deref for CommonState {
70 type Target = ConnectionOutputs;
71
72 fn deref(&self) -> &Self::Target {
73 &self.outputs
74 }
75}
76
77impl DerefMut for CommonState {
78 fn deref_mut(&mut self) -> &mut Self::Target {
79 &mut self.outputs
80 }
81}
82
83impl fmt::Debug for CommonState {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.debug_struct("CommonState")
86 .finish_non_exhaustive()
87 }
88}
89
90#[derive(Default)]
92pub struct ConnectionOutputs {
93 negotiated_version: Option<ProtocolVersion>,
94 handshake_kind: Option<HandshakeKind>,
95 suite: Option<SupportedCipherSuite>,
96 negotiated_kx_group: Option<&'static dyn SupportedKxGroup>,
97 alpn_protocol: Option<ApplicationProtocol<'static>>,
98 peer_identity: Option<VerifiedIdentity<'static>>,
99 extended_main_secret: Option<bool>,
100 pub(crate) exporter: Option<Box<dyn Exporter>>,
101 pub(crate) early_exporter: Option<Box<dyn Exporter>>,
102}
103
104impl ConnectionOutputs {
105 pub fn peer_identity(&self) -> Option<&VerifiedIdentity<'static>> {
114 self.peer_identity.as_ref()
115 }
116
117 pub fn alpn_protocol(&self) -> Option<&ApplicationProtocol<'static>> {
123 self.alpn_protocol.as_ref()
124 }
125
126 pub fn negotiated_cipher_suite(&self) -> Option<SupportedCipherSuite> {
130 self.suite
131 }
132
133 pub fn negotiated_key_exchange_group(&self) -> Option<&'static dyn SupportedKxGroup> {
143 self.negotiated_kx_group
144 }
145
146 pub fn protocol_version(&self) -> Option<ProtocolVersion> {
150 self.negotiated_version
151 }
152
153 pub fn extended_main_secret(&self) -> Option<bool> {
161 self.extended_main_secret
162 }
163
164 pub fn handshake_kind(&self) -> Option<HandshakeKind> {
171 self.handshake_kind
172 }
173
174 pub(super) fn into_kernel_parts(self) -> Option<(ProtocolVersion, SupportedCipherSuite)> {
175 let Self {
176 negotiated_version,
177 suite,
178 ..
179 } = self;
180
181 match (negotiated_version, suite) {
182 (Some(version), Some(suite)) => Some((version, suite)),
183 _ => None,
184 }
185 }
186}
187
188impl ConnectionOutput for ConnectionOutputs {
189 fn handle(&mut self, ev: OutputEvent<'_>) {
190 match ev {
191 OutputEvent::ApplicationProtocol(protocol) => {
192 self.alpn_protocol = Some(ApplicationProtocol::from(protocol.as_ref()).to_owned())
193 }
194 OutputEvent::CipherSuite(suite) => self.suite = Some(suite),
195 OutputEvent::EarlyExporter(exporter) => self.early_exporter = Some(exporter),
196 OutputEvent::Exporter(exporter) => self.exporter = Some(exporter),
197 OutputEvent::ExtendedMainSecret(ems) => self.extended_main_secret = Some(ems),
198 OutputEvent::HandshakeKind(hk) => {
199 assert!(self.handshake_kind.is_none());
200 self.handshake_kind = Some(hk);
201 }
202 OutputEvent::KeyExchangeGroup(kxg) => {
203 assert!(self.negotiated_kx_group.is_none());
204 self.negotiated_kx_group = Some(kxg);
205 }
206 OutputEvent::PeerIdentity(identity) => self.peer_identity = Some(identity),
207 OutputEvent::ProtocolVersion(ver) => {
208 self.negotiated_version = Some(ver);
209 }
210 }
211 }
212}
213
214impl fmt::Debug for ConnectionOutputs {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 let Self {
217 negotiated_version,
218 handshake_kind,
219 suite,
220 negotiated_kx_group,
221 alpn_protocol,
222 peer_identity,
223 extended_main_secret,
224 exporter: _,
225 early_exporter: _,
226 } = self;
227 f.debug_struct("ConnectionOutputs")
228 .field("negotiated_version", negotiated_version)
229 .field("handshake_kind", handshake_kind)
230 .field("suite", suite)
231 .field("negotiated_kx_group", negotiated_kx_group)
232 .field("alpn_protocol", alpn_protocol)
233 .field("peer_identity", peer_identity)
234 .field("extended_main_secret", extended_main_secret)
235 .finish_non_exhaustive()
236 }
237}
238
239pub(crate) fn maybe_send_fatal_alert(send: &mut dyn SendOutput, error: &Error, tls: &mut Vec<u8>) {
241 let Ok(alert) = AlertDescription::try_from(error) else {
242 return;
243 };
244 send.send_alert(AlertLevel::Fatal, alert, tls);
245}
246
247#[derive(Debug, PartialEq, Clone, Copy)]
249#[non_exhaustive]
250pub enum HandshakeKind {
251 Full,
256
257 FullWithHelloRetryRequest,
263
264 Resumed,
270
271 ResumedWithHelloRetryRequest,
277}
278
279pub(crate) trait Output<'m> {
281 fn emit(&mut self, ev: Event<'_>);
282
283 fn output(&mut self, ev: OutputEvent<'_>);
284
285 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
286
287 fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
288 None
289 }
290
291 fn received_plaintext(&mut self, _payload: Payload<'m>) {}
292
293 fn start_traffic(&mut self);
294
295 fn receive(&mut self) -> &mut ReceivePath;
296
297 fn send(&mut self) -> &mut dyn SendOutput;
298}
299
300pub(crate) trait ConnectionOutput {
301 fn handle(&mut self, ev: OutputEvent<'_>);
302}
303
304pub(crate) enum Event<'a> {
306 EarlyApplicationData(Payload<'a>),
307 EarlyData(EarlyDataEvent),
308 EchStatus(EchStatus),
309 ReceivedServerName(Option<DnsName<'static>>),
310 ResumptionData(Vec<u8>),
311}
312
313pub(crate) enum OutputEvent<'a> {
314 ApplicationProtocol(ApplicationProtocol<'a>),
315 CipherSuite(SupportedCipherSuite),
316 EarlyExporter(Box<dyn Exporter>),
317 Exporter(Box<dyn Exporter>),
318 ExtendedMainSecret(bool),
319 HandshakeKind(HandshakeKind),
320 KeyExchangeGroup(&'static dyn SupportedKxGroup),
321 PeerIdentity(VerifiedIdentity<'static>),
322 ProtocolVersion(ProtocolVersion),
323}
324
325pub(crate) enum EarlyDataEvent {
326 Accepted,
328 Enable(usize),
330 Start,
332 Finished,
334 Rejected,
336}
337
338pub(crate) enum UnborrowedPayload {
343 Unborrowed(Range<usize>),
344 Owned(Vec<u8>),
345}
346
347impl UnborrowedPayload {
348 pub(crate) fn unborrow(locator: &Locator, payload: Payload<'_>) -> Self {
357 match payload {
358 Payload::Borrowed(payload) => Self::Unborrowed(locator.locate(payload)),
359 Payload::Owned(payload) => Self::Owned(payload),
360 }
361 }
362
363 pub(crate) fn reborrow<'b>(self, delocator: &Delocator<'b>) -> Payload<'b> {
370 match self {
371 Self::Unborrowed(range) => Payload::Borrowed(delocator.slice_from_range(&range)),
372 Self::Owned(payload) => Payload::Owned(payload),
373 }
374 }
375}
376
377#[expect(clippy::exhaustive_enums)]
379#[derive(Clone, Copy, Debug, PartialEq)]
380pub enum Side {
381 Client,
383 Server,
385}
386
387#[derive(Copy, Clone, Eq, PartialEq, Debug)]
389#[non_exhaustive]
390pub enum Protocol {
391 Tcp,
393 Quic(quic::Version),
395}
396
397impl Protocol {
398 pub(crate) fn is_quic(&self) -> bool {
399 matches!(self, Self::Quic(_))
400 }
401
402 pub(crate) fn supports_version(&self, version: ProtocolVersion) -> bool {
403 match self {
404 Self::Quic(_) => version == ProtocolVersion::TLSv1_3,
405 Self::Tcp => true,
406 }
407 }
408}
409
410pub(crate) struct HandshakeFlight<'a, const TLS13: bool> {
411 pub(crate) transcript: &'a mut HandshakeHash,
412 body: Vec<u8>,
413}
414
415impl<'a, const TLS13: bool> HandshakeFlight<'a, TLS13> {
416 pub(crate) fn new(transcript: &'a mut HandshakeHash) -> Self {
417 Self {
418 transcript,
419 body: Vec::new(),
420 }
421 }
422
423 pub(crate) fn add(&mut self, hs: HandshakeMessagePayload<'_>) {
424 let start_len = self.body.len();
425 hs.encode(&mut self.body);
426 self.transcript
427 .add(&self.body[start_len..]);
428 }
429
430 pub(crate) fn finish(self, output: &mut dyn Output<'_>) {
431 let m = Message {
432 version: EncodableVersion::Legacy(match TLS13 {
433 true => ProtocolVersion::TLSv1_3,
434 false => ProtocolVersion::TLSv1_2,
435 }),
436 payload: MessagePayload::HandshakeFlight(Payload::new(self.body)),
437 };
438
439 output.send_msg(m, TLS13);
440 }
441}
442
443pub(crate) type HandshakeFlightTls12<'a> = HandshakeFlight<'a, false>;
444pub(crate) type HandshakeFlightTls13<'a> = HandshakeFlight<'a, true>;