diff options
-rw-r--r-- | Lib/test/support/__init__.py | 20 | ||||
-rw-r--r-- | Lib/test/test_hashlib.py | 14 | ||||
-rw-r--r-- | Lib/test/test_hmac.py | 12 | ||||
-rw-r--r-- | Modules/_hashopenssl.c | 2 |
4 files changed, 36 insertions, 12 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index e401090..d593fc1 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -69,6 +69,11 @@ try: except ImportError: resource = None +try: + import _hashlib +except ImportError: + _hashlib = None + __all__ = [ # globals "PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast", @@ -86,8 +91,8 @@ __all__ = [ "create_empty_file", "can_symlink", "fs_is_case_insensitive", # unittest "is_resource_enabled", "requires", "requires_freebsd_version", - "requires_linux_version", "requires_mac_ver", "check_syntax_error", - "check_syntax_warning", + "requires_linux_version", "requires_mac_ver", "requires_hashdigest", + "check_syntax_error", "check_syntax_warning", "TransientResource", "time_out", "socket_peer_reset", "ioerror_peer_reset", "transient_internet", "BasicTestRunner", "run_unittest", "run_doctest", "skip_unless_symlink", "requires_gzip", "requires_bz2", "requires_lzma", @@ -649,12 +654,16 @@ def requires_mac_ver(*min_version): return decorator -def requires_hashdigest(digestname): +def requires_hashdigest(digestname, openssl=None, usedforsecurity=True): """Decorator raising SkipTest if a hashing algorithm is not available The hashing algorithm could be missing or blocked by a strict crypto policy. + If 'openssl' is True, then the decorator checks that OpenSSL provides + the algorithm. Otherwise the check falls back to built-in + implementations. The usedforsecurity flag is passed to the constructor. + ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS ValueError: unsupported hash type md4 """ @@ -662,7 +671,10 @@ def requires_hashdigest(digestname): @functools.wraps(func) def wrapper(*args, **kwargs): try: - hashlib.new(digestname) + if openssl and _hashlib is not None: + _hashlib.new(digestname, usedforsecurity=usedforsecurity) + else: + hashlib.new(digestname, usedforsecurity=usedforsecurity) except ValueError: raise unittest.SkipTest( f"hash digest '{digestname}' is not available." diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index d55de02..0e30b2f 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -8,6 +8,7 @@ import array from binascii import unhexlify +import functools import hashlib import importlib import itertools @@ -18,6 +19,7 @@ import unittest import warnings from test import support from test.support import _4G, bigmemtest, import_fresh_module +from test.support import requires_hashdigest from http.client import HTTPException # Were we compiled --with-pydebug or with #define Py_DEBUG? @@ -119,6 +121,7 @@ class HashLibTestCase(unittest.TestCase): constructors.add(_test_algorithm_via_hashlib_new) _hashlib = self._conditional_import_module('_hashlib') + self._hashlib = _hashlib if _hashlib: # These two algorithms should always be present when this module # is compiled. If not, something was compiled wrong. @@ -127,7 +130,13 @@ class HashLibTestCase(unittest.TestCase): for algorithm, constructors in self.constructors_to_test.items(): constructor = getattr(_hashlib, 'openssl_'+algorithm, None) if constructor: - constructors.add(constructor) + try: + constructor() + except ValueError: + # default constructor blocked by crypto policy + pass + else: + constructors.add(constructor) def add_builtin_constructor(name): constructor = getattr(hashlib, "__get_builtin_constructor")(name) @@ -193,6 +202,9 @@ class HashLibTestCase(unittest.TestCase): cons(b'', usedforsecurity=False) hashlib.new("sha256", usedforsecurity=True) hashlib.new("sha256", usedforsecurity=False) + if self._hashlib is not None: + self._hashlib.new("md5", usedforsecurity=False) + self._hashlib.openssl_md5(usedforsecurity=False) def test_unknown_hash(self): self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index 2c09de8..1bbf201 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -21,7 +21,7 @@ def ignore_warning(func): class TestVectorsTestCase(unittest.TestCase): - @requires_hashdigest('md5') + @requires_hashdigest('md5', openssl=True) def test_md5_vectors(self): # Test the HMAC module against test vectors from the RFC. @@ -79,7 +79,7 @@ class TestVectorsTestCase(unittest.TestCase): b"and Larger Than One Block-Size Data"), "6f630fad67cda0ee1fb1f562db3aa53e") - @requires_hashdigest('sha1') + @requires_hashdigest('sha1', openssl=True) def test_sha_vectors(self): def shatest(key, data, digest): h = hmac.HMAC(key, data, digestmod=hashlib.sha1) @@ -272,19 +272,19 @@ class TestVectorsTestCase(unittest.TestCase): '134676fb6de0446065c97440fa8c6a58', }) - @requires_hashdigest('sha224') + @requires_hashdigest('sha224', openssl=True) def test_sha224_rfc4231(self): self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64) - @requires_hashdigest('sha256') + @requires_hashdigest('sha256', openssl=True) def test_sha256_rfc4231(self): self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64) - @requires_hashdigest('sha384') + @requires_hashdigest('sha384', openssl=True) def test_sha384_rfc4231(self): self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128) - @requires_hashdigest('sha512') + @requires_hashdigest('sha512', openssl=True) def test_sha512_rfc4231(self): self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 48511f7..b147dbe 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -552,7 +552,7 @@ EVPnew(const EVP_MD *digest, } - if (!EVP_DigestInit(self->ctx, digest)) { + if (!EVP_DigestInit_ex(self->ctx, digest, NULL)) { _setException(PyExc_ValueError); Py_DECREF(self); return NULL; |