Skip to content

Commit 12dfd46

Browse files
authored
FIPS provider integration (#17)
* FIPS provider integration * ensure all integration tests enable fips * run fips tests with single thread to avoid exhausting entropy in CI, and issues caused by repeated enabling of FIPs provider
1 parent 1318c44 commit 12dfd46

File tree

15 files changed

+191
-139
lines changed

15 files changed

+191
-139
lines changed

.github/workflows/ci.yml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ jobs:
4848
- name: cargo clippy --no-default-features (warnings)
4949
run: cargo clippy --no-default-features --all-targets -- -D warnings
5050

51-
test-fips:
52-
name: Test using FIPS openssl
51+
test-fips-1-1-1:
52+
name: Test using FIPS openssl 1.1.1
5353
runs-on: ubuntu-latest
5454
container:
5555
image: registry.access.redhat.com/ubi8/ubi:latest
5656
steps:
5757
- name: Install dependencies
58-
run: dnf install -y gcc openssl-devel openssl
58+
run: dnf install -y gcc openssl-devel
5959
- name: Check out repository
6060
uses: actions/checkout@v4
6161
- name: Install toolchain
@@ -64,5 +64,25 @@ jobs:
6464
toolchain: stable
6565
- name: Cache build artifacts
6666
uses: Swatinem/rust-cache@v2
67+
# Use single thread on FIPS to avoid running out of entropy
6768
- name: Run cargo test --features fips
68-
run: cargo test --features fips
69+
run: cargo test --tests --features fips -- --test-threads=1
70+
71+
test-fips-openssl-3:
72+
name: Test using FIPS openssl 3
73+
runs-on: ubuntu-latest
74+
container:
75+
image: registry.access.redhat.com/ubi9/ubi:latest
76+
steps:
77+
- name: Install dependencies
78+
run: dnf install -y gcc openssl-devel
79+
- name: Check out repository
80+
uses: actions/checkout@v4
81+
- name: Install toolchain
82+
uses: dtolnay/rust-toolchain@v1
83+
with:
84+
toolchain: stable
85+
- name: Cache build artifacts
86+
uses: Swatinem/rust-cache@v2
87+
- name: Run cargo test --features fips
88+
run: cargo test --tests --features fips -- --test-threads=1

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,15 @@ openssl = "0.10.68"
1515
openssl-sys = "0.9.104"
1616
rustls = { version = "0.23.0", default-features = false }
1717
rustls-webpki = { version = "0.102.2", default-features = false }
18+
once_cell = "1.8.0"
1819

1920
[features]
2021
default = ["tls12"]
2122
fips = []
2223
tls12 = ["rustls/tls12", "foreign-types-shared"]
2324

2425
[dev-dependencies]
25-
antidote = "1.0.0"
2626
hex = "0.4.3"
27-
lazy_static = "1.4.0"
28-
once_cell = "1.8.0"
2927
rcgen = { version = "0.13.1", default-features = false, features = [
3028
"aws_lc_rs",
3129
] }

src/hash.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl rustls::crypto::hash::Hash for Algorithm {
6464
}
6565

6666
fn fips(&self) -> bool {
67-
crate::fips()
67+
crate::fips::enabled()
6868
}
6969
}
7070

src/hkdf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl RustlsHkdf for Hkdf {
7373
}
7474

7575
fn fips(&self) -> bool {
76-
crate::fips()
76+
crate::fips::enabled()
7777
}
7878
}
7979

src/hmac.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl rustls::crypto::hmac::Hmac for Hmac {
2323
}
2424

2525
fn fips(&self) -> bool {
26-
crate::fips()
26+
crate::fips::enabled()
2727
}
2828
}
2929

src/kx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl SupportedKxGroup for EcKxGroup {
8888
}
8989

9090
fn fips(&self) -> bool {
91-
crate::fips()
91+
crate::fips::enabled()
9292
}
9393
}
9494

src/lib.rs

Lines changed: 81 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,11 @@
5252
//!
5353
//! # Features
5454
//! - `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.
56-
//!
57-
//! # FIPS
58-
//!
59-
//! To use rustls with OpenSSL in FIPS mode, perform the following actions.
60-
//!
61-
//! ## 1. Enable the FIPS feature
62-
//!
63-
//! This removes non-FIPS-approved cipher suites and key exchanges.
64-
//!
65-
//! ## 2. Specify `require_ems` when constructing [rustls::ClientConfig] or [rustls::ServerConfig]
66-
//!
67-
//! See [rustls documentation](https://docs.rs/rustls/latest/rustls/client/struct.ClientConfig.html#structfield.require_ems) for rationale.
68-
//!
69-
//! ## 3. Enable FIPS mode for OpenSSL
70-
//!
71-
//! [enable_fips()] can be used to enable FIPS mode for OpenSSL without users needing to depend on the [openssl] crate directly.
72-
//! This calls [openssl::fips::enable](https://github.com/sfackler/rust-openssl/blob/538a5cb737e8d83085553cac01643820dc7ff205/openssl/src/fips.rs#L12), panicking if that fails.
73-
74-
//! ## 4. Validate the FIPS status of your ClientConfig or ServerConfig at runtime
75-
//! 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).
55+
//! - `fips`: Enabling this feature removes non-FIPS-approved cipher suites and key exchanges. Disabled by default. See [fips].
7656
#![warn(missing_docs)]
77-
78-
use openssl::rand::rand_bytes;
57+
use openssl::error::ErrorStack;
58+
use openssl::rand::rand_priv_bytes;
59+
use openssl_sys::c_int;
7960
use rustls::crypto::{CryptoProvider, GetRandomFailed, SupportedKxGroup};
8061
use rustls::SupportedCipherSuite;
8162

@@ -238,28 +219,89 @@ pub struct SecureRandom;
238219

239220
impl rustls::crypto::SecureRandom for SecureRandom {
240221
fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> {
241-
rand_bytes(buf).map_err(|_| GetRandomFailed)
222+
rand_priv_bytes(buf).map_err(|_| GetRandomFailed)
242223
}
243224

244225
fn fips(&self) -> bool {
245-
fips()
226+
fips::enabled()
246227
}
247228
}
248229

249-
/// Returns `true` if OpenSSL is running in FIPS mode.
250-
#[cfg(fips_module)]
251-
pub(crate) fn fips() -> bool {
252-
openssl::fips::enabled()
253-
}
254-
#[cfg(not(fips_module))]
255-
pub(crate) fn fips() -> bool {
256-
false
230+
pub(crate) fn cvt(r: c_int) -> Result<i32, ErrorStack> {
231+
if r <= 0 {
232+
Err(ErrorStack::get())
233+
} else {
234+
Ok(r)
235+
}
257236
}
258237

259-
/// Enable FIPS mode for OpenSSL.
260-
///
261-
/// Panics if FIPS mode cannot be enabled.
262-
#[cfg(all(fips_module, feature = "fips"))]
263-
pub fn enable_fips() {
264-
openssl::fips::enable(true).expect("Failed to enable FIPS mode.");
238+
pub 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+
}
265307
}

src/prf.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::hash::Algorithm;
1+
use crate::{cvt, hash::Algorithm};
22
use core::ffi::c_void;
33
use foreign_types_shared::ForeignTypeRef;
44
use openssl::{
@@ -45,19 +45,11 @@ impl rustls::crypto::tls12::Prf for Prf {
4545
}
4646

4747
fn fips(&self) -> bool {
48-
crate::fips()
48+
crate::fips::enabled()
4949
}
5050
}
5151

5252
// rust-openssl doesn't expose tls1_prf function yet: https://github.com/sfackler/rust-openssl/pull/2329
53-
fn cvt(r: c_int) -> Result<i32, ErrorStack> {
54-
if r <= 0 {
55-
Err(ErrorStack::get())
56-
} else {
57-
Ok(r)
58-
}
59-
}
60-
6153
extern "C" {
6254
fn EVP_PKEY_CTX_ctrl(
6355
ctx: *mut EVP_PKEY_CTX,

src/quic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl quic::Algorithm for KeyBuilder {
6161
}
6262

6363
fn fips(&self) -> bool {
64-
crate::fips()
64+
crate::fips::enabled()
6565
}
6666
}
6767

src/signer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl rustls::crypto::KeyProvider for KeyProvider {
9595
}
9696

9797
fn fips(&self) -> bool {
98-
crate::fips()
98+
crate::fips::enabled()
9999
}
100100
}
101101

0 commit comments

Comments
 (0)