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