bpo-38270: More fixes for strict crypto policy (GH-16418)
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 <christian@python.org> https://bugs.python.org/issue38270
This commit is contained in:
parent
5faff977ad
commit
9055815809
|
@ -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."
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue