rustls/client/
client_conn.rs

1use alloc::sync::Arc;
2use alloc::vec::Vec;
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use core::{fmt, mem};
6
7use pki_types::{ServerName, UnixTime};
8
9use super::handy::NoClientSessionStorage;
10use super::hs;
11use crate::builder::ConfigBuilder;
12use crate::client::{EchMode, EchStatus};
13use crate::common_state::{CommonState, Protocol, Side};
14use crate::conn::{ConnectionCore, UnbufferedConnectionCommon};
15use crate::crypto::{CryptoProvider, SupportedKxGroup};
16use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme};
17use crate::error::Error;
18use crate::log::trace;
19use crate::msgs::enums::NamedGroup;
20use crate::msgs::handshake::ClientExtension;
21use crate::msgs::persist;
22use crate::suites::SupportedCipherSuite;
23#[cfg(feature = "std")]
24use crate::time_provider::DefaultTimeProvider;
25use crate::time_provider::TimeProvider;
26use crate::unbuffered::{EncryptError, TransmitTlsData};
27#[cfg(feature = "std")]
28use crate::WantsVerifier;
29use crate::{compress, sign, verify, versions, KeyLog, WantsVersions};
30#[cfg(doc)]
31use crate::{crypto, DistinguishedName};
32
33/// A trait for the ability to store client session data, so that sessions
34/// can be resumed in future connections.
35///
36/// Generally all data in this interface should be treated as
37/// **highly sensitive**, containing enough key material to break all security
38/// of the corresponding session.
39///
40/// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't
41/// expressed in the type system to allow implementations freedom in
42/// how to achieve interior mutability.  `Mutex` is a common choice.
43pub trait ClientSessionStore: fmt::Debug + Send + Sync {
44    /// Remember what `NamedGroup` the given server chose.
45    fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup);
46
47    /// This should return the value most recently passed to `set_kx_hint`
48    /// for the given `server_name`.
49    ///
50    /// If `None` is returned, the caller chooses the first configured group,
51    /// and an extra round trip might happen if that choice is unsatisfactory
52    /// to the server.
53    fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup>;
54
55    /// Remember a TLS1.2 session.
56    ///
57    /// At most one of these can be remembered at a time, per `server_name`.
58    fn set_tls12_session(
59        &self,
60        server_name: ServerName<'static>,
61        value: persist::Tls12ClientSessionValue,
62    );
63
64    /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`.
65    fn tls12_session(
66        &self,
67        server_name: &ServerName<'_>,
68    ) -> Option<persist::Tls12ClientSessionValue>;
69
70    /// Remove and forget any saved TLS1.2 session for `server_name`.
71    fn remove_tls12_session(&self, server_name: &ServerName<'static>);
72
73    /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing
74    /// resumption of this session.
75    ///
76    /// This can be called multiple times for a given session, allowing multiple independent tickets
77    /// to be valid at once.  The number of times this is called is controlled by the server, so
78    /// implementations of this trait should apply a reasonable bound of how many items are stored
79    /// simultaneously.
80    fn insert_tls13_ticket(
81        &self,
82        server_name: ServerName<'static>,
83        value: persist::Tls13ClientSessionValue,
84    );
85
86    /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`.
87    ///
88    /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_.
89    fn take_tls13_ticket(
90        &self,
91        server_name: &ServerName<'static>,
92    ) -> Option<persist::Tls13ClientSessionValue>;
93}
94
95/// A trait for the ability to choose a certificate chain and
96/// private key for the purposes of client authentication.
97pub trait ResolvesClientCert: fmt::Debug + Send + Sync {
98    /// Resolve a client certificate chain/private key to use as the client's
99    /// identity.
100    ///
101    /// `root_hint_subjects` is an optional list of certificate authority
102    /// subject distinguished names that the client can use to help
103    /// decide on a client certificate the server is likely to accept. If
104    /// the list is empty, the client should send whatever certificate it
105    /// has. The hints are expected to be DER-encoded X.500 distinguished names,
106    /// per [RFC 5280 A.1]. See [`DistinguishedName`] for more information
107    /// on decoding with external crates like `x509-parser`.
108    ///
109    /// `sigschemes` is the list of the [`SignatureScheme`]s the server
110    /// supports.
111    ///
112    /// Return `None` to continue the handshake without any client
113    /// authentication.  The server may reject the handshake later
114    /// if it requires authentication.
115    ///
116    /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
117    fn resolve(
118        &self,
119        root_hint_subjects: &[&[u8]],
120        sigschemes: &[SignatureScheme],
121    ) -> Option<Arc<sign::CertifiedKey>>;
122
123    /// Return true if any certificates at all are available.
124    fn has_certs(&self) -> bool;
125}
126
127/// Common configuration for (typically) all connections made by a program.
128///
129/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots
130/// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()`
131/// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred
132/// milliseconds.
133///
134/// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder_with_provider()`]
135/// function.
136///
137/// Note that using [`ConfigBuilder<ClientConfig, WantsVersions>::with_ech()`] will produce a common
138/// configuration specific to the provided [`crate::client::EchConfig`] that may not be appropriate
139/// for all connections made by the program. In this case the configuration should only be shared
140/// by connections intended for domains that offer the provided [`crate::client::EchConfig`] in
141/// their DNS zone.
142///
143/// # Defaults
144///
145/// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB).
146/// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session
147///    ids or tickets, with a max of eight tickets per server.
148/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated.
149/// * [`ClientConfig::key_log`]: key material is not logged.
150/// * [`ClientConfig::cert_decompressors`]: depends on the crate features, see [`compress::default_cert_decompressors()`].
151/// * [`ClientConfig::cert_compressors`]: depends on the crate features, see [`compress::default_cert_compressors()`].
152/// * [`ClientConfig::cert_compression_cache`]: caches the most recently used 4 compressions
153///
154/// [`RootCertStore`]: crate::RootCertStore
155#[derive(Clone, Debug)]
156pub struct ClientConfig {
157    /// Which ALPN protocols we include in our client hello.
158    /// If empty, no ALPN extension is sent.
159    pub alpn_protocols: Vec<Vec<u8>>,
160
161    /// How and when the client can resume a previous session.
162    pub resumption: Resumption,
163
164    /// The maximum size of plaintext input to be emitted in a single TLS record.
165    /// A value of None is equivalent to the [TLS maximum] of 16 kB.
166    ///
167    /// rustls enforces an arbitrary minimum of 32 bytes for this field.
168    /// Out of range values are reported as errors from [ClientConnection::new].
169    ///
170    /// Setting this value to a little less than the TCP MSS may improve latency
171    /// for stream-y workloads.
172    ///
173    /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1
174    /// [ClientConnection::new]: crate::client::ClientConnection::new
175    pub max_fragment_size: Option<usize>,
176
177    /// How to decide what client auth certificate/keys to use.
178    pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
179
180    /// Whether to send the Server Name Indication (SNI) extension
181    /// during the client handshake.
182    ///
183    /// The default is true.
184    pub enable_sni: bool,
185
186    /// How to output key material for debugging.  The default
187    /// does nothing.
188    pub key_log: Arc<dyn KeyLog>,
189
190    /// Allows traffic secrets to be extracted after the handshake,
191    /// e.g. for kTLS setup.
192    pub enable_secret_extraction: bool,
193
194    /// Whether to send data on the first flight ("early data") in
195    /// TLS 1.3 handshakes.
196    ///
197    /// The default is false.
198    pub enable_early_data: bool,
199
200    /// If set to `true`, requires the server to support the extended
201    /// master secret extraction method defined in [RFC 7627].
202    ///
203    /// The default is `true` if the `fips` crate feature is enabled,
204    /// `false` otherwise.
205    ///
206    /// It must be set to `true` to meet FIPS requirement mentioned in section
207    /// **D.Q Transition of the TLS 1.2 KDF to Support the Extended Master
208    /// Secret** from [FIPS 140-3 IG.pdf].
209    ///
210    /// [RFC 7627]: https://datatracker.ietf.org/doc/html/rfc7627
211    /// [FIPS 140-3 IG.pdf]: https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf
212    #[cfg(feature = "tls12")]
213    pub require_ems: bool,
214
215    /// Provides the current system time
216    pub time_provider: Arc<dyn TimeProvider>,
217
218    /// Source of randomness and other crypto.
219    pub(super) provider: Arc<CryptoProvider>,
220
221    /// Supported versions, in no particular order.  The default
222    /// is all supported versions.
223    pub(super) versions: versions::EnabledVersions,
224
225    /// How to verify the server certificate chain.
226    pub(super) verifier: Arc<dyn verify::ServerCertVerifier>,
227
228    /// How to decompress the server's certificate chain.
229    ///
230    /// If this is non-empty, the [RFC8779] certificate compression
231    /// extension is offered, and any compressed certificates are
232    /// transparently decompressed during the handshake.
233    ///
234    /// This only applies to TLS1.3 connections.  It is ignored for
235    /// TLS1.2 connections.
236    ///
237    /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/
238    pub cert_decompressors: Vec<&'static dyn compress::CertDecompressor>,
239
240    /// How to compress the client's certificate chain.
241    ///
242    /// If a server supports this extension, and advertises support
243    /// for one of the compression algorithms included here, the
244    /// client certificate will be compressed according to [RFC8779].
245    ///
246    /// This only applies to TLS1.3 connections.  It is ignored for
247    /// TLS1.2 connections.
248    ///
249    /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/
250    pub cert_compressors: Vec<&'static dyn compress::CertCompressor>,
251
252    /// Caching for compressed certificates.
253    ///
254    /// This is optional: [`compress::CompressionCache::Disabled`] gives
255    /// a cache that does no caching.
256    pub cert_compression_cache: Arc<compress::CompressionCache>,
257
258    /// How to offer Encrypted Client Hello (ECH). The default is to not offer ECH.
259    pub(super) ech_mode: Option<EchMode>,
260}
261
262impl ClientConfig {
263    /// Create a builder for a client configuration with
264    /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider]
265    /// and safe protocol version defaults.
266    ///
267    /// For more information, see the [`ConfigBuilder`] documentation.
268    #[cfg(feature = "std")]
269    pub fn builder() -> ConfigBuilder<Self, WantsVerifier> {
270        Self::builder_with_protocol_versions(versions::DEFAULT_VERSIONS)
271    }
272
273    /// Create a builder for a client configuration with
274    /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider]
275    /// and the provided protocol versions.
276    ///
277    /// Panics if
278    /// - the supported versions are not compatible with the provider (eg.
279    ///   the combination of ciphersuites supported by the provider and supported
280    ///   versions lead to zero cipher suites being usable),
281    /// - if a `CryptoProvider` cannot be resolved using a combination of
282    ///   the crate features and process default.
283    ///
284    /// For more information, see the [`ConfigBuilder`] documentation.
285    #[cfg(feature = "std")]
286    pub fn builder_with_protocol_versions(
287        versions: &[&'static versions::SupportedProtocolVersion],
288    ) -> ConfigBuilder<Self, WantsVerifier> {
289        // Safety assumptions:
290        // 1. that the provider has been installed (explicitly or implicitly)
291        // 2. that the process-level default provider is usable with the supplied protocol versions.
292        Self::builder_with_provider(Arc::clone(
293            CryptoProvider::get_default_or_install_from_crate_features(),
294        ))
295        .with_protocol_versions(versions)
296        .unwrap()
297    }
298
299    /// Create a builder for a client configuration with a specific [`CryptoProvider`].
300    ///
301    /// This will use the provider's configured ciphersuites. You must additionally choose
302    /// which protocol versions to enable, using `with_protocol_versions` or
303    /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol
304    /// version is not supported by the provider's ciphersuites.
305    ///
306    /// For more information, see the [`ConfigBuilder`] documentation.
307    #[cfg(feature = "std")]
308    pub fn builder_with_provider(
309        provider: Arc<CryptoProvider>,
310    ) -> ConfigBuilder<Self, WantsVersions> {
311        ConfigBuilder {
312            state: WantsVersions {
313                provider,
314                time_provider: Arc::new(DefaultTimeProvider),
315            },
316            side: PhantomData,
317        }
318    }
319    /// Create a builder for a client configuration with no default implementation details.
320    ///
321    /// This API must be used by `no_std` users.
322    ///
323    /// You must provide a specific [`TimeProvider`].
324    ///
325    /// You must provide a specific [`CryptoProvider`].
326    ///
327    /// This will use the provider's configured ciphersuites. You must additionally choose
328    /// which protocol versions to enable, using `with_protocol_versions` or
329    /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol
330    /// version is not supported by the provider's ciphersuites.
331    ///
332    /// For more information, see the [`ConfigBuilder`] documentation.
333    pub fn builder_with_details(
334        provider: Arc<CryptoProvider>,
335        time_provider: Arc<dyn TimeProvider>,
336    ) -> ConfigBuilder<Self, WantsVersions> {
337        ConfigBuilder {
338            state: WantsVersions {
339                provider,
340                time_provider,
341            },
342            side: PhantomData,
343        }
344    }
345
346    /// Return true if connections made with this `ClientConfig` will
347    /// operate in FIPS mode.
348    ///
349    /// This is different from [`CryptoProvider::fips()`]: [`CryptoProvider::fips()`]
350    /// is concerned only with cryptography, whereas this _also_ covers TLS-level
351    /// configuration that NIST recommends, as well as ECH HPKE suites if applicable.
352    pub fn fips(&self) -> bool {
353        let mut is_fips = self.provider.fips();
354
355        #[cfg(feature = "tls12")]
356        {
357            is_fips = is_fips && self.require_ems
358        }
359
360        if let Some(ech_mode) = &self.ech_mode {
361            is_fips = is_fips && ech_mode.fips();
362        }
363
364        is_fips
365    }
366
367    /// Return the crypto provider used to construct this client configuration.
368    pub fn crypto_provider(&self) -> &Arc<CryptoProvider> {
369        &self.provider
370    }
371
372    /// Access configuration options whose use is dangerous and requires
373    /// extra care.
374    pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> {
375        danger::DangerousClientConfig { cfg: self }
376    }
377
378    /// We support a given TLS version if it's quoted in the configured
379    /// versions *and* at least one ciphersuite for this version is
380    /// also configured.
381    pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool {
382        self.versions.contains(v)
383            && self
384                .provider
385                .cipher_suites
386                .iter()
387                .any(|cs| cs.version().version == v)
388    }
389
390    #[cfg(feature = "std")]
391    pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool {
392        self.provider
393            .cipher_suites
394            .iter()
395            .any(|cs| cs.usable_for_protocol(proto))
396    }
397
398    pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> {
399        self.provider
400            .cipher_suites
401            .iter()
402            .copied()
403            .find(|&scs| scs.suite() == suite)
404    }
405
406    pub(super) fn find_kx_group(&self, group: NamedGroup) -> Option<&'static dyn SupportedKxGroup> {
407        self.provider
408            .kx_groups
409            .iter()
410            .copied()
411            .find(|skxg| skxg.name() == group)
412    }
413
414    pub(super) fn current_time(&self) -> Result<UnixTime, Error> {
415        self.time_provider
416            .current_time()
417            .ok_or(Error::FailedToGetCurrentTime)
418    }
419}
420
421/// Configuration for how/when a client is allowed to resume a previous session.
422#[derive(Clone, Debug)]
423pub struct Resumption {
424    /// How we store session data or tickets. The default is to use an in-memory
425    /// [super::handy::ClientSessionMemoryCache].
426    pub(super) store: Arc<dyn ClientSessionStore>,
427
428    /// What mechanism is used for resuming a TLS 1.2 session.
429    pub(super) tls12_resumption: Tls12Resumption,
430}
431
432impl Resumption {
433    /// Create a new `Resumption` that stores data for the given number of sessions in memory.
434    ///
435    /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with
436    /// a session id or RFC 5077 ticket.
437    #[cfg(feature = "std")]
438    pub fn in_memory_sessions(num: usize) -> Self {
439        Self {
440            store: Arc::new(super::handy::ClientSessionMemoryCache::new(num)),
441            tls12_resumption: Tls12Resumption::SessionIdOrTickets,
442        }
443    }
444
445    /// Use a custom [`ClientSessionStore`] implementation to store sessions.
446    ///
447    /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket.
448    pub fn store(store: Arc<dyn ClientSessionStore>) -> Self {
449        Self {
450            store,
451            tls12_resumption: Tls12Resumption::SessionIdOrTickets,
452        }
453    }
454
455    /// Disable all use of session resumption.
456    pub fn disabled() -> Self {
457        Self {
458            store: Arc::new(NoClientSessionStorage),
459            tls12_resumption: Tls12Resumption::Disabled,
460        }
461    }
462
463    /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism.
464    ///
465    /// This is meaningless if you've disabled resumption entirely, which is the case in `no-std`
466    /// contexts.
467    pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self {
468        self.tls12_resumption = tls12;
469        self
470    }
471}
472
473impl Default for Resumption {
474    /// Create an in-memory session store resumption with up to 256 server names, allowing
475    /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket.
476    fn default() -> Self {
477        #[cfg(feature = "std")]
478        let ret = Self::in_memory_sessions(256);
479
480        #[cfg(not(feature = "std"))]
481        let ret = Self::disabled();
482
483        ret
484    }
485}
486
487/// What mechanisms to support for resuming a TLS 1.2 session.
488#[derive(Clone, Copy, Debug, PartialEq)]
489pub enum Tls12Resumption {
490    /// Disable 1.2 resumption.
491    Disabled,
492    /// Support 1.2 resumption using session ids only.
493    SessionIdOnly,
494    /// Support 1.2 resumption using session ids or RFC 5077 tickets.
495    ///
496    /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly`
497    /// option. Note that TLS 1.3 tickets do not have those issues.
498    ///
499    /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/>
500    SessionIdOrTickets,
501}
502
503/// Container for unsafe APIs
504pub(super) mod danger {
505    use alloc::sync::Arc;
506
507    use super::verify::ServerCertVerifier;
508    use super::ClientConfig;
509
510    /// Accessor for dangerous configuration options.
511    #[derive(Debug)]
512    pub struct DangerousClientConfig<'a> {
513        /// The underlying ClientConfig
514        pub cfg: &'a mut ClientConfig,
515    }
516
517    impl<'a> DangerousClientConfig<'a> {
518        /// Overrides the default `ServerCertVerifier` with something else.
519        pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerCertVerifier>) {
520            self.cfg.verifier = verifier;
521        }
522    }
523}
524
525#[derive(Debug, PartialEq)]
526enum EarlyDataState {
527    Disabled,
528    Ready,
529    Accepted,
530    AcceptedFinished,
531    Rejected,
532}
533
534#[derive(Debug)]
535pub(super) struct EarlyData {
536    state: EarlyDataState,
537    left: usize,
538}
539
540impl EarlyData {
541    fn new() -> Self {
542        Self {
543            left: 0,
544            state: EarlyDataState::Disabled,
545        }
546    }
547
548    pub(super) fn is_enabled(&self) -> bool {
549        matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted)
550    }
551
552    #[cfg(feature = "std")]
553    fn is_accepted(&self) -> bool {
554        matches!(
555            self.state,
556            EarlyDataState::Accepted | EarlyDataState::AcceptedFinished
557        )
558    }
559
560    pub(super) fn enable(&mut self, max_data: usize) {
561        assert_eq!(self.state, EarlyDataState::Disabled);
562        self.state = EarlyDataState::Ready;
563        self.left = max_data;
564    }
565
566    pub(super) fn rejected(&mut self) {
567        trace!("EarlyData rejected");
568        self.state = EarlyDataState::Rejected;
569    }
570
571    pub(super) fn accepted(&mut self) {
572        trace!("EarlyData accepted");
573        assert_eq!(self.state, EarlyDataState::Ready);
574        self.state = EarlyDataState::Accepted;
575    }
576
577    pub(super) fn finished(&mut self) {
578        trace!("EarlyData finished");
579        self.state = match self.state {
580            EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
581            _ => panic!("bad EarlyData state"),
582        }
583    }
584
585    fn check_write_opt(&mut self, sz: usize) -> Option<usize> {
586        match self.state {
587            EarlyDataState::Disabled => unreachable!(),
588            EarlyDataState::Ready | EarlyDataState::Accepted => {
589                let take = if self.left < sz {
590                    mem::replace(&mut self.left, 0)
591                } else {
592                    self.left -= sz;
593                    sz
594                };
595
596                Some(take)
597            }
598            EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => None,
599        }
600    }
601}
602
603#[cfg(feature = "std")]
604mod connection {
605    use alloc::sync::Arc;
606    use alloc::vec::Vec;
607    use core::fmt;
608    use core::ops::{Deref, DerefMut};
609    use std::io;
610
611    use pki_types::ServerName;
612
613    use super::ClientConnectionData;
614    use crate::client::EchStatus;
615    use crate::common_state::Protocol;
616    use crate::conn::{ConnectionCommon, ConnectionCore};
617    use crate::error::Error;
618    use crate::suites::ExtractedSecrets;
619    use crate::ClientConfig;
620
621    /// Stub that implements io::Write and dispatches to `write_early_data`.
622    pub struct WriteEarlyData<'a> {
623        sess: &'a mut ClientConnection,
624    }
625
626    impl<'a> WriteEarlyData<'a> {
627        fn new(sess: &'a mut ClientConnection) -> Self {
628            WriteEarlyData { sess }
629        }
630
631        /// How many bytes you may send.  Writes will become short
632        /// once this reaches zero.
633        pub fn bytes_left(&self) -> usize {
634            self.sess
635                .inner
636                .core
637                .data
638                .early_data
639                .bytes_left()
640        }
641    }
642
643    impl<'a> io::Write for WriteEarlyData<'a> {
644        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
645            self.sess.write_early_data(buf)
646        }
647
648        fn flush(&mut self) -> io::Result<()> {
649            Ok(())
650        }
651    }
652
653    impl super::EarlyData {
654        fn check_write(&mut self, sz: usize) -> io::Result<usize> {
655            self.check_write_opt(sz)
656                .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidInput))
657        }
658
659        fn bytes_left(&self) -> usize {
660            self.left
661        }
662    }
663
664    /// This represents a single TLS client connection.
665    pub struct ClientConnection {
666        inner: ConnectionCommon<ClientConnectionData>,
667    }
668
669    impl fmt::Debug for ClientConnection {
670        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
671            f.debug_struct("ClientConnection")
672                .finish()
673        }
674    }
675
676    impl ClientConnection {
677        /// Make a new ClientConnection.  `config` controls how
678        /// we behave in the TLS protocol, `name` is the
679        /// name of the server we want to talk to.
680        pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> {
681            Ok(Self {
682                inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(),
683            })
684        }
685
686        /// Returns an `io::Write` implementer you can write bytes to
687        /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server.
688        ///
689        /// This returns None in many circumstances when the capability to
690        /// send early data is not available, including but not limited to:
691        ///
692        /// - The server hasn't been talked to previously.
693        /// - The server does not support resumption.
694        /// - The server does not support early data.
695        /// - The resumption data for the server has expired.
696        ///
697        /// The server specifies a maximum amount of early data.  You can
698        /// learn this limit through the returned object, and writes through
699        /// it will process only this many bytes.
700        ///
701        /// The server can choose not to accept any sent early data --
702        /// in this case the data is lost but the connection continues.  You
703        /// can tell this happened using `is_early_data_accepted`.
704        pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> {
705            if self
706                .inner
707                .core
708                .data
709                .early_data
710                .is_enabled()
711            {
712                Some(WriteEarlyData::new(self))
713            } else {
714                None
715            }
716        }
717
718        /// Returns True if the server signalled it will process early data.
719        ///
720        /// If you sent early data and this returns false at the end of the
721        /// handshake then the server will not process the data.  This
722        /// is not an error, but you may wish to resend the data.
723        pub fn is_early_data_accepted(&self) -> bool {
724            self.inner.core.is_early_data_accepted()
725        }
726
727        /// Extract secrets, so they can be used when configuring kTLS, for example.
728        /// Should be used with care as it exposes secret key material.
729        pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
730            self.inner.dangerous_extract_secrets()
731        }
732
733        /// Return the connection's Encrypted Client Hello (ECH) status.
734        pub fn ech_status(&self) -> EchStatus {
735            self.inner.core.data.ech_status
736        }
737
738        /// Return true if the connection was made with a `ClientConfig` that is FIPS compatible.
739        ///
740        /// This is different from [`crate::crypto::CryptoProvider::fips()`]:
741        /// it is concerned only with cryptography, whereas this _also_ covers TLS-level
742        /// configuration that NIST recommends, as well as ECH HPKE suites if applicable.
743        pub fn fips(&self) -> bool {
744            self.inner.core.data.fips
745        }
746
747        fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> {
748            self.inner
749                .core
750                .data
751                .early_data
752                .check_write(data.len())
753                .map(|sz| {
754                    self.inner
755                        .send_early_plaintext(&data[..sz])
756                })
757        }
758    }
759
760    impl Deref for ClientConnection {
761        type Target = ConnectionCommon<ClientConnectionData>;
762
763        fn deref(&self) -> &Self::Target {
764            &self.inner
765        }
766    }
767
768    impl DerefMut for ClientConnection {
769        fn deref_mut(&mut self) -> &mut Self::Target {
770            &mut self.inner
771        }
772    }
773
774    #[doc(hidden)]
775    impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection {
776        type Error = ();
777
778        fn try_from(value: &'a mut crate::Connection) -> Result<Self, Self::Error> {
779            use crate::Connection::*;
780            match value {
781                Client(conn) => Ok(conn),
782                Server(_) => Err(()),
783            }
784        }
785    }
786
787    impl From<ClientConnection> for crate::Connection {
788        fn from(conn: ClientConnection) -> Self {
789            Self::Client(conn)
790        }
791    }
792}
793#[cfg(feature = "std")]
794pub use connection::{ClientConnection, WriteEarlyData};
795
796impl ConnectionCore<ClientConnectionData> {
797    pub(crate) fn for_client(
798        config: Arc<ClientConfig>,
799        name: ServerName<'static>,
800        extra_exts: Vec<ClientExtension>,
801        proto: Protocol,
802    ) -> Result<Self, Error> {
803        let mut common_state = CommonState::new(Side::Client);
804        common_state.set_max_fragment_size(config.max_fragment_size)?;
805        common_state.protocol = proto;
806        common_state.enable_secret_extraction = config.enable_secret_extraction;
807        let mut data = ClientConnectionData::new();
808        data.fips = config.fips();
809
810        let mut cx = hs::ClientContext {
811            common: &mut common_state,
812            data: &mut data,
813            // `start_handshake` won't produce plaintext
814            sendable_plaintext: None,
815        };
816
817        let state = hs::start_handshake(name, extra_exts, config, &mut cx)?;
818        Ok(Self::new(state, data, common_state))
819    }
820
821    #[cfg(feature = "std")]
822    pub(crate) fn is_early_data_accepted(&self) -> bool {
823        self.data.early_data.is_accepted()
824    }
825}
826
827/// Unbuffered version of `ClientConnection`
828///
829/// See the [`crate::unbuffered`] module docs for more details
830pub struct UnbufferedClientConnection {
831    inner: UnbufferedConnectionCommon<ClientConnectionData>,
832}
833
834impl UnbufferedClientConnection {
835    /// Make a new ClientConnection. `config` controls how we behave in the TLS protocol, `name` is
836    /// the name of the server we want to talk to.
837    pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> {
838        Ok(Self {
839            inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(),
840        })
841    }
842}
843
844impl Deref for UnbufferedClientConnection {
845    type Target = UnbufferedConnectionCommon<ClientConnectionData>;
846
847    fn deref(&self) -> &Self::Target {
848        &self.inner
849    }
850}
851
852impl DerefMut for UnbufferedClientConnection {
853    fn deref_mut(&mut self) -> &mut Self::Target {
854        &mut self.inner
855    }
856}
857
858impl TransmitTlsData<'_, ClientConnectionData> {
859    /// returns an adapter that allows encrypting early (RTT-0) data before transmitting the
860    /// already encoded TLS data
861    ///
862    /// IF allowed by the protocol
863    pub fn may_encrypt_early_data(&mut self) -> Option<MayEncryptEarlyData<'_>> {
864        if self
865            .conn
866            .core
867            .data
868            .early_data
869            .is_enabled()
870        {
871            Some(MayEncryptEarlyData { conn: self.conn })
872        } else {
873            None
874        }
875    }
876}
877
878/// Allows encrypting early (RTT-0) data
879pub struct MayEncryptEarlyData<'c> {
880    conn: &'c mut UnbufferedConnectionCommon<ClientConnectionData>,
881}
882
883impl MayEncryptEarlyData<'_> {
884    /// Encrypts `application_data` into the `outgoing_tls` buffer
885    ///
886    /// returns the number of bytes that were written into `outgoing_tls`, or an error if
887    /// the provided buffer was too small. In the error case, `outgoing_tls` is not modified
888    pub fn encrypt(
889        &mut self,
890        early_data: &[u8],
891        outgoing_tls: &mut [u8],
892    ) -> Result<usize, EarlyDataError> {
893        let allowed = match self
894            .conn
895            .core
896            .data
897            .early_data
898            .check_write_opt(early_data.len())
899        {
900            Some(allowed) => allowed,
901            None => return Err(EarlyDataError::ExceededAllowedEarlyData),
902        };
903
904        self.conn
905            .core
906            .common_state
907            .write_plaintext(early_data[..allowed].into(), outgoing_tls)
908            .map_err(|e| e.into())
909    }
910}
911
912/// Errors that may arise when encrypting early (RTT-0) data
913#[derive(Debug)]
914pub enum EarlyDataError {
915    /// Cannot encrypt more early data due to imposed limits
916    ExceededAllowedEarlyData,
917    /// Encryption error
918    Encrypt(EncryptError),
919}
920
921impl From<EncryptError> for EarlyDataError {
922    fn from(v: EncryptError) -> Self {
923        Self::Encrypt(v)
924    }
925}
926
927impl fmt::Display for EarlyDataError {
928    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
929        match self {
930            Self::ExceededAllowedEarlyData => f.write_str("cannot send any more early data"),
931            Self::Encrypt(e) => fmt::Display::fmt(e, f),
932        }
933    }
934}
935
936#[cfg(feature = "std")]
937impl std::error::Error for EarlyDataError {}
938
939/// State associated with a client connection.
940#[derive(Debug)]
941pub struct ClientConnectionData {
942    pub(super) early_data: EarlyData,
943    pub(super) resumption_ciphersuite: Option<SupportedCipherSuite>,
944    pub(super) ech_status: EchStatus,
945    pub(super) fips: bool,
946}
947
948impl ClientConnectionData {
949    fn new() -> Self {
950        Self {
951            early_data: EarlyData::new(),
952            resumption_ciphersuite: None,
953            ech_status: EchStatus::NotOffered,
954            fips: false,
955        }
956    }
957}
958
959impl crate::conn::SideData for ClientConnectionData {}