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