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