From 3c492c53eeb42fca607946fde4bdd397a193f82b Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Wed, 21 Oct 2026 13:33:46 +0200 Subject: [PATCH 1/4] Support FIPS builds of wolfSSL - drop x25519 and chacha20, enable private key reads around secret outputs, run self tests up front --- rustls-wolfcrypt-provider/build.rs | 10 +++++ rustls-wolfcrypt-provider/src/aead/quic.rs | 41 ++++++++++++++++++-- rustls-wolfcrypt-provider/src/hkdf.rs | 20 +++++++--- rustls-wolfcrypt-provider/src/kx.rs | 10 ++++- rustls-wolfcrypt-provider/src/kx/sec256r1.rs | 4 ++ rustls-wolfcrypt-provider/src/kx/sec384r1.rs | 4 ++ rustls-wolfcrypt-provider/src/kx/sec521r1.rs | 4 ++ rustls-wolfcrypt-provider/src/lib.rs | 24 +++++++++++- rustls-wolfcrypt-provider/src/prf.rs | 2 + rustls-wolfcrypt-provider/src/sign/ecdsa.rs | 2 + rustls-wolfcrypt-provider/src/types/mod.rs | 1 + rustls-wolfcrypt-provider/tests/e2e.rs | 15 ++++++- 12 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 rustls-wolfcrypt-provider/build.rs diff --git a/rustls-wolfcrypt-provider/build.rs b/rustls-wolfcrypt-provider/build.rs new file mode 100644 index 0000000..32948d0 --- /dev/null +++ b/rustls-wolfcrypt-provider/build.rs @@ -0,0 +1,10 @@ +// Turns on the `fips` cfg when wolfssl-wolfcrypt is built against a FIPS +// wolfSSL. The crate publishes that as FIPS=1 in its build metadata, which +// Cargo hands to crates depending on it directly as DEP_WOLFSSL_FIPS. +fn main() { + println!("cargo::rustc-check-cfg=cfg(fips)"); + println!("cargo::rerun-if-env-changed=DEP_WOLFSSL_FIPS"); + if std::env::var("DEP_WOLFSSL_FIPS").as_deref() == Ok("1") { + println!("cargo::rustc-cfg=fips"); + } +} diff --git a/rustls-wolfcrypt-provider/src/aead/quic.rs b/rustls-wolfcrypt-provider/src/aead/quic.rs index a3259bc..7f63578 100644 --- a/rustls-wolfcrypt-provider/src/aead/quic.rs +++ b/rustls-wolfcrypt-provider/src/aead/quic.rs @@ -4,12 +4,16 @@ use aead::{AeadInPlace, KeyInit}; use alloc::vec; +#[cfg(not(fips))] use core::mem; +#[cfg(not(fips))] use foreign_types::ForeignType; use zeroize::Zeroizing; use crate::alloc::string::ToString; +#[cfg(not(fips))] use crate::error::check_if_zero; +#[cfg(not(fips))] use crate::types::ChaChaObject; use alloc::boxed::Box; use alloc::vec::Vec; @@ -18,8 +22,10 @@ use rustls::crypto::cipher::{Iv, Nonce}; use rustls::quic::Tag; use rustls::{crypto::cipher::AeadKey, quic, Error}; use wolfssl_wolfcrypt::aes::{Aes128Gcm, Aes256Gcm, ECB}; +#[cfg(not(fips))] use wolfssl_wolfcrypt::chacha20_poly1305::ChaCha20Poly1305Aead; // The crate has no safe wrapper for plain ChaCha20, used for header protection. +#[cfg(not(fips))] use wolfssl_wolfcrypt::sys::{ wc_Chacha_Process, wc_Chacha_SetIV, wc_Chacha_SetKey, word32, ChaCha, }; @@ -37,6 +43,7 @@ macro_rules! mask_array { } pub enum Cipher { Aes(AesCipher), + #[cfg(not(fips))] ChaCha20(ChaChaCipher), } @@ -48,6 +55,7 @@ pub(crate) const TAG_LEN: usize = 16; pub const AES_128_KEY_LEN: usize = 128 / 8; pub const AES_256_KEY_LEN: usize = 256 / 8; +#[cfg(not(fips))] pub const CHACHA_KEY_LEN: usize = 32; pub const SAMPLE_LEN: usize = TAG_LEN; pub const MASK_LEN: usize = 5; @@ -82,6 +90,7 @@ impl HPAlgorithm { pub enum HPAlgorithmID { Aes128, Aes256, + #[cfg(not(fips))] ChaCha20, } @@ -118,6 +127,7 @@ fn init_hp_aes_cipher(key: &[u8]) -> Result { fn generate_mask_aes(hp_cipher: &Cipher, sample: &[u8]) -> Result<[u8; MASK_LEN], Error> { let aes_cipher = match hp_cipher { Cipher::Aes(c) => c, + #[cfg(not(fips))] _ => return Err(Error::General("Invalid cipher type".into())), }; @@ -128,6 +138,7 @@ fn generate_mask_aes(hp_cipher: &Cipher, sample: &[u8]) -> Result<[u8; MASK_LEN] } /// ChaCha20. +#[cfg(not(fips))] pub static CHACHA20: HPAlgorithm = HPAlgorithm { key_len: CHACHA_KEY_LEN, init: init_hp_chacha20_cipher, @@ -135,12 +146,14 @@ pub static CHACHA20: HPAlgorithm = HPAlgorithm { id: HPAlgorithmID::ChaCha20, }; +#[cfg(not(fips))] fn init_hp_chacha20_cipher(key: &[u8]) -> Result { let mut chacha_cipher = ChaChaCipher::new(None)?; chacha_cipher.set_key(key)?; Ok(Cipher::ChaCha20(chacha_cipher)) } +#[cfg(not(fips))] fn generate_mask_chacha20(hp_cipher: &Cipher, sample: &[u8]) -> Result<[u8; MASK_LEN], Error> { let chacha20_cipher = match hp_cipher { Cipher::ChaCha20(c) => c, @@ -260,6 +273,7 @@ impl quic::HeaderProtectionKey for HeaderProtectionKey { pub(crate) enum PacketKeyAlgorithmID { Aes128Gcm, Aes256Gcm, + #[cfg(not(fips))] ChaCha20Poly1305, } @@ -334,6 +348,7 @@ fn encrypt_aes_gcm( ) -> Result { let aes_cipher = match packet_cipher { Cipher::Aes(c) => c, + #[cfg(not(fips))] _ => return Err(Error::General("Invalid cipher type".into())), }; aes_cipher.encrypt_separate_tag(nonce, aad, in_out) @@ -347,6 +362,7 @@ pub(super) fn decrypt_aes_gcm( ) -> Result<(), Error> { let aes_cipher = match packet_cipher { Cipher::Aes(aes_key) => aes_key, + #[cfg(not(fips))] _ => return Err(Error::General("Invalid cipher type".into())), }; aes_cipher.decrypt(nonce, aad, in_out) @@ -357,6 +373,7 @@ pub(super) fn decrypt_aes_gcm( /// The keys are 256 bits long and the nonces are 96 bits long. /// /// [RFC 8439]: https://tools.ietf.org/html/rfc8439 +#[cfg(not(fips))] pub static CHACHA20_POLY1305: AeadAlgorithm = AeadAlgorithm { init: init_chacha20_poly1305_cipher, encrypt: encrypt_chacha20_poly1305, @@ -365,6 +382,7 @@ pub static CHACHA20_POLY1305: AeadAlgorithm = AeadAlgorithm { id: PacketKeyAlgorithmID::ChaCha20Poly1305, }; +#[cfg(not(fips))] fn init_chacha20_poly1305_cipher(key: &[u8]) -> Result { let key_array = <[u8; 32]>::try_from(key) .map_err(|_| Error::General("Invalid key length for ChaCha20-Poly1305".into()))?; @@ -372,6 +390,7 @@ fn init_chacha20_poly1305_cipher(key: &[u8]) -> Result { Ok(Cipher::ChaCha20(chacha_cipher)) } +#[cfg(not(fips))] fn encrypt_chacha20_poly1305( packet_cipher: &Cipher, nonce: &[u8], @@ -385,6 +404,7 @@ fn encrypt_chacha20_poly1305( chacha_cipher.encrypt_separate_tag(nonce, aad, in_out) } +#[cfg(not(fips))] fn decrypt_chacha20_poly1305( packet_cipher: &Cipher, nonce: &[u8], @@ -628,10 +648,12 @@ impl AesCipher { } } +#[cfg(not(fips))] pub struct ChaChaCipher { key: Option>, } +#[cfg(not(fips))] impl ChaChaCipher { pub fn new(key: Option<[u8; CHACHA_KEY_LEN]>) -> Result { Ok(Self { @@ -764,16 +786,21 @@ impl ChaChaCipher { #[cfg(test)] mod tests { use hex_literal::hex; + #[cfg(not(fips))] use rustls::crypto::tls13::HkdfExpander; use std::prelude::v1::Vec; use std::vec; use crate::aead; + #[cfg(not(fips))] use rustls::crypto::cipher::{AeadKey, Iv, NONCE_LEN}; use rustls::quic::*; use crate::default_provider; - use crate::{TLS13_AES_128_GCM_SHA256, TLS13_CHACHA20_POLY1305_SHA256}; + use crate::TLS13_AES_128_GCM_SHA256; + #[cfg(not(fips))] + use crate::TLS13_CHACHA20_POLY1305_SHA256; + #[cfg(not(fips))] use rustls::crypto::tls13::OkmBlock; use rustls::internal::msgs::codec::Codec; use rustls::{ClientConfig, Error, ServerConfig, Side, SideData}; @@ -973,6 +1000,7 @@ mod tests { pub body: Vec, } + #[cfg(not(fips))] #[derive(Debug, Clone)] struct ChaCha20TestVector { key: [u8; 32], @@ -993,6 +1021,7 @@ mod tests { }, } + #[cfg(not(fips))] fn hkdf_expand_label( expander: &Box, label: &[u8], @@ -1018,6 +1047,7 @@ mod tests { let _ = expander.expand_slice(info, output); } + #[cfg(not(fips))] fn test_short_packet(version: rustls::quic::Version, expected: &[u8]) { // Code taken from rustls with modification let chacha_key_len = TLS13_CHACHA20_POLY1305_SHA256 @@ -1132,6 +1162,7 @@ mod tests { assert_eq!(plain, &PLAIN[4..]); } + #[cfg(not(fips))] #[test] fn short_packet_header_protection() { // https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea @@ -1144,6 +1175,7 @@ mod tests { ); } + #[cfg(not(fips))] #[test] fn short_packet_header_protection_v2() { // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-chacha20-poly1305-short-head @@ -1550,6 +1582,7 @@ mod tests { } } + #[cfg(not(fips))] #[test] fn test_chacha_mask_generation() { //Test idea taken from ring @@ -1571,9 +1604,10 @@ mod tests { #[test] fn test_sample_len() { - let hp_algs: Vec<&aead::quic::HPAlgorithm> = vec![ + let hp_algs: &[&aead::quic::HPAlgorithm] = &[ &aead::quic::AES_128, &aead::quic::AES_256, + #[cfg(not(fips))] &aead::quic::CHACHA20, ]; let mut first = vec![0u8; 1]; @@ -1623,9 +1657,10 @@ mod tests { #[test] fn test_key_len() { - let hp_algs: Vec<&aead::quic::HPAlgorithm> = vec![ + let hp_algs: &[&aead::quic::HPAlgorithm] = &[ &aead::quic::AES_128, &aead::quic::AES_256, + #[cfg(not(fips))] &aead::quic::CHACHA20, ]; for alg in hp_algs { diff --git a/rustls-wolfcrypt-provider/src/hkdf.rs b/rustls-wolfcrypt-provider/src/hkdf.rs index 4013752..4733659 100644 --- a/rustls-wolfcrypt-provider/src/hkdf.rs +++ b/rustls-wolfcrypt-provider/src/hkdf.rs @@ -5,6 +5,9 @@ use rustls::crypto::hmac::Hmac as RustlsHmac; use rustls::crypto::tls13::{self, Hkdf as RustlsHkdf}; use wolfssl_wolfcrypt::hkdf::{hkdf_expand, hkdf_extract}; +#[cfg(fips)] +use wolfssl_wolfcrypt::fips::PrivateKeyRead; + use crate::hmac::WCShaHmac; use zeroize::Zeroizing; @@ -30,6 +33,8 @@ impl RustlsHkdf for WCHkdfUsingHmac { let zero_salt = vec![0u8; hash_len]; let salt_bytes = salt.unwrap_or(&zero_salt); + #[cfg(fips)] + let _read = PrivateKeyRead::enable().ok(); hkdf_extract( self.0.hash_type(), Some(salt_bytes), @@ -94,6 +99,8 @@ impl tls13::HkdfExpander for WolfHkdfExpander { return Err(tls13::OutputLengthError); } + #[cfg(fips)] + let _read = PrivateKeyRead::enable().ok(); hkdf_expand( self.hash_type, &self.extracted_key, @@ -118,9 +125,9 @@ impl tls13::HkdfExpander for WolfHkdfExpander { #[cfg(test)] mod tests { use super::*; - use crate::{ - TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, - }; + #[cfg(not(fips))] + use crate::TLS13_CHACHA20_POLY1305_SHA256; + use crate::{TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384}; use hex_literal::hex; use wycheproof::{hkdf::TestName, TestResult}; @@ -237,8 +244,11 @@ mod tests { #[test] fn test_hkdf_wycheproof_sha256() { - let suites: &[rustls::SupportedCipherSuite] = - &[TLS13_AES_128_GCM_SHA256, TLS13_CHACHA20_POLY1305_SHA256]; + let suites: &[rustls::SupportedCipherSuite] = &[ + TLS13_AES_128_GCM_SHA256, + #[cfg(not(fips))] + TLS13_CHACHA20_POLY1305_SHA256, + ]; let test_name: TestName = TestName::HkdfSha256; diff --git a/rustls-wolfcrypt-provider/src/kx.rs b/rustls-wolfcrypt-provider/src/kx.rs index ab4d90f..288388e 100644 --- a/rustls-wolfcrypt-provider/src/kx.rs +++ b/rustls-wolfcrypt-provider/src/kx.rs @@ -5,9 +5,16 @@ use rustls::ffdhe_groups::FfdheGroup; mod sec256r1; mod sec384r1; mod sec521r1; +#[cfg(not(fips))] mod x25519; -pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[&X25519, &SECP256R1, &SECP384R1, &SECP521R1]; +pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[ + #[cfg(not(fips))] + &X25519, + &SECP256R1, + &SECP384R1, + &SECP521R1, +]; macro_rules! define_kx_group { ($name:ident, $kx_type:ty, $kx_func:ident, $named_group:expr) => { @@ -31,6 +38,7 @@ macro_rules! define_kx_group { } // Define Supported KeyExchange groups +#[cfg(not(fips))] define_kx_group!( X25519, x25519::KeyExchangeX25519, diff --git a/rustls-wolfcrypt-provider/src/kx/sec256r1.rs b/rustls-wolfcrypt-provider/src/kx/sec256r1.rs index 80aa7e2..f0a01b2 100644 --- a/rustls-wolfcrypt-provider/src/kx/sec256r1.rs +++ b/rustls-wolfcrypt-provider/src/kx/sec256r1.rs @@ -20,6 +20,8 @@ impl KeyExchangeSecP256r1 { let mut priv_key_raw: Zeroizing> = Zeroizing::new(alloc::vec![0u8; 32].into_boxed_slice()); + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); key.export_private(&mut priv_key_raw) .map_err(|_| rustls::Error::General("wc_ecc_export_private_only failed".into()))?; @@ -56,6 +58,8 @@ impl KeyExchangeSecP256r1 { .map_err(|_| rustls::Error::General("Failed to set RNG on private key".into()))?; let mut out = [0u8; 32]; + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); priv_key .shared_secret(&mut pub_key, &mut out) .map_err(|_| rustls::Error::General("Failed to compute ECC shared secret".into()))?; diff --git a/rustls-wolfcrypt-provider/src/kx/sec384r1.rs b/rustls-wolfcrypt-provider/src/kx/sec384r1.rs index cf559fb..95a7631 100644 --- a/rustls-wolfcrypt-provider/src/kx/sec384r1.rs +++ b/rustls-wolfcrypt-provider/src/kx/sec384r1.rs @@ -20,6 +20,8 @@ impl KeyExchangeSecP384r1 { let mut priv_key_raw: Zeroizing> = Zeroizing::new(alloc::vec![0u8; 48].into_boxed_slice()); + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); key.export_private(&mut priv_key_raw) .map_err(|_| rustls::Error::General("wc_ecc_export_private_only failed".into()))?; @@ -56,6 +58,8 @@ impl KeyExchangeSecP384r1 { .map_err(|_| rustls::Error::General("Failed to set RNG on private key".into()))?; let mut out = [0u8; 48]; + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); priv_key .shared_secret(&mut pub_key, &mut out) .map_err(|_| rustls::Error::General("Failed to compute ECC shared secret".into()))?; diff --git a/rustls-wolfcrypt-provider/src/kx/sec521r1.rs b/rustls-wolfcrypt-provider/src/kx/sec521r1.rs index 1df062b..081e409 100644 --- a/rustls-wolfcrypt-provider/src/kx/sec521r1.rs +++ b/rustls-wolfcrypt-provider/src/kx/sec521r1.rs @@ -20,6 +20,8 @@ impl KeyExchangeSecP521r1 { let mut priv_key_raw: Zeroizing> = Zeroizing::new(alloc::vec![0u8; 66].into_boxed_slice()); + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); key.export_private(&mut priv_key_raw) .map_err(|_| rustls::Error::General("wc_ecc_export_private_only failed".into()))?; @@ -56,6 +58,8 @@ impl KeyExchangeSecP521r1 { .map_err(|_| rustls::Error::General("Failed to set RNG on private key".into()))?; let mut out = [0u8; 66]; + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); priv_key .shared_secret(&mut pub_key, &mut out) .map_err(|_| rustls::Error::General("Failed to compute ECC shared secret".into()))?; diff --git a/rustls-wolfcrypt-provider/src/lib.rs b/rustls-wolfcrypt-provider/src/lib.rs index 49eef77..535750a 100644 --- a/rustls-wolfcrypt-provider/src/lib.rs +++ b/rustls-wolfcrypt-provider/src/lib.rs @@ -21,6 +21,7 @@ use crate::prf::WCPrfUsingHmac; pub mod aead { pub mod aes128gcm; pub mod aes256gcm; + #[cfg(not(fips))] pub mod chacha20; #[cfg(feature = "quic")] pub mod quic; @@ -30,9 +31,11 @@ pub mod sign { pub mod eddsa; pub mod rsa; } +#[cfg(not(fips))] +use crate::aead::chacha20; #[cfg(feature = "quic")] use crate::aead::quic::KeyFactory; -use crate::aead::{aes128gcm, aes256gcm, chacha20}; +use crate::aead::{aes128gcm, aes256gcm}; pub mod hash { pub mod sha256; @@ -54,6 +57,7 @@ type SigningAlgorithms = Vec>; * Crypto provider struct that we populate with our own crypto backend (wolfcrypt). * */ pub fn default_provider() -> CryptoProvider { + run_fips_self_tests(); CryptoProvider { cipher_suites: ALL_CIPHER_SUITES.to_vec(), kx_groups: kx::ALL_KX_GROUPS.to_vec(), @@ -66,6 +70,7 @@ pub fn default_provider() -> CryptoProvider { pub fn provider_with_specified_ciphers( ciphers: Vec, ) -> CryptoProvider { + run_fips_self_tests(); CryptoProvider { cipher_suites: ciphers, kx_groups: kx::ALL_KX_GROUPS.to_vec(), @@ -75,6 +80,17 @@ pub fn provider_with_specified_ciphers( } } +/// Runs wolfCrypt's FIPS self tests before the provider is used, so threads +/// using an algorithm for the first time at once don't race on its self test. +/// A failure leaves the failed algorithms refused, so it shows up on use. +/// Does nothing in non-FIPS builds. +fn run_fips_self_tests() { + #[cfg(fips)] + if let Err(rc) = wolfssl_wolfcrypt::fips::run_all_self_tests() { + log::error!("wolfCrypt FIPS self tests failed: {}", rc); + } +} + #[derive(Debug)] struct Provider; @@ -116,12 +132,15 @@ impl rustls::crypto::KeyProvider for Provider { pub static ALL_CIPHER_SUITES: &[rustls::SupportedCipherSuite] = &[ TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256, + #[cfg(not(fips))] TLS13_CHACHA20_POLY1305_SHA256, TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + #[cfg(not(fips))] TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS12_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS12_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + #[cfg(not(fips))] TLS12_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, ]; @@ -141,6 +160,7 @@ static ALL_ECDSA_SCHEMES: &[rustls::SignatureScheme] = &[ rustls::SignatureScheme::ED25519, ]; +#[cfg(not(fips))] pub static TLS13_CHACHA20_POLY1305_SHA256: rustls::SupportedCipherSuite = rustls::SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite { common: rustls::crypto::CipherSuiteCommon { @@ -207,6 +227,7 @@ pub static TLS13_AES_256_GCM_SHA384: rustls::SupportedCipherSuite = }), }); +#[cfg(not(fips))] pub static TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: rustls::SupportedCipherSuite = rustls::SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: rustls::crypto::CipherSuiteCommon { @@ -246,6 +267,7 @@ pub static TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384: rustls::SupportedCipherSuite sign: ALL_RSA_SCHEMES, }); +#[cfg(not(fips))] pub static TLS12_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: rustls::SupportedCipherSuite = rustls::SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { common: rustls::crypto::CipherSuiteCommon { diff --git a/rustls-wolfcrypt-provider/src/prf.rs b/rustls-wolfcrypt-provider/src/prf.rs index 67afa1c..649ffa0 100644 --- a/rustls-wolfcrypt-provider/src/prf.rs +++ b/rustls-wolfcrypt-provider/src/prf.rs @@ -39,6 +39,8 @@ fn wc_prf( // The TLS 1.2 PRF is P_hash(secret, label || seed) (RFC 5246, section 5). let label_seed = [label, seed].concat(); + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); prf(secret, &label_seed, hash_type, output) .map_err(|_| rustls::Error::General("TLS 1.2 PRF failed".into())) } diff --git a/rustls-wolfcrypt-provider/src/sign/ecdsa.rs b/rustls-wolfcrypt-provider/src/sign/ecdsa.rs index 627d28c..61afef5 100644 --- a/rustls-wolfcrypt-provider/src/sign/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/sign/ecdsa.rs @@ -66,6 +66,8 @@ impl TryFrom<&PrivateKeyDer<'_>> for EcdsaSigningKey { // The export writes exactly the curve's key size, so a buffer big // enough for P-521 also tells us which curve the key is on. let mut priv_key_bytes = Zeroizing::new(vec![0u8; MAX_ECC_KEY_SIZE]); + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().ok(); let key_size = key .export_private(&mut priv_key_bytes) .map_err(|_| rustls::Error::General("wc_ecc_export_private_only failed".into()))?; diff --git a/rustls-wolfcrypt-provider/src/types/mod.rs b/rustls-wolfcrypt-provider/src/types/mod.rs index d085e8b..9177ce1 100644 --- a/rustls-wolfcrypt-provider/src/types/mod.rs +++ b/rustls-wolfcrypt-provider/src/types/mod.rs @@ -150,4 +150,5 @@ define_foreign_type!( ); define_foreign_type_no_copy!(RsaKeyObject, RsaKeyObjectRef, RsaKey, drop(wc_FreeRsaKey)); +#[cfg(not(fips))] define_foreign_type_no_copy!(ChaChaObject, ChaChaObjectRef, ChaCha); diff --git a/rustls-wolfcrypt-provider/tests/e2e.rs b/rustls-wolfcrypt-provider/tests/e2e.rs index 837373b..27d4478 100644 --- a/rustls-wolfcrypt-provider/tests/e2e.rs +++ b/rustls-wolfcrypt-provider/tests/e2e.rs @@ -7,8 +7,11 @@ use rustls_wolfcrypt_provider::error::*; use rustls_wolfcrypt_provider::types::*; use rustls_wolfcrypt_provider::{ TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS13_AES_128_GCM_SHA256, - TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, + TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, +}; +#[cfg(not(fips))] +use rustls_wolfcrypt_provider::{ + TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS13_CHACHA20_POLY1305_SHA256, }; use std::env; use std::fs::File; @@ -101,6 +104,7 @@ mod tests { let current_dir_string = current_dir.to_string_lossy().into_owned(); let ciphers = [ + #[cfg(not(fips))] TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384, @@ -194,6 +198,7 @@ mod tests { let current_dir_string = current_dir.to_string_lossy().into_owned(); let ciphers = [ + #[cfg(not(fips))] TLS13_CHACHA20_POLY1305_SHA256, TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, @@ -283,6 +288,7 @@ mod tests { #[test] fn test_tl12_against_website() { let ciphers = [ + #[cfg(not(fips))] TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384, @@ -343,6 +349,7 @@ mod tests { #[test] fn test_tl13_against_website() { let ciphers = [ + #[cfg(not(fips))] TLS13_CHACHA20_POLY1305_SHA256, TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, @@ -488,6 +495,8 @@ mod tests { // Export private key in DER format let mut priv_key_raw = vec![0u8; key_size]; + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().unwrap(); key.export_private(&mut priv_key_raw).unwrap(); let der_ecc_key = ecc_private_key_to_der(&priv_key_raw, &pub_key_bytes, curve_id); @@ -525,6 +534,8 @@ mod tests { // Export private key let mut priv_key_raw = [0u8; Ed25519::KEY_SIZE]; + #[cfg(fips)] + let _read = wolfssl_wolfcrypt::fips::PrivateKeyRead::enable().unwrap(); key.export_private_only(&mut priv_key_raw).unwrap(); // Export public key From 413dd8c7650f5e766db75db8f00420eddc14f420 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Wed, 21 Oct 2026 14:00:34 +0200 Subject: [PATCH 2/4] Report FIPS to rustls from every provider component in FIPS builds --- rustls-wolfcrypt-provider/src/aead/aes128gcm.rs | 8 ++++++++ rustls-wolfcrypt-provider/src/aead/aes256gcm.rs | 8 ++++++++ rustls-wolfcrypt-provider/src/aead/quic.rs | 2 +- rustls-wolfcrypt-provider/src/hash/sha256.rs | 4 ++++ rustls-wolfcrypt-provider/src/hash/sha384.rs | 4 ++++ rustls-wolfcrypt-provider/src/hkdf.rs | 4 ++++ rustls-wolfcrypt-provider/src/hmac/mod.rs | 4 ++++ rustls-wolfcrypt-provider/src/kx.rs | 4 ++++ rustls-wolfcrypt-provider/src/lib.rs | 8 ++++++++ rustls-wolfcrypt-provider/src/prf.rs | 4 ++++ rustls-wolfcrypt-provider/src/verify/ecdsa.rs | 4 ++++ rustls-wolfcrypt-provider/src/verify/eddsa.rs | 4 ++++ rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs | 12 ++++++++++++ rustls-wolfcrypt-provider/src/verify/rsapss.rs | 12 ++++++++++++ 14 files changed, 81 insertions(+), 1 deletion(-) diff --git a/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs b/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs index f97b0c8..8c86ba8 100644 --- a/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs +++ b/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs @@ -16,6 +16,10 @@ const GCM_TAG_LENGTH: usize = 16; pub struct Aes128Gcm; impl Tls12AeadAlgorithm for Aes128Gcm { + fn fips(&self) -> bool { + cfg!(fips) + } + fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box { let mut iv_as_array = [0u8; GCM_NONCE_LENGTH]; iv_as_array[..(GCM_NONCE_LENGTH - 8)].copy_from_slice(iv); // implicit @@ -177,6 +181,10 @@ impl MessageDecrypter for WCTls12Decrypter { } impl Tls13AeadAlgorithm for Aes128Gcm { + fn fips(&self) -> bool { + cfg!(fips) + } + fn encrypter(&self, key: AeadKey, iv: Iv) -> Box { Box::new(WCTls13Cipher { cipher: new_cipher(&key), diff --git a/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs b/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs index 9fc3fb0..039f466 100644 --- a/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs +++ b/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs @@ -16,6 +16,10 @@ const GCM_TAG_LENGTH: usize = 16; pub struct Aes256Gcm; impl Tls12AeadAlgorithm for Aes256Gcm { + fn fips(&self) -> bool { + cfg!(fips) + } + fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box { let mut iv_as_array = [0u8; GCM_NONCE_LENGTH]; iv_as_array[..(GCM_NONCE_LENGTH - 8)].copy_from_slice(iv); // implicit @@ -177,6 +181,10 @@ impl MessageDecrypter for WCTls12Decrypter { } impl Tls13AeadAlgorithm for Aes256Gcm { + fn fips(&self) -> bool { + cfg!(fips) + } + fn encrypter(&self, key: AeadKey, iv: Iv) -> Box { Box::new(WCTls13Cipher { cipher: new_cipher(&key), diff --git a/rustls-wolfcrypt-provider/src/aead/quic.rs b/rustls-wolfcrypt-provider/src/aead/quic.rs index 7f63578..0e47027 100644 --- a/rustls-wolfcrypt-provider/src/aead/quic.rs +++ b/rustls-wolfcrypt-provider/src/aead/quic.rs @@ -543,7 +543,7 @@ impl quic::Algorithm for KeyFactory { } fn fips(&self) -> bool { - false + cfg!(fips) } } diff --git a/rustls-wolfcrypt-provider/src/hash/sha256.rs b/rustls-wolfcrypt-provider/src/hash/sha256.rs index 6af6760..28ece3c 100644 --- a/rustls-wolfcrypt-provider/src/hash/sha256.rs +++ b/rustls-wolfcrypt-provider/src/hash/sha256.rs @@ -7,6 +7,10 @@ use wolfssl_wolfcrypt::sha::SHA256; pub struct WCSha256; impl hash::Hash for WCSha256 { + fn fips(&self) -> bool { + cfg!(fips) + } + fn start(&self) -> Box { let sha256 = SHA256::new().expect("SHA256::new failed"); Box::new(WCSha256Context::new(sha256)) diff --git a/rustls-wolfcrypt-provider/src/hash/sha384.rs b/rustls-wolfcrypt-provider/src/hash/sha384.rs index 0893138..1c1efce 100644 --- a/rustls-wolfcrypt-provider/src/hash/sha384.rs +++ b/rustls-wolfcrypt-provider/src/hash/sha384.rs @@ -7,6 +7,10 @@ use wolfssl_wolfcrypt::sha::SHA384; pub struct WCSha384; impl hash::Hash for WCSha384 { + fn fips(&self) -> bool { + cfg!(fips) + } + fn start(&self) -> Box { let sha384 = SHA384::new().expect("SHA384::new failed"); Box::new(WCSha384Context::new(sha384)) diff --git a/rustls-wolfcrypt-provider/src/hkdf.rs b/rustls-wolfcrypt-provider/src/hkdf.rs index 4733659..d7607c2 100644 --- a/rustls-wolfcrypt-provider/src/hkdf.rs +++ b/rustls-wolfcrypt-provider/src/hkdf.rs @@ -14,6 +14,10 @@ use zeroize::Zeroizing; pub struct WCHkdfUsingHmac(pub WCShaHmac); impl RustlsHkdf for WCHkdfUsingHmac { + fn fips(&self) -> bool { + cfg!(fips) + } + fn extract_from_zero_ikm( &self, salt: Option<&[u8]>, diff --git a/rustls-wolfcrypt-provider/src/hmac/mod.rs b/rustls-wolfcrypt-provider/src/hmac/mod.rs index 17ad664..9758449 100644 --- a/rustls-wolfcrypt-provider/src/hmac/mod.rs +++ b/rustls-wolfcrypt-provider/src/hmac/mod.rs @@ -34,6 +34,10 @@ impl WCShaHmac { } impl crypto::hmac::Hmac for WCShaHmac { + fn fips(&self) -> bool { + cfg!(fips) + } + fn with_key(&self, key: &[u8]) -> Box { Box::new(WCHmacKey { key: Zeroizing::new(key.to_vec()), diff --git a/rustls-wolfcrypt-provider/src/kx.rs b/rustls-wolfcrypt-provider/src/kx.rs index 288388e..277b38b 100644 --- a/rustls-wolfcrypt-provider/src/kx.rs +++ b/rustls-wolfcrypt-provider/src/kx.rs @@ -22,6 +22,10 @@ macro_rules! define_kx_group { pub struct $name; impl crypto::SupportedKxGroup for $name { + fn fips(&self) -> bool { + cfg!(fips) + } + fn start(&self) -> Result, rustls::Error> { Ok(Box::new(<$kx_type>::$kx_func()?)) } diff --git a/rustls-wolfcrypt-provider/src/lib.rs b/rustls-wolfcrypt-provider/src/lib.rs index 535750a..4d401a2 100644 --- a/rustls-wolfcrypt-provider/src/lib.rs +++ b/rustls-wolfcrypt-provider/src/lib.rs @@ -95,6 +95,10 @@ fn run_fips_self_tests() { struct Provider; impl rustls::crypto::SecureRandom for Provider { + fn fips(&self) -> bool { + cfg!(fips) + } + fn fill(&self, bytes: &mut [u8]) -> Result<(), rustls::crypto::GetRandomFailed> { match random::wolfcrypt_random_buffer_generator(bytes) { Ok(()) => Ok(()), @@ -104,6 +108,10 @@ impl rustls::crypto::SecureRandom for Provider { } impl rustls::crypto::KeyProvider for Provider { + fn fips(&self) -> bool { + cfg!(fips) + } + fn load_private_key( &self, key_der: PrivateKeyDer<'static>, diff --git a/rustls-wolfcrypt-provider/src/prf.rs b/rustls-wolfcrypt-provider/src/prf.rs index 649ffa0..1ec2de1 100644 --- a/rustls-wolfcrypt-provider/src/prf.rs +++ b/rustls-wolfcrypt-provider/src/prf.rs @@ -7,6 +7,10 @@ use crate::hmac::*; pub struct WCPrfUsingHmac(pub WCShaHmac); impl crypto::tls12::Prf for WCPrfUsingHmac { + fn fips(&self) -> bool { + cfg!(fips) + } + fn for_key_exchange( &self, output: &mut [u8; 48], diff --git a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs index 455c0a9..3f4629c 100644 --- a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs @@ -29,6 +29,10 @@ impl EcdsaVerifier { } impl SignatureVerificationAlgorithm for EcdsaVerifier { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { match self.scheme { SignatureScheme::ECDSA_NISTP256_SHA256 => alg_id::ECDSA_P256, diff --git a/rustls-wolfcrypt-provider/src/verify/eddsa.rs b/rustls-wolfcrypt-provider/src/verify/eddsa.rs index 6711751..9b5f7ed 100644 --- a/rustls-wolfcrypt-provider/src/verify/eddsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/eddsa.rs @@ -6,6 +6,10 @@ use wolfssl_wolfcrypt::ed25519::Ed25519 as WCEd25519; pub struct Ed25519; impl SignatureVerificationAlgorithm for Ed25519 { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::ED25519 } diff --git a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs index b773e56..3739339 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs @@ -16,6 +16,10 @@ use wolfssl_wolfcrypt::sys::*; pub struct RsaPkcs1Sha256Verify; impl SignatureVerificationAlgorithm for RsaPkcs1Sha256Verify { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::RSA_ENCRYPTION } @@ -78,6 +82,10 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha256Verify { pub struct RsaPkcs1Sha384Verify; impl SignatureVerificationAlgorithm for RsaPkcs1Sha384Verify { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::RSA_ENCRYPTION } @@ -140,6 +148,10 @@ impl SignatureVerificationAlgorithm for RsaPkcs1Sha384Verify { pub struct RsaPkcs1Sha512Verify; impl SignatureVerificationAlgorithm for RsaPkcs1Sha512Verify { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::RSA_ENCRYPTION } diff --git a/rustls-wolfcrypt-provider/src/verify/rsapss.rs b/rustls-wolfcrypt-provider/src/verify/rsapss.rs index fd92643..8188c41 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapss.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapss.rs @@ -32,6 +32,10 @@ fn verify_pss( pub struct RsaPssSha256Verify; impl SignatureVerificationAlgorithm for RsaPssSha256Verify { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::RSA_ENCRYPTION } @@ -61,6 +65,10 @@ impl SignatureVerificationAlgorithm for RsaPssSha256Verify { pub struct RsaPssSha384Verify; impl SignatureVerificationAlgorithm for RsaPssSha384Verify { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::RSA_ENCRYPTION } @@ -90,6 +98,10 @@ impl SignatureVerificationAlgorithm for RsaPssSha384Verify { pub struct RsaPssSha512Verify; impl SignatureVerificationAlgorithm for RsaPssSha512Verify { + fn fips(&self) -> bool { + cfg!(fips) + } + fn public_key_alg_id(&self) -> AlgorithmIdentifier { alg_id::RSA_ENCRYPTION } From b2e2a9da87214cd73613a2f8e47bcd45201c4e64 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Wed, 21 Oct 2026 14:19:30 +0200 Subject: [PATCH 3/4] Test that the provider reports FIPS exactly in FIPS builds --- rustls-wolfcrypt-provider/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rustls-wolfcrypt-provider/src/lib.rs b/rustls-wolfcrypt-provider/src/lib.rs index 4d401a2..913e595 100644 --- a/rustls-wolfcrypt-provider/src/lib.rs +++ b/rustls-wolfcrypt-provider/src/lib.rs @@ -314,3 +314,13 @@ pub static TLS12_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: rustls::SupportedCipherSui kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, sign: ALL_ECDSA_SCHEMES, }); + +#[cfg(test)] +mod tests { + // rustls calls the provider FIPS only if every part of it says so, + // QUIC included when that feature is on. + #[test] + fn test_fips_matches_build() { + assert_eq!(crate::default_provider().fips(), cfg!(fips)); + } +} From f78cec417b4ec87393e2693f6c9174ccc3b03c3f Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Thu, 22 Oct 2026 12:38:07 +0200 Subject: [PATCH 4/4] Answer fips() from wolfSSL's live FIPS mode, so a failed self test or integrity check reports false --- .../src/aead/aes128gcm.rs | 4 ++-- .../src/aead/aes256gcm.rs | 4 ++-- rustls-wolfcrypt-provider/src/aead/quic.rs | 2 +- rustls-wolfcrypt-provider/src/hash/sha256.rs | 2 +- rustls-wolfcrypt-provider/src/hash/sha384.rs | 2 +- rustls-wolfcrypt-provider/src/hkdf.rs | 2 +- rustls-wolfcrypt-provider/src/hmac/mod.rs | 2 +- rustls-wolfcrypt-provider/src/kx.rs | 2 +- rustls-wolfcrypt-provider/src/lib.rs | 21 +++++++++++++++++-- rustls-wolfcrypt-provider/src/prf.rs | 2 +- rustls-wolfcrypt-provider/src/verify/ecdsa.rs | 2 +- rustls-wolfcrypt-provider/src/verify/eddsa.rs | 2 +- .../src/verify/rsapkcs1.rs | 6 +++--- .../src/verify/rsapss.rs | 6 +++--- 14 files changed, 38 insertions(+), 21 deletions(-) diff --git a/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs b/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs index 8c86ba8..948fc89 100644 --- a/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs +++ b/rustls-wolfcrypt-provider/src/aead/aes128gcm.rs @@ -17,7 +17,7 @@ pub struct Aes128Gcm; impl Tls12AeadAlgorithm for Aes128Gcm { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box { @@ -182,7 +182,7 @@ impl MessageDecrypter for WCTls12Decrypter { impl Tls13AeadAlgorithm for Aes128Gcm { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn encrypter(&self, key: AeadKey, iv: Iv) -> Box { diff --git a/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs b/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs index 039f466..42185f3 100644 --- a/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs +++ b/rustls-wolfcrypt-provider/src/aead/aes256gcm.rs @@ -17,7 +17,7 @@ pub struct Aes256Gcm; impl Tls12AeadAlgorithm for Aes256Gcm { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box { @@ -182,7 +182,7 @@ impl MessageDecrypter for WCTls12Decrypter { impl Tls13AeadAlgorithm for Aes256Gcm { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn encrypter(&self, key: AeadKey, iv: Iv) -> Box { diff --git a/rustls-wolfcrypt-provider/src/aead/quic.rs b/rustls-wolfcrypt-provider/src/aead/quic.rs index 0e47027..ad02a54 100644 --- a/rustls-wolfcrypt-provider/src/aead/quic.rs +++ b/rustls-wolfcrypt-provider/src/aead/quic.rs @@ -543,7 +543,7 @@ impl quic::Algorithm for KeyFactory { } fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } } diff --git a/rustls-wolfcrypt-provider/src/hash/sha256.rs b/rustls-wolfcrypt-provider/src/hash/sha256.rs index 28ece3c..89152d1 100644 --- a/rustls-wolfcrypt-provider/src/hash/sha256.rs +++ b/rustls-wolfcrypt-provider/src/hash/sha256.rs @@ -8,7 +8,7 @@ pub struct WCSha256; impl hash::Hash for WCSha256 { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn start(&self) -> Box { diff --git a/rustls-wolfcrypt-provider/src/hash/sha384.rs b/rustls-wolfcrypt-provider/src/hash/sha384.rs index 1c1efce..6dd4fbd 100644 --- a/rustls-wolfcrypt-provider/src/hash/sha384.rs +++ b/rustls-wolfcrypt-provider/src/hash/sha384.rs @@ -8,7 +8,7 @@ pub struct WCSha384; impl hash::Hash for WCSha384 { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn start(&self) -> Box { diff --git a/rustls-wolfcrypt-provider/src/hkdf.rs b/rustls-wolfcrypt-provider/src/hkdf.rs index d7607c2..8616678 100644 --- a/rustls-wolfcrypt-provider/src/hkdf.rs +++ b/rustls-wolfcrypt-provider/src/hkdf.rs @@ -15,7 +15,7 @@ pub struct WCHkdfUsingHmac(pub WCShaHmac); impl RustlsHkdf for WCHkdfUsingHmac { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn extract_from_zero_ikm( diff --git a/rustls-wolfcrypt-provider/src/hmac/mod.rs b/rustls-wolfcrypt-provider/src/hmac/mod.rs index 9758449..09d0b5c 100644 --- a/rustls-wolfcrypt-provider/src/hmac/mod.rs +++ b/rustls-wolfcrypt-provider/src/hmac/mod.rs @@ -35,7 +35,7 @@ impl WCShaHmac { impl crypto::hmac::Hmac for WCShaHmac { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn with_key(&self, key: &[u8]) -> Box { diff --git a/rustls-wolfcrypt-provider/src/kx.rs b/rustls-wolfcrypt-provider/src/kx.rs index 277b38b..e81a821 100644 --- a/rustls-wolfcrypt-provider/src/kx.rs +++ b/rustls-wolfcrypt-provider/src/kx.rs @@ -23,7 +23,7 @@ macro_rules! define_kx_group { impl crypto::SupportedKxGroup for $name { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn start(&self) -> Result, rustls::Error> { diff --git a/rustls-wolfcrypt-provider/src/lib.rs b/rustls-wolfcrypt-provider/src/lib.rs index 913e595..c362c97 100644 --- a/rustls-wolfcrypt-provider/src/lib.rs +++ b/rustls-wolfcrypt-provider/src/lib.rs @@ -91,12 +91,29 @@ fn run_fips_self_tests() { } } +/// The answer every fips method in this provider gives. In FIPS builds it asks +/// wolfSSL at run time, so a failed self test or integrity check answers false. +pub(crate) fn fips() -> bool { + #[cfg(fips)] + { + use wolfssl_wolfcrypt::sys; + // NORMAL is the only healthy mode, DEGRADED and FAILED mean a self test + // or the integrity check failed. + let mode = unsafe { sys::wolfCrypt_GetMode_fips() }; + mode == sys::FipsModeId_FIPS_MODE_NORMAL as core::ffi::c_int + } + #[cfg(not(fips))] + { + false + } +} + #[derive(Debug)] struct Provider; impl rustls::crypto::SecureRandom for Provider { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn fill(&self, bytes: &mut [u8]) -> Result<(), rustls::crypto::GetRandomFailed> { @@ -109,7 +126,7 @@ impl rustls::crypto::SecureRandom for Provider { impl rustls::crypto::KeyProvider for Provider { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn load_private_key( diff --git a/rustls-wolfcrypt-provider/src/prf.rs b/rustls-wolfcrypt-provider/src/prf.rs index 1ec2de1..7c682e5 100644 --- a/rustls-wolfcrypt-provider/src/prf.rs +++ b/rustls-wolfcrypt-provider/src/prf.rs @@ -8,7 +8,7 @@ pub struct WCPrfUsingHmac(pub WCShaHmac); impl crypto::tls12::Prf for WCPrfUsingHmac { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn for_key_exchange( diff --git a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs index 3f4629c..429a40d 100644 --- a/rustls-wolfcrypt-provider/src/verify/ecdsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/ecdsa.rs @@ -30,7 +30,7 @@ impl EcdsaVerifier { impl SignatureVerificationAlgorithm for EcdsaVerifier { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { diff --git a/rustls-wolfcrypt-provider/src/verify/eddsa.rs b/rustls-wolfcrypt-provider/src/verify/eddsa.rs index 9b5f7ed..1b1423c 100644 --- a/rustls-wolfcrypt-provider/src/verify/eddsa.rs +++ b/rustls-wolfcrypt-provider/src/verify/eddsa.rs @@ -7,7 +7,7 @@ pub struct Ed25519; impl SignatureVerificationAlgorithm for Ed25519 { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { diff --git a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs index 3739339..cc6917c 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapkcs1.rs @@ -17,7 +17,7 @@ pub struct RsaPkcs1Sha256Verify; impl SignatureVerificationAlgorithm for RsaPkcs1Sha256Verify { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { @@ -83,7 +83,7 @@ pub struct RsaPkcs1Sha384Verify; impl SignatureVerificationAlgorithm for RsaPkcs1Sha384Verify { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { @@ -149,7 +149,7 @@ pub struct RsaPkcs1Sha512Verify; impl SignatureVerificationAlgorithm for RsaPkcs1Sha512Verify { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { diff --git a/rustls-wolfcrypt-provider/src/verify/rsapss.rs b/rustls-wolfcrypt-provider/src/verify/rsapss.rs index 8188c41..4cff56d 100644 --- a/rustls-wolfcrypt-provider/src/verify/rsapss.rs +++ b/rustls-wolfcrypt-provider/src/verify/rsapss.rs @@ -33,7 +33,7 @@ pub struct RsaPssSha256Verify; impl SignatureVerificationAlgorithm for RsaPssSha256Verify { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { @@ -66,7 +66,7 @@ pub struct RsaPssSha384Verify; impl SignatureVerificationAlgorithm for RsaPssSha384Verify { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier { @@ -99,7 +99,7 @@ pub struct RsaPssSha512Verify; impl SignatureVerificationAlgorithm for RsaPssSha512Verify { fn fips(&self) -> bool { - cfg!(fips) + crate::fips() } fn public_key_alg_id(&self) -> AlgorithmIdentifier {