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