Blame SOURCES/00329-fips.patch

8f0bcc
From 37aa11f4c57e08bd3859c0de1c22f1d5296b6fdc Mon Sep 17 00:00:00 2001
8f0bcc
From: Petr Viktorin <encukou@gmail.com>
8f0bcc
Date: Wed, 11 Aug 2021 16:51:03 +0200
8f0bcc
Subject: [PATCH 01/10] Backport PyModule_AddObjectRef as
8f0bcc
 _PyModule_AddObjectRef
93c559
8f0bcc
Having PyModule_AddObjectRef available should make backporting
8f0bcc
newer patches easier. The new API is much safer.
8f0bcc
The backport adds an underscore so that we don't break extension
8f0bcc
modules that define PyModule_AddObjectRef themselves on Python<=3.9
8f0bcc
(which would be a virtuous thing to do).
93c559
---
8f0bcc
 Include/modsupport.h | 10 ++++++++++
8f0bcc
 Python/modsupport.c  | 13 +++++++++++--
8f0bcc
 2 files changed, 21 insertions(+), 2 deletions(-)
93c559
8f0bcc
diff --git a/Include/modsupport.h b/Include/modsupport.h
8f0bcc
index 4c4aab6..d9fac52 100644
8f0bcc
--- a/Include/modsupport.h
8f0bcc
+++ b/Include/modsupport.h
8f0bcc
@@ -136,7 +136,17 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
8f0bcc
 void _PyArg_Fini(void);
8f0bcc
 #endif   /* Py_LIMITED_API */
8f0bcc
 
8f0bcc
+// Add an attribute with name 'name' and value 'obj' to the module 'mod.
8f0bcc
+// On success, return 0 on success.
8f0bcc
+// On error, raise an exception and return -1.
8f0bcc
+// Backported from Python 3.10, where it's available without the underscore
8f0bcc
+// in the name, to ease porting patches to RHEL
8f0bcc
+PyAPI_FUNC(int) _PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value);
8f0bcc
+
8f0bcc
+// Similar to PyModule_AddObjectRef() but steal a reference to 'obj'
8f0bcc
+// (Py_DECREF(obj)) on success (if it returns 0).
8f0bcc
 PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *);
8f0bcc
+
8f0bcc
 PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
8f0bcc
 PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *);
8f0bcc
 #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
8f0bcc
diff --git a/Python/modsupport.c b/Python/modsupport.c
8f0bcc
index 13482c6..fca1083 100644
8f0bcc
--- a/Python/modsupport.c
8f0bcc
+++ b/Python/modsupport.c
8f0bcc
@@ -631,7 +631,7 @@ va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len,
8f0bcc
 
8f0bcc
 
8f0bcc
 int
8f0bcc
-PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
8f0bcc
+_PyModule_AddObjectRef(PyObject *m, const char *name, PyObject *o)
8f0bcc
 {
8f0bcc
     PyObject *dict;
8f0bcc
     if (!PyModule_Check(m)) {
8f0bcc
@@ -655,10 +655,19 @@ PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
8f0bcc
     }
8f0bcc
     if (PyDict_SetItemString(dict, name, o))
8f0bcc
         return -1;
8f0bcc
-    Py_DECREF(o);
8f0bcc
     return 0;
93c559
 }
93c559
 
8f0bcc
+int
8f0bcc
+PyModule_AddObject(PyObject *mod, const char *name, PyObject *value)
8f0bcc
+{
8f0bcc
+    int res = _PyModule_AddObjectRef(mod, name, value);
8f0bcc
+    if (res == 0) {
8f0bcc
+        Py_DECREF(value);
8f0bcc
+    }
8f0bcc
+    return res;
8f0bcc
+}
93c559
+
8f0bcc
 int
8f0bcc
 PyModule_AddIntConstant(PyObject *m, const char *name, long value)
8f0bcc
 {
8f0bcc
-- 
8f0bcc
2.35.3
8f0bcc
8f0bcc
8f0bcc
From 3fc28233b7244bb891499a974c3f3cda42454760 Mon Sep 17 00:00:00 2001
8f0bcc
From: Petr Viktorin <encukou@gmail.com>
8f0bcc
Date: Fri, 13 Aug 2021 13:16:43 +0200
8f0bcc
Subject: [PATCH 02/10] _hashopenssl: Uncomment and use initialization function
8f0bcc
 list
8f0bcc
8f0bcc
This simplifies backporting of future changes.
8f0bcc
8f0bcc
We use this change instead of Python 3.10's:
8f0bcc
    bpo-1635741: Port _hashlib to multiphase initialization (GH-23358)
8f0bcc
---
8f0bcc
 Modules/_hashopenssl.c | 30 +++++-------------------------
8f0bcc
 1 file changed, 5 insertions(+), 25 deletions(-)
8f0bcc
8f0bcc
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
8f0bcc
index 4db058c..56dfff9 100644
8f0bcc
--- a/Modules/_hashopenssl.c
8f0bcc
+++ b/Modules/_hashopenssl.c
8f0bcc
@@ -2227,7 +2227,6 @@ hashlib_init_hmactype(PyObject *module)
8f0bcc
     return 0;
8f0bcc
 }
93c559
 
8f0bcc
-#if 0
8f0bcc
 static PyModuleDef_Slot hashlib_slots[] = {
8f0bcc
     /* OpenSSL 1.0.2 and LibreSSL */
8f0bcc
     {Py_mod_exec, hashlib_openssl_legacy_init},
8f0bcc
@@ -2238,7 +2237,6 @@ static PyModuleDef_Slot hashlib_slots[] = {
8f0bcc
     {Py_mod_exec, hashlib_md_meth_names},
8f0bcc
     {0, NULL}
8f0bcc
 };
8f0bcc
-#endif
8f0bcc
 
8f0bcc
 static struct PyModuleDef _hashlibmodule = {
8f0bcc
     PyModuleDef_HEAD_INIT,
8f0bcc
@@ -2266,29 +2264,11 @@ PyInit__hashlib(void)
8f0bcc
         return NULL;
8f0bcc
     }
93c559
 
8f0bcc
-    if (hashlib_openssl_legacy_init(m) < 0) {
8f0bcc
-        Py_DECREF(m);
8f0bcc
-        return NULL;
8f0bcc
-    }
8f0bcc
-    if (hashlib_init_hashtable(m) < 0) {
8f0bcc
-        Py_DECREF(m);
8f0bcc
-        return NULL;
8f0bcc
-    }
8f0bcc
-    if (hashlib_init_evptype(m) < 0) {
8f0bcc
-        Py_DECREF(m);
8f0bcc
-        return NULL;
8f0bcc
-    }
8f0bcc
-    if (hashlib_init_evpxoftype(m) < 0) {
8f0bcc
-        Py_DECREF(m);
8f0bcc
-        return NULL;
8f0bcc
-    }
8f0bcc
-    if (hashlib_init_hmactype(m) < 0) {
8f0bcc
-        Py_DECREF(m);
8f0bcc
-        return NULL;
8f0bcc
-    }
8f0bcc
-    if (hashlib_md_meth_names(m) == -1) {
8f0bcc
-        Py_DECREF(m);
8f0bcc
-        return NULL;
8f0bcc
+    for (int i=0; hashlib_slots[i].slot; i++) {
8f0bcc
+        if (((int (*)(PyObject*))hashlib_slots[i].value)(m) < 0) {
8f0bcc
+            Py_DECREF(m);
8f0bcc
+            return NULL;
8f0bcc
+        }
8f0bcc
     }
93c559
 
8f0bcc
     return m;
8f0bcc
-- 
8f0bcc
2.35.3
8f0bcc
8f0bcc
8f0bcc
From 309e06621a9a8b8220c8f83d588cc76e1fa2380d Mon Sep 17 00:00:00 2001
8f0bcc
From: Christian Heimes <christian@python.org>
8f0bcc
Date: Sat, 27 Mar 2021 14:55:03 +0100
8f0bcc
Subject: [PATCH 03/10] bpo-40645: use C implementation of HMAC (GH-24920,
8f0bcc
 GH-25063, GH-26079)
8f0bcc
8f0bcc
This backports the feature and 2 subsequent bugfixes
8f0bcc
from: https://bugs.python.org/issue40645
8f0bcc
8f0bcc
Signed-off-by: Christian Heimes <christian@python.org>
8f0bcc
Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
8f0bcc
Co-Authored-By: Pablo Galindo <Pablogsal@gmail.com>
8f0bcc
---
8f0bcc
 Lib/hashlib.py                                |   1 +
8f0bcc
 Lib/hmac.py                                   |  86 ++++++----
8f0bcc
 Lib/test/test_hmac.py                         | 114 +++++++------
8f0bcc
 .../2021-03-19-10-22-17.bpo-40645.5pXhb-.rst  |   2 +
8f0bcc
 Modules/_hashopenssl.c                        | 150 ++++++++++++++++--
8f0bcc
 Modules/clinic/_hashopenssl.c.h               |  38 +----
8f0bcc
 6 files changed, 265 insertions(+), 126 deletions(-)
8f0bcc
 create mode 100644 Misc/NEWS.d/next/Library/2021-03-19-10-22-17.bpo-40645.5pXhb-.rst
8f0bcc
8f0bcc
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
8f0bcc
index 58c340d..ffa3be0 100644
8f0bcc
--- a/Lib/hashlib.py
8f0bcc
+++ b/Lib/hashlib.py
8f0bcc
@@ -173,6 +173,7 @@ try:
93c559
     algorithms_available = algorithms_available.union(
93c559
             _hashlib.openssl_md_meth_names)
93c559
 except ImportError:
8f0bcc
+    _hashlib = None
93c559
     new = __py_new
93c559
     __get_hash = __get_builtin_constructor
93c559
 
8f0bcc
diff --git a/Lib/hmac.py b/Lib/hmac.py
8f0bcc
index 180bc37..8b4f920 100644
8f0bcc
--- a/Lib/hmac.py
8f0bcc
+++ b/Lib/hmac.py
8f0bcc
@@ -8,11 +8,12 @@ try:
8f0bcc
     import _hashlib as _hashopenssl
8f0bcc
 except ImportError:
8f0bcc
     _hashopenssl = None
8f0bcc
-    _openssl_md_meths = None
8f0bcc
+    _functype = None
8f0bcc
     from _operator import _compare_digest as compare_digest
8f0bcc
 else:
8f0bcc
-    _openssl_md_meths = frozenset(_hashopenssl.openssl_md_meth_names)
8f0bcc
     compare_digest = _hashopenssl.compare_digest
8f0bcc
+    _functype = type(_hashopenssl.openssl_sha256)  # builtin type
8f0bcc
+
8f0bcc
 import hashlib as _hashlib
8f0bcc
 
8f0bcc
 trans_5C = bytes((x ^ 0x5C) for x in range(256))
8f0bcc
@@ -23,7 +24,6 @@ trans_36 = bytes((x ^ 0x36) for x in range(256))
8f0bcc
 digest_size = None
8f0bcc
 
93c559
 
93c559
-
8f0bcc
 class HMAC:
8f0bcc
     """RFC 2104 HMAC class.  Also complies with RFC 4231.
8f0bcc
 
8f0bcc
@@ -32,7 +32,7 @@ class HMAC:
8f0bcc
     blocksize = 64  # 512-bit HMAC; can be changed in subclasses.
8f0bcc
 
8f0bcc
     __slots__ = (
8f0bcc
-        "_digest_cons", "_inner", "_outer", "block_size", "digest_size"
8f0bcc
+        "_hmac", "_inner", "_outer", "block_size", "digest_size"
8f0bcc
     )
8f0bcc
 
8f0bcc
     def __init__(self, key, msg=None, digestmod=''):
8f0bcc
@@ -55,15 +55,30 @@ class HMAC:
8f0bcc
         if not digestmod:
8f0bcc
             raise TypeError("Missing required parameter 'digestmod'.")
8f0bcc
 
8f0bcc
+        if _hashopenssl and isinstance(digestmod, (str, _functype)):
8f0bcc
+            try:
8f0bcc
+                self._init_hmac(key, msg, digestmod)
8f0bcc
+            except _hashopenssl.UnsupportedDigestmodError:
8f0bcc
+                self._init_old(key, msg, digestmod)
8f0bcc
+        else:
8f0bcc
+            self._init_old(key, msg, digestmod)
8f0bcc
+
8f0bcc
+    def _init_hmac(self, key, msg, digestmod):
8f0bcc
+        self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod)
8f0bcc
+        self.digest_size = self._hmac.digest_size
8f0bcc
+        self.block_size = self._hmac.block_size
8f0bcc
+
8f0bcc
+    def _init_old(self, key, msg, digestmod):
8f0bcc
         if callable(digestmod):
8f0bcc
-            self._digest_cons = digestmod
8f0bcc
+            digest_cons = digestmod
8f0bcc
         elif isinstance(digestmod, str):
8f0bcc
-            self._digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
8f0bcc
+            digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
8f0bcc
         else:
8f0bcc
-            self._digest_cons = lambda d=b'': digestmod.new(d)
8f0bcc
+            digest_cons = lambda d=b'': digestmod.new(d)
8f0bcc
 
8f0bcc
-        self._outer = self._digest_cons()
8f0bcc
-        self._inner = self._digest_cons()
8f0bcc
+        self._hmac = None
8f0bcc
+        self._outer = digest_cons()
8f0bcc
+        self._inner = digest_cons()
8f0bcc
         self.digest_size = self._inner.digest_size
8f0bcc
 
8f0bcc
         if hasattr(self._inner, 'block_size'):
8f0bcc
@@ -79,13 +94,13 @@ class HMAC:
8f0bcc
                            RuntimeWarning, 2)
8f0bcc
             blocksize = self.blocksize
8f0bcc
 
8f0bcc
+        if len(key) > blocksize:
8f0bcc
+            key = digest_cons(key).digest()
8f0bcc
+
8f0bcc
         # self.blocksize is the default blocksize. self.block_size is
8f0bcc
         # effective block size as well as the public API attribute.
8f0bcc
         self.block_size = blocksize
8f0bcc
 
8f0bcc
-        if len(key) > blocksize:
8f0bcc
-            key = self._digest_cons(key).digest()
93c559
-
8f0bcc
         key = key.ljust(blocksize, b'\0')
8f0bcc
         self._outer.update(key.translate(trans_5C))
8f0bcc
         self._inner.update(key.translate(trans_36))
8f0bcc
@@ -94,23 +109,15 @@ class HMAC:
8f0bcc
 
8f0bcc
     @property
8f0bcc
     def name(self):
8f0bcc
-        return "hmac-" + self._inner.name
93c559
-
8f0bcc
-    @property
8f0bcc
-    def digest_cons(self):
8f0bcc
-        return self._digest_cons
93c559
-
8f0bcc
-    @property
8f0bcc
-    def inner(self):
8f0bcc
-        return self._inner
93c559
-
8f0bcc
-    @property
8f0bcc
-    def outer(self):
8f0bcc
-        return self._outer
8f0bcc
+        if self._hmac:
8f0bcc
+            return self._hmac.name
8f0bcc
+        else:
8f0bcc
+            return f"hmac-{self._inner.name}"
8f0bcc
 
8f0bcc
     def update(self, msg):
8f0bcc
         """Feed data from msg into this hashing object."""
8f0bcc
-        self._inner.update(msg)
8f0bcc
+        inst = self._hmac or self._inner
8f0bcc
+        inst.update(msg)
8f0bcc
 
8f0bcc
     def copy(self):
8f0bcc
         """Return a separate copy of this hashing object.
8f0bcc
@@ -119,10 +126,14 @@ class HMAC:
8f0bcc
         """
8f0bcc
         # Call __new__ directly to avoid the expensive __init__.
8f0bcc
         other = self.__class__.__new__(self.__class__)
8f0bcc
-        other._digest_cons = self._digest_cons
8f0bcc
         other.digest_size = self.digest_size
8f0bcc
-        other._inner = self._inner.copy()
8f0bcc
-        other._outer = self._outer.copy()
8f0bcc
+        if self._hmac:
8f0bcc
+            other._hmac = self._hmac.copy()
8f0bcc
+            other._inner = other._outer = None
8f0bcc
+        else:
8f0bcc
+            other._hmac = None
8f0bcc
+            other._inner = self._inner.copy()
8f0bcc
+            other._outer = self._outer.copy()
8f0bcc
         return other
8f0bcc
 
8f0bcc
     def _current(self):
8f0bcc
@@ -130,9 +141,12 @@ class HMAC:
8f0bcc
 
8f0bcc
         To be used only internally with digest() and hexdigest().
8f0bcc
         """
8f0bcc
-        h = self._outer.copy()
8f0bcc
-        h.update(self._inner.digest())
8f0bcc
-        return h
8f0bcc
+        if self._hmac:
8f0bcc
+            return self._hmac
8f0bcc
+        else:
8f0bcc
+            h = self._outer.copy()
8f0bcc
+            h.update(self._inner.digest())
8f0bcc
+            return h
8f0bcc
 
8f0bcc
     def digest(self):
8f0bcc
         """Return the hash value of this hashing object.
8f0bcc
@@ -179,9 +193,11 @@ def digest(key, msg, digest):
8f0bcc
             A hashlib constructor returning a new hash object. *OR*
8f0bcc
             A module supporting PEP 247.
8f0bcc
     """
8f0bcc
-    if (_hashopenssl is not None and
8f0bcc
-            isinstance(digest, str) and digest in _openssl_md_meths):
8f0bcc
-        return _hashopenssl.hmac_digest(key, msg, digest)
8f0bcc
+    if _hashopenssl is not None and isinstance(digest, (str, _functype)):
8f0bcc
+        try:
8f0bcc
+            return _hashopenssl.hmac_digest(key, msg, digest)
8f0bcc
+        except _hashopenssl.UnsupportedDigestmodError:
8f0bcc
+            pass
8f0bcc
 
8f0bcc
     if callable(digest):
8f0bcc
         digest_cons = digest
8f0bcc
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
8f0bcc
index 6daf22c..adf52ad 100644
8f0bcc
--- a/Lib/test/test_hmac.py
8f0bcc
+++ b/Lib/test/test_hmac.py
8f0bcc
@@ -11,14 +11,21 @@ from test.support import hashlib_helper
8f0bcc
 from _operator import _compare_digest as operator_compare_digest
93c559
 
93c559
 try:
8f0bcc
+    import _hashlib as _hashopenssl
8f0bcc
     from _hashlib import HMAC as C_HMAC
8f0bcc
     from _hashlib import hmac_new as c_hmac_new
8f0bcc
     from _hashlib import compare_digest as openssl_compare_digest
8f0bcc
 except ImportError:
8f0bcc
+    _hashopenssl = None
8f0bcc
     C_HMAC = None
8f0bcc
     c_hmac_new = None
8f0bcc
     openssl_compare_digest = None
93c559
 
8f0bcc
+try:
8f0bcc
+    import _sha256 as sha256_module
8f0bcc
+except ImportError:
8f0bcc
+    sha256_module = None
8f0bcc
+
8f0bcc
 
8f0bcc
 def ignore_warning(func):
8f0bcc
     @functools.wraps(func)
8f0bcc
@@ -32,22 +39,27 @@ def ignore_warning(func):
8f0bcc
 
8f0bcc
 class TestVectorsTestCase(unittest.TestCase):
8f0bcc
 
8f0bcc
-    def asssert_hmac(
8f0bcc
-        self, key, data, digest, hashfunc, hashname, digest_size, block_size
8f0bcc
+    def assert_hmac_internals(
8f0bcc
+            self, h, digest, hashname, digest_size, block_size
8f0bcc
     ):
8f0bcc
-        h = hmac.HMAC(key, data, digestmod=hashfunc)
8f0bcc
         self.assertEqual(h.hexdigest().upper(), digest.upper())
8f0bcc
         self.assertEqual(h.digest(), binascii.unhexlify(digest))
8f0bcc
         self.assertEqual(h.name, f"hmac-{hashname}")
8f0bcc
         self.assertEqual(h.digest_size, digest_size)
8f0bcc
         self.assertEqual(h.block_size, block_size)
8f0bcc
 
8f0bcc
+    def assert_hmac(
8f0bcc
+        self, key, data, digest, hashfunc, hashname, digest_size, block_size
8f0bcc
+    ):
8f0bcc
+        h = hmac.HMAC(key, data, digestmod=hashfunc)
8f0bcc
+        self.assert_hmac_internals(
8f0bcc
+            h, digest, hashname, digest_size, block_size
8f0bcc
+        )
8f0bcc
+
8f0bcc
         h = hmac.HMAC(key, data, digestmod=hashname)
8f0bcc
-        self.assertEqual(h.hexdigest().upper(), digest.upper())
8f0bcc
-        self.assertEqual(h.digest(), binascii.unhexlify(digest))
8f0bcc
-        self.assertEqual(h.name, f"hmac-{hashname}")
8f0bcc
-        self.assertEqual(h.digest_size, digest_size)
8f0bcc
-        self.assertEqual(h.block_size, block_size)
8f0bcc
+        self.assert_hmac_internals(
8f0bcc
+            h, digest, hashname, digest_size, block_size
8f0bcc
+        )
8f0bcc
 
8f0bcc
         h = hmac.HMAC(key, digestmod=hashname)
8f0bcc
         h2 = h.copy()
8f0bcc
@@ -56,11 +68,9 @@ class TestVectorsTestCase(unittest.TestCase):
8f0bcc
         self.assertEqual(h.hexdigest().upper(), digest.upper())
8f0bcc
 
8f0bcc
         h = hmac.new(key, data, digestmod=hashname)
8f0bcc
-        self.assertEqual(h.hexdigest().upper(), digest.upper())
8f0bcc
-        self.assertEqual(h.digest(), binascii.unhexlify(digest))
8f0bcc
-        self.assertEqual(h.name, f"hmac-{hashname}")
8f0bcc
-        self.assertEqual(h.digest_size, digest_size)
8f0bcc
-        self.assertEqual(h.block_size, block_size)
8f0bcc
+        self.assert_hmac_internals(
8f0bcc
+            h, digest, hashname, digest_size, block_size
8f0bcc
+        )
8f0bcc
 
8f0bcc
         h = hmac.new(key, None, digestmod=hashname)
8f0bcc
         h.update(data)
8f0bcc
@@ -81,23 +91,18 @@ class TestVectorsTestCase(unittest.TestCase):
8f0bcc
             hmac.digest(key, data, digest=hashfunc),
8f0bcc
             binascii.unhexlify(digest)
8f0bcc
         )
8f0bcc
-        with unittest.mock.patch('hmac._openssl_md_meths', {}):
8f0bcc
-            self.assertEqual(
8f0bcc
-                hmac.digest(key, data, digest=hashname),
8f0bcc
-                binascii.unhexlify(digest)
8f0bcc
-            )
8f0bcc
-            self.assertEqual(
8f0bcc
-                hmac.digest(key, data, digest=hashfunc),
8f0bcc
-                binascii.unhexlify(digest)
8f0bcc
-            )
93c559
+
8f0bcc
+        h = hmac.HMAC.__new__(hmac.HMAC)
8f0bcc
+        h._init_old(key, data, digestmod=hashname)
8f0bcc
+        self.assert_hmac_internals(
8f0bcc
+            h, digest, hashname, digest_size, block_size
8f0bcc
+        )
8f0bcc
 
8f0bcc
         if c_hmac_new is not None:
8f0bcc
             h = c_hmac_new(key, data, digestmod=hashname)
8f0bcc
-            self.assertEqual(h.hexdigest().upper(), digest.upper())
8f0bcc
-            self.assertEqual(h.digest(), binascii.unhexlify(digest))
8f0bcc
-            self.assertEqual(h.name, f"hmac-{hashname}")
8f0bcc
-            self.assertEqual(h.digest_size, digest_size)
8f0bcc
-            self.assertEqual(h.block_size, block_size)
8f0bcc
+            self.assert_hmac_internals(
8f0bcc
+                h, digest, hashname, digest_size, block_size
8f0bcc
+            )
8f0bcc
 
8f0bcc
             h = c_hmac_new(key, digestmod=hashname)
8f0bcc
             h2 = h.copy()
8f0bcc
@@ -105,12 +110,24 @@ class TestVectorsTestCase(unittest.TestCase):
8f0bcc
             h.update(data)
8f0bcc
             self.assertEqual(h.hexdigest().upper(), digest.upper())
8f0bcc
 
8f0bcc
+            func = getattr(_hashopenssl, f"openssl_{hashname}")
8f0bcc
+            h = c_hmac_new(key, data, digestmod=func)
8f0bcc
+            self.assert_hmac_internals(
8f0bcc
+                h, digest, hashname, digest_size, block_size
8f0bcc
+            )
93c559
+
8f0bcc
+            h = hmac.HMAC.__new__(hmac.HMAC)
8f0bcc
+            h._init_hmac(key, data, digestmod=hashname)
8f0bcc
+            self.assert_hmac_internals(
8f0bcc
+                h, digest, hashname, digest_size, block_size
8f0bcc
+            )
93c559
+
8f0bcc
     @hashlib_helper.requires_hashdigest('md5', openssl=True)
8f0bcc
     def test_md5_vectors(self):
8f0bcc
         # Test the HMAC module against test vectors from the RFC.
8f0bcc
 
8f0bcc
         def md5test(key, data, digest):
8f0bcc
-            self.asssert_hmac(
8f0bcc
+            self.assert_hmac(
8f0bcc
                 key, data, digest,
8f0bcc
                 hashfunc=hashlib.md5,
8f0bcc
                 hashname="md5",
8f0bcc
@@ -150,7 +167,7 @@ class TestVectorsTestCase(unittest.TestCase):
8f0bcc
     @hashlib_helper.requires_hashdigest('sha1', openssl=True)
8f0bcc
     def test_sha_vectors(self):
8f0bcc
         def shatest(key, data, digest):
8f0bcc
-            self.asssert_hmac(
8f0bcc
+            self.assert_hmac(
8f0bcc
                 key, data, digest,
8f0bcc
                 hashfunc=hashlib.sha1,
8f0bcc
                 hashname="sha1",
8f0bcc
@@ -191,7 +208,7 @@ class TestVectorsTestCase(unittest.TestCase):
8f0bcc
         def hmactest(key, data, hexdigests):
8f0bcc
             digest = hexdigests[hashfunc]
8f0bcc
 
8f0bcc
-            self.asssert_hmac(
8f0bcc
+            self.assert_hmac(
8f0bcc
                 key, data, digest,
8f0bcc
                 hashfunc=hashfunc,
8f0bcc
                 hashname=hash_name,
8f0bcc
@@ -427,6 +444,15 @@ class ConstructorTestCase(unittest.TestCase):
8f0bcc
         ):
8f0bcc
             C_HMAC()
8f0bcc
 
8f0bcc
+    @unittest.skipUnless(sha256_module is not None, 'need _sha256')
8f0bcc
+    def test_with_sha256_module(self):
8f0bcc
+        h = hmac.HMAC(b"key", b"hash this!", digestmod=sha256_module.sha256)
8f0bcc
+        self.assertEqual(h.hexdigest(), self.expected)
8f0bcc
+        self.assertEqual(h.name, "hmac-sha256")
93c559
+
8f0bcc
+        digest = hmac.digest(b"key", b"hash this!", sha256_module.sha256)
8f0bcc
+        self.assertEqual(digest, binascii.unhexlify(self.expected))
93c559
+
8f0bcc
 
8f0bcc
 class SanityTestCase(unittest.TestCase):
8f0bcc
 
8f0bcc
@@ -447,21 +473,21 @@ class SanityTestCase(unittest.TestCase):
8f0bcc
 class CopyTestCase(unittest.TestCase):
8f0bcc
 
8f0bcc
     @hashlib_helper.requires_hashdigest('sha256')
8f0bcc
-    def test_attributes(self):
8f0bcc
+    def test_attributes_old(self):
8f0bcc
         # Testing if attributes are of same type.
8f0bcc
-        h1 = hmac.HMAC(b"key", digestmod="sha256")
8f0bcc
+        h1 = hmac.HMAC.__new__(hmac.HMAC)
8f0bcc
+        h1._init_old(b"key", b"msg", digestmod="sha256")
8f0bcc
         h2 = h1.copy()
8f0bcc
-        self.assertTrue(h1._digest_cons == h2._digest_cons,
8f0bcc
-            "digest constructors don't match.")
8f0bcc
         self.assertEqual(type(h1._inner), type(h2._inner),
8f0bcc
             "Types of inner don't match.")
8f0bcc
         self.assertEqual(type(h1._outer), type(h2._outer),
8f0bcc
             "Types of outer don't match.")
8f0bcc
 
8f0bcc
     @hashlib_helper.requires_hashdigest('sha256')
8f0bcc
-    def test_realcopy(self):
8f0bcc
+    def test_realcopy_old(self):
8f0bcc
         # Testing if the copy method created a real copy.
8f0bcc
-        h1 = hmac.HMAC(b"key", digestmod="sha256")
8f0bcc
+        h1 = hmac.HMAC.__new__(hmac.HMAC)
8f0bcc
+        h1._init_old(b"key", b"msg", digestmod="sha256")
8f0bcc
         h2 = h1.copy()
8f0bcc
         # Using id() in case somebody has overridden __eq__/__ne__.
8f0bcc
         self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.")
8f0bcc
@@ -469,17 +495,15 @@ class CopyTestCase(unittest.TestCase):
8f0bcc
             "No real copy of the attribute 'inner'.")
8f0bcc
         self.assertTrue(id(h1._outer) != id(h2._outer),
8f0bcc
             "No real copy of the attribute 'outer'.")
8f0bcc
-        self.assertEqual(h1._inner, h1.inner)
8f0bcc
-        self.assertEqual(h1._outer, h1.outer)
8f0bcc
-        self.assertEqual(h1._digest_cons, h1.digest_cons)
8f0bcc
+        self.assertIs(h1._hmac, None)
8f0bcc
 
8f0bcc
+    @unittest.skipIf(_hashopenssl is None, "test requires _hashopenssl")
8f0bcc
     @hashlib_helper.requires_hashdigest('sha256')
8f0bcc
-    def test_properties(self):
8f0bcc
-        # deprecated properties
8f0bcc
-        h1 = hmac.HMAC(b"key", digestmod="sha256")
8f0bcc
-        self.assertEqual(h1._inner, h1.inner)
8f0bcc
-        self.assertEqual(h1._outer, h1.outer)
8f0bcc
-        self.assertEqual(h1._digest_cons, h1.digest_cons)
8f0bcc
+    def test_realcopy_hmac(self):
8f0bcc
+        h1 = hmac.HMAC.__new__(hmac.HMAC)
8f0bcc
+        h1._init_hmac(b"key", b"msg", digestmod="sha256")
8f0bcc
+        h2 = h1.copy()
8f0bcc
+        self.assertTrue(id(h1._hmac) != id(h2._hmac))
8f0bcc
 
8f0bcc
     @hashlib_helper.requires_hashdigest('sha256')
8f0bcc
     def test_equality(self):
8f0bcc
diff --git a/Misc/NEWS.d/next/Library/2021-03-19-10-22-17.bpo-40645.5pXhb-.rst b/Misc/NEWS.d/next/Library/2021-03-19-10-22-17.bpo-40645.5pXhb-.rst
8f0bcc
new file mode 100644
8f0bcc
index 0000000..a9ab1c0
8f0bcc
--- /dev/null
8f0bcc
+++ b/Misc/NEWS.d/next/Library/2021-03-19-10-22-17.bpo-40645.5pXhb-.rst
8f0bcc
@@ -0,0 +1,2 @@
8f0bcc
+The :mod:`hmac` module now uses OpenSSL's HMAC implementation when digestmod
8f0bcc
+argument is a hash name or builtin hash function.
8f0bcc
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
8f0bcc
index 56dfff9..ca9fea9 100644
8f0bcc
--- a/Modules/_hashopenssl.c
8f0bcc
+++ b/Modules/_hashopenssl.c
8f0bcc
@@ -260,6 +260,8 @@ typedef struct {
8f0bcc
     PyTypeObject *EVPXOFtype;
8f0bcc
 #endif
8f0bcc
     _Py_hashtable_t *hashtable;
8f0bcc
+    PyObject *constructs;
8f0bcc
+    PyObject *unsupported_digestmod_error;
8f0bcc
 } _hashlibstate;
8f0bcc
 
8f0bcc
 static inline _hashlibstate*
8f0bcc
@@ -420,6 +422,48 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
8f0bcc
     return digest;
8f0bcc
 }
8f0bcc
 
8f0bcc
+/* Get digest EVP from object
8f0bcc
+ *
8f0bcc
+ * * string
8f0bcc
+ * * _hashopenssl builtin function
8f0bcc
+ *
8f0bcc
+ * on error returns NULL with exception set.
8f0bcc
+ */
8f0bcc
+static PY_EVP_MD*
8f0bcc
+py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type py_ht) {
8f0bcc
+    PY_EVP_MD* evp;
8f0bcc
+    PyObject *name_obj = NULL;
8f0bcc
+    const char *name;
8f0bcc
+
8f0bcc
+    if (PyUnicode_Check(digestmod)) {
8f0bcc
+        name_obj = digestmod;
8f0bcc
+    } else {
8f0bcc
+        _hashlibstate *state = get_hashlib_state(module);
8f0bcc
+        // borrowed ref
8f0bcc
+        name_obj = PyDict_GetItem(state->constructs, digestmod);
93c559
+    }
8f0bcc
+    if (name_obj == NULL) {
8f0bcc
+        _hashlibstate *state = get_hashlib_state(module);
8f0bcc
+        PyErr_Clear();
8f0bcc
+        PyErr_Format(
8f0bcc
+            state->unsupported_digestmod_error,
8f0bcc
+            "Unsupported digestmod %R", digestmod);
8f0bcc
+        return NULL;
93c559
+    }
93c559
+
8f0bcc
+    name = PyUnicode_AsUTF8(name_obj);
8f0bcc
+    if (name == NULL) {
8f0bcc
+        return NULL;
8f0bcc
+    }
93c559
+
8f0bcc
+    evp = py_digest_by_name(module, name, py_ht);
8f0bcc
+    if (evp == NULL) {
8f0bcc
+        return NULL;
93c559
+    }
93c559
+
8f0bcc
+    return evp;
8f0bcc
+}
93c559
+
8f0bcc
 static EVPobject *
8f0bcc
 newEVPobject(PyTypeObject *type)
8f0bcc
 {
8f0bcc
@@ -1238,7 +1282,6 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name,
93c559
 
8f0bcc
     PY_EVP_MD *digest = py_digest_by_name(module, hash_name, Py_ht_pbkdf2);
8f0bcc
     if (digest == NULL) {
8f0bcc
-        PyErr_SetString(PyExc_ValueError, "unsupported hash type");
8f0bcc
         goto end;
8f0bcc
     }
93c559
 
8f0bcc
@@ -1443,25 +1486,21 @@ _hashlib.hmac_digest as _hashlib_hmac_singleshot
93c559
 
8f0bcc
     key: Py_buffer
8f0bcc
     msg: Py_buffer
8f0bcc
-    digest: str
8f0bcc
+    digest: object
93c559
 
8f0bcc
 Single-shot HMAC.
8f0bcc
 [clinic start generated code]*/
93c559
 
8f0bcc
 static PyObject *
8f0bcc
 _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
8f0bcc
-                              Py_buffer *msg, const char *digest)
8f0bcc
-/*[clinic end generated code: output=15658ede5ab98185 input=019dffc571909a46]*/
8f0bcc
+                              Py_buffer *msg, PyObject *digest)
8f0bcc
+/*[clinic end generated code: output=82f19965d12706ac input=0a0790cc3db45c2e]*/
8f0bcc
 {
8f0bcc
     unsigned char md[EVP_MAX_MD_SIZE] = {0};
8f0bcc
     unsigned int md_len = 0;
8f0bcc
     unsigned char *result;
8f0bcc
     PY_EVP_MD *evp;
93c559
 
8f0bcc
-    evp = py_digest_by_name(module, digest, Py_ht_mac);
8f0bcc
-    if (evp == NULL) {
8f0bcc
-        return NULL;
8f0bcc
-    }
8f0bcc
     if (key->len > INT_MAX) {
8f0bcc
         PyErr_SetString(PyExc_OverflowError,
8f0bcc
                         "key is too long.");
8f0bcc
@@ -1473,7 +1512,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
8f0bcc
         return NULL;
8f0bcc
     }
93c559
 
8f0bcc
-    evp = py_digest_by_name(module, digest, Py_ht_mac);
8f0bcc
+    evp = py_digest_by_digestmod(module, digest, Py_ht_mac);
8f0bcc
     if (evp == NULL) {
93c559
         return NULL;
8f0bcc
     }
8f0bcc
@@ -1505,15 +1544,15 @@ _hashlib.hmac_new
93c559
 
8f0bcc
     key: Py_buffer
8f0bcc
     msg as msg_obj: object(c_default="NULL") = b''
8f0bcc
-    digestmod: str(c_default="NULL") = None
8f0bcc
+    digestmod: object(c_default="NULL") = None
93c559
 
8f0bcc
 Return a new hmac object.
8f0bcc
 [clinic start generated code]*/
93c559
 
8f0bcc
 static PyObject *
8f0bcc
 _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
8f0bcc
-                       const char *digestmod)
8f0bcc
-/*[clinic end generated code: output=9a35673be0cbea1b input=a0878868eb190134]*/
8f0bcc
+                       PyObject *digestmod)
8f0bcc
+/*[clinic end generated code: output=c20d9e4d9ed6d219 input=5f4071dcc7f34362]*/
93c559
 {
8f0bcc
     PyTypeObject *type = get_hashlib_state(module)->HMACtype;
8f0bcc
     PY_EVP_MD *digest;
8f0bcc
@@ -1527,14 +1566,14 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
8f0bcc
         return NULL;
8f0bcc
     }
93c559
 
8f0bcc
-    if ((digestmod == NULL) || !strlen(digestmod)) {
8f0bcc
+    if (digestmod == NULL) {
8f0bcc
         PyErr_SetString(
8f0bcc
             PyExc_TypeError, "Missing required parameter 'digestmod'.");
8f0bcc
         return NULL;
8f0bcc
     }
93c559
 
8f0bcc
-    digest = py_digest_by_name(module, digestmod, Py_ht_mac);
8f0bcc
-    if (!digest) {
8f0bcc
+    digest = py_digest_by_digestmod(module, digestmod, Py_ht_mac);
8f0bcc
+    if (digest == NULL) {
8f0bcc
         return NULL;
8f0bcc
     }
93c559
 
8f0bcc
@@ -2117,6 +2156,8 @@ hashlib_traverse(PyObject *m, visitproc visit, void *arg)
8f0bcc
 #ifdef PY_OPENSSL_HAS_SHAKE
8f0bcc
     Py_VISIT(state->EVPXOFtype);
8f0bcc
 #endif
8f0bcc
+    Py_VISIT(state->constructs);
8f0bcc
+    Py_VISIT(state->unsupported_digestmod_error);
8f0bcc
     return 0;
8f0bcc
 }
93c559
 
8f0bcc
@@ -2129,10 +2170,14 @@ hashlib_clear(PyObject *m)
8f0bcc
 #ifdef PY_OPENSSL_HAS_SHAKE
8f0bcc
     Py_CLEAR(state->EVPXOFtype);
8f0bcc
 #endif
8f0bcc
+    Py_CLEAR(state->constructs);
8f0bcc
+    Py_CLEAR(state->unsupported_digestmod_error);
8f0bcc
+
8f0bcc
     if (state->hashtable != NULL) {
8f0bcc
         _Py_hashtable_destroy(state->hashtable);
8f0bcc
         state->hashtable = NULL;
8f0bcc
     }
8f0bcc
+
8f0bcc
     return 0;
8f0bcc
 }
93c559
 
8f0bcc
@@ -2227,6 +2272,79 @@ hashlib_init_hmactype(PyObject *module)
8f0bcc
     return 0;
8f0bcc
 }
93c559
 
8f0bcc
+static int
8f0bcc
+hashlib_init_constructors(PyObject *module)
8f0bcc
+{
8f0bcc
+    /* Create dict from builtin openssl_hash functions to name
8f0bcc
+     * {_hashlib.openssl_sha256: "sha256", ...}
8f0bcc
+     */
8f0bcc
+    PyModuleDef *mdef;
8f0bcc
+    PyMethodDef *fdef;
8f0bcc
+    PyObject *proxy;
8f0bcc
+    PyObject *func, *name_obj;
8f0bcc
+    _hashlibstate *state = get_hashlib_state(module);
8f0bcc
+
8f0bcc
+    mdef = PyModule_GetDef(module);
8f0bcc
+    if (mdef == NULL) {
8f0bcc
+        return -1;
8f0bcc
+    }
93c559
+
8f0bcc
+    state->constructs = PyDict_New();
8f0bcc
+    if (state->constructs == NULL) {
8f0bcc
+        return -1;
8f0bcc
+    }
8f0bcc
+
8f0bcc
+    for (fdef = mdef->m_methods; fdef->ml_name != NULL; fdef++) {
8f0bcc
+        if (strncmp(fdef->ml_name, "openssl_", 8)) {
8f0bcc
+            continue;
8f0bcc
+        }
8f0bcc
+        name_obj = PyUnicode_FromString(fdef->ml_name + 8);
8f0bcc
+        if (name_obj == NULL) {
8f0bcc
+            return -1;
8f0bcc
+        }
8f0bcc
+        func  = PyObject_GetAttrString(module, fdef->ml_name);
8f0bcc
+        if (func == NULL) {
8f0bcc
+            Py_DECREF(name_obj);
8f0bcc
+            return -1;
8f0bcc
+        }
8f0bcc
+        int rc = PyDict_SetItem(state->constructs, func, name_obj);
8f0bcc
+        Py_DECREF(func);
8f0bcc
+        Py_DECREF(name_obj);
8f0bcc
+        if (rc < 0) {
8f0bcc
+            return -1;
93c559
+        }
8f0bcc
+    }
93c559
+
8f0bcc
+    proxy = PyDictProxy_New(state->constructs);
8f0bcc
+    if (proxy == NULL) {
8f0bcc
+        return -1;
8f0bcc
+    }
93c559
+
8f0bcc
+    int rc = _PyModule_AddObjectRef(module, "_constructors", proxy);
8f0bcc
+    Py_DECREF(proxy);
8f0bcc
+    if (rc < 0) {
8f0bcc
+        return -1;
8f0bcc
+    }
8f0bcc
+    return 0;
8f0bcc
+}
93c559
+
8f0bcc
+static int
8f0bcc
+hashlib_exception(PyObject *module)
8f0bcc
+{
8f0bcc
+    _hashlibstate *state = get_hashlib_state(module);
8f0bcc
+    state->unsupported_digestmod_error = PyErr_NewException(
8f0bcc
+        "_hashlib.UnsupportedDigestmodError", PyExc_ValueError, NULL);
8f0bcc
+    if (state->unsupported_digestmod_error == NULL) {
8f0bcc
+        return -1;
8f0bcc
+    }
8f0bcc
+    if (_PyModule_AddObjectRef(module, "UnsupportedDigestmodError",
8f0bcc
+                              state->unsupported_digestmod_error) < 0) {
8f0bcc
+        return -1;
8f0bcc
+    }
8f0bcc
+    return 0;
8f0bcc
+}
93c559
+
8f0bcc
+
8f0bcc
 static PyModuleDef_Slot hashlib_slots[] = {
8f0bcc
     /* OpenSSL 1.0.2 and LibreSSL */
8f0bcc
     {Py_mod_exec, hashlib_openssl_legacy_init},
8f0bcc
@@ -2235,6 +2353,8 @@ static PyModuleDef_Slot hashlib_slots[] = {
8f0bcc
     {Py_mod_exec, hashlib_init_evpxoftype},
8f0bcc
     {Py_mod_exec, hashlib_init_hmactype},
8f0bcc
     {Py_mod_exec, hashlib_md_meth_names},
8f0bcc
+    {Py_mod_exec, hashlib_init_constructors},
8f0bcc
+    {Py_mod_exec, hashlib_exception},
8f0bcc
     {0, NULL}
8f0bcc
 };
93c559
 
8f0bcc
diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h
8f0bcc
index 68aa765..4466ec4 100644
8f0bcc
--- a/Modules/clinic/_hashopenssl.c.h
8f0bcc
+++ b/Modules/clinic/_hashopenssl.c.h
8f0bcc
@@ -1106,7 +1106,7 @@ PyDoc_STRVAR(_hashlib_hmac_singleshot__doc__,
93c559
 
8f0bcc
 static PyObject *
8f0bcc
 _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
8f0bcc
-                              Py_buffer *msg, const char *digest);
8f0bcc
+                              Py_buffer *msg, PyObject *digest);
8f0bcc
 
8f0bcc
 static PyObject *
8f0bcc
 _hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
8f0bcc
@@ -1117,7 +1117,7 @@ _hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nar
8f0bcc
     PyObject *argsbuf[3];
8f0bcc
     Py_buffer key = {NULL, NULL};
8f0bcc
     Py_buffer msg = {NULL, NULL};
8f0bcc
-    const char *digest;
8f0bcc
+    PyObject *digest;
8f0bcc
 
8f0bcc
     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf);
8f0bcc
     if (!args) {
8f0bcc
@@ -1137,19 +1137,7 @@ _hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nar
8f0bcc
         _PyArg_BadArgument("hmac_digest", "argument 'msg'", "contiguous buffer", args[1]);
8f0bcc
         goto exit;
8f0bcc
     }
8f0bcc
-    if (!PyUnicode_Check(args[2])) {
8f0bcc
-        _PyArg_BadArgument("hmac_digest", "argument 'digest'", "str", args[2]);
8f0bcc
-        goto exit;
8f0bcc
-    }
8f0bcc
-    Py_ssize_t digest_length;
8f0bcc
-    digest = PyUnicode_AsUTF8AndSize(args[2], &digest_length);
8f0bcc
-    if (digest == NULL) {
8f0bcc
-        goto exit;
8f0bcc
-    }
8f0bcc
-    if (strlen(digest) != (size_t)digest_length) {
8f0bcc
-        PyErr_SetString(PyExc_ValueError, "embedded null character");
8f0bcc
-        goto exit;
8f0bcc
-    }
8f0bcc
+    digest = args[2];
8f0bcc
     return_value = _hashlib_hmac_singleshot_impl(module, &key, &msg, digest);
8f0bcc
 
8f0bcc
 exit:
8f0bcc
@@ -1176,7 +1164,7 @@ PyDoc_STRVAR(_hashlib_hmac_new__doc__,
8f0bcc
 
8f0bcc
 static PyObject *
8f0bcc
 _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
8f0bcc
-                       const char *digestmod);
8f0bcc
+                       PyObject *digestmod);
8f0bcc
 
8f0bcc
 static PyObject *
8f0bcc
 _hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
8f0bcc
@@ -1188,7 +1176,7 @@ _hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
8f0bcc
     Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
8f0bcc
     Py_buffer key = {NULL, NULL};
8f0bcc
     PyObject *msg_obj = NULL;
8f0bcc
-    const char *digestmod = NULL;
8f0bcc
+    PyObject *digestmod = NULL;
8f0bcc
 
8f0bcc
     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf);
8f0bcc
     if (!args) {
8f0bcc
@@ -1210,19 +1198,7 @@ _hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
8f0bcc
             goto skip_optional_pos;
8f0bcc
         }
8f0bcc
     }
8f0bcc
-    if (!PyUnicode_Check(args[2])) {
8f0bcc
-        _PyArg_BadArgument("hmac_new", "argument 'digestmod'", "str", args[2]);
8f0bcc
-        goto exit;
8f0bcc
-    }
8f0bcc
-    Py_ssize_t digestmod_length;
8f0bcc
-    digestmod = PyUnicode_AsUTF8AndSize(args[2], &digestmod_length);
8f0bcc
-    if (digestmod == NULL) {
8f0bcc
-        goto exit;
8f0bcc
-    }
8f0bcc
-    if (strlen(digestmod) != (size_t)digestmod_length) {
8f0bcc
-        PyErr_SetString(PyExc_ValueError, "embedded null character");
8f0bcc
-        goto exit;
8f0bcc
-    }
8f0bcc
+    digestmod = args[2];
8f0bcc
 skip_optional_pos:
8f0bcc
     return_value = _hashlib_hmac_new_impl(module, &key, msg_obj, digestmod);
93c559
 
8f0bcc
@@ -1442,4 +1418,4 @@ exit:
8f0bcc
 #ifndef _HASHLIB_GET_FIPS_MODE_METHODDEF
8f0bcc
     #define _HASHLIB_GET_FIPS_MODE_METHODDEF
8f0bcc
 #endif /* !defined(_HASHLIB_GET_FIPS_MODE_METHODDEF) */
8f0bcc
-/*[clinic end generated code: output=b6b280e46bf0b139 input=a9049054013a1b77]*/
8f0bcc
+/*[clinic end generated code: output=7ff9aad0bd53e7ce input=a9049054013a1b77]*/
93c559
-- 
8f0bcc
2.35.3
93c559
93c559
8f0bcc
From 2656f4998c17d8a63b5b45462a2dae5b1b3d520f Mon Sep 17 00:00:00 2001
93c559
From: Charalampos Stratakis <cstratak@redhat.com>
93c559
Date: Thu, 12 Dec 2019 16:58:31 +0100
8f0bcc
Subject: [PATCH 04/10] Expose blake2b and blake2s hashes from OpenSSL
93c559
8f0bcc
These aren't as powerful as Python's own implementation, but they can be
8f0bcc
used under FIPS.
93c559
---
8f0bcc
 Lib/test/test_hashlib.py        |   6 ++
8f0bcc
 Modules/_hashopenssl.c          |  37 +++++++++++
93c559
 Modules/clinic/_hashopenssl.c.h | 106 +++++++++++++++++++++++++++++++-
8f0bcc
 3 files changed, 148 insertions(+), 1 deletion(-)
93c559
8f0bcc
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
8f0bcc
index f845c7a..7aaeb76 100644
8f0bcc
--- a/Lib/test/test_hashlib.py
8f0bcc
+++ b/Lib/test/test_hashlib.py
8f0bcc
@@ -363,6 +363,12 @@ class HashLibTestCase(unittest.TestCase):
8f0bcc
         # 2 is for hashlib.name(...) and hashlib.new(name, ...)
8f0bcc
         self.assertGreaterEqual(len(constructors), 2)
8f0bcc
         for hash_object_constructor in constructors:
8f0bcc
+
8f0bcc
+            # OpenSSL's blake2s & blake2d don't support `key`
8f0bcc
+            _name = hash_object_constructor.__name__
8f0bcc
+            if 'key' in kwargs and _name.startswith('openssl_blake2'):
8f0bcc
+                return
8f0bcc
+
8f0bcc
             m = hash_object_constructor(data, **kwargs)
8f0bcc
             computed = m.hexdigest() if not shake else m.hexdigest(length)
8f0bcc
             self.assertEqual(
93c559
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
8f0bcc
index ca9fea9..9d98d20 100644
93c559
--- a/Modules/_hashopenssl.c
93c559
+++ b/Modules/_hashopenssl.c
8f0bcc
@@ -1138,6 +1138,41 @@ _hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj,
93c559
 }
93c559
 
93c559
 
93c559
+/*[clinic input]
93c559
+_hashlib.openssl_blake2b
93c559
+    string as data_obj: object(py_default="b''") = NULL
93c559
+    *
93c559
+    usedforsecurity: bool = True
93c559
+Returns a blake2b hash object; optionally initialized with a string
93c559
+[clinic start generated code]*/
93c559
+
93c559
+static PyObject *
93c559
+_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj,
93c559
+                              int usedforsecurity)
93c559
+/*[clinic end generated code: output=7a838b1643cde13e input=4ad7fd54268f3689]*/
93c559
+
93c559
+{
8f0bcc
+    return py_evp_fromname(module, Py_hash_blake2b, data_obj, usedforsecurity);
93c559
+}
93c559
+
93c559
+/*[clinic input]
93c559
+_hashlib.openssl_blake2s
93c559
+    string as data_obj: object(py_default="b''") = NULL
93c559
+    *
93c559
+    usedforsecurity: bool = True
93c559
+Returns a blake2s hash object; optionally initialized with a string
93c559
+[clinic start generated code]*/
93c559
+
93c559
+static PyObject *
93c559
+_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj,
93c559
+                              int usedforsecurity)
93c559
+/*[clinic end generated code: output=4eda6b40757471da input=1ed39481ffa4e26a]*/
93c559
+
93c559
+{
8f0bcc
+    return py_evp_fromname(module, Py_hash_blake2s, data_obj, usedforsecurity);
93c559
+}
93c559
+
93c559
+
93c559
 #ifdef PY_OPENSSL_HAS_SHA3
93c559
 
93c559
 /*[clinic input]
8f0bcc
@@ -2135,6 +2170,8 @@ static struct PyMethodDef EVP_functions[] = {
93c559
     _HASHLIB_OPENSSL_SHA256_METHODDEF
93c559
     _HASHLIB_OPENSSL_SHA384_METHODDEF
93c559
     _HASHLIB_OPENSSL_SHA512_METHODDEF
93c559
+    _HASHLIB_OPENSSL_BLAKE2B_METHODDEF
93c559
+    _HASHLIB_OPENSSL_BLAKE2S_METHODDEF
93c559
     _HASHLIB_OPENSSL_SHA3_224_METHODDEF
93c559
     _HASHLIB_OPENSSL_SHA3_256_METHODDEF
93c559
     _HASHLIB_OPENSSL_SHA3_384_METHODDEF
93c559
diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h
8f0bcc
index 4466ec4..54c22b2 100644
93c559
--- a/Modules/clinic/_hashopenssl.c.h
93c559
+++ b/Modules/clinic/_hashopenssl.c.h
93c559
@@ -540,6 +540,110 @@ exit:
93c559
     return return_value;
93c559
 }
93c559
 
93c559
+PyDoc_STRVAR(_hashlib_openssl_blake2b__doc__,
93c559
+"openssl_blake2b($module, /, string=b\'\', *, usedforsecurity=True)\n"
93c559
+"--\n"
93c559
+"\n"
93c559
+"Returns a blake2b hash object; optionally initialized with a string");
93c559
+
93c559
+#define _HASHLIB_OPENSSL_BLAKE2B_METHODDEF    \
93c559
+    {"openssl_blake2b", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2b, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2b__doc__},
93c559
+
93c559
+static PyObject *
93c559
+_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj,
93c559
+                              int usedforsecurity);
93c559
+
93c559
+static PyObject *
93c559
+_hashlib_openssl_blake2b(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
93c559
+{
93c559
+    PyObject *return_value = NULL;
93c559
+    static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
93c559
+    static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2b", 0};
93c559
+    PyObject *argsbuf[2];
93c559
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
93c559
+    PyObject *data_obj = NULL;
93c559
+    int usedforsecurity = 1;
93c559
+
93c559
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf);
93c559
+    if (!args) {
93c559
+        goto exit;
93c559
+    }
93c559
+    if (!noptargs) {
93c559
+        goto skip_optional_pos;
93c559
+    }
93c559
+    if (args[0]) {
93c559
+        data_obj = args[0];
93c559
+        if (!--noptargs) {
93c559
+            goto skip_optional_pos;
93c559
+        }
93c559
+    }
93c559
+skip_optional_pos:
93c559
+    if (!noptargs) {
93c559
+        goto skip_optional_kwonly;
93c559
+    }
93c559
+    usedforsecurity = PyObject_IsTrue(args[1]);
93c559
+    if (usedforsecurity < 0) {
93c559
+        goto exit;
93c559
+    }
93c559
+skip_optional_kwonly:
93c559
+    return_value = _hashlib_openssl_blake2b_impl(module, data_obj, usedforsecurity);
93c559
+
93c559
+exit:
93c559
+    return return_value;
93c559
+}
93c559
+
93c559
+PyDoc_STRVAR(_hashlib_openssl_blake2s__doc__,
93c559
+"openssl_blake2s($module, /, string=b\'\', *, usedforsecurity=True)\n"
93c559
+"--\n"
93c559
+"\n"
93c559
+"Returns a blake2s hash object; optionally initialized with a string");
93c559
+
93c559
+#define _HASHLIB_OPENSSL_BLAKE2S_METHODDEF    \
93c559
+    {"openssl_blake2s", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2s, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2s__doc__},
93c559
+
93c559
+static PyObject *
93c559
+_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj,
93c559
+                              int usedforsecurity);
93c559
+
93c559
+static PyObject *
93c559
+_hashlib_openssl_blake2s(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
93c559
+{
93c559
+    PyObject *return_value = NULL;
93c559
+    static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
93c559
+    static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2s", 0};
93c559
+    PyObject *argsbuf[2];
93c559
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
93c559
+    PyObject *data_obj = NULL;
93c559
+    int usedforsecurity = 1;
93c559
+
93c559
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf);
93c559
+    if (!args) {
93c559
+        goto exit;
93c559
+    }
93c559
+    if (!noptargs) {
93c559
+        goto skip_optional_pos;
93c559
+    }
93c559
+    if (args[0]) {
93c559
+        data_obj = args[0];
93c559
+        if (!--noptargs) {
93c559
+            goto skip_optional_pos;
93c559
+        }
93c559
+    }
93c559
+skip_optional_pos:
93c559
+    if (!noptargs) {
93c559
+        goto skip_optional_kwonly;
93c559
+    }
93c559
+    usedforsecurity = PyObject_IsTrue(args[1]);
93c559
+    if (usedforsecurity < 0) {
93c559
+        goto exit;
93c559
+    }
93c559
+skip_optional_kwonly:
93c559
+    return_value = _hashlib_openssl_blake2s_impl(module, data_obj, usedforsecurity);
93c559
+
93c559
+exit:
93c559
+    return return_value;
93c559
+}
93c559
+
93c559
 #if defined(PY_OPENSSL_HAS_SHA3)
93c559
 
93c559
 PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__,
8f0bcc
@@ -1418,4 +1522,4 @@ exit:
93c559
 #ifndef _HASHLIB_GET_FIPS_MODE_METHODDEF
93c559
     #define _HASHLIB_GET_FIPS_MODE_METHODDEF
93c559
 #endif /* !defined(_HASHLIB_GET_FIPS_MODE_METHODDEF) */
8f0bcc
-/*[clinic end generated code: output=7ff9aad0bd53e7ce input=a9049054013a1b77]*/
8f0bcc
+/*[clinic end generated code: output=fab05055e982f112 input=a9049054013a1b77]*/
93c559
-- 
8f0bcc
2.35.3
93c559
93c559
8f0bcc
From 652264a57ab6564bfe775d88502776df95cd897d Mon Sep 17 00:00:00 2001
93c559
From: Petr Viktorin <pviktori@redhat.com>
8f0bcc
Date: Thu, 1 Aug 2019 17:57:05 +0200
8f0bcc
Subject: [PATCH 05/10] Use a stronger hash in multiprocessing handshake
93c559
8f0bcc
Adapted from patch by David Malcolm,
8f0bcc
https://bugs.python.org/issue17258
93c559
---
8f0bcc
 Lib/multiprocessing/connection.py | 8 ++++++--
8f0bcc
 1 file changed, 6 insertions(+), 2 deletions(-)
8f0bcc
8f0bcc
diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
8f0bcc
index 510e4b5..b68f2fb 100644
8f0bcc
--- a/Lib/multiprocessing/connection.py
8f0bcc
+++ b/Lib/multiprocessing/connection.py
8f0bcc
@@ -42,6 +42,10 @@ BUFSIZE = 8192
8f0bcc
 # A very generous timeout when it comes to local connections...
8f0bcc
 CONNECTION_TIMEOUT = 20.
8f0bcc
 
8f0bcc
+# The hmac module implicitly defaults to using MD5.
8f0bcc
+# Support using a stronger algorithm for the challenge/response code:
8f0bcc
+HMAC_DIGEST_NAME='sha256'
8f0bcc
+
8f0bcc
 _mmap_counter = itertools.count()
8f0bcc
 
8f0bcc
 default_family = 'AF_INET'
8f0bcc
@@ -741,7 +745,7 @@ def deliver_challenge(connection, authkey):
8f0bcc
             "Authkey must be bytes, not {0!s}".format(type(authkey)))
8f0bcc
     message = os.urandom(MESSAGE_LENGTH)
8f0bcc
     connection.send_bytes(CHALLENGE + message)
8f0bcc
-    digest = hmac.new(authkey, message, 'md5').digest()
8f0bcc
+    digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest()
8f0bcc
     response = connection.recv_bytes(256)        # reject large message
8f0bcc
     if response == digest:
8f0bcc
         connection.send_bytes(WELCOME)
8f0bcc
@@ -757,7 +761,7 @@ def answer_challenge(connection, authkey):
8f0bcc
     message = connection.recv_bytes(256)         # reject large message
8f0bcc
     assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message
8f0bcc
     message = message[len(CHALLENGE):]
8f0bcc
-    digest = hmac.new(authkey, message, 'md5').digest()
8f0bcc
+    digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest()
8f0bcc
     connection.send_bytes(digest)
8f0bcc
     response = connection.recv_bytes(256)        # reject large message
8f0bcc
     if response != WELCOME:
8f0bcc
-- 
8f0bcc
2.35.3
8f0bcc
8f0bcc
8f0bcc
From 4a8637f114196b1ab19435ea64c19c7acf77776c Mon Sep 17 00:00:00 2001
8f0bcc
From: Petr Viktorin <pviktori@redhat.com>
8f0bcc
Date: Thu, 25 Jul 2019 17:19:06 +0200
8f0bcc
Subject: [PATCH 06/10] Disable Python's hash implementations in FIPS mode,
8f0bcc
 forcing OpenSSL
93c559
93c559
---
8f0bcc
 Lib/hashlib.py                 | 11 +++++++----
8f0bcc
 Lib/test/test_hashlib.py       | 17 ++++++++++++-----
8f0bcc
 Modules/_blake2/blake2b_impl.c |  4 ++++
8f0bcc
 Modules/_blake2/blake2module.c |  3 +++
8f0bcc
 Modules/_blake2/blake2s_impl.c |  4 ++++
8f0bcc
 Modules/hashlib.h              | 23 +++++++++++++++++++++++
8f0bcc
 setup.py                       | 27 ++++++++++++++++-----------
8f0bcc
 7 files changed, 69 insertions(+), 20 deletions(-)
93c559
8f0bcc
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
8f0bcc
index ffa3be0..3e3f4dd 100644
8f0bcc
--- a/Lib/hashlib.py
8f0bcc
+++ b/Lib/hashlib.py
8f0bcc
@@ -70,14 +70,17 @@ __all__ = __always_supported + ('new', 'algorithms_guaranteed',
93c559
 
8f0bcc
 __builtin_constructor_cache = {}
93c559
 
8f0bcc
-# Prefer our blake2 implementation
8f0bcc
+# Prefer our blake2 implementation (unless in FIPS mode)
8f0bcc
 # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s. The OpenSSL
8f0bcc
 # implementations neither support keyed blake2 (blake2 MAC) nor advanced
8f0bcc
 # features like salt, personalization, or tree hashing. OpenSSL hash-only
8f0bcc
 # variants are available as 'blake2b512' and 'blake2s256', though.
8f0bcc
-__block_openssl_constructor = {
8f0bcc
-    'blake2b', 'blake2s',
8f0bcc
-}
8f0bcc
+import _hashlib
8f0bcc
+if _hashlib.get_fips_mode():
8f0bcc
+    __block_openssl_constructor = set()
8f0bcc
+else:
8f0bcc
+    __block_openssl_constructor = {'blake2b', 'blake2s'}
8f0bcc
+
93c559
 
8f0bcc
 def __get_builtin_constructor(name):
8f0bcc
     cache = __builtin_constructor_cache
8f0bcc
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
8f0bcc
index 7aaeb76..fa4a8d7 100644
8f0bcc
--- a/Lib/test/test_hashlib.py
8f0bcc
+++ b/Lib/test/test_hashlib.py
8f0bcc
@@ -35,14 +35,15 @@ else:
8f0bcc
         m.strip() for m in builtin_hashes.strip('"').lower().split(",")
8f0bcc
     }
93c559
 
8f0bcc
-# hashlib with and without OpenSSL backend for PBKDF2
8f0bcc
-# only import builtin_hashlib when all builtin hashes are available.
8f0bcc
-# Otherwise import prints noise on stderr
8f0bcc
+# RHEL: `_hashlib` is always importable and `hashlib` can't be imported
8f0bcc
+# without it.
8f0bcc
 openssl_hashlib = import_fresh_module('hashlib', fresh=['_hashlib'])
8f0bcc
-if builtin_hashes == default_builtin_hashes:
8f0bcc
+try:
8f0bcc
     builtin_hashlib = import_fresh_module('hashlib', blocked=['_hashlib'])
8f0bcc
-else:
8f0bcc
+except ImportError:
8f0bcc
     builtin_hashlib = None
8f0bcc
+else:
8f0bcc
+    raise AssertionError('hashlib is importablee without _hashlib')
93c559
 
8f0bcc
 try:
8f0bcc
     from _hashlib import HASH, HASHXOF, openssl_md_meth_names, get_fips_mode
8f0bcc
@@ -118,6 +119,12 @@ class HashLibTestCase(unittest.TestCase):
8f0bcc
         except ModuleNotFoundError as error:
8f0bcc
             if self._warn_on_extension_import and module_name in builtin_hashes:
8f0bcc
                 warnings.warn('Did a C extension fail to compile? %s' % error)
8f0bcc
+        except ImportError:
8f0bcc
+            if get_fips_mode() and module_name == '_blake2':
8f0bcc
+                # blake2b & blake2s disabled under FIPS
8f0bcc
+                return None
8f0bcc
+            else:
8f0bcc
+                raise
8f0bcc
         return None
93c559
 
8f0bcc
     def __init__(self, *args, **kwargs):
8f0bcc
diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c
8f0bcc
index 7fb1296..bc01cd5 100644
8f0bcc
--- a/Modules/_blake2/blake2b_impl.c
8f0bcc
+++ b/Modules/_blake2/blake2b_impl.c
8f0bcc
@@ -96,6 +96,8 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
8f0bcc
     BLAKE2bObject *self = NULL;
8f0bcc
     Py_buffer buf;
93c559
 
8f0bcc
+    FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2");
8f0bcc
+
8f0bcc
     self = new_BLAKE2bObject(type);
8f0bcc
     if (self == NULL) {
8f0bcc
         goto error;
8f0bcc
@@ -274,6 +276,8 @@ _blake2_blake2b_update(BLAKE2bObject *self, PyObject *data)
8f0bcc
 {
8f0bcc
     Py_buffer buf;
93c559
 
8f0bcc
+    FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2");
93c559
+
8f0bcc
     GET_BUFFER_VIEW_OR_ERROUT(data, &buf;;
93c559
 
8f0bcc
     if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE)
8f0bcc
diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c
8f0bcc
index ff142c9..144ec03 100644
8f0bcc
--- a/Modules/_blake2/blake2module.c
8f0bcc
+++ b/Modules/_blake2/blake2module.c
8f0bcc
@@ -9,6 +9,7 @@
8f0bcc
  */
93c559
 
8f0bcc
 #include "Python.h"
8f0bcc
+#include "../hashlib.h"
93c559
 
8f0bcc
 #include "impl/blake2.h"
93c559
 
8f0bcc
@@ -57,6 +58,8 @@ PyInit__blake2(void)
8f0bcc
     PyObject *m;
8f0bcc
     PyObject *d;
8f0bcc
 
8f0bcc
+    FAIL_RETURN_IN_FIPS_MODE(PyExc_ImportError, "blake2");
93c559
+
8f0bcc
     m = PyModule_Create(&blake2_module);
8f0bcc
     if (m == NULL)
8f0bcc
         return NULL;
8f0bcc
diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c
8f0bcc
index e3e90d0..e45f8f6 100644
8f0bcc
--- a/Modules/_blake2/blake2s_impl.c
8f0bcc
+++ b/Modules/_blake2/blake2s_impl.c
8f0bcc
@@ -96,6 +96,8 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
8f0bcc
     BLAKE2sObject *self = NULL;
8f0bcc
     Py_buffer buf;
8f0bcc
 
8f0bcc
+    FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2");
93c559
+
8f0bcc
     self = new_BLAKE2sObject(type);
8f0bcc
     if (self == NULL) {
8f0bcc
         goto error;
8f0bcc
@@ -274,6 +276,8 @@ _blake2_blake2s_update(BLAKE2sObject *self, PyObject *data)
8f0bcc
 {
8f0bcc
     Py_buffer buf;
8f0bcc
 
8f0bcc
+    FAIL_RETURN_IN_FIPS_MODE(PyExc_ValueError, "_blake2");
93c559
+
8f0bcc
     GET_BUFFER_VIEW_OR_ERROUT(data, &buf;;
8f0bcc
 
8f0bcc
     if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE)
8f0bcc
diff --git a/Modules/hashlib.h b/Modules/hashlib.h
8f0bcc
index 56ae7a5..45fb403 100644
8f0bcc
--- a/Modules/hashlib.h
8f0bcc
+++ b/Modules/hashlib.h
8f0bcc
@@ -1,5 +1,11 @@
8f0bcc
 /* Common code for use by all hashlib related modules. */
8f0bcc
 
8f0bcc
+// RHEL: use OpenSSL to turn off unsupported modules under FIPS mode
8f0bcc
+// EVP_default_properties_is_fips_enabled() on OpenSSL >= 3.0.0
8f0bcc
+#include <openssl/evp.h>
8f0bcc
+// FIPS_mode() on OpenSSL < 3.0.0
8f0bcc
+#include <openssl/crypto.h>
93c559
+
8f0bcc
 /*
8f0bcc
  * Given a PyObject* obj, fill in the Py_buffer* viewp with the result
8f0bcc
  * of PyObject_GetBuffer.  Sets an exception and issues the erraction
8f0bcc
@@ -57,3 +63,20 @@
8f0bcc
  * to allow the user to optimize based on the platform they're using. */
8f0bcc
 #define HASHLIB_GIL_MINSIZE 2048
8f0bcc
 
8f0bcc
+__attribute__((__unused__))
8f0bcc
+static int
8f0bcc
+_Py_hashlib_fips_error(PyObject *exc, char *name) {
8f0bcc
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
8f0bcc
+    if (EVP_default_properties_is_fips_enabled(NULL)) {
8f0bcc
+#else
8f0bcc
+    if (FIPS_mode()) {
8f0bcc
+#endif
8f0bcc
+        PyErr_Format(exc, "%s is not available in FIPS mode", name);
8f0bcc
+        return 1;
93c559
+    }
8f0bcc
+    return 0;
93c559
+}
93c559
+
8f0bcc
+#define FAIL_RETURN_IN_FIPS_MODE(exc, name) do { \
8f0bcc
+    if (_Py_hashlib_fips_error(exc, name)) return NULL; \
8f0bcc
+} while (0)
8f0bcc
diff --git a/setup.py b/setup.py
8f0bcc
index 0bec170..479f4b5 100644
8f0bcc
--- a/setup.py
8f0bcc
+++ b/setup.py
8f0bcc
@@ -2315,7 +2315,7 @@ class PyBuildExt(build_ext):
8f0bcc
                            sources=sources,
8f0bcc
                            depends=depends))
8f0bcc
 
8f0bcc
-    def detect_openssl_hashlib(self):
8f0bcc
+    def detect_openssl_args(self):
8f0bcc
         # Detect SSL support for the socket module (via _ssl)
8f0bcc
         config_vars = sysconfig.get_config_vars()
8f0bcc
 
8f0bcc
@@ -2335,16 +2335,14 @@ class PyBuildExt(build_ext):
8f0bcc
         openssl_libs = split_var('OPENSSL_LIBS', '-l')
8f0bcc
         if not openssl_libs:
8f0bcc
             # libssl and libcrypto not found
8f0bcc
-            self.missing.extend(['_ssl', '_hashlib'])
8f0bcc
-            return None, None
8f0bcc
+            raise ValueError('Cannot build for RHEL without OpenSSL')
8f0bcc
 
8f0bcc
         # Find OpenSSL includes
8f0bcc
         ssl_incs = find_file(
8f0bcc
             'openssl/ssl.h', self.inc_dirs, openssl_includes
8f0bcc
         )
8f0bcc
         if ssl_incs is None:
8f0bcc
-            self.missing.extend(['_ssl', '_hashlib'])
8f0bcc
-            return None, None
8f0bcc
+            raise ValueError('Cannot build for RHEL without OpenSSL')
8f0bcc
 
8f0bcc
         # OpenSSL 1.0.2 uses Kerberos for KRB5 ciphers
8f0bcc
         krb5_h = find_file(
8f0bcc
@@ -2354,12 +2352,20 @@ class PyBuildExt(build_ext):
8f0bcc
         if krb5_h:
8f0bcc
             ssl_incs.extend(krb5_h)
8f0bcc
 
8f0bcc
+        return {
8f0bcc
+            'include_dirs': openssl_includes,
8f0bcc
+            'library_dirs': openssl_libdirs,
8f0bcc
+            'libraries': openssl_libs,
8f0bcc
+        }
93c559
+
8f0bcc
+    def detect_openssl_hashlib(self):
93c559
+
8f0bcc
+        config_vars = sysconfig.get_config_vars()
93c559
+
8f0bcc
         if config_vars.get("HAVE_X509_VERIFY_PARAM_SET1_HOST"):
8f0bcc
             self.add(Extension(
8f0bcc
                 '_ssl', ['_ssl.c'],
8f0bcc
-                include_dirs=openssl_includes,
8f0bcc
-                library_dirs=openssl_libdirs,
8f0bcc
-                libraries=openssl_libs,
8f0bcc
+                **self.detect_openssl_args(),
8f0bcc
                 depends=[
8f0bcc
                     'socketmodule.h',
8f0bcc
                     '_ssl/debughelpers.c',
8f0bcc
@@ -2372,9 +2378,7 @@ class PyBuildExt(build_ext):
8f0bcc
 
8f0bcc
         self.add(Extension('_hashlib', ['_hashopenssl.c'],
93c559
                            depends=['hashlib.h'],
8f0bcc
-                           include_dirs=openssl_includes,
8f0bcc
-                           library_dirs=openssl_libdirs,
8f0bcc
-                           libraries=openssl_libs))
8f0bcc
+                           **self.detect_openssl_args()) )
93c559
 
93c559
     def detect_hash_builtins(self):
93c559
         # By default we always compile these even when OpenSSL is available
8f0bcc
@@ -2431,6 +2435,7 @@ class PyBuildExt(build_ext):
8f0bcc
                     '_blake2/blake2b_impl.c',
8f0bcc
                     '_blake2/blake2s_impl.c'
8f0bcc
                 ],
8f0bcc
+                **self.detect_openssl_args(),  # for FIPS_mode verification
8f0bcc
                 depends=blake2_deps
8f0bcc
             ))
8f0bcc
 
93c559
-- 
8f0bcc
2.35.3
93c559
93c559
8f0bcc
From 165bcd0377075dbac9fa3f988ed5189668597ab6 Mon Sep 17 00:00:00 2001
8f0bcc
From: Charalampos Stratakis <cstratak@redhat.com>
8f0bcc
Date: Fri, 29 Jan 2021 14:16:21 +0100
8f0bcc
Subject: [PATCH 07/10] Use python's fall back crypto implementations only if
8f0bcc
 we are not in FIPS mode
93c559
93c559
---
8f0bcc
 Lib/hashlib.py           | 69 +++-------------------------------------
8f0bcc
 Lib/test/test_hashlib.py | 23 +++++++++++++-
8f0bcc
 2 files changed, 27 insertions(+), 65 deletions(-)
93c559
8f0bcc
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
8f0bcc
index 3e3f4dd..b842f5f 100644
8f0bcc
--- a/Lib/hashlib.py
8f0bcc
+++ b/Lib/hashlib.py
8f0bcc
@@ -67,7 +67,6 @@ algorithms_available = set(__always_supported)
8f0bcc
 __all__ = __always_supported + ('new', 'algorithms_guaranteed',
8f0bcc
                                 'algorithms_available', 'pbkdf2_hmac')
93c559
 
8f0bcc
-
8f0bcc
 __builtin_constructor_cache = {}
8f0bcc
 
8f0bcc
 # Prefer our blake2 implementation (unless in FIPS mode)
8f0bcc
@@ -83,6 +82,8 @@ else:
8f0bcc
 
8f0bcc
 
8f0bcc
 def __get_builtin_constructor(name):
8f0bcc
+    if _hashlib.get_fips_mode():
8f0bcc
+        raise ValueError('unsupported hash type ' + name + '(in FIPS mode)')
8f0bcc
     cache = __builtin_constructor_cache
8f0bcc
     constructor = cache.get(name)
8f0bcc
     if constructor is not None:
8f0bcc
@@ -176,79 +177,19 @@ try:
8f0bcc
     algorithms_available = algorithms_available.union(
8f0bcc
             _hashlib.openssl_md_meth_names)
8f0bcc
 except ImportError:
8f0bcc
-    _hashlib = None
8f0bcc
-    new = __py_new
8f0bcc
-    __get_hash = __get_builtin_constructor
8f0bcc
+    raise  # importing _hashlib should never fail on RHEL
8f0bcc
 
8f0bcc
 try:
8f0bcc
     # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
8f0bcc
     from _hashlib import pbkdf2_hmac
8f0bcc
 except ImportError:
8f0bcc
-    _trans_5C = bytes((x ^ 0x5C) for x in range(256))
8f0bcc
-    _trans_36 = bytes((x ^ 0x36) for x in range(256))
8f0bcc
-
8f0bcc
-    def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
8f0bcc
-        """Password based key derivation function 2 (PKCS #5 v2.0)
8f0bcc
-
8f0bcc
-        This Python implementations based on the hmac module about as fast
8f0bcc
-        as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
8f0bcc
-        for long passwords.
8f0bcc
-        """
8f0bcc
-        if not isinstance(hash_name, str):
8f0bcc
-            raise TypeError(hash_name)
8f0bcc
-
8f0bcc
-        if not isinstance(password, (bytes, bytearray)):
8f0bcc
-            password = bytes(memoryview(password))
8f0bcc
-        if not isinstance(salt, (bytes, bytearray)):
8f0bcc
-            salt = bytes(memoryview(salt))
8f0bcc
-
8f0bcc
-        # Fast inline HMAC implementation
8f0bcc
-        inner = new(hash_name)
8f0bcc
-        outer = new(hash_name)
8f0bcc
-        blocksize = getattr(inner, 'block_size', 64)
8f0bcc
-        if len(password) > blocksize:
8f0bcc
-            password = new(hash_name, password).digest()
8f0bcc
-        password = password + b'\x00' * (blocksize - len(password))
8f0bcc
-        inner.update(password.translate(_trans_36))
8f0bcc
-        outer.update(password.translate(_trans_5C))
8f0bcc
-
8f0bcc
-        def prf(msg, inner=inner, outer=outer):
8f0bcc
-            # PBKDF2_HMAC uses the password as key. We can re-use the same
8f0bcc
-            # digest objects and just update copies to skip initialization.
8f0bcc
-            icpy = inner.copy()
8f0bcc
-            ocpy = outer.copy()
8f0bcc
-            icpy.update(msg)
8f0bcc
-            ocpy.update(icpy.digest())
8f0bcc
-            return ocpy.digest()
8f0bcc
-
8f0bcc
-        if iterations < 1:
8f0bcc
-            raise ValueError(iterations)
8f0bcc
-        if dklen is None:
8f0bcc
-            dklen = outer.digest_size
8f0bcc
-        if dklen < 1:
8f0bcc
-            raise ValueError(dklen)
8f0bcc
-
8f0bcc
-        dkey = b''
8f0bcc
-        loop = 1
8f0bcc
-        from_bytes = int.from_bytes
8f0bcc
-        while len(dkey) < dklen:
8f0bcc
-            prev = prf(salt + loop.to_bytes(4, 'big'))
8f0bcc
-            # endianness doesn't matter here as long to / from use the same
8f0bcc
-            rkey = int.from_bytes(prev, 'big')
8f0bcc
-            for i in range(iterations - 1):
8f0bcc
-                prev = prf(prev)
8f0bcc
-                # rkey = rkey ^ prev
8f0bcc
-                rkey ^= from_bytes(prev, 'big')
8f0bcc
-            loop += 1
8f0bcc
-            dkey += rkey.to_bytes(inner.digest_size, 'big')
8f0bcc
-
8f0bcc
-        return dkey[:dklen]
8f0bcc
+    raise  # importing _hashlib should never fail on RHEL
8f0bcc
 
8f0bcc
 try:
8f0bcc
     # OpenSSL's scrypt requires OpenSSL 1.1+
8f0bcc
     from _hashlib import scrypt
8f0bcc
 except ImportError:
8f0bcc
-    pass
8f0bcc
+    raise  # importing _hashlib should never fail on RHEL
8f0bcc
 
8f0bcc
 
8f0bcc
 for __func_name in __always_supported:
8f0bcc
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
8f0bcc
index fa4a8d7..ec6c883 100644
8f0bcc
--- a/Lib/test/test_hashlib.py
8f0bcc
+++ b/Lib/test/test_hashlib.py
8f0bcc
@@ -171,7 +171,13 @@ class HashLibTestCase(unittest.TestCase):
8f0bcc
                         constructors.add(constructor)
8f0bcc
 
8f0bcc
         def add_builtin_constructor(name):
8f0bcc
-            constructor = getattr(hashlib, "__get_builtin_constructor")(name)
8f0bcc
+            try:
8f0bcc
+                constructor = getattr(hashlib, "__get_builtin_constructor")(name)
8f0bcc
+            except ValueError:
8f0bcc
+                if get_fips_mode():
8f0bcc
+                    return
8f0bcc
+                else:
8f0bcc
+                    raise
8f0bcc
             self.constructors_to_test[name].add(constructor)
8f0bcc
 
8f0bcc
         _md5 = self._conditional_import_module('_md5')
8f0bcc
@@ -266,6 +272,20 @@ class HashLibTestCase(unittest.TestCase):
8f0bcc
     def test_new_upper_to_lower(self):
8f0bcc
         self.assertEqual(hashlib.new("SHA256").name, "sha256")
8f0bcc
 
8f0bcc
+    @unittest.skipUnless(get_fips_mode(), "Builtin constructor only usable in FIPS mode")
8f0bcc
+    def test_get_builtin_constructor_fips(self):
8f0bcc
+        get_builtin_constructor = getattr(hashlib,
8f0bcc
+                                          '__get_builtin_constructor')
8f0bcc
+        with self.assertRaises(ValueError):
8f0bcc
+            get_builtin_constructor('md5')
8f0bcc
+        with self.assertRaises(ValueError):
8f0bcc
+            get_builtin_constructor('sha256')
8f0bcc
+        with self.assertRaises(ValueError):
8f0bcc
+            get_builtin_constructor('blake2s')
8f0bcc
+        with self.assertRaises(ValueError):
8f0bcc
+            get_builtin_constructor('test')
93c559
+
8f0bcc
+    @unittest.skipIf(get_fips_mode(), "No builtin constructors in FIPS mode")
8f0bcc
     def test_get_builtin_constructor(self):
8f0bcc
         get_builtin_constructor = getattr(hashlib,
8f0bcc
                                           '__get_builtin_constructor')
8f0bcc
@@ -1061,6 +1081,7 @@ class KDFTests(unittest.TestCase):
8f0bcc
                 iterations=1, dklen=None)
8f0bcc
             self.assertEqual(out, self.pbkdf2_results['sha1'][0][0])
93c559
 
8f0bcc
+    @unittest.skip("The python implementation of pbkdf2_hmac has been removed")
8f0bcc
     @unittest.skipIf(builtin_hashlib is None, "test requires builtin_hashlib")
8f0bcc
     def test_pbkdf2_hmac_py(self):
8f0bcc
         self._test_pbkdf2_hmac(builtin_hashlib.pbkdf2_hmac, builtin_hashes)
93c559
-- 
8f0bcc
2.35.3
93c559
93c559
8f0bcc
From f4383a6e0be8b75db2380fdcf0174b09709b613f Mon Sep 17 00:00:00 2001
93c559
From: Charalampos Stratakis <cstratak@redhat.com>
93c559
Date: Wed, 31 Jul 2019 15:43:43 +0200
8f0bcc
Subject: [PATCH 08/10] Test equivalence of hashes for the various digests with
8f0bcc
 usedforsecurity=True/False
93c559
93c559
---
8f0bcc
 Lib/test/test_fips.py    | 24 +++++++++++++++++++++
8f0bcc
 Lib/test/test_hashlib.py | 46 ++++++++++++++++++++++++++++++----------
8f0bcc
 2 files changed, 59 insertions(+), 11 deletions(-)
93c559
 create mode 100644 Lib/test/test_fips.py
93c559
93c559
diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py
93c559
new file mode 100644
8f0bcc
index 0000000..1f99dd7
93c559
--- /dev/null
93c559
+++ b/Lib/test/test_fips.py
8f0bcc
@@ -0,0 +1,24 @@
93c559
+import unittest
93c559
+import hashlib, _hashlib
93c559
+
93c559
+
93c559
+
93c559
+class HashlibFipsTests(unittest.TestCase):
93c559
+
8f0bcc
+    @unittest.skipUnless(_hashlib.get_fips_mode(), "Test only when FIPS is enabled")
93c559
+    def test_fips_imports(self):
93c559
+        """blake2s and blake2b should fail to import in FIPS mode
93c559
+        """
93c559
+        with self.assertRaises(ValueError, msg='blake2s not available in FIPS'):
93c559
+            m = hashlib.blake2s()
93c559
+        with self.assertRaises(ValueError, msg='blake2b not available in FIPS'):
93c559
+            m = hashlib.blake2b()
93c559
+
8f0bcc
+    @unittest.skipIf(_hashlib.get_fips_mode(), "blake2 hashes are not available under FIPS")
93c559
+    def test_blake2_hashes(self):
93c559
+        self.assertEqual(hashlib.blake2b(b'abc').hexdigest(), _hashlib.openssl_blake2b(b'abc').hexdigest())
93c559
+        self.assertEqual(hashlib.blake2s(b'abc').hexdigest(), _hashlib.openssl_blake2s(b'abc').hexdigest())
93c559
+
93c559
+
93c559
+if __name__ == "__main__":
93c559
+    unittest.main()
93c559
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
8f0bcc
index ec6c883..0fd036f 100644
93c559
--- a/Lib/test/test_hashlib.py
93c559
+++ b/Lib/test/test_hashlib.py
93c559
@@ -20,6 +20,7 @@ import warnings
93c559
 from test import support
93c559
 from test.support import _4G, bigmemtest, import_fresh_module
93c559
 from http.client import HTTPException
93c559
+from functools import partial
93c559
 
93c559
 # Were we compiled --with-pydebug or with #define Py_DEBUG?
93c559
 COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount')
8f0bcc
@@ -55,6 +56,11 @@ except ImportError:
8f0bcc
     def get_fips_mode():
8f0bcc
         return 0
93c559
 
8f0bcc
+if get_fips_mode():
8f0bcc
+    FIPS_DISABLED = {'md5'}
8f0bcc
+else:
8f0bcc
+    FIPS_DISABLED = set()
8f0bcc
+
93c559
 try:
8f0bcc
     import _blake2
8f0bcc
 except ImportError:
8f0bcc
@@ -98,6 +104,11 @@ def read_vectors(hash_name):
93c559
             parts[0] = bytes.fromhex(parts[0])
93c559
             yield parts
93c559
 
8f0bcc
+def _is_blake2_constructor(constructor):
93c559
+    if isinstance(constructor, partial):
8f0bcc
+        constructor = constructor.func
8f0bcc
+    return  getattr(constructor, '__name__', '').startswith('openssl_blake2')
93c559
+
93c559
 
93c559
 class HashLibTestCase(unittest.TestCase):
93c559
     supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
8f0bcc
@@ -142,15 +153,21 @@ class HashLibTestCase(unittest.TestCase):
8f0bcc
                 continue
93c559
             self.constructors_to_test[algorithm] = set()
93c559
 
93c559
+        def _add_constructor(algorithm, constructor):
93c559
+            constructors.add(partial(constructor, usedforsecurity=False))
93c559
+            if algorithm not in FIPS_DISABLED:
93c559
+                constructors.add(constructor)
93c559
+                constructors.add(partial(constructor, usedforsecurity=True))
93c559
+
93c559
         # For each algorithm, test the direct constructor and the use
93c559
         # of hashlib.new given the algorithm name.
93c559
         for algorithm, constructors in self.constructors_to_test.items():
93c559
-            constructors.add(getattr(hashlib, algorithm))
93c559
+            _add_constructor(algorithm, getattr(hashlib, algorithm))
93c559
             def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
93c559
                 if data is None:
93c559
                     return hashlib.new(_alg, **kwargs)
93c559
                 return hashlib.new(_alg, data, **kwargs)
93c559
-            constructors.add(_test_algorithm_via_hashlib_new)
93c559
+            _add_constructor(algorithm, _test_algorithm_via_hashlib_new)
93c559
 
93c559
         _hashlib = self._conditional_import_module('_hashlib')
93c559
         self._hashlib = _hashlib
8f0bcc
@@ -162,13 +179,7 @@ class HashLibTestCase(unittest.TestCase):
93c559
             for algorithm, constructors in self.constructors_to_test.items():
93c559
                 constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
93c559
                 if constructor:
93c559
-                    try:
93c559
-                        constructor()
93c559
-                    except ValueError:
93c559
-                        # default constructor blocked by crypto policy
93c559
-                        pass
93c559
-                    else:
93c559
-                        constructors.add(constructor)
93c559
+                    _add_constructor(algorithm, constructor)
93c559
 
93c559
         def add_builtin_constructor(name):
8f0bcc
             try:
8f0bcc
@@ -346,6 +357,8 @@ class HashLibTestCase(unittest.TestCase):
93c559
                 self.assertIn(h.name, self.supported_hash_names)
93c559
             else:
93c559
                 self.assertNotIn(h.name, self.supported_hash_names)
8f0bcc
+            if not h.name.startswith('blake2') and h.name not in FIPS_DISABLED:
93c559
+                self.assertEqual(h.name, hashlib.new(h.name).name)
8f0bcc
             self.assertEqual(
8f0bcc
                 h.name,
8f0bcc
                 hashlib.new(h.name, usedforsecurity=False).name
8f0bcc
@@ -392,8 +405,10 @@ class HashLibTestCase(unittest.TestCase):
93c559
         for hash_object_constructor in constructors:
93c559
 
8f0bcc
             # OpenSSL's blake2s & blake2d don't support `key`
8f0bcc
-            _name = hash_object_constructor.__name__
8f0bcc
-            if 'key' in kwargs and _name.startswith('openssl_blake2'):
8f0bcc
+            if (
8f0bcc
+                'key' in kwargs
8f0bcc
+                and _is_blake2_constructor(hash_object_constructor)
8f0bcc
+            ):
8f0bcc
                 return
93c559
 
8f0bcc
             m = hash_object_constructor(data, **kwargs)
8f0bcc
@@ -974,6 +989,15 @@ class HashLibTestCase(unittest.TestCase):
93c559
         ):
93c559
             HASHXOF()
93c559
 
8f0bcc
+    @unittest.skipUnless(get_fips_mode(), 'Needs FIPS mode.')
93c559
+    def test_usedforsecurity_repeat(self):
93c559
+        """Make sure usedforsecurity flag isn't copied to other contexts"""
93c559
+        for i in range(3):
93c559
+            for cons in hashlib.md5, partial(hashlib.new, 'md5'):
93c559
+                self.assertRaises(ValueError, cons)
93c559
+                self.assertRaises(ValueError, partial(cons, usedforsecurity=True))
93c559
+                self.assertEqual(cons(usedforsecurity=False).hexdigest(),
93c559
+                                'd41d8cd98f00b204e9800998ecf8427e')
93c559
 
93c559
 class KDFTests(unittest.TestCase):
93c559
 
93c559
-- 
8f0bcc
2.35.3
93c559
93c559
8f0bcc
From 5ecf11d53225bbe04e35970a834bcc90cd944391 Mon Sep 17 00:00:00 2001
93c559
From: Petr Viktorin <pviktori@redhat.com>
93c559
Date: Mon, 26 Aug 2019 19:39:48 +0200
8f0bcc
Subject: [PATCH 09/10] Guard against Python HMAC in FIPS mode
93c559
93c559
---
8f0bcc
 Lib/hmac.py           | 13 +++++++++----
8f0bcc
 Lib/test/test_hmac.py | 10 ++++++++++
8f0bcc
 2 files changed, 19 insertions(+), 4 deletions(-)
93c559
93c559
diff --git a/Lib/hmac.py b/Lib/hmac.py
8f0bcc
index 8b4f920..20ef96c 100644
93c559
--- a/Lib/hmac.py
93c559
+++ b/Lib/hmac.py
8f0bcc
@@ -16,8 +16,9 @@ else:
93c559
 
8f0bcc
 import hashlib as _hashlib
93c559
 
8f0bcc
-trans_5C = bytes((x ^ 0x5C) for x in range(256))
8f0bcc
-trans_36 = bytes((x ^ 0x36) for x in range(256))
8f0bcc
+if not _hashopenssl.get_fips_mode():
8f0bcc
+    trans_5C = bytes((x ^ 0x5C) for x in range(256))
8f0bcc
+    trans_36 = bytes((x ^ 0x36) for x in range(256))
93c559
 
8f0bcc
 # The size of the digests returned by HMAC depends on the underlying
8f0bcc
 # hashing module used.  Use digest_size from the instance of HMAC instead.
8f0bcc
@@ -48,17 +49,18 @@ class HMAC:
8f0bcc
                    msg argument.  Passing it as a keyword argument is
8f0bcc
                    recommended, though not required for legacy API reasons.
93c559
         """
8f0bcc
-
8f0bcc
         if not isinstance(key, (bytes, bytearray)):
8f0bcc
             raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
93c559
 
8f0bcc
         if not digestmod:
8f0bcc
             raise TypeError("Missing required parameter 'digestmod'.")
8f0bcc
 
8f0bcc
-        if _hashopenssl and isinstance(digestmod, (str, _functype)):
8f0bcc
+        if _hashopenssl.get_fips_mode() or (_hashopenssl and isinstance(digestmod, (str, _functype))):
8f0bcc
             try:
8f0bcc
                 self._init_hmac(key, msg, digestmod)
8f0bcc
             except _hashopenssl.UnsupportedDigestmodError:
8f0bcc
+                if _hashopenssl.get_fips_mode():
8f0bcc
+                    raise
8f0bcc
                 self._init_old(key, msg, digestmod)
8f0bcc
         else:
8f0bcc
             self._init_old(key, msg, digestmod)
8f0bcc
@@ -69,6 +71,9 @@ class HMAC:
8f0bcc
         self.block_size = self._hmac.block_size
8f0bcc
 
8f0bcc
     def _init_old(self, key, msg, digestmod):
8f0bcc
+        if _hashopenssl.get_fips_mode():
8f0bcc
+            # In FIPS mode, use OpenSSL anyway: raise the appropriate error
8f0bcc
+            return self._init_hmac(key, msg, digestmod)
8f0bcc
         if callable(digestmod):
8f0bcc
             digest_cons = digestmod
8f0bcc
         elif isinstance(digestmod, str):
93c559
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
8f0bcc
index adf52ad..41e6a14 100644
93c559
--- a/Lib/test/test_hmac.py
93c559
+++ b/Lib/test/test_hmac.py
93c559
@@ -5,6 +5,7 @@ import hashlib
93c559
 import unittest
93c559
 import unittest.mock
93c559
 import warnings
93c559
+from _hashlib import get_fips_mode
93c559
 
93c559
 from test.support import hashlib_helper
93c559
 
8f0bcc
@@ -339,6 +340,7 @@ class TestVectorsTestCase(unittest.TestCase):
93c559
     def test_sha512_rfc4231(self):
93c559
         self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128)
93c559
 
8f0bcc
+    #unittest.skipIf(get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.')
93c559
     @hashlib_helper.requires_hashdigest('sha256')
93c559
     def test_legacy_block_size_warnings(self):
93c559
         class MockCrazyHash(object):
8f0bcc
@@ -351,6 +353,11 @@ class TestVectorsTestCase(unittest.TestCase):
8f0bcc
             def digest(self):
8f0bcc
                 return self._x.digest()
8f0bcc
 
8f0bcc
+        if get_fips_mode():
8f0bcc
+            with self.assertRaises(ValueError):
8f0bcc
+                hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
8f0bcc
+            return
8f0bcc
+
8f0bcc
         with warnings.catch_warnings():
8f0bcc
             warnings.simplefilter('error', RuntimeWarning)
8f0bcc
             with self.assertRaises(RuntimeWarning):
8f0bcc
@@ -444,6 +451,7 @@ class ConstructorTestCase(unittest.TestCase):
8f0bcc
         ):
8f0bcc
             C_HMAC()
8f0bcc
 
8f0bcc
+    @unittest.skipIf(get_fips_mode(), "_sha256 unavailable in FIPS mode")
8f0bcc
     @unittest.skipUnless(sha256_module is not None, 'need _sha256')
8f0bcc
     def test_with_sha256_module(self):
8f0bcc
         h = hmac.HMAC(b"key", b"hash this!", digestmod=sha256_module.sha256)
8f0bcc
@@ -472,6 +480,7 @@ class SanityTestCase(unittest.TestCase):
93c559
 
93c559
 class CopyTestCase(unittest.TestCase):
93c559
 
8f0bcc
+    @unittest.skipIf(get_fips_mode(), "_init_old unavailable in FIPS mode")
93c559
     @hashlib_helper.requires_hashdigest('sha256')
8f0bcc
     def test_attributes_old(self):
93c559
         # Testing if attributes are of same type.
8f0bcc
@@ -483,6 +492,7 @@ class CopyTestCase(unittest.TestCase):
8f0bcc
         self.assertEqual(type(h1._outer), type(h2._outer),
93c559
             "Types of outer don't match.")
93c559
 
8f0bcc
+    @unittest.skipIf(get_fips_mode(), "_init_old unavailable in FIPS mode")
93c559
     @hashlib_helper.requires_hashdigest('sha256')
8f0bcc
     def test_realcopy_old(self):
93c559
         # Testing if the copy method created a real copy.
93c559
-- 
8f0bcc
2.35.3
93c559
93c559
8f0bcc
From 532ce8649bf743c029aa5ddb25d74604d9798da9 Mon Sep 17 00:00:00 2001
8f0bcc
From: Petr Viktorin <encukou@gmail.com>
8f0bcc
Date: Wed, 25 Aug 2021 16:44:43 +0200
8f0bcc
Subject: [PATCH 10/10] Disable hash-based PYCs in FIPS mode
93c559
8f0bcc
If FIPS mode is on, we can't use siphash-based HMAC
8f0bcc
(_Py_KeyedHash), so:
93c559
8f0bcc
- Unchecked hash PYCs can be imported, but not created
8f0bcc
- Checked hash PYCs can not be imported nor created
8f0bcc
- The default mode is timestamp-based PYCs, even if
8f0bcc
  SOURCE_DATE_EPOCH is set.
8f0bcc
8f0bcc
If FIPS mode is off, there are no changes in behavior.
8f0bcc
8f0bcc
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1835169
93c559
---
8f0bcc
 Lib/py_compile.py                             |  2 ++
8f0bcc
 Lib/test/support/__init__.py                  | 14 +++++++++++++
8f0bcc
 Lib/test/test_cmd_line_script.py              |  2 ++
8f0bcc
 Lib/test/test_compileall.py                   | 11 +++++++++-
8f0bcc
 Lib/test/test_imp.py                          |  2 ++
8f0bcc
 .../test_importlib/source/test_file_loader.py |  6 ++++++
8f0bcc
 Lib/test/test_py_compile.py                   | 11 ++++++++--
8f0bcc
 Lib/test/test_zipimport.py                    |  2 ++
8f0bcc
 Python/import.c                               | 20 +++++++++++++++++++
8f0bcc
 9 files changed, 67 insertions(+), 3 deletions(-)
93c559
8f0bcc
diff --git a/Lib/py_compile.py b/Lib/py_compile.py
8f0bcc
index bba3642..02db901 100644
8f0bcc
--- a/Lib/py_compile.py
8f0bcc
+++ b/Lib/py_compile.py
8f0bcc
@@ -70,7 +70,9 @@ class PycInvalidationMode(enum.Enum):
8f0bcc
 
8f0bcc
 
8f0bcc
 def _get_default_invalidation_mode():
8f0bcc
+    import _hashlib
8f0bcc
     if (os.environ.get('SOURCE_DATE_EPOCH') and not
8f0bcc
+            _hashlib.get_fips_mode() and not
8f0bcc
             os.environ.get('RPM_BUILD_ROOT')):
8f0bcc
         return PycInvalidationMode.CHECKED_HASH
8f0bcc
     else:
8f0bcc
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
8f0bcc
index 86ac8f0..dc042f7 100644
8f0bcc
--- a/Lib/test/support/__init__.py
8f0bcc
+++ b/Lib/test/support/__init__.py
8f0bcc
@@ -3294,3 +3294,17 @@ def clear_ignored_deprecations(*tokens: object) -> None:
8f0bcc
     if warnings.filters != new_filters:
8f0bcc
         warnings.filters[:] = new_filters
8f0bcc
         warnings._filters_mutated()
8f0bcc
+
8f0bcc
+
8f0bcc
+def fails_in_fips_mode(expected_error):
8f0bcc
+    import _hashlib
8f0bcc
+    if _hashlib.get_fips_mode():
8f0bcc
+        def _decorator(func):
8f0bcc
+            def _wrapper(self, *args, **kwargs):
8f0bcc
+                with self.assertRaises(expected_error):
8f0bcc
+                    func(self, *args, **kwargs)
8f0bcc
+            return _wrapper
8f0bcc
+    else:
8f0bcc
+        def _decorator(func):
8f0bcc
+            return func
8f0bcc
+    return _decorator
8f0bcc
diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
8f0bcc
index 7cb1370..61df232 100644
8f0bcc
--- a/Lib/test/test_cmd_line_script.py
8f0bcc
+++ b/Lib/test/test_cmd_line_script.py
8f0bcc
@@ -282,6 +282,7 @@ class CmdLineTest(unittest.TestCase):
8f0bcc
             self._check_script(zip_name, run_name, zip_name, zip_name, '',
8f0bcc
                                zipimport.zipimporter)
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_zipfile_compiled_checked_hash(self):
8f0bcc
         with support.temp_dir() as script_dir:
8f0bcc
             script_name = _make_test_script(script_dir, '__main__')
8f0bcc
@@ -292,6 +293,7 @@ class CmdLineTest(unittest.TestCase):
8f0bcc
             self._check_script(zip_name, run_name, zip_name, zip_name, '',
8f0bcc
                                zipimport.zipimporter)
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_zipfile_compiled_unchecked_hash(self):
8f0bcc
         with support.temp_dir() as script_dir:
8f0bcc
             script_name = _make_test_script(script_dir, '__main__')
8f0bcc
diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py
8f0bcc
index ab647d6..7d50f07 100644
8f0bcc
--- a/Lib/test/test_compileall.py
8f0bcc
+++ b/Lib/test/test_compileall.py
8f0bcc
@@ -758,14 +758,23 @@ class CommandLineTestsBase:
8f0bcc
         out = self.assertRunOK('badfilename')
8f0bcc
         self.assertRegex(out, b"Can't list 'badfilename'")
8f0bcc
 
8f0bcc
-    def test_pyc_invalidation_mode(self):
8f0bcc
+    @support.fails_in_fips_mode(AssertionError)
8f0bcc
+    def test_pyc_invalidation_mode_checked(self):
8f0bcc
         script_helper.make_script(self.pkgdir, 'f1', '')
8f0bcc
         pyc = importlib.util.cache_from_source(
8f0bcc
             os.path.join(self.pkgdir, 'f1.py'))
8f0bcc
+
8f0bcc
         self.assertRunOK('--invalidation-mode=checked-hash', self.pkgdir)
8f0bcc
         with open(pyc, 'rb') as fp:
8f0bcc
             data = fp.read()
8f0bcc
         self.assertEqual(int.from_bytes(data[4:8], 'little'), 0b11)
8f0bcc
+
8f0bcc
+    @support.fails_in_fips_mode(AssertionError)
8f0bcc
+    def test_pyc_invalidation_mode_unchecked(self):
8f0bcc
+        script_helper.make_script(self.pkgdir, 'f1', '')
8f0bcc
+        pyc = importlib.util.cache_from_source(
8f0bcc
+            os.path.join(self.pkgdir, 'f1.py'))
8f0bcc
+
8f0bcc
         self.assertRunOK('--invalidation-mode=unchecked-hash', self.pkgdir)
8f0bcc
         with open(pyc, 'rb') as fp:
8f0bcc
             data = fp.read()
8f0bcc
diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py
8f0bcc
index fe394dc..802f0e8 100644
8f0bcc
--- a/Lib/test/test_imp.py
8f0bcc
+++ b/Lib/test/test_imp.py
8f0bcc
@@ -343,6 +343,7 @@ class ImportTests(unittest.TestCase):
8f0bcc
         import _frozen_importlib
8f0bcc
         self.assertEqual(_frozen_importlib.__spec__.origin, "frozen")
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_source_hash(self):
8f0bcc
         self.assertEqual(_imp.source_hash(42, b'hi'), b'\xc6\xe7Z\r\x03:}\xab')
8f0bcc
         self.assertEqual(_imp.source_hash(43, b'hi'), b'\x85\x9765\xf8\x9a\x8b9')
8f0bcc
@@ -362,6 +363,7 @@ class ImportTests(unittest.TestCase):
8f0bcc
             res = script_helper.assert_python_ok(*args)
8f0bcc
             self.assertEqual(res.out.strip().decode('utf-8'), expected)
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_find_and_load_checked_pyc(self):
8f0bcc
         # issue 34056
8f0bcc
         with support.temp_cwd():
8f0bcc
diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py
8f0bcc
index ab44722..480cc81 100644
8f0bcc
--- a/Lib/test/test_importlib/source/test_file_loader.py
8f0bcc
+++ b/Lib/test/test_importlib/source/test_file_loader.py
8f0bcc
@@ -17,6 +17,7 @@ import types
93c559
 import unittest
93c559
 import warnings
93c559
 
8f0bcc
+from test import support
8f0bcc
 from test.support import make_legacy_pyc, unload
8f0bcc
 
8f0bcc
 from test.test_py_compile import without_source_date_epoch
8f0bcc
@@ -239,6 +240,7 @@ class SimpleTest(abc.LoaderTests):
8f0bcc
                 loader.load_module('bad name')
8f0bcc
 
8f0bcc
     @util.writes_bytecode_files
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_checked_hash_based_pyc(self):
8f0bcc
         with util.create_modules('_temp') as mapping:
8f0bcc
             source = mapping['_temp']
8f0bcc
@@ -270,6 +272,7 @@ class SimpleTest(abc.LoaderTests):
8f0bcc
             )
8f0bcc
 
8f0bcc
     @util.writes_bytecode_files
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_overridden_checked_hash_based_pyc(self):
8f0bcc
         with util.create_modules('_temp') as mapping, \
8f0bcc
              unittest.mock.patch('_imp.check_hash_based_pycs', 'never'):
8f0bcc
@@ -295,6 +298,7 @@ class SimpleTest(abc.LoaderTests):
8f0bcc
             self.assertEqual(mod.state, 'old')
8f0bcc
 
8f0bcc
     @util.writes_bytecode_files
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_unchecked_hash_based_pyc(self):
8f0bcc
         with util.create_modules('_temp') as mapping:
8f0bcc
             source = mapping['_temp']
8f0bcc
@@ -325,6 +329,7 @@ class SimpleTest(abc.LoaderTests):
8f0bcc
             )
8f0bcc
 
8f0bcc
     @util.writes_bytecode_files
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def test_overridden_unchecked_hash_based_pyc(self):
8f0bcc
         with util.create_modules('_temp') as mapping, \
8f0bcc
              unittest.mock.patch('_imp.check_hash_based_pycs', 'always'):
8f0bcc
@@ -434,6 +439,7 @@ class BadBytecodeTest:
8f0bcc
                                                del_source=del_source)
8f0bcc
             test('_temp', mapping, bc_path)
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def _test_partial_hash(self, test, *, del_source=False):
8f0bcc
         with util.create_modules('_temp') as mapping:
8f0bcc
             bc_path = self.manipulate_bytecode(
8f0bcc
diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py
8f0bcc
index b2d3dcf..7e4b0c5 100644
8f0bcc
--- a/Lib/test/test_py_compile.py
8f0bcc
+++ b/Lib/test/test_py_compile.py
8f0bcc
@@ -141,13 +141,16 @@ class PyCompileTestsBase:
8f0bcc
             importlib.util.cache_from_source(bad_coding)))
8f0bcc
 
8f0bcc
     def test_source_date_epoch(self):
8f0bcc
+        import _hashlib
8f0bcc
         py_compile.compile(self.source_path, self.pyc_path)
8f0bcc
         self.assertTrue(os.path.exists(self.pyc_path))
8f0bcc
         self.assertFalse(os.path.exists(self.cache_path))
8f0bcc
         with open(self.pyc_path, 'rb') as fp:
8f0bcc
             flags = importlib._bootstrap_external._classify_pyc(
8f0bcc
                 fp.read(), 'test', {})
8f0bcc
-        if os.environ.get('SOURCE_DATE_EPOCH'):
8f0bcc
+        if _hashlib.get_fips_mode():
8f0bcc
+            expected_flags = 0b00
8f0bcc
+        elif os.environ.get('SOURCE_DATE_EPOCH'):
8f0bcc
             expected_flags = 0b11
8f0bcc
         else:
8f0bcc
             expected_flags = 0b00
8f0bcc
@@ -178,7 +181,8 @@ class PyCompileTestsBase:
8f0bcc
         # Specifying optimized bytecode should lead to a path reflecting that.
8f0bcc
         self.assertIn('opt-2', py_compile.compile(self.source_path, optimize=2))
8f0bcc
 
8f0bcc
-    def test_invalidation_mode(self):
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
+    def test_invalidation_mode_checked(self):
8f0bcc
         py_compile.compile(
8f0bcc
             self.source_path,
8f0bcc
             invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
8f0bcc
@@ -187,6 +191,9 @@ class PyCompileTestsBase:
8f0bcc
             flags = importlib._bootstrap_external._classify_pyc(
8f0bcc
                 fp.read(), 'test', {})
8f0bcc
         self.assertEqual(flags, 0b11)
8f0bcc
+
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
+    def test_invalidation_mode_unchecked(self):
8f0bcc
         py_compile.compile(
8f0bcc
             self.source_path,
8f0bcc
             invalidation_mode=py_compile.PycInvalidationMode.UNCHECKED_HASH,
8f0bcc
diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py
8f0bcc
index b7347a3..09ea990 100644
8f0bcc
--- a/Lib/test/test_zipimport.py
8f0bcc
+++ b/Lib/test/test_zipimport.py
8f0bcc
@@ -186,6 +186,7 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
8f0bcc
                  TESTMOD + pyc_ext: (NOW, test_pyc)}
8f0bcc
         self.doTest(pyc_ext, files, TESTMOD)
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     def testUncheckedHashBasedPyc(self):
8f0bcc
         source = b"state = 'old'"
8f0bcc
         source_hash = importlib.util.source_hash(source)
8f0bcc
@@ -200,6 +201,7 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
8f0bcc
             self.assertEqual(mod.state, 'old')
8f0bcc
         self.doTest(None, files, TESTMOD, call=check)
8f0bcc
 
8f0bcc
+    @support.fails_in_fips_mode(ImportError)
8f0bcc
     @unittest.mock.patch('_imp.check_hash_based_pycs', 'always')
8f0bcc
     def test_checked_hash_based_change_pyc(self):
8f0bcc
         source = b"state = 'old'"
8f0bcc
diff --git a/Python/import.c b/Python/import.c
8f0bcc
index 8358d70..1b7fb85 100644
8f0bcc
--- a/Python/import.c
8f0bcc
+++ b/Python/import.c
8f0bcc
@@ -2354,6 +2354,26 @@ static PyObject *
8f0bcc
 _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source)
8f0bcc
 /*[clinic end generated code: output=edb292448cf399ea input=9aaad1e590089789]*/
8f0bcc
 {
8f0bcc
+    PyObject *_hashlib = PyImport_ImportModule("_hashlib");
8f0bcc
+    if (_hashlib == NULL) {
93c559
+        return NULL;
93c559
+    }
8f0bcc
+    PyObject *fips_mode_obj = PyObject_CallMethod(_hashlib, "get_fips_mode", NULL);
8f0bcc
+    Py_DECREF(_hashlib);
8f0bcc
+    if (fips_mode_obj == NULL) {
8f0bcc
+        return NULL;
93c559
+    }
8f0bcc
+    int fips_mode = PyObject_IsTrue(fips_mode_obj);
8f0bcc
+    Py_DECREF(fips_mode_obj);
8f0bcc
+    if (fips_mode < 0) {
8f0bcc
+        return NULL;
93c559
+    }
8f0bcc
+    if (fips_mode) {
8f0bcc
+        PyErr_SetString(
8f0bcc
+            PyExc_ImportError,
8f0bcc
+            "hash-based PYC validation (siphash24) not available in FIPS mode");
8f0bcc
+        return NULL;
8f0bcc
+    };
8f0bcc
     union {
8f0bcc
         uint64_t x;
8f0bcc
         char data[sizeof(uint64_t)];
93c559
-- 
8f0bcc
2.35.3
93c559