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}