1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut};
3use core::{fmt, mem};
4use std::io;
5
6use pki_types::{FipsStatus, ServerName};
7
8use super::config::ClientConfig;
9use super::hs::ClientHelloInput;
10use crate::client::EchStatus;
11use crate::common_state::{
12 CommonState, ConnectionOutputs, EarlyDataEvent, Event, Output, Protocol, Side,
13};
14use crate::conn::unbuffered::EncryptError;
15use crate::conn::{
16 Connection, ConnectionCommon, ConnectionCore, IoState, KeyingMaterialExporter, Reader,
17 SideCommonOutput, Writer,
18};
19#[cfg(doc)]
20use crate::crypto;
21use crate::enums::ApplicationProtocol;
22use crate::error::Error;
23use crate::log::trace;
24use crate::msgs::ClientExtensionsInput;
25use crate::suites::ExtractedSecrets;
26use crate::sync::Arc;
27
28pub struct ClientConnection {
30 inner: ConnectionCommon<ClientSide>,
31}
32
33impl fmt::Debug for ClientConnection {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f.debug_struct("ClientConnection")
36 .finish_non_exhaustive()
37 }
38}
39
40impl ClientConnection {
41 pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
60 if self
61 .inner
62 .core
63 .side
64 .early_data
65 .is_enabled()
66 {
67 Some(WriteEarlyData::new(self))
68 } else {
69 None
70 }
71 }
72
73 pub fn is_early_data_accepted(&self) -> bool {
79 self.inner.core.is_early_data_accepted()
80 }
81
82 pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
85 self.inner.dangerous_extract_secrets()
86 }
87
88 pub fn ech_status(&self) -> EchStatus {
90 self.inner.core.side.ech_status
91 }
92
93 fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> {
94 self.inner
95 .core
96 .side
97 .early_data
98 .check_write(data.len())
99 .map(|sz| {
100 self.inner
101 .send
102 .send_early_plaintext(&data[..sz])
103 })
104 }
105
106 pub fn tls13_tickets_received(&self) -> u32 {
108 self.inner
109 .core
110 .common
111 .recv
112 .tls13_tickets_received
113 }
114}
115
116impl Connection for ClientConnection {
117 fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error> {
118 self.inner.read_tls(rd)
119 }
120
121 fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> {
122 self.inner.write_tls(wr)
123 }
124
125 fn wants_read(&self) -> bool {
126 self.inner.wants_read()
127 }
128
129 fn wants_write(&self) -> bool {
130 self.inner.wants_write()
131 }
132
133 fn reader(&mut self) -> Reader<'_> {
134 self.inner.reader()
135 }
136
137 fn writer(&mut self) -> Writer<'_> {
138 self.inner.writer()
139 }
140
141 fn process_new_packets(&mut self) -> Result<IoState, Error> {
142 self.inner.process_new_packets()
143 }
144
145 fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
146 self.inner.exporter()
147 }
148
149 fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
150 self.inner.dangerous_extract_secrets()
151 }
152
153 fn set_buffer_limit(&mut self, limit: Option<usize>) {
154 self.inner.set_buffer_limit(limit)
155 }
156
157 fn set_plaintext_buffer_limit(&mut self, limit: Option<usize>) {
158 self.inner
159 .set_plaintext_buffer_limit(limit)
160 }
161
162 fn refresh_traffic_keys(&mut self) -> Result<(), Error> {
163 self.inner.refresh_traffic_keys()
164 }
165
166 fn send_close_notify(&mut self) {
167 self.inner.send_close_notify();
168 }
169
170 fn is_handshaking(&self) -> bool {
171 self.inner.is_handshaking()
172 }
173
174 fn fips(&self) -> FipsStatus {
175 self.inner.fips
176 }
177}
178
179impl Deref for ClientConnection {
180 type Target = ConnectionOutputs;
181
182 fn deref(&self) -> &Self::Target {
183 &self.inner
184 }
185}
186
187impl DerefMut for ClientConnection {
188 fn deref_mut(&mut self) -> &mut Self::Target {
189 &mut self.inner
190 }
191}
192
193pub struct ClientConnectionBuilder {
197 pub(crate) config: Arc<ClientConfig>,
198 pub(crate) name: ServerName<'static>,
199 pub(crate) alpn_protocols: Option<Vec<ApplicationProtocol<'static>>>,
200}
201
202impl ClientConnectionBuilder {
203 pub fn with_alpn(mut self, alpn_protocols: Vec<ApplicationProtocol<'static>>) -> Self {
205 self.alpn_protocols = Some(alpn_protocols);
206 self
207 }
208
209 pub fn build(self) -> Result<ClientConnection, Error> {
211 let Self {
212 config,
213 name,
214 alpn_protocols,
215 } = self;
216
217 let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
218 let fips = config.fips();
219 Ok(ClientConnection {
220 inner: ConnectionCommon::new(
221 ConnectionCore::for_client(
222 config,
223 name,
224 ClientExtensionsInput::from_alpn(alpn_protocols),
225 Protocol::Tcp,
226 )?,
227 fips,
228 ),
229 })
230 }
231}
232
233pub struct WriteEarlyData<'a> {
239 sess: &'a mut ClientConnection,
240}
241
242impl<'a> WriteEarlyData<'a> {
243 fn new(sess: &'a mut ClientConnection) -> Self {
244 WriteEarlyData { sess }
245 }
246
247 pub fn bytes_left(&self) -> usize {
250 self.sess
251 .inner
252 .core
253 .side
254 .early_data
255 .bytes_left()
256 }
257
258 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
278 self.sess.inner.core.early_exporter()
279 }
280}
281
282impl io::Write for WriteEarlyData<'_> {
283 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
284 self.sess.write_early_data(buf)
285 }
286
287 fn flush(&mut self) -> io::Result<()> {
288 Ok(())
289 }
290}
291
292impl ConnectionCore<ClientSide> {
293 pub(crate) fn for_client(
294 config: Arc<ClientConfig>,
295 name: ServerName<'static>,
296 extra_exts: ClientExtensionsInput,
297 proto: Protocol,
298 ) -> Result<Self, Error> {
299 let mut common_state = CommonState::new(Side::Client, proto);
300 common_state
301 .send
302 .set_max_fragment_size(config.max_fragment_size)?;
303 let mut data = ClientConnectionData::new();
304
305 let mut output = SideCommonOutput {
306 side: &mut data,
307 common: &mut common_state,
308 };
309
310 let input = ClientHelloInput::new(name, &extra_exts, proto, &mut output, config)?;
311 let state = input.start_handshake(extra_exts, &mut output)?;
312
313 Ok(Self::new(state, data, common_state))
314 }
315
316 pub(crate) fn is_early_data_accepted(&self) -> bool {
317 self.side.early_data.is_accepted()
318 }
319}
320
321#[derive(Debug)]
322pub(super) struct EarlyData {
323 state: EarlyDataState,
324 left: usize,
325}
326
327impl EarlyData {
328 fn new() -> Self {
329 Self {
330 state: EarlyDataState::Disabled,
331 left: 0,
332 }
333 }
334
335 fn is_enabled(&self) -> bool {
336 matches!(
337 self.state,
338 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted
339 )
340 }
341
342 fn is_accepted(&self) -> bool {
343 matches!(
344 self.state,
345 EarlyDataState::Accepted | EarlyDataState::AcceptedFinished
346 )
347 }
348
349 fn enable(&mut self, max_data: usize) {
350 assert_eq!(self.state, EarlyDataState::Disabled);
351 self.state = EarlyDataState::Ready;
352 self.left = max_data;
353 }
354
355 fn start(&mut self) {
356 assert_eq!(self.state, EarlyDataState::Ready);
357 self.state = EarlyDataState::Sending;
358 }
359
360 fn rejected(&mut self) {
361 trace!("EarlyData rejected");
362 self.state = EarlyDataState::Rejected;
363 }
364
365 fn accepted(&mut self) {
366 trace!("EarlyData accepted");
367 assert_eq!(self.state, EarlyDataState::Sending);
368 self.state = EarlyDataState::Accepted;
369 }
370
371 pub(super) fn finished(&mut self) {
372 trace!("EarlyData finished");
373 self.state = match self.state {
374 EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
375 _ => panic!("bad EarlyData state"),
376 }
377 }
378
379 fn check_write(&mut self, sz: usize) -> io::Result<usize> {
380 self.check_write_opt(sz)
381 .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidInput))
382 }
383
384 fn check_write_opt(&mut self, sz: usize) -> Option<usize> {
385 match self.state {
386 EarlyDataState::Disabled => unreachable!(),
387 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
388 let take = if self.left < sz {
389 mem::replace(&mut self.left, 0)
390 } else {
391 self.left -= sz;
392 sz
393 };
394
395 Some(take)
396 }
397 EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => None,
398 }
399 }
400
401 fn bytes_left(&self) -> usize {
402 self.left
403 }
404}
405
406#[derive(Debug, PartialEq)]
407enum EarlyDataState {
408 Disabled,
409 Ready,
410 Sending,
411 Accepted,
412 AcceptedFinished,
413 Rejected,
414}
415
416#[non_exhaustive]
418#[derive(Debug)]
419pub enum EarlyDataError {
420 ExceededAllowedEarlyData,
422 Encrypt(EncryptError),
424}
425
426impl From<EncryptError> for EarlyDataError {
427 fn from(v: EncryptError) -> Self {
428 Self::Encrypt(v)
429 }
430}
431
432impl fmt::Display for EarlyDataError {
433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434 match self {
435 Self::ExceededAllowedEarlyData => f.write_str("cannot send any more early data"),
436 Self::Encrypt(e) => fmt::Display::fmt(e, f),
437 }
438 }
439}
440
441impl core::error::Error for EarlyDataError {}
442
443#[derive(Debug)]
444pub(crate) struct ClientConnectionData {
445 early_data: EarlyData,
446 ech_status: EchStatus,
447}
448
449impl ClientConnectionData {
450 fn new() -> Self {
451 Self {
452 early_data: EarlyData::new(),
453 ech_status: EchStatus::default(),
454 }
455 }
456}
457
458impl Output for ClientConnectionData {
459 fn emit(&mut self, ev: Event<'_>) {
460 match ev {
461 Event::EchStatus(ech) => self.ech_status = ech,
462 Event::EarlyData(EarlyDataEvent::Accepted) => self.early_data.accepted(),
463 Event::EarlyData(EarlyDataEvent::Enable(sz)) => self.early_data.enable(sz),
464 Event::EarlyData(EarlyDataEvent::Finished) => self.early_data.finished(),
465 Event::EarlyData(EarlyDataEvent::Start) => self.early_data.start(),
466 Event::EarlyData(EarlyDataEvent::Rejected) => self.early_data.rejected(),
467 _ => unreachable!(),
468 }
469 }
470}
471
472#[expect(clippy::exhaustive_structs)]
474#[derive(Debug)]
475pub struct ClientSide;
476
477impl crate::conn::SideData for ClientSide {}
478
479impl crate::conn::private::Side for ClientSide {
480 type Data = ClientConnectionData;
481 type State = super::hs::ClientState;
482}