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