rustls/
builder.rs

1use crate::error::Error;
2use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS};
3use crate::suites::{SupportedCipherSuite, DEFAULT_CIPHER_SUITES};
4use crate::versions;
5
6use std::fmt;
7use std::marker::PhantomData;
8
9/// Building a [`ServerConfig`] or [`ClientConfig`] in a linker-friendly and
10/// complete way.
11///
12/// Linker-friendly: meaning unused cipher suites, protocol
13/// versions, key exchange mechanisms, etc. can be discarded
14/// by the linker as they'll be unreferenced.
15///
16/// Complete: the type system ensures all decisions required to run a
17/// server or client have been made by the time the process finishes.
18///
19/// Example, to make a [`ServerConfig`]:
20///
21/// ```no_run
22/// # use rustls::ServerConfig;
23/// # let certs = vec![];
24/// # let private_key = rustls::PrivateKey(vec![]);
25/// ServerConfig::builder()
26///     .with_safe_default_cipher_suites()
27///     .with_safe_default_kx_groups()
28///     .with_safe_default_protocol_versions()
29///     .unwrap()
30///     .with_no_client_auth()
31///     .with_single_cert(certs, private_key)
32///     .expect("bad certificate/key");
33/// ```
34///
35/// This may be shortened to:
36///
37/// ```no_run
38/// # use rustls::ServerConfig;
39/// # let certs = vec![];
40/// # let private_key = rustls::PrivateKey(vec![]);
41/// ServerConfig::builder()
42///     .with_safe_defaults()
43///     .with_no_client_auth()
44///     .with_single_cert(certs, private_key)
45///     .expect("bad certificate/key");
46/// ```
47///
48/// To make a [`ClientConfig`]:
49///
50/// ```no_run
51/// # use rustls::ClientConfig;
52/// # let root_certs = rustls::RootCertStore::empty();
53/// # let certs = vec![];
54/// # let private_key = rustls::PrivateKey(vec![]);
55/// ClientConfig::builder()
56///     .with_safe_default_cipher_suites()
57///     .with_safe_default_kx_groups()
58///     .with_safe_default_protocol_versions()
59///     .unwrap()
60///     .with_root_certificates(root_certs)
61///     .with_client_auth_cert(certs, private_key)
62///     .expect("bad certificate/key");
63/// ```
64///
65/// This may be shortened to:
66///
67/// ```
68/// # use rustls::ClientConfig;
69/// # let root_certs = rustls::RootCertStore::empty();
70/// ClientConfig::builder()
71///     .with_safe_defaults()
72///     .with_root_certificates(root_certs)
73///     .with_no_client_auth();
74/// ```
75///
76/// The types used here fit together like this:
77///
78/// 1. Call [`ClientConfig::builder()`] or [`ServerConfig::builder()`] to initialize a builder.
79/// 1. You must make a decision on which cipher suites to use, typically
80///    by calling [`ConfigBuilder<S, WantsCipherSuites>::with_safe_default_cipher_suites()`].
81/// 2. Now you must make a decision
82///    on key exchange groups: typically by calling
83///    [`ConfigBuilder<S, WantsKxGroups>::with_safe_default_kx_groups()`].
84/// 3. Now you must make
85///    a decision on which protocol versions to support, typically by calling
86///    [`ConfigBuilder<S, WantsVersions>::with_safe_default_protocol_versions()`].
87/// 5. Now see [`ConfigBuilder<ClientConfig, WantsVerifier>`] or
88///    [`ConfigBuilder<ServerConfig, WantsVerifier>`] for further steps.
89///
90/// [`ServerConfig`]: crate::ServerConfig
91/// [`ClientConfig`]: crate::ClientConfig
92/// [`ClientConfig::builder()`]: crate::ClientConfig::builder()
93/// [`ServerConfig::builder()`]: crate::ServerConfig::builder()
94/// [`ConfigBuilder<ClientConfig, WantsVerifier>`]: struct.ConfigBuilder.html#impl-3
95/// [`ConfigBuilder<ServerConfig, WantsVerifier>`]: struct.ConfigBuilder.html#impl-6
96#[derive(Clone)]
97pub struct ConfigBuilder<Side: ConfigSide, State> {
98    pub(crate) state: State,
99    pub(crate) side: PhantomData<Side>,
100}
101
102impl<Side: ConfigSide, State: fmt::Debug> fmt::Debug for ConfigBuilder<Side, State> {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        let side_name = std::any::type_name::<Side>();
105        let side_name = side_name
106            .split("::")
107            .last()
108            .unwrap_or(side_name);
109        f.debug_struct(&format!("ConfigBuilder<{}, _>", side_name))
110            .field("state", &self.state)
111            .finish()
112    }
113}
114
115/// Config builder state where the caller must supply cipher suites.
116///
117/// For more information, see the [`ConfigBuilder`] documentation.
118#[derive(Clone, Debug)]
119pub struct WantsCipherSuites(pub(crate) ());
120
121impl<S: ConfigSide> ConfigBuilder<S, WantsCipherSuites> {
122    /// Start side-specific config with defaults for underlying cryptography.
123    ///
124    /// If used, this will enable all safe supported cipher suites ([`DEFAULT_CIPHER_SUITES`]), all
125    /// safe supported key exchange groups ([`ALL_KX_GROUPS`]) and all safe supported protocol
126    /// versions ([`DEFAULT_VERSIONS`]).
127    ///
128    /// These are safe defaults, useful for 99% of applications.
129    ///
130    /// [`DEFAULT_VERSIONS`]: versions::DEFAULT_VERSIONS
131    pub fn with_safe_defaults(self) -> ConfigBuilder<S, WantsVerifier> {
132        ConfigBuilder {
133            state: WantsVerifier {
134                cipher_suites: DEFAULT_CIPHER_SUITES.to_vec(),
135                kx_groups: ALL_KX_GROUPS.to_vec(),
136                versions: versions::EnabledVersions::new(versions::DEFAULT_VERSIONS),
137            },
138            side: self.side,
139        }
140    }
141
142    /// Choose a specific set of cipher suites.
143    pub fn with_cipher_suites(
144        self,
145        cipher_suites: &[SupportedCipherSuite],
146    ) -> ConfigBuilder<S, WantsKxGroups> {
147        ConfigBuilder {
148            state: WantsKxGroups {
149                cipher_suites: cipher_suites.to_vec(),
150            },
151            side: self.side,
152        }
153    }
154
155    /// Choose the default set of cipher suites ([`DEFAULT_CIPHER_SUITES`]).
156    ///
157    /// Note that this default provides only high-quality suites: there is no need
158    /// to filter out low-, export- or NULL-strength cipher suites: rustls does not
159    /// implement these.
160    pub fn with_safe_default_cipher_suites(self) -> ConfigBuilder<S, WantsKxGroups> {
161        self.with_cipher_suites(DEFAULT_CIPHER_SUITES)
162    }
163}
164
165/// Config builder state where the caller must supply key exchange groups.
166///
167/// For more information, see the [`ConfigBuilder`] documentation.
168#[derive(Clone, Debug)]
169pub struct WantsKxGroups {
170    cipher_suites: Vec<SupportedCipherSuite>,
171}
172
173impl<S: ConfigSide> ConfigBuilder<S, WantsKxGroups> {
174    /// Choose a specific set of key exchange groups.
175    pub fn with_kx_groups(
176        self,
177        kx_groups: &[&'static SupportedKxGroup],
178    ) -> ConfigBuilder<S, WantsVersions> {
179        ConfigBuilder {
180            state: WantsVersions {
181                cipher_suites: self.state.cipher_suites,
182                kx_groups: kx_groups.to_vec(),
183            },
184            side: self.side,
185        }
186    }
187
188    /// Choose the default set of key exchange groups ([`ALL_KX_GROUPS`]).
189    ///
190    /// This is a safe default: rustls doesn't implement any poor-quality groups.
191    pub fn with_safe_default_kx_groups(self) -> ConfigBuilder<S, WantsVersions> {
192        self.with_kx_groups(&ALL_KX_GROUPS)
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    cipher_suites: Vec<SupportedCipherSuite>,
202    kx_groups: Vec<&'static SupportedKxGroup>,
203}
204
205impl<S: ConfigSide> ConfigBuilder<S, WantsVersions> {
206    /// Accept the default protocol versions: both TLS1.2 and TLS1.3 are enabled.
207    pub fn with_safe_default_protocol_versions(
208        self,
209    ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> {
210        self.with_protocol_versions(versions::DEFAULT_VERSIONS)
211    }
212
213    /// Use a specific set of protocol versions.
214    pub fn with_protocol_versions(
215        self,
216        versions: &[&'static versions::SupportedProtocolVersion],
217    ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> {
218        let mut any_usable_suite = false;
219        for suite in &self.state.cipher_suites {
220            if versions.contains(&suite.version()) {
221                any_usable_suite = true;
222                break;
223            }
224        }
225
226        if !any_usable_suite {
227            return Err(Error::General("no usable cipher suites configured".into()));
228        }
229
230        if self.state.kx_groups.is_empty() {
231            return Err(Error::General("no kx groups configured".into()));
232        }
233
234        Ok(ConfigBuilder {
235            state: WantsVerifier {
236                cipher_suites: self.state.cipher_suites,
237                kx_groups: self.state.kx_groups,
238                versions: versions::EnabledVersions::new(versions),
239            },
240            side: self.side,
241        })
242    }
243}
244
245/// Config builder state where the caller must supply a verifier.
246///
247/// For more information, see the [`ConfigBuilder`] documentation.
248#[derive(Clone, Debug)]
249pub struct WantsVerifier {
250    pub(crate) cipher_suites: Vec<SupportedCipherSuite>,
251    pub(crate) kx_groups: Vec<&'static SupportedKxGroup>,
252    pub(crate) versions: versions::EnabledVersions,
253}
254
255/// Helper trait to abstract [`ConfigBuilder`] over building a [`ClientConfig`] or [`ServerConfig`].
256///
257/// [`ClientConfig`]: crate::ClientConfig
258/// [`ServerConfig`]: crate::ServerConfig
259pub trait ConfigSide: sealed::Sealed {}
260
261impl ConfigSide for crate::ClientConfig {}
262impl ConfigSide for crate::ServerConfig {}
263
264mod sealed {
265    pub trait Sealed {}
266    impl Sealed for crate::ClientConfig {}
267    impl Sealed for crate::ServerConfig {}
268}