Blame SOURCES/00329-fips.patch

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