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