https://github.com/python/cpython/commit/d3ef5ba34d3068b8178d6ff0f39462db6bbc4ad5
commit: d3ef5ba34d3068b8178d6ff0f39462db6bbc4ad5
branch: main
author: Bénédikt Tran <[email protected]>
committer: picnixz <[email protected]>
date: 2025-12-14T09:45:36+01:00
summary:

gh-142451: correctly copy HMAC attributes in `HMAC.copy()` (#142510)

files:
A Misc/NEWS.d/next/Library/2025-12-10-11-02-53.gh-issue-142451.eCLvhG.rst
M Lib/hmac.py
M Lib/test/test_hmac.py
M Modules/_hashopenssl.c

diff --git a/Lib/hmac.py b/Lib/hmac.py
index 9d3fae8b1b1597..e0c040bcd5fe3d 100644
--- a/Lib/hmac.py
+++ b/Lib/hmac.py
@@ -171,6 +171,7 @@ def copy(self):
         # Call __new__ directly to avoid the expensive __init__.
         other = self.__class__.__new__(self.__class__)
         other.digest_size = self.digest_size
+        other.block_size = self.block_size
         if self._hmac:
             other._hmac = self._hmac.copy()
             other._inner = other._outer = None
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
index 7634deeb1d8eb9..17888a9f286c8f 100644
--- a/Lib/test/test_hmac.py
+++ b/Lib/test/test_hmac.py
@@ -1076,6 +1076,15 @@ def test_properties(self):
         self.assertEqual(h.digest_size, self.digest_size)
         self.assertEqual(h.block_size, self.block_size)
 
+    def test_copy(self):
+        # Test a generic copy() and the attributes it exposes.
+        # See https://github.com/python/cpython/issues/142451.
+        h1 = self.hmac_new(b"my secret key", digestmod=self.digestname)
+        h2 = h1.copy()
+        self.assertEqual(h1.name, h2.name)
+        self.assertEqual(h1.digest_size, h2.digest_size)
+        self.assertEqual(h1.block_size, h2.block_size)
+
     def test_repr(self):
         # HMAC object representation may differ across implementations
         raise NotImplementedError
diff --git 
a/Misc/NEWS.d/next/Library/2025-12-10-11-02-53.gh-issue-142451.eCLvhG.rst 
b/Misc/NEWS.d/next/Library/2025-12-10-11-02-53.gh-issue-142451.eCLvhG.rst
new file mode 100644
index 00000000000000..3726d4178e26e4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-10-11-02-53.gh-issue-142451.eCLvhG.rst
@@ -0,0 +1,2 @@
+:mod:`hmac`: correctly copy :class:`~hmac.HMAC` attributes for objects
+copied through :meth:`HMAC.copy() <hmac.HMAC.copy>`. Patch by Bénédikt Tran.
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index 19089b009f7911..77832a768e0cbc 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -606,9 +606,14 @@ get_asn1_utf8name_by_nid(int nid)
 {
     const char *name = OBJ_nid2ln(nid);
     if (name == NULL) {
-        // In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise.
-        assert(ERR_peek_last_error() != 0);
-        if (ERR_GET_REASON(ERR_peek_last_error()) != OBJ_R_UNKNOWN_NID) {
+        /* In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise.
+         * However, not all versions of OpenSSL set a last error, so we simply
+         * ignore the last error if none exists.
+         *
+         * See https://github.com/python/cpython/issues/142451.
+         */
+        unsigned long errcode = ERR_peek_last_error();
+        if (errcode && ERR_GET_REASON(errcode) != OBJ_R_UNKNOWN_NID) {
             goto error;
         }
         // fallback to short name and unconditionally propagate errors
@@ -2255,6 +2260,9 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
         return NULL;
     }
     retval->ctx = ctx;
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+    retval->evp_md_nid = self->evp_md_nid;
+#endif
     HASHLIB_INIT_MUTEX(retval);
     return (PyObject *)retval;
 }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to