fix(proxy): refuse FIPS mode when cryptography's FIPS provider cannot hash

The stock cryptography wheel reads the host's FIPS config and reports FIPS on,
but its bundled OpenSSL cannot load the host's FIPS provider, so every
operation fails. Require a working SHA-256 alongside the FIPS flag.
This commit is contained in:
yucheng 2026-10-27 16:33:22 -07:00
parent 75c6d07a8f
commit 23ebd158bf
2 changed files with 29 additions and 10 deletions

View file

@ -31,13 +31,20 @@ def openssl_enforces_fips() -> bool:
def cryptography_enforces_fips() -> bool:
"""The cryptography library's own OpenSSL runs with FIPS-only defaults."""
"""The cryptography library's own OpenSSL runs with FIPS-only defaults and its FIPS provider can hash SHA-256."""
try:
from cryptography.exceptions import InternalError, UnsupportedAlgorithm
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
return rust_openssl.is_fips_enabled()
except (ImportError, AttributeError):
from cryptography.hazmat.primitives import hashes
except ImportError:
return False
try:
if not rust_openssl.is_fips_enabled():
return False
hashes.Hash(hashes.SHA256()).finalize()
except (AttributeError, InternalError, UnsupportedAlgorithm):
return False
return True
def enforce_fips_mode() -> None:
@ -63,6 +70,7 @@ def enforce_fips_mode() -> None:
)
if not cryptography_enforces_fips():
raise FipsModeError(
f"{FIPS_MODE_ENV_VAR} is on but the cryptography library's OpenSSL does not enforce FIPS. Build it against "
f"the system OpenSSL (pip install --no-binary cryptography cryptography), or unset {FIPS_MODE_ENV_VAR}."
f"{FIPS_MODE_ENV_VAR} is on but the cryptography library's OpenSSL has no working FIPS provider. Build it "
"against the system OpenSSL (pip install --no-binary cryptography cryptography), or unset "
f"{FIPS_MODE_ENV_VAR}."
)

View file

@ -1,8 +1,11 @@
import _hashlib
from contextlib import nullcontext
from unittest.mock import Mock
import pytest
from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.primitives import hashes
import litellm
from litellm.proxy.common_utils.fips import (
@ -50,10 +53,18 @@ def test_openssl_without_get_fips_mode_does_not_enforce_fips(monkeypatch):
assert openssl_enforces_fips() is False
@pytest.mark.parametrize("fips_enabled", [True, False])
def test_cryptography_enforces_fips_reads_its_openssl_fips_flag(monkeypatch, fips_enabled):
@pytest.mark.parametrize(
"fips_enabled, sha256_broken, enforces",
[(True, False, True), (False, False, False), (True, True, False)],
ids=["fips", "fips-flag-off", "sha256-broken"],
)
def test_cryptography_enforces_fips_needs_the_fips_flag_and_a_working_sha256(
monkeypatch, fips_enabled, sha256_broken, enforces
):
monkeypatch.setattr(rust_openssl, "is_fips_enabled", lambda: fips_enabled)
assert cryptography_enforces_fips() is fips_enabled
if sha256_broken:
monkeypatch.setattr(hashes, "Hash", Mock(side_effect=InternalError("Unknown OpenSSL error", [])))
assert cryptography_enforces_fips() is enforces
def test_cryptography_without_is_fips_enabled_does_not_enforce_fips(monkeypatch):
@ -78,7 +89,7 @@ def test_this_runners_openssl_does_not_enforce_fips():
("true", "false", True, True, True, "TLS certificate verification is disabled"),
("true", None, False, True, True, "TLS certificate verification is disabled"),
("true", None, True, False, True, "is on but OpenSSL does not enforce FIPS"),
("true", None, True, True, False, "cryptography library's OpenSSL does not enforce FIPS"),
("true", None, True, True, False, "cryptography library's OpenSSL has no working FIPS provider"),
("enforced", None, True, True, True, "LITELLM_FIPS_MODE='enforced' is not a boolean"),
],
ids=[