| 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 | pub fn crypto_provider(&self) -> &Arc<CryptoProvider> { |
| 174 | &self.provider |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | impl<Side: ConfigSide, State: fmt::Debug> fmt::Debug for ConfigBuilder<Side, State> { |
| 179 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 180 | let side_name: &'static str = core::any::type_name::<Side>(); |
| 181 | let (ty: &str, _) = side_name |
| 182 | .split_once('<' ) |
| 183 | .unwrap_or((side_name, "" )); |
| 184 | let (_, name: &str) = ty.rsplit_once("::" ).unwrap_or(("" , ty)); |
| 185 | |
| 186 | f&mut DebugStruct<'_, '_>.debug_struct(&format!("ConfigBuilder< {}, _>" , name,)) |
| 187 | .field(name:"state" , &self.state) |
| 188 | .finish() |
| 189 | } |
| 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 | pub fn with_safe_default_protocol_versions( |
| 201 | self, |
| 202 | ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> { |
| 203 | self.with_protocol_versions(versions::DEFAULT_VERSIONS) |
| 204 | } |
| 205 | |
| 206 | /// Use a specific set of protocol versions. |
| 207 | pub fn with_protocol_versions( |
| 208 | self, |
| 209 | versions: &[&'static versions::SupportedProtocolVersion], |
| 210 | ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> { |
| 211 | let mut any_usable_suite = false; |
| 212 | for suite in &self.provider.cipher_suites { |
| 213 | if versions.contains(&suite.version()) { |
| 214 | any_usable_suite = true; |
| 215 | break; |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | if !any_usable_suite { |
| 220 | return Err(Error::General("no usable cipher suites configured" .into())); |
| 221 | } |
| 222 | |
| 223 | if self.provider.kx_groups.is_empty() { |
| 224 | return Err(Error::General("no kx groups configured" .into())); |
| 225 | } |
| 226 | |
| 227 | // verifying cipher suites have matching kx groups |
| 228 | let mut supported_kx_algos = Vec::with_capacity(ALL_KEY_EXCHANGE_ALGORITHMS.len()); |
| 229 | for group in self.provider.kx_groups.iter() { |
| 230 | let kx = group.name().key_exchange_algorithm(); |
| 231 | if !supported_kx_algos.contains(&kx) { |
| 232 | supported_kx_algos.push(kx); |
| 233 | } |
| 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 | if supported_kx_algos.len() == ALL_KEY_EXCHANGE_ALGORITHMS.len() { |
| 237 | break; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | for cs in self.provider.cipher_suites.iter() { |
| 242 | let cs_kx = cs.key_exchange_algorithms(); |
| 243 | if cs_kx |
| 244 | .iter() |
| 245 | .any(|kx| supported_kx_algos.contains(kx)) |
| 246 | { |
| 247 | continue; |
| 248 | } |
| 249 | let suite_name = cs.common().suite; |
| 250 | return Err(Error::General(alloc::format!( |
| 251 | "Ciphersuite {suite_name:?} requires {cs_kx:?} key exchange, but no {cs_kx:?}-compatible \ |
| 252 | key exchange groups were present in `CryptoProvider`'s `kx_groups` field" , |
| 253 | ))); |
| 254 | } |
| 255 | |
| 256 | Ok(ConfigBuilder { |
| 257 | state: WantsVerifier { |
| 258 | versions: versions::EnabledVersions::new(versions), |
| 259 | client_ech_mode: None, |
| 260 | }, |
| 261 | provider: self.provider, |
| 262 | time_provider: self.time_provider, |
| 263 | side: self.side, |
| 264 | }) |
| 265 | } |
| 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 | } |
| 291 | |