1use crate::builder::ConfigBuilder;
2use crate::common_state::{CommonState, Protocol, Side};
3use crate::conn::{ConnectionCommon, ConnectionCore};
4use crate::crypto::{CryptoProvider, SupportedKxGroup};
5use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme};
6use crate::error::Error;
7#[cfg(feature = "logging")]
8use crate::log::trace;
9use crate::msgs::enums::NamedGroup;
10use crate::msgs::handshake::ClientExtension;
11use crate::msgs::persist;
12use crate::sign;
13use crate::suites::{ExtractedSecrets, SupportedCipherSuite};
14use crate::versions;
15use crate::KeyLog;
16#[cfg(feature = "ring")]
17use crate::WantsVerifier;
18use crate::{verify, WantsVersions};
19
20use super::handy::{ClientSessionMemoryCache, NoClientSessionStorage};
21use super::hs;
22
23use pki_types::ServerName;
24
25use alloc::sync::Arc;
26use alloc::vec::Vec;
27use core::fmt;
28use core::marker::PhantomData;
29use core::mem;
30use core::ops::{Deref, DerefMut};
31use std::io;
32
33#[cfg(doc)]
34use crate::{crypto, DistinguishedName};
35
36/// A trait for the ability to store client session data, so that sessions
37/// can be resumed in future connections.
38///
39/// Generally all data in this interface should be treated as
40/// **highly sensitive**, containing enough key material to break all security
41/// of the corresponding session.
42///
43/// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't
44/// expressed in the type system to allow implementations freedom in
45/// how to achieve interior mutability. `Mutex` is a common choice.
46pub trait ClientSessionStore: fmt::Debug + Send + Sync {
47 /// Remember what `NamedGroup` the given server chose.
48 fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup);
49
50 /// This should return the value most recently passed to `set_kx_hint`
51 /// for the given `server_name`.
52 ///
53 /// If `None` is returned, the caller chooses the first configured group,
54 /// and an extra round trip might happen if that choice is unsatisfactory
55 /// to the server.
56 fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup>;
57
58 /// Remember a TLS1.2 session.
59 ///
60 /// At most one of these can be remembered at a time, per `server_name`.
61 fn set_tls12_session(
62 &self,
63 server_name: ServerName<'static>,
64 value: persist::Tls12ClientSessionValue,
65 );
66
67 /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`.
68 fn tls12_session(
69 &self,
70 server_name: &ServerName<'_>,
71 ) -> Option<persist::Tls12ClientSessionValue>;
72
73 /// Remove and forget any saved TLS1.2 session for `server_name`.
74 fn remove_tls12_session(&self, server_name: &ServerName<'static>);
75
76 /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing
77 /// resumption of this session.
78 ///
79 /// This can be called multiple times for a given session, allowing multiple independent tickets
80 /// to be valid at once. The number of times this is called is controlled by the server, so
81 /// implementations of this trait should apply a reasonable bound of how many items are stored
82 /// simultaneously.
83 fn insert_tls13_ticket(
84 &self,
85 server_name: ServerName<'static>,
86 value: persist::Tls13ClientSessionValue,
87 );
88
89 /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`.
90 ///
91 /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_.
92 fn take_tls13_ticket(
93 &self,
94 server_name: &ServerName<'static>,
95 ) -> Option<persist::Tls13ClientSessionValue>;
96}
97
98/// A trait for the ability to choose a certificate chain and
99/// private key for the purposes of client authentication.
100pub trait ResolvesClientCert: fmt::Debug + Send + Sync {
101 /// Resolve a client certificate chain/private key to use as the client's
102 /// identity.
103 ///
104 /// `root_hint_subjects` is an optional list of certificate authority
105 /// subject distinguished names that the client can use to help
106 /// decide on a client certificate the server is likely to accept. If
107 /// the list is empty, the client should send whatever certificate it
108 /// has. The hints are expected to be DER-encoded X.500 distinguished names,
109 /// per [RFC 5280 A.1]. See [`DistinguishedName`] for more information
110 /// on decoding with external crates like `x509-parser`.
111 ///
112 /// `sigschemes` is the list of the [`SignatureScheme`]s the server
113 /// supports.
114 ///
115 /// Return `None` to continue the handshake without any client
116 /// authentication. The server may reject the handshake later
117 /// if it requires authentication.
118 ///
119 /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
120 fn resolve(
121 &self,
122 root_hint_subjects: &[&[u8]],
123 sigschemes: &[SignatureScheme],
124 ) -> Option<Arc<sign::CertifiedKey>>;
125
126 /// Return true if any certificates at all are available.
127 fn has_certs(&self) -> bool;
128}
129
130/// Common configuration for (typically) all connections made by a program.
131///
132/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots
133/// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()`
134/// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred
135/// milliseconds.
136///
137/// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder_with_provider()`]
138/// function.
139///
140/// # Defaults
141///
142/// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB).
143/// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session
144/// ids or tickets, with a max of eight tickets per server.
145/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated.
146/// * [`ClientConfig::key_log`]: key material is not logged.
147///
148/// [`RootCertStore`]: crate::RootCertStore
149#[derive(Debug)]
150pub struct ClientConfig {
151 /// Source of randomness and other crypto.
152 pub(super) provider: Arc<CryptoProvider>,
153
154 /// Which ALPN protocols we include in our client hello.
155 /// If empty, no ALPN extension is sent.
156 pub alpn_protocols: Vec<Vec<u8>>,
157
158 /// How and when the client can resume a previous session.
159 pub resumption: Resumption,
160
161 /// The maximum size of plaintext input to be emitted in a single TLS record.
162 /// A value of None is equivalent to the [TLS maximum] of 16 kB.
163 ///
164 /// rustls enforces an arbitrary minimum of 32 bytes for this field.
165 /// Out of range values are reported as errors from [ClientConnection::new].
166 ///
167 /// Setting this value to a little less than the TCP MSS may improve latency
168 /// for stream-y workloads.
169 ///
170 /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1
171 /// [ClientConnection::new]: crate::client::ClientConnection::new
172 pub max_fragment_size: Option<usize>,
173
174 /// How to decide what client auth certificate/keys to use.
175 pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
176
177 /// Supported versions, in no particular order. The default
178 /// is all supported versions.
179 pub(super) versions: versions::EnabledVersions,
180
181 /// Whether to send the Server Name Indication (SNI) extension
182 /// during the client handshake.
183 ///
184 /// The default is true.
185 pub enable_sni: bool,
186
187 /// How to verify the server certificate chain.
188 pub(super) verifier: Arc<dyn verify::ServerCertVerifier>,
189
190 /// How to output key material for debugging. The default
191 /// does nothing.
192 pub key_log: Arc<dyn KeyLog>,
193
194 /// Allows traffic secrets to be extracted after the handshake,
195 /// e.g. for kTLS setup.
196 pub enable_secret_extraction: bool,
197
198 /// Whether to send data on the first flight ("early data") in
199 /// TLS 1.3 handshakes.
200 ///
201 /// The default is false.
202 pub enable_early_data: bool,
203}
204
205/// What mechanisms to support for resuming a TLS 1.2 session.
206#[derive(Clone, Copy, Debug, PartialEq)]
207pub enum Tls12Resumption {
208 /// Disable 1.2 resumption.
209 Disabled,
210 /// Support 1.2 resumption using session ids only.
211 SessionIdOnly,
212 /// Support 1.2 resumption using session ids or RFC 5077 tickets.
213 ///
214 /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly`
215 /// option. Note that TLS 1.3 tickets do not have those issues.
216 ///
217 /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/>
218 SessionIdOrTickets,
219}
220
221impl Clone for ClientConfig {
222 fn clone(&self) -> Self {
223 Self {
224 provider: Arc::<CryptoProvider>::clone(&self.provider),
225 resumption: self.resumption.clone(),
226 alpn_protocols: self.alpn_protocols.clone(),
227 max_fragment_size: self.max_fragment_size,
228 client_auth_cert_resolver: Arc::clone(&self.client_auth_cert_resolver),
229 versions: self.versions,
230 enable_sni: self.enable_sni,
231 verifier: Arc::clone(&self.verifier),
232 key_log: Arc::clone(&self.key_log),
233 enable_secret_extraction: self.enable_secret_extraction,
234 enable_early_data: self.enable_early_data,
235 }
236 }
237}
238
239impl ClientConfig {
240 /// Create a builder for a client configuration with the default
241 /// [`CryptoProvider`]: [`crypto::ring::default_provider`] and safe ciphersuite and
242 /// protocol defaults.
243 ///
244 /// For more information, see the [`ConfigBuilder`] documentation.
245 #[cfg(feature = "ring")]
246 pub fn builder() -> ConfigBuilder<Self, WantsVerifier> {
247 // Safety: we know the *ring* provider's ciphersuites are compatible with the safe default protocol versions.
248 Self::builder_with_provider(crate::crypto::ring::default_provider().into())
249 .with_safe_default_protocol_versions()
250 .unwrap()
251 }
252
253 /// Create a builder for a client configuration with the default
254 /// [`CryptoProvider`]: [`crypto::ring::default_provider`], safe ciphersuite defaults and
255 /// the provided protocol versions.
256 ///
257 /// Panics if provided an empty slice of supported versions.
258 ///
259 /// For more information, see the [`ConfigBuilder`] documentation.
260 #[cfg(feature = "ring")]
261 pub fn builder_with_protocol_versions(
262 versions: &[&'static versions::SupportedProtocolVersion],
263 ) -> ConfigBuilder<Self, WantsVerifier> {
264 // Safety: we know the *ring* provider's ciphersuites are compatible with all protocol version choices.
265 Self::builder_with_provider(crate::crypto::ring::default_provider().into())
266 .with_protocol_versions(versions)
267 .unwrap()
268 }
269
270 /// Create a builder for a client configuration with a specific [`CryptoProvider`].
271 ///
272 /// This will use the provider's configured ciphersuites. You must additionally choose
273 /// which protocol versions to enable, using `with_protocol_versions` or
274 /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol
275 /// version is not supported by the provider's ciphersuites.
276 ///
277 /// For more information, see the [`ConfigBuilder`] documentation.
278 pub fn builder_with_provider(
279 provider: Arc<CryptoProvider>,
280 ) -> ConfigBuilder<Self, WantsVersions> {
281 ConfigBuilder {
282 state: WantsVersions { provider },
283 side: PhantomData,
284 }
285 }
286
287 /// We support a given TLS version if it's quoted in the configured
288 /// versions *and* at least one ciphersuite for this version is
289 /// also configured.
290 pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool {
291 self.versions.contains(v)
292 && self
293 .provider
294 .cipher_suites
295 .iter()
296 .any(|cs| cs.version().version == v)
297 }
298
299 pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool {
300 self.provider
301 .cipher_suites
302 .iter()
303 .any(|cs| cs.usable_for_protocol(proto))
304 }
305
306 /// Access configuration options whose use is dangerous and requires
307 /// extra care.
308 pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> {
309 danger::DangerousClientConfig { cfg: self }
310 }
311
312 pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> {
313 self.provider
314 .cipher_suites
315 .iter()
316 .copied()
317 .find(|&scs| scs.suite() == suite)
318 }
319
320 pub(super) fn find_kx_group(&self, group: NamedGroup) -> Option<&'static dyn SupportedKxGroup> {
321 self.provider
322 .kx_groups
323 .iter()
324 .copied()
325 .find(|skxg| skxg.name() == group)
326 }
327}
328
329/// Configuration for how/when a client is allowed to resume a previous session.
330#[derive(Clone, Debug)]
331pub struct Resumption {
332 /// How we store session data or tickets. The default is to use an in-memory
333 /// [ClientSessionMemoryCache].
334 pub(super) store: Arc<dyn ClientSessionStore>,
335
336 /// What mechanism is used for resuming a TLS 1.2 session.
337 pub(super) tls12_resumption: Tls12Resumption,
338}
339
340impl Resumption {
341 /// Create a new `Resumption` that stores data for the given number of sessions in memory.
342 ///
343 /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with
344 /// a session id or RFC 5077 ticket.
345 pub fn in_memory_sessions(num: usize) -> Self {
346 Self {
347 store: Arc::new(ClientSessionMemoryCache::new(num)),
348 tls12_resumption: Tls12Resumption::SessionIdOrTickets,
349 }
350 }
351
352 /// Use a custom [`ClientSessionStore`] implementation to store sessions.
353 ///
354 /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket.
355 pub fn store(store: Arc<dyn ClientSessionStore>) -> Self {
356 Self {
357 store,
358 tls12_resumption: Tls12Resumption::SessionIdOrTickets,
359 }
360 }
361
362 /// Disable all use of session resumption.
363 pub fn disabled() -> Self {
364 Self {
365 store: Arc::new(NoClientSessionStorage),
366 tls12_resumption: Tls12Resumption::Disabled,
367 }
368 }
369
370 /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism.
371 ///
372 /// This is meaningless if you've disabled resumption entirely.
373 pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self {
374 self.tls12_resumption = tls12;
375 self
376 }
377}
378
379impl Default for Resumption {
380 /// Create an in-memory session store resumption with up to 256 server names, allowing
381 /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket.
382 fn default() -> Self {
383 Self::in_memory_sessions(num:256)
384 }
385}
386
387/// Container for unsafe APIs
388pub(super) mod danger {
389 use alloc::sync::Arc;
390
391 use super::verify::ServerCertVerifier;
392 use super::ClientConfig;
393
394 /// Accessor for dangerous configuration options.
395 #[derive(Debug)]
396 pub struct DangerousClientConfig<'a> {
397 /// The underlying ClientConfig
398 pub cfg: &'a mut ClientConfig,
399 }
400
401 impl<'a> DangerousClientConfig<'a> {
402 /// Overrides the default `ServerCertVerifier` with something else.
403 pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerCertVerifier>) {
404 self.cfg.verifier = verifier;
405 }
406 }
407}
408
409#[derive(Debug, PartialEq)]
410enum EarlyDataState {
411 Disabled,
412 Ready,
413 Accepted,
414 AcceptedFinished,
415 Rejected,
416}
417
418#[derive(Debug)]
419pub(super) struct EarlyData {
420 state: EarlyDataState,
421 left: usize,
422}
423
424impl EarlyData {
425 fn new() -> Self {
426 Self {
427 left: 0,
428 state: EarlyDataState::Disabled,
429 }
430 }
431
432 pub(super) fn is_enabled(&self) -> bool {
433 matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted)
434 }
435
436 fn is_accepted(&self) -> bool {
437 matches!(
438 self.state,
439 EarlyDataState::Accepted | EarlyDataState::AcceptedFinished
440 )
441 }
442
443 pub(super) fn enable(&mut self, max_data: usize) {
444 assert_eq!(self.state, EarlyDataState::Disabled);
445 self.state = EarlyDataState::Ready;
446 self.left = max_data;
447 }
448
449 pub(super) fn rejected(&mut self) {
450 trace!("EarlyData rejected");
451 self.state = EarlyDataState::Rejected;
452 }
453
454 pub(super) fn accepted(&mut self) {
455 trace!("EarlyData accepted");
456 assert_eq!(self.state, EarlyDataState::Ready);
457 self.state = EarlyDataState::Accepted;
458 }
459
460 pub(super) fn finished(&mut self) {
461 trace!("EarlyData finished");
462 self.state = match self.state {
463 EarlyDataState::Accepted => EarlyDataState::AcceptedFinished,
464 _ => panic!("bad EarlyData state"),
465 }
466 }
467
468 fn check_write(&mut self, sz: usize) -> io::Result<usize> {
469 match self.state {
470 EarlyDataState::Disabled => unreachable!(),
471 EarlyDataState::Ready | EarlyDataState::Accepted => {
472 let take = if self.left < sz {
473 mem::replace(&mut self.left, 0)
474 } else {
475 self.left -= sz;
476 sz
477 };
478
479 Ok(take)
480 }
481 EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => {
482 Err(io::Error::from(io::ErrorKind::InvalidInput))
483 }
484 }
485 }
486
487 fn bytes_left(&self) -> usize {
488 self.left
489 }
490}
491
492/// Stub that implements io::Write and dispatches to `write_early_data`.
493pub struct WriteEarlyData<'a> {
494 sess: &'a mut ClientConnection,
495}
496
497impl<'a> WriteEarlyData<'a> {
498 fn new(sess: &'a mut ClientConnection) -> WriteEarlyData<'a> {
499 WriteEarlyData { sess }
500 }
501
502 /// How many bytes you may send. Writes will become short
503 /// once this reaches zero.
504 pub fn bytes_left(&self) -> usize {
505 self.sess
506 .inner
507 .core
508 .data
509 .early_data
510 .bytes_left()
511 }
512}
513
514impl<'a> io::Write for WriteEarlyData<'a> {
515 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
516 self.sess.write_early_data(buf)
517 }
518
519 fn flush(&mut self) -> io::Result<()> {
520 Ok(())
521 }
522}
523
524/// This represents a single TLS client connection.
525pub struct ClientConnection {
526 inner: ConnectionCommon<ClientConnectionData>,
527}
528
529impl fmt::Debug for ClientConnection {
530 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
531 fDebugStruct<'_, '_>.debug_struct(name:"ClientConnection")
532 .finish()
533 }
534}
535
536impl ClientConnection {
537 /// Make a new ClientConnection. `config` controls how
538 /// we behave in the TLS protocol, `name` is the
539 /// name of the server we want to talk to.
540 pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> {
541 Ok(Self {
542 inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(),
543 })
544 }
545
546 /// Returns an `io::Write` implementer you can write bytes to
547 /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server.
548 ///
549 /// This returns None in many circumstances when the capability to
550 /// send early data is not available, including but not limited to:
551 ///
552 /// - The server hasn't been talked to previously.
553 /// - The server does not support resumption.
554 /// - The server does not support early data.
555 /// - The resumption data for the server has expired.
556 ///
557 /// The server specifies a maximum amount of early data. You can
558 /// learn this limit through the returned object, and writes through
559 /// it will process only this many bytes.
560 ///
561 /// The server can choose not to accept any sent early data --
562 /// in this case the data is lost but the connection continues. You
563 /// can tell this happened using `is_early_data_accepted`.
564 pub fn early_data(&mut self) -> Option<WriteEarlyData> {
565 if self
566 .inner
567 .core
568 .data
569 .early_data
570 .is_enabled()
571 {
572 Some(WriteEarlyData::new(self))
573 } else {
574 None
575 }
576 }
577
578 /// Returns True if the server signalled it will process early data.
579 ///
580 /// If you sent early data and this returns false at the end of the
581 /// handshake then the server will not process the data. This
582 /// is not an error, but you may wish to resend the data.
583 pub fn is_early_data_accepted(&self) -> bool {
584 self.inner.core.is_early_data_accepted()
585 }
586
587 /// Extract secrets, so they can be used when configuring kTLS, for example.
588 /// Should be used with care as it exposes secret key material.
589 pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> {
590 self.inner.dangerous_extract_secrets()
591 }
592
593 fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> {
594 self.inner
595 .core
596 .data
597 .early_data
598 .check_write(data.len())
599 .map(|sz| {
600 self.inner
601 .send_early_plaintext(&data[..sz])
602 })
603 }
604}
605
606impl Deref for ClientConnection {
607 type Target = ConnectionCommon<ClientConnectionData>;
608
609 fn deref(&self) -> &Self::Target {
610 &self.inner
611 }
612}
613
614impl DerefMut for ClientConnection {
615 fn deref_mut(&mut self) -> &mut Self::Target {
616 &mut self.inner
617 }
618}
619
620#[doc(hidden)]
621impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection {
622 type Error = ();
623
624 fn try_from(value: &'a mut crate::Connection) -> Result<Self, Self::Error> {
625 use crate::Connection::*;
626 match value {
627 Client(conn: &mut ClientConnection) => Ok(conn),
628 Server(_) => Err(()),
629 }
630 }
631}
632
633impl From<ClientConnection> for crate::Connection {
634 fn from(conn: ClientConnection) -> Self {
635 Self::Client(conn)
636 }
637}
638
639impl ConnectionCore<ClientConnectionData> {
640 pub(crate) fn for_client(
641 config: Arc<ClientConfig>,
642 name: ServerName<'static>,
643 extra_exts: Vec<ClientExtension>,
644 proto: Protocol,
645 ) -> Result<Self, Error> {
646 let mut common_state = CommonState::new(Side::Client);
647 common_state.set_max_fragment_size(config.max_fragment_size)?;
648 common_state.protocol = proto;
649 common_state.enable_secret_extraction = config.enable_secret_extraction;
650 let mut data = ClientConnectionData::new();
651
652 let mut cx = hs::ClientContext {
653 common: &mut common_state,
654 data: &mut data,
655 };
656
657 let state = hs::start_handshake(name, extra_exts, config, &mut cx)?;
658 Ok(Self::new(state, data, common_state))
659 }
660
661 pub(crate) fn is_early_data_accepted(&self) -> bool {
662 self.data.early_data.is_accepted()
663 }
664}
665
666/// State associated with a client connection.
667#[derive(Debug)]
668pub struct ClientConnectionData {
669 pub(super) early_data: EarlyData,
670 pub(super) resumption_ciphersuite: Option<SupportedCipherSuite>,
671}
672
673impl ClientConnectionData {
674 fn new() -> Self {
675 Self {
676 early_data: EarlyData::new(),
677 resumption_ciphersuite: None,
678 }
679 }
680}
681
682impl crate::conn::SideData for ClientConnectionData {}
683