crossbario / crossbario/autobahn-python

[BUG] Compatibility: Support execution on FIPS-enabled Linux kernels (RHEL 9 / Rocky 9)

Open
#1,844 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-investigation
Dominant language
Python
Stars
2.5k
Forks
768
PR merge metrics
No merged PRs in 30d

Description

Porting OSS to the "Enterprise/Government" RHEL world, a potential issue is that Python's hashlib binds to the system OpenSSL. On RHEL 9 with FIPS mode enabled, OpenSSL will ruthlessly abort any call to a non-validated algorithm (like MD5) unless explicitly told it is not being used for security purposes.

Context

Deploying this project in regulated environments (US Defense / FedRAMP) requires the underlying OS to run in FIPS 140-2/3 mode.
Specifically, when running on RHEL 9 or Rocky Linux 9 (and potentially Amazon Linux 2023) where the kernel is booted with fips=1, the system OpenSSL library disables non-approved cryptographic algorithms.

The Problem

Currently, parts of the codebase might use hashlib.md5() (and possibly other non-FIPS algorithms). In a strict FIPS environment, invoking hashlib.md5() without specific flags causes the Python runtime to crash with a ValueError.

Example Traceback:

ValueError: [digital envelope routines] unsupported

Or in older OpenSSL versions:

ValueError: error:060800A3:digital envelope routines:EVP_DigestInit_ex:disabled for fips

While MD5 is broken for cryptographic security (signatures, collision resistance), it is frequently used for non-security purposes, such as:

  • Generating deterministic UUIDs
  • Cache keys
  • File fingerprinting / ETags
  • Internal ID generation
Proposed Solution

Python 3.9+ introduced the usedforsecurity flag in hashlib. We need to audit the codebase and update all instances of non-cryptographic hashing to explicitly flag them.

Before:

m = hashlib.md5(data)
# OR
m = hashlib.new('md5', data)

After:

# explicitly signal to OpenSSL that this is not for security
m = hashlib.md5(data, usedforsecurity=False) 
# OR
m = hashlib.new('md5', data, usedforsecurity=False)

Note that in the context of US Government compliance, the flag usedforsecurity=False does not mean "This is insecure." It effectively translates to:

    bypass_fips_allowlist=True

or

    i_accept_liability_for_using_math_nist_does_not_understand=True

and thus is (in my eyes) badly named (in Python).

Certain cryptographically secure algorithms are simply unknown or too new for NIST (again, professional opinion):

  • BLAKE2 / RIPEMD-160 are not broken. They are just "foreign" or "too new" for NIST. The fact that RHEL crashes on them is a policy enforcement implementation detail, not a security vulnerability in our code.

  • NIST FIPS standards lag behind modern cryptography by 5-10 years. (e.g., They are only just now finalizing PQC, while the industry has moved on). The fact that they force a crash on BLAKE2 (which is arguably safer than the approved SHA-1) is absurd, but it is the reality of the RHEL kernel.

Affected Environments
  • Python: CPython 3.11+, PyPy 3.11+
  • OS: RHEL 9, Rocky Linux 9, AlmaLinux 9 (UBI 9 images)
  • Architecture: x86_64, aarch64
Action Items
  • Audit hashlib.md5 usage: Grep the codebase for all instances of md5.
  • Audit hashlib.sha1 usage: SHA-1 is restricted in some newer FIPS profiles for signing, though usually allowed for HMAC. Check if usedforsecurity=False is applicable here as well.
  • Audit other algorithms: Ensure no usage of ARC4, Blowfish, or RIPEMD, which may be completely removed in FIPS builds regardless of flags.
  • Apply Fix: Update calls to use usedforsecurity=False where appropriate (targeting Python 3.9+ syntax).
  • Verify PyPy Compatibility: Ensure PyPy 3.11+ respects this flag or fails gracefully.
  • CI/Test: (Optional) Add a test case that mocks a FIPS environment or verifies the flag is passed.
Reference
A quick note on PyPy

PyPy 7.3.11+ (implementing Python 3.9) does support the usedforsecurity argument in the signature to maintain API compatibility, but historically, PyPy's _hashlib implementation was sometimes inconsistent in how it passed that flag down to the C-level OpenSSL EVP_MD_CTX_set_flags.

If running PyPy on RHEL 9, we definitely want to verify this manually. If PyPy ignores the flag and passes the call to a FIPS-locked OpenSSL, it will still crash.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by searching the codebase for hashlib.md5, hashlib.sha1, hashlib.new, and other algorithms named in the issue. Inspect each call site to determine whether the hash is used for security, then verify Python 3.9+ and PyPy compatibility. Done means appropriate non-security hashes pass usedforsecurity=False and the affected behavior is tested or verified in a FIPS-enabled environment.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.