clia_rustls_mod/
builder.rs

1use alloc::format;
2use alloc::sync::Arc;
3use alloc::vec::Vec;
4use core::fmt;
5use core::marker::PhantomData;
6
7use crate::crypto::CryptoProvider;
8use crate::error::Error;
9use crate::msgs::handshake::ALL_KEY_EXCHANGE_ALGORITHMS;
10use crate::time_provider::TimeProvider;
11use crate::versions;
12#[cfg(doc)]
13use crate::{ClientConfig, ServerConfig};
14
15/// A [builder] for [`ServerConfig`] or [`ClientConfig`] values.
16///
17/// To get one of these, call [`ServerConfig::builder()`] or [`ClientConfig::builder()`].
18///
19/// To build a config, you must make at least two decisions (in order):
20///
21/// - How should this client or server verify certificates provided by its peer?
22/// - What certificates should this client or server present to its peer?
23///
24/// For settings besides these, see the fields of [`ServerConfig`] and [`ClientConfig`].
25///
26/// The usual choice for protocol primitives is to call
27/// [`ClientConfig::builder`]/[`ServerConfig::builder`]
28/// which will use rustls' default cryptographic provider and safe defaults for ciphersuites and
29/// supported protocol versions.
30///
31/// ```
32/// # #[cfg(feature = "aws_lc_rs")] {
33/// # rustls::crypto::aws_lc_rs::default_provider().install_default();
34/// use rustls::{ClientConfig, ServerConfig};
35/// ClientConfig::builder()
36/// //  ...
37/// # ;
38///
39/// ServerConfig::builder()
40/// //  ...
41/// # ;
42/// # }
43/// ```
44///
45/// You may also override the choice of protocol versions:
46///
47/// ```no_run
48/// # #[cfg(feature = "aws_lc_rs")] {
49/// # rustls::crypto::aws_lc_rs::default_provider().install_default();
50/// # use rustls::ServerConfig;
51/// ServerConfig::builder_with_protocol_versions(&[&rustls::version::TLS13])
52/// //  ...
53/// # ;
54/// # }
55/// ```
56///
57/// Overriding the default cryptographic provider introduces a `Result` that must be unwrapped,
58/// because the config builder checks for consistency of the choices made. For instance, it's an error to
59/// configure only TLS 1.2 cipher suites while specifying that TLS 1.3 should be the only supported protocol
60/// version.
61///
62/// If you configure a smaller set of protocol primitives than the default, you may get a smaller binary,
63/// since the code for the unused ones can be optimized away at link time.
64///
65/// After choosing protocol primitives, you must choose (a) how to verify certificates and (b) what certificates
66/// (if any) to send to the peer. The methods to do this are specific to whether you're building a ClientConfig
67/// or a ServerConfig, as tracked by the [`ConfigSide`] type parameter on the various impls of ConfigBuilder.
68///
69/// # ClientConfig certificate configuration
70///
71/// For a client, _certificate verification_ must be configured either by calling one of:
72///  - [`ConfigBuilder::with_root_certificates`] or
73///  - [`ConfigBuilder::dangerous()`] and [`DangerousClientConfigBuilder::with_custom_certificate_verifier`]
74///
75/// Next, _certificate sending_ (also known as "client authentication", "mutual TLS", or "mTLS") must be configured
76/// or disabled using one of:
77/// - [`ConfigBuilder::with_no_client_auth`] - to not send client authentication (most common)
78/// - [`ConfigBuilder::with_client_auth_cert`] - to always send a specific certificate
79/// - [`ConfigBuilder::with_client_cert_resolver`] - to send a certificate chosen dynamically
80///
81/// For example:
82///
83/// ```
84/// # #[cfg(feature = "aws_lc_rs")] {
85/// # rustls::crypto::aws_lc_rs::default_provider().install_default();
86/// # use rustls::ClientConfig;
87/// # let root_certs = rustls::RootCertStore::empty();
88/// ClientConfig::builder()
89///     .with_root_certificates(root_certs)
90///     .with_no_client_auth();
91/// # }
92/// ```
93///
94/// # ServerConfig certificate configuration
95///
96/// For a server, _certificate verification_ must be configured by calling one of:
97/// - [`ConfigBuilder::with_no_client_auth`] - to not require client authentication (most common)
98/// - [`ConfigBuilder::with_client_cert_verifier`] - to use a custom verifier
99///
100/// Next, _certificate sending_ must be configured by calling one of:
101/// - [`ConfigBuilder::with_single_cert`] - to send a specific certificate
102/// - [`ConfigBuilder::with_single_cert_with_ocsp`] - to send a specific certificate, plus stapled OCSP
103/// - [`ConfigBuilder::with_cert_resolver`] - to send a certificate chosen dynamically
104///
105/// For example:
106///
107/// ```no_run
108/// # #[cfg(feature = "aws_lc_rs")] {
109/// # rustls::crypto::aws_lc_rs::default_provider().install_default();
110/// # use rustls::ServerConfig;
111/// # let certs = vec![];
112/// # let private_key = pki_types::PrivateKeyDer::from(
113/// #    pki_types::PrivatePkcs8KeyDer::from(vec![])
114/// # );
115/// ServerConfig::builder()
116///     .with_no_client_auth()
117///     .with_single_cert(certs, private_key)
118///     .expect("bad certificate/key");
119/// # }
120/// ```
121///
122/// # Types
123///
124/// ConfigBuilder uses the [typestate] pattern to ensure at compile time that each required
125/// configuration item is provided exactly once. This is tracked in the `State` type parameter,
126/// which can have these values:
127///
128/// - [`WantsVersions`]
129/// - [`WantsVerifier`]
130/// - [`WantsClientCert`]
131/// - [`WantsServerCert`]
132///
133/// The other type parameter is `Side`, which is either `ServerConfig` or `ClientConfig`
134/// depending on whether the ConfigBuilder was built with [`ServerConfig::builder()`] or
135/// [`ClientConfig::builder()`].
136///
137/// You won't need to write out either of these type parameters explicitly. If you write a
138/// correct chain of configuration calls they will be used automatically. If you write an
139/// incorrect chain of configuration calls you will get an error message from the compiler
140/// mentioning some of these types.
141///
142/// Additionally, ServerConfig and ClientConfig carry a private field containing a
143/// [`CryptoProvider`], from [`ClientConfig::builder_with_provider()`] or
144/// [`ServerConfig::builder_with_provider()`]. This determines which cryptographic backend
145/// is used. The default is [the process-default provider](`CryptoProvider::get_default`).
146///
147/// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html
148/// [typestate]: http://cliffle.com/blog/rust-typestate/
149/// [`ServerConfig`]: crate::ServerConfig
150/// [`ServerConfig::builder`]: crate::ServerConfig::builder
151/// [`ClientConfig`]: crate::ClientConfig
152/// [`ClientConfig::builder()`]: crate::ClientConfig::builder()
153/// [`ServerConfig::builder()`]: crate::ServerConfig::builder()
154/// [`ClientConfig::builder_with_provider()`]: crate::ClientConfig::builder_with_provider()
155/// [`ServerConfig::builder_with_provider()`]: crate::ServerConfig::builder_with_provider()
156/// [`ConfigBuilder<ClientConfig, WantsVerifier>`]: struct.ConfigBuilder.html#impl-3
157/// [`ConfigBuilder<ServerConfig, WantsVerifier>`]: struct.ConfigBuilder.html#impl-6
158/// [`WantsClientCert`]: crate::client::WantsClientCert
159/// [`WantsServerCert`]: crate::server::WantsServerCert
160/// [`CryptoProvider::get_default`]: crate::crypto::CryptoProvider::get_default
161/// [`DangerousClientConfigBuilder::with_custom_certificate_verifier`]: crate::client::danger::DangerousClientConfigBuilder::with_custom_certificate_verifier
162#[derive(Clone)]
163pub struct ConfigBuilder<Side: ConfigSide, State> {
164    pub(crate) state: State,
165    pub(crate) side: PhantomData<Side>,
166}
167
168impl<Side: ConfigSide, State: fmt::Debug> fmt::Debug for ConfigBuilder<Side, State> {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        let side_name = core::any::type_name::<Side>();
171        let (ty, _) = side_name
172            .split_once('<')
173            .unwrap_or((side_name, ""));
174        let (_, name) = ty.rsplit_once("::").unwrap_or(("", ty));
175
176        f.debug_struct(&format!("ConfigBuilder<{}, _>", name,))
177            .field("state", &self.state)
178            .finish()
179    }
180}
181
182/// Config builder state where the caller must supply TLS protocol versions.
183///
184/// For more information, see the [`ConfigBuilder`] documentation.
185#[derive(Clone, Debug)]
186pub struct WantsVersions {
187    pub(crate) provider: Arc<CryptoProvider>,
188    pub(crate) time_provider: Arc<dyn TimeProvider>,
189}
190
191impl<S: ConfigSide> ConfigBuilder<S, WantsVersions> {
192    /// Accept the default protocol versions: both TLS1.2 and TLS1.3 are enabled.
193    pub fn with_safe_default_protocol_versions(
194        self,
195    ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> {
196        self.with_protocol_versions(versions::DEFAULT_VERSIONS)
197    }
198
199    /// Use a specific set of protocol versions.
200    pub fn with_protocol_versions(
201        self,
202        versions: &[&'static versions::SupportedProtocolVersion],
203    ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> {
204        let mut any_usable_suite = false;
205        for suite in &self.state.provider.cipher_suites {
206            if versions.contains(&suite.version()) {
207                any_usable_suite = true;
208                break;
209            }
210        }
211
212        if !any_usable_suite {
213            return Err(Error::General("no usable cipher suites configured".into()));
214        }
215
216        if self.state.provider.kx_groups.is_empty() {
217            return Err(Error::General("no kx groups configured".into()));
218        }
219
220        // verifying cipher suites have matching kx groups
221        let mut supported_kx_algos = Vec::with_capacity(ALL_KEY_EXCHANGE_ALGORITHMS.len());
222        for group in self.state.provider.kx_groups.iter() {
223            let kx = group.name().key_exchange_algorithm();
224            if !supported_kx_algos.contains(&kx) {
225                supported_kx_algos.push(kx);
226            }
227            // Small optimization. We don't need to go over other key exchange groups
228            // if we already cover all supported key exchange algorithms
229            if supported_kx_algos.len() == ALL_KEY_EXCHANGE_ALGORITHMS.len() {
230                break;
231            }
232        }
233
234        for cs in self.state.provider.cipher_suites.iter() {
235            let cs_kx = cs.key_exchange_algorithms();
236            if cs_kx
237                .iter()
238                .any(|kx| supported_kx_algos.contains(kx))
239            {
240                continue;
241            }
242            let suite_name = cs.common().suite;
243            return Err(Error::General(alloc::format!(
244                "Ciphersuite {suite_name:?} requires {cs_kx:?} key exchange, but no {cs_kx:?}-compatible \
245                key exchange groups were present in `CryptoProvider`'s `kx_groups` field",
246            )));
247        }
248
249        Ok(ConfigBuilder {
250            state: WantsVerifier {
251                provider: self.state.provider,
252                versions: versions::EnabledVersions::new(versions),
253                time_provider: self.state.time_provider,
254            },
255            side: self.side,
256        })
257    }
258}
259
260/// Config builder state where the caller must supply a verifier.
261///
262/// For more information, see the [`ConfigBuilder`] documentation.
263#[derive(Clone, Debug)]
264pub struct WantsVerifier {
265    pub(crate) provider: Arc<CryptoProvider>,
266    pub(crate) versions: versions::EnabledVersions,
267    pub(crate) time_provider: Arc<dyn TimeProvider>,
268}
269
270/// Helper trait to abstract [`ConfigBuilder`] over building a [`ClientConfig`] or [`ServerConfig`].
271///
272/// [`ClientConfig`]: crate::ClientConfig
273/// [`ServerConfig`]: crate::ServerConfig
274pub trait ConfigSide: sealed::Sealed {}
275
276impl ConfigSide for crate::ClientConfig {}
277impl ConfigSide for crate::ServerConfig {}
278
279mod sealed {
280    pub trait Sealed {}
281    impl Sealed for crate::ClientConfig {}
282    impl Sealed for crate::ServerConfig {}
283}