use std::sync::OnceLock;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum CryptoProviderError {
#[error("failed to install FIPS crypto provider - another provider is already installed")]
FipsProviderConflict,
#[cfg(target_os = "windows")]
#[error(
"Windows is not in FIPS mode (HKLM\\System\\CurrentControlSet\\Control\\Lsa\\FipsAlgorithmPolicy != 1). \
Enable system-wide FIPS via Group Policy (Computer Configuration > Windows Settings > \
Security Settings > Local Policies > Security Options > 'System cryptography: Use FIPS \
compliant algorithms') and reboot before launching this service."
)]
SystemFipsModeNotEnabled,
}
static INIT_RESULT: OnceLock<Result<(), CryptoProviderError>> = OnceLock::new();
pub fn init_crypto_provider() -> Result<(), CryptoProviderError> {
INIT_RESULT
.get_or_init(|| {
#[cfg(all(feature = "fips", target_os = "macos"))]
{
if let Err(prev) = rustls_corecrypto_provider::default_provider().install_default()
{
tracing::error!(
previous_provider = ?prev,
"FIPS crypto provider conflict: another rustls provider was already installed"
);
return Err(CryptoProviderError::FipsProviderConflict);
}
tracing::info!("FIPS-140-3 crypto provider installed (Apple corecrypto, macOS, TLS 1.3-only)");
}
#[cfg(all(feature = "fips", target_os = "windows"))]
{
let provider = rustls_cng_crypto::fips_provider();
if provider.cipher_suites.is_empty() {
tracing::error!(
"Windows FIPS mode not enabled (FipsAlgorithmPolicy != 1); \
rustls-cng-crypto returned an empty FIPS provider"
);
return Err(CryptoProviderError::SystemFipsModeNotEnabled);
}
if let Err(prev) = provider.install_default() {
tracing::error!(
previous_provider = ?prev,
"FIPS crypto provider conflict: another rustls provider was already installed"
);
return Err(CryptoProviderError::FipsProviderConflict);
}
tracing::info!("FIPS-140-3 crypto provider installed (Windows CNG)");
}
#[cfg(all(feature = "fips", not(any(target_os = "macos", target_os = "windows"))))]
{
if let Err(prev) = rustls::crypto::default_fips_provider().install_default() {
tracing::error!(
previous_provider = ?prev,
"FIPS crypto provider conflict: another rustls provider was already installed"
);
return Err(CryptoProviderError::FipsProviderConflict);
}
tracing::info!("FIPS-140-3 crypto provider installed (AWS-LC FIPS module)");
}
#[cfg(feature = "fips")]
{
let Some(provider) = rustls::crypto::CryptoProvider::get_default() else {
unreachable!("provider must be installed at this point");
};
assert!(
provider.fips(),
"FIPS post-install witness failed: installed provider does not report fips()==true"
);
tracing::info!("FIPS post-install witness: OK");
}
#[cfg(not(feature = "fips"))]
{
if let Err(prev) = rustls::crypto::aws_lc_rs::default_provider().install_default() {
tracing::warn!(
previous_provider = ?prev,
"aws-lc-rs crypto provider not installed: another default provider was already set"
);
} else {
tracing::info!("aws-lc-rs crypto provider installed");
}
}
Ok(())
})
.clone()
}