1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::fmt;
4use core::ops::{Deref, DerefMut, Range};
5
6use pki_types::DnsName;
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}
28
29impl CommonState {
30 pub(crate) fn new(side: Side) -> Self {
31 Self {
32 outputs: ConnectionOutputs::default(),
33 send: SendPath::default(),
34 recv: ReceivePath::new(side),
35 }
36 }
37
38 pub fn wants_write(&self) -> bool {
42 !self.send.sendable_tls.is_empty()
43 }
44
45 pub fn send_close_notify(&mut self) {
53 self.send.send_close_notify()
54 }
55
56 pub fn is_handshaking(&self) -> bool {
64 !(self.send.may_send_application_data && self.recv.may_receive_application_data)
65 }
66}
67
68impl Deref for CommonState {
69 type Target = ConnectionOutputs;
70
71 fn deref(&self) -> &Self::Target {
72 &self.outputs
73 }
74}
75
76impl DerefMut for CommonState {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 &mut self.outputs
79 }
80}
81
82impl fmt::Debug for CommonState {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 f.debug_struct("CommonState")
85 .finish_non_exhaustive()
86 }
87}
88
89#[derive(Default)]
91pub struct ConnectionOutputs {
92 negotiated_version: Option<ProtocolVersion>,
93 handshake_kind: Option<HandshakeKind>,
94 suite: Option<SupportedCipherSuite>,
95 negotiated_kx_group: Option<&'static dyn SupportedKxGroup>,
96 alpn_protocol: Option<ApplicationProtocol<'static>>,
97 peer_identity: Option<Identity<'static>>,
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<&Identity<'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 handshake_kind(&self) -> Option<HandshakeKind> {
158 self.handshake_kind
159 }
160
161 pub(super) fn into_kernel_parts(self) -> Option<(ProtocolVersion, SupportedCipherSuite)> {
162 let Self {
163 negotiated_version,
164 suite,
165 ..
166 } = self;
167
168 match (negotiated_version, suite) {
169 (Some(version), Some(suite)) => Some((version, suite)),
170 _ => None,
171 }
172 }
173}
174
175impl ConnectionOutput for ConnectionOutputs {
176 fn handle(&mut self, ev: OutputEvent<'_>) {
177 match ev {
178 OutputEvent::ApplicationProtocol(protocol) => {
179 self.alpn_protocol = Some(ApplicationProtocol::from(protocol.as_ref()).to_owned())
180 }
181 OutputEvent::CipherSuite(suite) => self.suite = Some(suite),
182 OutputEvent::EarlyExporter(exporter) => self.early_exporter = Some(exporter),
183 OutputEvent::Exporter(exporter) => self.exporter = Some(exporter),
184 OutputEvent::HandshakeKind(hk) => {
185 assert!(self.handshake_kind.is_none());
186 self.handshake_kind = Some(hk);
187 }
188 OutputEvent::KeyExchangeGroup(kxg) => {
189 assert!(self.negotiated_kx_group.is_none());
190 self.negotiated_kx_group = Some(kxg);
191 }
192 OutputEvent::PeerIdentity(identity) => self.peer_identity = Some(identity),
193 OutputEvent::ProtocolVersion(ver) => {
194 self.negotiated_version = Some(ver);
195 }
196 }
197 }
198}
199
200pub(crate) fn maybe_send_fatal_alert(send: &mut dyn SendOutput, error: &Error) {
202 let Ok(alert) = AlertDescription::try_from(error) else {
203 return;
204 };
205 send.send_alert(AlertLevel::Fatal, alert);
206}
207
208#[derive(Debug, PartialEq, Clone, Copy)]
210#[non_exhaustive]
211pub enum HandshakeKind {
212 Full,
217
218 FullWithHelloRetryRequest,
224
225 Resumed,
231
232 ResumedWithHelloRetryRequest,
238}
239
240pub(crate) trait Output<'m> {
242 fn emit(&mut self, ev: Event<'_>);
243
244 fn output(&mut self, ev: OutputEvent<'_>);
245
246 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
247
248 fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
249 None
250 }
251
252 fn received_plaintext(&mut self, _payload: Payload<'m>) {}
253
254 fn start_traffic(&mut self);
255
256 fn receive(&mut self) -> &mut ReceivePath;
257
258 fn send(&mut self) -> &mut dyn SendOutput;
259}
260
261pub(crate) trait ConnectionOutput {
262 fn handle(&mut self, ev: OutputEvent<'_>);
263}
264
265pub(crate) enum Event<'a> {
267 EarlyApplicationData(Payload<'a>),
268 EarlyData(EarlyDataEvent),
269 EchStatus(EchStatus),
270 ReceivedServerName(Option<DnsName<'static>>),
271 ResumptionData(Vec<u8>),
272}
273
274pub(crate) enum OutputEvent<'a> {
275 ApplicationProtocol(ApplicationProtocol<'a>),
276 CipherSuite(SupportedCipherSuite),
277 EarlyExporter(Box<dyn Exporter>),
278 Exporter(Box<dyn Exporter>),
279 HandshakeKind(HandshakeKind),
280 KeyExchangeGroup(&'static dyn SupportedKxGroup),
281 PeerIdentity(Identity<'static>),
282 ProtocolVersion(ProtocolVersion),
283}
284
285pub(crate) enum EarlyDataEvent {
286 Accepted,
288 Enable(usize),
290 Start,
292 Finished,
294 Rejected,
296}
297
298pub(crate) enum UnborrowedPayload {
303 Unborrowed(Range<usize>),
304 Owned(Vec<u8>),
305}
306
307impl UnborrowedPayload {
308 pub(crate) fn unborrow(locator: &Locator, payload: Payload<'_>) -> Self {
317 match payload {
318 Payload::Borrowed(payload) => Self::Unborrowed(locator.locate(payload)),
319 Payload::Owned(payload) => Self::Owned(payload),
320 }
321 }
322
323 pub(crate) fn reborrow<'b>(self, delocator: &Delocator<'b>) -> Payload<'b> {
330 match self {
331 Self::Unborrowed(range) => Payload::Borrowed(delocator.slice_from_range(&range)),
332 Self::Owned(payload) => Payload::Owned(payload),
333 }
334 }
335}
336
337#[expect(clippy::exhaustive_enums)]
339#[derive(Clone, Copy, Debug, PartialEq)]
340pub enum Side {
341 Client,
343 Server,
345}
346
347#[derive(Copy, Clone, Eq, PartialEq, Debug)]
348pub(crate) enum Protocol {
349 Tcp,
351 Quic(quic::Version),
353}
354
355impl Protocol {
356 pub(crate) fn is_quic(&self) -> bool {
357 matches!(self, Self::Quic(_))
358 }
359}
360
361pub(crate) struct HandshakeFlight<'a, const TLS13: bool> {
362 pub(crate) transcript: &'a mut HandshakeHash,
363 body: Vec<u8>,
364}
365
366impl<'a, const TLS13: bool> HandshakeFlight<'a, TLS13> {
367 pub(crate) fn new(transcript: &'a mut HandshakeHash) -> Self {
368 Self {
369 transcript,
370 body: Vec::new(),
371 }
372 }
373
374 pub(crate) fn add(&mut self, hs: HandshakeMessagePayload<'_>) {
375 let start_len = self.body.len();
376 hs.encode(&mut self.body);
377 self.transcript
378 .add(&self.body[start_len..]);
379 }
380
381 pub(crate) fn finish(self, output: &mut dyn Output<'_>) {
382 let m = Message {
383 version: match TLS13 {
384 true => ProtocolVersion::TLSv1_3,
385 false => ProtocolVersion::TLSv1_2,
386 },
387 payload: MessagePayload::HandshakeFlight(Payload::new(self.body)),
388 };
389
390 output.send_msg(m, TLS13);
391 }
392}
393
394pub(crate) type HandshakeFlightTls12<'a> = HandshakeFlight<'a, false>;
395pub(crate) type HandshakeFlightTls13<'a> = HandshakeFlight<'a, true>;