Blame SOURCES/00329-fips.patch

0e7543
From 5943fa462c4b2afe297b06aaef911efcf935c0d7 Mon Sep 17 00:00:00 2001
0e7543
From: Petr Viktorin <encukou@gmail.com>
0e7543
Date: Wed, 11 Aug 2021 16:51:03 +0200
0e7543
Subject: [PATCH 1/5] Backport PyModule_AddObjectRef as _PyModule_AddObjectRef
0e7543
0e7543
Having PyModule_AddObjectRef available should make backporting
0e7543
newer patches easier. The new API is much safer.
0e7543
The backport adds an underscore so that we don't break extension
0e7543
modules that define PyModule_AddObjectRef themselves on Python<=3.9
0e7543
(which would be a virtuous thing to do).
0e7543
---
0e7543
 Include/modsupport.h | 10 ++++++++++
0e7543
 Python/modsupport.c  | 13 +++++++++++--
0e7543
 2 files changed, 21 insertions(+), 2 deletions(-)
0e7543
0e7543
diff --git a/Include/modsupport.h b/Include/modsupport.h
0e7543
index 4c4aab65ba..d9fac52521 100644
0e7543
--- a/Include/modsupport.h
0e7543
+++ b/Include/modsupport.h
0e7543
@@ -136,7 +136,17 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
0e7543
 void _PyArg_Fini(void);
0e7543
 #endif   /* Py_LIMITED_API */
0e7543
 
0e7543
+// Add an attribute with name 'name' and value 'obj' to the module 'mod.
0e7543
+// On success, return 0 on success.
0e7543
+// On error, raise an exception and return -1.
0e7543
+// Backported from Python 3.10, where it's available without the underscore
0e7543
+// in the name, to ease porting patches to RHEL
0e7543
+PyAPI_FUNC(int) _PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value);
0e7543
+
0e7543
+// Similar to PyModule_AddObjectRef() but steal a reference to 'obj'
0e7543
+// (Py_DECREF(obj)) on success (if it returns 0).
0e7543
 PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *);
0e7543
+
0e7543
 PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
0e7543
 PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *);
0e7543
 #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
0e7543
diff --git a/Python/modsupport.c b/Python/modsupport.c
0e7543
index 13482c6508..fca1083e2d 100644
0e7543
--- a/Python/modsupport.c
0e7543
+++ b/Python/modsupport.c
0e7543
@@ -631,7 +631,7 @@ va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len,
0e7543
 
0e7543
 
0e7543
 int
0e7543
-PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
0e7543
+_PyModule_AddObjectRef(PyObject *m, const char *name, PyObject *o)
0e7543
 {
0e7543
     PyObject *dict;
0e7543
     if (!PyModule_Check(m)) {
0e7543
@@ -655,10 +655,19 @@ PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
0e7543
     }
0e7543
     if (PyDict_SetItemString(dict, name, o))
0e7543
         return -1;
0e7543
-    Py_DECREF(o);
0e7543
     return 0;
0e7543
 }
0e7543
 
0e7543
+int
0e7543
+PyModule_AddObject(PyObject *mod, const char *name, PyObject *value)
0e7543
+{
0e7543
+    int res = _PyModule_AddObjectRef(mod, name, value);
0e7543
+    if (res == 0) {
0e7543
+        Py_DECREF(value);
0e7543
+    }
0e7543
+    return res;
0e7543
+}
0e7543
+
0e7543
 int
0e7543
 PyModule_AddIntConstant(PyObject *m, const char *name, long value)
0e7543
 {
0e7543
-- 
0e7543
2.31.1
0e7543
0e7543
0e7543
From d6ecb3ac9a626af2ecd782d6c7b452251713c4a6 Mon Sep 17 00:00:00 2001
0e7543
From: Petr Viktorin <encukou@gmail.com>
0e7543
Date: Fri, 13 Aug 2021 13:16:43 +0200
0e7543
Subject: [PATCH 2/5] _hashopenssl: Uncomment and use initialization function
0e7543
 list
0e7543
0e7543
This simplifies backporting of future changes.
0e7543
0e7543
We use this change instead of Python 3.10's:
0e7543
    bpo-1635741: Port _hashlib to multiphase initialization (GH-23358)
0e7543
---
0e7543
 Modules/_hashopenssl.c | 26 +++++---------------------
0e7543
 1 file changed, 5 insertions(+), 21 deletions(-)
0e7543
0e7543
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
0e7543
index ff3a1aef5e..db661dc5f7 100644
0e7543
--- a/Modules/_hashopenssl.c
0e7543
+++ b/Modules/_hashopenssl.c
0e7543
@@ -2085,7 +2085,6 @@ hashlib_init_hmactype(PyObject *module)
0e7543
     return 0;
0e7543
 }
0e7543
 
0e7543
-#if 0
0e7543
 static PyModuleDef_Slot hashlib_slots[] = {
0e7543
     /* OpenSSL 1.0.2 and LibreSSL */
0e7543
     {Py_mod_exec, hashlib_openssl_legacy_init},
0e7543
@@ -2095,7 +2094,6 @@ static PyModuleDef_Slot hashlib_slots[] = {
0e7543
     {Py_mod_exec, hashlib_md_meth_names},
0e7543
     {0, NULL}
0e7543
 };
0e7543
-#endif
0e7543
 
0e7543
 static struct PyModuleDef _hashlibmodule = {
0e7543
     PyModuleDef_HEAD_INIT,
0e7543
@@ -2123,25 +2121,11 @@ PyInit__hashlib(void)
0e7543
         return NULL;
0e7543
     }
0e7543
 
0e7543
-    if (hashlib_openssl_legacy_init(m) < 0) {
0e7543
-        Py_DECREF(m);
0e7543
-        return NULL;
0e7543
-    }
0e7543
-    if (hashlib_init_evptype(m) < 0) {
0e7543
-        Py_DECREF(m);
0e7543
-        return NULL;
0e7543
-    }
0e7543
-    if (hashlib_init_evpxoftype(m) < 0) {
0e7543
-        Py_DECREF(m);
0e7543
-        return NULL;
0e7543
-    }
0e7543
-    if (hashlib_init_hmactype(m) < 0) {
0e7543
-        Py_DECREF(m);
0e7543
-        return NULL;
0e7543
-    }
0e7543
-    if (hashlib_md_meth_names(m) == -1) {
0e7543
-        Py_DECREF(m);
0e7543
-        return NULL;
0e7543
+    for (int i=0; hashlib_slots[i].slot; i++) {
0e7543
+        if (((int (*)(PyObject*))hashlib_slots[i].value)(m) < 0) {
0e7543
+            Py_DECREF(m);
0e7543
+            return NULL;
0e7543
+        }
0e7543
     }
0e7543
 
0e7543
     return m;
0e7543
-- 
0e7543
2.31.1
0e7543
0e7543
0e7543
From ce54104e69b9f3e9b3f49cec2054b66e84a5cbb8 Mon Sep 17 00:00:00 2001
0e7543
From: Christian Heimes <christian@python.org>
0e7543
Date: Sat, 27 Mar 2021 14:55:03 +0100
0e7543
Subject: [PATCH 3/5] bpo-40645: use C implementation of HMAC (GH-24920,
0e7543
 GH-25063, GH-26079)
0e7543
0e7543
This backports the feature and 2 subsequent bugfixes
0e7543
from: https://bugs.python.org/issue40645
0e7543
0e7543
Signed-off-by: Christian Heimes <christian@python.org>
0e7543
Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
0e7543
Co-Authored-By: Pablo Galindo <Pablogsal@gmail.com>
0e7543
---
0e7543
 Lib/hashlib.py                                |   1 +
0e7543
 Lib/hmac.py                                   |  86 ++++++----
0e7543
 Lib/test/test_hmac.py                         | 114 ++++++++-----
0e7543
 .../2021-03-29-11-55-06.bpo-40645.PhaT-B.rst  |   2 +
0e7543
 .../2021-03-19-10-22-17.bpo-40645.5pXhb-.rst  |   2 +
0e7543
 Modules/_hashopenssl.c                        | 158 ++++++++++++++++--
0e7543
 Modules/clinic/_hashopenssl.c.h               |  38 +----
0e7543
 7 files changed, 276 insertions(+), 125 deletions(-)
0e7543
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-03-29-11-55-06.bpo-40645.PhaT-B.rst
0e7543
 create mode 100644 Misc/NEWS.d/next/Library/2021-03-19-10-22-17.bpo-40645.5pXhb-.rst
0e7543
0e7543
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
0e7543
index 58c340d56e..ffa3be049a 100644
0e7543
--- a/Lib/hashlib.py
0e7543
+++ b/Lib/hashlib.py
0e7543
@@ -173,6 +173,7 @@ try:
0e7543
     algorithms_available = algorithms_available.union(
0e7543
             _hashlib.openssl_md_meth_names)
0e7543
 except ImportError:
0e7543
+    _hashlib = None
0e7543
     new = __py_new
0e7543
     __get_hash = __get_builtin_constructor
0e7543
 
0e7543
diff --git a/Lib/hmac.py b/Lib/hmac.py
0e7543
index 180bc378b5..8b4f920db9 100644
0e7543
--- a/Lib/hmac.py
0e7543
+++ b/Lib/hmac.py
0e7543
@@ -8,11 +8,12 @@ try:
0e7543
     import _hashlib as _hashopenssl
0e7543
 except ImportError:
0e7543
     _hashopenssl = None
0e7543
-    _openssl_md_meths = None
0e7543
+    _functype = None
0e7543
     from _operator import _compare_digest as compare_digest
0e7543
 else:
0e7543
-    _openssl_md_meths = frozenset(_hashopenssl.openssl_md_meth_names)
0e7543
     compare_digest = _hashopenssl.compare_digest
0e7543
+    _functype = type(_hashopenssl.openssl_sha256)  # builtin type
0e7543
+
0e7543
 import hashlib as _hashlib
0e7543
 
0e7543
 trans_5C = bytes((x ^ 0x5C) for x in range(256))
0e7543
@@ -23,7 +24,6 @@ trans_36 = bytes((x ^ 0x36) for x in range(256))
0e7543
 digest_size = None
0e7543
 
0e7543
 
0e7543
-
0e7543
 class HMAC:
0e7543
     """RFC 2104 HMAC class.  Also complies with RFC 4231.
0e7543
 
0e7543
@@ -32,7 +32,7 @@ class HMAC:
0e7543
     blocksize = 64  # 512-bit HMAC; can be changed in subclasses.
0e7543
 
0e7543
     __slots__ = (
0e7543
-        "_digest_cons", "_inner", "_outer", "block_size", "digest_size"
0e7543
+        "_hmac", "_inner", "_outer", "block_size", "digest_size"
0e7543
     )
0e7543
 
0e7543
     def __init__(self, key, msg=None, digestmod=''):
0e7543
@@ -55,15 +55,30 @@ class HMAC:
0e7543
         if not digestmod:
0e7543
             raise TypeError("Missing required parameter 'digestmod'.")
0e7543
 
0e7543
+        if _hashopenssl and isinstance(digestmod, (str, _functype)):
0e7543
+            try:
0e7543
+                self._init_hmac(key, msg, digestmod)
0e7543
+            except _hashopenssl.UnsupportedDigestmodError:
0e7543
+                self._init_old(key, msg, digestmod)
0e7543
+        else:
0e7543
+            self._init_old(key, msg, digestmod)
0e7543
+
0e7543
+    def _init_hmac(self, key, msg, digestmod):
0e7543
+        self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod)
0e7543
+        self.digest_size = self._hmac.digest_size
0e7543
+        self.block_size = self._hmac.block_size
0e7543
+
0e7543
+    def _init_old(self, key, msg, digestmod):
0e7543
         if callable(digestmod):
0e7543
-            self._digest_cons = digestmod
0e7543
+            digest_cons = digestmod
0e7543
         elif isinstance(digestmod, str):
0e7543
-            self._digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
0e7543
+            digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
0e7543
         else:
0e7543
-            self._digest_cons = lambda d=b'': digestmod.new(d)
0e7543
+            digest_cons = lambda d=b'': digestmod.new(d)
0e7543
 
0e7543
-        self._outer = self._digest_cons()
0e7543
-        self._inner = self._digest_cons()
0e7543
+        self._hmac = None
0e7543
+        self._outer = digest_cons()
0e7543
+        self._inner = digest_cons()
0e7543
         self.digest_size = self._inner.digest_size
0e7543
 
0e7543
         if hasattr(self._inner, 'block_size'):
0e7543
@@ -79,13 +94,13 @@ class HMAC:
0e7543
                            RuntimeWarning, 2)
0e7543
             blocksize = self.blocksize
0e7543
 
0e7543
+        if len(key) > blocksize:
0e7543
+            key = digest_cons(key).digest()
0e7543
+
0e7543
         # self.blocksize is the default blocksize. self.block_size is
0e7543
         # effective block size as well as the public API attribute.
0e7543
         self.block_size = blocksize
0e7543
 
0e7543
-        if len(key) > blocksize:
0e7543
-            key = self._digest_cons(key).digest()
0e7543
-
0e7543
         key = key.ljust(blocksize, b'\0')
0e7543
         self._outer.update(key.translate(trans_5C))
0e7543
         self._inner.update(key.translate(trans_36))
0e7543
@@ -94,23 +109,15 @@ class HMAC:
0e7543
 
0e7543
     @property
0e7543
     def name(self):
0e7543
-        return "hmac-" + self._inner.name
0e7543
-
0e7543
-    @property
0e7543
-    def digest_cons(self):
0e7543
-        return self._digest_cons
0e7543
-
0e7543
-    @property
0e7543
-    def inner(self):
0e7543
-        return self._inner
0e7543
-
0e7543
-    @property
0e7543
-    def outer(self):
0e7543
-        return self._outer
0e7543
+        if self._hmac:
0e7543
+            return self._hmac.name
0e7543
+        else:
0e7543
+            return f"hmac-{self._inner.name}"
0e7543
 
0e7543
     def update(self, msg):
0e7543
         """Feed data from msg into this hashing object."""
0e7543
-        self._inner.update(msg)
0e7543
+        inst = self._hmac or self._inner
0e7543
+        inst.update(msg)
0e7543
 
0e7543
     def copy(self):
0e7543
         """Return a separate copy of this hashing object.
0e7543
@@ -119,10 +126,14 @@ class HMAC:
0e7543
         """
0e7543
         # Call __new__ directly to avoid the expensive __init__.
0e7543
         other = self.__class__.__new__(self.__class__)
0e7543
-        other._digest_cons = self._digest_cons
0e7543
         other.digest_size = self.digest_size
0e7543
-        other._inner = self._inner.copy()
0e7543
-        other._outer = self._outer.copy()
0e7543
+        if self._hmac:
0e7543
+            other._hmac = self._hmac.copy()
0e7543
+            other._inner = other._outer = None
0e7543
+        else:
0e7543
+            other._hmac = None
0e7543
+            other._inner = self._inner.copy()
0e7543
+            other._outer = self._outer.copy()
0e7543
         return other
0e7543
 
0e7543
     def _current(self):
0e7543
@@ -130,9 +141,12 @@ class HMAC:
0e7543
 
0e7543
         To be used only internally with digest() and hexdigest().
0e7543
         """
0e7543
-        h = self._outer.copy()
0e7543
-        h.update(self._inner.digest())
0e7543
-        return h
0e7543
+        if self._hmac:
0e7543
+            return self._hmac
0e7543
+        else:
0e7543
+            h = self._outer.copy()
0e7543
+            h.update(self._inner.digest())
0e7543
+            return h
0e7543
 
0e7543
     def digest(self):
0e7543
         """Return the hash value of this hashing object.
0e7543
@@ -179,9 +193,11 @@ def digest(key, msg, digest):
0e7543
             A hashlib constructor returning a new hash object. *OR*
0e7543
             A module supporting PEP 247.
0e7543
     """
0e7543
-    if (_hashopenssl is not None and
0e7543
-            isinstance(digest, str) and digest in _openssl_md_meths):
0e7543
-        return _hashopenssl.hmac_digest(key, msg, digest)
0e7543
+    if _hashopenssl is not None and isinstance(digest, (str, _functype)):
0e7543
+        try:
0e7543
+            return _hashopenssl.hmac_digest(key, msg, digest)
0e7543
+        except _hashopenssl.UnsupportedDigestmodError:
0e7543
+            pass
0e7543
 
0e7543
     if callable(digest):
0e7543
         digest_cons = digest
0e7543
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
0e7543
index 6daf22ca06..adf52adbf2 100644
0e7543
--- a/Lib/test/test_hmac.py
0e7543
+++ b/Lib/test/test_hmac.py
0e7543
@@ -11,14 +11,21 @@ from test.support import hashlib_helper
0e7543
 from _operator import _compare_digest as operator_compare_digest
0e7543
 
0e7543
 try:
0e7543
+    import _hashlib as _hashopenssl
0e7543
     from _hashlib import HMAC as C_HMAC
0e7543
     from _hashlib import hmac_new as c_hmac_new
0e7543
     from _hashlib import compare_digest as openssl_compare_digest
0e7543
 except ImportError:
0e7543
+    _hashopenssl = None
0e7543
     C_HMAC = None
0e7543
     c_hmac_new = None
0e7543
     openssl_compare_digest = None
0e7543
 
0e7543
+try:
0e7543
+    import _sha256 as sha256_module
0e7543
+except ImportError:
0e7543
+    sha256_module = None
0e7543
+
0e7543
 
0e7543
 def ignore_warning(func):
0e7543
     @functools.wraps(func)
0e7543
@@ -32,22 +39,27 @@ def ignore_warning(func):
0e7543
 
0e7543
 class TestVectorsTestCase(unittest.TestCase):
0e7543
 
0e7543
-    def asssert_hmac(
0e7543
-        self, key, data, digest, hashfunc, hashname, digest_size, block_size
0e7543
+    def assert_hmac_internals(
0e7543
+            self, h, digest, hashname, digest_size, block_size
0e7543
     ):
0e7543
-        h = hmac.HMAC(key, data, digestmod=hashfunc)
0e7543
         self.assertEqual(h.hexdigest().upper(), digest.upper())
0e7543
         self.assertEqual(h.digest(), binascii.unhexlify(digest))
0e7543
         self.assertEqual(h.name, f"hmac-{hashname}")
0e7543
         self.assertEqual(h.digest_size, digest_size)
0e7543
         self.assertEqual(h.block_size, block_size)
0e7543
 
0e7543
+    def assert_hmac(
0e7543
+        self, key, data, digest, hashfunc, hashname, digest_size, block_size
0e7543
+    ):
0e7543
+        h = hmac.HMAC(key, data, digestmod=hashfunc)
0e7543
+        self.assert_hmac_internals(
0e7543
+            h, digest, hashname, digest_size, block_size
0e7543
+        )
0e7543
+
0e7543
         h = hmac.HMAC(key, data, digestmod=hashname)
0e7543
-        self.assertEqual(h.hexdigest().upper(), digest.upper())
0e7543
-        self.assertEqual(h.digest(), binascii.unhexlify(digest))
0e7543
-        self.assertEqual(h.name, f"hmac-{hashname}")
0e7543
-        self.assertEqual(h.digest_size, digest_size)
0e7543
-        self.assertEqual(h.block_size, block_size)
0e7543
+        self.assert_hmac_internals(
0e7543
+            h, digest, hashname, digest_size, block_size
0e7543
+        )
0e7543
 
0e7543
         h = hmac.HMAC(key, digestmod=hashname)
0e7543
         h2 = h.copy()
0e7543
@@ -56,11 +68,9 @@ class TestVectorsTestCase(unittest.TestCase):
0e7543
         self.assertEqual(h.hexdigest().upper(), digest.upper())
0e7543
 
0e7543
         h = hmac.new(key, data, digestmod=hashname)
0e7543
-        self.assertEqual(h.hexdigest().upper(), digest.upper())
0e7543
-        self.assertEqual(h.digest(), binascii.unhexlify(digest))
0e7543
-        self.assertEqual(h.name, f"hmac-{hashname}")
0e7543
-        self.assertEqual(h.digest_size, digest_size)
0e7543
-        self.assertEqual(h.block_size, block_size)
0e7543
+        self.assert_hmac_internals(
0e7543
+            h, digest, hashname, digest_size, block_size
0e7543
+        )
0e7543
 
0e7543
         h = hmac.new(key, None, digestmod=hashname)
0e7543
         h.update(data)
0e7543
@@ -81,23 +91,18 @@ class TestVectorsTestCase(unittest.TestCase):
0e7543
             hmac.digest(key, data, digest=hashfunc),
0e7543
             binascii.unhexlify(digest)
0e7543
         )
0e7543
-        with unittest.mock.patch('hmac._openssl_md_meths', {}):
0e7543
-            self.assertEqual(
0e7543
-                hmac.digest(key, data, digest=hashname),
0e7543
-                binascii.unhexlify(digest)
0e7543
-            )
0e7543
-            self.assertEqual(
0e7543
-                hmac.digest(key, data, digest=hashfunc),
0e7543
-                binascii.unhexlify(digest)
0e7543
-            )
0e7543
+
0e7543
+        h = hmac.HMAC.__new__(hmac.HMAC)
0e7543
+        h._init_old(key, data, digestmod=hashname)
0e7543
+        self.assert_hmac_internals(
0e7543
+            h, digest, hashname, digest_size, block_size
0e7543
+        )
0e7543
 
0e7543
         if c_hmac_new is not None:
0e7543
             h = c_hmac_new(key, data, digestmod=hashname)
0e7543
-            self.assertEqual(h.hexdigest().upper(), digest.upper())
0e7543
-            self.assertEqual(h.digest(), binascii.unhexlify(digest))
0e7543
-            self.assertEqual(h.name, f"hmac-{hashname}")
0e7543
-            self.assertEqual(h.digest_size, digest_size)
0e7543
-            self.assertEqual(h.block_size, block_size)
0e7543
+            self.assert_hmac_internals(
0e7543
+                h, digest, hashname, digest_size, block_size
0e7543
+            )
0e7543
 
0e7543
             h = c_hmac_new(key, digestmod=hashname)
0e7543
             h2 = h.copy()
0e7543
@@ -105,12 +110,24 @@ class TestVectorsTestCase(unittest.TestCase):
0e7543
             h.update(data)
0e7543
             self.assertEqual(h.hexdigest().upper(), digest.upper())
0e7543
 
0e7543
+            func = getattr(_hashopenssl, f"openssl_{hashname}")
0e7543
+            h = c_hmac_new(key, data, digestmod=func)
0e7543
+            self.assert_hmac_internals(
0e7543
+                h, digest, hashname, digest_size, block_size
0e7543
+            )
0e7543
+
0e7543
+            h = hmac.HMAC.__new__(hmac.HMAC)
0e7543
+            h._init_hmac(key, data, digestmod=hashname)
0e7543
+            self.assert_hmac_internals(
0e7543
+                h, digest, hashname, digest_size, block_size
0e7543
+            )
0e7543
+
0e7543
     @hashlib_helper.requires_hashdigest('md5', openssl=True)
0e7543
     def test_md5_vectors(self):
0e7543
         # Test the HMAC module against test vectors from the RFC.
0e7543
 
0e7543
         def md5test(key, data, digest):
0e7543
-            self.asssert_hmac(
0e7543
+            self.assert_hmac(
0e7543
                 key, data, digest,
0e7543
                 hashfunc=hashlib.md5,
0e7543
                 hashname="md5",
0e7543
@@ -150,7 +167,7 @@ class TestVectorsTestCase(unittest.TestCase):
0e7543
     @hashlib_helper.requires_hashdigest('sha1', openssl=True)
0e7543
     def test_sha_vectors(self):
0e7543
         def shatest(key, data, digest):
0e7543
-            self.asssert_hmac(
0e7543
+            self.assert_hmac(
0e7543
                 key, data, digest,
0e7543
                 hashfunc=hashlib.sha1,
0e7543
                 hashname="sha1",
0e7543
@@ -191,7 +208,7 @@ class TestVectorsTestCase(unittest.TestCase):
0e7543
         def hmactest(key, data, hexdigests):
0e7543
             digest = hexdigests[hashfunc]
0e7543
 
0e7543
-            self.asssert_hmac(
0e7543
+            self.assert_hmac(
0e7543
                 key, data, digest,
0e7543
                 hashfunc=hashfunc,
0e7543
                 hashname=hash_name,
0e7543
@@ -427,6 +444,15 @@ class ConstructorTestCase(unittest.TestCase):
0e7543
         ):
0e7543
             C_HMAC()
0e7543
 
0e7543
+    @unittest.skipUnless(sha256_module is not None, 'need _sha256')
0e7543
+    def test_with_sha256_module(self):
0e7543
+        h = hmac.HMAC(b"key", b"hash this!", digestmod=sha256_module.sha256)
0e7543
+        self.assertEqual(h.hexdigest(), self.expected)
0e7543
+        self.assertEqual(h.name, "hmac-sha256")
0e7543
+
0e7543
+        digest = hmac.digest(b"key", b"hash this!", sha256_module.sha256)
0e7543
+        self.assertEqual(digest, binascii.unhexlify(self.expected))
0e7543
+
0e7543
 
0e7543
 class SanityTestCase(unittest.TestCase):
0e7543
 
0e7543
@@ -447,21 +473,21 @@ class SanityTestCase(unittest.TestCase):
0e7543
 class CopyTestCase(unittest.TestCase):
0e7543
 
0e7543
     @hashlib_helper.requires_hashdigest('sha256')
0e7543
-    def test_attributes(self):
0e7543
+    def test_attributes_old(self):
0e7543
         # Testing if attributes are of same type.
0e7543
-        h1 = hmac.HMAC(b"key", digestmod="sha256")
0e7543
+        h1 = hmac.HMAC.__new__(hmac.HMAC)
0e7543
+        h1._init_old(b"key", b"msg", digestmod="sha256")
0e7543
         h2 = h1.copy()
0e7543
-        self.assertTrue(h1._digest_cons == h2._digest_cons,
0e7543
-            "digest constructors don't match.")
0e7543
         self.assertEqual(type(h1._inner), type(h2._inner),
0e7543
             "Types of inner don't match.")
0e7543
         self.assertEqual(type(h1._outer), type(h2._outer),
0e7543
             "Types of outer don't match.")
0e7543
 
0e7543
     @hashlib_helper.requires_hashdigest('sha256')
0e7543
-    def test_realcopy(self):
0e7543
+    def test_realcopy_old(self):
0e7543
         # Testing if the copy method created a real copy.
0e7543
-        h1 = hmac.HMAC(b"key", digestmod="sha256")
0e7543
+        h1 = hmac.HMAC.__new__(hmac.HMAC)
0e7543
+        h1._init_old(b"key", b"msg", digestmod="sha256")
0e7543
         h2 = h1.copy()
0e7543
         # Using id() in case somebody has overridden __eq__/__ne__.
0e7543
         self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.")
0e7543
@@ -469,17 +495,15 @@ class CopyTestCase(unittest.TestCase):
0e7543
             "No real copy of the attribute 'inner'.")
0e7543
         self.assertTrue(id(h1._outer) != id(h2._outer),
0e7543
             "No real copy of the attribute 'outer'.")
0e7543
-        self.assertEqual(h1._inner, h1.inner)
0e7543
-        self.assertEqual(h1._outer, h1.outer)
0e7543
-        self.assertEqual(h1._digest_cons, h1.digest_cons)
0e7543
+        self.assertIs(h1._hmac, None)
0e7543
 
0e7543
+    @unittest.skipIf(_hashopenssl is None, "test requires _hashopenssl")
0e7543
     @hashlib_helper.requires_hashdigest('sha256')
0e7543
-    def test_properties(self):
0e7543
-        # deprecated properties
0e7543
-        h1 = hmac.HMAC(b"key", digestmod="sha256")
0e7543
-        self.assertEqual(h1._inner, h1.inner)
0e7543
-        self.assertEqual(h1._outer, h1.outer)
0e7543
-        self.assertEqual(h1._digest_cons, h1.digest_cons)
0e7543
+    def test_realcopy_hmac(self):
0e7543
+        h1 = hmac.HMAC.__new__(hmac.HMAC)
0e7543
+        h1._init_hmac(b"key", b"msg", digestmod="sha256")
0e7543
+        h2 = h1.copy()
0e7543
+        self.assertTrue(id(h1._hmac) != id(h2._hmac))
0e7543
 
0e7543
     @hashlib_helper.requires_hashdigest('sha256')
0e7543
     def test_equality(self):
0e7543
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-03-29-11-55-06.bpo-40645.PhaT-B.rst b/Misc/NEWS.d/next/Core and Builtins/2021-03-29-11-55-06.bpo-40645.PhaT-B.rst
0e7543
new file mode 100644
0e7543
index 0000000000..9ca9843947
0e7543
--- /dev/null
0e7543
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-03-29-11-55-06.bpo-40645.PhaT-B.rst	
0e7543
@@ -0,0 +1,2 @@
0e7543
+Fix reference leak in the :mod:`_hashopenssl` extension. Patch by Pablo
0e7543
+Galindo.
0e7543
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
0e7543
new file mode 100644
0e7543
index 0000000000..a9ab1c0915
0e7543
--- /dev/null
0e7543
+++ b/Misc/NEWS.d/next/Library/2021-03-19-10-22-17.bpo-40645.5pXhb-.rst
0e7543
@@ -0,0 +1,2 @@
0e7543
+The :mod:`hmac` module now uses OpenSSL's HMAC implementation when digestmod
0e7543
+argument is a hash name or builtin hash function.
0e7543
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
0e7543
index db661dc5f7..fd3b3c0719 100644
0e7543
--- a/Modules/_hashopenssl.c
0e7543
+++ b/Modules/_hashopenssl.c
0e7543
@@ -92,6 +92,8 @@ typedef struct {
0e7543
 #ifdef PY_OPENSSL_HAS_SHAKE
0e7543
     PyTypeObject *EVPXOFtype;
0e7543
 #endif
0e7543
+    PyObject *constructs;
0e7543
+    PyObject *unsupported_digestmod_error;
0e7543
 } _hashlibstate;
0e7543
 
0e7543
 static inline _hashlibstate*
0e7543
@@ -295,9 +297,56 @@ py_digest_by_name(const char *name)
0e7543
 #endif
0e7543
     }
0e7543
 
0e7543
+    if (digest == NULL) {
0e7543
+        PyErr_Format(PyExc_ValueError, "unsupported hash type %s", name);
0e7543
+        return NULL;
0e7543
+    }
0e7543
+
0e7543
     return digest;
0e7543
 }
0e7543
 
0e7543
+/* Get digest EVP from object
0e7543
+ *
0e7543
+ * * string
0e7543
+ * * _hashopenssl builtin function
0e7543
+ *
0e7543
+ * on error returns NULL with exception set.
0e7543
+ */
0e7543
+static const EVP_MD*
0e7543
+py_digest_by_digestmod(PyObject *module, PyObject *digestmod) {
0e7543
+    const EVP_MD* evp;
0e7543
+    PyObject *name_obj = NULL;
0e7543
+    const char *name;
0e7543
+
0e7543
+    if (PyUnicode_Check(digestmod)) {
0e7543
+        name_obj = digestmod;
0e7543
+    } else {
0e7543
+        _hashlibstate *state = get_hashlib_state(module);
0e7543
+        // borrowed ref
0e7543
+        name_obj = PyDict_GetItem(state->constructs, digestmod);
0e7543
+    }
0e7543
+    if (name_obj == NULL) {
0e7543
+        _hashlibstate *state = get_hashlib_state(module);
0e7543
+        PyErr_Clear();
0e7543
+        PyErr_Format(
0e7543
+            state->unsupported_digestmod_error,
0e7543
+            "Unsupported digestmod %R", digestmod);
0e7543
+        return NULL;
0e7543
+    }
0e7543
+
0e7543
+    name = PyUnicode_AsUTF8(name_obj);
0e7543
+    if (name == NULL) {
0e7543
+        return NULL;
0e7543
+    }
0e7543
+
0e7543
+    evp = py_digest_by_name(name);
0e7543
+    if (evp == NULL) {
0e7543
+        return NULL;
0e7543
+    }
0e7543
+
0e7543
+    return evp;
0e7543
+}
0e7543
+
0e7543
 static EVPobject *
0e7543
 newEVPobject(PyTypeObject *type)
0e7543
 {
0e7543
@@ -822,7 +871,7 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj,
0e7543
 /*[clinic end generated code: output=ddd5053f92dffe90 input=c24554d0337be1b0]*/
0e7543
 {
0e7543
     Py_buffer view = { 0 };
0e7543
-    PyObject *ret_obj;
0e7543
+    PyObject *ret_obj = NULL;
0e7543
     char *name;
0e7543
     const EVP_MD *digest = NULL;
0e7543
 
0e7543
@@ -835,11 +884,15 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj,
0e7543
         GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
0e7543
 
0e7543
     digest = py_digest_by_name(name);
0e7543
+    if (digest == NULL) {
0e7543
+        goto exit;
0e7543
+    }
0e7543
 
0e7543
     ret_obj = EVPnew(module, digest,
0e7543
                      (unsigned char*)view.buf, view.len,
0e7543
                      usedforsecurity);
0e7543
 
0e7543
+exit:
0e7543
     if (data_obj)
0e7543
         PyBuffer_Release(&view);
0e7543
     return ret_obj;
0e7543
@@ -1130,7 +1183,6 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name,
0e7543
 
0e7543
     digest = py_digest_by_name(hash_name);
0e7543
     if (digest == NULL) {
0e7543
-        PyErr_SetString(PyExc_ValueError, "unsupported hash type");
0e7543
         goto end;
0e7543
     }
0e7543
 
0e7543
@@ -1334,26 +1386,26 @@ _hashlib.hmac_digest as _hashlib_hmac_singleshot
0e7543
 
0e7543
     key: Py_buffer
0e7543
     msg: Py_buffer
0e7543
-    digest: str
0e7543
+    digest: object
0e7543
 
0e7543
 Single-shot HMAC.
0e7543
 [clinic start generated code]*/
0e7543
 
0e7543
 static PyObject *
0e7543
 _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
0e7543
-                              Py_buffer *msg, const char *digest)
0e7543
-/*[clinic end generated code: output=15658ede5ab98185 input=019dffc571909a46]*/
0e7543
+                              Py_buffer *msg, PyObject *digest)
0e7543
+/*[clinic end generated code: output=82f19965d12706ac input=0a0790cc3db45c2e]*/
0e7543
 {
0e7543
     unsigned char md[EVP_MAX_MD_SIZE] = {0};
0e7543
     unsigned int md_len = 0;
0e7543
     unsigned char *result;
0e7543
     const EVP_MD *evp;
0e7543
 
0e7543
-    evp = py_digest_by_name(digest);
0e7543
+    evp = py_digest_by_digestmod(module, digest);
0e7543
     if (evp == NULL) {
0e7543
-        PyErr_SetString(PyExc_ValueError, "unsupported hash type");
0e7543
         return NULL;
0e7543
     }
0e7543
+
0e7543
     if (key->len > INT_MAX) {
0e7543
         PyErr_SetString(PyExc_OverflowError,
0e7543
                         "key is too long.");
0e7543
@@ -1391,15 +1443,15 @@ _hashlib.hmac_new
0e7543
 
0e7543
     key: Py_buffer
0e7543
     msg as msg_obj: object(c_default="NULL") = b''
0e7543
-    digestmod: str(c_default="NULL") = None
0e7543
+    digestmod: object(c_default="NULL") = None
0e7543
 
0e7543
 Return a new hmac object.
0e7543
 [clinic start generated code]*/
0e7543
 
0e7543
 static PyObject *
0e7543
 _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
0e7543
-                       const char *digestmod)
0e7543
-/*[clinic end generated code: output=9a35673be0cbea1b input=a0878868eb190134]*/
0e7543
+                       PyObject *digestmod)
0e7543
+/*[clinic end generated code: output=c20d9e4d9ed6d219 input=5f4071dcc7f34362]*/
0e7543
 {
0e7543
     PyTypeObject *type = get_hashlib_state(module)->HMACtype;
0e7543
     const EVP_MD *digest;
0e7543
@@ -1413,15 +1465,14 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
0e7543
         return NULL;
0e7543
     }
0e7543
 
0e7543
-    if ((digestmod == NULL) || !strlen(digestmod)) {
0e7543
+    if (digestmod == NULL) {
0e7543
         PyErr_SetString(
0e7543
             PyExc_TypeError, "Missing required parameter 'digestmod'.");
0e7543
         return NULL;
0e7543
     }
0e7543
 
0e7543
-    digest = py_digest_by_name(digestmod);
0e7543
-    if (!digest) {
0e7543
-        PyErr_SetString(PyExc_ValueError, "unknown hash function");
0e7543
+    digest = py_digest_by_digestmod(module, digestmod);
0e7543
+    if (digest == NULL) {
0e7543
         return NULL;
0e7543
     }
0e7543
 
0e7543
@@ -1992,6 +2043,8 @@ hashlib_traverse(PyObject *m, visitproc visit, void *arg)
0e7543
 #ifdef PY_OPENSSL_HAS_SHAKE
0e7543
     Py_VISIT(state->EVPXOFtype);
0e7543
 #endif
0e7543
+    Py_VISIT(state->constructs);
0e7543
+    Py_VISIT(state->unsupported_digestmod_error);
0e7543
     return 0;
0e7543
 }
0e7543
 
0e7543
@@ -2004,6 +2057,8 @@ hashlib_clear(PyObject *m)
0e7543
 #ifdef PY_OPENSSL_HAS_SHAKE
0e7543
     Py_CLEAR(state->EVPXOFtype);
0e7543
 #endif
0e7543
+    Py_CLEAR(state->constructs);
0e7543
+    Py_CLEAR(state->unsupported_digestmod_error);
0e7543
     return 0;
0e7543
 }
0e7543
 
0e7543
@@ -2085,6 +2140,79 @@ hashlib_init_hmactype(PyObject *module)
0e7543
     return 0;
0e7543
 }
0e7543
 
0e7543
+static int
0e7543
+hashlib_init_constructors(PyObject *module)
0e7543
+{
0e7543
+    /* Create dict from builtin openssl_hash functions to name
0e7543
+     * {_hashlib.openssl_sha256: "sha256", ...}
0e7543
+     */
0e7543
+    PyModuleDef *mdef;
0e7543
+    PyMethodDef *fdef;
0e7543
+    PyObject *proxy;
0e7543
+    PyObject *func, *name_obj;
0e7543
+    _hashlibstate *state = get_hashlib_state(module);
0e7543
+
0e7543
+    mdef = PyModule_GetDef(module);
0e7543
+    if (mdef == NULL) {
0e7543
+        return -1;
0e7543
+    }
0e7543
+
0e7543
+    state->constructs = PyDict_New();
0e7543
+    if (state->constructs == NULL) {
0e7543
+        return -1;
0e7543
+    }
0e7543
+
0e7543
+    for (fdef = mdef->m_methods; fdef->ml_name != NULL; fdef++) {
0e7543
+        if (strncmp(fdef->ml_name, "openssl_", 8)) {
0e7543
+            continue;
0e7543
+        }
0e7543
+        name_obj = PyUnicode_FromString(fdef->ml_name + 8);
0e7543
+        if (name_obj == NULL) {
0e7543
+            return -1;
0e7543
+        }
0e7543
+        func  = PyObject_GetAttrString(module, fdef->ml_name);
0e7543
+        if (func == NULL) {
0e7543
+            Py_DECREF(name_obj);
0e7543
+            return -1;
0e7543
+        }
0e7543
+        int rc = PyDict_SetItem(state->constructs, func, name_obj);
0e7543
+        Py_DECREF(func);
0e7543
+        Py_DECREF(name_obj);
0e7543
+        if (rc < 0) {
0e7543
+            return -1;
0e7543
+        }
0e7543
+    }
0e7543
+
0e7543
+    proxy = PyDictProxy_New(state->constructs);
0e7543
+    if (proxy == NULL) {
0e7543
+        return -1;
0e7543
+    }
0e7543
+
0e7543
+    int rc = _PyModule_AddObjectRef(module, "_constructors", proxy);
0e7543
+    Py_DECREF(proxy);
0e7543
+    if (rc < 0) {
0e7543
+        return -1;
0e7543
+    }
0e7543
+    return 0;
0e7543
+}
0e7543
+
0e7543
+static int
0e7543
+hashlib_exception(PyObject *module)
0e7543
+{
0e7543
+    _hashlibstate *state = get_hashlib_state(module);
0e7543
+    state->unsupported_digestmod_error = PyErr_NewException(
0e7543
+        "_hashlib.UnsupportedDigestmodError", PyExc_ValueError, NULL);
0e7543
+    if (state->unsupported_digestmod_error == NULL) {
0e7543
+        return -1;
0e7543
+    }
0e7543
+    if (_PyModule_AddObjectRef(module, "UnsupportedDigestmodError",
0e7543
+                              state->unsupported_digestmod_error) < 0) {
0e7543
+        return -1;
0e7543
+    }
0e7543
+    return 0;
0e7543
+}
0e7543
+
0e7543
+
0e7543
 static PyModuleDef_Slot hashlib_slots[] = {
0e7543
     /* OpenSSL 1.0.2 and LibreSSL */
0e7543
     {Py_mod_exec, hashlib_openssl_legacy_init},
0e7543
@@ -2092,6 +2220,8 @@ static PyModuleDef_Slot hashlib_slots[] = {
0e7543
     {Py_mod_exec, hashlib_init_evpxoftype},
0e7543
     {Py_mod_exec, hashlib_init_hmactype},
0e7543
     {Py_mod_exec, hashlib_md_meth_names},
0e7543
+    {Py_mod_exec, hashlib_init_constructors},
0e7543
+    {Py_mod_exec, hashlib_exception},
0e7543
     {0, NULL}
0e7543
 };
0e7543
 
0e7543
diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h
0e7543
index 68aa765e52..4466ec4330 100644
0e7543
--- a/Modules/clinic/_hashopenssl.c.h
0e7543
+++ b/Modules/clinic/_hashopenssl.c.h
0e7543
@@ -1106,7 +1106,7 @@ PyDoc_STRVAR(_hashlib_hmac_singleshot__doc__,
0e7543
 
0e7543
 static PyObject *
0e7543
 _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
0e7543
-                              Py_buffer *msg, const char *digest);
0e7543
+                              Py_buffer *msg, PyObject *digest);
0e7543
 
0e7543
 static PyObject *
0e7543
 _hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
0e7543
@@ -1117,7 +1117,7 @@ _hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nar
0e7543
     PyObject *argsbuf[3];
0e7543
     Py_buffer key = {NULL, NULL};
0e7543
     Py_buffer msg = {NULL, NULL};
0e7543
-    const char *digest;
0e7543
+    PyObject *digest;
0e7543
 
0e7543
     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf);
0e7543
     if (!args) {
0e7543
@@ -1137,19 +1137,7 @@ _hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nar
0e7543
         _PyArg_BadArgument("hmac_digest", "argument 'msg'", "contiguous buffer", args[1]);
0e7543
         goto exit;
0e7543
     }
0e7543
-    if (!PyUnicode_Check(args[2])) {
0e7543
-        _PyArg_BadArgument("hmac_digest", "argument 'digest'", "str", args[2]);
0e7543
-        goto exit;
0e7543
-    }
0e7543
-    Py_ssize_t digest_length;
0e7543
-    digest = PyUnicode_AsUTF8AndSize(args[2], &digest_length);
0e7543
-    if (digest == NULL) {
0e7543
-        goto exit;
0e7543
-    }
0e7543
-    if (strlen(digest) != (size_t)digest_length) {
0e7543
-        PyErr_SetString(PyExc_ValueError, "embedded null character");
0e7543
-        goto exit;
0e7543
-    }
0e7543
+    digest = args[2];
0e7543
     return_value = _hashlib_hmac_singleshot_impl(module, &key, &msg, digest);
0e7543
 
0e7543
 exit:
0e7543
@@ -1176,7 +1164,7 @@ PyDoc_STRVAR(_hashlib_hmac_new__doc__,
0e7543
 
0e7543
 static PyObject *
0e7543
 _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
0e7543
-                       const char *digestmod);
0e7543
+                       PyObject *digestmod);
0e7543
 
0e7543
 static PyObject *
0e7543
 _hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
0e7543
@@ -1188,7 +1176,7 @@ _hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
0e7543
     Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
0e7543
     Py_buffer key = {NULL, NULL};
0e7543
     PyObject *msg_obj = NULL;
0e7543
-    const char *digestmod = NULL;
0e7543
+    PyObject *digestmod = NULL;
0e7543
 
0e7543
     args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf);
0e7543
     if (!args) {
0e7543
@@ -1210,19 +1198,7 @@ _hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
0e7543
             goto skip_optional_pos;
0e7543
         }
0e7543
     }
0e7543
-    if (!PyUnicode_Check(args[2])) {
0e7543
-        _PyArg_BadArgument("hmac_new", "argument 'digestmod'", "str", args[2]);
0e7543
-        goto exit;
0e7543
-    }
0e7543
-    Py_ssize_t digestmod_length;
0e7543
-    digestmod = PyUnicode_AsUTF8AndSize(args[2], &digestmod_length);
0e7543
-    if (digestmod == NULL) {
0e7543
-        goto exit;
0e7543
-    }
0e7543
-    if (strlen(digestmod) != (size_t)digestmod_length) {
0e7543
-        PyErr_SetString(PyExc_ValueError, "embedded null character");
0e7543
-        goto exit;
0e7543
-    }
0e7543
+    digestmod = args[2];
0e7543
 skip_optional_pos:
0e7543
     return_value = _hashlib_hmac_new_impl(module, &key, msg_obj, digestmod);
0e7543
 
0e7543
@@ -1442,4 +1418,4 @@ exit:
0e7543
 #ifndef _HASHLIB_GET_FIPS_MODE_METHODDEF
0e7543
     #define _HASHLIB_GET_FIPS_MODE_METHODDEF
0e7543
 #endif /* !defined(_HASHLIB_GET_FIPS_MODE_METHODDEF) */
0e7543
-/*[clinic end generated code: output=b6b280e46bf0b139 input=a9049054013a1b77]*/
0e7543
+/*[clinic end generated code: output=7ff9aad0bd53e7ce input=a9049054013a1b77]*/
0e7543
-- 
0e7543
2.31.1
0e7543
0e7543
0e7543
From 547952d3ae9d94d9e38b71d4e309c1d4c2ec963b Mon Sep 17 00:00:00 2001
0e7543
From: Charalampos Stratakis <cstratak@redhat.com>
0e7543
Date: Thu, 12 Dec 2019 16:58:31 +0100
0e7543
Subject: [PATCH 4/5] Expose blake2b and blake2s hashes from OpenSSL
0e7543
0e7543
These aren't as powerful as Python's own implementation, but they can be
0e7543
used under FIPS.
0e7543
---
0e7543
 Lib/test/test_hashlib.py        |   6 ++
0e7543
 Modules/_hashopenssl.c          |  43 +++++++++++++
0e7543
 Modules/clinic/_hashopenssl.c.h | 106 +++++++++++++++++++++++++++++++-
0e7543
 3 files changed, 154 insertions(+), 1 deletion(-)
0e7543
0e7543
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
0e7543
index 86f31a5587..f843022b48 100644
0e7543
--- a/Lib/test/test_hashlib.py
0e7543
+++ b/Lib/test/test_hashlib.py
0e7543
@@ -354,6 +354,12 @@ class HashLibTestCase(unittest.TestCase):
0e7543
         # 2 is for hashlib.name(...) and hashlib.new(name, ...)
0e7543
         self.assertGreaterEqual(len(constructors), 2)
0e7543
         for hash_object_constructor in constructors:
0e7543
+
0e7543
+            # OpenSSL's blake2s & blake2d don't support `key`
0e7543
+            _name = hash_object_constructor.__name__
0e7543
+            if 'key' in kwargs and _name.startswith('openssl_blake2'):
0e7543
+                return
0e7543
+
0e7543
             m = hash_object_constructor(data, **kwargs)
0e7543
             computed = m.hexdigest() if not shake else m.hexdigest(length)
0e7543
             self.assertEqual(
0e7543
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
0e7543
index fd3b3c0719..065c6c0612 100644
0e7543
--- a/Modules/_hashopenssl.c
0e7543
+++ b/Modules/_hashopenssl.c
0e7543
@@ -294,6 +294,12 @@ py_digest_by_name(const char *name)
0e7543
         else if (!strcmp(name, "blake2b512")) {
0e7543
             digest = EVP_blake2b512();
0e7543
         }
0e7543
+        else if (!strcmp(name, "blake2s")) {
0e7543
+            digest = EVP_blake2s256();
0e7543
+        }
0e7543
+        else if (!strcmp(name, "blake2b")) {
0e7543
+            digest = EVP_blake2b512();
0e7543
+        }
0e7543
 #endif
0e7543
     }
0e7543
 
0e7543
@@ -1038,6 +1044,41 @@ _hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj,
0e7543
 }
0e7543
 
0e7543
 
0e7543
+/*[clinic input]
0e7543
+_hashlib.openssl_blake2b
0e7543
+    string as data_obj: object(py_default="b''") = NULL
0e7543
+    *
0e7543
+    usedforsecurity: bool = True
0e7543
+Returns a blake2b hash object; optionally initialized with a string
0e7543
+[clinic start generated code]*/
0e7543
+
0e7543
+static PyObject *
0e7543
+_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj,
0e7543
+                              int usedforsecurity)
0e7543
+/*[clinic end generated code: output=7a838b1643cde13e input=4ad7fd54268f3689]*/
0e7543
+
0e7543
+{
0e7543
+    return EVP_fast_new(module, data_obj, EVP_blake2b512(), usedforsecurity);
0e7543
+}
0e7543
+
0e7543
+/*[clinic input]
0e7543
+_hashlib.openssl_blake2s
0e7543
+    string as data_obj: object(py_default="b''") = NULL
0e7543
+    *
0e7543
+    usedforsecurity: bool = True
0e7543
+Returns a blake2s hash object; optionally initialized with a string
0e7543
+[clinic start generated code]*/
0e7543
+
0e7543
+static PyObject *
0e7543
+_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj,
0e7543
+                              int usedforsecurity)
0e7543
+/*[clinic end generated code: output=4eda6b40757471da input=1ed39481ffa4e26a]*/
0e7543
+
0e7543
+{
0e7543
+    return EVP_fast_new(module, data_obj, EVP_blake2s256(), usedforsecurity);
0e7543
+}
0e7543
+
0e7543
+
0e7543
 #ifdef PY_OPENSSL_HAS_SHA3
0e7543
 
0e7543
 /*[clinic input]
0e7543
@@ -2022,6 +2063,8 @@ static struct PyMethodDef EVP_functions[] = {
0e7543
     _HASHLIB_OPENSSL_SHA256_METHODDEF
0e7543
     _HASHLIB_OPENSSL_SHA384_METHODDEF
0e7543
     _HASHLIB_OPENSSL_SHA512_METHODDEF
0e7543
+    _HASHLIB_OPENSSL_BLAKE2B_METHODDEF
0e7543
+    _HASHLIB_OPENSSL_BLAKE2S_METHODDEF
0e7543
     _HASHLIB_OPENSSL_SHA3_224_METHODDEF
0e7543
     _HASHLIB_OPENSSL_SHA3_256_METHODDEF
0e7543
     _HASHLIB_OPENSSL_SHA3_384_METHODDEF
0e7543
diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h
0e7543
index 4466ec4330..54c22b25d3 100644
0e7543
--- a/Modules/clinic/_hashopenssl.c.h
0e7543
+++ b/Modules/clinic/_hashopenssl.c.h
0e7543
@@ -540,6 +540,110 @@ exit:
0e7543
     return return_value;
0e7543
 }
0e7543
 
0e7543
+PyDoc_STRVAR(_hashlib_openssl_blake2b__doc__,
0e7543
+"openssl_blake2b($module, /, string=b\'\', *, usedforsecurity=True)\n"
0e7543
+"--\n"
0e7543
+"\n"
0e7543
+"Returns a blake2b hash object; optionally initialized with a string");
0e7543
+
0e7543
+#define _HASHLIB_OPENSSL_BLAKE2B_METHODDEF    \
0e7543
+    {"openssl_blake2b", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2b, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2b__doc__},
0e7543
+
0e7543
+static PyObject *
0e7543
+_hashlib_openssl_blake2b_impl(PyObject *module, PyObject *data_obj,
0e7543
+                              int usedforsecurity);
0e7543
+
0e7543
+static PyObject *
0e7543
+_hashlib_openssl_blake2b(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
0e7543
+{
0e7543
+    PyObject *return_value = NULL;
0e7543
+    static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
0e7543
+    static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2b", 0};
0e7543
+    PyObject *argsbuf[2];
0e7543
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
0e7543
+    PyObject *data_obj = NULL;
0e7543
+    int usedforsecurity = 1;
0e7543
+
0e7543
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf);
0e7543
+    if (!args) {
0e7543
+        goto exit;
0e7543
+    }
0e7543
+    if (!noptargs) {
0e7543
+        goto skip_optional_pos;
0e7543
+    }
0e7543
+    if (args[0]) {
0e7543
+        data_obj = args[0];
0e7543
+        if (!--noptargs) {
0e7543
+            goto skip_optional_pos;
0e7543
+        }
0e7543
+    }
0e7543
+skip_optional_pos:
0e7543
+    if (!noptargs) {
0e7543
+        goto skip_optional_kwonly;
0e7543
+    }
0e7543
+    usedforsecurity = PyObject_IsTrue(args[1]);
0e7543
+    if (usedforsecurity < 0) {
0e7543
+        goto exit;
0e7543
+    }
0e7543
+skip_optional_kwonly:
0e7543
+    return_value = _hashlib_openssl_blake2b_impl(module, data_obj, usedforsecurity);
0e7543
+
0e7543
+exit:
0e7543
+    return return_value;
0e7543
+}
0e7543
+
0e7543
+PyDoc_STRVAR(_hashlib_openssl_blake2s__doc__,
0e7543
+"openssl_blake2s($module, /, string=b\'\', *, usedforsecurity=True)\n"
0e7543
+"--\n"
0e7543
+"\n"
0e7543
+"Returns a blake2s hash object; optionally initialized with a string");
0e7543
+
0e7543
+#define _HASHLIB_OPENSSL_BLAKE2S_METHODDEF    \
0e7543
+    {"openssl_blake2s", (PyCFunction)(void(*)(void))_hashlib_openssl_blake2s, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_blake2s__doc__},
0e7543
+
0e7543
+static PyObject *
0e7543
+_hashlib_openssl_blake2s_impl(PyObject *module, PyObject *data_obj,
0e7543
+                              int usedforsecurity);
0e7543
+
0e7543
+static PyObject *
0e7543
+_hashlib_openssl_blake2s(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
0e7543
+{
0e7543
+    PyObject *return_value = NULL;
0e7543
+    static const char * const _keywords[] = {"string", "usedforsecurity", NULL};
0e7543
+    static _PyArg_Parser _parser = {NULL, _keywords, "openssl_blake2s", 0};
0e7543
+    PyObject *argsbuf[2];
0e7543
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
0e7543
+    PyObject *data_obj = NULL;
0e7543
+    int usedforsecurity = 1;
0e7543
+
0e7543
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf);
0e7543
+    if (!args) {
0e7543
+        goto exit;
0e7543
+    }
0e7543
+    if (!noptargs) {
0e7543
+        goto skip_optional_pos;
0e7543
+    }
0e7543
+    if (args[0]) {
0e7543
+        data_obj = args[0];
0e7543
+        if (!--noptargs) {
0e7543
+            goto skip_optional_pos;
0e7543
+        }
0e7543
+    }
0e7543
+skip_optional_pos:
0e7543
+    if (!noptargs) {
0e7543
+        goto skip_optional_kwonly;
0e7543
+    }
0e7543
+    usedforsecurity = PyObject_IsTrue(args[1]);
0e7543
+    if (usedforsecurity < 0) {
0e7543
+        goto exit;
0e7543
+    }
0e7543
+skip_optional_kwonly:
0e7543
+    return_value = _hashlib_openssl_blake2s_impl(module, data_obj, usedforsecurity);
0e7543
+
0e7543
+exit:
0e7543
+    return return_value;
0e7543
+}
0e7543
+
0e7543
 #if defined(PY_OPENSSL_HAS_SHA3)
0e7543
 
0e7543
 PyDoc_STRVAR(_hashlib_openssl_sha3_224__doc__,
0e7543
@@ -1418,4 +1522,4 @@ exit:
0e7543
 #ifndef _HASHLIB_GET_FIPS_MODE_METHODDEF
0e7543
     #define _HASHLIB_GET_FIPS_MODE_METHODDEF
0e7543
 #endif /* !defined(_HASHLIB_GET_FIPS_MODE_METHODDEF) */
0e7543
-/*[clinic end generated code: output=7ff9aad0bd53e7ce input=a9049054013a1b77]*/
0e7543
+/*[clinic end generated code: output=fab05055e982f112 input=a9049054013a1b77]*/
0e7543
-- 
0e7543
2.31.1
0e7543
0e7543
0e7543
From 4d2a433760548bb9813139844e574c06ea3fdb7a Mon Sep 17 00:00:00 2001
0e7543
From: Petr Viktorin <pviktori@redhat.com>
0e7543
Date: Thu, 1 Aug 2019 17:57:05 +0200
0e7543
Subject: [PATCH 5/5] Use a stronger hash in multiprocessing handshake
0e7543
0e7543
Adapted from patch by David Malcolm,
0e7543
https://bugs.python.org/issue17258
0e7543
---
0e7543
 Lib/multiprocessing/connection.py | 8 ++++++--
0e7543
 1 file changed, 6 insertions(+), 2 deletions(-)
0e7543
0e7543
diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
0e7543
index 510e4b5aba..b68f2fb837 100644
0e7543
--- a/Lib/multiprocessing/connection.py
0e7543
+++ b/Lib/multiprocessing/connection.py
0e7543
@@ -42,6 +42,10 @@ BUFSIZE = 8192
0e7543
 # A very generous timeout when it comes to local connections...
0e7543
 CONNECTION_TIMEOUT = 20.
0e7543
 
0e7543
+# The hmac module implicitly defaults to using MD5.
0e7543
+# Support using a stronger algorithm for the challenge/response code:
0e7543
+HMAC_DIGEST_NAME='sha256'
0e7543
+
0e7543
 _mmap_counter = itertools.count()
0e7543
 
0e7543
 default_family = 'AF_INET'
0e7543
@@ -741,7 +745,7 @@ def deliver_challenge(connection, authkey):
0e7543
             "Authkey must be bytes, not {0!s}".format(type(authkey)))
0e7543
     message = os.urandom(MESSAGE_LENGTH)
0e7543
     connection.send_bytes(CHALLENGE + message)
0e7543
-    digest = hmac.new(authkey, message, 'md5').digest()
0e7543
+    digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest()
0e7543
     response = connection.recv_bytes(256)        # reject large message
0e7543
     if response == digest:
0e7543
         connection.send_bytes(WELCOME)
0e7543
@@ -757,7 +761,7 @@ def answer_challenge(connection, authkey):
0e7543
     message = connection.recv_bytes(256)         # reject large message
0e7543
     assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message
0e7543
     message = message[len(CHALLENGE):]
0e7543
-    digest = hmac.new(authkey, message, 'md5').digest()
0e7543
+    digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest()
0e7543
     connection.send_bytes(digest)
0e7543
     response = connection.recv_bytes(256)        # reject large message
0e7543
     if response != WELCOME:
0e7543
-- 
0e7543
2.31.1
0e7543