From 25254800fe943eb1ff23edf7b46a39d33ba07a47 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sat, 11 Apr 2026 22:41:34 +0000 Subject: [PATCH 1/2] gh-146287: use signed type for HMAC digest size to prevent unsigned wrapping Change _hashlib_hmac_digest_size() return type from unsigned int to int so that a hypothetical negative return from EVP_MD_size() is not silently wrapped to a large positive value. Add an explicit check for negative digest_size in the legacy OpenSSL path, and use SystemError (not ValueError) since these conditions indicate internal invariant violations. Also add debug-build asserts to EVP_get_block_size and EVP_get_digest_size documenting that the hash context is always initialized. --- Modules/_hashopenssl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 5d86c2e5886afd..52c1a8135a934f 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -1006,6 +1006,7 @@ _hashlib_HASH_get_blocksize(PyObject *op, void *Py_UNUSED(closure)) { HASHobject *self = HASHobject_CAST(op); long block_size = EVP_MD_CTX_block_size(self->ctx); + assert(block_size > 0); return PyLong_FromLong(block_size); } @@ -1014,6 +1015,7 @@ _hashlib_HASH_get_digestsize(PyObject *op, void *Py_UNUSED(closure)) { HASHobject *self = HASHobject_CAST(op); long size = EVP_MD_CTX_size(self->ctx); + assert(size > 0); return PyLong_FromLong(size); } @@ -2200,7 +2202,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, * * On error, set an exception and return BAD_DIGEST_SIZE. */ -static unsigned int +static int _hashlib_hmac_digest_size(HMACobject *self) { assert(EVP_MAX_MD_SIZE < INT_MAX); @@ -2215,15 +2217,19 @@ _hashlib_hmac_digest_size(HMACobject *self) } int digest_size = EVP_MD_size(md); /* digest_size < 0 iff EVP_MD context is NULL (which is impossible here) */ - assert(digest_size >= 0); + assert(digest_size > 0); assert(digest_size <= (int)EVP_MAX_MD_SIZE); + if (digest_size < 0) { + raise_ssl_error(PyExc_SystemError, "invalid digest size"); + return BAD_DIGEST_SIZE; + } #endif /* digest_size == 0 means that the context is not entirely initialized */ if (digest_size == 0) { - raise_ssl_error(PyExc_ValueError, "missing digest size"); + raise_ssl_error(PyExc_SystemError, "missing digest size"); return BAD_DIGEST_SIZE; } - return (unsigned int)digest_size; + return (int)digest_size; } static int @@ -2321,7 +2327,7 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg) static Py_ssize_t _hmac_digest(HMACobject *self, unsigned char *buf) { - unsigned int digest_size = _hashlib_hmac_digest_size(self); + int digest_size = _hashlib_hmac_digest_size(self); assert(digest_size <= EVP_MAX_MD_SIZE); if (digest_size == BAD_DIGEST_SIZE) { assert(PyErr_Occurred()); @@ -2386,7 +2392,7 @@ static PyObject * _hashlib_hmac_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) { HMACobject *self = HMACobject_CAST(op); - unsigned int size = _hashlib_hmac_digest_size(self); + int size = _hashlib_hmac_digest_size(self); return size == BAD_DIGEST_SIZE ? NULL : PyLong_FromLong(size); } From 1bb2b53d283f6ee59647bbdf9525d9feaf9a6719 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com> Date: Sat, 11 Apr 2026 15:53:34 -0700 Subject: [PATCH 2/2] remove overzealous assert. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Modules/_hashopenssl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 52c1a8135a934f..fa3eceb74d1694 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -2217,7 +2217,6 @@ _hashlib_hmac_digest_size(HMACobject *self) } int digest_size = EVP_MD_size(md); /* digest_size < 0 iff EVP_MD context is NULL (which is impossible here) */ - assert(digest_size > 0); assert(digest_size <= (int)EVP_MAX_MD_SIZE); if (digest_size < 0) { raise_ssl_error(PyExc_SystemError, "invalid digest size");