Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitad0fab8

Browse files
committed
gh-127298: When in FIPS mode ensure builtin hashes check for usedforsecurity=False
When _hashlib/OpenSSL is available, and OpenSSL is in FIPS mode,ensure that builtin (fallback) hash implementations are wrapped with acheck for usedforsecurity=False. It is likely that buitinimplementations are FIPS unapproved (either algorithm disallowed; orthe implementation not certified by NIST).This enables strict approved-only compliance when usedforsecurity=Trueon FIPS systems only.And yet it also enables fallback access with usedforsecurity=False forany missing (historical, disallowed or missing certifiedimplementation) algorithms (i.e. blake2, md5, shake/sha3) depending onthe runtime configuration of OpenSSL.
1 parent2b0e2b2 commitad0fab8

File tree

6 files changed

+116
-16
lines changed

6 files changed

+116
-16
lines changed

‎Lib/hashlib.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,23 @@
7979
'blake2b','blake2s',
8080
}
8181

82+
# Wrapper that only allows usage when usedforsecurity=False
83+
# (effectively unapproved service indicator)
84+
def__usedforsecurity_check(md,name,*args,**kwargs):
85+
ifkwargs.get("usedforsecurity",True):
86+
raiseValueError(name+" is blocked when usedforsecurity=True")
87+
returnmd(*args,**kwargs)
88+
89+
# If _hashlib is in FIPS mode, use the above wrapper to ensure builtin
90+
# implementation checks usedforsecurity kwarg. It means all builtin
91+
# implementations are treated as an unapproved implementation, as they
92+
# are unlikely to have been certified by NIST.
93+
def__get_wrapped_builtin(md,name):
94+
if_hashlibisnotNoneand_hashlib.get_fips_mode()==1:
95+
fromfunctoolsimportpartial
96+
returnpartial(__usedforsecurity_check,md,name)
97+
returnmd
98+
8299
def__get_builtin_constructor(name):
83100
cache=__builtin_constructor_cache
84101
constructor=cache.get(name)
@@ -87,32 +104,32 @@ def __get_builtin_constructor(name):
87104
try:
88105
ifnamein {'SHA1','sha1'}:
89106
import_sha1
90-
cache['SHA1']=cache['sha1']=_sha1.sha1
107+
cache['SHA1']=cache['sha1']=__get_wrapped_builtin(_sha1.sha1,name)
91108
elifnamein {'MD5','md5'}:
92109
import_md5
93-
cache['MD5']=cache['md5']=_md5.md5
110+
cache['MD5']=cache['md5']=__get_wrapped_builtin(_md5.md5,name)
94111
elifnamein {'SHA256','sha256','SHA224','sha224'}:
95112
import_sha2
96-
cache['SHA224']=cache['sha224']=_sha2.sha224
97-
cache['SHA256']=cache['sha256']=_sha2.sha256
113+
cache['SHA224']=cache['sha224']=__get_wrapped_builtin(_sha2.sha224,name)
114+
cache['SHA256']=cache['sha256']=__get_wrapped_builtin(_sha2.sha256,name)
98115
elifnamein {'SHA512','sha512','SHA384','sha384'}:
99116
import_sha2
100-
cache['SHA384']=cache['sha384']=_sha2.sha384
101-
cache['SHA512']=cache['sha512']=_sha2.sha512
117+
cache['SHA384']=cache['sha384']=__get_wrapped_builtin(_sha2.sha384,name)
118+
cache['SHA512']=cache['sha512']=__get_wrapped_builtin(_sha2.sha512,name)
102119
elifnamein {'blake2b','blake2s'}:
103120
import_blake2
104-
cache['blake2b']=_blake2.blake2b
105-
cache['blake2s']=_blake2.blake2s
121+
cache['blake2b']=__get_wrapped_builtin(_blake2.blake2b,name)
122+
cache['blake2s']=__get_wrapped_builtin(_blake2.blake2s,name)
106123
elifnamein {'sha3_224','sha3_256','sha3_384','sha3_512'}:
107124
import_sha3
108-
cache['sha3_224']=_sha3.sha3_224
109-
cache['sha3_256']=_sha3.sha3_256
110-
cache['sha3_384']=_sha3.sha3_384
111-
cache['sha3_512']=_sha3.sha3_512
125+
cache['sha3_224']=__get_wrapped_builtin(_sha3.sha3_224,name)
126+
cache['sha3_256']=__get_wrapped_builtin(_sha3.sha3_256,name)
127+
cache['sha3_384']=__get_wrapped_builtin(_sha3.sha3_384,name)
128+
cache['sha3_512']=__get_wrapped_builtin(_sha3.sha3_512,name)
112129
elifnamein {'shake_128','shake_256'}:
113130
import_sha3
114-
cache['shake_128']=_sha3.shake_128
115-
cache['shake_256']=_sha3.shake_256
131+
cache['shake_128']=__get_wrapped_builtin(_sha3.shake_128,name)
132+
cache['shake_256']=__get_wrapped_builtin(_sha3.shake_256,name)
116133
exceptImportError:
117134
pass# no extension module, this hash is unsupported.
118135

@@ -163,7 +180,7 @@ def __hash_new(name, data=b'', **kwargs):
163180
# hash, try using our builtin implementations.
164181
# This allows for SHA224/256 and SHA384/512 support even though
165182
# the OpenSSL library prior to 0.9.8 doesn't provide them.
166-
return__get_builtin_constructor(name)(data)
183+
return__get_builtin_constructor(name)(data,**kwargs)
167184

168185

169186
try:

‎Lib/test/hashlibdata/openssl.cnf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Activate base provider only, with default properties fips=yes. It
2+
# means that fips mode is on, and no digest implementations are
3+
# available. Perfect for mock testing builtin FIPS wrappers.
4+
5+
config_diagnostics = 1
6+
openssl_conf = openssl_init
7+
8+
[openssl_init]
9+
providers = provider_sect
10+
alg_section = algorithm_sect
11+
12+
[provider_sect]
13+
base = base_sect
14+
15+
[base_sect]
16+
activate = 1
17+
18+
[algorithm_sect]
19+
default_properties =fips=yes

‎Lib/test/ssltests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
TESTS= [
99
'test_asyncio','test_ensurepip.py','test_ftplib','test_hashlib',
10-
'test_hmac','test_httplib','test_imaplib',
10+
'test_hashlib_fips','test_hmac','test_httplib','test_imaplib',
1111
'test_poplib','test_ssl','test_smtplib','test_smtpnet',
1212
'test_urllib2_localnet','test_venv','test_xmlrpc'
1313
]

‎Lib/test/test_hashlib_fips.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Test the hashlib module usedforsecurity wrappers under fips.
2+
#
3+
# Copyright (C) 2024 Dimitri John Ledkov (dimitri.ledkov@surgut.co.uk)
4+
# Licensed to PSF under a Contributor Agreement.
5+
#
6+
7+
importos
8+
importunittest
9+
10+
OPENSSL_CONF_BACKUP=os.environ.get("OPENSSL_CONF")
11+
12+
classHashLibFIPSTestCase(unittest.TestCase):
13+
@classmethod
14+
defsetUpClass(cls):
15+
# This openssl.cnf mocks FIPS mode without any digest
16+
# loaded. It means all digests must raise ValueError when
17+
# usedforsecurity=True via either openssl or builtin
18+
# constructors
19+
OPENSSL_CONF=os.path.join(os.path.dirname(__file__),"hashlibdata","openssl.cnf")
20+
os.environ["OPENSSL_CONF"]=OPENSSL_CONF
21+
# Ensure hashlib is loading a fresh libcrypto with openssl
22+
# context affected by the above config file. Check if this can
23+
# be folded into test_hashlib.py, specifically if
24+
# import_fresh_module() results in a fresh library context
25+
importhashlib
26+
27+
defsetUp(self):
28+
try:
29+
from_hashlibimportget_fips_mode
30+
exceptImportError:
31+
self.skipTest('_hashlib not available')
32+
33+
ifget_fips_mode()!=1:
34+
self.skipTest('mocking fips mode failed')
35+
36+
@classmethod
37+
deftearDownClass(cls):
38+
ifOPENSSL_CONF_BACKUP:
39+
os.environ["OPENSSL_CONF"]=OPENSSL_CONF_BACKUP
40+
else:
41+
del(os.environ["OPENSSL_CONF"])
42+
43+
deftest_algorithms_available(self):
44+
importhashlib
45+
self.assertTrue(set(hashlib.algorithms_guaranteed).
46+
issubset(hashlib.algorithms_available))
47+
# all available algorithms must be loadable, bpo-47101
48+
self.assertNotIn("undefined",hashlib.algorithms_available)
49+
fornameinhashlib.algorithms_available:
50+
digest=hashlib.new(name,usedforsecurity=False)
51+
52+
deftest_usedforsecurity_true(self):
53+
importhashlib
54+
fornameinhashlib.algorithms_available:
55+
withself.assertRaises(ValueError):
56+
digest=hashlib.new(name,usedforsecurity=True)
57+
58+
if__name__=="__main__":
59+
unittest.main()

‎Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,7 @@ TESTSUBDIRS=idlelib/idle_test \
24472447
test/decimaltestdata \
24482448
test/dtracedata \
24492449
test/encoded_modules \
2450+
test/hashlibdata \
24502451
test/leakers \
24512452
test/libregrtest \
24522453
test/mathdata \
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:mod:`hashlib`'s fallback builtin hash implementations now check
2+
usedforsecurity=True, if hashlib is in FIPS mode. This ensures that
3+
approved-only implementations are in use on FIPS systems by default,
4+
and fallback ones are made available for unapproved purposes only.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp