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