rustls/client/
builder.rs

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