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