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 {}