Skip to main content

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}