rustls/client/
config.rs

1use alloc::vec::Vec;
2use core::any::Any;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::marker::PhantomData;
6
7use pki_types::{PrivateKeyDer, ServerName, UnixTime};
8
9use super::ech::EchMode;
10#[cfg(feature = "std")]
11use super::handy::ClientSessionMemoryCache;
12use super::handy::{FailResolveClientCert, NoClientSessionStorage};
13use crate::builder::{ConfigBuilder, WantsVerifier};
14#[cfg(doc)]
15use crate::crypto;
16use crate::crypto::kx::NamedGroup;
17use crate::crypto::{
18    CipherSuite, Credentials, CryptoProvider, Identity, SelectedCredential, SignatureScheme,
19    SingleCredential, hash,
20};
21use crate::enums::{CertificateType, ProtocolVersion};
22use crate::error::{ApiMisuse, Error};
23use crate::key_log::NoKeyLog;
24use crate::msgs::persist;
25use crate::suites::SupportedCipherSuite;
26use crate::sync::Arc;
27#[cfg(feature = "std")]
28use crate::time_provider::DefaultTimeProvider;
29use crate::time_provider::TimeProvider;
30use crate::webpki::{self, WebPkiServerVerifier};
31use crate::{DistinguishedName, DynHasher, KeyLog, compress, verify};
32
33/// Common configuration for (typically) all connections made by a program.
34///
35/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots
36/// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()`
37/// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred
38/// milliseconds.
39///
40/// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder()`]
41/// function.
42///
43/// Note that using [`ConfigBuilder<ClientConfig, WantsVersions>::with_ech()`] will produce a common
44/// configuration specific to the provided [`crate::client::EchConfig`] that may not be appropriate
45/// for all connections made by the program. In this case the configuration should only be shared
46/// by connections intended for domains that offer the provided [`crate::client::EchConfig`] in
47/// their DNS zone.
48///
49/// # Defaults
50///
51/// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB).
52/// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session
53///   ids or tickets, with a max of eight tickets per server.
54/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated.
55/// * [`ClientConfig::key_log`]: key material is not logged.
56/// * [`ClientConfig::cert_decompressors`]: depends on the crate features, see [`compress::default_cert_decompressors()`].
57/// * [`ClientConfig::cert_compressors`]: depends on the crate features, see [`compress::default_cert_compressors()`].
58/// * [`ClientConfig::cert_compression_cache`]: caches the most recently used 4 compressions
59///
60/// [`RootCertStore`]: crate::RootCertStore
61#[derive(Clone, Debug)]
62pub struct ClientConfig {
63    /// Which ALPN protocols we include in our client hello.
64    /// If empty, no ALPN extension is sent.
65    pub alpn_protocols: Vec<Vec<u8>>,
66
67    /// How and when the client can resume a previous session.
68    ///
69    /// # Sharing `resumption` between `ClientConfig`s
70    /// In a program using many `ClientConfig`s it may improve resumption rates
71    /// (which has a significant impact on connection performance) if those
72    /// configs share a single `Resumption`.
73    ///
74    /// However, resumption is only allowed between two `ClientConfig`s if their
75    /// `client_auth_cert_resolver` (ie, potential client authentication credentials)
76    /// and `verifier` (ie, server certificate verification settings):
77    ///
78    /// - are the same type (determined by hashing their `TypeId`), and
79    /// - input the same data into [`ServerVerifier::hash_config()`] and
80    ///   [`ClientCredentialResolver::hash_config()`].
81    ///
82    /// To illustrate, imagine two `ClientConfig`s `A` and `B`.  `A` fully validates
83    /// the server certificate, `B` does not.  If `A` and `B` shared a resumption store,
84    /// it would be possible for a session originated by `B` to be inserted into the
85    /// store, and then resumed by `A`.  This would give a false impression to the user
86    /// of `A` that the server certificate is fully validated.
87    ///
88    /// [`ServerVerifier::hash_config()`]: verify::ServerVerifier::hash_config()
89    pub resumption: Resumption,
90
91    /// The maximum size of plaintext input to be emitted in a single TLS record.
92    /// A value of None is equivalent to the [TLS maximum] of 16 kB.
93    ///
94    /// rustls enforces an arbitrary minimum of 32 bytes for this field.
95    /// Out of range values are reported as errors from [ClientConnection::new].
96    ///
97    /// Setting this value to a little less than the TCP MSS may improve latency
98    /// for stream-y workloads.
99    ///
100    /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1
101    /// [ClientConnection::new]: crate::client::ClientConnection::new
102    pub max_fragment_size: Option<usize>,
103
104    /// Whether to send the Server Name Indication (SNI) extension
105    /// during the client handshake.
106    ///
107    /// The default is true.
108    pub enable_sni: bool,
109
110    /// How to output key material for debugging.  The default
111    /// does nothing.
112    pub key_log: Arc<dyn KeyLog>,
113
114    /// Allows traffic secrets to be extracted after the handshake,
115    /// e.g. for kTLS setup.
116    pub enable_secret_extraction: bool,
117
118    /// Whether to send data on the first flight ("early data") in
119    /// TLS 1.3 handshakes.
120    ///
121    /// The default is false.
122    pub enable_early_data: bool,
123
124    /// If set to `true`, requires the server to support the extended
125    /// master secret extraction method defined in [RFC 7627].
126    ///
127    /// The default is `true` if the `fips` crate feature is enabled,
128    /// `false` otherwise.
129    ///
130    /// It must be set to `true` to meet FIPS requirement mentioned in section
131    /// **D.Q Transition of the TLS 1.2 KDF to Support the Extended Master
132    /// Secret** from [FIPS 140-3 IG.pdf].
133    ///
134    /// [RFC 7627]: https://datatracker.ietf.org/doc/html/rfc7627
135    /// [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
136    pub require_ems: bool,
137
138    /// Items that affect the fundamental security properties of a connection.
139    pub(super) domain: SecurityDomain,
140
141    /// How to decompress the server's certificate chain.
142    ///
143    /// If this is non-empty, the [RFC8779] certificate compression
144    /// extension is offered, and any compressed certificates are
145    /// transparently decompressed during the handshake.
146    ///
147    /// This only applies to TLS1.3 connections.  It is ignored for
148    /// TLS1.2 connections.
149    ///
150    /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/
151    pub cert_decompressors: Vec<&'static dyn compress::CertDecompressor>,
152
153    /// How to compress the client's certificate chain.
154    ///
155    /// If a server supports this extension, and advertises support
156    /// for one of the compression algorithms included here, the
157    /// client certificate will be compressed according to [RFC8779].
158    ///
159    /// This only applies to TLS1.3 connections.  It is ignored for
160    /// TLS1.2 connections.
161    ///
162    /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/
163    pub cert_compressors: Vec<&'static dyn compress::CertCompressor>,
164
165    /// Caching for compressed certificates.
166    ///
167    /// This is optional: [`compress::CompressionCache::Disabled`] gives
168    /// a cache that does no caching.
169    pub cert_compression_cache: Arc<compress::CompressionCache>,
170
171    /// How to offer Encrypted Client Hello (ECH). The default is to not offer ECH.
172    pub(super) ech_mode: Option<EchMode>,
173}
174
175impl ClientConfig {
176    /// Create a builder for a client configuration with a specific [`CryptoProvider`].
177    ///
178    /// This will use the provider's configured ciphersuites.
179    ///
180    /// For more information, see the [`ConfigBuilder`] documentation.
181    #[cfg(feature = "std")]
182    pub fn builder(provider: Arc<CryptoProvider>) -> ConfigBuilder<Self, WantsVerifier> {
183        Self::builder_with_details(provider, Arc::new(DefaultTimeProvider))
184    }
185
186    /// Create a builder for a client configuration with no default implementation details.
187    ///
188    /// This API must be used by `no_std` users.
189    ///
190    /// You must provide a specific [`TimeProvider`].
191    ///
192    /// You must provide a specific [`CryptoProvider`].
193    ///
194    /// For more information, see the [`ConfigBuilder`] documentation.
195    pub fn builder_with_details(
196        provider: Arc<CryptoProvider>,
197        time_provider: Arc<dyn TimeProvider>,
198    ) -> ConfigBuilder<Self, WantsVerifier> {
199        ConfigBuilder {
200            state: WantsVerifier {
201                client_ech_mode: None,
202            },
203            provider,
204            time_provider,
205            side: PhantomData,
206        }
207    }
208
209    /// Access configuration options whose use is dangerous and requires
210    /// extra care.
211    pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> {
212        danger::DangerousClientConfig { cfg: self }
213    }
214
215    /// Return true if connections made with this `ClientConfig` will
216    /// operate in FIPS mode.
217    ///
218    /// This is different from [`CryptoProvider::fips()`]: [`CryptoProvider::fips()`]
219    /// is concerned only with cryptography, whereas this _also_ covers TLS-level
220    /// configuration that NIST recommends, as well as ECH HPKE suites if applicable.
221    pub fn fips(&self) -> bool {
222        let mut is_fips = self.domain.provider.fips() && self.require_ems;
223
224        if let Some(ech_mode) = &self.ech_mode {
225            is_fips = is_fips && ech_mode.fips();
226        }
227
228        is_fips
229    }
230
231    /// Return the crypto provider used to construct this client configuration.
232    pub fn provider(&self) -> &Arc<CryptoProvider> {
233        &self.domain.provider
234    }
235
236    /// Return the resolver for this client configuration.
237    ///
238    /// This is the object that determines which credentials to use for client
239    /// authentication.
240    pub fn resolver(&self) -> &Arc<dyn ClientCredentialResolver> {
241        &self.domain.client_auth_cert_resolver
242    }
243
244    /// Return the resolver for this client configuration.
245    ///
246    /// This is the object that determines which credentials to use for client
247    /// authentication.
248    pub fn verifier(&self) -> &Arc<dyn verify::ServerVerifier> {
249        &self.domain.verifier
250    }
251
252    pub(super) fn needs_key_share(&self) -> bool {
253        self.supports_version(ProtocolVersion::TLSv1_3)
254    }
255
256    pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool {
257        self.domain.provider.supports_version(v)
258    }
259
260    pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> {
261        self.domain
262            .provider
263            .iter_cipher_suites()
264            .find(|&scs| scs.suite() == suite)
265    }
266
267    pub(super) fn current_time(&self) -> Result<UnixTime, Error> {
268        self.domain
269            .time_provider
270            .current_time()
271            .ok_or(Error::FailedToGetCurrentTime)
272    }
273
274    /// A hash which partitions this config's use of the [`Self::resumption`] store.
275    pub(super) fn config_hash(&self) -> [u8; 32] {
276        self.domain.config_hash
277    }
278}
279
280struct HashAdapter<'a>(&'a mut dyn hash::Context);
281
282impl Hasher for HashAdapter<'_> {
283    fn finish(&self) -> u64 {
284        // SAFETY: this is private to `SecurityDomain::new`, which guarantees `hash::Output`
285        // is at least 32 bytes.
286        u64::from_be_bytes(
287            self.0.fork_finish().as_ref()[..8]
288                .try_into()
289                .unwrap(),
290        )
291    }
292
293    fn write(&mut self, bytes: &[u8]) {
294        self.0.update(bytes)
295    }
296}
297
298/// A trait for the ability to store client session data, so that sessions
299/// can be resumed in future connections.
300///
301/// Generally all data in this interface should be treated as
302/// **highly sensitive**, containing enough key material to break all security
303/// of the corresponding session.
304///
305/// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't
306/// expressed in the type system to allow implementations freedom in
307/// how to achieve interior mutability.  `Mutex` is a common choice.
308pub trait ClientSessionStore: fmt::Debug + Send + Sync {
309    /// Remember what `NamedGroup` the given server chose.
310    fn set_kx_hint(&self, key: ClientSessionKey<'static>, group: NamedGroup);
311
312    /// This should return the value most recently passed to `set_kx_hint`
313    /// for the given `key`.
314    ///
315    /// If `None` is returned, the caller chooses the first configured group,
316    /// and an extra round trip might happen if that choice is unsatisfactory
317    /// to the server.
318    fn kx_hint(&self, key: &ClientSessionKey<'_>) -> Option<NamedGroup>;
319
320    /// Remember a TLS1.2 session.
321    ///
322    /// At most one of these can be remembered at a time, per `server_name`.
323    fn set_tls12_session(
324        &self,
325        key: ClientSessionKey<'static>,
326        value: persist::Tls12ClientSessionValue,
327    );
328
329    /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`.
330    fn tls12_session(&self, key: &ClientSessionKey<'_>)
331    -> Option<persist::Tls12ClientSessionValue>;
332
333    /// Remove and forget any saved TLS1.2 session for `server_name`.
334    fn remove_tls12_session(&self, key: &ClientSessionKey<'static>);
335
336    /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing
337    /// resumption of this session.
338    ///
339    /// This can be called multiple times for a given session, allowing multiple independent tickets
340    /// to be valid at once.  The number of times this is called is controlled by the server, so
341    /// implementations of this trait should apply a reasonable bound of how many items are stored
342    /// simultaneously.
343    fn insert_tls13_ticket(
344        &self,
345        key: ClientSessionKey<'static>,
346        value: persist::Tls13ClientSessionValue,
347    );
348
349    /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`.
350    ///
351    /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_.
352    fn take_tls13_ticket(
353        &self,
354        key: &ClientSessionKey<'static>,
355    ) -> Option<persist::Tls13ClientSessionValue>;
356}
357
358/// Identifies a security context and server in the [`ClientSessionStore`] interface.
359#[derive(Clone, Debug, Eq, Hash, PartialEq)]
360#[non_exhaustive]
361pub struct ClientSessionKey<'a> {
362    /// A hash to partition the client storage between different security domains.
363    pub config_hash: [u8; 32],
364
365    /// Transport-level identity of the server.
366    pub server_name: ServerName<'a>,
367}
368
369impl ClientSessionKey<'_> {
370    /// Copy the value to own its contents.
371    pub fn to_owned(&self) -> ClientSessionKey<'static> {
372        let Self {
373            config_hash,
374            server_name,
375        } = self;
376        ClientSessionKey {
377            config_hash: *config_hash,
378            server_name: server_name.to_owned(),
379        }
380    }
381}
382
383/// A trait for the ability to choose a certificate chain and
384/// private key for the purposes of client authentication.
385pub trait ClientCredentialResolver: fmt::Debug + Send + Sync {
386    /// Resolve a client certificate chain/private key to use as the client's identity.
387    ///
388    /// The `SelectedCredential` returned from this method contains an identity and a
389    /// one-time-use [`Signer`] wrapping the private key. This is usually obtained via a
390    /// [`Credentials`], on which an implementation can call [`Credentials::signer()`].
391    /// An implementation can either store long-lived [`Credentials`] values, or instantiate
392    /// them as needed using one of its constructors.
393    ///
394    /// Return `None` to continue the handshake without any client
395    /// authentication.  The server may reject the handshake later
396    /// if it requires authentication.
397    ///
398    /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
399    ///
400    /// [`Credentials`]: crate::crypto::Credentials
401    /// [`Credentials::signer()`]: crate::crypto::Credentials::signer
402    /// [`Signer`]: crate::crypto::Signer
403    fn resolve(&self, request: &CredentialRequest<'_>) -> Option<SelectedCredential>;
404
405    /// Returns which [`CertificateType`]s this resolver supports.
406    ///
407    /// Should return the empty slice if the resolver does not have any credentials to send.
408    /// Implementations should return the same value every time.
409    ///
410    /// See [RFC 7250](https://tools.ietf.org/html/rfc7250) for more information.
411    fn supported_certificate_types(&self) -> &'static [CertificateType];
412
413    /// Instance configuration should be input to `h`.
414    fn hash_config(&self, h: &mut dyn Hasher);
415}
416
417/// Context from the server to inform client credential selection.
418pub struct CredentialRequest<'a> {
419    pub(super) negotiated_type: CertificateType,
420    pub(super) root_hint_subjects: &'a [DistinguishedName],
421    pub(super) signature_schemes: &'a [SignatureScheme],
422}
423
424impl CredentialRequest<'_> {
425    /// List of certificate authority subject distinguished names provided by the server.
426    ///
427    /// If the list is empty, the client should send whatever certificate it has. The hints
428    /// are expected to be DER-encoded X.500 distinguished names, per [RFC 5280 A.1]. Note that
429    /// the encoding comes from the server and has not been validated by rustls.
430    ///
431    /// See [`DistinguishedName`] for more information on decoding with external crates like
432    /// `x509-parser`.
433    ///
434    /// [`DistinguishedName`]: crate::DistinguishedName
435    pub fn root_hint_subjects(&self) -> &[DistinguishedName] {
436        self.root_hint_subjects
437    }
438
439    /// Get the compatible signature schemes.
440    pub fn signature_schemes(&self) -> &[SignatureScheme] {
441        self.signature_schemes
442    }
443
444    /// The negotiated certificate type.
445    ///
446    /// If the server does not support [RFC 7250], this will be `CertificateType::X509`.
447    ///
448    /// [RFC 7250]: https://tools.ietf.org/html/rfc7250
449    pub fn negotiated_type(&self) -> CertificateType {
450        self.negotiated_type
451    }
452}
453
454/// Items that affect the fundamental security properties of a connection.
455///
456/// This is its own type because `config_hash` depends on the other fields:
457/// fields therefore should not be mutated, but an entire object created
458/// through [`Self::new`] for any edits.
459#[derive(Clone, Debug)]
460pub(super) struct SecurityDomain {
461    /// Provides the current system time
462    time_provider: Arc<dyn TimeProvider>,
463
464    /// Source of randomness and other crypto.
465    provider: Arc<CryptoProvider>,
466
467    /// How to verify the server certificate chain.
468    verifier: Arc<dyn verify::ServerVerifier>,
469
470    /// How to decide what client auth certificate/keys to use.
471    client_auth_cert_resolver: Arc<dyn ClientCredentialResolver>,
472
473    config_hash: [u8; 32],
474}
475
476impl SecurityDomain {
477    pub(crate) fn new(
478        provider: Arc<CryptoProvider>,
479        client_auth_cert_resolver: Arc<dyn ClientCredentialResolver + 'static>,
480        verifier: Arc<dyn verify::ServerVerifier + 'static>,
481        time_provider: Arc<dyn TimeProvider + 'static>,
482    ) -> Self {
483        // Use a hash function that outputs at least 32 bytes.
484        let hash = provider
485            .iter_cipher_suites()
486            .map(|cs| cs.hash_provider())
487            .find(|h| h.output_len() >= 32)
488            .expect("no suitable cipher suite available (with |H| >= 32)"); // this is -- in practice -- all cipher suites
489
490        let mut h = hash.start();
491        let mut adapter = HashAdapter(h.as_mut());
492
493        // Include TypeId of impl, so two different types with different non-configured
494        // behavior do not collide even if their `hash_config()`s are the same.
495        client_auth_cert_resolver
496            .type_id()
497            .hash(&mut DynHasher(&mut adapter));
498        client_auth_cert_resolver.hash_config(&mut adapter);
499
500        verifier
501            .type_id()
502            .hash(&mut DynHasher(&mut adapter));
503        verifier.hash_config(&mut adapter);
504
505        time_provider
506            .type_id()
507            .hash(&mut DynHasher(&mut adapter));
508
509        let config_hash = h.finish().as_ref()[..32]
510            .try_into()
511            .unwrap();
512
513        Self {
514            time_provider,
515            provider,
516            verifier,
517            client_auth_cert_resolver,
518            config_hash,
519        }
520    }
521
522    fn with_verifier(&self, verifier: Arc<dyn verify::ServerVerifier + 'static>) -> Self {
523        let Self {
524            time_provider,
525            provider,
526            verifier: _,
527            client_auth_cert_resolver,
528            config_hash: _,
529        } = self;
530        Self::new(
531            provider.clone(),
532            client_auth_cert_resolver.clone(),
533            verifier,
534            time_provider.clone(),
535        )
536    }
537}
538
539/// Configuration for how/when a client is allowed to resume a previous session.
540#[derive(Clone, Debug)]
541pub struct Resumption {
542    /// How we store session data or tickets. The default is to use an in-memory
543    /// [super::handy::ClientSessionMemoryCache].
544    pub(super) store: Arc<dyn ClientSessionStore>,
545
546    /// What mechanism is used for resuming a TLS 1.2 session.
547    pub(super) tls12_resumption: Tls12Resumption,
548}
549
550impl Resumption {
551    /// Create a new `Resumption` that stores data for the given number of sessions in memory.
552    ///
553    /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with
554    /// a session id or RFC 5077 ticket.
555    #[cfg(feature = "std")]
556    pub fn in_memory_sessions(num: usize) -> Self {
557        Self {
558            store: Arc::new(ClientSessionMemoryCache::new(num)),
559            tls12_resumption: Tls12Resumption::SessionIdOrTickets,
560        }
561    }
562
563    /// Use a custom [`ClientSessionStore`] implementation to store sessions.
564    ///
565    /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket.
566    pub fn store(store: Arc<dyn ClientSessionStore>) -> Self {
567        Self {
568            store,
569            tls12_resumption: Tls12Resumption::SessionIdOrTickets,
570        }
571    }
572
573    /// Disable all use of session resumption.
574    pub fn disabled() -> Self {
575        Self {
576            store: Arc::new(NoClientSessionStorage),
577            tls12_resumption: Tls12Resumption::Disabled,
578        }
579    }
580
581    /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism.
582    ///
583    /// This is meaningless if you've disabled resumption entirely, which is the case in `no-std`
584    /// contexts.
585    pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self {
586        self.tls12_resumption = tls12;
587        self
588    }
589}
590
591impl Default for Resumption {
592    /// Create an in-memory session store resumption with up to 256 server names, allowing
593    /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket.
594    fn default() -> Self {
595        #[cfg(feature = "std")]
596        let ret = Self::in_memory_sessions(256);
597
598        #[cfg(not(feature = "std"))]
599        let ret = Self::disabled();
600
601        ret
602    }
603}
604
605/// What mechanisms to support for resuming a TLS 1.2 session.
606#[non_exhaustive]
607#[derive(Clone, Copy, Debug, PartialEq)]
608pub enum Tls12Resumption {
609    /// Disable 1.2 resumption.
610    Disabled,
611    /// Support 1.2 resumption using session ids only.
612    SessionIdOnly,
613    /// Support 1.2 resumption using session ids or RFC 5077 tickets.
614    ///
615    /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly`
616    /// option. Note that TLS 1.3 tickets do not have those issues.
617    ///
618    /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/>
619    SessionIdOrTickets,
620}
621
622impl ConfigBuilder<ClientConfig, WantsVerifier> {
623    /// Choose how to verify server certificates.
624    ///
625    /// Using this function does not configure revocation.  If you wish to
626    /// configure revocation, instead use:
627    ///
628    /// ```diff
629    /// - .with_root_certificates(root_store)
630    /// + .with_webpki_verifier(
631    /// +   WebPkiServerVerifier::builder(root_store, crypto_provider)
632    /// +   .with_crls(...)
633    /// +   .build()?
634    /// + )
635    /// ```
636    pub fn with_root_certificates(
637        self,
638        root_store: impl Into<Arc<webpki::RootCertStore>>,
639    ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
640        let algorithms = self
641            .provider
642            .signature_verification_algorithms;
643        self.with_webpki_verifier(
644            WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(),
645        )
646    }
647
648    /// Choose how to verify server certificates using a webpki verifier.
649    ///
650    /// See [`webpki::WebPkiServerVerifier::builder`] and
651    /// [`webpki::WebPkiServerVerifier::builder`] for more information.
652    pub fn with_webpki_verifier(
653        self,
654        verifier: Arc<WebPkiServerVerifier>,
655    ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
656        ConfigBuilder {
657            state: WantsClientCert {
658                verifier,
659                client_ech_mode: self.state.client_ech_mode,
660            },
661            provider: self.provider,
662            time_provider: self.time_provider,
663            side: PhantomData,
664        }
665    }
666
667    /// Enable Encrypted Client Hello (ECH) in the given mode.
668    ///
669    /// This requires TLS 1.3 as the only supported protocol version to meet the requirement
670    /// to support ECH.  At the end, the config building process will return an error if either
671    /// TLS1.3 _is not_ supported by the provider, or TLS1.2 _is_ supported.
672    ///
673    /// The `ClientConfig` that will be produced by this builder will be specific to the provided
674    /// [`crate::client::EchConfig`] and may not be appropriate for all connections made by the program.
675    /// In this case the configuration should only be shared by connections intended for domains
676    /// that offer the provided [`crate::client::EchConfig`] in their DNS zone.
677    pub fn with_ech(mut self, mode: EchMode) -> Self {
678        self.state.client_ech_mode = Some(mode);
679        self
680    }
681
682    /// Access configuration options whose use is dangerous and requires
683    /// extra care.
684    pub fn dangerous(self) -> danger::DangerousClientConfigBuilder {
685        danger::DangerousClientConfigBuilder { cfg: self }
686    }
687}
688
689/// A config builder state where the caller needs to supply whether and how to provide a client
690/// certificate.
691///
692/// For more information, see the [`ConfigBuilder`] documentation.
693#[derive(Clone)]
694pub struct WantsClientCert {
695    verifier: Arc<dyn verify::ServerVerifier>,
696    client_ech_mode: Option<EchMode>,
697}
698
699impl ConfigBuilder<ClientConfig, WantsClientCert> {
700    /// Sets a single certificate chain and matching private key for use
701    /// in client authentication.
702    ///
703    /// `cert_chain` is a vector of DER-encoded certificates.
704    /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The
705    /// `aws-lc-rs` and `ring` [`CryptoProvider`]s support
706    /// all three encodings, but other `CryptoProviders` may not.
707    ///
708    /// This function fails if `key_der` is invalid.
709    pub fn with_client_auth_cert(
710        self,
711        identity: Arc<Identity<'static>>,
712        key_der: PrivateKeyDer<'static>,
713    ) -> Result<ClientConfig, Error> {
714        let credentials = Credentials::from_der(identity, key_der, &self.provider)?;
715        self.with_client_credential_resolver(Arc::new(SingleCredential::from(credentials)))
716    }
717
718    /// Do not support client auth.
719    pub fn with_no_client_auth(self) -> Result<ClientConfig, Error> {
720        self.with_client_credential_resolver(Arc::new(FailResolveClientCert {}))
721    }
722
723    /// Sets a custom [`ClientCredentialResolver`].
724    pub fn with_client_credential_resolver(
725        self,
726        client_auth_cert_resolver: Arc<dyn ClientCredentialResolver>,
727    ) -> Result<ClientConfig, Error> {
728        self.provider.consistency_check()?;
729
730        if self.state.client_ech_mode.is_some() {
731            match (
732                self.provider
733                    .tls12_cipher_suites
734                    .is_empty(),
735                self.provider
736                    .tls13_cipher_suites
737                    .is_empty(),
738            ) {
739                (_, true) => return Err(ApiMisuse::EchRequiresTls13Support.into()),
740                (false, _) => return Err(ApiMisuse::EchForbidsTls12Support.into()),
741                (true, false) => {}
742            };
743        }
744
745        Ok(ClientConfig {
746            domain: SecurityDomain::new(
747                self.provider,
748                client_auth_cert_resolver,
749                self.state.verifier,
750                self.time_provider,
751            ),
752            alpn_protocols: Vec::new(),
753            resumption: Resumption::default(),
754            max_fragment_size: None,
755            enable_sni: true,
756            key_log: Arc::new(NoKeyLog {}),
757            enable_secret_extraction: false,
758            enable_early_data: false,
759            require_ems: cfg!(feature = "fips"),
760            cert_compressors: compress::default_cert_compressors().to_vec(),
761            cert_compression_cache: Arc::new(compress::CompressionCache::default()),
762            cert_decompressors: compress::default_cert_decompressors().to_vec(),
763            ech_mode: self.state.client_ech_mode,
764        })
765    }
766}
767
768/// Container for unsafe APIs
769pub(super) mod danger {
770    use core::marker::PhantomData;
771
772    use crate::client::WantsClientCert;
773    use crate::client::config::ClientConfig;
774    use crate::sync::Arc;
775    use crate::verify::ServerVerifier;
776    use crate::{ConfigBuilder, WantsVerifier};
777
778    /// Accessor for dangerous configuration options.
779    #[derive(Debug)]
780    pub struct DangerousClientConfig<'a> {
781        /// The underlying ClientConfig
782        pub(super) cfg: &'a mut ClientConfig,
783    }
784
785    impl DangerousClientConfig<'_> {
786        /// Overrides the default `ServerVerifier` with something else.
787        pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerVerifier>) {
788            self.cfg.domain = self.cfg.domain.with_verifier(verifier);
789        }
790    }
791
792    /// Accessor for dangerous configuration options.
793    #[derive(Debug)]
794    pub struct DangerousClientConfigBuilder {
795        /// The underlying ClientConfigBuilder
796        pub(super) cfg: ConfigBuilder<ClientConfig, WantsVerifier>,
797    }
798
799    impl DangerousClientConfigBuilder {
800        /// Set a custom certificate verifier.
801        pub fn with_custom_certificate_verifier(
802            self,
803            verifier: Arc<dyn ServerVerifier>,
804        ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
805            ConfigBuilder {
806                state: WantsClientCert {
807                    verifier,
808                    client_ech_mode: self.cfg.state.client_ech_mode,
809                },
810                provider: self.cfg.provider,
811                time_provider: self.cfg.time_provider,
812                side: PhantomData,
813            }
814        }
815    }
816}