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