portable_rustls/client/
client_conn.rs

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