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