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