1use alloc::vec::Vec;
2use core::ops::Deref;
3use core::{fmt, mem};
4
5use pki_types::{FipsStatus, ServerName};
6
7use super::config::ClientConfig;
8use super::hs::{ClientHelloInput, ClientState};
9use crate::client::EchStatus;
10use crate::common_state::{CommonState, ConnectionOutputs, EarlyDataEvent, Event, Protocol, Side};
11use crate::conn::private::SideOutput;
12use crate::conn::split::SplitConnection;
13use crate::conn::{
14 Connection, ConnectionCommon, KeyingMaterialExporter, MessageHandler, SideCommonOutput,
15 SideData, StateMachine, VerifyPeerIdentity,
16};
17#[cfg(doc)]
18use crate::crypto;
19use crate::crypto::cipher::{OutboundPlain, Payload};
20use crate::enums::ApplicationProtocol;
21use crate::error::{ApiMisuse, Error};
22use crate::msgs::{ClientExtensionsInput, TransportParameters};
23use crate::quic::{self, ClientConnection as QuicClientConnection, Quic, QuicCommon, QuicOutput};
24use crate::suites::ExtractedSecrets;
25use crate::sync::Arc;
26use crate::tracing::trace;
27use crate::verify::ServerIdentity;
28use crate::{NeedsInput, TlsInputBuffer};
29
30pub struct ClientConnection {
35 inner: ConnectionCommon<ClientSide>,
36}
37
38impl fmt::Debug for ClientConnection {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 f.debug_struct("ClientConnection")
41 .finish_non_exhaustive()
42 }
43}
44
45impl ClientConnection {
46 pub fn split(self) -> Result<SplitConnection<ClientSide>, Error> {
61 self.inner.split()
62 }
63
64 pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
82 let ConnectionCommon { side, common, .. } = &mut self.inner;
83 let early_data = side.early_data.as_mut()?;
84 match early_data.state {
85 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
86 Some(WriteEarlyData { early_data, common })
87 }
88 _ => None,
89 }
90 }
91
92 pub fn is_early_data_accepted(&self) -> bool {
98 self.inner.is_early_data_accepted()
99 }
100
101 pub fn ech_status(&self) -> EchStatus {
103 self.inner.side.ech_status
104 }
105
106 pub fn tls13_tickets_received(&self) -> u32 {
108 self.inner
109 .common
110 .recv
111 .tls13_tickets_received
112 }
113}
114
115impl Connection for ClientConnection {
116 type Side = ClientSide;
117
118 fn write(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> Result<(), Error> {
119 self.inner.write(plaintext, tls)
120 }
121
122 fn wants_read(&self) -> bool {
123 self.inner.wants_read()
124 }
125
126 fn read_tls<'a, 'm>(
127 &'a mut self,
128 input: &'m mut dyn TlsInputBuffer,
129 tls: &'a mut Vec<u8>,
130 ) -> MessageHandler<'a, 'm, ClientSide> {
131 self.inner.read_tls(input, tls)
132 }
133
134 fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
135 self.inner.exporter()
136 }
137
138 fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
139 self.inner.dangerous_extract_secrets()
140 }
141
142 fn refresh_traffic_keys(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
143 self.inner.refresh_traffic_keys(tls)
144 }
145
146 fn send_close_notify(&mut self, tls: &mut Vec<u8>) {
147 self.inner.send_close_notify(tls);
148 }
149
150 fn is_handshaking(&self) -> bool {
151 self.inner.is_handshaking()
152 }
153
154 fn fips(&self) -> FipsStatus {
155 self.inner.fips
156 }
157}
158
159impl Deref for ClientConnection {
160 type Target = ConnectionOutputs;
161
162 fn deref(&self) -> &Self::Target {
163 &self.inner
164 }
165}
166
167pub struct ClientConnectionBuilder {
171 pub(crate) config: Arc<ClientConfig>,
172 pub(crate) name: ServerName<'static>,
173 pub(crate) alpn_protocols: Option<Vec<ApplicationProtocol<'static>>>,
174}
175
176impl ClientConnectionBuilder {
177 pub fn with_alpn(mut self, alpn_protocols: Vec<ApplicationProtocol<'static>>) -> Self {
179 self.alpn_protocols = Some(alpn_protocols);
180 self
181 }
182
183 pub fn build(self, tls: &mut Vec<u8>) -> Result<ClientConnection, Error> {
185 let Self {
186 config,
187 name,
188 alpn_protocols,
189 } = self;
190
191 let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
192 Ok(ClientConnection {
193 inner: ConnectionCommon::for_client(
194 config,
195 name,
196 ClientExtensionsInput::from_alpn(alpn_protocols),
197 None,
198 Protocol::Tcp,
199 tls,
200 )?,
201 })
202 }
203
204 pub fn build_quic(
210 self,
211 version: quic::Version,
212 params: Vec<u8>,
213 ) -> Result<QuicClientConnection, Error> {
214 let suites = &self
215 .config
216 .provider()
217 .tls13_cipher_suites;
218 if suites.is_empty() {
219 return Err(ApiMisuse::QuicRequiresTls13Support.into());
220 }
221
222 if !suites
223 .iter()
224 .any(|scs| scs.quic.is_some())
225 {
226 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
227 }
228
229 let exts = ClientExtensionsInput {
230 transport_parameters: Some(match version {
231 quic::Version::V1 | quic::Version::V2 => {
232 TransportParameters::Quic(Payload::new(params))
233 }
234 }),
235
236 ..ClientExtensionsInput::from_alpn(
237 self.alpn_protocols
238 .unwrap_or_else(|| self.config.alpn_protocols.clone()),
239 )
240 };
241
242 let mut quic = Quic {
243 version,
244 ..Quic::default()
245 };
246
247 let mut tls = Vec::new();
248 let inner = ConnectionCommon::for_client(
249 self.config,
250 self.name,
251 exts,
252 Some(&mut quic),
253 Protocol::Quic(version),
254 &mut tls,
255 )?;
256
257 debug_assert!(tls.is_empty());
259 Ok(QuicClientConnection::from(QuicCommon::new(inner, quic)))
260 }
261
262 pub fn start_handshake(self, tls: &mut Vec<u8>) -> Result<NeedsInput<ClientSide>, Error> {
273 let Self {
274 config,
275 name,
276 alpn_protocols,
277 } = self;
278
279 let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
280 Ok(NeedsInput {
281 inner: ConnectionCommon::for_client(
282 config,
283 name,
284 ClientExtensionsInput::from_alpn(alpn_protocols),
285 None,
286 Protocol::Tcp,
287 tls,
288 )?,
289 })
290 }
291}
292
293#[non_exhaustive]
297#[derive(Debug)]
298pub enum ClientHandshake {
299 NeedsInput(NeedsInput<ClientSide>),
301
302 VerifyServerIdentity(VerifyPeerIdentity<ClientSide>),
306
307 Complete(SplitConnection<ClientSide>),
311}
312
313impl TryFrom<ConnectionCommon<ClientSide>> for ClientHandshake {
314 type Error = Error;
315
316 fn try_from(mut inner: ConnectionCommon<ClientSide>) -> Result<Self, Error> {
317 const MISUSED: Error = Error::Unreachable("forgot to restore state");
318
319 Ok(match mem::replace(&mut inner.state, Err(MISUSED))? {
320 ClientState::VerifyServerIdentity(verify_identity) => {
321 Self::VerifyServerIdentity(VerifyPeerIdentity {
322 inner,
323 verify_identity,
324 })
325 }
326
327 state if state.is_traffic() => {
328 inner.state = Ok(state);
329 Self::Complete(SplitConnection::try_from(inner)?)
330 }
331
332 state => {
333 inner.state = Ok(state);
334 Self::NeedsInput(NeedsInput { inner })
335 }
336 })
337 }
338}
339
340pub struct WriteEarlyData<'a> {
346 early_data: &'a mut EarlyData,
347 common: &'a mut CommonState,
348}
349
350impl<'a> WriteEarlyData<'a> {
351 #[must_use]
357 pub fn write(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> usize {
358 let state = &mut self.early_data;
359 let plaintext = match state.state {
360 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
361 let take = Ord::min(plaintext.len(), state.left);
362 state.left -= take;
363 plaintext.split_at(take).0
364 }
365 EarlyDataState::AcceptedFinished => return 0,
366 };
367
368 self.common
369 .send
370 .send_appdata_encrypt(plaintext, tls)
371 }
372
373 pub fn bytes_left(&self) -> usize {
376 self.early_data.left
377 }
378
379 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
399 self.common.early_exporter()
400 }
401}
402
403impl ConnectionCommon<ClientSide> {
404 pub(crate) fn for_client(
405 config: Arc<ClientConfig>,
406 name: ServerName<'static>,
407 extra_exts: ClientExtensionsInput,
408 quic: Option<&mut dyn QuicOutput>,
409 protocol: Protocol,
410 tls: &mut Vec<u8>,
411 ) -> Result<Self, Error> {
412 let mut common_state = CommonState::new(Side::Client, config.fips());
413 common_state
414 .send
415 .set_max_fragment_size(config.max_fragment_size)?;
416 let mut data = ClientConnectionData::default();
417
418 let mut output = SideCommonOutput {
419 side: &mut data,
420 quic,
421 common: &mut common_state,
422 tls,
423 };
424
425 let input = ClientHelloInput::new(name, &extra_exts, protocol, &mut output, config)?;
426 let state = input.start_handshake(extra_exts, &mut output)?;
427
428 Ok(Self::new(state, data, common_state))
429 }
430
431 pub(crate) fn is_early_data_accepted(&self) -> bool {
432 matches!(
433 &self.side.early_data,
434 Some(EarlyData {
435 state: EarlyDataState::Accepted | EarlyDataState::AcceptedFinished,
436 ..
437 })
438 )
439 }
440}
441
442#[expect(clippy::exhaustive_structs)]
444#[derive(Debug)]
445pub struct ClientSide;
446
447impl SideData for ClientSide {
448 type Handshake = ClientHandshake;
449 type PeerIdentity<'a> = ServerIdentity<'static, 'a>;
450
451 #[expect(private_interfaces)]
452 fn handshake_from_inner(common: ConnectionCommon<Self>) -> Result<Self::Handshake, Error> {
453 ClientHandshake::try_from(common)
454 }
455}
456
457impl crate::conn::private::Side for ClientSide {
458 type Data = ClientConnectionData;
459 type State = ClientState;
460}
461
462impl SideOutput for ClientConnectionData {
463 fn emit(&mut self, ev: Event) {
464 match ev {
465 Event::EchStatus(ech) => self.ech_status = ech,
466 Event::EarlyData(event) => match (event, &mut self.early_data) {
467 (EarlyDataEvent::Enable(sz), None) => self.early_data = Some(EarlyData::new(sz)),
468 (EarlyDataEvent::Start, Some(early_data)) => {
469 assert_eq!(early_data.state, EarlyDataState::Ready);
470 early_data.state = EarlyDataState::Sending;
471 }
472 (EarlyDataEvent::Accepted, Some(early_data)) => {
473 trace!("EarlyData accepted");
474 assert_eq!(early_data.state, EarlyDataState::Sending);
475 early_data.state = EarlyDataState::Accepted;
476 }
477 (EarlyDataEvent::Rejected, _) => self.early_data = None,
478 (EarlyDataEvent::Finished, Some(early_data)) => {
479 trace!("EarlyData finished");
480 early_data.state = match early_data.state {
481 EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
482 _ => panic!("bad EarlyData state"),
483 }
484 }
485 _ => unreachable!(),
486 },
487 _ => unreachable!(),
488 }
489 }
490}
491
492#[derive(Default)]
493pub(crate) struct ClientConnectionData {
494 early_data: Option<EarlyData>,
495 ech_status: EchStatus,
496}
497
498pub(super) struct EarlyData {
499 state: EarlyDataState,
500 left: usize,
501}
502
503impl EarlyData {
504 fn new(left: usize) -> Self {
505 Self {
506 state: EarlyDataState::Ready,
507 left,
508 }
509 }
510}
511
512#[derive(Debug, PartialEq)]
513enum EarlyDataState {
514 Ready,
515 Sending,
516 Accepted,
517 AcceptedFinished,
518}