forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-127298: When in FIPS mode ensure builtin hashes check for us…
…edforsecurity=False When _hashlib/OpenSSL is available, and OpenSSL is in FIPS mode, ensure that builtin (fallback) hash implementations are wrapped with a check for usedforsecurity=False. It is likely that buitin implementations are FIPS unapproved (either algorithm disallowed; or the implementation not certified by NIST). This enables strict approved-only compliance when usedforsecurity=True on FIPS systems only. And yet it also enables fallback access with usedforsecurity=False for any missing (historical, disallowed or missing certified implementation) algorithms (i.e. blake2, md5, shake/sha3) depending on the runtime configuration of OpenSSL.
- Loading branch information
Showing
5 changed files
with
115 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Activate base provider only, with default properties fips=yes. It | ||
# means that fips mode is on, and no digest implementations are | ||
# available. Perfect for mock testing builtin FIPS wrappers. | ||
|
||
config_diagnostics = 1 | ||
openssl_conf = openssl_init | ||
|
||
[openssl_init] | ||
providers = provider_sect | ||
alg_section = algorithm_sect | ||
|
||
[provider_sect] | ||
base = base_sect | ||
|
||
[base_sect] | ||
activate = 1 | ||
|
||
[algorithm_sect] | ||
default_properties = fips=yes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Test the hashlib module usedforsecurity wrappers under fips. | ||
# | ||
# Copyright (C) 2024 Dimitri John Ledkov ([email protected]) | ||
# Licensed to PSF under a Contributor Agreement. | ||
# | ||
|
||
import os | ||
import unittest | ||
|
||
OPENSSL_CONF_BACKUP = os.environ.get("OPENSSL_CONF") | ||
|
||
class HashLibFIPSTestCase(unittest.TestCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
# This openssl.cnf mocks FIPS mode without any digest | ||
# loaded. It means all digests must raise ValueError when | ||
# usedforsecurity=True via either openssl or builtin | ||
# constructors | ||
OPENSSL_CONF = os.path.join(os.path.dirname(__file__), "hashlibdata", "openssl.cnf") | ||
os.environ["OPENSSL_CONF"] = OPENSSL_CONF | ||
# Ensure hashlib is loading a fresh libcrypto with openssl context | ||
# affected by the above config file. Check if this can be | ||
# folded into test_hashlib.py, specifically if | ||
# import_fresh_module() results in a fresh Open | ||
import hashlib | ||
|
||
def setUp(self): | ||
try: | ||
from _hashlib import get_fips_mode | ||
except ImportError: | ||
self.skipTest('_hashlib not available') | ||
|
||
if get_fips_mode() != 1: | ||
self.skipTest('mocking fips mode failed') | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
if OPENSSL_CONF_BACKUP: | ||
os.environ["OPENSSL_CONF"] = OPENSSL_CONF_BACKUP | ||
else: | ||
del(os.environ["OPENSSL_CONF"]) | ||
|
||
def test_algorithms_available(self): | ||
import hashlib | ||
self.assertTrue(set(hashlib.algorithms_guaranteed). | ||
issubset(hashlib.algorithms_available)) | ||
# all available algorithms must be loadable, bpo-47101 | ||
self.assertNotIn("undefined", hashlib.algorithms_available) | ||
for name in hashlib.algorithms_available: | ||
digest = hashlib.new(name, usedforsecurity=False) | ||
|
||
def test_usedforsecurity_true(self): | ||
import hashlib | ||
for name in hashlib.algorithms_available: | ||
with self.assertRaises(ValueError): | ||
digest = hashlib.new(name, usedforsecurity=True) | ||
|
||
if __name__ == "__main__": | ||
unittest.main() |
4 changes: 4 additions & 0 deletions
4
Misc/NEWS.d/next/Library/2024-11-26-16-31-40.gh-issue-127298.jqYJvn.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
:mod:`hashlib`'s fallback builtin hash implementations now check | ||
usedforsecurity=True, if hashlib is in FIPS mode. This ensures that | ||
approved-only implementations are in use on FIPS systems by default, | ||
and fallback ones are made available for unapproved purposes only. |