From ef8944e45aafe2e9b38b848587099c0c691dd8ac Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jul 28 2020 12:08:16 +0000 Subject: import python38-3.8.3-1.module+el8.3.0+7187+a27ec44b --- diff --git a/.gitignore b/.gitignore index 0a63432..b50fd1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/Python-3.8.0.tar.xz +SOURCES/Python-3.8.3.tar.xz diff --git a/.python38.metadata b/.python38.metadata index f6fe148..6c2bce0 100644 --- a/.python38.metadata +++ b/.python38.metadata @@ -1 +1 @@ -7720e0384558c598107cf046c48165fd7e1f5b2c SOURCES/Python-3.8.0.tar.xz +3bafa40df1cd069c112761c388a9f2e94b5d33dd SOURCES/Python-3.8.3.tar.xz diff --git a/SOURCES/00001-rpath.patch b/SOURCES/00001-rpath.patch index d9dd3ce..15f95a9 100644 --- a/SOURCES/00001-rpath.patch +++ b/SOURCES/00001-rpath.patch @@ -1,4 +1,4 @@ -From 8ecb6d320c03242ca94bf2e99d9d80510d5011e1 Mon Sep 17 00:00:00 2001 +From 08c67bfedd07ebec54f5087b59045b8c78fa2a6d Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 Jan 2010 21:25:18 +0000 Subject: [PATCH] 00001: Fixup distutils/unixccompiler.py to remove standard @@ -9,7 +9,7 @@ Subject: [PATCH] 00001: Fixup distutils/unixccompiler.py to remove standard 1 file changed, 9 insertions(+) diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py -index d10a78da31..4df4b67810 100644 +index 4d7a6de740..353086a648 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -82,6 +82,15 @@ class UnixCCompiler(CCompiler): @@ -29,5 +29,5 @@ index d10a78da31..4df4b67810 100644 include_dirs=None, extra_preargs=None, extra_postargs=None): fixed_args = self._fix_compile_args(None, macros, include_dirs) -- -2.21.0 +2.26.2 diff --git a/SOURCES/00102-lib64.patch b/SOURCES/00102-lib64.patch index f1f0c8d..5acaf5c 100644 --- a/SOURCES/00102-lib64.patch +++ b/SOURCES/00102-lib64.patch @@ -1,4 +1,4 @@ -From b9f1dd6be195cc3b11a80e6f0dde2096dd8b9855 Mon Sep 17 00:00:00 2001 +From be6b9803109c3702dbff0ed8b0953913206008ca Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 Jan 2010 21:25:18 +0000 Subject: [PATCH] 00102: Change the various install paths to use /usr/lib64/ @@ -139,10 +139,10 @@ index b9e2fafbc0..0ae6d35b69 100644 'scripts': '{userbase}/bin', 'data': '{userbase}', diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py -index 41c4229919..543c88432a 100644 +index 1bbc697936..9a7e80dfa0 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py -@@ -266,8 +266,8 @@ class HelperFunctionsTests(unittest.TestCase): +@@ -267,8 +267,8 @@ class HelperFunctionsTests(unittest.TestCase): dirs = site.getsitepackages() if os.sep == '/': # OS X, Linux, FreeBSD, etc @@ -154,7 +154,7 @@ index 41c4229919..543c88432a 100644 'site-packages') self.assertEqual(dirs[0], wanted) diff --git a/Makefile.pre.in b/Makefile.pre.in -index 502317aa0c..4ad3df1122 100644 +index a914a9c70f..406a441082 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -143,7 +143,7 @@ LIBDIR= @libdir@ @@ -198,10 +198,10 @@ index b727f66953..a0c5fb6139 100644 return DECODE_LOCALE_ERR("EXEC_PREFIX define", len); } diff --git a/configure b/configure -index 2a933cdbeb..bec365124e 100755 +index 8886561645..78867c6ffc 100755 --- a/configure +++ b/configure -@@ -15182,9 +15182,9 @@ fi +@@ -15214,9 +15214,9 @@ fi if test x$PLATFORM_TRIPLET = x; then @@ -214,10 +214,10 @@ index 2a933cdbeb..bec365124e 100755 diff --git a/configure.ac b/configure.ac -index a189d42c2c..154a0aa5cc 100644 +index d8de9d4943..477a5ff1cb 100644 --- a/configure.ac +++ b/configure.ac -@@ -4668,9 +4668,9 @@ fi +@@ -4689,9 +4689,9 @@ fi dnl define LIBPL after ABIFLAGS and LDVERSION is defined. AC_SUBST(PY_ENABLE_SHARED) if test x$PLATFORM_TRIPLET = x; then @@ -230,7 +230,7 @@ index a189d42c2c..154a0aa5cc 100644 AC_SUBST(LIBPL) diff --git a/setup.py b/setup.py -index 20d7f35652..024a1035c0 100644 +index b168ed4082..8628b9d1cd 100644 --- a/setup.py +++ b/setup.py @@ -649,7 +649,7 @@ class PyBuildExt(build_ext): @@ -257,5 +257,5 @@ index 20d7f35652..024a1035c0 100644 libraries=readline_libs)) else: -- -2.21.0 +2.26.2 diff --git a/SOURCES/00111-no-static-lib.patch b/SOURCES/00111-no-static-lib.patch index 361af70..ed8ca3e 100644 --- a/SOURCES/00111-no-static-lib.patch +++ b/SOURCES/00111-no-static-lib.patch @@ -1,4 +1,4 @@ -From f6df02cde47874f10e183ead483c90941bb8076f Mon Sep 17 00:00:00 2001 +From 50236468e82a7a19ed3dd7e13cb922e7d3e0ff7f Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 18 Jan 2010 17:59:07 +0000 Subject: [PATCH] 00111: Don't try to build a libpythonMAJOR.MINOR.a @@ -21,7 +21,7 @@ Co-authored-by: Miro Hrončok 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in -index 4ad3df1122..72d202d71b 100644 +index 406a441082..917303dd92 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -562,7 +562,7 @@ clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c @@ -74,5 +74,5 @@ index 4ad3df1122..72d202d71b 100644 $(INSTALL_DATA) Programs/python.o $(DESTDIR)$(LIBPL)/python.o $(INSTALL_DATA) $(srcdir)/Modules/config.c.in $(DESTDIR)$(LIBPL)/config.c.in -- -2.21.0 +2.26.2 diff --git a/SOURCES/00189-use-rpm-wheels.patch b/SOURCES/00189-use-rpm-wheels.patch index 83487e3..8d44707 100644 --- a/SOURCES/00189-use-rpm-wheels.patch +++ b/SOURCES/00189-use-rpm-wheels.patch @@ -1,40 +1,45 @@ -From e5c11f104e1d2543ac3ba4b3f0a7989821e57947 Mon Sep 17 00:00:00 2001 +From 36f1f2b4620b13bdc7ac1c349253ac07960c33b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 15 Aug 2018 15:36:29 +0200 Subject: [PATCH] 00189: Instead of bundled wheels, use our RPM packaged wheels We keep them in /usr/share/python-wheels --- - Lib/ensurepip/__init__.py | 26 +++++++++++++++++--------- - 1 file changed, 17 insertions(+), 9 deletions(-) + Lib/ensurepip/__init__.py | 32 ++++++++++++++++++++++---------- + 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py -index fc0edec6e3..4d17e413db 100644 +index 566fb2a096..47da08d3d5 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py -@@ -1,16 +1,27 @@ +@@ -1,6 +1,7 @@ +import distutils.version +import glob import os import os.path -import pkgutil import sys + import runpy import tempfile - +@@ -8,10 +9,24 @@ import tempfile __all__ = ["version", "bootstrap"] +_WHEEL_DIR = "/usr/share/python38-wheels/" -_SETUPTOOLS_VERSION = "41.2.0" ++_wheels = {} -_PIP_VERSION = "19.2.3" +def _get_most_recent_wheel_version(pkg): + prefix = os.path.join(_WHEEL_DIR, "{}-".format(pkg)) -+ suffix = "-py2.py3-none-any.whl" -+ pattern = "{}*{}".format(prefix, suffix) -+ versions = (p[len(prefix):-len(suffix)] for p in glob.glob(pattern)) -+ return str(max(versions, key=distutils.version.LooseVersion)) ++ _wheels[pkg] = {} ++ for suffix in "-py2.py3-none-any.whl", "-py3-none-any.whl": ++ pattern = "{}*{}".format(prefix, suffix) ++ for path in glob.glob(pattern): ++ version_str = path[len(prefix):-len(suffix)] ++ _wheels[pkg][version_str] = os.path.basename(path) ++ return str(max(_wheels[pkg], key=distutils.version.LooseVersion)) + + +_SETUPTOOLS_VERSION = _get_most_recent_wheel_version("setuptools") @@ -43,16 +48,18 @@ index fc0edec6e3..4d17e413db 100644 _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION), -@@ -96,12 +107,9 @@ def _bootstrap(*, root=None, upgrade=False, user=False, +@@ -105,13 +120,10 @@ def _bootstrap(*, root=None, upgrade=False, user=False, + # additional paths that need added to sys.path additional_paths = [] for project, version in _PROJECTS: - wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version) +- wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version) - whl = pkgutil.get_data( - "ensurepip", - "_bundled/{}".format(wheel_name), - ) - with open(os.path.join(tmpdir, wheel_name), "wb") as fp: - fp.write(whl) ++ wheel_name = _wheels[project][version] + with open(os.path.join(_WHEEL_DIR, wheel_name), "rb") as sfp: + with open(os.path.join(tmpdir, wheel_name), "wb") as fp: + fp.write(sfp.read()) @@ -60,5 +67,5 @@ index fc0edec6e3..4d17e413db 100644 additional_paths.append(os.path.join(tmpdir, wheel_name)) -- -2.21.0 +2.26.2 diff --git a/SOURCES/00251-change-user-install-location.patch b/SOURCES/00251-change-user-install-location.patch index 1e0ddbb..e993c42 100644 --- a/SOURCES/00251-change-user-install-location.patch +++ b/SOURCES/00251-change-user-install-location.patch @@ -1,4 +1,4 @@ -From 76330e0a8798b3b03160edc7e8d42d3dbee756fd Mon Sep 17 00:00:00 2001 +From 197b8de27ebcd17fc5dd51426a639950c6f6c284 Mon Sep 17 00:00:00 2001 From: Michal Cyprian Date: Mon, 26 Jun 2017 16:32:56 +0200 Subject: [PATCH] 00251: Change user install location @@ -60,5 +60,5 @@ index 22d53fa562..9513526109 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) -- -2.21.0 +2.26.2 diff --git a/SOURCES/00274-fix-arch-names.patch b/SOURCES/00274-fix-arch-names.patch index f383a58..26654f2 100644 --- a/SOURCES/00274-fix-arch-names.patch +++ b/SOURCES/00274-fix-arch-names.patch @@ -1,4 +1,4 @@ -From 64c67dbfa789f242e8ffd1ac88bafb4df2842401 Mon Sep 17 00:00:00 2001 +From 3172104314227af128f3ce68e9650663a7c1268c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 28 Aug 2017 17:16:46 +0200 Subject: [PATCH] 00274: Upstream uses Debian-style architecture naming, change @@ -29,10 +29,10 @@ index ba37cf99e2..52a9ec6662 100755 ppc64le | powerpc64little) basic_machine=powerpc64le-unknown diff --git a/configure.ac b/configure.ac -index 154a0aa5cc..273954f461 100644 +index 477a5ff1cb..aea27ef86a 100644 --- a/configure.ac +++ b/configure.ac -@@ -741,9 +741,9 @@ cat >> conftest.c <> conftest.c <> conftest.c <> conftest.c <> conftest.c <> conftest.c < Date: Thu, 11 Jul 2019 13:44:13 +0200 Subject: [PATCH] 00328: Restore pyc to TIMESTAMP invalidation mode as default @@ -31,7 +31,7 @@ index 21736896af..310bed5620 100644 else: return PycInvalidationMode.TIMESTAMP diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py -index d6677ab45f..88059b127e 100644 +index d4a68c9320..ed09874023 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -17,6 +17,7 @@ def without_source_date_epoch(fxn): @@ -51,5 +51,5 @@ index d6677ab45f..88059b127e 100644 return wrapper -- -2.21.0 +2.26.2 diff --git a/SOURCES/00329-fips.patch b/SOURCES/00329-fips.patch new file mode 100644 index 0000000..4c96d02 --- /dev/null +++ b/SOURCES/00329-fips.patch @@ -0,0 +1,7145 @@ +From eba7874ad8a269c1e6e7f56a3f1d759448a0ea83 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 25 Jul 2019 16:19:52 +0200 +Subject: [PATCH 01/36] Expose OpenSSL FIPS_mode() as hashlib.get_fips_mode() + +--- + Lib/hashlib.py | 5 +++++ + Modules/_hashopenssl.c | 37 +++++++++++++++++++++++++++++++++ + Modules/clinic/_hashopenssl.c.h | 25 +++++++++++++++++++++- + 3 files changed, 66 insertions(+), 1 deletion(-) + +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index 56873b7..63ae836 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -243,6 +243,11 @@ try: + except ImportError: + pass + ++try: ++ from _hashlib import get_fips_mode ++except ImportError: ++ pass ++ + + for __func_name in __always_supported: + # try them all, some may not work due to the OpenSSL +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index 3e5f9c3..d38aae9 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -26,6 +26,9 @@ + #include + #include "openssl/err.h" + ++/* Expose FIPS_mode */ ++#include ++ + #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL < 1.1.0 */ + #define EVP_MD_CTX_new EVP_MD_CTX_create +@@ -1068,12 +1071,46 @@ generate_hash_name_list(void) + return state.set; + } + ++/*[clinic input] ++_hashlib.get_fips_mode ++ ++Determine the OpenSSL FIPS mode of operation. ++ ++Effectively any non-zero return value indicates FIPS mode; ++values other than 1 may have additional significance. ++ ++See OpenSSL documentation for the FIPS_mode() function for details. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_get_fips_mode_impl(PyObject *module) ++/*[clinic end generated code: output=ad8a7793310d3f98 input=f42a2135df2a5e11]*/ ++ ++{ ++ int result = FIPS_mode(); ++ if (result == 0) { ++ // "If the library was built without support of the FIPS Object Module, ++ // then the function will return 0 with an error code of ++ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." ++ // But 0 is also a valid result value. ++ ++ unsigned long errcode = ERR_peek_last_error(); ++ if (errcode) { ++ _setException(PyExc_ValueError); ++ return NULL; ++ } ++ } ++ return PyLong_FromLong(result); ++} ++ ++ + /* List of functions exported by this module */ + + static struct PyMethodDef EVP_functions[] = { + EVP_NEW_METHODDEF + PBKDF2_HMAC_METHODDEF + _HASHLIB_SCRYPT_METHODDEF ++ _HASHLIB_GET_FIPS_MODE_METHODDEF + _HASHLIB_HMAC_DIGEST_METHODDEF + _HASHLIB_OPENSSL_MD5_METHODDEF + _HASHLIB_OPENSSL_SHA1_METHODDEF +diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h +index 9aaea47..30fd8a9 100644 +--- a/Modules/clinic/_hashopenssl.c.h ++++ b/Modules/clinic/_hashopenssl.c.h +@@ -620,7 +620,30 @@ exit: + return return_value; + } + ++PyDoc_STRVAR(_hashlib_get_fips_mode__doc__, ++"get_fips_mode($module, /)\n" ++"--\n" ++"\n" ++"Determine the OpenSSL FIPS mode of operation.\n" ++"\n" ++"Effectively any non-zero return value indicates FIPS mode;\n" ++"values other than 1 may have additional significance.\n" ++"\n" ++"See OpenSSL documentation for the FIPS_mode() function for details."); ++ ++#define _HASHLIB_GET_FIPS_MODE_METHODDEF \ ++ {"get_fips_mode", (PyCFunction)_hashlib_get_fips_mode, METH_NOARGS, _hashlib_get_fips_mode__doc__}, ++ ++static PyObject * ++_hashlib_get_fips_mode_impl(PyObject *module); ++ ++static PyObject * ++_hashlib_get_fips_mode(PyObject *module, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hashlib_get_fips_mode_impl(module); ++} ++ + #ifndef _HASHLIB_SCRYPT_METHODDEF + #define _HASHLIB_SCRYPT_METHODDEF + #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ +-/*[clinic end generated code: output=38c2637f67e9bb79 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=5467006d93e7479e input=a9049054013a1b77]*/ +-- +2.25.4 + + +From 692168044948a41211bb0efabacf0cbfade8db14 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 25 Jul 2019 17:04:06 +0200 +Subject: [PATCH 02/36] Use python's fall backs for the crypto it implements + only if we are not in FIPS mode + +--- + Lib/hashlib.py | 207 +++++++++++++++------------------------ + Lib/test/test_hashlib.py | 1 + + 2 files changed, 81 insertions(+), 127 deletions(-) + +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index 63ae836..1bcfdf9 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -68,7 +68,6 @@ __all__ = __always_supported + ('new', 'algorithms_guaranteed', + 'algorithms_available', 'pbkdf2_hmac') + + +-__builtin_constructor_cache = {} + + __block_openssl_constructor = { + 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', +@@ -76,54 +75,64 @@ __block_openssl_constructor = { + 'blake2b', 'blake2s', + } + +-def __get_builtin_constructor(name): +- cache = __builtin_constructor_cache +- constructor = cache.get(name) +- if constructor is not None: +- return constructor +- try: +- if name in {'SHA1', 'sha1'}: +- import _sha1 +- cache['SHA1'] = cache['sha1'] = _sha1.sha1 +- elif name in {'MD5', 'md5'}: +- import _md5 +- cache['MD5'] = cache['md5'] = _md5.md5 +- elif name in {'SHA256', 'sha256', 'SHA224', 'sha224'}: +- import _sha256 +- cache['SHA224'] = cache['sha224'] = _sha256.sha224 +- cache['SHA256'] = cache['sha256'] = _sha256.sha256 +- elif name in {'SHA512', 'sha512', 'SHA384', 'sha384'}: +- import _sha512 +- cache['SHA384'] = cache['sha384'] = _sha512.sha384 +- cache['SHA512'] = cache['sha512'] = _sha512.sha512 +- elif name in {'blake2b', 'blake2s'}: +- import _blake2 +- cache['blake2b'] = _blake2.blake2b +- cache['blake2s'] = _blake2.blake2s +- elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512'}: +- import _sha3 +- cache['sha3_224'] = _sha3.sha3_224 +- cache['sha3_256'] = _sha3.sha3_256 +- cache['sha3_384'] = _sha3.sha3_384 +- cache['sha3_512'] = _sha3.sha3_512 +- elif name in {'shake_128', 'shake_256'}: +- import _sha3 +- cache['shake_128'] = _sha3.shake_128 +- cache['shake_256'] = _sha3.shake_256 +- except ImportError: +- pass # no extension module, this hash is unsupported. +- +- constructor = cache.get(name) +- if constructor is not None: +- return constructor +- +- raise ValueError('unsupported hash type ' + name) ++try: ++ from _hashlib import get_fips_mode ++except ImportError: ++ def get_fips_mode(): ++ return 0 ++ ++if not get_fips_mode(): ++ __builtin_constructor_cache = {} ++ ++ def __get_builtin_constructor(name): ++ cache = __builtin_constructor_cache ++ constructor = cache.get(name) ++ if constructor is not None: ++ return constructor ++ try: ++ if name in {'SHA1', 'sha1'}: ++ import _sha1 ++ cache['SHA1'] = cache['sha1'] = _sha1.sha1 ++ elif name in {'MD5', 'md5'}: ++ import _md5 ++ cache['MD5'] = cache['md5'] = _md5.md5 ++ elif name in {'SHA256', 'sha256', 'SHA224', 'sha224'}: ++ import _sha256 ++ cache['SHA224'] = cache['sha224'] = _sha256.sha224 ++ cache['SHA256'] = cache['sha256'] = _sha256.sha256 ++ elif name in {'SHA512', 'sha512', 'SHA384', 'sha384'}: ++ import _sha512 ++ cache['SHA384'] = cache['sha384'] = _sha512.sha384 ++ cache['SHA512'] = cache['sha512'] = _sha512.sha512 ++ elif name in {'blake2b', 'blake2s'}: ++ import _blake2 ++ cache['blake2b'] = _blake2.blake2b ++ cache['blake2s'] = _blake2.blake2s ++ elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512'}: ++ import _sha3 ++ cache['sha3_224'] = _sha3.sha3_224 ++ cache['sha3_256'] = _sha3.sha3_256 ++ cache['sha3_384'] = _sha3.sha3_384 ++ cache['sha3_512'] = _sha3.sha3_512 ++ elif name in {'shake_128', 'shake_256'}: ++ import _sha3 ++ cache['shake_128'] = _sha3.shake_128 ++ cache['shake_256'] = _sha3.shake_256 ++ except ImportError: ++ pass # no extension module, this hash is unsupported. ++ ++ constructor = cache.get(name) ++ if constructor is not None: ++ return constructor ++ ++ raise ValueError('unsupported hash type ' + name) + + + def __get_openssl_constructor(name): +- if name in __block_openssl_constructor: +- # Prefer our blake2 and sha3 implementation. +- return __get_builtin_constructor(name) ++ if not get_fips_mode(): ++ if name in __block_openssl_constructor: ++ # Prefer our blake2 and sha3 implementation. ++ return __get_builtin_constructor(name) + try: + f = getattr(_hashlib, 'openssl_' + name) + # Allow the C module to raise ValueError. The function will be +@@ -132,27 +141,31 @@ def __get_openssl_constructor(name): + # Use the C function directly (very fast) + return f + except (AttributeError, ValueError): ++ if get_fips_mode(): ++ raise + return __get_builtin_constructor(name) + + +-def __py_new(name, data=b'', **kwargs): +- """new(name, data=b'', **kwargs) - Return a new hashing object using the +- named algorithm; optionally initialized with data (which must be +- a bytes-like object). +- """ +- return __get_builtin_constructor(name)(data, **kwargs) ++if not get_fips_mode(): ++ def __py_new(name, data=b'', **kwargs): ++ """new(name, data=b'', **kwargs) - Return a new hashing object using the ++ named algorithm; optionally initialized with data (which must be ++ a bytes-like object). ++ """ ++ return __get_builtin_constructor(name)(data, **kwargs) + + + def __hash_new(name, data=b'', **kwargs): + """new(name, data=b'') - Return a new hashing object using the named algorithm; + optionally initialized with data (which must be a bytes-like object). + """ +- if name in __block_openssl_constructor: +- # Prefer our blake2 and sha3 implementation +- # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s. +- # It does neither support keyed blake2 nor advanced features like +- # salt, personal, tree hashing or SSE. +- return __get_builtin_constructor(name)(data, **kwargs) ++ if not get_fips_mode(): ++ if name in __block_openssl_constructor: ++ # Prefer our blake2 and sha3 implementation ++ # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s. ++ # It does neither support keyed blake2 nor advanced features like ++ # salt, personal, tree hashing or SSE. ++ return __get_builtin_constructor(name)(data, **kwargs) + try: + return _hashlib.new(name, data) + except ValueError: +@@ -160,6 +173,8 @@ def __hash_new(name, data=b'', **kwargs): + # hash, try using our builtin implementations. + # This allows for SHA224/256 and SHA384/512 support even though + # the OpenSSL library prior to 0.9.8 doesn't provide them. ++ if get_fips_mode(): ++ raise + return __get_builtin_constructor(name)(data) + + +@@ -170,72 +185,13 @@ try: + algorithms_available = algorithms_available.union( + _hashlib.openssl_md_meth_names) + except ImportError: ++ if get_fips_mode(): ++ raise + new = __py_new + __get_hash = __get_builtin_constructor + +-try: +- # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA +- from _hashlib import pbkdf2_hmac +-except ImportError: +- _trans_5C = bytes((x ^ 0x5C) for x in range(256)) +- _trans_36 = bytes((x ^ 0x36) for x in range(256)) +- +- def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None): +- """Password based key derivation function 2 (PKCS #5 v2.0) +- +- This Python implementations based on the hmac module about as fast +- as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster +- for long passwords. +- """ +- if not isinstance(hash_name, str): +- raise TypeError(hash_name) +- +- if not isinstance(password, (bytes, bytearray)): +- password = bytes(memoryview(password)) +- if not isinstance(salt, (bytes, bytearray)): +- salt = bytes(memoryview(salt)) +- +- # Fast inline HMAC implementation +- inner = new(hash_name) +- outer = new(hash_name) +- blocksize = getattr(inner, 'block_size', 64) +- if len(password) > blocksize: +- password = new(hash_name, password).digest() +- password = password + b'\x00' * (blocksize - len(password)) +- inner.update(password.translate(_trans_36)) +- outer.update(password.translate(_trans_5C)) +- +- def prf(msg, inner=inner, outer=outer): +- # PBKDF2_HMAC uses the password as key. We can re-use the same +- # digest objects and just update copies to skip initialization. +- icpy = inner.copy() +- ocpy = outer.copy() +- icpy.update(msg) +- ocpy.update(icpy.digest()) +- return ocpy.digest() +- +- if iterations < 1: +- raise ValueError(iterations) +- if dklen is None: +- dklen = outer.digest_size +- if dklen < 1: +- raise ValueError(dklen) +- +- dkey = b'' +- loop = 1 +- from_bytes = int.from_bytes +- while len(dkey) < dklen: +- prev = prf(salt + loop.to_bytes(4, 'big')) +- # endianness doesn't matter here as long to / from use the same +- rkey = int.from_bytes(prev, 'big') +- for i in range(iterations - 1): +- prev = prf(prev) +- # rkey = rkey ^ prev +- rkey ^= from_bytes(prev, 'big') +- loop += 1 +- dkey += rkey.to_bytes(inner.digest_size, 'big') +- +- return dkey[:dklen] ++# OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA ++from _hashlib import pbkdf2_hmac + + try: + # OpenSSL's scrypt requires OpenSSL 1.1+ +@@ -243,11 +199,6 @@ try: + except ImportError: + pass + +-try: +- from _hashlib import get_fips_mode +-except ImportError: +- pass +- + + for __func_name in __always_supported: + # try them all, some may not work due to the OpenSSL +@@ -261,4 +212,6 @@ for __func_name in __always_supported: + + # Cleanup locals() + del __always_supported, __func_name, __get_hash +-del __py_new, __hash_new, __get_openssl_constructor ++del __hash_new, __get_openssl_constructor ++if not get_fips_mode(): ++ del __py_new +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 8b53d23..e9abcbb 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -945,6 +945,7 @@ class KDFTests(unittest.TestCase): + iterations=1, dklen=None) + self.assertEqual(out, self.pbkdf2_results['sha1'][0][0]) + ++ @unittest.skip("The python implementation of pbkdf2_hmac has been removed") + def test_pbkdf2_hmac_py(self): + self._test_pbkdf2_hmac(py_hashlib.pbkdf2_hmac) + +-- +2.25.4 + + +From 25b2075a04c0622cd11b8ea986d7d817a1a5d375 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 25 Jul 2019 17:19:06 +0200 +Subject: [PATCH 03/36] Disable Python's hash implementations in FIPS mode, + forcing OpenSSL + +--- + Include/_hashopenssl.h | 66 ++++++++++++++++++++++++++++++++++ + Modules/_blake2/blake2b_impl.c | 5 +++ + Modules/_blake2/blake2module.c | 3 ++ + Modules/_blake2/blake2s_impl.c | 5 +++ + Modules/_hashopenssl.c | 37 +------------------ + Modules/_sha3/sha3module.c | 5 +++ + setup.py | 48 +++++++++++++------------ + 7 files changed, 110 insertions(+), 59 deletions(-) + create mode 100644 Include/_hashopenssl.h + +diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h +new file mode 100644 +index 0000000..a726c0d +--- /dev/null ++++ b/Include/_hashopenssl.h +@@ -0,0 +1,66 @@ ++#ifndef Py_HASHOPENSSL_H ++#define Py_HASHOPENSSL_H ++ ++#include "Python.h" ++#include ++#include ++ ++/* LCOV_EXCL_START */ ++static PyObject * ++_setException(PyObject *exc) ++{ ++ unsigned long errcode; ++ const char *lib, *func, *reason; ++ ++ errcode = ERR_peek_last_error(); ++ if (!errcode) { ++ PyErr_SetString(exc, "unknown reasons"); ++ return NULL; ++ } ++ ERR_clear_error(); ++ ++ lib = ERR_lib_error_string(errcode); ++ func = ERR_func_error_string(errcode); ++ reason = ERR_reason_error_string(errcode); ++ ++ if (lib && func) { ++ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); ++ } ++ else if (lib) { ++ PyErr_Format(exc, "[%s] %s", lib, reason); ++ } ++ else { ++ PyErr_SetString(exc, reason); ++ } ++ return NULL; ++} ++/* LCOV_EXCL_STOP */ ++ ++ ++__attribute__((__unused__)) ++static int ++_Py_hashlib_fips_error(char *name) { ++ int result = FIPS_mode(); ++ if (result == 0) { ++ // "If the library was built without support of the FIPS Object Module, ++ // then the function will return 0 with an error code of ++ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." ++ // But 0 is also a valid result value. ++ ++ unsigned long errcode = ERR_peek_last_error(); ++ if (errcode) { ++ _setException(PyExc_ValueError); ++ return 1; ++ } ++ return 0; ++ } ++ PyErr_Format(PyExc_ValueError, "%s is not available in FIPS mode", ++ name); ++ return 1; ++} ++ ++#define FAIL_RETURN_IN_FIPS_MODE(name) do { \ ++ if (_Py_hashlib_fips_error(name)) return NULL; \ ++} while (0) ++ ++#endif // !Py_HASHOPENSSL_H +diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c +index edab31e..1daf5c3 100644 +--- a/Modules/_blake2/blake2b_impl.c ++++ b/Modules/_blake2/blake2b_impl.c +@@ -14,6 +14,7 @@ + */ + + #include "Python.h" ++#include "_hashopenssl.h" + #include "pystrhex.h" + #include "pythread.h" + +@@ -96,6 +97,8 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + BLAKE2bObject *self = NULL; + Py_buffer buf; + ++ FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ + self = new_BLAKE2bObject(type); + if (self == NULL) { + goto error; +@@ -274,6 +277,8 @@ _blake2_blake2b_update(BLAKE2bObject *self, PyObject *data) + { + Py_buffer buf; + ++ FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ + GET_BUFFER_VIEW_OR_ERROUT(data, &buf); + + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) +diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c +index e2a3d42..817b716 100644 +--- a/Modules/_blake2/blake2module.c ++++ b/Modules/_blake2/blake2module.c +@@ -9,6 +9,7 @@ + */ + + #include "Python.h" ++#include "_hashopenssl.h" + + #include "impl/blake2.h" + +@@ -57,6 +58,8 @@ PyInit__blake2(void) + PyObject *m; + PyObject *d; + ++ FAIL_RETURN_IN_FIPS_MODE("blake2"); ++ + m = PyModule_Create(&blake2_module); + if (m == NULL) + return NULL; +diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c +index ef2f7e1..389711a 100644 +--- a/Modules/_blake2/blake2s_impl.c ++++ b/Modules/_blake2/blake2s_impl.c +@@ -14,6 +14,7 @@ + */ + + #include "Python.h" ++#include "_hashopenssl.h" + #include "pystrhex.h" + #include "pythread.h" + +@@ -96,6 +97,8 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + BLAKE2sObject *self = NULL; + Py_buffer buf; + ++ FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ + self = new_BLAKE2sObject(type); + if (self == NULL) { + goto error; +@@ -274,6 +277,8 @@ _blake2_blake2s_update(BLAKE2sObject *self, PyObject *data) + { + Py_buffer buf; + ++ FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ + GET_BUFFER_VIEW_OR_ERROUT(data, &buf); + + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index d38aae9..10a987d 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -17,6 +17,7 @@ + #include "structmember.h" + #include "hashlib.h" + #include "pystrhex.h" ++#include "_hashopenssl.h" + + + /* EVP is the preferred interface to hashing in OpenSSL */ +@@ -24,10 +25,6 @@ + #include + /* We use the object interface to discover what hashes OpenSSL supports. */ + #include +-#include "openssl/err.h" +- +-/* Expose FIPS_mode */ +-#include + + #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL < 1.1.0 */ +@@ -65,38 +62,6 @@ class _hashlib.HASH "EVPobject *" "&EVPtype" + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a881a5092eecad28]*/ + +- +-/* LCOV_EXCL_START */ +-static PyObject * +-_setException(PyObject *exc) +-{ +- unsigned long errcode; +- const char *lib, *func, *reason; +- +- errcode = ERR_peek_last_error(); +- if (!errcode) { +- PyErr_SetString(exc, "unknown reasons"); +- return NULL; +- } +- ERR_clear_error(); +- +- lib = ERR_lib_error_string(errcode); +- func = ERR_func_error_string(errcode); +- reason = ERR_reason_error_string(errcode); +- +- if (lib && func) { +- PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); +- } +- else if (lib) { +- PyErr_Format(exc, "[%s] %s", lib, reason); +- } +- else { +- PyErr_SetString(exc, reason); +- } +- return NULL; +-} +-/* LCOV_EXCL_STOP */ +- + static PyObject* + py_digest_name(const EVP_MD *md) + { +diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c +index c1fb618..34d09b4 100644 +--- a/Modules/_sha3/sha3module.c ++++ b/Modules/_sha3/sha3module.c +@@ -18,6 +18,7 @@ + #include "Python.h" + #include "pystrhex.h" + #include "../hashlib.h" ++#include "_hashopenssl.h" + + /* ************************************************************************** + * SHA-3 (Keccak) and SHAKE +@@ -160,6 +161,7 @@ static PyTypeObject SHAKE256type; + static SHA3object * + newSHA3object(PyTypeObject *type) + { ++ FAIL_RETURN_IN_FIPS_MODE("_sha3"); + SHA3object *newobj; + newobj = (SHA3object *)PyObject_New(SHA3object, type); + if (newobj == NULL) { +@@ -173,6 +175,7 @@ newSHA3object(PyTypeObject *type) + static PyObject * + py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + { ++ FAIL_RETURN_IN_FIPS_MODE("_sha3"); + SHA3object *self = NULL; + Py_buffer buf = {NULL, NULL}; + HashReturn res; +@@ -704,6 +707,8 @@ PyInit__sha3(void) + { + PyObject *m = NULL; + ++ FAIL_RETURN_IN_FIPS_MODE("_sha3"); ++ + if ((m = PyModule_Create(&_SHA3module)) == NULL) { + return NULL; + } +diff --git a/setup.py b/setup.py +index 024a103..a16961e 100644 +--- a/setup.py ++++ b/setup.py +@@ -1688,7 +1688,6 @@ class PyBuildExt(build_ext): + def detect_modules(self): + self.configure_compiler() + self.init_inc_lib_dirs() +- + self.detect_simple_extensions() + if TEST_EXTENSIONS: + self.detect_test_extensions() +@@ -2187,7 +2186,7 @@ class PyBuildExt(build_ext): + sources=sources, + depends=depends)) + +- def detect_openssl_hashlib(self): ++ def detect_openssl_args(self): + # Detect SSL support for the socket module (via _ssl) + config_vars = sysconfig.get_config_vars() + +@@ -2208,7 +2207,7 @@ class PyBuildExt(build_ext): + if not openssl_libs: + # libssl and libcrypto not found + self.missing.extend(['_ssl', '_hashlib']) +- return None, None ++ raise ValueError('Cannot build for RHEL without OpenSSL') + + # Find OpenSSL includes + ssl_incs = find_file( +@@ -2216,7 +2215,7 @@ class PyBuildExt(build_ext): + ) + if ssl_incs is None: + self.missing.extend(['_ssl', '_hashlib']) +- return None, None ++ raise ValueError('Cannot build for RHEL without OpenSSL') + + # OpenSSL 1.0.2 uses Kerberos for KRB5 ciphers + krb5_h = find_file( +@@ -2226,12 +2225,23 @@ class PyBuildExt(build_ext): + if krb5_h: + ssl_incs.extend(krb5_h) + ++ ++ ssl_args = { ++ 'include_dirs': openssl_includes, ++ 'library_dirs': openssl_libdirs, ++ 'libraries': ['ssl', 'crypto'], ++ } ++ ++ return ssl_args ++ ++ def detect_openssl_hashlib(self): ++ ++ config_vars = sysconfig.get_config_vars() ++ + if config_vars.get("HAVE_X509_VERIFY_PARAM_SET1_HOST"): + self.add(Extension( + '_ssl', ['_ssl.c'], +- include_dirs=openssl_includes, +- library_dirs=openssl_libdirs, +- libraries=openssl_libs, ++ **self.detect_openssl_args(), + depends=['socketmodule.h', '_ssl/debughelpers.c']) + ) + else: +@@ -2239,22 +2249,12 @@ class PyBuildExt(build_ext): + + self.add(Extension('_hashlib', ['_hashopenssl.c'], + depends=['hashlib.h'], +- include_dirs=openssl_includes, +- library_dirs=openssl_libdirs, +- libraries=openssl_libs)) ++ **self.detect_openssl_args()) ) + + def detect_hash_builtins(self): +- # We always compile these even when OpenSSL is available (issue #14693). +- # It's harmless and the object code is tiny (40-50 KiB per module, +- # only loaded when actually used). +- self.add(Extension('_sha256', ['sha256module.c'], +- depends=['hashlib.h'])) +- self.add(Extension('_sha512', ['sha512module.c'], +- depends=['hashlib.h'])) +- self.add(Extension('_md5', ['md5module.c'], +- depends=['hashlib.h'])) +- self.add(Extension('_sha1', ['sha1module.c'], +- depends=['hashlib.h'])) ++ # RHEL: Always force OpenSSL for md5, sha1, sha256, sha512; ++ # don't build Python's implementations. ++ # sha3 and blake2 have extra functionality, so do build those: + + blake2_deps = glob(os.path.join(self.srcdir, + 'Modules/_blake2/impl/*')) +@@ -2264,14 +2264,16 @@ class PyBuildExt(build_ext): + ['_blake2/blake2module.c', + '_blake2/blake2b_impl.c', + '_blake2/blake2s_impl.c'], +- depends=blake2_deps)) ++ **self.detect_openssl_args(), ++ depends=blake2_deps)) + + sha3_deps = glob(os.path.join(self.srcdir, + 'Modules/_sha3/kcp/*')) + sha3_deps.append('hashlib.h') + self.add(Extension('_sha3', + ['_sha3/sha3module.c'], +- depends=sha3_deps)) ++ **self.detect_openssl_args(), ++ depends=sha3_deps + ['hashlib.h'])) + + def detect_nis(self): + if MS_WINDOWS or CYGWIN or HOST_PLATFORM == 'qnx6': +-- +2.25.4 + + +From 97d839b2d8c03a7b428907e51a44269fdfe3a48d Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 12 Dec 2019 16:58:31 +0100 +Subject: [PATCH 04/36] Expose all hashes available to OpenSSL + +--- + Modules/_hashopenssl.c | 150 ++++++++++++++++ + Modules/clinic/_hashopenssl.c.h | 298 +++++++++++++++++++++++++++++++- + 2 files changed, 447 insertions(+), 1 deletion(-) + +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index 10a987d..e10dbd7 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -190,6 +190,12 @@ py_digest_by_name(const char *name) + else if (!strcmp(name, "blake2b512")) { + digest = EVP_blake2b512(); + } ++ else if (!strcmp(name, "blake2s")) { ++ digest = EVP_blake2s256(); ++ } ++ else if (!strcmp(name, "blake2b")) { ++ digest = EVP_blake2b512(); ++ } + #endif + } + +@@ -708,6 +714,142 @@ _hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj) + return EVP_fast_new(module, data_obj, EVP_sha512()); + } + ++/*[clinic input] ++_hashlib.openssl_blake2b ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a blake2b hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=0d65acd1d9bb5e3f input=d9e6f84fa97e630d]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_blake2b512()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_blake2s ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a blake2s hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=0f1330138041ec22 input=f1aec29465fc49c6]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_blake2s256()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_sha3_224 ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a sha3_224 hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=e3817bed6ecafc20 input=adc74bf14410af70]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_sha3_224()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_sha3_256 ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a sha3_256 hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=9c15fac1ce09cd62 input=2922c3e78ab8bd2d]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_sha3_256()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_sha3_384 ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a sha3_384 hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=0923a782b9b81a40 input=742b499c372c8316]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_sha3_384()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_sha3_512 ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a sha3-512 hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=34bbe194704dbce4 input=46383f88e59a0385]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_sha3_512()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_shake_128 ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a shake_128 hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=a6ea5917ce65ef10 input=f256751eb810fdaa]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_shake128()); ++} ++ ++/*[clinic input] ++_hashlib.openssl_shake_256 ++ ++ string as data_obj: object(py_default="b''") = NULL ++ ++Returns a shake_256 hash object; optionally initialized with a string ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj) ++/*[clinic end generated code: output=c91aaa96b000e186 input=d1331313db34116c]*/ ++ ++{ ++ return EVP_fast_new(module, data_obj, EVP_shake256()); ++} ++ + + /*[clinic input] + _hashlib.pbkdf2_hmac as pbkdf2_hmac +@@ -1083,6 +1225,14 @@ static struct PyMethodDef EVP_functions[] = { + _HASHLIB_OPENSSL_SHA256_METHODDEF + _HASHLIB_OPENSSL_SHA384_METHODDEF + _HASHLIB_OPENSSL_SHA512_METHODDEF ++ _HASHLIB_OPENSSL_BLAKE2B_METHODDEF ++ _HASHLIB_OPENSSL_BLAKE2S_METHODDEF ++ _HASHLIB_OPENSSL_SHA3_224_METHODDEF ++ _HASHLIB_OPENSSL_SHA3_256_METHODDEF ++ _HASHLIB_OPENSSL_SHA3_384_METHODDEF ++ _HASHLIB_OPENSSL_SHA3_512_METHODDEF ++ _HASHLIB_OPENSSL_SHAKE_128_METHODDEF ++ _HASHLIB_OPENSSL_SHAKE_256_METHODDEF + {NULL, NULL} /* Sentinel */ + }; + +diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h +index 30fd8a9..e96a752 100644 +--- a/Modules/clinic/_hashopenssl.c.h ++++ b/Modules/clinic/_hashopenssl.c.h +@@ -331,6 +331,302 @@ exit: + return return_value; + } + ++PyDoc_STRVAR(_hashlib_openssl_blake2b__doc__, ++"openssl_blake2b($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a blake2b hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_BLAKE2B_METHODDEF \ ++ {"openssl_blake2b", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2b, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2b__doc__}, ++ ++static PyObject * ++_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_blake2b(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2b", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_blake2b_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_blake2s__doc__, ++"openssl_blake2s($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a blake2s hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_BLAKE2S_METHODDEF \ ++ {"openssl_blake2s", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2s, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2s__doc__}, ++ ++static PyObject * ++_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_blake2s(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2s", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_blake2s_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__, ++"openssl_sha3_224($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a sha3_224 hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_SHA3_224_METHODDEF \ ++ {"openssl_sha3_224", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_224, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_224__doc__}, ++ ++static PyObject * ++_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_224", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_sha3_224_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_sha3_256__doc__, ++"openssl_sha3_256($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a sha3_256 hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_SHA3_256_METHODDEF \ ++ {"openssl_sha3_256", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_256__doc__}, ++ ++static PyObject * ++_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_256", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_sha3_256_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_sha3_384__doc__, ++"openssl_sha3_384($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a sha3_384 hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_SHA3_384_METHODDEF \ ++ {"openssl_sha3_384", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_384, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_384__doc__}, ++ ++static PyObject * ++_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_384", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_sha3_384_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_sha3_512__doc__, ++"openssl_sha3_512($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a sha3-512 hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_SHA3_512_METHODDEF \ ++ {"openssl_sha3_512", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_512, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_512__doc__}, ++ ++static PyObject * ++_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_512", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_sha3_512_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_shake_128__doc__, ++"openssl_shake_128($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a shake_128 hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_SHAKE_128_METHODDEF \ ++ {"openssl_shake_128", (PyCFunction)(void(*)(void))_hashlib_openssl_shake_128, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_128__doc__}, ++ ++static PyObject * ++_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_shake_128", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_shake_128_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hashlib_openssl_shake_256__doc__, ++"openssl_shake_256($module, /, string=b\'\')\n" ++"--\n" ++"\n" ++"Returns a shake_256 hash object; optionally initialized with a string"); ++ ++#define _HASHLIB_OPENSSL_SHAKE_256_METHODDEF \ ++ {"openssl_shake_256", (PyCFunction)(void(*)(void))_hashlib_openssl_shake_256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_256__doc__}, ++ ++static PyObject * ++_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj); ++ ++static PyObject * ++_hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"string", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "openssl_shake_256", 0}; ++ PyObject *argsbuf[1]; ++ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; ++ PyObject *data_obj = NULL; ++ ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (!noptargs) { ++ goto skip_optional_pos; ++ } ++ data_obj = args[0]; ++skip_optional_pos: ++ return_value = _hashlib_openssl_shake_256_impl(module, data_obj); ++ ++exit: ++ return return_value; ++} ++ + PyDoc_STRVAR(pbkdf2_hmac__doc__, + "pbkdf2_hmac($module, /, hash_name, password, salt, iterations,\n" + " dklen=None)\n" +@@ -646,4 +942,4 @@ _hashlib_get_fips_mode(PyObject *module, PyObject *Py_UNUSED(ignored)) + #ifndef _HASHLIB_SCRYPT_METHODDEF + #define _HASHLIB_SCRYPT_METHODDEF + #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ +-/*[clinic end generated code: output=5467006d93e7479e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=be8e21a10dff71e7 input=a9049054013a1b77]*/ +-- +2.25.4 + + +From b681f084a48d5f2f3eb5257b33e968268850ea7b Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 25 Jul 2019 18:13:45 +0200 +Subject: [PATCH 05/36] Fix tests + +--- + Lib/test/test_hashlib.py | 58 +++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 13 deletions(-) + +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index e9abcbb..2a55fd4 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -190,7 +190,9 @@ class HashLibTestCase(unittest.TestCase): + a = array.array("b", range(10)) + for cons in self.hash_constructors: + c = cons(a) +- if c.name in self.shakes: ++ if (c.name in self.shakes ++ and not cons.__name__.startswith('openssl_') ++ ): + c.hexdigest(16) + else: + c.hexdigest() +@@ -240,7 +242,9 @@ class HashLibTestCase(unittest.TestCase): + def test_hexdigest(self): + for cons in self.hash_constructors: + h = cons() +- if h.name in self.shakes: ++ if (h.name in self.shakes ++ and not cons.__name__.startswith('openssl_') ++ ): + self.assertIsInstance(h.digest(16), bytes) + self.assertEqual(hexstr(h.digest(16)), h.hexdigest(16)) + else: +@@ -254,6 +258,8 @@ class HashLibTestCase(unittest.TestCase): + h = cons() + if h.name not in self.shakes: + continue ++ if cons.__name__.startswith('openssl_'): ++ continue + for digest in h.digest, h.hexdigest: + self.assertRaises(ValueError, digest, -10) + for length in large_sizes: +@@ -282,7 +288,9 @@ class HashLibTestCase(unittest.TestCase): + m1.update(bees) + m1.update(cees) + m1.update(dees) +- if m1.name in self.shakes: ++ if (m1.name in self.shakes ++ and not cons.__name__.startswith('openssl_') ++ ): + args = (16,) + else: + args = () +@@ -309,15 +317,36 @@ class HashLibTestCase(unittest.TestCase): + # 2 is for hashlib.name(...) and hashlib.new(name, ...) + self.assertGreaterEqual(len(constructors), 2) + for hash_object_constructor in constructors: ++ if ( ++ kwargs ++ and hash_object_constructor.__name__.startswith('openssl_') ++ ): ++ return + m = hash_object_constructor(data, **kwargs) +- computed = m.hexdigest() if not shake else m.hexdigest(length) ++ if shake: ++ if hash_object_constructor.__name__.startswith('openssl_'): ++ if length > m.digest_size: ++ # OpenSSL doesn't give long digests ++ return ++ computed = m.hexdigest()[:length*2] ++ hexdigest = hexdigest[:length*2] ++ else: ++ computed = m.hexdigest(length) ++ else: ++ computed = m.hexdigest() + self.assertEqual( + computed, hexdigest, + "Hash algorithm %s constructed using %s returned hexdigest" + " %r for %d byte input data that should have hashed to %r." + % (name, hash_object_constructor, + computed, len(data), hexdigest)) +- computed = m.digest() if not shake else m.digest(length) ++ if shake: ++ if hash_object_constructor.__name__.startswith('openssl_'): ++ computed = m.digest()[:length] ++ else: ++ computed = m.digest(length) ++ else: ++ computed = m.digest() + digest = bytes.fromhex(hexdigest) + self.assertEqual(computed, digest) + if not shake: +@@ -357,12 +386,14 @@ class HashLibTestCase(unittest.TestCase): + for hash_object_constructor in constructors: + m = hash_object_constructor() + self.assertEqual(m.block_size, block_size) +- self.assertEqual(m.digest_size, digest_size) ++ if not hash_object_constructor.__name__.startswith('openssl_'): ++ self.assertEqual(m.digest_size, digest_size) + if digest_length: +- self.assertEqual(len(m.digest(digest_length)), +- digest_length) +- self.assertEqual(len(m.hexdigest(digest_length)), +- 2*digest_length) ++ if not hash_object_constructor.__name__.startswith('openssl_'): ++ self.assertEqual(len(m.digest(digest_length)), ++ digest_length) ++ self.assertEqual(len(m.hexdigest(digest_length)), ++ 2*digest_length) + else: + self.assertEqual(len(m.digest()), digest_size) + self.assertEqual(len(m.hexdigest()), 2*digest_size) +@@ -395,9 +426,10 @@ class HashLibTestCase(unittest.TestCase): + # _hashopenssl's variant does not have extra SHA3 attributes + continue + self.assertEqual(capacity + rate, 1600) +- self.assertEqual(m._capacity_bits, capacity) +- self.assertEqual(m._rate_bits, rate) +- self.assertEqual(m._suffix, suffix) ++ if not hash_object_constructor.__name__.startswith('openssl_'): ++ self.assertEqual(m._capacity_bits, capacity) ++ self.assertEqual(m._rate_bits, rate) ++ self.assertEqual(m._suffix, suffix) + + @requires_sha3 + def test_extra_sha3(self): +-- +2.25.4 + + +From 78dea79c8a284940a5d5997646745cb29f74d720 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Fri, 26 Jul 2019 11:27:57 +0200 +Subject: [PATCH 06/36] Change FIPS exceptions from _blake2, _sha3 module init + to ImportError + +--- + Include/_hashopenssl.h | 11 +++++------ + Modules/_blake2/blake2b_impl.c | 4 ++-- + Modules/_blake2/blake2module.c | 2 +- + Modules/_blake2/blake2s_impl.c | 4 ++-- + Modules/_sha3/sha3module.c | 6 +++--- + 5 files changed, 13 insertions(+), 14 deletions(-) + +diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h +index a726c0d..47ed003 100644 +--- a/Include/_hashopenssl.h ++++ b/Include/_hashopenssl.h +@@ -39,7 +39,7 @@ _setException(PyObject *exc) + + __attribute__((__unused__)) + static int +-_Py_hashlib_fips_error(char *name) { ++_Py_hashlib_fips_error(PyObject *exc, char *name) { + int result = FIPS_mode(); + if (result == 0) { + // "If the library was built without support of the FIPS Object Module, +@@ -49,18 +49,17 @@ _Py_hashlib_fips_error(char *name) { + + unsigned long errcode = ERR_peek_last_error(); + if (errcode) { +- _setException(PyExc_ValueError); ++ _setException(exc); + return 1; + } + return 0; + } +- PyErr_Format(PyExc_ValueError, "%s is not available in FIPS mode", +- name); ++ PyErr_Format(exc, "%s is not available in FIPS mode", name); + return 1; + } + +-#define FAIL_RETURN_IN_FIPS_MODE(name) do { \ +- if (_Py_hashlib_fips_error(name)) return NULL; \ ++#define FAIL_RETURN_IN_FIPS_MODE(exc, name) do { \ ++ if (_Py_hashlib_fips_error(exc, name)) return NULL; \ + } while (0) + + #endif // !Py_HASHOPENSSL_H +diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c +index 1daf5c3..97ce89d 100644 +--- a/Modules/_blake2/blake2b_impl.c ++++ b/Modules/_blake2/blake2b_impl.c +@@ -97,7 +97,7 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + BLAKE2bObject *self = NULL; + Py_buffer buf; + +- FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2"); + + self = new_BLAKE2bObject(type); + if (self == NULL) { +@@ -277,7 +277,7 @@ _blake2_blake2b_update(BLAKE2bObject *self, PyObject *data) + { + Py_buffer buf; + +- FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2"); + + GET_BUFFER_VIEW_OR_ERROUT(data, &buf); + +diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c +index 817b716..a9c7cbc 100644 +--- a/Modules/_blake2/blake2module.c ++++ b/Modules/_blake2/blake2module.c +@@ -58,7 +58,7 @@ PyInit__blake2(void) + PyObject *m; + PyObject *d; + +- FAIL_RETURN_IN_FIPS_MODE("blake2"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ImportError, "blake2"); + + m = PyModule_Create(&blake2_module); + if (m == NULL) +diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c +index 389711a..c4447b4 100644 +--- a/Modules/_blake2/blake2s_impl.c ++++ b/Modules/_blake2/blake2s_impl.c +@@ -97,7 +97,7 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + BLAKE2sObject *self = NULL; + Py_buffer buf; + +- FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2"); + + self = new_BLAKE2sObject(type); + if (self == NULL) { +@@ -277,7 +277,7 @@ _blake2_blake2s_update(BLAKE2sObject *self, PyObject *data) + { + Py_buffer buf; + +- FAIL_RETURN_IN_FIPS_MODE("_blake2"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2"); + + GET_BUFFER_VIEW_OR_ERROUT(data, &buf); + +diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c +index 34d09b4..3079e1e 100644 +--- a/Modules/_sha3/sha3module.c ++++ b/Modules/_sha3/sha3module.c +@@ -161,7 +161,7 @@ static PyTypeObject SHAKE256type; + static SHA3object * + newSHA3object(PyTypeObject *type) + { +- FAIL_RETURN_IN_FIPS_MODE("_sha3"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_sha3"); + SHA3object *newobj; + newobj = (SHA3object *)PyObject_New(SHA3object, type); + if (newobj == NULL) { +@@ -175,7 +175,7 @@ newSHA3object(PyTypeObject *type) + static PyObject * + py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + { +- FAIL_RETURN_IN_FIPS_MODE("_sha3"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_sha3"); + SHA3object *self = NULL; + Py_buffer buf = {NULL, NULL}; + HashReturn res; +@@ -707,7 +707,7 @@ PyInit__sha3(void) + { + PyObject *m = NULL; + +- FAIL_RETURN_IN_FIPS_MODE("_sha3"); ++ FAIL_RETURN_IN_FIPS_MODE(PyExc_ImportError, "_sha3"); + + if ((m = PyModule_Create(&_SHA3module)) == NULL) { + return NULL; +-- +2.25.4 + + +From be76f342f801a674fdbb622fd6e096bd7a09e1e6 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Fri, 26 Jul 2019 11:24:09 +0200 +Subject: [PATCH 07/36] Make hashlib importable under FIPS mode + +--- + Lib/hashlib.py | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index 1bcfdf9..898e6dc 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -137,12 +137,14 @@ def __get_openssl_constructor(name): + f = getattr(_hashlib, 'openssl_' + name) + # Allow the C module to raise ValueError. The function will be + # defined but the hash not actually available thanks to OpenSSL. +- f() ++ if not get_fips_mode(): ++ # N.B. In "FIPS mode", there is no fallback. ++ # If this test fails, we want to export the broken hash ++ # constructor anyway. ++ f() + # Use the C function directly (very fast) + return f + except (AttributeError, ValueError): +- if get_fips_mode(): +- raise + return __get_builtin_constructor(name) + + +-- +2.25.4 + + +From 15b34c0943d79ec7d236a5eefab636a288dc0ae1 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Fri, 26 Jul 2019 15:41:10 +0200 +Subject: [PATCH 08/36] Implement hmac.new using new built-in module, + _hmacopenssl + +--- + Lib/hmac.py | 32 ++- + Modules/_hmacopenssl.c | 396 ++++++++++++++++++++++++++++++++ + Modules/clinic/_hmacopenssl.c.h | 133 +++++++++++ + setup.py | 4 + + 4 files changed, 564 insertions(+), 1 deletion(-) + create mode 100644 Modules/_hmacopenssl.c + create mode 100644 Modules/clinic/_hmacopenssl.c.h + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index b769876..daabc8c 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -13,6 +13,8 @@ except ImportError: + else: + _openssl_md_meths = frozenset(_hashopenssl.openssl_md_meth_names) + import hashlib as _hashlib ++import _hashlib as _hashlibopenssl ++import _hmacopenssl + + trans_5C = bytes((x ^ 0x5C) for x in range(256)) + trans_36 = bytes((x ^ 0x36) for x in range(256)) +@@ -43,6 +45,11 @@ class HMAC: + msg argument. Passing it as a keyword argument is + recommended, though not required for legacy API reasons. + """ ++ if _hashlib.get_fips_mode(): ++ raise ValueError( ++ 'hmac.HMAC is not available in FIPS mode. ' ++ + 'Use hmac.new().' ++ ) + + if not isinstance(key, (bytes, bytearray)): + raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) +@@ -93,6 +100,8 @@ class HMAC: + + def update(self, msg): + """Feed data from msg into this hashing object.""" ++ if _hashlib.get_fips_mode(): ++ raise ValueError('hmac.HMAC is not available in FIPS mode') + self.inner.update(msg) + + def copy(self): +@@ -133,6 +142,18 @@ class HMAC: + h = self._current() + return h.hexdigest() + ++def _get_openssl_name(digestmod): ++ if isinstance(digestmod, str): ++ return digestmod.lower() ++ elif callable(digestmod): ++ digestmod = digestmod(b'') ++ ++ if not isinstance(digestmod, _hashlibopenssl.HASH): ++ raise TypeError( ++ 'Only OpenSSL hashlib hashes are accepted in FIPS mode.') ++ ++ return digestmod.name.lower().replace('_', '-') ++ + def new(key, msg=None, digestmod=''): + """Create a new hashing object and return it. + +@@ -150,7 +171,16 @@ def new(key, msg=None, digestmod=''): + method, and can ask for the hash value at any time by calling its digest() + or hexdigest() methods. + """ +- return HMAC(key, msg, digestmod) ++ if _hashlib.get_fips_mode(): ++ if digestmod is None: ++ digestmod = 'md5' ++ name = _get_openssl_name(digestmod) ++ result = _hmacopenssl.new(key, digestmod=name) ++ if msg: ++ result.update(msg) ++ return result ++ else: ++ return HMAC(key, msg, digestmod) + + + def digest(key, msg, digest): +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +new file mode 100644 +index 0000000..ca95d72 +--- /dev/null ++++ b/Modules/_hmacopenssl.c +@@ -0,0 +1,396 @@ ++/* Module that wraps all OpenSSL MHAC algorithm */ ++ ++/* Copyright (C) 2019 Red Hat, Inc. Red Hat, Inc. and/or its affiliates ++ * ++ * Based on _hashopenssl.c, which is: ++ * Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org) ++ * Licensed to PSF under a Contributor Agreement. ++ * ++ * Derived from a skeleton of shamodule.c containing work performed by: ++ * ++ * Andrew Kuchling (amk@amk.ca) ++ * Greg Stein (gstein@lyra.org) ++ * ++ */ ++ ++#define PY_SSIZE_T_CLEAN ++ ++#include "Python.h" ++#include "structmember.h" ++#include "hashlib.h" ++#include "pystrhex.h" ++#include "_hashopenssl.h" ++ ++ ++#include ++ ++static PyTypeObject HmacType; ++ ++typedef struct { ++ PyObject_HEAD ++ PyObject *name; /* name of the hash algorithm */ ++ HMAC_CTX *ctx; /* OpenSSL hmac context */ ++ PyThread_type_lock lock; /* HMAC context lock */ ++} HmacObject; ++ ++#include "clinic/_hmacopenssl.c.h" ++/*[clinic input] ++module _hmacopenssl ++class _hmacopenssl.HMAC "HmacObject *" "&HmacType" ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c98d3f2af591c085]*/ ++ ++ ++/*[clinic input] ++_hmacopenssl.new ++ ++ key: Py_buffer ++ * ++ digestmod: str ++ ++Return a new hmac object. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, ++ const char *digestmod) ++/*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ ++{ ++ if (digestmod == NULL) { ++ PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); ++ return NULL; ++ } ++ ++ /* name mut be lowercase */ ++ for (int i=0; digestmod[i]; i++) { ++ if ( ++ ((digestmod[i] < 'a') || (digestmod[i] > 'z')) ++ && ((digestmod[i] < '0') || (digestmod[i] > '9')) ++ && digestmod[i] != '-' ++ ) { ++ PyErr_SetString(PyExc_ValueError, "digestmod must be lowercase"); ++ return NULL; ++ } ++ } ++ ++ const EVP_MD *digest = EVP_get_digestbyname(digestmod); ++ if (!digest) { ++ PyErr_SetString(PyExc_ValueError, "unknown hash function"); ++ return NULL; ++ } ++ ++ PyObject *name = NULL; ++ HMAC_CTX *ctx = NULL; ++ HmacObject *retval = NULL; ++ ++ name = PyUnicode_FromFormat("hmac-%s", digestmod); ++ if (name == NULL) { ++ goto error; ++ } ++ ++ ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ _setException(PyExc_ValueError); ++ goto error; ++ } ++ ++ int r = HMAC_Init_ex( ++ ctx, ++ (const char*)key->buf, ++ key->len, ++ digest, ++ NULL /*impl*/); ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ goto error; ++ } ++ ++ retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ if (retval == NULL) { ++ goto error; ++ } ++ ++ retval->name = name; ++ retval->ctx = ctx; ++ retval->lock = NULL; ++ ++ return (PyObject*)retval; ++ ++error: ++ if (ctx) HMAC_CTX_free(ctx); ++ if (name) Py_DECREF(name); ++ if (retval) PyObject_Del(name); ++ return NULL; ++} ++ ++/*[clinic input] ++_hmacopenssl.HMAC.copy ++ ++Return a copy (“clone”) of the HMAC object. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hmacopenssl_HMAC_copy_impl(HmacObject *self) ++/*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ ++{ ++ HmacObject *retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ if (retval == NULL) { ++ return NULL; ++ } ++ ++ Py_INCREF(self->name); ++ retval->name = self->name; ++ ++ int r = HMAC_CTX_copy(retval->ctx, self->ctx); ++ if (r == 0) { ++ PyObject_Del(retval); ++ return _setException(PyExc_ValueError); ++ } ++ ++ return (PyObject*)retval; ++} ++ ++static void ++_hmac_dealloc(HmacObject *self) ++{ ++ if (self->lock != NULL) { ++ PyThread_free_lock(self->lock); ++ } ++ HMAC_CTX_free(self->ctx); ++ Py_XDECREF(self->name); ++ PyObject_Del(self); ++} ++ ++static PyObject * ++_hmac_repr(HmacObject *self) ++{ ++ return PyUnicode_FromFormat("<%U HMAC object @ %p>", self->name, self); ++} ++ ++/*[clinic input] ++_hmacopenssl.HMAC.update ++ ++ msg: Py_buffer ++ ++Update the HMAC object with msg. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg) ++/*[clinic end generated code: output=0efeee663a98cee5 input=0683d64f35808cb9]*/ ++{ ++ if (self->lock == NULL && msg->len >= HASHLIB_GIL_MINSIZE) { ++ self->lock = PyThread_allocate_lock(); ++ /* fail? lock = NULL and we fail over to non-threaded code. */ ++ } ++ ++ int r; ++ ++ if (self->lock != NULL) { ++ Py_BEGIN_ALLOW_THREADS ++ PyThread_acquire_lock(self->lock, 1); ++ r = HMAC_Update(self->ctx, (const unsigned char*)msg->buf, msg->len); ++ PyThread_release_lock(self->lock); ++ Py_END_ALLOW_THREADS ++ } else { ++ r = HMAC_Update(self->ctx, (const unsigned char*)msg->buf, msg->len); ++ } ++ ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static unsigned int ++_digest_size(HmacObject *self) ++{ ++ const EVP_MD *md = HMAC_CTX_get_md(self->ctx); ++ if (md == NULL) { ++ _setException(PyExc_ValueError); ++ return 0; ++ } ++ return EVP_MD_size(md); ++} ++ ++static int ++_digest(HmacObject *self, unsigned char *buf, unsigned int len) ++{ ++ HMAC_CTX *temp_ctx = HMAC_CTX_new(); ++ if (temp_ctx == NULL) { ++ PyErr_NoMemory(); ++ return 0; ++ } ++ int r = HMAC_CTX_copy(temp_ctx, self->ctx); ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ return 0; ++ } ++ r = HMAC_Final(temp_ctx, buf, &len); ++ HMAC_CTX_free(temp_ctx); ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ return 0; ++ } ++ return 1; ++} ++ ++/*[clinic input] ++_hmacopenssl.HMAC.digest ++ ++Return the digest of the bytes passed to the update() method so far. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hmacopenssl_HMAC_digest_impl(HmacObject *self) ++/*[clinic end generated code: output=3aa6dbfc46ec4957 input=bf769a10b1d9edd9]*/ ++{ ++ unsigned int digest_size = _digest_size(self); ++ if (digest_size == 0) { ++ return _setException(PyExc_ValueError); ++ } ++ unsigned char buf[digest_size]; /* FIXME: C99 feature */ ++ int r = _digest(self, buf, digest_size); ++ if (r == 0) { ++ return NULL; ++ } ++ return PyBytes_FromStringAndSize((const char *)buf, digest_size); ++} ++ ++/*[clinic input] ++_hmacopenssl.HMAC.hexdigest ++ ++Return hexadecimal digest of the bytes passed to the update() method so far. ++ ++This may be used to exchange the value safely in email or other non-binary ++environments. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hmacopenssl_HMAC_hexdigest_impl(HmacObject *self) ++/*[clinic end generated code: output=630f6fa89f9f1e48 input=b8e60ec8b811c4cd]*/ ++{ ++ unsigned int digest_size = _digest_size(self); ++ if (digest_size == 0) { ++ return _setException(PyExc_ValueError); ++ } ++ unsigned char buf[digest_size]; /* FIXME: C99 feature */ ++ int r = _digest(self, buf, digest_size); ++ if (r == 0) { ++ return NULL; ++ } ++ return _Py_strhex((const char *)buf, digest_size); ++} ++ ++ ++ ++static PyObject * ++_hmacopenssl_get_digest_size(HmacObject *self, void *closure) ++{ ++ unsigned int digest_size = _digest_size(self); ++ if (digest_size == 0) { ++ return _setException(PyExc_ValueError); ++ } ++ return PyLong_FromLong(digest_size); ++} ++ ++static PyObject * ++_hmacopenssl_get_block_size(HmacObject *self, void *closure) ++{ ++ const EVP_MD *md = HMAC_CTX_get_md(self->ctx); ++ if (md == NULL) { ++ return _setException(PyExc_ValueError); ++ } ++ return PyLong_FromLong(EVP_MD_size(md)); ++} ++ ++static PyMethodDef Hmac_methods[] = { ++ _HMACOPENSSL_HMAC_UPDATE_METHODDEF ++ _HMACOPENSSL_HMAC_DIGEST_METHODDEF ++ _HMACOPENSSL_HMAC_HEXDIGEST_METHODDEF ++ _HMACOPENSSL_HMAC_COPY_METHODDEF ++ {NULL, NULL} /* sentinel */ ++}; ++ ++static PyGetSetDef Hmac_getset[] = { ++ {"digest_size", (getter)_hmacopenssl_get_digest_size, NULL, NULL, NULL}, ++ {"block_size", (getter)_hmacopenssl_get_block_size, NULL, NULL, NULL}, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyMemberDef Hmac_members[] = { ++ {"name", T_OBJECT, offsetof(HmacObject, name), READONLY, PyDoc_STR("HMAC name")}, ++}; ++ ++PyDoc_STRVAR(hmactype_doc, ++"The object used to calculate HMAC of a message.\n\ ++\n\ ++Methods:\n\ ++\n\ ++update() -- updates the current digest with an additional string\n\ ++digest() -- return the current digest value\n\ ++hexdigest() -- return the current digest as a string of hexadecimal digits\n\ ++copy() -- return a copy of the current hash object\n\ ++\n\ ++Attributes:\n\ ++\n\ ++name -- the name, including the hash algorithm used by this object\n\ ++digest_size -- number of bytes in digest() output\n"); ++ ++static PyTypeObject HmacType = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "_hmacopenssl.HMAC", /*tp_name*/ ++ sizeof(HmacObject), /*tp_basicsize*/ ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .tp_doc = hmactype_doc, ++ .tp_repr = (reprfunc)_hmac_repr, ++ .tp_dealloc = (destructor)_hmac_dealloc, ++ .tp_methods = Hmac_methods, ++ .tp_getset = Hmac_getset, ++ .tp_members = Hmac_members, ++}; ++ ++static struct PyMethodDef hmacopenssl_functions[] = { ++ _HMACOPENSSL_NEW_METHODDEF ++ {NULL, NULL} /* Sentinel */ ++}; ++ ++ ++ ++/* Initialize this module. */ ++ ++ ++static struct PyModuleDef _hmacopenssl_module = { ++ PyModuleDef_HEAD_INIT, ++ "_hmacopenssl", ++ NULL, ++ -1, ++ hmacopenssl_functions, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ ++PyMODINIT_FUNC ++PyInit__hmacopenssl(void) ++{ ++ /* TODO build EVP_functions openssl_* entries dynamically based ++ * on what hashes are supported rather than listing many ++ * but having some be unsupported. Only init appropriate ++ * constants. */ ++ ++ Py_TYPE(&HmacType) = &PyType_Type; ++ if (PyType_Ready(&HmacType) < 0) ++ return NULL; ++ ++ PyObject *m = PyModule_Create(&_hmacopenssl_module); ++ if (m == NULL) ++ return NULL; ++ ++ Py_INCREF((PyObject *)&HmacType); ++ PyModule_AddObject(m, "HMAC", (PyObject *)&HmacType); ++ ++ return m; ++} +diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h +new file mode 100644 +index 0000000..b472a6e +--- /dev/null ++++ b/Modules/clinic/_hmacopenssl.c.h +@@ -0,0 +1,133 @@ ++/*[clinic input] ++preserve ++[clinic start generated code]*/ ++ ++PyDoc_STRVAR(_hmacopenssl_new__doc__, ++"new($module, /, key, *, digestmod)\n" ++"--\n" ++"\n" ++"Return a new hmac object."); ++ ++#define _HMACOPENSSL_NEW_METHODDEF \ ++ {"new", (PyCFunction)_hmacopenssl_new, METH_FASTCALL, _hmacopenssl_new__doc__}, ++ ++static PyObject * ++_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, ++ const char *digestmod); ++ ++static PyObject * ++_hmacopenssl_new(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"key", "digestmod", NULL}; ++ static _PyArg_Parser _parser = {"y*$s:new", _keywords, 0}; ++ Py_buffer key = {NULL, NULL}; ++ const char *digestmod; ++ ++ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, ++ &key, &digestmod)) { ++ goto exit; ++ } ++ return_value = _hmacopenssl_new_impl(module, &key, digestmod); ++ ++exit: ++ /* Cleanup for key */ ++ if (key.obj) { ++ PyBuffer_Release(&key); ++ } ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, ++"copy($self, /)\n" ++"--\n" ++"\n" ++"Return a copy (“clone”) of the HMAC object."); ++ ++#define _HMACOPENSSL_HMAC_COPY_METHODDEF \ ++ {"copy", (PyCFunction)_hmacopenssl_HMAC_copy, METH_NOARGS, _hmacopenssl_HMAC_copy__doc__}, ++ ++static PyObject * ++_hmacopenssl_HMAC_copy_impl(HmacObject *self); ++ ++static PyObject * ++_hmacopenssl_HMAC_copy(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hmacopenssl_HMAC_copy_impl(self); ++} ++ ++PyDoc_STRVAR(_hmacopenssl_HMAC_update__doc__, ++"update($self, /, msg)\n" ++"--\n" ++"\n" ++"Update the HMAC object with msg."); ++ ++#define _HMACOPENSSL_HMAC_UPDATE_METHODDEF \ ++ {"update", (PyCFunction)_hmacopenssl_HMAC_update, METH_FASTCALL, _hmacopenssl_HMAC_update__doc__}, ++ ++static PyObject * ++_hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg); ++ ++static PyObject * ++_hmacopenssl_HMAC_update(HmacObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"msg", NULL}; ++ static _PyArg_Parser _parser = {"y*:update", _keywords, 0}; ++ Py_buffer msg = {NULL, NULL}; ++ ++ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, ++ &msg)) { ++ goto exit; ++ } ++ return_value = _hmacopenssl_HMAC_update_impl(self, &msg); ++ ++exit: ++ /* Cleanup for msg */ ++ if (msg.obj) { ++ PyBuffer_Release(&msg); ++ } ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(_hmacopenssl_HMAC_digest__doc__, ++"digest($self, /)\n" ++"--\n" ++"\n" ++"Return the digest of the bytes passed to the update() method so far."); ++ ++#define _HMACOPENSSL_HMAC_DIGEST_METHODDEF \ ++ {"digest", (PyCFunction)_hmacopenssl_HMAC_digest, METH_NOARGS, _hmacopenssl_HMAC_digest__doc__}, ++ ++static PyObject * ++_hmacopenssl_HMAC_digest_impl(HmacObject *self); ++ ++static PyObject * ++_hmacopenssl_HMAC_digest(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hmacopenssl_HMAC_digest_impl(self); ++} ++ ++PyDoc_STRVAR(_hmacopenssl_HMAC_hexdigest__doc__, ++"hexdigest($self, /)\n" ++"--\n" ++"\n" ++"Return hexadecimal digest of the bytes passed to the update() method so far.\n" ++"\n" ++"This may be used to exchange the value safely in email or other non-binary\n" ++"environments."); ++ ++#define _HMACOPENSSL_HMAC_HEXDIGEST_METHODDEF \ ++ {"hexdigest", (PyCFunction)_hmacopenssl_HMAC_hexdigest, METH_NOARGS, _hmacopenssl_HMAC_hexdigest__doc__}, ++ ++static PyObject * ++_hmacopenssl_HMAC_hexdigest_impl(HmacObject *self); ++ ++static PyObject * ++_hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hmacopenssl_HMAC_hexdigest_impl(self); ++} ++/*[clinic end generated code: output=10b6e8cac6d7a2c9 input=a9049054013a1b77]*/ +diff --git a/setup.py b/setup.py +index a16961e..3d2465d 100644 +--- a/setup.py ++++ b/setup.py +@@ -2251,6 +2251,10 @@ class PyBuildExt(build_ext): + depends=['hashlib.h'], + **self.detect_openssl_args()) ) + ++ self.add(Extension('_hmacopenssl', ['_hmacopenssl.c'], ++ depends = ['hashlib.h'], ++ **self.detect_openssl_args()) ) ++ + def detect_hash_builtins(self): + # RHEL: Always force OpenSSL for md5, sha1, sha256, sha512; + # don't build Python's implementations. +-- +2.25.4 + + +From f72ffcdcee6c59aa61a8df4a3bf6633d200d6417 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Mon, 29 Jul 2019 12:45:11 +0200 +Subject: [PATCH 09/36] FIPS review + +* Port _hmacopenssl to multiphase init. +* Make _hmacopenssl.HMAC.copy create same type as self. +* hmac.py cosmetic nitpick +--- + Lib/hmac.py | 2 +- + Modules/_hmacopenssl.c | 112 +++++++++++++++++++++++++---------------- + 2 files changed, 70 insertions(+), 44 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index daabc8c..2ec24da 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -48,7 +48,7 @@ class HMAC: + if _hashlib.get_fips_mode(): + raise ValueError( + 'hmac.HMAC is not available in FIPS mode. ' +- + 'Use hmac.new().' ++ 'Use hmac.new().' + ) + + if not isinstance(key, (bytes, bytearray)): +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index ca95d72..216ed04 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -24,7 +24,10 @@ + + #include + +-static PyTypeObject HmacType; ++typedef struct hmacopenssl_state { ++ PyTypeObject *HmacType; ++} hmacopenssl_state; ++ + + typedef struct { + PyObject_HEAD +@@ -36,9 +39,9 @@ typedef struct { + #include "clinic/_hmacopenssl.c.h" + /*[clinic input] + module _hmacopenssl +-class _hmacopenssl.HMAC "HmacObject *" "&HmacType" ++class _hmacopenssl.HMAC "HmacObject *" "PyModule_GetState(module)->HmacType" + [clinic start generated code]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c98d3f2af591c085]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ + + + /*[clinic input] +@@ -56,11 +59,18 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + const char *digestmod) + /*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ + { ++ hmacopenssl_state *state; ++ + if (digestmod == NULL) { + PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); + return NULL; + } + ++ state = PyModule_GetState(module); ++ if (state == NULL) { ++ return NULL; ++ } ++ + /* name mut be lowercase */ + for (int i=0; digestmod[i]; i++) { + if ( +@@ -105,7 +115,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + goto error; + } + +- retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ retval = (HmacObject *)PyObject_New(HmacObject, state->HmacType); + if (retval == NULL) { + goto error; + } +@@ -133,7 +143,9 @@ static PyObject * + _hmacopenssl_HMAC_copy_impl(HmacObject *self) + /*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ + { +- HmacObject *retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ HmacObject *retval; ++ ++ retval = (HmacObject *)PyObject_New(HmacObject, (PyTypeObject *)PyObject_Type((PyObject *)self)); + if (retval == NULL) { + return NULL; + } +@@ -147,7 +159,7 @@ _hmacopenssl_HMAC_copy_impl(HmacObject *self) + return _setException(PyExc_ValueError); + } + +- return (PyObject*)retval; ++ return (PyObject *)retval; + } + + static void +@@ -338,19 +350,24 @@ Attributes:\n\ + name -- the name, including the hash algorithm used by this object\n\ + digest_size -- number of bytes in digest() output\n"); + +-static PyTypeObject HmacType = { +- PyVarObject_HEAD_INIT(NULL, 0) +- "_hmacopenssl.HMAC", /*tp_name*/ +- sizeof(HmacObject), /*tp_basicsize*/ +- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, +- .tp_doc = hmactype_doc, +- .tp_repr = (reprfunc)_hmac_repr, +- .tp_dealloc = (destructor)_hmac_dealloc, +- .tp_methods = Hmac_methods, +- .tp_getset = Hmac_getset, +- .tp_members = Hmac_members, ++static PyType_Slot HmacType_slots[] = { ++ {Py_tp_doc, hmactype_doc}, ++ {Py_tp_repr, (reprfunc)_hmac_repr}, ++ {Py_tp_dealloc,(destructor)_hmac_dealloc}, ++ {Py_tp_methods, Hmac_methods}, ++ {Py_tp_getset, Hmac_getset}, ++ {Py_tp_members, Hmac_members}, ++ {0, NULL} ++}; ++ ++PyType_Spec HmacType_spec = { ++ "_hmacopenssl.HMAC", /* name */ ++ sizeof(HmacObject), /* basicsize */ ++ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .slots = HmacType_slots, + }; + ++ + static struct PyMethodDef hmacopenssl_functions[] = { + _HMACOPENSSL_NEW_METHODDEF + {NULL, NULL} /* Sentinel */ +@@ -360,37 +377,46 @@ static struct PyMethodDef hmacopenssl_functions[] = { + + /* Initialize this module. */ + +- +-static struct PyModuleDef _hmacopenssl_module = { +- PyModuleDef_HEAD_INIT, +- "_hmacopenssl", +- NULL, +- -1, +- hmacopenssl_functions, +- NULL, +- NULL, +- NULL, +- NULL +-}; +- +-PyMODINIT_FUNC +-PyInit__hmacopenssl(void) +-{ ++static int ++hmacopenssl_exec(PyObject *m) { + /* TODO build EVP_functions openssl_* entries dynamically based + * on what hashes are supported rather than listing many +- * but having some be unsupported. Only init appropriate ++ * and having some unsupported. Only init appropriate + * constants. */ ++ PyObject *temp; + +- Py_TYPE(&HmacType) = &PyType_Type; +- if (PyType_Ready(&HmacType) < 0) +- return NULL; ++ temp = PyType_FromSpec(&HmacType_spec); ++ if (temp == NULL) { ++ goto fail; ++ } + +- PyObject *m = PyModule_Create(&_hmacopenssl_module); +- if (m == NULL) +- return NULL; ++ if (PyModule_AddObject(m, "HMAC", temp) == -1) { ++ goto fail; ++ } ++ ++ return 0; + +- Py_INCREF((PyObject *)&HmacType); +- PyModule_AddObject(m, "HMAC", (PyObject *)&HmacType); ++fail: ++ Py_XDECREF(temp); ++ return -1; ++} + +- return m; ++static PyModuleDef_Slot hmacopenssl_slots[] = { ++ {Py_mod_exec, hmacopenssl_exec}, ++ {0, NULL}, ++}; ++ ++static struct PyModuleDef _hmacopenssl_def = { ++ PyModuleDef_HEAD_INIT, /* m_base */ ++ .m_name = "_hmacopenssl", ++ .m_methods = hmacopenssl_functions, ++ .m_slots = hmacopenssl_slots, ++ .m_size = sizeof(hmacopenssl_state) ++}; ++ ++ ++PyMODINIT_FUNC ++PyInit__hmacopenssl(void) ++{ ++ return PyModuleDef_Init(&_hmacopenssl_def); + } +-- +2.25.4 + + +From 408a7d606654249f4aaa2c26cd960b770429229c Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Mon, 29 Jul 2019 13:05:04 +0200 +Subject: [PATCH 10/36] revert cosmetic nitpick and remove trailing whitespace + +--- + Lib/hmac.py | 2 +- + Modules/_hmacopenssl.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index 2ec24da..daabc8c 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -48,7 +48,7 @@ class HMAC: + if _hashlib.get_fips_mode(): + raise ValueError( + 'hmac.HMAC is not available in FIPS mode. ' +- 'Use hmac.new().' ++ + 'Use hmac.new().' + ) + + if not isinstance(key, (bytes, bytearray)): +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 216ed04..221714c 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -363,7 +363,7 @@ static PyType_Slot HmacType_slots[] = { + PyType_Spec HmacType_spec = { + "_hmacopenssl.HMAC", /* name */ + sizeof(HmacObject), /* basicsize */ +- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = HmacType_slots, + }; + +@@ -407,7 +407,7 @@ static PyModuleDef_Slot hmacopenssl_slots[] = { + }; + + static struct PyModuleDef _hmacopenssl_def = { +- PyModuleDef_HEAD_INIT, /* m_base */ ++ PyModuleDef_HEAD_INIT, /* m_base */ + .m_name = "_hmacopenssl", + .m_methods = hmacopenssl_functions, + .m_slots = hmacopenssl_slots, +-- +2.25.4 + + +From 6ed4037723b1ac437cfd8401355350ef5c47f0e1 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Wed, 31 Jul 2019 15:43:43 +0200 +Subject: [PATCH 11/36] Add initial tests for various hashes under FIPS mode + +--- + Lib/test/test_fips.py | 64 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 64 insertions(+) + create mode 100644 Lib/test/test_fips.py + +diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py +new file mode 100644 +index 0000000..bee911e +--- /dev/null ++++ b/Lib/test/test_fips.py +@@ -0,0 +1,64 @@ ++import unittest ++import hmac, _hmacopenssl ++import hashlib, _hashlib ++ ++ ++ ++class HashlibFipsTests(unittest.TestCase): ++ ++ @unittest.skipUnless(hashlib.get_fips_mode(), "Test only when FIPS is enabled") ++ def test_fips_imports(self): ++ """blake2s and blake2b should fail to import in FIPS mode ++ """ ++ with self.assertRaises(ValueError, msg='blake2s not available in FIPS'): ++ m = hashlib.blake2s() ++ with self.assertRaises(ValueError, msg='blake2b not available in FIPS'): ++ m = hashlib.blake2b() ++ ++ def compare_hashes(self, python_hash, openssl_hash): ++ """ ++ Compare between the python implementation and the openssl one that the digests ++ are the same ++ """ ++ if python_hash.name.startswith('shake_128'): ++ m = python_hash.hexdigest(16) ++ elif python_hash.name.startswith('shake_256'): ++ m = python_hash.hexdigest(32) ++ else: ++ m = python_hash.hexdigest() ++ h = openssl_hash.hexdigest() ++ ++ self.assertEqual(m, h) ++ ++ @unittest.skipIf(hashlib.get_fips_mode(), "blake2 hashes are not available under FIPS") ++ def test_blake2_hashes(self): ++ self.compare_hashes(hashlib.blake2b(b'abc'), _hashlib.openssl_blake2b(b'abc')) ++ self.compare_hashes(hashlib.blake2s(b'abc'), _hashlib.openssl_blake2s(b'abc')) ++ ++ def test_sha3_hashes(self): ++ self.compare_hashes(hashlib.sha3_224(b'abc'), _hashlib.openssl_sha3_224(b'abc')) ++ self.compare_hashes(hashlib.sha3_256(b'abc'), _hashlib.openssl_sha3_256(b'abc')) ++ self.compare_hashes(hashlib.sha3_384(b'abc'), _hashlib.openssl_sha3_384(b'abc')) ++ self.compare_hashes(hashlib.sha3_512(b'abc'), _hashlib.openssl_sha3_512(b'abc')) ++ ++ @unittest.skipIf(hashlib.get_fips_mode(), "shake hashes are not available under FIPS") ++ def test_shake_hashes(self): ++ self.compare_hashes(hashlib.shake_128(b'abc'), _hashlib.openssl_shake_128(b'abc')) ++ self.compare_hashes(hashlib.shake_256(b'abc'), _hashlib.openssl_shake_256(b'abc')) ++ ++ def test_sha(self): ++ self.compare_hashes(hashlib.sha1(b'abc'), _hashlib.openssl_sha1(b'abc')) ++ self.compare_hashes(hashlib.sha224(b'abc'), _hashlib.openssl_sha224(b'abc')) ++ self.compare_hashes(hashlib.sha256(b'abc'), _hashlib.openssl_sha256(b'abc')) ++ self.compare_hashes(hashlib.sha384(b'abc'), _hashlib.openssl_sha384(b'abc')) ++ self.compare_hashes(hashlib.sha512(b'abc'), _hashlib.openssl_sha512(b'abc')) ++ ++ def test_hmac_digests(self): ++ self.compare_hashes(_hmacopenssl.new(b'My hovercraft is full of eels', digestmod='sha384'), ++ hmac.new(b'My hovercraft is full of eels', digestmod='sha384')) ++ ++ ++ ++ ++if __name__ == "__main__": ++ unittest.main() +-- +2.25.4 + + +From 2548227dff8ae23fb7d3dd45b6e044ff17796547 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Thu, 1 Aug 2019 16:39:37 +0200 +Subject: [PATCH 12/36] Initialize HMAC type. + +--- + Modules/_hmacopenssl.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 221714c..239445a 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -22,12 +22,12 @@ + #include "_hashopenssl.h" + + +-#include + + typedef struct hmacopenssl_state { + PyTypeObject *HmacType; + } hmacopenssl_state; + ++#include + + typedef struct { + PyObject_HEAD +@@ -39,7 +39,7 @@ typedef struct { + #include "clinic/_hmacopenssl.c.h" + /*[clinic input] + module _hmacopenssl +-class _hmacopenssl.HMAC "HmacObject *" "PyModule_GetState(module)->HmacType" ++class _hmacopenssl.HMAC "HmacObject *" "((hmacopenssl_state *)PyModule_GetState(module))->HmacType" + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ + +@@ -71,7 +71,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + return NULL; + } + +- /* name mut be lowercase */ ++ /* name must be lowercase */ + for (int i=0; digestmod[i]; i++) { + if ( + ((digestmod[i] < 'a') || (digestmod[i] > 'z')) +@@ -383,7 +383,8 @@ hmacopenssl_exec(PyObject *m) { + * on what hashes are supported rather than listing many + * and having some unsupported. Only init appropriate + * constants. */ +- PyObject *temp; ++ PyObject *temp = NULL; ++ hmacopenssl_state *state; + + temp = PyType_FromSpec(&HmacType_spec); + if (temp == NULL) { +@@ -394,6 +395,9 @@ hmacopenssl_exec(PyObject *m) { + goto fail; + } + ++ state = PyModule_GetState(m); ++ state->HmacType = (PyTypeObject *)temp; ++ + return 0; + + fail: +-- +2.25.4 + + +From 4d40c61ed97eae9169df2e526d935d4997902f97 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 1 Aug 2019 17:57:05 +0200 +Subject: [PATCH 13/36] Use a stronger hash in multiprocessing handshake + +Adapted from patch by David Malcolm, +https://bugs.python.org/issue17258 +--- + Lib/multiprocessing/connection.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py +index c9f995e..64180b2 100644 +--- a/Lib/multiprocessing/connection.py ++++ b/Lib/multiprocessing/connection.py +@@ -42,6 +42,10 @@ BUFSIZE = 8192 + # A very generous timeout when it comes to local connections... + CONNECTION_TIMEOUT = 20. + ++# The hmac module implicitly defaults to using MD5. ++# Support using a stronger algorithm for the challenge/response code: ++HMAC_DIGEST_NAME='sha256' ++ + _mmap_counter = itertools.count() + + default_family = 'AF_INET' +@@ -735,7 +739,7 @@ def deliver_challenge(connection, authkey): + "Authkey must be bytes, not {0!s}".format(type(authkey))) + message = os.urandom(MESSAGE_LENGTH) + connection.send_bytes(CHALLENGE + message) +- digest = hmac.new(authkey, message, 'md5').digest() ++ digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest() + response = connection.recv_bytes(256) # reject large message + if response == digest: + connection.send_bytes(WELCOME) +@@ -751,7 +755,7 @@ def answer_challenge(connection, authkey): + message = connection.recv_bytes(256) # reject large message + assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message + message = message[len(CHALLENGE):] +- digest = hmac.new(authkey, message, 'md5').digest() ++ digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest() + connection.send_bytes(digest) + response = connection.recv_bytes(256) # reject large message + if response != WELCOME: +-- +2.25.4 + + +From bc917ee79da1166e9ff94e76bbb2a64044db2fc0 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Fri, 2 Aug 2019 17:36:01 +0200 +Subject: [PATCH 14/36] Fix refcounting + +--- + Modules/_hmacopenssl.c | 35 ++++++++++++++++++++++++++++++++++- + 1 file changed, 34 insertions(+), 1 deletion(-) + +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 239445a..9c28828 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -373,6 +373,34 @@ static struct PyMethodDef hmacopenssl_functions[] = { + {NULL, NULL} /* Sentinel */ + }; + ++static int ++hmacopenssl_traverse(PyObject *self, visitproc visit, void *arg) ++{ ++ hmacopenssl_state *state; ++ ++ state = PyModule_GetState(self); ++ ++ if (state) { ++ Py_VISIT(state->HmacType); ++ } ++ ++ return 0; ++} ++ ++static int ++hmacopenssl_clear(PyObject *self) ++{ ++ hmacopenssl_state *state; ++ ++ state = PyModule_GetState(self); ++ ++ if (state) { ++ Py_CLEAR(state->HmacType); ++ } ++ ++ return 0; ++} ++ + + + /* Initialize this module. */ +@@ -396,7 +424,10 @@ hmacopenssl_exec(PyObject *m) { + } + + state = PyModule_GetState(m); ++ + state->HmacType = (PyTypeObject *)temp; ++ Py_INCREF(temp); ++ + + return 0; + +@@ -415,7 +446,9 @@ static struct PyModuleDef _hmacopenssl_def = { + .m_name = "_hmacopenssl", + .m_methods = hmacopenssl_functions, + .m_slots = hmacopenssl_slots, +- .m_size = sizeof(hmacopenssl_state) ++ .m_size = sizeof(hmacopenssl_state), ++ .m_traverse = hmacopenssl_traverse, ++ .m_clear = hmacopenssl_clear + }; + + +-- +2.25.4 + + +From 5807870fbc69dcd107a2fac7ce58da052d5e7fea Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 13:37:05 +0200 +Subject: [PATCH 15/36] hmac: Don't default to md5 in FIPS mode + +--- + Lib/hmac.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index daabc8c..0302364 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -173,7 +173,7 @@ def new(key, msg=None, digestmod=''): + """ + if _hashlib.get_fips_mode(): + if digestmod is None: +- digestmod = 'md5' ++ raise ValueError("'digestmod' argument is mandatory in FIPS mode") + name = _get_openssl_name(digestmod) + result = _hmacopenssl.new(key, digestmod=name) + if msg: +-- +2.25.4 + + +From 04a69823b36ee8626aa74b40d5a631dd09759451 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 14:20:58 +0200 +Subject: [PATCH 16/36] Make _hmacopenssl.HMAC subclassable; subclass it as + hmac.HMAC under FIPS + +This removes the _hmacopenssl.new function. +--- + Lib/hmac.py | 26 +++++++----- + Lib/test/test_fips.py | 2 +- + Modules/_hmacopenssl.c | 75 ++++++++++++++++----------------- + Modules/clinic/_hmacopenssl.c.h | 39 +---------------- + 4 files changed, 55 insertions(+), 87 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index 0302364..e4222be 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -143,6 +143,8 @@ class HMAC: + return h.hexdigest() + + def _get_openssl_name(digestmod): ++ if digestmod is None: ++ raise ValueError("'digestmod' argument is mandatory in FIPS mode") + if isinstance(digestmod, str): + return digestmod.lower() + elif callable(digestmod): +@@ -154,6 +156,19 @@ def _get_openssl_name(digestmod): + + return digestmod.name.lower().replace('_', '-') + ++class HMAC_openssl(_hmacopenssl.HMAC): ++ def __new__(cls, key, msg = None, digestmod = None): ++ name = _get_openssl_name(digestmod) ++ result = _hmacopenssl.HMAC.__new__(cls, key, digestmod=name) ++ if msg: ++ result.update(msg) ++ return result ++ ++ ++if _hashlib.get_fips_mode(): ++ HMAC = HMAC_openssl ++ ++ + def new(key, msg=None, digestmod=''): + """Create a new hashing object and return it. + +@@ -171,16 +186,7 @@ def new(key, msg=None, digestmod=''): + method, and can ask for the hash value at any time by calling its digest() + or hexdigest() methods. + """ +- if _hashlib.get_fips_mode(): +- if digestmod is None: +- raise ValueError("'digestmod' argument is mandatory in FIPS mode") +- name = _get_openssl_name(digestmod) +- result = _hmacopenssl.new(key, digestmod=name) +- if msg: +- result.update(msg) +- return result +- else: +- return HMAC(key, msg, digestmod) ++ return HMAC(key, msg, digestmod) + + + def digest(key, msg, digest): +diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py +index bee911e..34812e6 100644 +--- a/Lib/test/test_fips.py ++++ b/Lib/test/test_fips.py +@@ -54,7 +54,7 @@ class HashlibFipsTests(unittest.TestCase): + self.compare_hashes(hashlib.sha512(b'abc'), _hashlib.openssl_sha512(b'abc')) + + def test_hmac_digests(self): +- self.compare_hashes(_hmacopenssl.new(b'My hovercraft is full of eels', digestmod='sha384'), ++ self.compare_hashes(_hmacopenssl.HMAC(b'My hovercraft is full of eels', digestmod='sha384'), + hmac.new(b'My hovercraft is full of eels', digestmod='sha384')) + + +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 9c28828..7d3d973 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -41,33 +41,25 @@ typedef struct { + module _hmacopenssl + class _hmacopenssl.HMAC "HmacObject *" "((hmacopenssl_state *)PyModule_GetState(module))->HmacType" + [clinic start generated code]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9fe07a087adc2cf9]*/ + + +-/*[clinic input] +-_hmacopenssl.new +- +- key: Py_buffer +- * +- digestmod: str +- +-Return a new hmac object. +-[clinic start generated code]*/ +- + static PyObject * +-_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, +- const char *digestmod) +-/*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ ++Hmac_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) + { +- hmacopenssl_state *state; +- +- if (digestmod == NULL) { +- PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); ++ static char *kwarg_names[] = {"key", "digestmod", NULL}; ++ Py_buffer key = {NULL, NULL}; ++ char *digestmod = NULL; ++ ++ int ret = PyArg_ParseTupleAndKeywords( ++ args, kwds, "y*|$s:_hmacopenssl.HMAC", kwarg_names, ++ &key, &digestmod); ++ if (ret == 0) { + return NULL; + } + +- state = PyModule_GetState(module); +- if (state == NULL) { ++ if (digestmod == NULL) { ++ PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); + return NULL; + } + +@@ -106,8 +98,8 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + + int r = HMAC_Init_ex( + ctx, +- (const char*)key->buf, +- key->len, ++ (const char*)key.buf, ++ key.len, + digest, + NULL /*impl*/); + if (r == 0) { +@@ -115,7 +107,10 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + goto error; + } + +- retval = (HmacObject *)PyObject_New(HmacObject, state->HmacType); ++ PyBuffer_Release(&key); ++ key.buf = NULL; ++ ++ retval = (HmacObject *)subtype->tp_alloc(subtype, 0); + if (retval == NULL) { + goto error; + } +@@ -130,6 +125,7 @@ error: + if (ctx) HMAC_CTX_free(ctx); + if (name) Py_DECREF(name); + if (retval) PyObject_Del(name); ++ if (key.buf) PyBuffer_Release(&key); + return NULL; + } + +@@ -145,19 +141,27 @@ _hmacopenssl_HMAC_copy_impl(HmacObject *self) + { + HmacObject *retval; + +- retval = (HmacObject *)PyObject_New(HmacObject, (PyTypeObject *)PyObject_Type((PyObject *)self)); ++ HMAC_CTX *ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ return _setException(PyExc_ValueError); ++ } ++ ++ int r = HMAC_CTX_copy(ctx, self->ctx); ++ if (r == 0) { ++ HMAC_CTX_free(ctx); ++ return _setException(PyExc_ValueError); ++ } ++ ++ retval = (HmacObject *)Py_TYPE(self)->tp_alloc(Py_TYPE(self), 0); + if (retval == NULL) { ++ HMAC_CTX_free(ctx); + return NULL; + } +- ++ retval->ctx = ctx; + Py_INCREF(self->name); + retval->name = self->name; + +- int r = HMAC_CTX_copy(retval->ctx, self->ctx); +- if (r == 0) { +- PyObject_Del(retval); +- return _setException(PyExc_ValueError); +- } ++ retval->lock = NULL; + + return (PyObject *)retval; + } +@@ -169,8 +173,8 @@ _hmac_dealloc(HmacObject *self) + PyThread_free_lock(self->lock); + } + HMAC_CTX_free(self->ctx); +- Py_XDECREF(self->name); +- PyObject_Del(self); ++ Py_CLEAR(self->name); ++ Py_TYPE(self)->tp_free(self); + } + + static PyObject * +@@ -357,6 +361,7 @@ static PyType_Slot HmacType_slots[] = { + {Py_tp_methods, Hmac_methods}, + {Py_tp_getset, Hmac_getset}, + {Py_tp_members, Hmac_members}, ++ {Py_tp_new, Hmac_new}, + {0, NULL} + }; + +@@ -368,11 +373,6 @@ PyType_Spec HmacType_spec = { + }; + + +-static struct PyMethodDef hmacopenssl_functions[] = { +- _HMACOPENSSL_NEW_METHODDEF +- {NULL, NULL} /* Sentinel */ +-}; +- + static int + hmacopenssl_traverse(PyObject *self, visitproc visit, void *arg) + { +@@ -444,7 +444,6 @@ static PyModuleDef_Slot hmacopenssl_slots[] = { + static struct PyModuleDef _hmacopenssl_def = { + PyModuleDef_HEAD_INIT, /* m_base */ + .m_name = "_hmacopenssl", +- .m_methods = hmacopenssl_functions, + .m_slots = hmacopenssl_slots, + .m_size = sizeof(hmacopenssl_state), + .m_traverse = hmacopenssl_traverse, +diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h +index b472a6e..861acc1 100644 +--- a/Modules/clinic/_hmacopenssl.c.h ++++ b/Modules/clinic/_hmacopenssl.c.h +@@ -2,43 +2,6 @@ + preserve + [clinic start generated code]*/ + +-PyDoc_STRVAR(_hmacopenssl_new__doc__, +-"new($module, /, key, *, digestmod)\n" +-"--\n" +-"\n" +-"Return a new hmac object."); +- +-#define _HMACOPENSSL_NEW_METHODDEF \ +- {"new", (PyCFunction)_hmacopenssl_new, METH_FASTCALL, _hmacopenssl_new__doc__}, +- +-static PyObject * +-_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, +- const char *digestmod); +- +-static PyObject * +-_hmacopenssl_new(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +-{ +- PyObject *return_value = NULL; +- static const char * const _keywords[] = {"key", "digestmod", NULL}; +- static _PyArg_Parser _parser = {"y*$s:new", _keywords, 0}; +- Py_buffer key = {NULL, NULL}; +- const char *digestmod; +- +- if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, +- &key, &digestmod)) { +- goto exit; +- } +- return_value = _hmacopenssl_new_impl(module, &key, digestmod); +- +-exit: +- /* Cleanup for key */ +- if (key.obj) { +- PyBuffer_Release(&key); +- } +- +- return return_value; +-} +- + PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, + "copy($self, /)\n" + "--\n" +@@ -130,4 +93,4 @@ _hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) + { + return _hmacopenssl_HMAC_hexdigest_impl(self); + } +-/*[clinic end generated code: output=10b6e8cac6d7a2c9 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d93ad460795d49b5 input=a9049054013a1b77]*/ +-- +2.25.4 + + +From e0cbbc9dac64f173baa5348cf3608536ea8aea70 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 16:10:36 +0200 +Subject: [PATCH 17/36] Fix _hmacopenssl.HMAC.block_size + +--- + Modules/_hmacopenssl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 7d3d973..a24c8ba 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -318,7 +318,7 @@ _hmacopenssl_get_block_size(HmacObject *self, void *closure) + if (md == NULL) { + return _setException(PyExc_ValueError); + } +- return PyLong_FromLong(EVP_MD_size(md)); ++ return PyLong_FromLong(EVP_MD_block_size(md)); + } + + static PyMethodDef Hmac_methods[] = { +-- +2.25.4 + + +From d90c5c55ad983d84b09b366d4b62f06aa535fad6 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 15:02:08 +0200 +Subject: [PATCH 18/36] distutils upload: Skip md5 checksum in FIPS mode + +--- + Lib/distutils/command/upload.py | 12 +++++++++++- + Lib/distutils/tests/test_upload.py | 13 +++++++++++-- + 2 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py +index 11afa24..79a6315 100644 +--- a/Lib/distutils/command/upload.py ++++ b/Lib/distutils/command/upload.py +@@ -102,7 +102,6 @@ class upload(PyPIRCCommand): + 'content': (os.path.basename(filename),content), + 'filetype': command, + 'pyversion': pyversion, +- 'md5_digest': hashlib.md5(content).hexdigest(), + + # additional meta-data + 'metadata_version': '1.0', +@@ -122,6 +121,17 @@ class upload(PyPIRCCommand): + 'obsoletes': meta.get_obsoletes(), + } + ++ try: ++ digest = hashlib.md5(content).hexdigest() ++ except ValueError as e: ++ msg = 'calculating md5 checksum failed: %s' % e ++ self.announce(msg, log.ERROR) ++ if not hashlib.get_fips_mode(): ++ # this really shouldn't fail ++ raise ++ else: ++ data['md5_digest'] = digest ++ + data['comment'] = '' + + if self.sign: +diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py +index c17d8e7..b4b64e9 100644 +--- a/Lib/distutils/tests/test_upload.py ++++ b/Lib/distutils/tests/test_upload.py +@@ -3,6 +3,7 @@ import os + import unittest + import unittest.mock as mock + from urllib.request import HTTPError ++import hashlib + + from test.support import run_unittest + +@@ -130,7 +131,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + + # what did we send ? + headers = dict(self.last_open.req.headers) +- self.assertEqual(headers['Content-length'], '2162') ++ if hashlib.get_fips_mode(): ++ # md5 hash is omitted ++ self.assertEqual(headers['Content-length'], '2020') ++ else: ++ self.assertEqual(headers['Content-length'], '2162') + content_type = headers['Content-type'] + self.assertTrue(content_type.startswith('multipart/form-data')) + self.assertEqual(self.last_open.req.get_method(), 'POST') +@@ -166,7 +171,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + cmd.run() + + headers = dict(self.last_open.req.headers) +- self.assertEqual(headers['Content-length'], '2172') ++ if hashlib.get_fips_mode(): ++ # md5 hash is omitted ++ self.assertEqual(headers['Content-length'], '2030') ++ else: ++ self.assertEqual(headers['Content-length'], '2172') + self.assertIn(b'long description\r', self.last_open.req.data) + + def test_upload_fails(self): +-- +2.25.4 + + +From 885f7b41697f252260a67d78ca8c46450843fa5e Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 15:32:25 +0200 +Subject: [PATCH 19/36] Fix HMAC tests on FIPS mode + +--- + Lib/hmac.py | 3 +++ + Lib/test/test_hmac.py | 26 ++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index e4222be..394c810 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -158,6 +158,9 @@ def _get_openssl_name(digestmod): + + class HMAC_openssl(_hmacopenssl.HMAC): + def __new__(cls, key, msg = None, digestmod = None): ++ if not isinstance(key, (bytes, bytearray)): ++ raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) ++ + name = _get_openssl_name(digestmod) + result = _hmacopenssl.HMAC.__new__(cls, key, digestmod=name) + if msg: +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 23c108f..0a85981 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -288,6 +288,7 @@ class TestVectorsTestCase(unittest.TestCase): + def test_sha512_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) + ++ @unittest.skipIf(hashlib.get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') + @requires_hashdigest('sha256') + def test_legacy_block_size_warnings(self): + class MockCrazyHash(object): +@@ -337,6 +338,14 @@ class ConstructorTestCase(unittest.TestCase): + except Exception: + self.fail("Standard constructor call raised exception.") + ++ def test_normal_digestmod(self): ++ # Standard constructor call. ++ failed = 0 ++ try: ++ h = hmac.HMAC(b"key", digestmod='sha1') ++ except Exception: ++ self.fail("Standard constructor call raised exception.") ++ + @requires_hashdigest('sha256') + def test_with_str_key(self): + # Pass a key of type str, which is an error, because it expects a key +@@ -404,6 +413,7 @@ class SanityTestCase(unittest.TestCase): + + class CopyTestCase(unittest.TestCase): + ++ @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') + def test_attributes(self): + # Testing if attributes are of same type. +@@ -416,6 +426,7 @@ class CopyTestCase(unittest.TestCase): + self.assertEqual(type(h1.outer), type(h2.outer), + "Types of outer don't match.") + ++ @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') + def test_realcopy(self): + # Testing if the copy method created a real copy. +@@ -428,6 +439,21 @@ class CopyTestCase(unittest.TestCase): + self.assertTrue(id(h1.outer) != id(h2.outer), + "No real copy of the attribute 'outer'.") + ++ def test_realcopy(self): ++ # Testing if the copy method created a real copy. ++ h1 = hmac.HMAC(b"key", digestmod="sha1") ++ h2 = h1.copy() ++ # Using id() in case somebody has overridden __eq__/__ne__. ++ self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.") ++ old_digest = h1.digest() ++ assert h1.digest() == h2.digest() ++ h1.update(b'hi') ++ assert h1.digest() != h2.digest() ++ assert h2.digest() == old_digest ++ new_digest = h1.digest() ++ h2.update(b'hi') ++ assert h1.digest() == h2.digest() == new_digest ++ + @requires_hashdigest('sha256') + def test_equality(self): + # Testing if the copy has the same digests. +-- +2.25.4 + + +From 288d91b4752801264b37f7e94d964e1dffdee562 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 16:37:12 +0200 +Subject: [PATCH 20/36] test_tools: Skip md5sum tests in FIPS mode + +--- + Lib/test/test_tools/test_md5sum.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Lib/test/test_tools/test_md5sum.py b/Lib/test/test_tools/test_md5sum.py +index fb565b7..7028a4d 100644 +--- a/Lib/test/test_tools/test_md5sum.py ++++ b/Lib/test/test_tools/test_md5sum.py +@@ -4,11 +4,15 @@ import os + import unittest + from test import support + from test.support.script_helper import assert_python_ok, assert_python_failure ++import hashlib + + from test.test_tools import scriptsdir, skip_if_missing + + skip_if_missing() + ++if hashlib.get_fips_mode(): ++ raise unittest.SkipTest("md5sum won't work at all in FIPS mode") ++ + class MD5SumTests(unittest.TestCase): + @classmethod + def setUpClass(cls): +-- +2.25.4 + + +From 2c89b2e465e60558e0e066cc42a087ee6f31d520 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 18:23:57 +0200 +Subject: [PATCH 21/36] Make hashlib tests pass in FIPS mode + +--- + Lib/test/test_hashlib.py | 67 ++++++++++++++++++++++++++++------------ + 1 file changed, 48 insertions(+), 19 deletions(-) + +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 2a55fd4..9ae5efc 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -28,6 +28,11 @@ COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') + c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) + py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) + ++if hashlib.get_fips_mode(): ++ FIPS_DISABLED = {'md5', 'MD5', 'blake2b', 'blake2s'} ++else: ++ FIPS_DISABLED = set() ++ + try: + from _hashlib import HASH + except ImportError: +@@ -88,6 +93,11 @@ class HashLibTestCase(unittest.TestCase): + # Issue #14693: fallback modules are always compiled under POSIX + _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG + ++ if hashlib.get_fips_mode(): ++ shakes = set() ++ supported_hash_names = tuple( ++ n for n in supported_hash_names if n not in FIPS_DISABLED) ++ + def _conditional_import_module(self, module_name): + """Import a module and return a reference to it or None on failure.""" + try: +@@ -95,8 +105,20 @@ class HashLibTestCase(unittest.TestCase): + except ModuleNotFoundError as error: + if self._warn_on_extension_import: + warnings.warn('Did a C extension fail to compile? %s' % error) ++ except ImportError as error: ++ if not hashlib.get_fips_mode(): ++ raise + return None + ++ def _has_shake_extras(self, hasher): ++ """Return true if the hasher should have "shake" API (digest length)""" ++ if hasher.name not in self.shakes: ++ return False ++ _hashlib = self._conditional_import_module('_hashlib') ++ if _hashlib and isinstance(hasher, _hashlib.HASH): ++ return False ++ return True ++ + def __init__(self, *args, **kwargs): + algorithms = set() + for algorithm in self.supported_hash_names: +@@ -190,15 +212,13 @@ class HashLibTestCase(unittest.TestCase): + a = array.array("b", range(10)) + for cons in self.hash_constructors: + c = cons(a) +- if (c.name in self.shakes +- and not cons.__name__.startswith('openssl_') +- ): ++ if self._has_shake_extras(c): + c.hexdigest(16) + else: + c.hexdigest() + + def test_algorithms_guaranteed(self): +- self.assertEqual(hashlib.algorithms_guaranteed, ++ self.assertEqual(hashlib.algorithms_guaranteed - FIPS_DISABLED, + set(_algo for _algo in self.supported_hash_names + if _algo.islower())) + +@@ -213,6 +233,12 @@ class HashLibTestCase(unittest.TestCase): + def test_new_upper_to_lower(self): + self.assertEqual(hashlib.new("SHA256").name, "sha256") + ++ @unittest.skipUnless(hashlib.get_fips_mode(), "Builtin constructor only unavailable in FIPS mode") ++ def test_get_builtin_constructor_fips(self): ++ with self.assertRaises(AttributeError): ++ hashlib.__get_builtin_constructor ++ ++ @unittest.skipIf(hashlib.get_fips_mode(), "No builtin constructors in FIPS mode") + def test_get_builtin_constructor(self): + get_builtin_constructor = getattr(hashlib, + '__get_builtin_constructor') +@@ -242,9 +268,7 @@ class HashLibTestCase(unittest.TestCase): + def test_hexdigest(self): + for cons in self.hash_constructors: + h = cons() +- if (h.name in self.shakes +- and not cons.__name__.startswith('openssl_') +- ): ++ if self._has_shake_extras(h): + self.assertIsInstance(h.digest(16), bytes) + self.assertEqual(hexstr(h.digest(16)), h.hexdigest(16)) + else: +@@ -256,9 +280,7 @@ class HashLibTestCase(unittest.TestCase): + large_sizes = (2**29, 2**32-10, 2**32+10, 2**61, 2**64-10, 2**64+10) + for cons in self.hash_constructors: + h = cons() +- if h.name not in self.shakes: +- continue +- if cons.__name__.startswith('openssl_'): ++ if not self._has_shake_extras(h): + continue + for digest in h.digest, h.hexdigest: + self.assertRaises(ValueError, digest, -10) +@@ -288,9 +310,7 @@ class HashLibTestCase(unittest.TestCase): + m1.update(bees) + m1.update(cees) + m1.update(dees) +- if (m1.name in self.shakes +- and not cons.__name__.startswith('openssl_') +- ): ++ if self._has_shake_extras(m1): + args = (16,) + else: + args = () +@@ -359,7 +379,8 @@ class HashLibTestCase(unittest.TestCase): + self.assertRaises(TypeError, hash_object_constructor, 'spam') + + def test_no_unicode(self): +- self.check_no_unicode('md5') ++ if not hashlib.get_fips_mode(): ++ self.check_no_unicode('md5') + self.check_no_unicode('sha1') + self.check_no_unicode('sha224') + self.check_no_unicode('sha256') +@@ -402,7 +423,8 @@ class HashLibTestCase(unittest.TestCase): + self.assertIn(name.split("_")[0], repr(m)) + + def test_blocksize_name(self): +- self.check_blocksize_name('md5', 64, 16) ++ if not hashlib.get_fips_mode(): ++ self.check_blocksize_name('md5', 64, 16) + self.check_blocksize_name('sha1', 64, 20) + self.check_blocksize_name('sha224', 64, 28) + self.check_blocksize_name('sha256', 64, 32) +@@ -445,22 +467,27 @@ class HashLibTestCase(unittest.TestCase): + self.check_blocksize_name('blake2b', 128, 64) + self.check_blocksize_name('blake2s', 64, 32) + ++ @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + def test_case_md5_0(self): + self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e') + ++ @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + def test_case_md5_1(self): + self.check('md5', b'abc', '900150983cd24fb0d6963f7d28e17f72') + ++ @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + def test_case_md5_2(self): + self.check('md5', + b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', + 'd174ab98d277d9f5a5611c2c9f419d9f') + ++ @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G + 5, memuse=1, dry_run=False) + def test_case_md5_huge(self, size): + self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') + ++ @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) + def test_case_md5_uintmax(self, size): +@@ -842,14 +869,16 @@ class HashLibTestCase(unittest.TestCase): + m = cons(b'x' * gil_minsize) + m.update(b'1') + +- m = hashlib.md5() ++ m = hashlib.sha1() + m.update(b'1') + m.update(b'#' * gil_minsize) + m.update(b'1') +- self.assertEqual(m.hexdigest(), 'cb1e1a2cbc80be75e19935d621fb9b21') ++ self.assertEqual(m.hexdigest(), ++ 'c45f7445ca0ea087d7a1758fbea07935f267c46a') + +- m = hashlib.md5(b'x' * gil_minsize) +- self.assertEqual(m.hexdigest(), 'cfb767f225d58469c5de3632a8803958') ++ m = hashlib.sha1(b'x' * gil_minsize) ++ self.assertEqual(m.hexdigest(), ++ '63fda1efde982ba1ffe9d53035bff5c9ce4758fb') + + @support.reap_threads + def test_threaded_hashing(self): +-- +2.25.4 + + +From 14f26f4f378718024d0b0f300ab2f84429d23044 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +Date: Wed, 14 Aug 2019 14:43:07 +0200 +Subject: [PATCH 22/36] distutils upload: only add md5 if available, but + *always* use sha256 + +--- + Lib/distutils/command/upload.py | 3 ++- + Lib/distutils/tests/test_upload.py | 14 ++++++++------ + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py +index 79a6315..553617a 100644 +--- a/Lib/distutils/command/upload.py ++++ b/Lib/distutils/command/upload.py +@@ -102,6 +102,7 @@ class upload(PyPIRCCommand): + 'content': (os.path.basename(filename),content), + 'filetype': command, + 'pyversion': pyversion, ++ 'sha256_digest': hashlib.sha256(content).hexdigest(), + + # additional meta-data + 'metadata_version': '1.0', +@@ -125,7 +126,7 @@ class upload(PyPIRCCommand): + digest = hashlib.md5(content).hexdigest() + except ValueError as e: + msg = 'calculating md5 checksum failed: %s' % e +- self.announce(msg, log.ERROR) ++ self.announce(msg, log.INFO) + if not hashlib.get_fips_mode(): + # this really shouldn't fail + raise +diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py +index b4b64e9..f720a79 100644 +--- a/Lib/distutils/tests/test_upload.py ++++ b/Lib/distutils/tests/test_upload.py +@@ -132,10 +132,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + # what did we send ? + headers = dict(self.last_open.req.headers) + if hashlib.get_fips_mode(): +- # md5 hash is omitted +- self.assertEqual(headers['Content-length'], '2020') ++ # only sha256 hash is used ++ self.assertEqual(headers['Content-length'], '2197') + else: +- self.assertEqual(headers['Content-length'], '2162') ++ # both sha256 and md5 hashes are used ++ self.assertEqual(headers['Content-length'], '2339') + content_type = headers['Content-type'] + self.assertTrue(content_type.startswith('multipart/form-data')) + self.assertEqual(self.last_open.req.get_method(), 'POST') +@@ -172,10 +173,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + + headers = dict(self.last_open.req.headers) + if hashlib.get_fips_mode(): +- # md5 hash is omitted +- self.assertEqual(headers['Content-length'], '2030') ++ # only sha256 hash is used ++ self.assertEqual(headers['Content-length'], '2207') + else: +- self.assertEqual(headers['Content-length'], '2172') ++ # both sha256 and md5 hashes are used ++ self.assertEqual(headers['Content-length'], '2349') + self.assertIn(b'long description\r', self.last_open.req.data) + + def test_upload_fails(self): +-- +2.25.4 + + +From 24e57cc45dc18146a583257e5825d6b6e672742d Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 13 Sep 2019 02:30:00 +0200 +Subject: [PATCH 23/36] bpo-9216: Add usedforsecurity to hashlib constructors + (GH-16044) + +The usedforsecurity keyword only argument added to the hash constructors is useful for FIPS builds and similar restrictive environment with non-technical requirements that legacy algorithms be forbidden by their implementations without being explicitly annotated as not being used for any security related purposes. Linux distros with FIPS support benefit from this being standard rather than making up their own way(s) to do it. + +Contributed and Signed-off-by: Christian Heimes christian@python.org +--- + Doc/library/hashlib.rst | 17 +- + Lib/test/test_hashlib.py | 9 + + Lib/uuid.py | 7 +- + .../2019-09-12-14-54-45.bpo-9216.W7QMpC.rst | 2 + + Modules/_blake2/blake2b_impl.c | 5 +- + Modules/_blake2/blake2s_impl.c | 5 +- + Modules/_blake2/clinic/blake2b_impl.c.h | 27 +- + Modules/_blake2/clinic/blake2s_impl.c.h | 27 +- + Modules/_hashopenssl.c | 151 ++++--- + Modules/_sha3/clinic/sha3module.c.h | 48 ++- + Modules/_sha3/sha3module.c | 41 +- + Modules/clinic/_hashopenssl.c.h | 407 ++++++++++++++---- + Modules/clinic/md5module.c.h | 28 +- + Modules/clinic/sha1module.c.h | 28 +- + Modules/clinic/sha256module.c.h | 54 ++- + Modules/clinic/sha512module.c.h | 54 ++- + Modules/md5module.c | 6 +- + Modules/sha1module.c | 6 +- + Modules/sha256module.c | 12 +- + Modules/sha512module.c | 12 +- + 20 files changed, 709 insertions(+), 237 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2019-09-12-14-54-45.bpo-9216.W7QMpC.rst + +diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst +index a16c7cd..6eb3a7b 100644 +--- a/Doc/library/hashlib.rst ++++ b/Doc/library/hashlib.rst +@@ -67,7 +67,7 @@ Constructors for hash algorithms that are always present in this module are + :func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, + :func:`sha512`, :func:`blake2b`, and :func:`blake2s`. + :func:`md5` is normally available as well, though it +-may be missing if you are using a rare "FIPS compliant" build of Python. ++may be missing or blocked if you are using a rare "FIPS compliant" build of Python. + Additional algorithms may also be available depending upon the OpenSSL + library that Python uses on your platform. On most platforms the + :func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, :func:`sha3_512`, +@@ -80,6 +80,13 @@ library that Python uses on your platform. On most platforms the + .. versionadded:: 3.6 + :func:`blake2b` and :func:`blake2s` were added. + ++.. versionchanged:: 3.9 ++ All hashlib constructors take a keyword-only argument *usedforsecurity* ++ with default value *True*. A false value allows the use of insecure and ++ blocked hashing algorithms in restricted environments. *False* indicates ++ that the hashing algorithm is not used in a security context, e.g. as a ++ non-cryptographic one-way compression function. ++ + For example, to obtain the digest of the byte string ``b'Nobody inspects the + spammish repetition'``:: + +@@ -99,7 +106,7 @@ More condensed: + >>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest() + 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2' + +-.. function:: new(name[, data]) ++.. function:: new(name[, data], *, usedforsecurity=True) + + Is a generic constructor that takes the string *name* of the desired + algorithm as its first parameter. It also exists to allow access to the +@@ -308,11 +315,13 @@ New hash objects are created by calling constructor functions: + + .. function:: blake2b(data=b'', *, digest_size=64, key=b'', salt=b'', \ + person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, \ +- node_depth=0, inner_size=0, last_node=False) ++ node_depth=0, inner_size=0, last_node=False, \ ++ usedforsecurity=True) + + .. function:: blake2s(data=b'', *, digest_size=32, key=b'', salt=b'', \ + person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, \ +- node_depth=0, inner_size=0, last_node=False) ++ node_depth=0, inner_size=0, last_node=False, \ ++ usedforsecurity=True) + + + These functions return the corresponding hash objects for calculating +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 9ae5efc..08bb91f 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -226,6 +226,15 @@ class HashLibTestCase(unittest.TestCase): + self.assertTrue(set(hashlib.algorithms_guaranteed). + issubset(hashlib.algorithms_available)) + ++ def test_usedforsecurity(self): ++ for cons in self.hash_constructors: ++ cons(usedforsecurity=True) ++ cons(usedforsecurity=False) ++ cons(b'', usedforsecurity=True) ++ cons(b'', usedforsecurity=False) ++ hashlib.new("sha256", usedforsecurity=True) ++ hashlib.new("sha256", usedforsecurity=False) ++ + def test_unknown_hash(self): + self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') + self.assertRaises(TypeError, hashlib.new, 1) +diff --git a/Lib/uuid.py b/Lib/uuid.py +index 188e16b..5f3bc9e 100644 +--- a/Lib/uuid.py ++++ b/Lib/uuid.py +@@ -772,8 +772,11 @@ def uuid1(node=None, clock_seq=None): + def uuid3(namespace, name): + """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" + from hashlib import md5 +- hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() +- return UUID(bytes=hash[:16], version=3) ++ digest = md5( ++ namespace.bytes + bytes(name, "utf-8"), ++ usedforsecurity=False ++ ).digest() ++ return UUID(bytes=digest[:16], version=3) + + def uuid4(): + """Generate a random UUID.""" +diff --git a/Misc/NEWS.d/next/Library/2019-09-12-14-54-45.bpo-9216.W7QMpC.rst b/Misc/NEWS.d/next/Library/2019-09-12-14-54-45.bpo-9216.W7QMpC.rst +new file mode 100644 +index 0000000..a97ca4b +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2019-09-12-14-54-45.bpo-9216.W7QMpC.rst +@@ -0,0 +1,2 @@ ++hashlib constructors now support usedforsecurity flag to signal that a ++hashing algorithm is not used in a security context. +diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c +index 97ce89d..16df232 100644 +--- a/Modules/_blake2/blake2b_impl.c ++++ b/Modules/_blake2/blake2b_impl.c +@@ -82,6 +82,7 @@ _blake2.blake2b.__new__ as py_blake2b_new + node_depth: int = 0 + inner_size: int = 0 + last_node: bool = False ++ usedforsecurity: bool = True + + Return a new BLAKE2b hash object. + [clinic start generated code]*/ +@@ -91,8 +92,8 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + Py_buffer *key, Py_buffer *salt, Py_buffer *person, + int fanout, int depth, unsigned long leaf_size, + unsigned long long node_offset, int node_depth, +- int inner_size, int last_node) +-/*[clinic end generated code: output=65e732c66c2297a0 input=82be35a4e6a9daa2]*/ ++ int inner_size, int last_node, int usedforsecurity) ++/*[clinic end generated code: output=32bfd8f043c6896f input=b947312abff46977]*/ + { + BLAKE2bObject *self = NULL; + Py_buffer buf; +diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c +index c4447b4..66a7ee5 100644 +--- a/Modules/_blake2/blake2s_impl.c ++++ b/Modules/_blake2/blake2s_impl.c +@@ -82,6 +82,7 @@ _blake2.blake2s.__new__ as py_blake2s_new + node_depth: int = 0 + inner_size: int = 0 + last_node: bool = False ++ usedforsecurity: bool = True + + Return a new BLAKE2s hash object. + [clinic start generated code]*/ +@@ -91,8 +92,8 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + Py_buffer *key, Py_buffer *salt, Py_buffer *person, + int fanout, int depth, unsigned long leaf_size, + unsigned long long node_offset, int node_depth, +- int inner_size, int last_node) +-/*[clinic end generated code: output=b95806be0514dcf7 input=641c0509debf714d]*/ ++ int inner_size, int last_node, int usedforsecurity) ++/*[clinic end generated code: output=556181f73905c686 input=4dda87723f23abb0]*/ + { + BLAKE2sObject *self = NULL; + Py_buffer buf; +diff --git a/Modules/_blake2/clinic/blake2b_impl.c.h b/Modules/_blake2/clinic/blake2b_impl.c.h +index cd329c0..07258c3 100644 +--- a/Modules/_blake2/clinic/blake2b_impl.c.h ++++ b/Modules/_blake2/clinic/blake2b_impl.c.h +@@ -5,7 +5,8 @@ preserve + PyDoc_STRVAR(py_blake2b_new__doc__, + "blake2b(data=b\'\', /, *, digest_size=_blake2.blake2b.MAX_DIGEST_SIZE,\n" + " key=b\'\', salt=b\'\', person=b\'\', fanout=1, depth=1, leaf_size=0,\n" +-" node_offset=0, node_depth=0, inner_size=0, last_node=False)\n" ++" node_offset=0, node_depth=0, inner_size=0, last_node=False,\n" ++" usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new BLAKE2b hash object."); +@@ -15,15 +16,15 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + Py_buffer *key, Py_buffer *salt, Py_buffer *person, + int fanout, int depth, unsigned long leaf_size, + unsigned long long node_offset, int node_depth, +- int inner_size, int last_node); ++ int inner_size, int last_node, int usedforsecurity); + + static PyObject * + py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL}; ++ static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "blake2b", 0}; +- PyObject *argsbuf[12]; ++ PyObject *argsbuf[13]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; +@@ -39,6 +40,7 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + int node_depth = 0; + int inner_size = 0; + int last_node = 0; ++ int usedforsecurity = 1; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 1, 0, argsbuf); + if (!fastargs) { +@@ -175,12 +177,21 @@ skip_optional_posonly: + goto skip_optional_kwonly; + } + } +- last_node = PyObject_IsTrue(fastargs[11]); +- if (last_node < 0) { ++ if (fastargs[11]) { ++ last_node = PyObject_IsTrue(fastargs[11]); ++ if (last_node < 0) { ++ goto exit; ++ } ++ if (!--noptargs) { ++ goto skip_optional_kwonly; ++ } ++ } ++ usedforsecurity = PyObject_IsTrue(fastargs[12]); ++ if (usedforsecurity < 0) { + goto exit; + } + skip_optional_kwonly: +- return_value = py_blake2b_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node); ++ return_value = py_blake2b_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity); + + exit: + /* Cleanup for key */ +@@ -261,4 +272,4 @@ _blake2_blake2b_hexdigest(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored)) + { + return _blake2_blake2b_hexdigest_impl(self); + } +-/*[clinic end generated code: output=cbb625d7f60c288c input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=2d6d0fe9aa42a42a input=a9049054013a1b77]*/ +diff --git a/Modules/_blake2/clinic/blake2s_impl.c.h b/Modules/_blake2/clinic/blake2s_impl.c.h +index 560bd68..71c5706 100644 +--- a/Modules/_blake2/clinic/blake2s_impl.c.h ++++ b/Modules/_blake2/clinic/blake2s_impl.c.h +@@ -5,7 +5,8 @@ preserve + PyDoc_STRVAR(py_blake2s_new__doc__, + "blake2s(data=b\'\', /, *, digest_size=_blake2.blake2s.MAX_DIGEST_SIZE,\n" + " key=b\'\', salt=b\'\', person=b\'\', fanout=1, depth=1, leaf_size=0,\n" +-" node_offset=0, node_depth=0, inner_size=0, last_node=False)\n" ++" node_offset=0, node_depth=0, inner_size=0, last_node=False,\n" ++" usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new BLAKE2s hash object."); +@@ -15,15 +16,15 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, + Py_buffer *key, Py_buffer *salt, Py_buffer *person, + int fanout, int depth, unsigned long leaf_size, + unsigned long long node_offset, int node_depth, +- int inner_size, int last_node); ++ int inner_size, int last_node, int usedforsecurity); + + static PyObject * + py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL}; ++ static const char * const _keywords[] = {"", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "blake2s", 0}; +- PyObject *argsbuf[12]; ++ PyObject *argsbuf[13]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; +@@ -39,6 +40,7 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + int node_depth = 0; + int inner_size = 0; + int last_node = 0; ++ int usedforsecurity = 1; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 1, 0, argsbuf); + if (!fastargs) { +@@ -175,12 +177,21 @@ skip_optional_posonly: + goto skip_optional_kwonly; + } + } +- last_node = PyObject_IsTrue(fastargs[11]); +- if (last_node < 0) { ++ if (fastargs[11]) { ++ last_node = PyObject_IsTrue(fastargs[11]); ++ if (last_node < 0) { ++ goto exit; ++ } ++ if (!--noptargs) { ++ goto skip_optional_kwonly; ++ } ++ } ++ usedforsecurity = PyObject_IsTrue(fastargs[12]); ++ if (usedforsecurity < 0) { + goto exit; + } + skip_optional_kwonly: +- return_value = py_blake2s_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node); ++ return_value = py_blake2s_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity); + + exit: + /* Cleanup for key */ +@@ -261,4 +272,4 @@ _blake2_blake2s_hexdigest(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored)) + { + return _blake2_blake2s_hexdigest_impl(self); + } +-/*[clinic end generated code: output=39af5a74c8805b36 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=c80d8d06ce40a192 input=a9049054013a1b77]*/ +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index e10dbd7..29c1bd8 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -517,7 +517,7 @@ static PyTypeObject EVPtype = { + \ + static PyObject * + EVPnew(const EVP_MD *digest, +- const unsigned char *cp, Py_ssize_t len) ++ const unsigned char *cp, Py_ssize_t len, int usedforsecurity) + { + int result = 0; + EVPobject *self; +@@ -530,6 +530,12 @@ EVPnew(const EVP_MD *digest, + if ((self = newEVPobject()) == NULL) + return NULL; + ++ if (!usedforsecurity) { ++#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW ++ EVP_MD_CTX_set_flags(self->ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); ++#endif ++ } ++ + if (!EVP_DigestInit_ex(self->ctx, digest, NULL)) { + _setException(PyExc_ValueError); + Py_DECREF(self); +@@ -561,6 +567,8 @@ _hashlib.new as EVP_new + + name as name_obj: object + string as data_obj: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new hash object using the named algorithm. + +@@ -571,8 +579,9 @@ The MD5 and SHA1 algorithms are always supported. + [clinic start generated code]*/ + + static PyObject * +-EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj) +-/*[clinic end generated code: output=9e7cf664e04b0226 input=7eb79bf30058bd02]*/ ++EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=ddd5053f92dffe90 input=c24554d0337be1b0]*/ + { + Py_buffer view = { 0 }; + PyObject *ret_obj; +@@ -589,7 +598,9 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj) + + digest = py_digest_by_name(name); + +- ret_obj = EVPnew(digest, (unsigned char*)view.buf, view.len); ++ ret_obj = EVPnew(digest, ++ (unsigned char*)view.buf, view.len, ++ usedforsecurity); + + if (data_obj) + PyBuffer_Release(&view); +@@ -597,7 +608,8 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj) + } + + static PyObject* +-EVP_fast_new(PyObject *module, PyObject *data_obj, const EVP_MD *digest) ++EVP_fast_new(PyObject *module, PyObject *data_obj, const EVP_MD *digest, ++ int usedforsecurity) + { + Py_buffer view = { 0 }; + PyObject *ret_obj; +@@ -605,7 +617,8 @@ EVP_fast_new(PyObject *module, PyObject *data_obj, const EVP_MD *digest) + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); + +- ret_obj = EVPnew(digest, (unsigned char*)view.buf, view.len); ++ ret_obj = EVPnew(digest, (unsigned char*)view.buf, view.len, ++ usedforsecurity); + + if (data_obj) + PyBuffer_Release(&view); +@@ -617,16 +630,19 @@ EVP_fast_new(PyObject *module, PyObject *data_obj, const EVP_MD *digest) + _hashlib.openssl_md5 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a md5 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=6caae75b73e22c3f input=52010d3869e1b1a7]*/ ++_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=87b0186440a44f8c input=990e36d5e689b16e]*/ + { +- return EVP_fast_new(module, data_obj, EVP_md5()); ++ return EVP_fast_new(module, data_obj, EVP_md5(), usedforsecurity); + } + + +@@ -634,16 +650,19 @@ _hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj) + _hashlib.openssl_sha1 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha1 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=07606d8f75153e61 input=16807d30e4aa8ae9]*/ ++_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=6813024cf690670d input=948f2f4b6deabc10]*/ + { +- return EVP_fast_new(module, data_obj, EVP_sha1()); ++ return EVP_fast_new(module, data_obj, EVP_sha1(), usedforsecurity); + } + + +@@ -651,16 +670,19 @@ _hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj) + _hashlib.openssl_sha224 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha224 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=55e848761bcef0c9 input=5dbc2f1d84eb459b]*/ ++_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=a2dfe7cc4eb14ebb input=f9272821fadca505]*/ + { +- return EVP_fast_new(module, data_obj, EVP_sha224()); ++ return EVP_fast_new(module, data_obj, EVP_sha224(), usedforsecurity); + } + + +@@ -668,16 +690,19 @@ _hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj) + _hashlib.openssl_sha256 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha256 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=05851d7cce34ac65 input=a68a5d21cda5a80f]*/ ++_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=1f874a34870f0a68 input=549fad9d2930d4c5]*/ + { +- return EVP_fast_new(module, data_obj, EVP_sha256()); ++ return EVP_fast_new(module, data_obj, EVP_sha256(), usedforsecurity); + } + + +@@ -685,16 +710,19 @@ _hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj) + _hashlib.openssl_sha384 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha384 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=5101a4704a932c2f input=6bdfa006622b64ea]*/ ++_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=58529eff9ca457b2 input=48601a6e3bf14ad7]*/ + { +- return EVP_fast_new(module, data_obj, EVP_sha384()); ++ return EVP_fast_new(module, data_obj, EVP_sha384(), usedforsecurity); + } + + +@@ -702,152 +730,179 @@ _hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj) + _hashlib.openssl_sha512 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha512 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=20c8e63ee560a5cb input=ece50182ad4b76a6]*/ ++_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=2c744c9e4a40d5f6 input=c5c46a2a817aa98f]*/ + { +- return EVP_fast_new(module, data_obj, EVP_sha512()); ++ return EVP_fast_new(module, data_obj, EVP_sha512(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_blake2b + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a blake2b hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=0d65acd1d9bb5e3f input=d9e6f84fa97e630d]*/ ++_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=7a838b1643cde13e input=37247f187d9c4f4a]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_blake2b512()); ++ return EVP_fast_new(module, data_obj, EVP_blake2b512(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_blake2s + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a blake2s hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=0f1330138041ec22 input=f1aec29465fc49c6]*/ ++_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=4eda6b40757471da input=36e42912f87ff123]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_blake2s256()); ++ return EVP_fast_new(module, data_obj, EVP_blake2s256(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_sha3_224 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha3_224 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=e3817bed6ecafc20 input=adc74bf14410af70]*/ ++_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=144641c1d144b974 input=450128ca92633287]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_sha3_224()); ++ return EVP_fast_new(module, data_obj, EVP_sha3_224(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_sha3_256 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha3_256 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=9c15fac1ce09cd62 input=2922c3e78ab8bd2d]*/ ++_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=c61f1ab772d06668 input=dda801b8285bc25f]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_sha3_256()); ++ return EVP_fast_new(module, data_obj, EVP_sha3_256(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_sha3_384 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha3_384 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=0923a782b9b81a40 input=742b499c372c8316]*/ ++_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=f68e4846858cf0ee input=3e2c46d271c64ec8]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_sha3_384()); ++ return EVP_fast_new(module, data_obj, EVP_sha3_384(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_sha3_512 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a sha3-512 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=34bbe194704dbce4 input=46383f88e59a0385]*/ ++_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=2eede478c159354a input=64e2cc0c094d56f4]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_sha3_512()); ++ return EVP_fast_new(module, data_obj, EVP_sha3_512(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_shake_128 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a shake_128 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=a6ea5917ce65ef10 input=f256751eb810fdaa]*/ ++_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=bc49cdd8ada1fa97 input=395c17aac1eb4d2e]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_shake128()); ++ return EVP_fast_new(module, data_obj, EVP_shake128(), usedforsecurity); + } + + /*[clinic input] + _hashlib.openssl_shake_256 + + string as data_obj: object(py_default="b''") = NULL ++ * ++ usedforsecurity: bool = True + + Returns a shake_256 hash object; optionally initialized with a string + + [clinic start generated code]*/ + + static PyObject * +-_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj) +-/*[clinic end generated code: output=c91aaa96b000e186 input=d1331313db34116c]*/ ++_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity) ++/*[clinic end generated code: output=358d213be8852df7 input=4fcf0b80fb663690]*/ + + { +- return EVP_fast_new(module, data_obj, EVP_shake256()); ++ return EVP_fast_new(module, data_obj, EVP_shake256(), usedforsecurity); + } + + +diff --git a/Modules/_sha3/clinic/sha3module.c.h b/Modules/_sha3/clinic/sha3module.c.h +index 554442d..1c79c26 100644 +--- a/Modules/_sha3/clinic/sha3module.c.h ++++ b/Modules/_sha3/clinic/sha3module.c.h +@@ -2,6 +2,52 @@ + preserve + [clinic start generated code]*/ + ++PyDoc_STRVAR(py_sha3_new__doc__, ++"sha3_224(data=b\'\', /, *, usedforsecurity=True)\n" ++"--\n" ++"\n" ++"Return a new BLAKE2b hash object."); ++ ++static PyObject * ++py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity); ++ ++static PyObject * ++py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"", "usedforsecurity", NULL}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "sha3_224", 0}; ++ PyObject *argsbuf[2]; ++ PyObject * const *fastargs; ++ Py_ssize_t nargs = PyTuple_GET_SIZE(args); ++ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; ++ PyObject *data = NULL; ++ int usedforsecurity = 1; ++ ++ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 1, 0, argsbuf); ++ if (!fastargs) { ++ goto exit; ++ } ++ if (nargs < 1) { ++ goto skip_optional_posonly; ++ } ++ noptargs--; ++ data = fastargs[0]; ++skip_optional_posonly: ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(fastargs[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = py_sha3_new_impl(type, data, usedforsecurity); ++ ++exit: ++ return return_value; ++} ++ + PyDoc_STRVAR(_sha3_sha3_224_copy__doc__, + "copy($self, /)\n" + "--\n" +@@ -118,4 +164,4 @@ _sha3_shake_128_hexdigest(SHA3object *self, PyObject *arg) + exit: + return return_value; + } +-/*[clinic end generated code: output=5b3e99b9a96471e8 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=c8a97b34e80def62 input=a9049054013a1b77]*/ +diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c +index 3079e1e..fc8b1b2 100644 +--- a/Modules/_sha3/sha3module.c ++++ b/Modules/_sha3/sha3module.c +@@ -171,22 +171,25 @@ newSHA3object(PyTypeObject *type) + return newobj; + } + ++/*[clinic input] ++@classmethod ++_sha3.sha3_224.__new__ as py_sha3_new ++ data: object(c_default="NULL") = b'' ++ / ++ * ++ usedforsecurity: bool = True ++ ++Return a new BLAKE2b hash object. ++[clinic start generated code]*/ + + static PyObject * +-py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) ++py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) ++/*[clinic end generated code: output=90409addc5d5e8b0 input=bcfcdf2e4368347a]*/ + { + FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_sha3"); + SHA3object *self = NULL; + Py_buffer buf = {NULL, NULL}; + HashReturn res; +- PyObject *data = NULL; +- +- if (!_PyArg_NoKeywords(_PyType_Name(type), kwargs)) { +- return NULL; +- } +- if (!PyArg_UnpackTuple(args, _PyType_Name(type), 0, 1, &data)) { +- return NULL; +- } + + self = newSHA3object(type); + if (self == NULL) { +@@ -532,22 +535,22 @@ static PyGetSetDef SHA3_getseters[] = { + } + + PyDoc_STRVAR(sha3_224__doc__, +-"sha3_224([data]) -> SHA3 object\n\ ++"sha3_224([data], *, usedforsecurity=True) -> SHA3 object\n\ + \n\ + Return a new SHA3 hash object with a hashbit length of 28 bytes."); + + PyDoc_STRVAR(sha3_256__doc__, +-"sha3_256([data]) -> SHA3 object\n\ ++"sha3_256([data], *, usedforsecurity=True) -> SHA3 object\n\ + \n\ + Return a new SHA3 hash object with a hashbit length of 32 bytes."); + + PyDoc_STRVAR(sha3_384__doc__, +-"sha3_384([data]) -> SHA3 object\n\ ++"sha3_384([data], *, usedforsecurity=True) -> SHA3 object\n\ + \n\ + Return a new SHA3 hash object with a hashbit length of 48 bytes."); + + PyDoc_STRVAR(sha3_512__doc__, +-"sha3_512([data]) -> SHA3 object\n\ ++"sha3_512([data], *, usedforsecurity=True) -> SHA3 object\n\ + \n\ + Return a new SHA3 hash object with a hashbit length of 64 bytes."); + +@@ -558,22 +561,22 @@ SHA3_TYPE(SHA3_512type, "_sha3.sha3_512", sha3_512__doc__, SHA3_methods); + + #ifdef PY_WITH_KECCAK + PyDoc_STRVAR(keccak_224__doc__, +-"keccak_224([data]) -> Keccak object\n\ ++"keccak_224([data], *, usedforsecurity=True) -> Keccak object\n\ + \n\ + Return a new Keccak hash object with a hashbit length of 28 bytes."); + + PyDoc_STRVAR(keccak_256__doc__, +-"keccak_256([data]) -> Keccak object\n\ ++"keccak_256([data], *, usedforsecurity=True) -> Keccak object\n\ + \n\ + Return a new Keccak hash object with a hashbit length of 32 bytes."); + + PyDoc_STRVAR(keccak_384__doc__, +-"keccak_384([data]) -> Keccak object\n\ ++"keccak_384([data], *, usedforsecurity=True) -> Keccak object\n\ + \n\ + Return a new Keccak hash object with a hashbit length of 48 bytes."); + + PyDoc_STRVAR(keccak_512__doc__, +-"keccak_512([data]) -> Keccak object\n\ ++"keccak_512([data], *, usedforsecurity=True) -> Keccak object\n\ + \n\ + Return a new Keccak hash object with a hashbit length of 64 bytes."); + +@@ -675,12 +678,12 @@ static PyMethodDef SHAKE_methods[] = { + }; + + PyDoc_STRVAR(shake_128__doc__, +-"shake_128([data]) -> SHAKE object\n\ ++"shake_128([data], *, usedforsecurity=True) -> SHAKE object\n\ + \n\ + Return a new SHAKE hash object."); + + PyDoc_STRVAR(shake_256__doc__, +-"shake_256([data]) -> SHAKE object\n\ ++"shake_256([data], *, usedforsecurity=True) -> SHAKE object\n\ + \n\ + Return a new SHAKE hash object."); + +diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h +index e96a752..9678847 100644 +--- a/Modules/clinic/_hashopenssl.c.h ++++ b/Modules/clinic/_hashopenssl.c.h +@@ -66,7 +66,7 @@ PyDoc_STRVAR(EVP_update__doc__, + {"update", (PyCFunction)EVP_update, METH_O, EVP_update__doc__}, + + PyDoc_STRVAR(EVP_new__doc__, +-"new($module, /, name, string=b\'\')\n" ++"new($module, /, name, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new hash object using the named algorithm.\n" +@@ -80,18 +80,20 @@ PyDoc_STRVAR(EVP_new__doc__, + {"new", (PyCFunction)(void(*)(void))EVP_new, METH_FASTCALL|METH_KEYWORDS, EVP_new__doc__}, + + static PyObject * +-EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj); ++EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + EVP_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"name", "string", NULL}; ++ static const char * const _keywords[] = {"name", "string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "new", 0}; +- PyObject *argsbuf[2]; ++ PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *name_obj; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { +@@ -101,16 +103,29 @@ EVP_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[1]; ++ if (args[1]) { ++ data_obj = args[1]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = EVP_new_impl(module, name_obj, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[2]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = EVP_new_impl(module, name_obj, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_md5__doc__, +-"openssl_md5($module, /, string=b\'\')\n" ++"openssl_md5($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a md5 hash object; optionally initialized with a string"); +@@ -119,17 +134,19 @@ PyDoc_STRVAR(_hashlib_openssl_md5__doc__, + {"openssl_md5", (PyCFunction)(void(*)(void))_hashlib_openssl_md5, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_md5__doc__}, + + static PyObject * +-_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_md5", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -138,16 +155,29 @@ _hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_md5_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_md5_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha1__doc__, +-"openssl_sha1($module, /, string=b\'\')\n" ++"openssl_sha1($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha1 hash object; optionally initialized with a string"); +@@ -156,17 +186,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha1__doc__, + {"openssl_sha1", (PyCFunction)(void(*)(void))_hashlib_openssl_sha1, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha1__doc__}, + + static PyObject * +-_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha1", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -175,16 +207,29 @@ _hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha1_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha1_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha224__doc__, +-"openssl_sha224($module, /, string=b\'\')\n" ++"openssl_sha224($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha224 hash object; optionally initialized with a string"); +@@ -193,17 +238,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha224__doc__, + {"openssl_sha224", (PyCFunction)(void(*)(void))_hashlib_openssl_sha224, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha224__doc__}, + + static PyObject * +-_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha224", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -212,16 +259,29 @@ _hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t narg + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha224_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha224_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha256__doc__, +-"openssl_sha256($module, /, string=b\'\')\n" ++"openssl_sha256($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha256 hash object; optionally initialized with a string"); +@@ -230,17 +290,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha256__doc__, + {"openssl_sha256", (PyCFunction)(void(*)(void))_hashlib_openssl_sha256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha256__doc__}, + + static PyObject * +-_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha256", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -249,16 +311,29 @@ _hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t narg + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha256_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha256_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha384__doc__, +-"openssl_sha384($module, /, string=b\'\')\n" ++"openssl_sha384($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha384 hash object; optionally initialized with a string"); +@@ -267,17 +342,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha384__doc__, + {"openssl_sha384", (PyCFunction)(void(*)(void))_hashlib_openssl_sha384, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha384__doc__}, + + static PyObject * +-_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha384", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -286,16 +363,29 @@ _hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t narg + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha384_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha384_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha512__doc__, +-"openssl_sha512($module, /, string=b\'\')\n" ++"openssl_sha512($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha512 hash object; optionally initialized with a string"); +@@ -304,17 +394,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha512__doc__, + {"openssl_sha512", (PyCFunction)(void(*)(void))_hashlib_openssl_sha512, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha512__doc__}, + + static PyObject * +-_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha512", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -323,16 +415,29 @@ _hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t narg + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha512_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha512_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_blake2b__doc__, +-"openssl_blake2b($module, /, string=b\'\')\n" ++"openssl_blake2b($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a blake2b hash object; optionally initialized with a string"); +@@ -341,17 +446,19 @@ PyDoc_STRVAR(_hashlib_openssl_blake2b__doc__, + {"openssl_blake2b", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2b, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2b__doc__}, + + static PyObject * +-_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_blake2b(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2b", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -360,16 +467,29 @@ _hashlib_openssl_blake2b(PyObject *module, PyObject *const *args, Py_ssize_t nar + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_blake2b_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_blake2b_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_blake2s__doc__, +-"openssl_blake2s($module, /, string=b\'\')\n" ++"openssl_blake2s($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a blake2s hash object; optionally initialized with a string"); +@@ -378,17 +498,19 @@ PyDoc_STRVAR(_hashlib_openssl_blake2s__doc__, + {"openssl_blake2s", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2s, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2s__doc__}, + + static PyObject * +-_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_blake2s(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2s", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -397,16 +519,29 @@ _hashlib_openssl_blake2s(PyObject *module, PyObject *const *args, Py_ssize_t nar + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_blake2s_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_blake2s_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__, +-"openssl_sha3_224($module, /, string=b\'\')\n" ++"openssl_sha3_224($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha3_224 hash object; optionally initialized with a string"); +@@ -415,17 +550,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__, + {"openssl_sha3_224", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_224, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_224__doc__}, + + static PyObject * +-_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_224", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -434,16 +571,29 @@ _hashlib_openssl_sha3_224(PyObject *module, PyObject *const *args, Py_ssize_t na + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha3_224_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha3_224_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha3_256__doc__, +-"openssl_sha3_256($module, /, string=b\'\')\n" ++"openssl_sha3_256($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha3_256 hash object; optionally initialized with a string"); +@@ -452,17 +602,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_256__doc__, + {"openssl_sha3_256", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_256__doc__}, + + static PyObject * +-_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_256", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -471,16 +623,29 @@ _hashlib_openssl_sha3_256(PyObject *module, PyObject *const *args, Py_ssize_t na + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha3_256_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha3_256_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha3_384__doc__, +-"openssl_sha3_384($module, /, string=b\'\')\n" ++"openssl_sha3_384($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha3_384 hash object; optionally initialized with a string"); +@@ -489,17 +654,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_384__doc__, + {"openssl_sha3_384", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_384, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_384__doc__}, + + static PyObject * +-_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_384", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -508,16 +675,29 @@ _hashlib_openssl_sha3_384(PyObject *module, PyObject *const *args, Py_ssize_t na + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha3_384_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha3_384_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_sha3_512__doc__, +-"openssl_sha3_512($module, /, string=b\'\')\n" ++"openssl_sha3_512($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a sha3-512 hash object; optionally initialized with a string"); +@@ -526,17 +706,19 @@ PyDoc_STRVAR(_hashlib_openssl_sha3_512__doc__, + {"openssl_sha3_512", (PyCFunction)(void(*)(void))_hashlib_openssl_sha3_512, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha3_512__doc__}, + + static PyObject * +-_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha3_512", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -545,16 +727,29 @@ _hashlib_openssl_sha3_512(PyObject *module, PyObject *const *args, Py_ssize_t na + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_sha3_512_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_sha3_512_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_shake_128__doc__, +-"openssl_shake_128($module, /, string=b\'\')\n" ++"openssl_shake_128($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a shake_128 hash object; optionally initialized with a string"); +@@ -563,17 +758,19 @@ PyDoc_STRVAR(_hashlib_openssl_shake_128__doc__, + {"openssl_shake_128", (PyCFunction)(void(*)(void))_hashlib_openssl_shake_128, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_128__doc__}, + + static PyObject * +-_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_shake_128", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -582,16 +779,29 @@ _hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t n + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_shake_128_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_shake_128_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_hashlib_openssl_shake_256__doc__, +-"openssl_shake_256($module, /, string=b\'\')\n" ++"openssl_shake_256($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Returns a shake_256 hash object; optionally initialized with a string"); +@@ -600,17 +810,19 @@ PyDoc_STRVAR(_hashlib_openssl_shake_256__doc__, + {"openssl_shake_256", (PyCFunction)(void(*)(void))_hashlib_openssl_shake_256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_256__doc__}, + + static PyObject * +-_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj); ++_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj, ++ int usedforsecurity); + + static PyObject * + _hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_shake_256", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *data_obj = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -619,9 +831,22 @@ _hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t n + if (!noptargs) { + goto skip_optional_pos; + } +- data_obj = args[0]; ++ if (args[0]) { ++ data_obj = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _hashlib_openssl_shake_256_impl(module, data_obj); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _hashlib_openssl_shake_256_impl(module, data_obj, usedforsecurity); + + exit: + return return_value; +@@ -942,4 +1167,4 @@ _hashlib_get_fips_mode(PyObject *module, PyObject *Py_UNUSED(ignored)) + #ifndef _HASHLIB_SCRYPT_METHODDEF + #define _HASHLIB_SCRYPT_METHODDEF + #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ +-/*[clinic end generated code: output=be8e21a10dff71e7 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=3db4f18f12892fa4 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/md5module.c.h b/Modules/clinic/md5module.c.h +index 12484cc..c109f9e 100644 +--- a/Modules/clinic/md5module.c.h ++++ b/Modules/clinic/md5module.c.h +@@ -66,7 +66,7 @@ PyDoc_STRVAR(MD5Type_update__doc__, + {"update", (PyCFunction)MD5Type_update, METH_O, MD5Type_update__doc__}, + + PyDoc_STRVAR(_md5_md5__doc__, +-"md5($module, /, string=b\'\')\n" ++"md5($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new MD5 hash object; optionally initialized with a string."); +@@ -75,17 +75,18 @@ PyDoc_STRVAR(_md5_md5__doc__, + {"md5", (PyCFunction)(void(*)(void))_md5_md5, METH_FASTCALL|METH_KEYWORDS, _md5_md5__doc__}, + + static PyObject * +-_md5_md5_impl(PyObject *module, PyObject *string); ++_md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity); + + static PyObject * + _md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "md5", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *string = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -94,11 +95,24 @@ _md5_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kw + if (!noptargs) { + goto skip_optional_pos; + } +- string = args[0]; ++ if (args[0]) { ++ string = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _md5_md5_impl(module, string); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _md5_md5_impl(module, string, usedforsecurity); + + exit: + return return_value; + } +-/*[clinic end generated code: output=53133f08cf9095fc input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=dbe3abc60086f3ef input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/sha1module.c.h b/Modules/clinic/sha1module.c.h +index 001c6af..fc37b1a 100644 +--- a/Modules/clinic/sha1module.c.h ++++ b/Modules/clinic/sha1module.c.h +@@ -66,7 +66,7 @@ PyDoc_STRVAR(SHA1Type_update__doc__, + {"update", (PyCFunction)SHA1Type_update, METH_O, SHA1Type_update__doc__}, + + PyDoc_STRVAR(_sha1_sha1__doc__, +-"sha1($module, /, string=b\'\')\n" ++"sha1($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new SHA1 hash object; optionally initialized with a string."); +@@ -75,17 +75,18 @@ PyDoc_STRVAR(_sha1_sha1__doc__, + {"sha1", (PyCFunction)(void(*)(void))_sha1_sha1, METH_FASTCALL|METH_KEYWORDS, _sha1_sha1__doc__}, + + static PyObject * +-_sha1_sha1_impl(PyObject *module, PyObject *string); ++_sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity); + + static PyObject * + _sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "sha1", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *string = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -94,11 +95,24 @@ _sha1_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject * + if (!noptargs) { + goto skip_optional_pos; + } +- string = args[0]; ++ if (args[0]) { ++ string = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _sha1_sha1_impl(module, string); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _sha1_sha1_impl(module, string, usedforsecurity); + + exit: + return return_value; + } +-/*[clinic end generated code: output=1ae7e73ec84a27d5 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=3ddd637ae17e14b3 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/sha256module.c.h b/Modules/clinic/sha256module.c.h +index 658abb1..2a788ea 100644 +--- a/Modules/clinic/sha256module.c.h ++++ b/Modules/clinic/sha256module.c.h +@@ -66,7 +66,7 @@ PyDoc_STRVAR(SHA256Type_update__doc__, + {"update", (PyCFunction)SHA256Type_update, METH_O, SHA256Type_update__doc__}, + + PyDoc_STRVAR(_sha256_sha256__doc__, +-"sha256($module, /, string=b\'\')\n" ++"sha256($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new SHA-256 hash object; optionally initialized with a string."); +@@ -75,17 +75,18 @@ PyDoc_STRVAR(_sha256_sha256__doc__, + {"sha256", (PyCFunction)(void(*)(void))_sha256_sha256, METH_FASTCALL|METH_KEYWORDS, _sha256_sha256__doc__}, + + static PyObject * +-_sha256_sha256_impl(PyObject *module, PyObject *string); ++_sha256_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity); + + static PyObject * + _sha256_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "sha256", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *string = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -94,16 +95,29 @@ _sha256_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje + if (!noptargs) { + goto skip_optional_pos; + } +- string = args[0]; ++ if (args[0]) { ++ string = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _sha256_sha256_impl(module, string); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _sha256_sha256_impl(module, string, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_sha256_sha224__doc__, +-"sha224($module, /, string=b\'\')\n" ++"sha224($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new SHA-224 hash object; optionally initialized with a string."); +@@ -112,17 +126,18 @@ PyDoc_STRVAR(_sha256_sha224__doc__, + {"sha224", (PyCFunction)(void(*)(void))_sha256_sha224, METH_FASTCALL|METH_KEYWORDS, _sha256_sha224__doc__}, + + static PyObject * +-_sha256_sha224_impl(PyObject *module, PyObject *string); ++_sha256_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity); + + static PyObject * + _sha256_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "sha224", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *string = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -131,11 +146,24 @@ _sha256_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje + if (!noptargs) { + goto skip_optional_pos; + } +- string = args[0]; ++ if (args[0]) { ++ string = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _sha256_sha224_impl(module, string); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _sha256_sha224_impl(module, string, usedforsecurity); + + exit: + return return_value; + } +-/*[clinic end generated code: output=c54d0956ec88409d input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=c8cca8adbe72ec9a input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/sha512module.c.h b/Modules/clinic/sha512module.c.h +index 459a934..b8185b6 100644 +--- a/Modules/clinic/sha512module.c.h ++++ b/Modules/clinic/sha512module.c.h +@@ -66,7 +66,7 @@ PyDoc_STRVAR(SHA512Type_update__doc__, + {"update", (PyCFunction)SHA512Type_update, METH_O, SHA512Type_update__doc__}, + + PyDoc_STRVAR(_sha512_sha512__doc__, +-"sha512($module, /, string=b\'\')\n" ++"sha512($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new SHA-512 hash object; optionally initialized with a string."); +@@ -75,17 +75,18 @@ PyDoc_STRVAR(_sha512_sha512__doc__, + {"sha512", (PyCFunction)(void(*)(void))_sha512_sha512, METH_FASTCALL|METH_KEYWORDS, _sha512_sha512__doc__}, + + static PyObject * +-_sha512_sha512_impl(PyObject *module, PyObject *string); ++_sha512_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity); + + static PyObject * + _sha512_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "sha512", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *string = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -94,16 +95,29 @@ _sha512_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje + if (!noptargs) { + goto skip_optional_pos; + } +- string = args[0]; ++ if (args[0]) { ++ string = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _sha512_sha512_impl(module, string); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _sha512_sha512_impl(module, string, usedforsecurity); + + exit: + return return_value; + } + + PyDoc_STRVAR(_sha512_sha384__doc__, +-"sha384($module, /, string=b\'\')\n" ++"sha384($module, /, string=b\'\', *, usedforsecurity=True)\n" + "--\n" + "\n" + "Return a new SHA-384 hash object; optionally initialized with a string."); +@@ -112,17 +126,18 @@ PyDoc_STRVAR(_sha512_sha384__doc__, + {"sha384", (PyCFunction)(void(*)(void))_sha512_sha384, METH_FASTCALL|METH_KEYWORDS, _sha512_sha384__doc__}, + + static PyObject * +-_sha512_sha384_impl(PyObject *module, PyObject *string); ++_sha512_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity); + + static PyObject * + _sha512_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"string", NULL}; ++ static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "sha384", 0}; +- PyObject *argsbuf[1]; ++ PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *string = NULL; ++ int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { +@@ -131,11 +146,24 @@ _sha512_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje + if (!noptargs) { + goto skip_optional_pos; + } +- string = args[0]; ++ if (args[0]) { ++ string = args[0]; ++ if (!--noptargs) { ++ goto skip_optional_pos; ++ } ++ } + skip_optional_pos: +- return_value = _sha512_sha384_impl(module, string); ++ if (!noptargs) { ++ goto skip_optional_kwonly; ++ } ++ usedforsecurity = PyObject_IsTrue(args[1]); ++ if (usedforsecurity < 0) { ++ goto exit; ++ } ++skip_optional_kwonly: ++ return_value = _sha512_sha384_impl(module, string, usedforsecurity); + + exit: + return return_value; + } +-/*[clinic end generated code: output=580df4b667084a7e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=bbfa72d8703c82b5 input=a9049054013a1b77]*/ +diff --git a/Modules/md5module.c b/Modules/md5module.c +index b9a351a..f2c2d32 100644 +--- a/Modules/md5module.c ++++ b/Modules/md5module.c +@@ -503,13 +503,15 @@ static PyTypeObject MD5type = { + _md5.md5 + + string: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new MD5 hash object; optionally initialized with a string. + [clinic start generated code]*/ + + static PyObject * +-_md5_md5_impl(PyObject *module, PyObject *string) +-/*[clinic end generated code: output=2cfd0f8c091b97e6 input=d12ef8f72d684f7b]*/ ++_md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity) ++/*[clinic end generated code: output=587071f76254a4ac input=7a144a1905636985]*/ + { + MD5object *new; + Py_buffer buf; +diff --git a/Modules/sha1module.c b/Modules/sha1module.c +index ce2ad26..4d191c3 100644 +--- a/Modules/sha1module.c ++++ b/Modules/sha1module.c +@@ -480,13 +480,15 @@ static PyTypeObject SHA1type = { + _sha1.sha1 + + string: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new SHA1 hash object; optionally initialized with a string. + [clinic start generated code]*/ + + static PyObject * +-_sha1_sha1_impl(PyObject *module, PyObject *string) +-/*[clinic end generated code: output=e5982830d1dece51 input=27ea54281d995ec2]*/ ++_sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity) ++/*[clinic end generated code: output=6f8b3af05126e18e input=bd54b68e2bf36a8a]*/ + { + SHA1object *new; + Py_buffer buf; +diff --git a/Modules/sha256module.c b/Modules/sha256module.c +index b8d6c4c..245f4c0 100644 +--- a/Modules/sha256module.c ++++ b/Modules/sha256module.c +@@ -601,13 +601,15 @@ static PyTypeObject SHA256type = { + _sha256.sha256 + + string: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new SHA-256 hash object; optionally initialized with a string. + [clinic start generated code]*/ + + static PyObject * +-_sha256_sha256_impl(PyObject *module, PyObject *string) +-/*[clinic end generated code: output=fa644436dcea5c31 input=09cce3fb855056b2]*/ ++_sha256_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity) ++/*[clinic end generated code: output=a1de327e8e1185cf input=9be86301aeb14ea5]*/ + { + SHAobject *new; + Py_buffer buf; +@@ -641,13 +643,15 @@ _sha256_sha256_impl(PyObject *module, PyObject *string) + _sha256.sha224 + + string: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new SHA-224 hash object; optionally initialized with a string. + [clinic start generated code]*/ + + static PyObject * +-_sha256_sha224_impl(PyObject *module, PyObject *string) +-/*[clinic end generated code: output=21e3ba22c3404f93 input=27a04ba24c353a73]*/ ++_sha256_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity) ++/*[clinic end generated code: output=08be6b36569bc69c input=9fcfb46e460860ac]*/ + { + SHAobject *new; + Py_buffer buf; +diff --git a/Modules/sha512module.c b/Modules/sha512module.c +index 98b9791..df4f9d2 100644 +--- a/Modules/sha512module.c ++++ b/Modules/sha512module.c +@@ -666,13 +666,15 @@ static PyTypeObject SHA512type = { + _sha512.sha512 + + string: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new SHA-512 hash object; optionally initialized with a string. + [clinic start generated code]*/ + + static PyObject * +-_sha512_sha512_impl(PyObject *module, PyObject *string) +-/*[clinic end generated code: output=8b865a2df73bd387 input=e69bad9ae9b6a308]*/ ++_sha512_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity) ++/*[clinic end generated code: output=a8d9e5f9e6a0831c input=23b4daebc2ebb9c9]*/ + { + SHAobject *new; + Py_buffer buf; +@@ -706,13 +708,15 @@ _sha512_sha512_impl(PyObject *module, PyObject *string) + _sha512.sha384 + + string: object(c_default="NULL") = b'' ++ * ++ usedforsecurity: bool = True + + Return a new SHA-384 hash object; optionally initialized with a string. + [clinic start generated code]*/ + + static PyObject * +-_sha512_sha384_impl(PyObject *module, PyObject *string) +-/*[clinic end generated code: output=ae4b2e26decf81e8 input=c9327788d4ea4545]*/ ++_sha512_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity) ++/*[clinic end generated code: output=da7d594a08027ac3 input=59ef72f039a6b431]*/ + { + SHAobject *new; + Py_buffer buf; +-- +2.25.4 + + +From 372b2b63bf8ffb3201dc3c8d2488f6a5a55c5b21 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 26 Aug 2019 19:09:39 +0200 +Subject: [PATCH 24/36] Test the usedforsecurity flag + +--- + Lib/test/test_hashlib.py | 88 ++++++++++++++++++++++++---------------- + 1 file changed, 54 insertions(+), 34 deletions(-) + +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 08bb91f..1368e91 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -21,6 +21,7 @@ from test import support + from test.support import _4G, bigmemtest, import_fresh_module + from test.support import requires_hashdigest + from http.client import HTTPException ++from functools import partial + + # Were we compiled --with-pydebug or with #define Py_DEBUG? + COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') +@@ -29,8 +30,10 @@ c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) + py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) + + if hashlib.get_fips_mode(): +- FIPS_DISABLED = {'md5', 'MD5', 'blake2b', 'blake2s'} ++ FIPS_UNAVAILABLE = {'blake2b', 'blake2s'} ++ FIPS_DISABLED = {'md5', 'MD5', *FIPS_UNAVAILABLE} + else: ++ FIPS_UNAVAILABLE = set() + FIPS_DISABLED = set() + + try: +@@ -80,6 +83,15 @@ def read_vectors(hash_name): + yield parts + + ++def _is_openssl_constructor(constructor): ++ if getattr(constructor, '__name__', '').startswith('openssl_'): ++ return True ++ if isinstance(constructor, partial): ++ if constructor.func.__name__.startswith('openssl_'): ++ return True ++ return False ++ ++ + class HashLibTestCase(unittest.TestCase): + supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', + 'sha224', 'SHA224', 'sha256', 'SHA256', +@@ -95,8 +107,6 @@ class HashLibTestCase(unittest.TestCase): + + if hashlib.get_fips_mode(): + shakes = set() +- supported_hash_names = tuple( +- n for n in supported_hash_names if n not in FIPS_DISABLED) + + def _conditional_import_module(self, module_name): + """Import a module and return a reference to it or None on failure.""" +@@ -122,7 +132,8 @@ class HashLibTestCase(unittest.TestCase): + def __init__(self, *args, **kwargs): + algorithms = set() + for algorithm in self.supported_hash_names: +- algorithms.add(algorithm.lower()) ++ if algorithm not in FIPS_UNAVAILABLE: ++ algorithms.add(algorithm.lower()) + + _blake2 = self._conditional_import_module('_blake2') + if _blake2: +@@ -132,15 +143,21 @@ class HashLibTestCase(unittest.TestCase): + for algorithm in algorithms: + self.constructors_to_test[algorithm] = set() + ++ def _add_constructor(algorithm, constructor): ++ constructors.add(partial(constructor, usedforsecurity=False)) ++ if algorithm not in FIPS_DISABLED: ++ constructors.add(constructor) ++ constructors.add(partial(constructor, usedforsecurity=True)) ++ + # For each algorithm, test the direct constructor and the use + # of hashlib.new given the algorithm name. + for algorithm, constructors in self.constructors_to_test.items(): +- constructors.add(getattr(hashlib, algorithm)) ++ _add_constructor(algorithm, getattr(hashlib, algorithm)) + def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs): + if data is None: + return hashlib.new(_alg, **kwargs) + return hashlib.new(_alg, data, **kwargs) +- constructors.add(_test_algorithm_via_hashlib_new) ++ _add_constructor(algorithm, _test_algorithm_via_hashlib_new) + + _hashlib = self._conditional_import_module('_hashlib') + self._hashlib = _hashlib +@@ -152,13 +169,7 @@ class HashLibTestCase(unittest.TestCase): + for algorithm, constructors in self.constructors_to_test.items(): + constructor = getattr(_hashlib, 'openssl_'+algorithm, None) + if constructor: +- try: +- constructor() +- except ValueError: +- # default constructor blocked by crypto policy +- pass +- else: +- constructors.add(constructor) ++ _add_constructor(algorithm, constructor) + + def add_builtin_constructor(name): + constructor = getattr(hashlib, "__get_builtin_constructor")(name) +@@ -218,7 +229,7 @@ class HashLibTestCase(unittest.TestCase): + c.hexdigest() + + def test_algorithms_guaranteed(self): +- self.assertEqual(hashlib.algorithms_guaranteed - FIPS_DISABLED, ++ self.assertEqual(hashlib.algorithms_guaranteed, + set(_algo for _algo in self.supported_hash_names + if _algo.islower())) + +@@ -305,7 +316,9 @@ class HashLibTestCase(unittest.TestCase): + self.assertIn(h.name, self.supported_hash_names) + else: + self.assertNotIn(h.name, self.supported_hash_names) +- self.assertEqual(h.name, hashlib.new(h.name).name) ++ if h.name not in FIPS_DISABLED: ++ self.assertEqual(h.name, hashlib.new(h.name).name) ++ self.assertEqual(h.name, hashlib.new(h.name, usedforsecurity=False).name) + + def test_large_update(self): + aas = b'a' * 128 +@@ -347,13 +360,15 @@ class HashLibTestCase(unittest.TestCase): + self.assertGreaterEqual(len(constructors), 2) + for hash_object_constructor in constructors: + if ( +- kwargs +- and hash_object_constructor.__name__.startswith('openssl_') ++ (kwargs.keys() - {'usedforsecurity'}) ++ and _is_openssl_constructor(hash_object_constructor) + ): ++ # Don't check openssl constructors with ++ # any extra keys (except usedforsecurity) + return + m = hash_object_constructor(data, **kwargs) + if shake: +- if hash_object_constructor.__name__.startswith('openssl_'): ++ if _is_openssl_constructor(hash_object_constructor): + if length > m.digest_size: + # OpenSSL doesn't give long digests + return +@@ -370,7 +385,7 @@ class HashLibTestCase(unittest.TestCase): + % (name, hash_object_constructor, + computed, len(data), hexdigest)) + if shake: +- if hash_object_constructor.__name__.startswith('openssl_'): ++ if _is_openssl_constructor(hash_object_constructor): + computed = m.digest()[:length] + else: + computed = m.digest(length) +@@ -388,8 +403,7 @@ class HashLibTestCase(unittest.TestCase): + self.assertRaises(TypeError, hash_object_constructor, 'spam') + + def test_no_unicode(self): +- if not hashlib.get_fips_mode(): +- self.check_no_unicode('md5') ++ self.check_no_unicode('md5') + self.check_no_unicode('sha1') + self.check_no_unicode('sha224') + self.check_no_unicode('sha256') +@@ -416,10 +430,10 @@ class HashLibTestCase(unittest.TestCase): + for hash_object_constructor in constructors: + m = hash_object_constructor() + self.assertEqual(m.block_size, block_size) +- if not hash_object_constructor.__name__.startswith('openssl_'): ++ if not _is_openssl_constructor(hash_object_constructor): + self.assertEqual(m.digest_size, digest_size) + if digest_length: +- if not hash_object_constructor.__name__.startswith('openssl_'): ++ if not _is_openssl_constructor(hash_object_constructor): + self.assertEqual(len(m.digest(digest_length)), + digest_length) + self.assertEqual(len(m.hexdigest(digest_length)), +@@ -457,7 +471,7 @@ class HashLibTestCase(unittest.TestCase): + # _hashopenssl's variant does not have extra SHA3 attributes + continue + self.assertEqual(capacity + rate, 1600) +- if not hash_object_constructor.__name__.startswith('openssl_'): ++ if not _is_openssl_constructor(hash_object_constructor): + self.assertEqual(m._capacity_bits, capacity) + self.assertEqual(m._rate_bits, rate) + self.assertEqual(m._suffix, suffix) +@@ -476,31 +490,27 @@ class HashLibTestCase(unittest.TestCase): + self.check_blocksize_name('blake2b', 128, 64) + self.check_blocksize_name('blake2s', 64, 32) + +- @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + def test_case_md5_0(self): +- self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e') ++ self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e', usedforsecurity=False) + +- @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + def test_case_md5_1(self): +- self.check('md5', b'abc', '900150983cd24fb0d6963f7d28e17f72') ++ self.check('md5', b'abc', '900150983cd24fb0d6963f7d28e17f72', usedforsecurity=False) + +- @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + def test_case_md5_2(self): + self.check('md5', + b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', +- 'd174ab98d277d9f5a5611c2c9f419d9f') ++ 'd174ab98d277d9f5a5611c2c9f419d9f', ++ usedforsecurity=False) + +- @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G + 5, memuse=1, dry_run=False) + def test_case_md5_huge(self, size): +- self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') ++ self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d', usedforsecurity=False) + +- @unittest.skipIf(hashlib.get_fips_mode(), "md5 unacceptable in FIPS mode") + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) + def test_case_md5_uintmax(self, size): +- self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') ++ self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3', usedforsecurity=False) + + # use the three examples from Federal Information Processing Standards + # Publication 180-1, Secure Hash Standard, 1995 April 17 +@@ -925,6 +935,16 @@ class HashLibTestCase(unittest.TestCase): + + self.assertEqual(expected_hash, hasher.hexdigest()) + ++ @unittest.skipUnless(hashlib.get_fips_mode(), 'Needs FIPS mode.') ++ def test_usedforsecurity_repeat(self): ++ """Make sure usedforsecurity flag isn't copied to other contexts""" ++ for i in range(3): ++ for cons in hashlib.md5, partial(hashlib.new, 'md5'): ++ self.assertRaises(ValueError, cons) ++ self.assertRaises(ValueError, partial(cons, usedforsecurity=True)) ++ self.assertEqual(cons(usedforsecurity=False).hexdigest(), ++ 'd41d8cd98f00b204e9800998ecf8427e') ++ + + class KDFTests(unittest.TestCase): + +-- +2.25.4 + + +From 7e2295b42d705d7d9cc0ccea472ff93bfa268b8c Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 29 Aug 2019 10:25:28 +0200 +Subject: [PATCH 25/36] Skip error checking in _hashlib.get_fips_mode + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1745499 +--- + Modules/_hashopenssl.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index 29c1bd8..d208f5c 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -1249,20 +1249,22 @@ _hashlib_get_fips_mode_impl(PyObject *module) + /*[clinic end generated code: output=ad8a7793310d3f98 input=f42a2135df2a5e11]*/ + + { +- int result = FIPS_mode(); +- if (result == 0) { +- // "If the library was built without support of the FIPS Object Module, +- // then the function will return 0 with an error code of +- // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." +- // But 0 is also a valid result value. +- +- unsigned long errcode = ERR_peek_last_error(); +- if (errcode) { +- _setException(PyExc_ValueError); +- return NULL; +- } +- } +- return PyLong_FromLong(result); ++ // XXX: This function skips error checking. ++ // This is only appropriate for RHEL. ++ ++ // From the OpenSSL docs: ++ // "If the library was built without support of the FIPS Object Module, ++ // then the function will return 0 with an error code of ++ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." ++ // In RHEL: ++ // * we do build with FIPS, so the function always succeeds ++ // * even if it didn't, people seem used to errors being left on the ++ // OpenSSL error stack. ++ ++ // For more info, see: ++ // https://bugzilla.redhat.com/show_bug.cgi?id=1745499 ++ ++ return PyLong_FromLong(FIPS_mode()); + } + + +-- +2.25.4 + + +From dd5f58152edbcac44bcb1cafbee511c44d60ff67 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 10 Oct 2019 13:04:50 +0200 +Subject: [PATCH 26/36] Skip error checking in _Py_hashlib_fips_error + +https://bugzilla.redhat.com/show_bug.cgi?id=1760106 +--- + Include/_hashopenssl.h | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h +index 47ed003..d4cbdef 100644 +--- a/Include/_hashopenssl.h ++++ b/Include/_hashopenssl.h +@@ -42,16 +42,10 @@ static int + _Py_hashlib_fips_error(PyObject *exc, char *name) { + int result = FIPS_mode(); + if (result == 0) { +- // "If the library was built without support of the FIPS Object Module, +- // then the function will return 0 with an error code of +- // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." +- // But 0 is also a valid result value. ++ // XXX: This function skips error checking. ++ // This is only appropriate for RHEL. ++ // See _hashlib.get_fips_mode for details. + +- unsigned long errcode = ERR_peek_last_error(); +- if (errcode) { +- _setException(exc); +- return 1; +- } + return 0; + } + PyErr_Format(exc, "%s is not available in FIPS mode", name); +-- +2.25.4 + + +From c76f0df2561ae64952f347d294aec2866e6b0586 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 19:12:38 +0200 +Subject: [PATCH 27/36] Fixups + +- Adjust error message of the original hmac.HMAC class +- Don't duplicate a test name +--- + Lib/hmac.py | 2 +- + Lib/test/test_hmac.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index 394c810..b2bff7d 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -47,7 +47,7 @@ class HMAC: + """ + if _hashlib.get_fips_mode(): + raise ValueError( +- 'hmac.HMAC is not available in FIPS mode. ' ++ 'This class is not available in FIPS mode. ' + + 'Use hmac.new().' + ) + +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 0a85981..0b481ec 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -439,7 +439,7 @@ class CopyTestCase(unittest.TestCase): + self.assertTrue(id(h1.outer) != id(h2.outer), + "No real copy of the attribute 'outer'.") + +- def test_realcopy(self): ++ def test_realcopy_by_digest(self): + # Testing if the copy method created a real copy. + h1 = hmac.HMAC(b"key", digestmod="sha1") + h2 = h1.copy() +-- +2.25.4 + + +From b6139620fa7aaf401ebd510a0dbca14629096f94 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 26 Aug 2019 19:39:48 +0200 +Subject: [PATCH 28/36] Don't re-export get_fips_mode from hashlib + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1745685 +--- + Lib/distutils/command/upload.py | 3 ++- + Lib/distutils/tests/test_upload.py | 5 +++-- + Lib/hashlib.py | 21 +++++++++++---------- + Lib/hmac.py | 6 +++--- + Lib/test/test_fips.py | 6 +++--- + Lib/test/test_hashlib.py | 16 +++++++++------- + Lib/test/test_hmac.py | 7 ++++--- + Lib/test/test_smtplib.py | 4 +++- + Lib/test/test_tools/test_md5sum.py | 4 ++-- + Lib/test/test_urllib2_localnet.py | 1 + + 10 files changed, 41 insertions(+), 32 deletions(-) + +diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py +index 553617a..8653cae 100644 +--- a/Lib/distutils/command/upload.py ++++ b/Lib/distutils/command/upload.py +@@ -127,7 +127,8 @@ class upload(PyPIRCCommand): + except ValueError as e: + msg = 'calculating md5 checksum failed: %s' % e + self.announce(msg, log.INFO) +- if not hashlib.get_fips_mode(): ++ from _hashlib import get_fips_mode ++ if not get_fips_mode(): + # this really shouldn't fail + raise + else: +diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py +index f720a79..a198b21 100644 +--- a/Lib/distutils/tests/test_upload.py ++++ b/Lib/distutils/tests/test_upload.py +@@ -4,6 +4,7 @@ import unittest + import unittest.mock as mock + from urllib.request import HTTPError + import hashlib ++from _hashlib import get_fips_mode + + from test.support import run_unittest + +@@ -131,7 +132,7 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + + # what did we send ? + headers = dict(self.last_open.req.headers) +- if hashlib.get_fips_mode(): ++ if get_fips_mode(): + # only sha256 hash is used + self.assertEqual(headers['Content-length'], '2197') + else: +@@ -172,7 +173,7 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + cmd.run() + + headers = dict(self.last_open.req.headers) +- if hashlib.get_fips_mode(): ++ if get_fips_mode(): + # only sha256 hash is used + self.assertEqual(headers['Content-length'], '2207') + else: +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index 898e6dc..2fc214e 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -76,12 +76,12 @@ __block_openssl_constructor = { + } + + try: +- from _hashlib import get_fips_mode ++ from _hashlib import get_fips_mode as _hashlib_get_fips_mode + except ImportError: +- def get_fips_mode(): ++ def _hashlib_get_fips_mode(): + return 0 + +-if not get_fips_mode(): ++if not _hashlib_get_fips_mode(): + __builtin_constructor_cache = {} + + def __get_builtin_constructor(name): +@@ -129,7 +129,7 @@ if not get_fips_mode(): + + + def __get_openssl_constructor(name): +- if not get_fips_mode(): ++ if not _hashlib_get_fips_mode(): + if name in __block_openssl_constructor: + # Prefer our blake2 and sha3 implementation. + return __get_builtin_constructor(name) +@@ -137,7 +137,7 @@ def __get_openssl_constructor(name): + f = getattr(_hashlib, 'openssl_' + name) + # Allow the C module to raise ValueError. The function will be + # defined but the hash not actually available thanks to OpenSSL. +- if not get_fips_mode(): ++ if not _hashlib.get_fips_mode(): + # N.B. In "FIPS mode", there is no fallback. + # If this test fails, we want to export the broken hash + # constructor anyway. +@@ -148,7 +148,7 @@ def __get_openssl_constructor(name): + return __get_builtin_constructor(name) + + +-if not get_fips_mode(): ++if not _hashlib_get_fips_mode(): + def __py_new(name, data=b'', **kwargs): + """new(name, data=b'', **kwargs) - Return a new hashing object using the + named algorithm; optionally initialized with data (which must be +@@ -161,7 +161,7 @@ def __hash_new(name, data=b'', **kwargs): + """new(name, data=b'') - Return a new hashing object using the named algorithm; + optionally initialized with data (which must be a bytes-like object). + """ +- if not get_fips_mode(): ++ if not _hashlib.get_fips_mode(): + if name in __block_openssl_constructor: + # Prefer our blake2 and sha3 implementation + # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s. +@@ -175,7 +175,7 @@ def __hash_new(name, data=b'', **kwargs): + # hash, try using our builtin implementations. + # This allows for SHA224/256 and SHA384/512 support even though + # the OpenSSL library prior to 0.9.8 doesn't provide them. +- if get_fips_mode(): ++ if _hashlib.get_fips_mode(): + raise + return __get_builtin_constructor(name)(data) + +@@ -187,7 +187,7 @@ try: + algorithms_available = algorithms_available.union( + _hashlib.openssl_md_meth_names) + except ImportError: +- if get_fips_mode(): ++ if _hashlib_get_fips_mode(): + raise + new = __py_new + __get_hash = __get_builtin_constructor +@@ -215,5 +215,6 @@ for __func_name in __always_supported: + # Cleanup locals() + del __always_supported, __func_name, __get_hash + del __hash_new, __get_openssl_constructor +-if not get_fips_mode(): ++if not _hashlib.get_fips_mode(): + del __py_new ++del _hashlib_get_fips_mode +diff --git a/Lib/hmac.py b/Lib/hmac.py +index b2bff7d..5055027 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -45,7 +45,7 @@ class HMAC: + msg argument. Passing it as a keyword argument is + recommended, though not required for legacy API reasons. + """ +- if _hashlib.get_fips_mode(): ++ if _hashlibopenssl.get_fips_mode(): + raise ValueError( + 'This class is not available in FIPS mode. ' + + 'Use hmac.new().' +@@ -100,7 +100,7 @@ class HMAC: + + def update(self, msg): + """Feed data from msg into this hashing object.""" +- if _hashlib.get_fips_mode(): ++ if _hashlibopenssl.get_fips_mode(): + raise ValueError('hmac.HMAC is not available in FIPS mode') + self.inner.update(msg) + +@@ -168,7 +168,7 @@ class HMAC_openssl(_hmacopenssl.HMAC): + return result + + +-if _hashlib.get_fips_mode(): ++if _hashlibopenssl.get_fips_mode(): + HMAC = HMAC_openssl + + +diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py +index 34812e6..86e61e2 100644 +--- a/Lib/test/test_fips.py ++++ b/Lib/test/test_fips.py +@@ -6,7 +6,7 @@ import hashlib, _hashlib + + class HashlibFipsTests(unittest.TestCase): + +- @unittest.skipUnless(hashlib.get_fips_mode(), "Test only when FIPS is enabled") ++ @unittest.skipUnless(_hashlib.get_fips_mode(), "Test only when FIPS is enabled") + def test_fips_imports(self): + """blake2s and blake2b should fail to import in FIPS mode + """ +@@ -30,7 +30,7 @@ class HashlibFipsTests(unittest.TestCase): + + self.assertEqual(m, h) + +- @unittest.skipIf(hashlib.get_fips_mode(), "blake2 hashes are not available under FIPS") ++ @unittest.skipIf(_hashlib.get_fips_mode(), "blake2 hashes are not available under FIPS") + def test_blake2_hashes(self): + self.compare_hashes(hashlib.blake2b(b'abc'), _hashlib.openssl_blake2b(b'abc')) + self.compare_hashes(hashlib.blake2s(b'abc'), _hashlib.openssl_blake2s(b'abc')) +@@ -41,7 +41,7 @@ class HashlibFipsTests(unittest.TestCase): + self.compare_hashes(hashlib.sha3_384(b'abc'), _hashlib.openssl_sha3_384(b'abc')) + self.compare_hashes(hashlib.sha3_512(b'abc'), _hashlib.openssl_sha3_512(b'abc')) + +- @unittest.skipIf(hashlib.get_fips_mode(), "shake hashes are not available under FIPS") ++ @unittest.skipIf(_hashlib.get_fips_mode(), "shake hashes are not available under FIPS") + def test_shake_hashes(self): + self.compare_hashes(hashlib.shake_128(b'abc'), _hashlib.openssl_shake_128(b'abc')) + self.compare_hashes(hashlib.shake_256(b'abc'), _hashlib.openssl_shake_256(b'abc')) +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 1368e91..a4b7840 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -29,7 +29,9 @@ COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') + c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) + py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) + +-if hashlib.get_fips_mode(): ++from _hashlib import get_fips_mode as _get_fips_mode ++ ++if _get_fips_mode(): + FIPS_UNAVAILABLE = {'blake2b', 'blake2s'} + FIPS_DISABLED = {'md5', 'MD5', *FIPS_UNAVAILABLE} + else: +@@ -105,7 +107,7 @@ class HashLibTestCase(unittest.TestCase): + # Issue #14693: fallback modules are always compiled under POSIX + _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG + +- if hashlib.get_fips_mode(): ++ if _get_fips_mode(): + shakes = set() + + def _conditional_import_module(self, module_name): +@@ -116,7 +118,7 @@ class HashLibTestCase(unittest.TestCase): + if self._warn_on_extension_import: + warnings.warn('Did a C extension fail to compile? %s' % error) + except ImportError as error: +- if not hashlib.get_fips_mode(): ++ if not _get_fips_mode(): + raise + return None + +@@ -253,12 +255,12 @@ class HashLibTestCase(unittest.TestCase): + def test_new_upper_to_lower(self): + self.assertEqual(hashlib.new("SHA256").name, "sha256") + +- @unittest.skipUnless(hashlib.get_fips_mode(), "Builtin constructor only unavailable in FIPS mode") ++ @unittest.skipUnless(_get_fips_mode(), "Builtin constructor only unavailable in FIPS mode") + def test_get_builtin_constructor_fips(self): + with self.assertRaises(AttributeError): + hashlib.__get_builtin_constructor + +- @unittest.skipIf(hashlib.get_fips_mode(), "No builtin constructors in FIPS mode") ++ @unittest.skipIf(_get_fips_mode(), "No builtin constructors in FIPS mode") + def test_get_builtin_constructor(self): + get_builtin_constructor = getattr(hashlib, + '__get_builtin_constructor') +@@ -446,7 +448,7 @@ class HashLibTestCase(unittest.TestCase): + self.assertIn(name.split("_")[0], repr(m)) + + def test_blocksize_name(self): +- if not hashlib.get_fips_mode(): ++ if not _get_fips_mode(): + self.check_blocksize_name('md5', 64, 16) + self.check_blocksize_name('sha1', 64, 20) + self.check_blocksize_name('sha224', 64, 28) +@@ -935,7 +937,7 @@ class HashLibTestCase(unittest.TestCase): + + self.assertEqual(expected_hash, hasher.hexdigest()) + +- @unittest.skipUnless(hashlib.get_fips_mode(), 'Needs FIPS mode.') ++ @unittest.skipUnless(_get_fips_mode(), 'Needs FIPS mode.') + def test_usedforsecurity_repeat(self): + """Make sure usedforsecurity flag isn't copied to other contexts""" + for i in range(3): +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 0b481ec..cc77928 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -5,6 +5,7 @@ import hashlib + import unittest + import unittest.mock + import warnings ++from _hashlib import get_fips_mode + + from test.support import requires_hashdigest + +@@ -288,7 +289,7 @@ class TestVectorsTestCase(unittest.TestCase): + def test_sha512_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) + +- @unittest.skipIf(hashlib.get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') ++ @unittest.skipIf(get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') + @requires_hashdigest('sha256') + def test_legacy_block_size_warnings(self): + class MockCrazyHash(object): +@@ -413,7 +414,7 @@ class SanityTestCase(unittest.TestCase): + + class CopyTestCase(unittest.TestCase): + +- @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") ++ @unittest.skipIf(get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') + def test_attributes(self): + # Testing if attributes are of same type. +@@ -426,7 +427,7 @@ class CopyTestCase(unittest.TestCase): + self.assertEqual(type(h1.outer), type(h2.outer), + "Types of outer don't match.") + +- @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") ++ @unittest.skipIf(get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') + def test_realcopy(self): + # Testing if the copy method created a real copy. +diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py +index d0c9862..9a44c0d 100644 +--- a/Lib/test/test_smtplib.py ++++ b/Lib/test/test_smtplib.py +@@ -17,6 +17,8 @@ import select + import errno + import textwrap + import threading ++import hashlib ++from _hashlib import get_fips_mode + + import unittest + from test import support, mock_socket +@@ -1021,7 +1023,7 @@ class SMTPSimTests(unittest.TestCase): + + def testAUTH_multiple(self): + # Test that multiple authentication methods are tried. +- self.serv.add_feature("AUTH BOGUS PLAIN LOGIN CRAM-MD5") ++ self.serv.add_feature("AUTH BOGUS PLAIN LOGIN") + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + resp = smtp.login(sim_auth[0], sim_auth[1]) + self.assertEqual(resp, (235, b'Authentication Succeeded')) +diff --git a/Lib/test/test_tools/test_md5sum.py b/Lib/test/test_tools/test_md5sum.py +index 7028a4d..3ba1ca0 100644 +--- a/Lib/test/test_tools/test_md5sum.py ++++ b/Lib/test/test_tools/test_md5sum.py +@@ -4,13 +4,13 @@ import os + import unittest + from test import support + from test.support.script_helper import assert_python_ok, assert_python_failure +-import hashlib ++import _hashlib + + from test.test_tools import scriptsdir, skip_if_missing + + skip_if_missing() + +-if hashlib.get_fips_mode(): ++if _hashlib.get_fips_mode(): + raise unittest.SkipTest("md5sum won't work at all in FIPS mode") + + class MD5SumTests(unittest.TestCase): +diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py +index 1cb358f..6f5cb7f 100644 +--- a/Lib/test/test_urllib2_localnet.py ++++ b/Lib/test/test_urllib2_localnet.py +@@ -7,6 +7,7 @@ import http.server + import threading + import unittest + import hashlib ++from _hashlib import get_fips_mode + + from test import support + +-- +2.25.4 + + +From 1de6c9e0e86e5c661ae32517492ecdf79a372e52 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 20 Nov 2019 10:59:25 +0100 +Subject: [PATCH 29/36] Use FIPS compliant CSPRNG + +Kernel's getrandom() source is not yet FIPS compliant. Use OpenSSL's +DRBG in FIPS mode and disable os.getrandom() function. + +Signed-off-by: Christian Heimes +--- + Lib/test/test_os.py | 5 +++ + Makefile.pre.in | 2 +- + Modules/posixmodule.c | 8 +++++ + Python/bootstrap_hash.c | 75 +++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 89 insertions(+), 1 deletion(-) + +diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py +index 4a076e3..f60ad6d 100644 +--- a/Lib/test/test_os.py ++++ b/Lib/test/test_os.py +@@ -1546,6 +1546,11 @@ class GetRandomTests(unittest.TestCase): + raise unittest.SkipTest("getrandom() syscall fails with ENOSYS") + else: + raise ++ except ValueError as exc: ++ if exc.args[0] == "getrandom is not FIPS compliant": ++ raise unittest.SkipTest("Skip in FIPS mode") ++ else: ++ raise + + def test_getrandom_type(self): + data = os.getrandom(16) +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 72d202d..9c34f99 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -116,7 +116,7 @@ PY_STDMODULE_CFLAGS= $(PY_CFLAGS) $(PY_CFLAGS_NODIST) $(PY_CPPFLAGS) $(CFLAGSFOR + PY_BUILTIN_MODULE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE_BUILTIN + PY_CORE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE + # Linker flags used for building the interpreter object files +-PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST) ++PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST) -lcrypto + # Strict or non-strict aliasing flags used to compile dtoa.c, see above + CFLAGS_ALIASING=@CFLAGS_ALIASING@ + +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +index 850769f..039392e 100644 +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -388,6 +388,9 @@ extern char *ctermid_r(char *); + #define MODNAME "posix" + #endif + ++/* for FIPS check in os.getrandom() */ ++#include ++ + #if defined(__sun) + /* Something to implement in autoconf, not present in autoconf 2.69 */ + #define HAVE_STRUCT_STAT_ST_FSTYPE 1 +@@ -13388,6 +13391,11 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) + return posix_error(); + } + ++ if (FIPS_mode()) { ++ PyErr_SetString(PyExc_ValueError, "getrandom is not FIPS compliant"); ++ return NULL; ++ } ++ + bytes = PyBytes_FromStringAndSize(NULL, size); + if (bytes == NULL) { + PyErr_NoMemory(); +diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c +index 43f5264..6716647 100644 +--- a/Python/bootstrap_hash.c ++++ b/Python/bootstrap_hash.c +@@ -409,6 +409,77 @@ dev_urandom_close(void) + } + #endif /* !MS_WINDOWS */ + ++#include ++#include ++#include ++ ++#if (OPENSSL_VERSION_NUMBER < 0x10101000L) || defined(LIBRESSL_VERSION_NUMBER) ++# error "py_openssl_drbg_urandom requires OpenSSL 1.1.1 for fork safety" ++#endif ++ ++static void ++py_openssl_set_exception(PyObject* exc) { ++ unsigned long errcode; ++ const char *lib, *func, *reason; ++ ++ errcode = ERR_peek_last_error(); ++ if (!errcode) { ++ PyErr_SetString(exc, "unknown reasons"); ++ } ++ ERR_clear_error(); ++ ++ lib = ERR_lib_error_string(errcode); ++ func = ERR_func_error_string(errcode); ++ reason = ERR_reason_error_string(errcode); ++ ++ if (lib && func) { ++ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); ++ } ++ else if (lib) { ++ PyErr_Format(exc, "[%s] %s", lib, reason); ++ } ++ else { ++ PyErr_SetString(exc, reason); ++ } ++} ++ ++static int ++py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) ++{ ++ int res; ++ static int init = 0; ++ ++ if (!init) { ++ init = 1; ++ res = OPENSSL_init_crypto(OPENSSL_INIT_ATFORK, NULL); ++ if (res == 0) { ++ if (raise) { ++ py_openssl_set_exception(PyExc_RuntimeError); ++ } ++ return 0; ++ } ++ } ++ ++ if (size > INT_MAX) { ++ if (raise) { ++ PyErr_Format(PyExc_OverflowError, ++ "RAND_bytes() size is limited to 2GB."); ++ } ++ return -1; ++ } ++ ++ res = RAND_bytes((unsigned char*)buffer, (int)size); ++ ++ if (res == 1) { ++ return 1; ++ } else { ++ if (raise) { ++ py_openssl_set_exception(PyExc_RuntimeError); ++ } ++ return 0; ++ } ++} ++ + + /* Fill buffer with pseudo-random bytes generated by a linear congruent + generator (LCG): +@@ -493,6 +564,10 @@ pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) + return 0; + } + ++ if (FIPS_mode()) { ++ return py_openssl_drbg_urandom(buffer, size, raise); ++ } ++ + #ifdef MS_WINDOWS + return win32_urandom((unsigned char *)buffer, size, raise); + #else +-- +2.25.4 + + +From 2af1274a6f6f7eb7aeb106007fd62e9fc889a86e Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 28 Nov 2019 17:26:02 +0100 +Subject: [PATCH 30/36] Fixups for FIPS compliant CSPRNG + +--- + Lib/test/test_os.py | 3 ++- + Python/bootstrap_hash.c | 33 +++------------------------------ + 2 files changed, 5 insertions(+), 31 deletions(-) + +diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py +index f60ad6d..be057ad 100644 +--- a/Lib/test/test_os.py ++++ b/Lib/test/test_os.py +@@ -28,6 +28,7 @@ import time + import unittest + import uuid + import warnings ++from _hashlib import get_fips_mode + from test import support + from platform import win32_is_iot + +@@ -1547,7 +1548,7 @@ class GetRandomTests(unittest.TestCase): + else: + raise + except ValueError as exc: +- if exc.args[0] == "getrandom is not FIPS compliant": ++ if get_fips_mode() and exc.args[0] == "getrandom is not FIPS compliant": + raise unittest.SkipTest("Skip in FIPS mode") + else: + raise +diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c +index 6716647..7466d5f 100644 +--- a/Python/bootstrap_hash.c ++++ b/Python/bootstrap_hash.c +@@ -409,40 +409,13 @@ dev_urandom_close(void) + } + #endif /* !MS_WINDOWS */ + +-#include +-#include + #include ++#include <_hashopenssl.h> + + #if (OPENSSL_VERSION_NUMBER < 0x10101000L) || defined(LIBRESSL_VERSION_NUMBER) + # error "py_openssl_drbg_urandom requires OpenSSL 1.1.1 for fork safety" + #endif + +-static void +-py_openssl_set_exception(PyObject* exc) { +- unsigned long errcode; +- const char *lib, *func, *reason; +- +- errcode = ERR_peek_last_error(); +- if (!errcode) { +- PyErr_SetString(exc, "unknown reasons"); +- } +- ERR_clear_error(); +- +- lib = ERR_lib_error_string(errcode); +- func = ERR_func_error_string(errcode); +- reason = ERR_reason_error_string(errcode); +- +- if (lib && func) { +- PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); +- } +- else if (lib) { +- PyErr_Format(exc, "[%s] %s", lib, reason); +- } +- else { +- PyErr_SetString(exc, reason); +- } +-} +- + static int + py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) + { +@@ -454,7 +427,7 @@ py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) + res = OPENSSL_init_crypto(OPENSSL_INIT_ATFORK, NULL); + if (res == 0) { + if (raise) { +- py_openssl_set_exception(PyExc_RuntimeError); ++ _setException(PyExc_RuntimeError); + } + return 0; + } +@@ -474,7 +447,7 @@ py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) + return 1; + } else { + if (raise) { +- py_openssl_set_exception(PyExc_RuntimeError); ++ _setException(PyExc_RuntimeError); + } + return 0; + } +-- +2.25.4 + + +From 17c962efe979581d12e1cf80a04b9538bdfe7c45 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 2 Apr 2020 16:50:37 +0200 +Subject: [PATCH 31/36] Do not raise a ValueError if digestmod is missing in + FIPS + +Python 3.8 already requires the digestmod argument and raises +a TypeError if it's missing, so we remove our downstream check +for it. +--- + Lib/hmac.py | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index 5055027..ee1ad76 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -143,8 +143,6 @@ class HMAC: + return h.hexdigest() + + def _get_openssl_name(digestmod): +- if digestmod is None: +- raise ValueError("'digestmod' argument is mandatory in FIPS mode") + if isinstance(digestmod, str): + return digestmod.lower() + elif callable(digestmod): +-- +2.25.4 + + +From 4acd1c8665231881335b6036a8595ac3220c0220 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 2 Apr 2020 16:55:36 +0200 +Subject: [PATCH 32/36] Regenerate the clinic files + +--- + Modules/_hmacopenssl.c | 4 ++-- + Modules/clinic/_hmacopenssl.c.h | 22 +++++++++++++++------- + 2 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index a24c8ba..9577cad 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -132,12 +132,12 @@ error: + /*[clinic input] + _hmacopenssl.HMAC.copy + +-Return a copy (“clone”) of the HMAC object. ++Return a copy ("clone") of the HMAC object. + [clinic start generated code]*/ + + static PyObject * + _hmacopenssl_HMAC_copy_impl(HmacObject *self) +-/*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ ++/*[clinic end generated code: output=fe5ee41faf30dcf0 input=06e7dbc1af7f4a13]*/ + { + HmacObject *retval; + +diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h +index 861acc1..527be83 100644 +--- a/Modules/clinic/_hmacopenssl.c.h ++++ b/Modules/clinic/_hmacopenssl.c.h +@@ -6,7 +6,7 @@ PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, + "copy($self, /)\n" + "--\n" + "\n" +-"Return a copy (“clone”) of the HMAC object."); ++"Return a copy (\"clone\") of the HMAC object."); + + #define _HMACOPENSSL_HMAC_COPY_METHODDEF \ + {"copy", (PyCFunction)_hmacopenssl_HMAC_copy, METH_NOARGS, _hmacopenssl_HMAC_copy__doc__}, +@@ -27,21 +27,29 @@ PyDoc_STRVAR(_hmacopenssl_HMAC_update__doc__, + "Update the HMAC object with msg."); + + #define _HMACOPENSSL_HMAC_UPDATE_METHODDEF \ +- {"update", (PyCFunction)_hmacopenssl_HMAC_update, METH_FASTCALL, _hmacopenssl_HMAC_update__doc__}, ++ {"update", (PyCFunction)(void(*)(void))_hmacopenssl_HMAC_update, METH_FASTCALL|METH_KEYWORDS, _hmacopenssl_HMAC_update__doc__}, + + static PyObject * + _hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg); + + static PyObject * +-_hmacopenssl_HMAC_update(HmacObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) ++_hmacopenssl_HMAC_update(HmacObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + static const char * const _keywords[] = {"msg", NULL}; +- static _PyArg_Parser _parser = {"y*:update", _keywords, 0}; ++ static _PyArg_Parser _parser = {NULL, _keywords, "update", 0}; ++ PyObject *argsbuf[1]; + Py_buffer msg = {NULL, NULL}; + +- if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, +- &msg)) { ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); ++ if (!args) { ++ goto exit; ++ } ++ if (PyObject_GetBuffer(args[0], &msg, PyBUF_SIMPLE) != 0) { ++ goto exit; ++ } ++ if (!PyBuffer_IsContiguous(&msg, 'C')) { ++ _PyArg_BadArgument("update", "argument 'msg'", "contiguous buffer", args[0]); + goto exit; + } + return_value = _hmacopenssl_HMAC_update_impl(self, &msg); +@@ -93,4 +101,4 @@ _hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) + { + return _hmacopenssl_HMAC_hexdigest_impl(self); + } +-/*[clinic end generated code: output=d93ad460795d49b5 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=9b75c31e1116bf6f input=a9049054013a1b77]*/ +-- +2.25.4 + + +From 900bbdc1e2d9498829731da4591f1ea4a5602fa4 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Tue, 7 Apr 2020 15:16:45 +0200 +Subject: [PATCH 33/36] Pass kwargs (like usedforsecurity) through __hash_new + +--- + Lib/hashlib.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index 2fc214e..785858f 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -169,7 +169,7 @@ def __hash_new(name, data=b'', **kwargs): + # salt, personal, tree hashing or SSE. + return __get_builtin_constructor(name)(data, **kwargs) + try: +- return _hashlib.new(name, data) ++ return _hashlib.new(name, data, **kwargs) + except ValueError: + # If the _hashlib module (OpenSSL) doesn't support the named + # hash, try using our builtin implementations. +@@ -177,7 +177,7 @@ def __hash_new(name, data=b'', **kwargs): + # the OpenSSL library prior to 0.9.8 doesn't provide them. + if _hashlib.get_fips_mode(): + raise +- return __get_builtin_constructor(name)(data) ++ return __get_builtin_constructor(name)(data, **kwargs) + + + try: +-- +2.25.4 + + +From ab62e35c2c3a71b2ff50098966e654c91fb861d0 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Tue, 7 Apr 2020 15:18:48 +0200 +Subject: [PATCH 34/36] Adjust new upstream test for failing hashes with + usedforsecurity + +--- + Lib/test/test_hashlib.py | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index a4b7840..a858bf4 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -239,15 +239,23 @@ class HashLibTestCase(unittest.TestCase): + self.assertTrue(set(hashlib.algorithms_guaranteed). + issubset(hashlib.algorithms_available)) + +- def test_usedforsecurity(self): ++ def test_usedforsecurity_false(self): + for cons in self.hash_constructors: +- cons(usedforsecurity=True) + cons(usedforsecurity=False) +- cons(b'', usedforsecurity=True) + cons(b'', usedforsecurity=False) +- hashlib.new("sha256", usedforsecurity=True) + hashlib.new("sha256", usedforsecurity=False) + ++ def test_usedforsecurity_true(self): ++ if _get_fips_mode(): ++ with self.assertRaises(ValueError): ++ hashlib.new("md5", usedforsecurity=True) ++ else: ++ for cons in self.hash_constructors: ++ cons(usedforsecurity=True) ++ cons(b'', usedforsecurity=True) ++ ++ hashlib.new("sha256", usedforsecurity=True) ++ + def test_unknown_hash(self): + self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') + self.assertRaises(TypeError, hashlib.new, 1) +-- +2.25.4 + + +From 2b6bf1615e9e04a688f622e4b45e0e062a09578f Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Fri, 24 Apr 2020 19:57:16 +0200 +Subject: [PATCH 35/36] Skip the test_with_digestmod_no_default under FIPS + +Also add a new test for testing the error values of +the digestmod parameter misuse under FIPS mode. +--- + Lib/test/test_hmac.py | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index cc77928..fd068e0 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -313,6 +313,7 @@ class TestVectorsTestCase(unittest.TestCase): + hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash) + self.fail('Expected warning about small block_size') + ++ @unittest.skipIf(get_fips_mode(), "digestmod misuse raises different errors under FIPS mode") + def test_with_digestmod_no_default(self): + """The digestmod parameter is required as of Python 3.8.""" + with self.assertRaisesRegex(TypeError, r'required.*digestmod'): +@@ -324,6 +325,18 @@ class TestVectorsTestCase(unittest.TestCase): + with self.assertRaisesRegex(TypeError, r'required.*digestmod'): + hmac.HMAC(key, msg=data, digestmod='') + ++ @unittest.skipIf(not get_fips_mode(), "test is run only under FIPS mode") ++ def test_with_digestmod_no_default_under_fips(self): ++ """Test the error values of digestmod misuse under FIPS mode.""" ++ with self.assertRaises(TypeError): ++ key = b"\x0b" * 16 ++ data = b"Hi There" ++ hmac.HMAC(key, data, digestmod=None) ++ with self.assertRaises(ValueError): ++ hmac.new(key, data) ++ with self.assertRaises(ValueError): ++ hmac.HMAC(key, msg=data, digestmod='') ++ + + class ConstructorTestCase(unittest.TestCase): + +-- +2.25.4 + + +From 65903540be85cbd6f188f6b5e69431859d0cbc0e Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Tue, 31 Mar 2020 18:00:42 +0200 +Subject: [PATCH 36/36] Add a sentinel value on the Hmac_members table of the + hmac module + +--- + Modules/_hmacopenssl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 9577cad..4bd7c15 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -337,6 +337,7 @@ static PyGetSetDef Hmac_getset[] = { + + static PyMemberDef Hmac_members[] = { + {"name", T_OBJECT, offsetof(HmacObject, name), READONLY, PyDoc_STR("HMAC name")}, ++ {NULL} /* Sentinel */ + }; + + PyDoc_STRVAR(hmactype_doc, +-- +2.25.4 + diff --git a/SOURCES/00337-test_ssl-test_min_max_version-add-range.patch b/SOURCES/00337-test_ssl-test_min_max_version-add-range.patch deleted file mode 100644 index df60a01..0000000 --- a/SOURCES/00337-test_ssl-test_min_max_version-add-range.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 4e4445efad2d3aa17b455a2683884e500d1a7c90 Mon Sep 17 00:00:00 2001 -From: Tomas Orsava -Date: Fri, 29 Nov 2019 16:07:27 +0100 -Subject: [PATCH] Adjust the test_min_max_version in test_ssl - -to accept the new settings in RHEL 8.2 where maximum_version is set to TLS 1.3. ---- - Lib/test/test_ssl.py | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index 419506f..c9b2cf9 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -1200,12 +1200,18 @@ class ContextTests(unittest.TestCase): - # RHEL 8 uses TLS 1.2 by default - ssl.TLSVersion.TLSv1_2 - } -+ maximum_range = { -+ # stock OpenSSL -+ ssl.TLSVersion.MAXIMUM_SUPPORTED, -+ # RHEL 8.2 requires maximum TLS 1.3 -+ ssl.TLSVersion.TLSv1_3 -+ } - - self.assertIn( - ctx.minimum_version, minimum_range - ) -- self.assertEqual( -- ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED -+ self.assertIn( -+ ctx.maximum_version, maximum_range - ) - - ctx.minimum_version = ssl.TLSVersion.TLSv1_1 --- -2.20.1 - diff --git a/SOURCES/00350-sqlite-fix-deterministic-test.patch b/SOURCES/00350-sqlite-fix-deterministic-test.patch new file mode 100644 index 0000000..1ec23dd --- /dev/null +++ b/SOURCES/00350-sqlite-fix-deterministic-test.patch @@ -0,0 +1,76 @@ +commit 00a240bf7f95bbd220f1cfbf9eb58484a5f9681a +Author: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> +Date: Fri May 29 05:46:34 2020 -0700 + + bpo-40784: Fix sqlite3 deterministic test (GH-20448) + + (cherry picked from commit c610d970f5373b143bf5f5900d4645e6a90fb460) + + Co-authored-by: Erlend Egeberg Aasland + +diff --git a/Lib/sqlite3/test/userfunctions.py b/Lib/sqlite3/test/userfunctions.py +index 9501f53..c11c82e 100644 +--- a/Lib/sqlite3/test/userfunctions.py ++++ b/Lib/sqlite3/test/userfunctions.py +@@ -1,8 +1,7 @@ +-#-*- coding: iso-8859-1 -*- + # pysqlite2/test/userfunctions.py: tests for user-defined functions and + # aggregates. + # +-# Copyright (C) 2005-2007 Gerhard H�ring ++# Copyright (C) 2005-2007 Gerhard Häring + # + # This file is part of pysqlite. + # +@@ -158,6 +157,7 @@ class FunctionTests(unittest.TestCase): + self.con.create_function("isblob", 1, func_isblob) + self.con.create_function("islonglong", 1, func_islonglong) + self.con.create_function("spam", -1, func) ++ self.con.execute("create table test(t text)") + + def tearDown(self): + self.con.close() +@@ -276,18 +276,36 @@ class FunctionTests(unittest.TestCase): + val = cur.fetchone()[0] + self.assertEqual(val, 2) + ++ # Regarding deterministic functions: ++ # ++ # Between 3.8.3 and 3.15.0, deterministic functions were only used to ++ # optimize inner loops, so for those versions we can only test if the ++ # sqlite machinery has factored out a call or not. From 3.15.0 and onward, ++ # deterministic functions were permitted in WHERE clauses of partial ++ # indices, which allows testing based on syntax, iso. the query optimizer. ++ @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher") + def CheckFuncNonDeterministic(self): + mock = unittest.mock.Mock(return_value=None) +- self.con.create_function("deterministic", 0, mock, deterministic=False) +- self.con.execute("select deterministic() = deterministic()") +- self.assertEqual(mock.call_count, 2) +- +- @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "deterministic parameter not supported") ++ self.con.create_function("nondeterministic", 0, mock, deterministic=False) ++ if sqlite.sqlite_version_info < (3, 15, 0): ++ self.con.execute("select nondeterministic() = nondeterministic()") ++ self.assertEqual(mock.call_count, 2) ++ else: ++ with self.assertRaises(sqlite.OperationalError): ++ self.con.execute("create index t on test(t) where nondeterministic() is not null") ++ ++ @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher") + def CheckFuncDeterministic(self): + mock = unittest.mock.Mock(return_value=None) + self.con.create_function("deterministic", 0, mock, deterministic=True) +- self.con.execute("select deterministic() = deterministic()") +- self.assertEqual(mock.call_count, 1) ++ if sqlite.sqlite_version_info < (3, 15, 0): ++ self.con.execute("select deterministic() = deterministic()") ++ self.assertEqual(mock.call_count, 1) ++ else: ++ try: ++ self.con.execute("create index t on test(t) where deterministic() is not null") ++ except sqlite.OperationalError: ++ self.fail("Unexpected failure while creating partial index") + + @unittest.skipIf(sqlite.sqlite_version_info >= (3, 8, 3), "SQLite < 3.8.3 needed") + def CheckFuncDeterministicNotSupported(self): diff --git a/SOURCES/Python-3.8.0.tar.xz.asc b/SOURCES/Python-3.8.0.tar.xz.asc deleted file mode 100644 index 942a421..0000000 --- a/SOURCES/Python-3.8.0.tar.xz.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCgAdFiEE4/8oOcBIslwITevpsmmV4xAlBWgFAl2kmqsACgkQsmmV4xAl -BWgUvRAAjomYhRM5CBKP99ygaTKAqeTHVnJt32O8n3OHPWL6YSSm2GBSnX4fhtqn -uX9VysXFc90zEX+ww2+n2+IwDzsddItWtdZfNnVAUeBs8GNGpq5KbnGX7LB7+orp -nJPcDUMsF2Mutuk7fREr8KHFUGSyMkUj+bh/1Ml+R7LGoTtPKywqtu7X0ACoJ3N0 -hds0qd79o8u5i2N5rLWfuj6/1HmorNwNhtJo7vIACZIUyIKP3rB8WXtE8+drptuv -ApYJdxE74iixntMuk6sCwPKBquIzwfEI3NzcmtJCV32cpASHB3+8FHJIlp94++9y -AUF4Kxp3aQui1XaeeLRdIpprl6M+PwB6tTQKoSkkecTVysj5GOdBRFEhGl5bFNO9 -DSiHU7uy8JkeOZVdcz4zIdZnlUUtCq4Ycpc8PXKjI0kbHlsp38y7F8lFNP10UY/D -iKDDGxQowCtVgKCORNhmKWCmEZcgbDZA9EAz9rgCdhPY7we3Qdj68L820ELxJeQj -50ss/6GcIJK1jgOSXng7DvUhlpsp5avhaM3iWnqCtU+a2fOVm0pQR826q62majLR -uui7SDKtVPU7VaLetfppuNjI3T8xUX86niSRtmlYjsjweJ+jXJWTnkkHUNI04UjH -2WANZRJ10NXl7UVRlnGYVzAcslyabnnlRw6Zf1haWtAWTLyP7Tw= -=bg98 ------END PGP SIGNATURE----- diff --git a/SOURCES/Python-3.8.3.tar.xz.asc b/SOURCES/Python-3.8.3.tar.xz.asc new file mode 100644 index 0000000..42c7be3 --- /dev/null +++ b/SOURCES/Python-3.8.3.tar.xz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEE4/8oOcBIslwITevpsmmV4xAlBWgFAl68Z1QACgkQsmmV4xAl +BWhdxQ/+PUi0er9eBEaWNaatCsEDXnBvrCs1OooL3WWJ2GC5zf3buMwj2pFOZf9D +YFFGdomhYhvRnyQCJQSXuWJXQaafzKAl1tvkgS2ycOnLvCJ/qw71SqorQxkMGK1m +TYZyLEapNkXrfDXRHfGybuVlNsHw9++abpEITqwucTWm9LiHZoF/zdK+JX/5RYQ0 +bfb8819DMZEyCsF+S8Jo6ZNyEIQyQxidFFt5HbMllFwsgzu37P8RqGSIoVNFJ8n9 +f7BWfXAIyGr7pIlJ+3qBYDXOeOx8iwIUxGu3Gbmiri+dlxz28Iei4mxPYHG4ji5B +3zMsqKcaVAMHzKuAwdF5ZbUg0DRRJweNoiDOsfKp0CI814pXmOLH0zi9OiLrxBzj +7v9H3dAPMC2f2zAFdNcjYVBRovCxIork/Lj3+6jGn67+8oV+eb23gnN5YpDAFAAu +ybtrt6fEi0uVJuxUl+MO5HkSmH3sLggVDskvuWPFLiuahcbSuiZoCvlB+osO9J0H +el/3Awv5TjckY/EVDt1T61aYLX0CHNcb8c/CjAf0OSd/96WxV3svtusllqcSYwiC +NxBRf0klpGn0Tpa+9hTAMc4dEKILgao1KsKiI8dj8YY3HcE0Lb3y9UdFcIDLCeqn +Sk5turYyKak7apZTY31/0eqqCUl/RlZwpmxVUUNViwR5F2ZPeAQ= +=jF/G +-----END PGP SIGNATURE----- diff --git a/SPECS/python38.spec b/SPECS/python38.spec index 28ddd18..521ecc1 100644 --- a/SPECS/python38.spec +++ b/SPECS/python38.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.0 +%global general_version %{pybasever}.3 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 1%{?dist} License: Python # Exclude i686 arch. Due to a modularity issue it's being added to the @@ -62,6 +62,9 @@ ExcludeArch: i686 # Expensive optimizations (mainly, profile-guided optimizations) %bcond_without optimizations +# https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup +%bcond_without no_semantic_interposition + # Run the test suite in %%check %bcond_without tests @@ -141,16 +144,6 @@ ExcludeArch: i686 # on files that test invalid syntax. %undefine py_auto_byte_compile -# For multilib support, files that are different between 32- and 64-bit arches -# need different filenames. Use "64" or "32" according to the word size. -# Currently, the best way to determine an architecture's word size happens to -# be checking %%{_lib}. -%if "%{_lib}" == "lib64" -%global wordsize 64 -%else -%global wordsize 32 -%endif - # ======================= # Build-time requirements @@ -260,6 +253,8 @@ Patch111: 00111-no-static-lib.patch # 00189 # # Instead of bundled wheels, use our RPM packaged wheels from # /usr/share/python38-wheels +# Downstream only: upstream bundles +# We might eventually pursuit upstream support, but it's low prio Patch189: 00189-use-rpm-wheels.patch # 00251 @@ -267,6 +262,7 @@ Patch189: 00189-use-rpm-wheels.patch # to /usr/local if executable is /usr/bin/python* and RPM build # is not detected to make pip and distutils install into separate location # Fedora Change: https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe +# Downstream only: Awaiting resources to work on upstream PEP Patch251: 00251-change-user-install-location.patch # 00274 # @@ -276,12 +272,38 @@ Patch274: 00274-fix-arch-names.patch # 00328 # # Restore pyc to TIMESTAMP invalidation mode as default in rpmbubild # See https://src.fedoraproject.org/rpms/redhat-rpm-config/pull-request/57#comment-27426 +# Downstream only: only used when building RPM packages +# Ideally, we should talk to upstream and explain why we don't want this Patch328: 00328-pyc-timestamp-invalidation-mode.patch -# 00337 # -# Adjust the test_min_max_version in test_ssl to accept the new settings in -# RHEL 8.2 where maximum_version is set to TLS 1.3 -Patch337: 00337-test_ssl-test_min_max_version-add-range.patch +# 00329 # +# Support OpenSSL FIPS mode +# - Fallback implementations md5, sha1, sha256, sha512 are removed in favor of OpenSSL wrappers +# - In FIPS mode, OpenSSL wrappers are always used in hashlib +# - add a new "usedforsecurity" keyword argument to the various digest +# algorithms in hashlib so that you can whitelist a callsite with +# "usedforsecurity=False" +# The change has been implemented upstream since Python 3.9: +# https://bugs.python.org/issue9216 +# - OpenSSL wrappers for the hashes blake2{b512,s256}, +# sha3_{224,256,384,512}, shake_{128,256} are now exported from _hashlib +# - In FIPS mode, the blake2, sha3 and shake hashes use OpenSSL wrappers +# and do not offer extended functionality (keys, tree hashing, custom digest size) +# - In FIPS mode, hmac.HMAC can only be instantiated with an OpenSSL wrapper +# or an string with OpenSSL hash name as the "digestmod" argument. +# The argument must be specified (instead of defaulting to ‘md5’). +# +# - Also while in FIPS mode, we utilize OpenSSL's DRBG and disable the +# os.getrandom() function. +# +# Resolves: rhbz#1731424 +Patch329: 00329-fips.patch + +# 00350 # +# bpo-40784: Fix sqlite3 deterministic test (GH-20448) +# https://bugs.python.org/issue40784 +# https://github.com/python/cpython/commit/00a240bf7f95bbd220f1cfbf9eb58484a5f9681a +Patch350: 00350-sqlite-fix-deterministic-test.patch # (New patches go here ^^^) # @@ -305,6 +327,15 @@ Patch337: 00337-test_ssl-test_min_max_version-add-range.patch # we enable this in both flat and nonflat package. Provides: python%{pybasever} = %{version}-%{release} +# When the user tries to `yum install python`, yum will list this package among +# the possible alternatives +Provides: alternative-for(python) + +# Runtime require alternatives +Requires: %{_sbindir}/alternatives +Requires(post): %{_sbindir}/alternatives +Requires(postun): %{_sbindir}/alternatives + %if %{without flatpackage} # Packages with Python modules in standard locations automatically @@ -368,6 +399,8 @@ Documentation for Python is provided in the %{name}-docs package. Packages containing additional libraries for Python are generally named with the "%{name}-" prefix. +For the unversioned "python" executable, see manual page "unversioned-python". + %if %{with main_python} # https://fedoraproject.org/wiki/Changes/Move_usr_bin_python_into_separate_package @@ -407,6 +440,10 @@ Provides: bundled(python38-setuptools) = 41.2.0 # See https://bugzilla.redhat.com/show_bug.cgi?id=1547131 Recommends: %{name}%{?_isa} = %{version}-%{release} +# tkinter is part of the standard library, +# but it is torn out to save an unwanted dependency on tk and X11. +# we recommend it when tk is already installed (for better UX) +Recommends: (%{name}-tkinter%{?_isa} = %{version}-%{release} if tk%{?_isa}) %description libs This package contains runtime libraries for use by Python: @@ -424,6 +461,9 @@ BuildRequires: python-rpm-macros # But we want them when packages BuildRequire python3-devel Requires: (python-rpm-macros if rpm-build) Requires: (python3-rpm-macros if rpm-build) +# python38 installs the alternatives master symlink to which we attach a slave +Requires(post): python38 +Requires(postun): python38 %if %{without bootstrap} # This is not "API" (packages that need setuptools should still BuildRequire it) @@ -459,6 +499,10 @@ Requires: %{name}-tkinter = %{version}-%{release} %{?python_provide:%python_provide python38-idle} +# python38 installs the alternatives master symlink to which we attach a slave +Requires(post): python38 +Requires(postun): python38 + %description idle IDLE is Python’s Integrated Development and Learning Environment. @@ -511,6 +555,9 @@ Requires: %{name}-devel%{?_isa} = %{version}-%{release} Requires: %{name}-test%{?_isa} = %{version}-%{release} Requires: %{name}-tkinter%{?_isa} = %{version}-%{release} Requires: %{name}-idle%{?_isa} = %{version}-%{release} +# python38 installs the alternatives master symlink to which we attach a slave +Requires(post): python38 +Requires(postun): python38 %{?python_provide:%python_provide python38-debug} @@ -604,7 +651,8 @@ rm Lib/ensurepip/_bundled/*.whl %patch251 -p1 %patch274 -p1 %patch328 -p1 -%patch337 -p1 +%patch329 -p1 +%patch350 -p1 # Remove files that should be generated by the build @@ -647,14 +695,14 @@ topdir=$(pwd) # Fedora packages utilizing %%py3_build will use them as well # https://fedoraproject.org/wiki/Changes/Python_Extension_Flags export CFLAGS="%{extension_cflags} -D_GNU_SOURCE -fPIC -fwrapv" -export CFLAGS_NODIST="%{build_cflags} -D_GNU_SOURCE -fPIC -fwrapv -fno-semantic-interposition" +export CFLAGS_NODIST="%{build_cflags} -D_GNU_SOURCE -fPIC -fwrapv%{?with_no_semantic_interposition: -fno-semantic-interposition}" export CXXFLAGS="%{extension_cxxflags} -D_GNU_SOURCE -fPIC -fwrapv" export CPPFLAGS="$(pkg-config --cflags-only-I libffi)" export OPT="%{extension_cflags} -D_GNU_SOURCE -fPIC -fwrapv" export LINKCC="gcc" export CFLAGS="$CFLAGS $(pkg-config --cflags openssl)" export LDFLAGS="%{extension_ldflags} -g $(pkg-config --libs-only-L openssl)" -export LDFLAGS_NODIST="%{build_ldflags} -fno-semantic-interposition -g $(pkg-config --libs-only-L openssl)" +export LDFLAGS_NODIST="%{build_ldflags}%{?with_no_semantic_interposition: -fno-semantic-interposition} -g $(pkg-config --libs-only-L openssl)" # We can build several different configurations of Python: regular and debug. # Define a common function that does one build: @@ -759,7 +807,7 @@ mkdir -p %{buildroot}$DirHoldingGdbPy # Filanames are defined here: %global _pyconfig32_h pyconfig-32.h %global _pyconfig64_h pyconfig-64.h -%global _pyconfig_h pyconfig-%{wordsize}.h +%global _pyconfig_h pyconfig-%{__isa_bits}.h # Use a common function to do an install for all our configurations: InstallPython() { @@ -967,6 +1015,21 @@ mkdir -p %{buildroot}/%{rpmmacrodir}/ install -m 644 %{SOURCE3} \ %{buildroot}/%{rpmmacrodir}/ +# All ghost files controlled by alternatives need to exist for the files +# section check to succeed +# - Don't list /usr/bin/python as a ghost file so `yum install /usr/bin/python` +# doesn't install this package +touch %{buildroot}%{_bindir}/unversioned-python +touch %{buildroot}%{_mandir}/man1/python.1.gz +touch %{buildroot}%{_bindir}/python3 +touch %{buildroot}%{_mandir}/man1/python3.1.gz +touch %{buildroot}%{_bindir}/pydoc3 +touch %{buildroot}%{_bindir}/pydoc-3 +touch %{buildroot}%{_bindir}/idle3 +touch %{buildroot}%{_bindir}/python3-config +touch %{buildroot}%{_bindir}/python3-debug +touch %{buildroot}%{_bindir}/python3-debug-config + # ====================================================== # Checks for packaging issues @@ -1022,6 +1085,7 @@ CheckPython() { LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.pythoninfo # Run the upstream test suite + # --timeout=1800: kill test running for longer than 30 minutes # test_gdb skipped on s390x: # https://bugzilla.redhat.com/show_bug.cgi?id=1678277 # test_gdb skipped everywhere: @@ -1030,7 +1094,7 @@ CheckPython() { # distutils.tests.test_bdist_rpm tests fail when bootstraping the Python # package: rpmbuild requires /usr/bin/pythonX.Y to be installed LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \ - -wW --slowest -j0 \ + -wW --slowest -j0 --timeout=1800 \ %if %{with bootstrap} -x test_distutils \ %endif @@ -1054,6 +1118,117 @@ CheckPython optimized %endif # with tests +%post +# Alternative for /usr/bin/python -> /usr/bin/python3 + man page +alternatives --install %{_bindir}/unversioned-python \ + python \ + %{_bindir}/python3 \ + 300 \ + --slave %{_bindir}/python \ + unversioned-python \ + %{_bindir}/python3 \ + --slave %{_mandir}/man1/python.1.gz \ + unversioned-python-man \ + %{_mandir}/man1/python3.1.gz + +# Alternative for /usr/bin/python -> /usr/bin/python3.8 + man page +alternatives --install %{_bindir}/unversioned-python \ + python \ + %{_bindir}/python3.8 \ + 208 \ + --slave %{_bindir}/python \ + unversioned-python \ + %{_bindir}/python3.8 \ + --slave %{_mandir}/man1/python.1.gz \ + unversioned-python-man \ + %{_mandir}/man1/python3.8.1.gz + +# Alternative for /usr/bin/python3 -> /usr/bin/python3.8 + related files +# Create only if it doesn't exist already +EXISTS=`alternatives --display python3 | \ + grep -c "^/usr/bin/python3.8 - priority [0-9]*"` + +if [ $EXISTS -eq 0 ]; then + alternatives --install %{_bindir}/python3 \ + python3 \ + %{_bindir}/python3.8 \ + 3800 \ + --slave %{_mandir}/man1/python3.1.gz \ + python3-man \ + %{_mandir}/man1/python3.8.1.gz \ + --slave %{_bindir}/pydoc3 \ + pydoc3 \ + %{_bindir}/pydoc3.8 \ + --slave %{_bindir}/pydoc-3 \ + pydoc-3 \ + %{_bindir}/pydoc3.8 +fi + +%postun +# Do this only during uninstall process (not during update) +if [ $1 -eq 0 ]; then + alternatives --remove python \ + %{_bindir}/python3.8 + + alternatives --remove python3 \ + %{_bindir}/python3.8 + + # Remove link python → python3 if no other python3.* exists + if ! alternatives --display python3 > /dev/null; then + alternatives --remove python \ + %{_bindir}/python3 + fi +fi + + +%post devel +alternatives --add-slave python3 %{_bindir}/python3.8 \ + %{_bindir}/python3-config \ + python3-config \ + %{_bindir}/python3.8-config + +%postun devel +# Do this only during uninstall process (not during update) +if [ $1 -eq 0 ]; then + alternatives --remove-slave python3 %{_bindir}/python3.8 \ + python3-config +fi + + +%post debug +alternatives --add-slave python3 %{_bindir}/python3.8 \ + %{_bindir}/python3-debug \ + python3-debug \ + %{_bindir}/python3.8d +alternatives --add-slave python3 %{_bindir}/python3.8 \ + %{_bindir}/python3-debug-config \ + python3-debug-config \ + %{_bindir}/python3.8d-config + +%postun debug +# Do this only during uninstall process (not during update) +if [ $1 -eq 0 ]; then + alternatives --remove-slave python3 %{_bindir}/python3.8 \ + python3-debug + alternatives --remove-slave python3 %{_bindir}/python3.8 \ + python3-debug-config +fi + + +%post idle +alternatives --add-slave python3 %{_bindir}/python3.8 \ + %{_bindir}/idle3 \ + idle3 \ + %{_bindir}/idle3.8 + +%postun idle +# Do this only during uninstall process (not during update) +if [ $1 -eq 0 ]; then + alternatives --remove-slave python3 %{_bindir}/python3.8 \ + idle3 +fi + + %files -n python38-rpm-macros %license LICENSE %doc README.rst @@ -1062,6 +1237,15 @@ CheckPython optimized %files %doc README.rst +# Alternatives +%ghost %{_bindir}/unversioned-python +%ghost %{_mandir}/man1/python.1.gz +%ghost %{_bindir}/python3 +%ghost %{_mandir}/man1/python3.1.gz +%ghost %{_bindir}/pydoc3 +%ghost %{_bindir}/pydoc-3 + + %if %{with main_python} %{_bindir}/pydoc* %{_bindir}/python3 @@ -1141,11 +1325,8 @@ CheckPython optimized %{pylibdir}/pydoc_data %{dynload_dir}/_blake2.%{SOABI_optimized}.so -%{dynload_dir}/_md5.%{SOABI_optimized}.so -%{dynload_dir}/_sha1.%{SOABI_optimized}.so -%{dynload_dir}/_sha256.%{SOABI_optimized}.so %{dynload_dir}/_sha3.%{SOABI_optimized}.so -%{dynload_dir}/_sha512.%{SOABI_optimized}.so +%{dynload_dir}/_hmacopenssl.%{SOABI_optimized}.so %{dynload_dir}/_asyncio.%{SOABI_optimized}.so %{dynload_dir}/_bisect.%{SOABI_optimized}.so @@ -1340,6 +1521,9 @@ CheckPython optimized %{_bindir}/python%{pybasever}-config %{_bindir}/python%{LDVERSION_optimized}-config %{_bindir}/python%{LDVERSION_optimized}-*-config +# Alternatives +%ghost %{_bindir}/python3-config + %{_libdir}/libpython%{LDVERSION_optimized}.so %{_libdir}/pkgconfig/python-%{LDVERSION_optimized}.pc %{_libdir}/pkgconfig/python-%{LDVERSION_optimized}-embed.pc @@ -1355,6 +1539,8 @@ CheckPython optimized %{_bindir}/idle* %else %{_bindir}/idle%{pybasever} +# Alternatives +%ghost %{_bindir}/idle3 %endif %{pylibdir}/idlelib @@ -1420,16 +1606,15 @@ CheckPython optimized # Analog of the core subpackage's files: %{_bindir}/python%{LDVERSION_debug} +# Alternatives +%ghost %{_bindir}/python3-debug # Analog of the -libs subpackage's files: # ...with debug builds of the built-in "extension" modules: %{dynload_dir}/_blake2.%{SOABI_debug}.so -%{dynload_dir}/_md5.%{SOABI_debug}.so -%{dynload_dir}/_sha1.%{SOABI_debug}.so -%{dynload_dir}/_sha256.%{SOABI_debug}.so %{dynload_dir}/_sha3.%{SOABI_debug}.so -%{dynload_dir}/_sha512.%{SOABI_debug}.so +%{dynload_dir}/_hmacopenssl.%{SOABI_debug}.so %{dynload_dir}/_asyncio.%{SOABI_debug}.so %{dynload_dir}/_bisect.%{SOABI_debug}.so @@ -1506,8 +1691,10 @@ CheckPython optimized %{_includedir}/python%{LDVERSION_debug} %{_bindir}/python%{LDVERSION_debug}-config %{_bindir}/python%{LDVERSION_debug}-*-config +%ghost %{_bindir}/python3-debug-config + %{_libdir}/libpython%{LDVERSION_debug}.so -%{_libdir}/libpython%{LDVERSION_debug}.so.1.0 +%{_libdir}/libpython%{LDVERSION_debug}.so.%{py_SOVERSION} %{_libdir}/pkgconfig/python-%{LDVERSION_debug}.pc %{_libdir}/pkgconfig/python-%{LDVERSION_debug}-embed.pc @@ -1549,6 +1736,42 @@ CheckPython optimized # ====================================================== %changelog +* Wed Jun 24 2020 Tomas Orsava - 3.8.3-2 +- Fix sqlite3 deterministic test +Related: rhbz#1847416 + +* Wed Jun 24 2020 Tomas Orsava - 3.8.3-1 +- Rebased to 3.8.3 final +- Backported changes from Fedora + - Recommend python3-tkinter when tk is installed + - Add bcond for no_semantic_interposition (enabled by default) + - Update the ensurepip module to work with setuptools >= 45 +Resolves: rhbz#1847416 + +* Thu May 07 2020 Charalampos Stratakis - 3.8.0-10 +- Fix test_hashlib and test_hmac under FIPS mode +Resolves: rhbz#1812477 + +* Thu Apr 23 2020 Lumír Balhar - 3.8.0-9 +- Fix ensurepip to run pip via runpy to fix compatibility with pip 19.3.1 +Resolves: rhbz#1827623 + +* Wed Apr 22 2020 Charalampos Stratakis - 3.8.0-8 +- Skip test_startup_imports from test_site if we have a .pth file in sys.path +Resolves: rhbz#1815643 + +* Fri Apr 03 2020 Charalampos Stratakis - 3.8.0-7 +- Security fix for CVE-2020-8492 +Resolves: rhbz#1810622 + +* Mon Feb 24 2020 Tomas Orsava - 3.8.0-6 +- Implement alternatives for /usr/bin/python, python3 and related executables +- Resolves: rhbz#1807041 + +* Fri Jan 10 2020 Charalampos Stratakis - 3.8.0-5 +- Add support for FIPS mode +- Resolves: rhbz#1793589 + * Thu Dec 12 2019 Tomas Orsava - 3.8.0-4 - Exclude unsupported i686 arch