1use alloc::vec::Vec;
2use core::fmt;
3use core::ops::Deref;
4
5use pki_types::{FipsStatus, ServerName};
6
7use super::config::ClientConfig;
8use super::hs::ClientHelloInput;
9use crate::TlsInputBuffer;
10use crate::client::EchStatus;
11use crate::common_state::{CommonState, ConnectionOutputs, EarlyDataEvent, Event, Protocol, Side};
12use crate::conn::private::SideOutput;
13use crate::conn::split::SplitConnection;
14use crate::conn::{
15 Connection, ConnectionCommon, KeyingMaterialExporter, MessageHandler, SideCommonOutput,
16 SideData,
17};
18#[cfg(doc)]
19use crate::crypto;
20use crate::crypto::cipher::OutboundPlain;
21use crate::enums::ApplicationProtocol;
22use crate::error::Error;
23use crate::msgs::ClientExtensionsInput;
24use crate::quic::QuicOutput;
25use crate::suites::ExtractedSecrets;
26use crate::sync::Arc;
27use crate::tracing::trace;
28
29pub struct ClientConnection {
31 inner: ConnectionCommon<ClientSide>,
32}
33
34impl fmt::Debug for ClientConnection {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 f.debug_struct("ClientConnection")
37 .finish_non_exhaustive()
38 }
39}
40
41impl ClientConnection {
42 pub fn split(self) -> Result<SplitConnection<ClientSide>, Error> {
57 self.inner.split()
58 }
59
60 pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
79 let ConnectionCommon { side, common, .. } = &mut self.inner;
80 let early_data = side.early_data.as_mut()?;
81 match early_data.state {
82 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
83 Some(WriteEarlyData { early_data, common })
84 }
85 _ => None,
86 }
87 }
88
89 pub fn is_early_data_accepted(&self) -> bool {
95 self.inner.is_early_data_accepted()
96 }
97
98 pub fn ech_status(&self) -> EchStatus {
100 self.inner.side.ech_status
101 }
102
103 pub fn tls13_tickets_received(&self) -> u32 {
105 self.inner
106 .common
107 .recv
108 .tls13_tickets_received
109 }
110}
111
112impl Connection for ClientConnection {
113 type Side = ClientSide;
114
115 fn write_tls(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> Result<(), Error> {
116 self.inner.write_tls(plaintext, tls)
117 }
118
119 fn wants_read(&self) -> bool {
120 self.inner.wants_read()
121 }
122
123 fn process_new_packets<'a, 'm>(
124 &'a mut self,
125 input: &'m mut dyn TlsInputBuffer,
126 tls: &'a mut Vec<u8>,
127 ) -> MessageHandler<'a, 'm, ClientSide> {
128 self.inner
129 .process_new_packets(input, tls)
130 }
131
132 fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
133 self.inner.exporter()
134 }
135
136 fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
137 self.inner.dangerous_extract_secrets()
138 }
139
140 fn refresh_traffic_keys(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
141 self.inner.refresh_traffic_keys(tls)
142 }
143
144 fn send_close_notify(&mut self, tls: &mut Vec<u8>) {
145 self.inner.send_close_notify(tls);
146 }
147
148 fn is_handshaking(&self) -> bool {
149 self.inner.is_handshaking()
150 }
151
152 fn fips(&self) -> FipsStatus {
153 self.inner.fips
154 }
155}
156
157impl Deref for ClientConnection {
158 type Target = ConnectionOutputs;
159
160 fn deref(&self) -> &Self::Target {
161 &self.inner
162 }
163}
164
165pub struct ClientConnectionBuilder {
169 pub(crate) config: Arc<ClientConfig>,
170 pub(crate) name: ServerName<'static>,
171 pub(crate) alpn_protocols: Option<Vec<ApplicationProtocol<'static>>>,
172}
173
174impl ClientConnectionBuilder {
175 pub fn with_alpn(mut self, alpn_protocols: Vec<ApplicationProtocol<'static>>) -> Self {
177 self.alpn_protocols = Some(alpn_protocols);
178 self
179 }
180
181 pub fn build(self, tls: &mut Vec<u8>) -> Result<ClientConnection, Error> {
183 let Self {
184 config,
185 name,
186 alpn_protocols,
187 } = self;
188
189 let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
190 Ok(ClientConnection {
191 inner: ConnectionCommon::for_client(
192 config,
193 name,
194 ClientExtensionsInput::from_alpn(alpn_protocols),
195 None,
196 Protocol::Tcp,
197 tls,
198 )?,
199 })
200 }
201}
202
203pub struct WriteEarlyData<'a> {
209 early_data: &'a mut EarlyData,
210 common: &'a mut CommonState,
211}
212
213impl<'a> WriteEarlyData<'a> {
214 pub fn write_tls(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> usize {
220 let state = &mut self.early_data;
221 let plaintext = match state.state {
222 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
223 let take = Ord::min(plaintext.len(), state.left);
224 state.left -= take;
225 plaintext.split_at(take).0
226 }
227 EarlyDataState::AcceptedFinished => return 0,
228 };
229
230 self.common
231 .send
232 .send_appdata_encrypt(plaintext, tls)
233 }
234
235 pub fn bytes_left(&self) -> usize {
238 self.early_data.left
239 }
240
241 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
261 self.common.early_exporter()
262 }
263}
264
265impl ConnectionCommon<ClientSide> {
266 pub(crate) fn for_client(
267 config: Arc<ClientConfig>,
268 name: ServerName<'static>,
269 extra_exts: ClientExtensionsInput,
270 quic: Option<&mut dyn QuicOutput>,
271 protocol: Protocol,
272 tls: &mut Vec<u8>,
273 ) -> Result<Self, Error> {
274 let mut common_state = CommonState::new(Side::Client, config.fips());
275 common_state
276 .send
277 .set_max_fragment_size(config.max_fragment_size)?;
278 let mut data = ClientConnectionData::default();
279
280 let mut output = SideCommonOutput {
281 side: &mut data,
282 quic,
283 common: &mut common_state,
284 tls,
285 };
286
287 let input = ClientHelloInput::new(name, &extra_exts, protocol, &mut output, config)?;
288 let state = input.start_handshake(extra_exts, &mut output)?;
289
290 Ok(Self::new(state, data, common_state))
291 }
292
293 pub(crate) fn is_early_data_accepted(&self) -> bool {
294 matches!(
295 &self.side.early_data,
296 Some(EarlyData {
297 state: EarlyDataState::Accepted | EarlyDataState::AcceptedFinished,
298 ..
299 })
300 )
301 }
302}
303
304#[expect(clippy::exhaustive_structs)]
306#[derive(Debug)]
307pub struct ClientSide;
308
309impl SideData for ClientSide {}
310
311impl crate::conn::private::Side for ClientSide {
312 type Data = ClientConnectionData;
313 type State = super::hs::ClientState;
314}
315
316impl SideOutput for ClientConnectionData {
317 fn emit(&mut self, ev: Event<'_>) {
318 match ev {
319 Event::EchStatus(ech) => self.ech_status = ech,
320 Event::EarlyData(event) => match (event, &mut self.early_data) {
321 (EarlyDataEvent::Enable(sz), None) => self.early_data = Some(EarlyData::new(sz)),
322 (EarlyDataEvent::Start, Some(early_data)) => {
323 assert_eq!(early_data.state, EarlyDataState::Ready);
324 early_data.state = EarlyDataState::Sending;
325 }
326 (EarlyDataEvent::Accepted, Some(early_data)) => {
327 trace!("EarlyData accepted");
328 assert_eq!(early_data.state, EarlyDataState::Sending);
329 early_data.state = EarlyDataState::Accepted;
330 }
331 (EarlyDataEvent::Rejected, _) => self.early_data = None,
332 (EarlyDataEvent::Finished, Some(early_data)) => {
333 trace!("EarlyData finished");
334 early_data.state = match early_data.state {
335 EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
336 _ => panic!("bad EarlyData state"),
337 }
338 }
339 _ => unreachable!(),
340 },
341 _ => unreachable!(),
342 }
343 }
344}
345
346#[derive(Default)]
347pub(crate) struct ClientConnectionData {
348 early_data: Option<EarlyData>,
349 ech_status: EchStatus,
350}
351
352pub(super) struct EarlyData {
353 state: EarlyDataState,
354 left: usize,
355}
356
357impl EarlyData {
358 fn new(left: usize) -> Self {
359 Self {
360 state: EarlyDataState::Ready,
361 left,
362 }
363 }
364}
365
366#[derive(Debug, PartialEq)]
367enum EarlyDataState {
368 Ready,
369 Sending,
370 Accepted,
371 AcceptedFinished,
372}