rustls/client/
builder.rs

1use alloc::sync::Arc;
2use alloc::vec::Vec;
3use core::marker::PhantomData;
4
5use pki_types::{CertificateDer, PrivateKeyDer};
6
7use super::client_conn::Resumption;
8use crate::builder::{ConfigBuilder, WantsVerifier};
9use crate::client::{handy, ClientConfig, EchMode, ResolvesClientCert};
10use crate::crypto::CryptoProvider;
11use crate::error::Error;
12use crate::key_log::NoKeyLog;
13use crate::msgs::handshake::CertificateChain;
14use crate::time_provider::TimeProvider;
15use crate::versions::TLS13;
16use crate::webpki::{self, WebPkiServerVerifier};
17use crate::{compress, verify, versions, WantsVersions};
18
19impl ConfigBuilder<ClientConfig, WantsVersions> {
20    /// Enable Encrypted Client Hello (ECH) in the given mode.
21    ///
22    /// This implicitly selects TLS 1.3 as the only supported protocol version to meet the
23    /// requirement to support ECH.
24    ///
25    /// The `ClientConfig` that will be produced by this builder will be specific to the provided
26    /// [`crate::client::EchConfig`] and may not be appropriate for all connections made by the program.
27    /// In this case the configuration should only be shared by connections intended for domains
28    /// that offer the provided [`crate::client::EchConfig`] in their DNS zone.
29    pub fn with_ech(
30        self,
31        mode: EchMode,
32    ) -> Result<ConfigBuilder<ClientConfig, WantsVerifier>, Error> {
33        let mut res = self.with_protocol_versions(&[&TLS13][..])?;
34        res.state.client_ech_mode = Some(mode);
35        Ok(res)
36    }
37}
38
39impl ConfigBuilder<ClientConfig, WantsVerifier> {
40    /// Choose how to verify server certificates.
41    ///
42    /// Using this function does not configure revocation.  If you wish to
43    /// configure revocation, instead use:
44    ///
45    /// ```diff
46    /// - .with_root_certificates(root_store)
47    /// + .with_webpki_verifier(
48    /// +   WebPkiServerVerifier::builder_with_provider(root_store, crypto_provider)
49    /// +   .with_crls(...)
50    /// +   .build()?
51    /// + )
52    /// ```
53    pub fn with_root_certificates(
54        self,
55        root_store: impl Into<Arc<webpki::RootCertStore>>,
56    ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
57        let algorithms = self
58            .state
59            .provider
60            .signature_verification_algorithms;
61        self.with_webpki_verifier(
62            WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(),
63        )
64    }
65
66    /// Choose how to verify server certificates using a webpki verifier.
67    ///
68    /// See [`webpki::WebPkiServerVerifier::builder`] and
69    /// [`webpki::WebPkiServerVerifier::builder_with_provider`] for more information.
70    pub fn with_webpki_verifier(
71        self,
72        verifier: Arc<WebPkiServerVerifier>,
73    ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
74        ConfigBuilder {
75            state: WantsClientCert {
76                provider: self.state.provider,
77                versions: self.state.versions,
78                verifier,
79                time_provider: self.state.time_provider,
80                client_ech_mode: self.state.client_ech_mode,
81            },
82            side: PhantomData,
83        }
84    }
85
86    /// Access configuration options whose use is dangerous and requires
87    /// extra care.
88    pub fn dangerous(self) -> danger::DangerousClientConfigBuilder {
89        danger::DangerousClientConfigBuilder { cfg: self }
90    }
91}
92
93/// Container for unsafe APIs
94pub(super) mod danger {
95    use alloc::sync::Arc;
96    use core::marker::PhantomData;
97
98    use crate::client::WantsClientCert;
99    use crate::{verify, ClientConfig, ConfigBuilder, WantsVerifier};
100
101    /// Accessor for dangerous configuration options.
102    #[derive(Debug)]
103    pub struct DangerousClientConfigBuilder {
104        /// The underlying ClientConfigBuilder
105        pub cfg: ConfigBuilder<ClientConfig, WantsVerifier>,
106    }
107
108    impl DangerousClientConfigBuilder {
109        /// Set a custom certificate verifier.
110        pub fn with_custom_certificate_verifier(
111            self,
112            verifier: Arc<dyn verify::ServerCertVerifier>,
113        ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
114            ConfigBuilder {
115                state: WantsClientCert {
116                    provider: self.cfg.state.provider,
117                    versions: self.cfg.state.versions,
118                    verifier,
119                    time_provider: self.cfg.state.time_provider,
120                    client_ech_mode: self.cfg.state.client_ech_mode,
121                },
122                side: PhantomData,
123            }
124        }
125    }
126}
127
128/// A config builder state where the caller needs to supply whether and how to provide a client
129/// certificate.
130///
131/// For more information, see the [`ConfigBuilder`] documentation.
132#[derive(Clone)]
133pub struct WantsClientCert {
134    provider: Arc<CryptoProvider>,
135    versions: versions::EnabledVersions,
136    verifier: Arc<dyn verify::ServerCertVerifier>,
137    time_provider: Arc<dyn TimeProvider>,
138    client_ech_mode: Option<EchMode>,
139}
140
141impl ConfigBuilder<ClientConfig, WantsClientCert> {
142    /// Sets a single certificate chain and matching private key for use
143    /// in client authentication.
144    ///
145    /// `cert_chain` is a vector of DER-encoded certificates.
146    /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The
147    /// `aws-lc-rs` and `ring` [`CryptoProvider`]s support all three encodings,
148    /// but other `CryptoProviders` may not.
149    ///
150    /// This function fails if `key_der` is invalid.
151    pub fn with_client_auth_cert(
152        self,
153        cert_chain: Vec<CertificateDer<'static>>,
154        key_der: PrivateKeyDer<'static>,
155    ) -> Result<ClientConfig, Error> {
156        let private_key = self
157            .state
158            .provider
159            .key_provider
160            .load_private_key(key_der)?;
161        let resolver =
162            handy::AlwaysResolvesClientCert::new(private_key, CertificateChain(cert_chain))?;
163        Ok(self.with_client_cert_resolver(Arc::new(resolver)))
164    }
165
166    /// Do not support client auth.
167    pub fn with_no_client_auth(self) -> ClientConfig {
168        self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {}))
169    }
170
171    /// Sets a custom [`ResolvesClientCert`].
172    pub fn with_client_cert_resolver(
173        self,
174        client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
175    ) -> ClientConfig {
176        ClientConfig {
177            provider: self.state.provider,
178            alpn_protocols: Vec::new(),
179            resumption: Resumption::default(),
180            max_fragment_size: None,
181            client_auth_cert_resolver,
182            versions: self.state.versions,
183            enable_sni: true,
184            verifier: self.state.verifier,
185            key_log: Arc::new(NoKeyLog {}),
186            enable_secret_extraction: false,
187            enable_early_data: false,
188            #[cfg(feature = "tls12")]
189            require_ems: cfg!(feature = "fips"),
190            time_provider: self.state.time_provider,
191            cert_compressors: compress::default_cert_compressors().to_vec(),
192            cert_compression_cache: Arc::new(compress::CompressionCache::default()),
193            cert_decompressors: compress::default_cert_decompressors().to_vec(),
194            ech_mode: self.state.client_ech_mode,
195        }
196    }
197}