Skip to content

Commit 2525480

Browse files
committed
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.
1 parent daa2578 commit 2525480

1 file changed

Lines changed: 12 additions & 6 deletions

File tree

Modules/_hashopenssl.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ _hashlib_HASH_get_blocksize(PyObject *op, void *Py_UNUSED(closure))
10061006
{
10071007
HASHobject *self = HASHobject_CAST(op);
10081008
long block_size = EVP_MD_CTX_block_size(self->ctx);
1009+
assert(block_size > 0);
10091010
return PyLong_FromLong(block_size);
10101011
}
10111012

@@ -1014,6 +1015,7 @@ _hashlib_HASH_get_digestsize(PyObject *op, void *Py_UNUSED(closure))
10141015
{
10151016
HASHobject *self = HASHobject_CAST(op);
10161017
long size = EVP_MD_CTX_size(self->ctx);
1018+
assert(size > 0);
10171019
return PyLong_FromLong(size);
10181020
}
10191021

@@ -2200,7 +2202,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
22002202
*
22012203
* On error, set an exception and return BAD_DIGEST_SIZE.
22022204
*/
2203-
static unsigned int
2205+
static int
22042206
_hashlib_hmac_digest_size(HMACobject *self)
22052207
{
22062208
assert(EVP_MAX_MD_SIZE < INT_MAX);
@@ -2215,15 +2217,19 @@ _hashlib_hmac_digest_size(HMACobject *self)
22152217
}
22162218
int digest_size = EVP_MD_size(md);
22172219
/* digest_size < 0 iff EVP_MD context is NULL (which is impossible here) */
2218-
assert(digest_size >= 0);
2220+
assert(digest_size > 0);
22192221
assert(digest_size <= (int)EVP_MAX_MD_SIZE);
2222+
if (digest_size < 0) {
2223+
raise_ssl_error(PyExc_SystemError, "invalid digest size");
2224+
return BAD_DIGEST_SIZE;
2225+
}
22202226
#endif
22212227
/* digest_size == 0 means that the context is not entirely initialized */
22222228
if (digest_size == 0) {
2223-
raise_ssl_error(PyExc_ValueError, "missing digest size");
2229+
raise_ssl_error(PyExc_SystemError, "missing digest size");
22242230
return BAD_DIGEST_SIZE;
22252231
}
2226-
return (unsigned int)digest_size;
2232+
return (int)digest_size;
22272233
}
22282234

22292235
static int
@@ -2321,7 +2327,7 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg)
23212327
static Py_ssize_t
23222328
_hmac_digest(HMACobject *self, unsigned char *buf)
23232329
{
2324-
unsigned int digest_size = _hashlib_hmac_digest_size(self);
2330+
int digest_size = _hashlib_hmac_digest_size(self);
23252331
assert(digest_size <= EVP_MAX_MD_SIZE);
23262332
if (digest_size == BAD_DIGEST_SIZE) {
23272333
assert(PyErr_Occurred());
@@ -2386,7 +2392,7 @@ static PyObject *
23862392
_hashlib_hmac_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
23872393
{
23882394
HMACobject *self = HMACobject_CAST(op);
2389-
unsigned int size = _hashlib_hmac_digest_size(self);
2395+
int size = _hashlib_hmac_digest_size(self);
23902396
return size == BAD_DIGEST_SIZE ? NULL : PyLong_FromLong(size);
23912397
}
23922398

0 commit comments

Comments
 (0)