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