Skip to content

Commit 2413aa9

Browse files
committed
bpo-38270: More fixes for strict crypto policy
test_hmac and test_hashlib test built-in hashing implementations and OpenSSL-based hashing implementations. Add more checks to skip OpenSSL implementations when a strict crypto policy is active. Use EVP_DigestInit_ex() instead of EVP_DigestInit() to initialize the EVP context. The EVP_DigestInit() function clears alls flags and breaks usedforsecurity flag again. Signed-off-by: Christian Heimes <[email protected]>
1 parent 0bcbfa4 commit 2413aa9

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

Lib/test/support/__init__.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@
6969
except ImportError:
7070
resource = None
7171

72+
try:
73+
import _hashlib
74+
except ImportError:
75+
_hashlib = None
76+
7277
__all__ = [
7378
# globals
7479
"PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
@@ -86,8 +91,8 @@
8691
"create_empty_file", "can_symlink", "fs_is_case_insensitive",
8792
# unittest
8893
"is_resource_enabled", "requires", "requires_freebsd_version",
89-
"requires_linux_version", "requires_mac_ver", "check_syntax_error",
90-
"check_syntax_warning",
94+
"requires_linux_version", "requires_mac_ver", "requires_hashdigest",
95+
"check_syntax_error", "check_syntax_warning",
9196
"TransientResource", "time_out", "socket_peer_reset", "ioerror_peer_reset",
9297
"transient_internet", "BasicTestRunner", "run_unittest", "run_doctest",
9398
"skip_unless_symlink", "requires_gzip", "requires_bz2", "requires_lzma",
@@ -649,20 +654,27 @@ def wrapper(*args, **kw):
649654
return decorator
650655

651656

652-
def requires_hashdigest(digestname):
657+
def requires_hashdigest(digestname, openssl=None, usedforsecurity=True):
653658
"""Decorator raising SkipTest if a hashing algorithm is not available
654659
655660
The hashing algorithm could be missing or blocked by a strict crypto
656661
policy.
657662
663+
If 'openssl' is True, then the decorator checks that OpenSSL provides
664+
the algorithm. Otherwise the check falls back to built-in
665+
implementations. The usedforsecurity flag is passed to the constructor.
666+
658667
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS
659668
ValueError: unsupported hash type md4
660669
"""
661670
def decorator(func):
662671
@functools.wraps(func)
663672
def wrapper(*args, **kwargs):
664673
try:
665-
hashlib.new(digestname)
674+
if openssl and _hashlib is not None:
675+
_hashlib.new(digestname, usedforsecurity=usedforsecurity)
676+
else:
677+
hashlib.new(digestname, usedforsecurity=usedforsecurity)
666678
except ValueError:
667679
raise unittest.SkipTest(
668680
f"hash digest '{digestname}' is not available."

Lib/test/test_hashlib.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import array
1010
from binascii import unhexlify
11+
import functools
1112
import hashlib
1213
import importlib
1314
import itertools
@@ -18,6 +19,7 @@
1819
import warnings
1920
from test import support
2021
from test.support import _4G, bigmemtest, import_fresh_module
22+
from test.support import requires_hashdigest
2123
from http.client import HTTPException
2224

2325
# Were we compiled --with-pydebug or with #define Py_DEBUG?
@@ -119,6 +121,7 @@ def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
119121
constructors.add(_test_algorithm_via_hashlib_new)
120122

121123
_hashlib = self._conditional_import_module('_hashlib')
124+
self._hashlib = _hashlib
122125
if _hashlib:
123126
# These two algorithms should always be present when this module
124127
# is compiled. If not, something was compiled wrong.
@@ -127,7 +130,13 @@ def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
127130
for algorithm, constructors in self.constructors_to_test.items():
128131
constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
129132
if constructor:
130-
constructors.add(constructor)
133+
try:
134+
constructor()
135+
except ValueError:
136+
# default constructor blocked by crypto policy
137+
pass
138+
else:
139+
constructors.add(constructor)
131140

132141
def add_builtin_constructor(name):
133142
constructor = getattr(hashlib, "__get_builtin_constructor")(name)
@@ -193,6 +202,9 @@ def test_usedforsecurity(self):
193202
cons(b'', usedforsecurity=False)
194203
hashlib.new("sha256", usedforsecurity=True)
195204
hashlib.new("sha256", usedforsecurity=False)
205+
if self._hashlib is not None:
206+
self._hashlib.new("md5", usedforsecurity=False)
207+
self._hashlib.openssl_md5(usedforsecurity=False)
196208

197209
def test_unknown_hash(self):
198210
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')

Lib/test/test_hmac.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def wrapper(*args, **kwargs):
2121

2222
class TestVectorsTestCase(unittest.TestCase):
2323

24-
@requires_hashdigest('md5')
24+
@requires_hashdigest('md5', openssl=True)
2525
def test_md5_vectors(self):
2626
# Test the HMAC module against test vectors from the RFC.
2727

@@ -79,7 +79,7 @@ def md5test(key, data, digest):
7979
b"and Larger Than One Block-Size Data"),
8080
"6f630fad67cda0ee1fb1f562db3aa53e")
8181

82-
@requires_hashdigest('sha1')
82+
@requires_hashdigest('sha1', openssl=True)
8383
def test_sha_vectors(self):
8484
def shatest(key, data, digest):
8585
h = hmac.HMAC(key, data, digestmod=hashlib.sha1)
@@ -272,19 +272,19 @@ def hmactest(key, data, hexdigests):
272272
'134676fb6de0446065c97440fa8c6a58',
273273
})
274274

275-
@requires_hashdigest('sha224')
275+
@requires_hashdigest('sha224', openssl=True)
276276
def test_sha224_rfc4231(self):
277277
self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64)
278278

279-
@requires_hashdigest('sha256')
279+
@requires_hashdigest('sha256', openssl=True)
280280
def test_sha256_rfc4231(self):
281281
self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64)
282282

283-
@requires_hashdigest('sha384')
283+
@requires_hashdigest('sha384', openssl=True)
284284
def test_sha384_rfc4231(self):
285285
self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128)
286286

287-
@requires_hashdigest('sha512')
287+
@requires_hashdigest('sha512', openssl=True)
288288
def test_sha512_rfc4231(self):
289289
self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128)
290290

Modules/_hashopenssl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ EVPnew(const EVP_MD *digest,
552552
}
553553

554554

555-
if (!EVP_DigestInit(self->ctx, digest)) {
555+
if (!EVP_DigestInit_ex(self->ctx, digest, NULL)) {
556556
_setException(PyExc_ValueError);
557557
Py_DECREF(self);
558558
return NULL;

0 commit comments

Comments
 (0)