rustls_cng_crypto/fips.rs
1//! # FIPS support
2//!
3//! To use rustls with this crate in FIPS mode, perform the following actions.
4//!
5//! ## 1. Enable FIPS mode for Windows
6//!
7//! See [Microsoft documentation](https://learn.microsoft.com/en-us/windows/security/security-foundations/certification/fips-140-validation).
8//!
9//! ## 2. Enable the `fips` feature, or explicitly use the [crate::fips_provider()] function
10//!
11//! The fips feature changes the behaviour of [crate::default_provider()] to use FIPS-approved cipher suites and key exchange groups.
12//! Or you can explicitly use the [crate::fips_provider()] function to create a provider with FIPS-approved cipher suites and key exchange groups.
13//! If Windows is not running in FIPS mode, the provider will be empty.
14//!
15//! ## 3. Specify `require_ems` when constructing [rustls::ClientConfig] or [rustls::ServerConfig]
16//!
17//! See [rustls documentation](https://docs.rs/rustls/latest/rustls/client/struct.ClientConfig.html#structfield.require_ems) for rationale.
18//!
19//! ## 4. Validate the FIPS status of your ClientConfig or ServerConfig at runtime
20//! See [rustls documentation on FIPS](https://docs.rs/rustls/latest/rustls/manual/_06_fips/index.html#3-validate-the-fips-status-of-your-clientconfigserverconfig-at-run-time).
21
22use rustls::crypto::CryptoProvider;
23use windows::Win32::Security::Cryptography::BCryptGetFipsAlgorithmMode;
24
25use crate::{KeyProvider, SecureRandom, ALL_CIPHER_SUITES, ALL_KX_GROUPS, SUPPORTED_SIG_ALGS};
26
27pub(crate) fn enabled() -> bool {
28 let mut enabled = 0u8;
29 unsafe {
30 BCryptGetFipsAlgorithmMode(&mut enabled).ok().unwrap();
31 }
32 enabled != 0
33}
34
35/// Returns a CNG-based [`CryptoProvider`] using FIPS-approved cipher suites and key exchange groups.
36///
37/// Usage requires that Windows is running in FIPS mode, otherwise the provider will be empty.
38pub fn provider() -> CryptoProvider {
39 CryptoProvider {
40 cipher_suites: ALL_CIPHER_SUITES
41 .iter()
42 .filter(|cs| cs.fips())
43 .cloned()
44 .collect(),
45 kx_groups: ALL_KX_GROUPS
46 .iter()
47 .filter(|kx| kx.fips())
48 .cloned()
49 .collect(),
50 signature_verification_algorithms: SUPPORTED_SIG_ALGS,
51 secure_random: &SecureRandom,
52 key_provider: &KeyProvider,
53 }
54}
55
56#[cfg(test)]
57mod tests {
58
59 use super::*;
60
61 #[test]
62 fn fips() {
63 let provider = provider();
64 assert_eq!(provider.fips(), enabled());
65 }
66
67 #[cfg(feature = "fips")]
68 #[test]
69 fn fips_provider_has_fips_cipher_suites() {
70 let provider = provider();
71 assert!(!provider.cipher_suites.is_empty());
72 assert!(!provider.kx_groups.is_empty());
73 assert!(provider.fips());
74 assert!(provider.cipher_suites.iter().any(|cs| cs.tls13().is_some()));
75 #[cfg(feature = "tls12")]
76 assert!(provider.cipher_suites.iter().any(|cs| cs.tls13().is_none()));
77 dbg!(provider);
78 }
79}