Skip to content

Commit d3ef5ba

Browse files
authored
gh-142451: correctly copy HMAC attributes in HMAC.copy() (#142510)
1 parent 4e41636 commit d3ef5ba

File tree

4 files changed

+23
-3
lines changed

4 files changed

+23
-3
lines changed

Lib/hmac.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ def copy(self):
171171
# Call __new__ directly to avoid the expensive __init__.
172172
other = self.__class__.__new__(self.__class__)
173173
other.digest_size = self.digest_size
174+
other.block_size = self.block_size
174175
if self._hmac:
175176
other._hmac = self._hmac.copy()
176177
other._inner = other._outer = None

Lib/test/test_hmac.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,15 @@ def test_properties(self):
10761076
self.assertEqual(h.digest_size, self.digest_size)
10771077
self.assertEqual(h.block_size, self.block_size)
10781078

1079+
def test_copy(self):
1080+
# Test a generic copy() and the attributes it exposes.
1081+
# See https://github.com/python/cpython/issues/142451.
1082+
h1 = self.hmac_new(b"my secret key", digestmod=self.digestname)
1083+
h2 = h1.copy()
1084+
self.assertEqual(h1.name, h2.name)
1085+
self.assertEqual(h1.digest_size, h2.digest_size)
1086+
self.assertEqual(h1.block_size, h2.block_size)
1087+
10791088
def test_repr(self):
10801089
# HMAC object representation may differ across implementations
10811090
raise NotImplementedError
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`hmac`: correctly copy :class:`~hmac.HMAC` attributes for objects
2+
copied through :meth:`HMAC.copy() <hmac.HMAC.copy>`. Patch by Bénédikt Tran.

Modules/_hashopenssl.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,9 +606,14 @@ get_asn1_utf8name_by_nid(int nid)
606606
{
607607
const char *name = OBJ_nid2ln(nid);
608608
if (name == NULL) {
609-
// In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise.
610-
assert(ERR_peek_last_error() != 0);
611-
if (ERR_GET_REASON(ERR_peek_last_error()) != OBJ_R_UNKNOWN_NID) {
609+
/* In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise.
610+
* However, not all versions of OpenSSL set a last error, so we simply
611+
* ignore the last error if none exists.
612+
*
613+
* See https://github.com/python/cpython/issues/142451.
614+
*/
615+
unsigned long errcode = ERR_peek_last_error();
616+
if (errcode && ERR_GET_REASON(errcode) != OBJ_R_UNKNOWN_NID) {
612617
goto error;
613618
}
614619
// fallback to short name and unconditionally propagate errors
@@ -2255,6 +2260,9 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
22552260
return NULL;
22562261
}
22572262
retval->ctx = ctx;
2263+
#ifdef Py_HAS_OPENSSL3_SUPPORT
2264+
retval->evp_md_nid = self->evp_md_nid;
2265+
#endif
22582266
HASHLIB_INIT_MUTEX(retval);
22592267
return (PyObject *)retval;
22602268
}

0 commit comments

Comments
 (0)