Skip to main content

rustls/client/
connection.rs

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    /// Allows writing TLS1.3 0RTT/"early" data.
27    ///
28    /// This returns None in many circumstances when the capability to
29    /// send early data is not available, including but not limited to:
30    ///
31    /// - The server hasn't been talked to previously.
32    /// - The server does not support resumption.
33    /// - The server does not support early data.
34    /// - The resumption data for the server has expired.
35    ///
36    /// The server specifies a maximum amount of early data.  You can
37    /// learn this limit through the returned object, and writes through
38    /// it will process only this many bytes.
39    ///
40    /// The server can choose not to accept any sent early data --
41    /// in this case the data is lost but the connection continues.  You
42    /// can tell this happened using [`ClientSide::is_early_data_accepted()`].
43    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
49/// Builder for client [`Connection`] values.
50///
51/// Create one with [`ClientConfig::connect()`].
52pub 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    /// Specify the ALPN protocols to use for this connection.
60    pub fn with_alpn(mut self, alpn_protocols: Vec<ApplicationProtocol<'static>>) -> Self {
61        self.alpn_protocols = Some(alpn_protocols);
62        self
63    }
64
65    /// Finalize the builder and create the [`Connection`].
66    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    /// Finalize the builder and create a QUIC [`Connection`].
84    ///
85    /// This differs from `ClientConnectionBuilder::build()` in that it takes an extra `params`
86    /// argument, which contains the TLS-encoded transport parameters to send, and an extra
87    /// `version` argument, specifying the QUIC protocol version.
88    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        // In QUIC mode, handshake output is emitted via `QuicEvent`s, not `tls`.
130        debug_assert!(tls.is_empty());
131        Ok(conn)
132    }
133
134    /// Finalize the builder and create a [`quic::ClientHandshake`].
135    ///
136    /// `params` contains the TLS-encoded transport parameters to send, and `version`
137    /// specifies the QUIC protocol version.
138    ///
139    /// It is a fundamental fact of client TLS connections that the client writes first; the
140    /// resulting events are appended to `output`.  The client then always reads the server's
141    /// response, as represented by the [`quic::NeedsInput`] return value.
142    ///
143    /// You may wrap this in the [`quic::ClientHandshake::NeedsInput`] variant to generalise the
144    /// type to a [`quic::ClientHandshake`].
145    ///
146    /// The returned object should be fed data from a single server.
147    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    /// Finalize the builder and create a [`ClientHandshake`].
159    ///
160    /// It is a fundamental fact of client TLS connections that the client writes first; this data
161    /// is written to `tls`.  The client then always reads the server's response, as represented
162    /// by the [`NeedsInput`] return value.
163    ///
164    /// You may wrap this in the [`ClientHandshake::NeedsInput`] variant to generalise the type to a
165    /// [`ClientHandshake`].
166    ///
167    /// The returned object should be fed data from a single server.
168    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/// An in-progress TLS client handshake.
187///
188/// Make one of these using [`ClientConnectionBuilder::start_handshake()`].
189#[non_exhaustive]
190#[derive(Debug)]
191pub enum ClientHandshake {
192    /// More data needs to be received to make progress.
193    NeedsInput(NeedsInput<ClientSide>),
194
195    /// The server's presented identity must be verified.
196    ///
197    /// See [`VerifyPeerIdentity`] for how to proceed.
198    VerifyServerIdentity(VerifyPeerIdentity<ClientSide, Tcp>),
199
200    /// The handshake is complete.
201    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    /// Returns an object you can use to send TLS1.3 early data (a.k.a. "0-RTT data")
228    /// to the server.
229    ///
230    /// This returns None in many circumstances when the capability to
231    /// send early data is not available, including but not limited to:
232    ///
233    /// - The server hasn't been talked to previously.
234    /// - The server does not support resumption.
235    /// - The server does not support early data.
236    /// - The resumption data for the server has expired.
237    ///
238    /// The server specifies a maximum amount of early data.  You can
239    /// learn this limit through the returned object, and writes through
240    /// it will process only this many bytes.
241    ///
242    /// The server can choose not to accept any sent early data --
243    /// in this case the data is lost but the connection continues.  You
244    /// can tell this happened using [`ClientSide::is_early_data_accepted()`].
245    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
251/// Allows writing of early data in resumed TLS 1.3 connections.
252///
253/// "Early data" is also known as "0-RTT data".
254///
255/// Use [`Self::write()`] to encrypt early data into TLS records.
256pub 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    /// Encrypt early data as TLS records and encode them into `tls`.
274    ///
275    /// Yields the number of bytes of `plaintext` that were consumed.  This may be less than
276    /// the length of `plaintext` if the server has limited the amount of early data that
277    /// may be sent.
278    #[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    /// How many bytes you may send.  Writes will become short
300    /// once this reaches zero.
301    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/// TLS client-specific information determined during a connection.
341#[derive(Debug, Default)]
342pub struct ClientSide {
343    early_data: Option<EarlyData>,
344    ech_status: EchStatus,
345}
346
347impl ClientSide {
348    /// Returns True if the server signalled it will process early data.
349    ///
350    /// If you sent early data and this returns false at the end of the
351    /// handshake then the server will not process the data.  This
352    /// is not an error, but you may wish to resend the data.
353    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    /// Return the connection's Encrypted Client Hello (ECH) status.
364    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}