rustls/client/
client_conn.rs

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