1use alloc::vec::Vec;
2
3use pki_types::ServerName;
4
5use super::config::ClientConfig;
6use super::hs::{ClientHelloInput, ClientState};
7use crate::client::EchStatus;
8use crate::common_state::{CommonState, EarlyDataEvent, Event, Side};
9use crate::conn::private::SideOutput;
10use crate::conn::split::SplitConnection;
11use crate::conn::{
12 ClientNext, Connection, DataKind, NeedsInput, SideCommonOutput, SideData, Tcp, Transport,
13 VerifyPeerIdentity,
14};
15#[cfg(doc)]
16use crate::crypto;
17use crate::crypto::cipher::{OutboundPlain, Payload};
18use crate::enums::ApplicationProtocol;
19use crate::error::{ApiMisuse, Error};
20use crate::msgs::{ClientExtensionsInput, TransportParameters};
21use crate::quic::{self, Quic};
22use crate::sync::Arc;
23use crate::tracing::trace;
24use crate::verify::ServerIdentity;
25
26impl Connection<ClientSide, Tcp> {
27 pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
45 let Self { side, common, .. } = self;
46 WriteEarlyData::new(&mut side.early_data, common)
47 }
48}
49
50pub struct ClientConnectionBuilder {
54 pub(crate) config: Arc<ClientConfig>,
55 pub(crate) name: ServerName<'static>,
56 pub(crate) alpn_protocols: Option<Vec<ApplicationProtocol<'static>>>,
57}
58
59impl ClientConnectionBuilder {
60 pub fn with_alpn(mut self, alpn_protocols: Vec<ApplicationProtocol<'static>>) -> Self {
62 self.alpn_protocols = Some(alpn_protocols);
63 self
64 }
65
66 pub fn build(self, tls: &mut Vec<u8>) -> Result<Connection<ClientSide, Tcp>, Error> {
68 let Self {
69 config,
70 name,
71 alpn_protocols,
72 } = self;
73
74 let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
75 Connection::for_client(
76 config,
77 name,
78 ClientExtensionsInput::from_alpn(alpn_protocols),
79 Tcp,
80 tls,
81 )
82 }
83
84 pub fn build_quic(
90 self,
91 version: quic::Version,
92 params: Vec<u8>,
93 ) -> Result<Connection<ClientSide, Quic>, Error> {
94 let suites = &self
95 .config
96 .provider()
97 .tls13_cipher_suites;
98 if suites.is_empty() {
99 return Err(ApiMisuse::QuicRequiresTls13Support.into());
100 }
101
102 if !suites
103 .iter()
104 .any(|scs| scs.quic.is_some())
105 {
106 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
107 }
108
109 let exts = ClientExtensionsInput {
110 transport_parameters: Some(match version {
111 quic::Version::V1 | quic::Version::V2 => {
112 TransportParameters::Quic(Payload::new(params))
113 }
114 }),
115
116 ..ClientExtensionsInput::from_alpn(
117 self.alpn_protocols
118 .unwrap_or_else(|| self.config.alpn_protocols.clone()),
119 )
120 };
121
122 let quic = Quic {
123 version,
124 ..Quic::default()
125 };
126
127 let mut tls = Vec::new();
128 let conn = Connection::for_client(self.config, self.name, exts, quic, &mut tls)?;
129
130 debug_assert!(tls.is_empty());
132 Ok(conn)
133 }
134
135 pub fn start_quic_handshake(
149 self,
150 version: quic::Version,
151 params: Vec<u8>,
152 output: &mut Vec<quic::QuicEvent>,
153 ) -> Result<quic::NeedsInput<ClientSide>, Error> {
154 let mut conn = self.build_quic(version, params)?;
155 output.extend(conn.events());
156 Ok(quic::NeedsInput(conn))
157 }
158
159 pub fn start_handshake(self, tls: &mut Vec<u8>) -> Result<NeedsInput<ClientSide>, Error> {
170 let Self {
171 config,
172 name,
173 alpn_protocols,
174 } = self;
175
176 let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
177 Ok(NeedsInput::new(Connection::for_client(
178 config,
179 name,
180 ClientExtensionsInput::from_alpn(alpn_protocols),
181 Tcp,
182 tls,
183 )?))
184 }
185}
186
187#[non_exhaustive]
191#[derive(Debug)]
192pub enum ClientHandshake {
193 NeedsInput(NeedsInput<ClientSide>),
195
196 VerifyServerIdentity(VerifyPeerIdentity<ClientSide, Tcp>),
200
201 Complete(SplitConnection<ClientSide>),
205}
206
207impl TryFrom<Connection<ClientSide, Tcp>> for ClientHandshake {
208 type Error = Error;
209
210 fn try_from(conn: Connection<ClientSide, Tcp>) -> Result<Self, Error> {
211 Ok(match ClientNext::try_from(conn)? {
212 ClientNext::NeedsInput(conn) => Self::NeedsInput(NeedsInput(conn)),
213
214 ClientNext::VerifyServerIdentity(verify) => Self::VerifyServerIdentity(verify),
215
216 ClientNext::Complete(conn) => Self::Complete(SplitConnection::try_from(conn)?),
217 })
218 }
219}
220
221impl NeedsInput<ClientSide> {
222 pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
241 let Connection { side, common, .. } = &mut self.0;
242 WriteEarlyData::new(&mut side.early_data, common)
243 }
244}
245
246pub struct WriteEarlyData<'a> {
252 early_data: &'a mut EarlyData,
253 common: &'a mut CommonState,
254}
255
256impl<'a> WriteEarlyData<'a> {
257 fn new(early_data: &'a mut Option<EarlyData>, common: &'a mut CommonState) -> Option<Self> {
258 let early_data = early_data.as_mut()?;
259
260 match early_data.state {
261 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
262 Some(WriteEarlyData { early_data, common })
263 }
264 _ => None,
265 }
266 }
267
268 #[must_use]
274 pub fn write(
275 &mut self,
276 plaintext: OutboundPlain<'_>,
277 tls: &mut Vec<u8>,
278 ) -> Result<usize, Error> {
279 let state = &mut self.early_data;
280 let plaintext = match state.state {
281 EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
282 let take = Ord::min(plaintext.len(), state.left);
283 state.left -= take;
284 plaintext.split_at(take).0
285 }
286 EarlyDataState::AcceptedFinished => return Ok(0),
287 };
288
289 self.common
290 .send
291 .send_appdata_encrypt(DataKind::Early(plaintext), tls)
292 }
293
294 pub fn bytes_left(&self) -> usize {
297 self.early_data.left
298 }
299}
300
301impl<T: Transport> Connection<ClientSide, T> {
302 pub(crate) fn for_client(
303 config: Arc<ClientConfig>,
304 name: ServerName<'static>,
305 extra_exts: ClientExtensionsInput,
306 mut transport: T,
307 tls: &mut Vec<u8>,
308 ) -> Result<Self, Error> {
309 let mut common = CommonState::new(Side::Client, config.fips());
310 common
311 .send
312 .set_max_fragment_size(config.max_fragment_size)?;
313 let mut side = ClientSide::default();
314
315 let protocol = transport.protocol();
316 let mut output = SideCommonOutput {
317 side: &mut side,
318 quic: transport.quic(),
319 common: &mut common,
320 tls,
321 };
322
323 let input = ClientHelloInput::new(name, &extra_exts, protocol, &mut output, config)?;
324 let state = input.start_handshake(extra_exts, &mut output)?;
325
326 Ok(Self {
327 state: Ok(state),
328 side,
329 common,
330 transport,
331 })
332 }
333}
334
335#[derive(Debug, Default)]
337pub struct ClientSide {
338 early_data: Option<EarlyData>,
339 ech_status: EchStatus,
340}
341
342impl ClientSide {
343 pub fn is_early_data_accepted(&self) -> bool {
349 matches!(
350 &self.early_data,
351 Some(EarlyData {
352 state: EarlyDataState::Accepted | EarlyDataState::AcceptedFinished,
353 ..
354 })
355 )
356 }
357
358 pub fn ech_status(&self) -> EchStatus {
360 self.ech_status
361 }
362}
363
364impl SideData for ClientSide {
365 type Handshake = ClientHandshake;
366 type QuicHandshake = quic::ClientHandshake;
367
368 type PeerIdentity<'a> = ServerIdentity<'static, 'a>;
369}
370
371impl SideOutput for ClientSide {
372 fn emit(&mut self, ev: Event) {
373 match ev {
374 Event::EchStatus(ech) => self.ech_status = ech,
375 Event::EarlyData(event) => match (event, &mut self.early_data) {
376 (EarlyDataEvent::Enable(sz), None) => self.early_data = Some(EarlyData::new(sz)),
377 (EarlyDataEvent::Start, Some(early_data)) => {
378 assert_eq!(early_data.state, EarlyDataState::Ready);
379 early_data.state = EarlyDataState::Sending;
380 }
381 (EarlyDataEvent::Accepted, Some(early_data)) => {
382 trace!("EarlyData accepted");
383 assert_eq!(early_data.state, EarlyDataState::Sending);
384 early_data.state = EarlyDataState::Accepted;
385 }
386 (EarlyDataEvent::Rejected, _) => self.early_data = None,
387 (EarlyDataEvent::Finished, Some(early_data)) => {
388 trace!("EarlyData finished");
389 early_data.state = match early_data.state {
390 EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
391 _ => panic!("bad EarlyData state"),
392 }
393 }
394 _ => unreachable!(),
395 },
396 _ => unreachable!(),
397 }
398 }
399}
400
401impl crate::conn::private::Side for ClientSide {
402 type State = ClientState;
403}
404
405#[derive(Debug)]
406pub(super) struct EarlyData {
407 state: EarlyDataState,
408 left: usize,
409}
410
411impl EarlyData {
412 fn new(left: usize) -> Self {
413 Self {
414 state: EarlyDataState::Ready,
415 left,
416 }
417 }
418}
419
420#[derive(Debug, PartialEq)]
421enum EarlyDataState {
422 Ready,
423 Sending,
424 Accepted,
425 AcceptedFinished,
426}