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