rustls/client/
client_conn.rs

1use crate::builder::ConfigBuilder;
2use crate::common_state::{CommonState, Protocol, Side};
3use crate::conn::{ConnectionCommon, ConnectionCore};
4use crate::crypto::{CryptoProvider, SupportedKxGroup};
5use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme};
6use crate::error::Error;
7#[cfg(feature = "logging")]
8use crate::log::trace;
9use crate::msgs::enums::NamedGroup;
10use crate::msgs::handshake::ClientExtension;
11use crate::msgs::persist;
12use crate::sign;
13use crate::suites::{ExtractedSecrets, SupportedCipherSuite};
14use crate::versions;
15use crate::KeyLog;
16#[cfg(feature = "ring")]
17use crate::WantsVerifier;
18use crate::{verify, WantsVersions};
19
20use super::handy::{ClientSessionMemoryCache, NoClientSessionStorage};
21use super::hs;
22
23use pki_types::ServerName;
24
25use alloc::sync::Arc;
26use alloc::vec::Vec;
27use core::fmt;
28use core::marker::PhantomData;
29use core::mem;
30use core::ops::{Deref, DerefMut};
31use std::io;
32
33#[cfg(doc)]
34use crate::{crypto, DistinguishedName};
35
36/// A trait for the ability to store client session data, so that sessions
37/// can be resumed in future connections.
38///
39/// Generally all data in this interface should be treated as
40/// **highly sensitive**, containing enough key material to break all security
41/// of the corresponding session.
42///
43/// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't
44/// expressed in the type system to allow implementations freedom in
45/// how to achieve interior mutability.  `Mutex` is a common choice.
46pub trait ClientSessionStore: fmt::Debug + Send + Sync {
47    /// Remember what `NamedGroup` the given server chose.
48    fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup);
49
50    /// This should return the value most recently passed to `set_kx_hint`
51    /// for the given `server_name`.
52    ///
53    /// If `None` is returned, the caller chooses the first configured group,
54    /// and an extra round trip might happen if that choice is unsatisfactory
55    /// to the server.
56    fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup>;
57
58    /// Remember a TLS1.2 session.
59    ///
60    /// At most one of these can be remembered at a time, per `server_name`.
61    fn set_tls12_session(
62        &self,
63        server_name: ServerName<'static>,
64        value: persist::Tls12ClientSessionValue,
65    );
66
67    /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`.
68    fn tls12_session(
69        &self,
70        server_name: &ServerName<'_>,
71    ) -> Option<persist::Tls12ClientSessionValue>;
72
73    /// Remove and forget any saved TLS1.2 session for `server_name`.
74    fn remove_tls12_session(&self, server_name: &ServerName<'static>);
75
76    /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing
77    /// resumption of this session.
78    ///
79    /// This can be called multiple times for a given session, allowing multiple independent tickets
80    /// to be valid at once.  The number of times this is called is controlled by the server, so
81    /// implementations of this trait should apply a reasonable bound of how many items are stored
82    /// simultaneously.
83    fn insert_tls13_ticket(
84        &self,
85        server_name: ServerName<'static>,
86        value: persist::Tls13ClientSessionValue,
87    );
88
89    /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`.
90    ///
91    /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_.
92    fn take_tls13_ticket(
93        &self,
94        server_name: &ServerName<'static>,
95    ) -> Option<persist::Tls13ClientSessionValue>;
96}
97
98/// A trait for the ability to choose a certificate chain and
99/// private key for the purposes of client authentication.
100pub trait ResolvesClientCert: fmt::Debug + Send + Sync {
101    /// Resolve a client certificate chain/private key to use as the client's
102    /// identity.
103    ///
104    /// `root_hint_subjects` is an optional list of certificate authority
105    /// subject distinguished names that the client can use to help
106    /// decide on a client certificate the server is likely to accept. If
107    /// the list is empty, the client should send whatever certificate it
108    /// has. The hints are expected to be DER-encoded X.500 distinguished names,
109    /// per [RFC 5280 A.1]. See [`DistinguishedName`] for more information
110    /// on decoding with external crates like `x509-parser`.
111    ///
112    /// `sigschemes` is the list of the [`SignatureScheme`]s the server
113    /// supports.
114    ///
115    /// Return `None` to continue the handshake without any client
116    /// authentication.  The server may reject the handshake later
117    /// if it requires authentication.
118    ///
119    /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
120    fn resolve(
121        &self,
122        root_hint_subjects: &[&[u8]],
123        sigschemes: &[SignatureScheme],
124    ) -> Option<Arc<sign::CertifiedKey>>;
125
126    /// Return true if any certificates at all are available.
127    fn has_certs(&self) -> bool;
128}
129
130/// Common configuration for (typically) all connections made by a program.
131///
132/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots
133/// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()`
134/// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred
135/// milliseconds.
136///
137/// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder_with_provider()`]
138/// function.
139///
140/// # Defaults
141///
142/// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB).
143/// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session
144///    ids or tickets, with a max of eight tickets per server.
145/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated.
146/// * [`ClientConfig::key_log`]: key material is not logged.
147///
148/// [`RootCertStore`]: crate::RootCertStore
149#[derive(Debug)]
150pub struct ClientConfig {
151    /// Source of randomness and other crypto.
152    pub(super) provider: Arc<CryptoProvider>,
153
154    /// Which ALPN protocols we include in our client hello.
155    /// If empty, no ALPN extension is sent.
156    pub alpn_protocols: Vec<Vec<u8>>,
157
158    /// How and when the client can resume a previous session.
159    pub resumption: Resumption,
160
161    /// The maximum size of plaintext input to be emitted in a single TLS record.
162    /// A value of None is equivalent to the [TLS maximum] of 16 kB.
163    ///
164    /// rustls enforces an arbitrary minimum of 32 bytes for this field.
165    /// Out of range values are reported as errors from [ClientConnection::new].
166    ///
167    /// Setting this value to a little less than the TCP MSS may improve latency
168    /// for stream-y workloads.
169    ///
170    /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1
171    /// [ClientConnection::new]: crate::client::ClientConnection::new
172    pub max_fragment_size: Option<usize>,
173
174    /// How to decide what client auth certificate/keys to use.
175    pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
176
177    /// Supported versions, in no particular order.  The default
178    /// is all supported versions.
179    pub(super) versions: versions::EnabledVersions,
180
181    /// Whether to send the Server Name Indication (SNI) extension
182    /// during the client handshake.
183    ///
184    /// The default is true.
185    pub enable_sni: bool,
186
187    /// How to verify the server certificate chain.
188    pub(super) verifier: Arc<dyn verify::ServerCertVerifier>,
189
190    /// How to output key material for debugging.  The default
191    /// does nothing.
192    pub key_log: Arc<dyn KeyLog>,
193
194    /// Allows traffic secrets to be extracted after the handshake,
195    /// e.g. for kTLS setup.
196    pub enable_secret_extraction: bool,
197
198    /// Whether to send data on the first flight ("early data") in
199    /// TLS 1.3 handshakes.
200    ///
201    /// The default is false.
202    pub enable_early_data: bool,
203}
204
205/// What mechanisms to support for resuming a TLS 1.2 session.
206#[derive(Clone, Copy, Debug, PartialEq)]
207pub enum Tls12Resumption {
208    /// Disable 1.2 resumption.
209    Disabled,
210    /// Support 1.2 resumption using session ids only.
211    SessionIdOnly,
212    /// Support 1.2 resumption using session ids or RFC 5077 tickets.
213    ///
214    /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly`
215    /// option. Note that TLS 1.3 tickets do not have those issues.
216    ///
217    /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/>
218    SessionIdOrTickets,
219}
220
221impl Clone for ClientConfig {
222    fn clone(&self) -> Self {
223        Self {
224            provider: Arc::<CryptoProvider>::clone(&self.provider),
225            resumption: self.resumption.clone(),
226            alpn_protocols: self.alpn_protocols.clone(),
227            max_fragment_size: self.max_fragment_size,
228            client_auth_cert_resolver: Arc::clone(&self.client_auth_cert_resolver),
229            versions: self.versions,
230            enable_sni: self.enable_sni,
231            verifier: Arc::clone(&self.verifier),
232            key_log: Arc::clone(&self.key_log),
233            enable_secret_extraction: self.enable_secret_extraction,
234            enable_early_data: self.enable_early_data,
235        }
236    }
237}
238
239impl ClientConfig {
240    /// Create a builder for a client configuration with the default
241    /// [`CryptoProvider`]: [`crypto::ring::default_provider`] and safe ciphersuite and
242    /// protocol defaults.
243    ///
244    /// For more information, see the [`ConfigBuilder`] documentation.
245    #[cfg(feature = "ring")]
246    pub fn builder() -> ConfigBuilder<Self, WantsVerifier> {
247        // Safety: we know the *ring* provider's ciphersuites are compatible with the safe default protocol versions.
248        Self::builder_with_provider(crate::crypto::ring::default_provider().into())
249            .with_safe_default_protocol_versions()
250            .unwrap()
251    }
252
253    /// Create a builder for a client configuration with the default
254    /// [`CryptoProvider`]: [`crypto::ring::default_provider`], safe ciphersuite defaults and
255    /// the provided protocol versions.
256    ///
257    /// Panics if provided an empty slice of supported versions.
258    ///
259    /// For more information, see the [`ConfigBuilder`] documentation.
260    #[cfg(feature = "ring")]
261    pub fn builder_with_protocol_versions(
262        versions: &[&'static versions::SupportedProtocolVersion],
263    ) -> ConfigBuilder<Self, WantsVerifier> {
264        // Safety: we know the *ring* provider's ciphersuites are compatible with all protocol version choices.
265        Self::builder_with_provider(crate::crypto::ring::default_provider().into())
266            .with_protocol_versions(versions)
267            .unwrap()
268    }
269
270    /// Create a builder for a client configuration with a specific [`CryptoProvider`].
271    ///
272    /// This will use the provider's configured ciphersuites. You must additionally choose
273    /// which protocol versions to enable, using `with_protocol_versions` or
274    /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol
275    /// version is not supported by the provider's ciphersuites.
276    ///
277    /// For more information, see the [`ConfigBuilder`] documentation.
278    pub fn builder_with_provider(
279        provider: Arc<CryptoProvider>,
280    ) -> ConfigBuilder<Self, WantsVersions> {
281        ConfigBuilder {
282            state: WantsVersions { provider },
283            side: PhantomData,
284        }
285    }
286
287    /// We support a given TLS version if it's quoted in the configured
288    /// versions *and* at least one ciphersuite for this version is
289    /// also configured.
290    pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool {
291        self.versions.contains(v)
292            && self
293                .provider
294                .cipher_suites
295                .iter()
296                .any(|cs| cs.version().version == v)
297    }
298
299    pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool {
300        self.provider
301            .cipher_suites
302            .iter()
303            .any(|cs| cs.usable_for_protocol(proto))
304    }
305
306    /// Access configuration options whose use is dangerous and requires
307    /// extra care.
308    pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> {
309        danger::DangerousClientConfig { cfg: self }
310    }
311
312    pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> {
313        self.provider
314            .cipher_suites
315            .iter()
316            .copied()
317            .find(|&scs| scs.suite() == suite)
318    }
319
320    pub(super) fn find_kx_group(&self, group: NamedGroup) -> Option<&'static dyn SupportedKxGroup> {
321        self.provider
322            .kx_groups
323            .iter()
324            .copied()
325            .find(|skxg| skxg.name() == group)
326    }
327}
328
329/// Configuration for how/when a client is allowed to resume a previous session.
330#[derive(Clone, Debug)]
331pub struct Resumption {
332    /// How we store session data or tickets. The default is to use an in-memory
333    /// [ClientSessionMemoryCache].
334    pub(super) store: Arc<dyn ClientSessionStore>,
335
336    /// What mechanism is used for resuming a TLS 1.2 session.
337    pub(super) tls12_resumption: Tls12Resumption,
338}
339
340impl Resumption {
341    /// Create a new `Resumption` that stores data for the given number of sessions in memory.
342    ///
343    /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with
344    /// a session id or RFC 5077 ticket.
345    pub fn in_memory_sessions(num: usize) -> Self {
346        Self {
347            store: Arc::new(ClientSessionMemoryCache::new(num)),
348            tls12_resumption: Tls12Resumption::SessionIdOrTickets,
349        }
350    }
351
352    /// Use a custom [`ClientSessionStore`] implementation to store sessions.
353    ///
354    /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket.
355    pub fn store(store: Arc<dyn ClientSessionStore>) -> Self {
356        Self {
357            store,
358            tls12_resumption: Tls12Resumption::SessionIdOrTickets,
359        }
360    }
361
362    /// Disable all use of session resumption.
363    pub fn disabled() -> Self {
364        Self {
365            store: Arc::new(NoClientSessionStorage),
366            tls12_resumption: Tls12Resumption::Disabled,
367        }
368    }
369
370    /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism.
371    ///
372    /// This is meaningless if you've disabled resumption entirely.
373    pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self {
374        self.tls12_resumption = tls12;
375        self
376    }
377}
378
379impl Default for Resumption {
380    /// Create an in-memory session store resumption with up to 256 server names, allowing
381    /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket.
382    fn default() -> Self {
383        Self::in_memory_sessions(256)
384    }
385}
386
387/// Container for unsafe APIs
388pub(super) mod danger {
389    use alloc::sync::Arc;
390
391    use super::verify::ServerCertVerifier;
392    use super::ClientConfig;
393
394    /// Accessor for dangerous configuration options.
395    #[derive(Debug)]
396    pub struct DangerousClientConfig<'a> {
397        /// The underlying ClientConfig
398        pub cfg: &'a mut ClientConfig,
399    }
400
401    impl<'a> DangerousClientConfig<'a> {
402        /// Overrides the default `ServerCertVerifier` with something else.
403        pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerCertVerifier>) {
404            self.cfg.verifier = verifier;
405        }
406    }
407}
408
409#[derive(Debug, PartialEq)]
410enum EarlyDataState {
411    Disabled,
412    Ready,
413    Accepted,
414    AcceptedFinished,
415    Rejected,
416}
417
418#[derive(Debug)]
419pub(super) struct EarlyData {
420    state: EarlyDataState,
421    left: usize,
422}
423
424impl EarlyData {
425    fn new() -> Self {
426        Self {
427            left: 0,
428            state: EarlyDataState::Disabled,
429        }
430    }
431
432    pub(super) fn is_enabled(&self) -> bool {
433        matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted)
434    }
435
436    fn is_accepted(&self) -> bool {
437        matches!(
438            self.state,
439            EarlyDataState::Accepted | EarlyDataState::AcceptedFinished
440        )
441    }
442
443    pub(super) fn enable(&mut self, max_data: usize) {
444        assert_eq!(self.state, EarlyDataState::Disabled);
445        self.state = EarlyDataState::Ready;
446        self.left = max_data;
447    }
448
449    pub(super) fn rejected(&mut self) {
450        trace!("EarlyData rejected");
451        self.state = EarlyDataState::Rejected;
452    }
453
454    pub(super) fn accepted(&mut self) {
455        trace!("EarlyData accepted");
456        assert_eq!(self.state, EarlyDataState::Ready);
457        self.state = EarlyDataState::Accepted;
458    }
459
460    pub(super) fn finished(&mut self) {
461        trace!("EarlyData finished");
462        self.state = match self.state {
463            EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
464            _ => panic!("bad EarlyData state"),
465        }
466    }
467
468    fn check_write(&mut self, sz: usize) -> io::Result<usize> {
469        match self.state {
470            EarlyDataState::Disabled => unreachable!(),
471            EarlyDataState::Ready | EarlyDataState::Accepted => {
472                let take = if self.left < sz {
473                    mem::replace(&mut self.left, 0)
474                } else {
475                    self.left -= sz;
476                    sz
477                };
478
479                Ok(take)
480            }
481            EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => {
482                Err(io::Error::from(io::ErrorKind::InvalidInput))
483            }
484        }
485    }
486
487    fn bytes_left(&self) -> usize {
488        self.left
489    }
490}
491
492/// Stub that implements io::Write and dispatches to `write_early_data`.
493pub struct WriteEarlyData<'a> {
494    sess: &'a mut ClientConnection,
495}
496
497impl<'a> WriteEarlyData<'a> {
498    fn new(sess: &'a mut ClientConnection) -> Self {
499        WriteEarlyData { sess }
500    }
501
502    /// How many bytes you may send.  Writes will become short
503    /// once this reaches zero.
504    pub fn bytes_left(&self) -> usize {
505        self.sess
506            .inner
507            .core
508            .data
509            .early_data
510            .bytes_left()
511    }
512}
513
514impl<'a> io::Write for WriteEarlyData<'a> {
515    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
516        self.sess.write_early_data(buf)
517    }
518
519    fn flush(&mut self) -> io::Result<()> {
520        Ok(())
521    }
522}
523
524/// This represents a single TLS client connection.
525pub struct ClientConnection {
526    inner: ConnectionCommon<ClientConnectionData>,
527}
528
529impl fmt::Debug for ClientConnection {
530    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
531        f.debug_struct("ClientConnection")
532            .finish()
533    }
534}
535
536impl ClientConnection {
537    /// Make a new ClientConnection.  `config` controls how
538    /// we behave in the TLS protocol, `name` is the
539    /// name of the server we want to talk to.
540    pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> {
541        Ok(Self {
542            inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(),
543        })
544    }
545
546    /// Returns an `io::Write` implementer you can write bytes to
547    /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server.
548    ///
549    /// This returns None in many circumstances when the capability to
550    /// send early data is not available, including but not limited to:
551    ///
552    /// - The server hasn't been talked to previously.
553    /// - The server does not support resumption.
554    /// - The server does not support early data.
555    /// - The resumption data for the server has expired.
556    ///
557    /// The server specifies a maximum amount of early data.  You can
558    /// learn this limit through the returned object, and writes through
559    /// it will process only this many bytes.
560    ///
561    /// The server can choose not to accept any sent early data --
562    /// in this case the data is lost but the connection continues.  You
563    /// can tell this happened using `is_early_data_accepted`.
564    pub fn early_data(&mut self) -> Option<WriteEarlyData> {
565        if self
566            .inner
567            .core
568            .data
569            .early_data
570            .is_enabled()
571        {
572            Some(WriteEarlyData::new(self))
573        } else {
574            None
575        }
576    }
577
578    /// Returns True if the server signalled it will process early data.
579    ///
580    /// If you sent early data and this returns false at the end of the
581    /// handshake then the server will not process the data.  This
582    /// is not an error, but you may wish to resend the data.
583    pub fn is_early_data_accepted(&self) -> bool {
584        self.inner.core.is_early_data_accepted()
585    }
586
587    /// Extract secrets, so they can be used when configuring kTLS, for example.
588    /// Should be used with care as it exposes secret key material.
589    pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
590        self.inner.dangerous_extract_secrets()
591    }
592
593    fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> {
594        self.inner
595            .core
596            .data
597            .early_data
598            .check_write(data.len())
599            .map(|sz| {
600                self.inner
601                    .send_early_plaintext(&data[..sz])
602            })
603    }
604}
605
606impl Deref for ClientConnection {
607    type Target = ConnectionCommon<ClientConnectionData>;
608
609    fn deref(&self) -> &Self::Target {
610        &self.inner
611    }
612}
613
614impl DerefMut for ClientConnection {
615    fn deref_mut(&mut self) -> &mut Self::Target {
616        &mut self.inner
617    }
618}
619
620#[doc(hidden)]
621impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection {
622    type Error = ();
623
624    fn try_from(value: &'a mut crate::Connection) -> Result<Self, Self::Error> {
625        use crate::Connection::*;
626        match value {
627            Client(conn) => Ok(conn),
628            Server(_) => Err(()),
629        }
630    }
631}
632
633impl From<ClientConnection> for crate::Connection {
634    fn from(conn: ClientConnection) -> Self {
635        Self::Client(conn)
636    }
637}
638
639impl ConnectionCore<ClientConnectionData> {
640    pub(crate) fn for_client(
641        config: Arc<ClientConfig>,
642        name: ServerName<'static>,
643        extra_exts: Vec<ClientExtension>,
644        proto: Protocol,
645    ) -> Result<Self, Error> {
646        let mut common_state = CommonState::new(Side::Client);
647        common_state.set_max_fragment_size(config.max_fragment_size)?;
648        common_state.protocol = proto;
649        common_state.enable_secret_extraction = config.enable_secret_extraction;
650        let mut data = ClientConnectionData::new();
651
652        let mut cx = hs::ClientContext {
653            common: &mut common_state,
654            data: &mut data,
655        };
656
657        let state = hs::start_handshake(name, extra_exts, config, &mut cx)?;
658        Ok(Self::new(state, data, common_state))
659    }
660
661    pub(crate) fn is_early_data_accepted(&self) -> bool {
662        self.data.early_data.is_accepted()
663    }
664}
665
666/// State associated with a client connection.
667#[derive(Debug)]
668pub struct ClientConnectionData {
669    pub(super) early_data: EarlyData,
670    pub(super) resumption_ciphersuite: Option<SupportedCipherSuite>,
671}
672
673impl ClientConnectionData {
674    fn new() -> Self {
675        Self {
676            early_data: EarlyData::new(),
677            resumption_ciphersuite: None,
678        }
679    }
680}
681
682impl crate::conn::SideData for ClientConnectionData {}