rustls_openssl/lib.rs
1//! # rustls-openssl
2//!
3//! A [rustls crypto provider](https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html) that uses OpenSSL for crypto.
4//!
5//! ## Supported Ciphers
6//!
7//! Supported cipher suites are listed below, in descending order of preference.
8//!
9//! The default provider includes all of these cipher suites, filtered based on runtime availability
10//! of the encryption algorithm, i.e when running against OpenSSL compiled without ChaCha20-Poly1305 support, the ChaCha20-Poly1305 cipher suites will be filtered out.
11//! If the `tls12` feature is disabled, then the TLS 1.2 cipher suites will not be available.
12//! Use [available_cipher_suites()] to get the runtime-available set of these cipher suites.
13//!
14//! ### TLS 1.3
15//!
16//! * TLS13_AES_256_GCM_SHA384
17//! * TLS13_AES_128_GCM_SHA256
18//! * TLS13_CHACHA20_POLY1305_SHA256
19//!
20//! ### TLS 1.2
21//!
22//! * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
23//! * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
24//! * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
25//! * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
26//! * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
27//! * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
28//!
29//! ## Supported Key Exchanges
30//!
31//! In descending order of preference:
32//!
33//! * X25519MLKEM768
34//! * SECP384R1
35//! * SECP256R1
36//! * X25519
37//! * MLKEM768
38//!
39//! If the `prefer-post-quantum` feature is enabled, X25519MLKEM768 will be the first group offered, otherwise it will be the last.
40//! MLKEM768 is not offered by default, but can be used by specifying it in the `custom_provider()` function.
41//!
42//! The default provider includes all of these key exchange groups, filtered based on runtime availability of the algorithm.
43//! Use [kx_group::available_default_groups()] to get the runtime-available set of default key exchange groups,
44//! and [kx_group::available_groups()] for the runtime-available set of all key exchange groups.
45//!
46//! ## Usage
47//!
48//! Add `rustls-openssl` to your `Cargo.toml`:
49//!
50//! ```toml
51//! [dependencies]
52//! rustls = { version = "0.23.0", features = ["tls12", "std"], default-features = false }
53//! rustls_openssl = "0.3"
54//! ```
55//!
56//! ### Configuration
57//!
58//! Use [default_provider()] to create a provider using cipher suites and key exchange groups listed above.
59//! Use [custom_provider()] to specify custom cipher suites and key exchange groups.
60//!
61//! # Features
62//! - `tls12`: Enables TLS 1.2 cipher suites. Enabled by default.
63//! - `prefer-post-quantum`: Enables X25519MLKEM768 as the first key exchange group. Enabled by default.
64//! - `vendored`: Enables vendored OpenSSL. Disabled by default.
65//! - `fips`: No longer used.
66#![warn(missing_docs)]
67use openssl::rand::rand_priv_bytes;
68use rustls::SupportedCipherSuite;
69use rustls::crypto::{CryptoProvider, GetRandomFailed, SupportedKxGroup};
70
71mod aead;
72mod hash;
73mod hkdf;
74mod hmac;
75pub mod kx_group;
76mod openssl_internal;
77#[cfg(feature = "tls12")]
78mod prf;
79mod quic;
80mod signer;
81#[cfg(feature = "tls12")]
82mod tls12;
83mod tls13;
84mod verify;
85
86pub mod cipher_suite {
87 //! Supported cipher suites.
88 #[cfg(feature = "tls12")]
89 pub use super::tls12::{
90 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
91 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
92 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
93 };
94 pub use super::tls13::{
95 TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
96 };
97}
98
99pub use signer::KeyProvider;
100pub use verify::SUPPORTED_SIG_ALGS;
101
102/// Returns an OpenSSL-based [CryptoProvider] using default available cipher suites ([available_cipher_suites()]) and key exchange groups ([kx_group::available_default_groups()]).
103///
104/// Sample usage:
105/// ```rust
106/// use rustls::{ClientConfig, RootCertStore};
107/// use rustls_openssl::default_provider;
108/// use std::sync::Arc;
109/// use webpki_roots;
110///
111/// let mut root_store = RootCertStore {
112/// roots: webpki_roots::TLS_SERVER_ROOTS.iter().cloned().collect(),
113/// };
114///
115/// let mut config =
116/// ClientConfig::builder_with_provider(Arc::new(default_provider()))
117/// .with_safe_default_protocol_versions()
118/// .unwrap()
119/// .with_root_certificates(root_store)
120/// .with_no_client_auth();
121///
122/// ```
123pub fn default_provider() -> CryptoProvider {
124 CryptoProvider {
125 cipher_suites: available_cipher_suites(),
126 kx_groups: kx_group::available_default_groups(),
127 signature_verification_algorithms: *verify::available_supported_sig_algs(),
128 secure_random: &SecureRandom,
129 key_provider: &KeyProvider,
130 }
131}
132
133/// Returns the cipher suites from [ALL_CIPHER_SUITES] that are available at runtime.
134pub fn available_cipher_suites() -> Vec<SupportedCipherSuite> {
135 ALL_CIPHER_SUITES
136 .iter()
137 .copied()
138 .filter(cipher_suite_available)
139 .collect()
140}
141
142fn cipher_suite_available(cipher_suite: &SupportedCipherSuite) -> bool {
143 match cipher_suite.suite() {
144 rustls::CipherSuite::TLS13_AES_128_GCM_SHA256
145 | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
146 | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => {
147 aead::Algorithm::Aes128Gcm.is_available()
148 }
149 rustls::CipherSuite::TLS13_AES_256_GCM_SHA384
150 | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
151 | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => {
152 aead::Algorithm::Aes256Gcm.is_available()
153 }
154 rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256
155 | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
156 | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => {
157 aead::Algorithm::ChaCha20Poly1305.is_available()
158 }
159 _ => true,
160 }
161}
162
163/// Create a [CryptoProvider] with specific cipher suites and key exchange groups
164///
165/// The specified cipher suites and key exchange groups should be defined in descending order of preference.
166/// i.e the first elements have the highest priority during negotiation.
167///
168/// If OpenSSL is running in FIPS mode, non-approved algorithms may be filtered
169/// out by runtime availability checks.
170///
171/// Sample usage:
172/// ```rust
173/// use rustls::{ClientConfig, RootCertStore};
174/// use rustls_openssl::custom_provider;
175/// use rustls_openssl::cipher_suite::TLS13_AES_128_GCM_SHA256;
176/// use rustls_openssl::kx_group::SECP256R1;
177/// use std::sync::Arc;
178/// use webpki_roots;
179///
180/// let mut root_store = RootCertStore {
181/// roots: webpki_roots::TLS_SERVER_ROOTS.iter().cloned().collect(),
182/// };
183///
184/// // Set custom config of cipher suites that have been imported from rustls_openssl.
185/// let cipher_suites = vec![TLS13_AES_128_GCM_SHA256];
186/// let kx_group = vec![SECP256R1];
187///
188/// let mut config =
189/// ClientConfig::builder_with_provider(Arc::new(custom_provider(
190/// cipher_suites, kx_group)))
191/// .with_safe_default_protocol_versions()
192/// .unwrap()
193/// .with_root_certificates(root_store)
194/// .with_no_client_auth();
195///
196///
197/// ```
198pub fn custom_provider(
199 cipher_suites: Vec<SupportedCipherSuite>,
200 kx_groups: Vec<&'static dyn SupportedKxGroup>,
201) -> CryptoProvider {
202 CryptoProvider {
203 cipher_suites,
204 kx_groups,
205 signature_verification_algorithms: *verify::available_supported_sig_algs(),
206 secure_random: &SecureRandom,
207 key_provider: &KeyProvider,
208 }
209}
210
211/// All supported cipher suites in descending order of preference:
212/// * TLS13_AES_256_GCM_SHA384
213/// * TLS13_AES_128_GCM_SHA256
214/// * TLS13_CHACHA20_POLY1305_SHA256
215/// * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
216/// * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
217/// * TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
218/// * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
219/// * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
220/// * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
221///
222/// ChaCha20-Poly1305 suites are runtime-filtered by [available_cipher_suites()].
223/// If the default `tls12` feature is disabled then the TLS 1.2 cipher suites will not be included.
224pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[
225 tls13::TLS13_AES_256_GCM_SHA384,
226 tls13::TLS13_AES_128_GCM_SHA256,
227 tls13::TLS13_CHACHA20_POLY1305_SHA256,
228 #[cfg(feature = "tls12")]
229 tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
230 #[cfg(feature = "tls12")]
231 tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
232 #[cfg(feature = "tls12")]
233 tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
234 #[cfg(feature = "tls12")]
235 tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
236 #[cfg(feature = "tls12")]
237 tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
238 #[cfg(feature = "tls12")]
239 tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
240];
241
242/// A struct that implements [rustls::crypto::SecureRandom].
243#[derive(Debug)]
244pub struct SecureRandom;
245
246impl rustls::crypto::SecureRandom for SecureRandom {
247 fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> {
248 rand_priv_bytes(buf).map_err(|_| GetRandomFailed)
249 }
250
251 fn fips(&self) -> bool {
252 fips::enabled()
253 }
254}
255
256pub mod fips {
257 //! # FIPS support
258 //!
259 //! To use rustls with OpenSSL in FIPS mode, perform the following actions.
260 //!
261 //! ## 1. Specify `require_ems` when constructing [rustls::ClientConfig] or [rustls::ServerConfig]
262 //!
263 //! See [rustls documentation](https://docs.rs/rustls/latest/rustls/client/struct.ClientConfig.html#structfield.require_ems) for rationale.
264 //!
265 //! ## 2. Enable FIPS mode for OpenSSL
266 //!
267 //! See [enable()].
268 //!
269 //! ## 3. Validate the FIPS status of your ClientConfig or ServerConfig at runtime
270 //! See [rustls documenation on FIPS](https://docs.rs/rustls/latest/rustls/manual/_06_fips/index.html#3-validate-the-fips-status-of-your-clientconfigserverconfig-at-run-time).
271
272 /// Returns `true` if OpenSSL is running in FIPS mode.
273 #[cfg(fips_module)]
274 pub(crate) fn enabled() -> bool {
275 openssl::fips::enabled()
276 }
277 #[cfg(not(fips_module))]
278 pub(crate) fn enabled() -> bool {
279 unsafe { openssl_sys::EVP_default_properties_is_fips_enabled(std::ptr::null_mut()) == 1 }
280 }
281
282 /// Enable FIPS mode for OpenSSL.
283 ///
284 /// This should be called on application startup before the provider is used.
285 ///
286 /// On OpenSSL 1.1.1 this calls [FIPS_mode_set](https://wiki.openssl.org/index.php/FIPS_mode_set()).
287 /// On OpenSSL 3 this loads a FIPS provider, which must be available.
288 ///
289 /// Panics if FIPS cannot be enabled
290 #[cfg(fips_module)]
291 pub fn enable() {
292 openssl::fips::enable(true).expect("Failed to enable FIPS mode.");
293 }
294
295 /// Enable FIPS mode for OpenSSL.
296 ///
297 /// This should be called on application startup before the provider is used.
298 ///
299 /// On OpenSSL 1.1.1 this calls [FIPS_mode_set](https://wiki.openssl.org/index.php/FIPS_mode_set()).
300 /// On OpenSSL 3 this loads a FIPS provider, which must be available.
301 ///
302 /// Panics if FIPS cannot be enabled
303 #[cfg(not(fips_module))]
304 pub fn enable() {
305 // Use OnceCell to ensure that the provider is only loaded once
306 use once_cell::sync::OnceCell;
307
308 use crate::openssl_internal;
309 static PROVIDER: OnceCell<openssl::provider::Provider> = OnceCell::new();
310 PROVIDER.get_or_init(|| {
311 let provider = openssl::provider::Provider::load(None, "fips")
312 .expect("Failed to load FIPS provider.");
313 unsafe {
314 openssl_internal::cvt(openssl_sys::EVP_default_properties_enable_fips(
315 std::ptr::null_mut(),
316 1,
317 ))
318 .expect("Failed to enable FIPS properties.");
319 }
320 provider
321 });
322 }
323}