litellm/tests/unit/proxy/common_utils/test_fips.py
yucheng-berri 9f489430a6
fix(proxy): probe scrypt instead of MD5 in the fips_mode OpenSSL check (#50305)
* fix(proxy): probe scrypt instead of MD5 in the fips_mode OpenSSL check

* test(proxy): fake a working scrypt so the fips_mode check tests pass on FIPS hosts
2026-11-05 17:43:32 -08:00

121 lines
4.8 KiB
Python

import _hashlib
from collections.abc import Mapping
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
from litellm.proxy.common_utils.fips import (
FipsModeError,
cryptography_enforces_fips,
enforce_fips_mode,
openssl_enforces_fips,
)
def _fake_openssl(monkeypatch: pytest.MonkeyPatch, *, fips_flag: int, scrypt_refused: bool) -> None:
monkeypatch.setattr(_hashlib, "get_fips_mode", lambda: fips_flag)
if scrypt_refused:
monkeypatch.setattr(_hashlib, "scrypt", Mock(side_effect=ValueError("[digital envelope routines] unsupported")))
else:
monkeypatch.setattr(_hashlib, "scrypt", Mock(return_value=b"\0" * 16))
@pytest.mark.parametrize(
"fips_flag, scrypt_refused, enforces",
[(1, True, True), (0, True, False), (1, False, False)],
ids=["fips", "fips-flag-off", "scrypt-allowed"],
)
def test_openssl_enforces_fips_needs_the_fips_flag_and_a_refused_scrypt(
monkeypatch: pytest.MonkeyPatch, fips_flag: int, scrypt_refused: bool, enforces: bool
) -> None:
_fake_openssl(monkeypatch, fips_flag=fips_flag, scrypt_refused=scrypt_refused)
assert openssl_enforces_fips() is enforces
def test_openssl_enforces_fips_while_md5_is_still_served_for_non_security_use(monkeypatch: pytest.MonkeyPatch) -> None:
_fake_openssl(monkeypatch, fips_flag=1, scrypt_refused=True)
monkeypatch.setattr(_hashlib, "new", Mock(return_value=Mock()))
assert openssl_enforces_fips() is True
def test_openssl_without_get_fips_mode_does_not_enforce_fips(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delattr(_hashlib, "get_fips_mode")
assert openssl_enforces_fips() is False
@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: pytest.MonkeyPatch, fips_enabled: bool, sha256_broken: bool, enforces: bool
) -> None:
monkeypatch.setattr(rust_openssl, "is_fips_enabled", lambda: 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: pytest.MonkeyPatch) -> None:
monkeypatch.delattr(rust_openssl, "is_fips_enabled")
assert cryptography_enforces_fips() is False
def test_this_runners_python_openssl_does_not_enforce_fips() -> None:
if _hashlib.get_fips_mode() == 1:
pytest.skip("this runner's Python OpenSSL is in FIPS mode")
assert openssl_enforces_fips() is False
def test_this_runners_cryptography_openssl_does_not_enforce_fips() -> None:
if rust_openssl.is_fips_enabled():
pytest.skip("this runner's cryptography OpenSSL is in FIPS mode")
assert cryptography_enforces_fips() is False
@pytest.mark.parametrize(
"general_settings, openssl_fips, cryptography_fips, refusal",
[
({}, False, False, None),
({"fips_mode": False}, False, False, None),
({"fips_mode": "false"}, False, False, None),
({"fips_mode": True}, True, True, None),
({"fips_mode": "true"}, True, True, None),
({"fips_mode": True}, False, True, "general_settings.fips_mode is on but OpenSSL does not enforce FIPS"),
({"fips_mode": " TRUE "}, False, True, "general_settings.fips_mode is on but OpenSSL does not enforce FIPS"),
({"fips_mode": True}, True, False, "cryptography library's OpenSSL has no working FIPS provider"),
({"fips_mode": "enforced"}, True, True, "general_settings.fips_mode='enforced' is not a boolean"),
({"fips_mode": 1}, True, True, "general_settings.fips_mode=1 is not a boolean"),
({"fips_mode": None}, True, True, "general_settings.fips_mode has no value"),
],
ids=[
"unset",
"false",
"false-from-a-string",
"fips",
"fips-from-a-string",
"openssl-not-fips",
"openssl-not-fips-from-a-padded-string",
"cryptography-not-fips",
"not-a-boolean",
"a-number",
"no-value",
],
)
def test_enforce_fips_mode(
monkeypatch: pytest.MonkeyPatch,
general_settings: Mapping[str, object],
openssl_fips: bool,
cryptography_fips: bool,
refusal: str | None,
) -> None:
_fake_openssl(monkeypatch, fips_flag=int(openssl_fips), scrypt_refused=openssl_fips)
monkeypatch.setattr(rust_openssl, "is_fips_enabled", lambda: cryptography_fips)
with pytest.raises(FipsModeError, match=refusal) if refusal else nullcontext():
enforce_fips_mode(general_settings)