Coverage Report

Created: 2026-03-14 06:47

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