Skip to main content

rustls/client/
connection.rs

1use alloc::vec::Vec;
2use core::ops::Deref;
3use core::{fmt, mem};
4
5use pki_types::{FipsStatus, ServerName};
6
7use super::config::ClientConfig;
8use super::hs::{ClientHelloInput, ClientState};
9use crate::client::EchStatus;
10use crate::common_state::{CommonState, ConnectionOutputs, EarlyDataEvent, Event, Protocol, Side};
11use crate::conn::private::SideOutput;
12use crate::conn::split::SplitConnection;
13use crate::conn::{
14    Connection, ConnectionCommon, KeyingMaterialExporter, MessageHandler, SideCommonOutput,
15    SideData, StateMachine, VerifyPeerIdentity,
16};
17#[cfg(doc)]
18use crate::crypto;
19use crate::crypto::cipher::{OutboundPlain, Payload};
20use crate::enums::ApplicationProtocol;
21use crate::error::{ApiMisuse, Error};
22use crate::msgs::{ClientExtensionsInput, TransportParameters};
23use crate::quic::{self, ClientConnection as QuicClientConnection, Quic, QuicCommon, QuicOutput};
24use crate::suites::ExtractedSecrets;
25use crate::sync::Arc;
26use crate::tracing::trace;
27use crate::verify::ServerIdentity;
28use crate::{NeedsInput, TlsInputBuffer};
29
30/// This represents a single TLS client connection.
31///
32/// Encrypt data destined for the peer using [`Connection::write()`].
33/// Process received data from the peer using [`Connection::read_tls()`].
34pub struct ClientConnection {
35    inner: ConnectionCommon<ClientSide>,
36}
37
38impl fmt::Debug for ClientConnection {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_struct("ClientConnection")
41            .finish_non_exhaustive()
42    }
43}
44
45impl ClientConnection {
46    /// Split a post-handshake connection into a [`SplitConnection`].
47    ///
48    /// This allows the two directions (transmit and receive) of the connection to be progressed
49    /// separately (including by different threads, which would allow dedicating a CPU core for each
50    /// direction rather than one per connection; this can dramatically improve performance for
51    /// full-duplex protocols).
52    ///
53    /// It also separates out the [`ConnectionOutputs`] which gives the application direct control
54    /// of how long this is kept.
55    ///
56    /// This fails if:
57    ///
58    /// - the handshake is not complete. Check with [`Connection::is_handshaking()`].
59    /// - there is any buffered TLS data to send.  Obtain it first with [`Connection::write()`].
60    pub fn split(self) -> Result<SplitConnection<ClientSide>, Error> {
61        self.inner.split()
62    }
63
64    /// Allows writing TLS1.3 0RTT/"early" data.
65    ///
66    /// This returns None in many circumstances when the capability to
67    /// send early data is not available, including but not limited to:
68    ///
69    /// - The server hasn't been talked to previously.
70    /// - The server does not support resumption.
71    /// - The server does not support early data.
72    /// - The resumption data for the server has expired.
73    ///
74    /// The server specifies a maximum amount of early data.  You can
75    /// learn this limit through the returned object, and writes through
76    /// it will process only this many bytes.
77    ///
78    /// The server can choose not to accept any sent early data --
79    /// in this case the data is lost but the connection continues.  You
80    /// can tell this happened using `is_early_data_accepted`.
81    pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
82        let ConnectionCommon { side, common, .. } = &mut self.inner;
83        let early_data = side.early_data.as_mut()?;
84        match early_data.state {
85            EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
86                Some(WriteEarlyData { early_data, common })
87            }
88            _ => None,
89        }
90    }
91
92    /// Returns True if the server signalled it will process early data.
93    ///
94    /// If you sent early data and this returns false at the end of the
95    /// handshake then the server will not process the data.  This
96    /// is not an error, but you may wish to resend the data.
97    pub fn is_early_data_accepted(&self) -> bool {
98        self.inner.is_early_data_accepted()
99    }
100
101    /// Return the connection's Encrypted Client Hello (ECH) status.
102    pub fn ech_status(&self) -> EchStatus {
103        self.inner.side.ech_status
104    }
105
106    /// Returns the number of TLS1.3 tickets that have been received.
107    pub fn tls13_tickets_received(&self) -> u32 {
108        self.inner
109            .common
110            .recv
111            .tls13_tickets_received
112    }
113}
114
115impl Connection for ClientConnection {
116    type Side = ClientSide;
117
118    fn write(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> Result<(), Error> {
119        self.inner.write(plaintext, tls)
120    }
121
122    fn wants_read(&self) -> bool {
123        self.inner.wants_read()
124    }
125
126    fn read_tls<'a, 'm>(
127        &'a mut self,
128        input: &'m mut dyn TlsInputBuffer,
129        tls: &'a mut Vec<u8>,
130    ) -> MessageHandler<'a, 'm, ClientSide> {
131        self.inner.read_tls(input, tls)
132    }
133
134    fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
135        self.inner.exporter()
136    }
137
138    fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
139        self.inner.dangerous_extract_secrets()
140    }
141
142    fn refresh_traffic_keys(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
143        self.inner.refresh_traffic_keys(tls)
144    }
145
146    fn send_close_notify(&mut self, tls: &mut Vec<u8>) {
147        self.inner.send_close_notify(tls);
148    }
149
150    fn is_handshaking(&self) -> bool {
151        self.inner.is_handshaking()
152    }
153
154    fn fips(&self) -> FipsStatus {
155        self.inner.fips
156    }
157}
158
159impl Deref for ClientConnection {
160    type Target = ConnectionOutputs;
161
162    fn deref(&self) -> &Self::Target {
163        &self.inner
164    }
165}
166
167/// Builder for [`ClientConnection`] values.
168///
169/// Create one with [`ClientConfig::connect()`].
170pub struct ClientConnectionBuilder {
171    pub(crate) config: Arc<ClientConfig>,
172    pub(crate) name: ServerName<'static>,
173    pub(crate) alpn_protocols: Option<Vec<ApplicationProtocol<'static>>>,
174}
175
176impl ClientConnectionBuilder {
177    /// Specify the ALPN protocols to use for this connection.
178    pub fn with_alpn(mut self, alpn_protocols: Vec<ApplicationProtocol<'static>>) -> Self {
179        self.alpn_protocols = Some(alpn_protocols);
180        self
181    }
182
183    /// Finalize the builder and create the `ClientConnection`.
184    pub fn build(self, tls: &mut Vec<u8>) -> Result<ClientConnection, Error> {
185        let Self {
186            config,
187            name,
188            alpn_protocols,
189        } = self;
190
191        let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
192        Ok(ClientConnection {
193            inner: ConnectionCommon::for_client(
194                config,
195                name,
196                ClientExtensionsInput::from_alpn(alpn_protocols),
197                None,
198                Protocol::Tcp,
199                tls,
200            )?,
201        })
202    }
203
204    /// Finalize the builder and create a QUIC `ClientConnection`.
205    ///
206    /// This differs from `ClientConnectionBuilder::build()` in that it takes an extra `params`
207    /// argument, which contains the TLS-encoded transport parameters to send, and an extra
208    /// `version` argument, specifying the QUIC protocol version.
209    pub fn build_quic(
210        self,
211        version: quic::Version,
212        params: Vec<u8>,
213    ) -> Result<QuicClientConnection, Error> {
214        let suites = &self
215            .config
216            .provider()
217            .tls13_cipher_suites;
218        if suites.is_empty() {
219            return Err(ApiMisuse::QuicRequiresTls13Support.into());
220        }
221
222        if !suites
223            .iter()
224            .any(|scs| scs.quic.is_some())
225        {
226            return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
227        }
228
229        let exts = ClientExtensionsInput {
230            transport_parameters: Some(match version {
231                quic::Version::V1 | quic::Version::V2 => {
232                    TransportParameters::Quic(Payload::new(params))
233                }
234            }),
235
236            ..ClientExtensionsInput::from_alpn(
237                self.alpn_protocols
238                    .unwrap_or_else(|| self.config.alpn_protocols.clone()),
239            )
240        };
241
242        let mut quic = Quic {
243            version,
244            ..Quic::default()
245        };
246
247        let mut tls = Vec::new();
248        let inner = ConnectionCommon::for_client(
249            self.config,
250            self.name,
251            exts,
252            Some(&mut quic),
253            Protocol::Quic(version),
254            &mut tls,
255        )?;
256
257        // In QUIC mode, handshake output is emitted via `QuicEvent`s, not `tls`.
258        debug_assert!(tls.is_empty());
259        Ok(QuicClientConnection::from(QuicCommon::new(inner, quic)))
260    }
261
262    /// Finalize the builder and create a [`ClientHandshake`].
263    ///
264    /// It is a fundamental fact of client TLS connections that the client writes first; this data
265    /// is written to `tls`.  The client then always reads the server's response, as represented
266    /// by the [`NeedsInput`] return value.
267    ///
268    /// You may wrap this in the [`ClientHandshake::NeedsInput`] variant to generalise the type to a
269    /// [`ClientHandshake`].
270    ///
271    /// The returned object should be fed data from a single server.
272    pub fn start_handshake(self, tls: &mut Vec<u8>) -> Result<NeedsInput<ClientSide>, Error> {
273        let Self {
274            config,
275            name,
276            alpn_protocols,
277        } = self;
278
279        let alpn_protocols = alpn_protocols.unwrap_or_else(|| config.alpn_protocols.clone());
280        Ok(NeedsInput {
281            inner: ConnectionCommon::for_client(
282                config,
283                name,
284                ClientExtensionsInput::from_alpn(alpn_protocols),
285                None,
286                Protocol::Tcp,
287                tls,
288            )?,
289        })
290    }
291}
292
293/// An in-progress TLS client handshake.
294///
295/// Make one of these using [`ClientConnectionBuilder::start_handshake()`].
296#[non_exhaustive]
297#[derive(Debug)]
298pub enum ClientHandshake {
299    /// More data needs to be received to make progress.
300    NeedsInput(NeedsInput<ClientSide>),
301
302    /// The server's presented identity must be verified.
303    ///
304    /// See [`VerifyPeerIdentity`] for how to proceed.
305    VerifyServerIdentity(VerifyPeerIdentity<ClientSide>),
306
307    /// The handshake is complete.
308    ///
309    /// Now see [`SplitConnection`] to continue the connection.
310    Complete(SplitConnection<ClientSide>),
311}
312
313impl TryFrom<ConnectionCommon<ClientSide>> for ClientHandshake {
314    type Error = Error;
315
316    fn try_from(mut inner: ConnectionCommon<ClientSide>) -> Result<Self, Error> {
317        const MISUSED: Error = Error::Unreachable("forgot to restore state");
318
319        Ok(match mem::replace(&mut inner.state, Err(MISUSED))? {
320            ClientState::VerifyServerIdentity(verify_identity) => {
321                Self::VerifyServerIdentity(VerifyPeerIdentity {
322                    inner,
323                    verify_identity,
324                })
325            }
326
327            state if state.is_traffic() => {
328                inner.state = Ok(state);
329                Self::Complete(SplitConnection::try_from(inner)?)
330            }
331
332            state => {
333                inner.state = Ok(state);
334                Self::NeedsInput(NeedsInput { inner })
335            }
336        })
337    }
338}
339
340/// Allows writing of early data in resumed TLS 1.3 connections.
341///
342/// "Early data" is also known as "0-RTT data".
343///
344/// Use [`Self::write()`] to encrypt early data into TLS records.
345pub struct WriteEarlyData<'a> {
346    early_data: &'a mut EarlyData,
347    common: &'a mut CommonState,
348}
349
350impl<'a> WriteEarlyData<'a> {
351    /// Encrypt early data as TLS records and encode them into `tls`.
352    ///
353    /// Yields the number of bytes of `plaintext` that were consumed.  This may be less than
354    /// the length of `plaintext` if the server has limited the amount of early data that
355    /// may be sent.
356    #[must_use]
357    pub fn write(&mut self, plaintext: OutboundPlain<'_>, tls: &mut Vec<u8>) -> usize {
358        let state = &mut self.early_data;
359        let plaintext = match state.state {
360            EarlyDataState::Ready | EarlyDataState::Sending | EarlyDataState::Accepted => {
361                let take = Ord::min(plaintext.len(), state.left);
362                state.left -= take;
363                plaintext.split_at(take).0
364            }
365            EarlyDataState::AcceptedFinished => return 0,
366        };
367
368        self.common
369            .send
370            .send_appdata_encrypt(plaintext, tls)
371    }
372
373    /// How many bytes you may send.  Writes will become short
374    /// once this reaches zero.
375    pub fn bytes_left(&self) -> usize {
376        self.early_data.left
377    }
378
379    /// Returns the "early" exporter that can derive key material for use in early data
380    ///
381    /// See [RFC 5705][] for general details on what exporters are, and [RFC 9846 S7.5][] for
382    /// specific details on the "early" exporter.
383    ///
384    /// **Beware** that the early exporter requires care, as it is subject to the same
385    /// potential for replay as early data itself.  See [RFC 9846 appendix F.5.1][] for
386    /// more detail.
387    ///
388    /// This function can be called at most once per connection. This function will error:
389    /// if called more than once per connection.
390    ///
391    /// If you are looking for the normal exporter, this is available from
392    /// [`Connection::exporter()`].
393    ///
394    /// [RFC 5705]: https://datatracker.ietf.org/doc/html/rfc5705
395    /// [RFC 9846 S7.5]: https://datatracker.ietf.org/doc/html/rfc9846#section-7.5
396    /// [RFC 9846 appendix F.5.1]: https://datatracker.ietf.org/doc/html/rfc9846#appendix-F.5.1
397    /// [`Connection::exporter()`]: crate::conn::Connection::exporter()
398    pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
399        self.common.early_exporter()
400    }
401}
402
403impl ConnectionCommon<ClientSide> {
404    pub(crate) fn for_client(
405        config: Arc<ClientConfig>,
406        name: ServerName<'static>,
407        extra_exts: ClientExtensionsInput,
408        quic: Option<&mut dyn QuicOutput>,
409        protocol: Protocol,
410        tls: &mut Vec<u8>,
411    ) -> Result<Self, Error> {
412        let mut common_state = CommonState::new(Side::Client, config.fips());
413        common_state
414            .send
415            .set_max_fragment_size(config.max_fragment_size)?;
416        let mut data = ClientConnectionData::default();
417
418        let mut output = SideCommonOutput {
419            side: &mut data,
420            quic,
421            common: &mut common_state,
422            tls,
423        };
424
425        let input = ClientHelloInput::new(name, &extra_exts, protocol, &mut output, config)?;
426        let state = input.start_handshake(extra_exts, &mut output)?;
427
428        Ok(Self::new(state, data, common_state))
429    }
430
431    pub(crate) fn is_early_data_accepted(&self) -> bool {
432        matches!(
433            &self.side.early_data,
434            Some(EarlyData {
435                state: EarlyDataState::Accepted | EarlyDataState::AcceptedFinished,
436                ..
437            })
438        )
439    }
440}
441
442/// State associated with a client connection.
443#[expect(clippy::exhaustive_structs)]
444#[derive(Debug)]
445pub struct ClientSide;
446
447impl SideData for ClientSide {
448    type Handshake = ClientHandshake;
449    type PeerIdentity<'a> = ServerIdentity<'static, 'a>;
450
451    #[expect(private_interfaces)]
452    fn handshake_from_inner(common: ConnectionCommon<Self>) -> Result<Self::Handshake, Error> {
453        ClientHandshake::try_from(common)
454    }
455}
456
457impl crate::conn::private::Side for ClientSide {
458    type Data = ClientConnectionData;
459    type State = ClientState;
460}
461
462impl SideOutput for ClientConnectionData {
463    fn emit(&mut self, ev: Event) {
464        match ev {
465            Event::EchStatus(ech) => self.ech_status = ech,
466            Event::EarlyData(event) => match (event, &mut self.early_data) {
467                (EarlyDataEvent::Enable(sz), None) => self.early_data = Some(EarlyData::new(sz)),
468                (EarlyDataEvent::Start, Some(early_data)) => {
469                    assert_eq!(early_data.state, EarlyDataState::Ready);
470                    early_data.state = EarlyDataState::Sending;
471                }
472                (EarlyDataEvent::Accepted, Some(early_data)) => {
473                    trace!("EarlyData accepted");
474                    assert_eq!(early_data.state, EarlyDataState::Sending);
475                    early_data.state = EarlyDataState::Accepted;
476                }
477                (EarlyDataEvent::Rejected, _) => self.early_data = None,
478                (EarlyDataEvent::Finished, Some(early_data)) => {
479                    trace!("EarlyData finished");
480                    early_data.state = match early_data.state {
481                        EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
482                        _ => panic!("bad EarlyData state"),
483                    }
484                }
485                _ => unreachable!(),
486            },
487            _ => unreachable!(),
488        }
489    }
490}
491
492#[derive(Default)]
493pub(crate) struct ClientConnectionData {
494    early_data: Option<EarlyData>,
495    ech_status: EchStatus,
496}
497
498pub(super) struct EarlyData {
499    state: EarlyDataState,
500    left: usize,
501}
502
503impl EarlyData {
504    fn new(left: usize) -> Self {
505        Self {
506            state: EarlyDataState::Ready,
507            left,
508        }
509    }
510}
511
512#[derive(Debug, PartialEq)]
513enum EarlyDataState {
514    Ready,
515    Sending,
516    Accepted,
517    AcceptedFinished,
518}