rustls_jls/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::error::Error;
10use crate::key_log::NoKeyLog;
11use crate::sign::{CertifiedKey, SingleCertAndKey};
12use crate::sync::Arc;
13use crate::versions::TLS13;
14use crate::webpki::{self, WebPkiServerVerifier};
15use crate::{WantsVersions, compress, verify, versions};
16
17use crate::jls::JlsConfig;
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            .provider
59            .signature_verification_algorithms;
60        self.with_webpki_verifier(
61            WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(),
62        )
63    }
64
65    /// Choose how to verify server certificates using a webpki verifier.
66    ///
67    /// See [`webpki::WebPkiServerVerifier::builder`] and
68    /// [`webpki::WebPkiServerVerifier::builder_with_provider`] for more information.
69    pub fn with_webpki_verifier(
70        self,
71        verifier: Arc<WebPkiServerVerifier>,
72    ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
73        ConfigBuilder {
74            state: WantsClientCert {
75                versions: self.state.versions,
76                verifier,
77                client_ech_mode: self.state.client_ech_mode,
78            },
79            provider: self.provider,
80            time_provider: self.time_provider,
81            side: PhantomData,
82        }
83    }
84
85    /// Access configuration options whose use is dangerous and requires
86    /// extra care.
87    pub fn dangerous(self) -> danger::DangerousClientConfigBuilder {
88        danger::DangerousClientConfigBuilder { cfg: self }
89    }
90}
91
92/// Container for unsafe APIs
93pub(super) mod danger {
94    use core::marker::PhantomData;
95
96    use crate::client::WantsClientCert;
97    use crate::sync::Arc;
98    use crate::{ClientConfig, ConfigBuilder, WantsVerifier, verify};
99
100    /// Accessor for dangerous configuration options.
101    #[derive(Debug)]
102    pub struct DangerousClientConfigBuilder {
103        /// The underlying ClientConfigBuilder
104        pub cfg: ConfigBuilder<ClientConfig, WantsVerifier>,
105    }
106
107    impl DangerousClientConfigBuilder {
108        /// Set a custom certificate verifier.
109        pub fn with_custom_certificate_verifier(
110            self,
111            verifier: Arc<dyn verify::ServerCertVerifier>,
112        ) -> ConfigBuilder<ClientConfig, WantsClientCert> {
113            ConfigBuilder {
114                state: WantsClientCert {
115                    versions: self.cfg.state.versions,
116                    verifier,
117                    client_ech_mode: self.cfg.state.client_ech_mode,
118                },
119                provider: self.cfg.provider,
120                time_provider: self.cfg.time_provider,
121                side: PhantomData,
122            }
123        }
124    }
125}
126
127/// A config builder state where the caller needs to supply whether and how to provide a client
128/// certificate.
129///
130/// For more information, see the [`ConfigBuilder`] documentation.
131#[derive(Clone)]
132pub struct WantsClientCert {
133    versions: versions::EnabledVersions,
134    verifier: Arc<dyn verify::ServerCertVerifier>,
135    client_ech_mode: Option<EchMode>,
136}
137
138impl ConfigBuilder<ClientConfig, WantsClientCert> {
139    /// Sets a single certificate chain and matching private key for use
140    /// in client authentication.
141    ///
142    /// `cert_chain` is a vector of DER-encoded certificates.
143    /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The
144    /// `aws-lc-rs` and `ring` [`CryptoProvider`][crate::CryptoProvider]s support
145    /// all three encodings, but other `CryptoProviders` may not.
146    ///
147    /// This function fails if `key_der` is invalid.
148    pub fn with_client_auth_cert(
149        self,
150        cert_chain: Vec<CertificateDer<'static>>,
151        key_der: PrivateKeyDer<'static>,
152    ) -> Result<ClientConfig, Error> {
153        let certified_key = CertifiedKey::from_der(cert_chain, key_der, &self.provider)?;
154        Ok(self.with_client_cert_resolver(Arc::new(SingleCertAndKey::from(certified_key))))
155    }
156
157    /// Do not support client auth.
158    pub fn with_no_client_auth(self) -> ClientConfig {
159        self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {}))
160    }
161
162    /// Sets a custom [`ResolvesClientCert`].
163    pub fn with_client_cert_resolver(
164        self,
165        client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
166    ) -> ClientConfig {
167        ClientConfig {
168            provider: self.provider,
169            alpn_protocols: Vec::new(),
170            resumption: Resumption::default(),
171            max_fragment_size: None,
172            client_auth_cert_resolver,
173            versions: self.state.versions,
174            enable_sni: true,
175            verifier: self.state.verifier,
176            key_log: Arc::new(NoKeyLog {}),
177            enable_secret_extraction: false,
178            enable_early_data: false,
179            jls_config: JlsConfig::default(),
180            #[cfg(feature = "tls12")]
181            require_ems: cfg!(feature = "fips"),
182            time_provider: self.time_provider,
183            cert_compressors: compress::default_cert_compressors().to_vec(),
184            cert_compression_cache: Arc::new(compress::CompressionCache::default()),
185            cert_decompressors: compress::default_cert_decompressors().to_vec(),
186            ech_mode: self.state.client_ech_mode,
187        }
188    }
189}