rustls/client/
client_conn.rs

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