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