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