Skip to content

Commit e545bae

Browse files
authored
pythongh-134531: simplify code for computing HMAC digests (python#138046)
1 parent 531fc3a commit e545bae

File tree

1 file changed

+45
-35
lines changed

1 file changed

+45
-35
lines changed

Modules/_hashopenssl.c

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,20 +1939,30 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
19391939
return 0;
19401940
}
19411941

1942-
/* returning 0 means that an error occurred and an exception is set */
1942+
#define BAD_DIGEST_SIZE 0
1943+
1944+
/*
1945+
* Return the digest size in bytes.
1946+
*
1947+
* On error, set an exception and return BAD_DIGEST_SIZE.
1948+
*/
19431949
static unsigned int
19441950
_hashlib_hmac_digest_size(HMACobject *self)
19451951
{
19461952
const EVP_MD *md = _hashlib_hmac_get_md(self);
19471953
if (md == NULL) {
1948-
return 0;
1954+
return BAD_DIGEST_SIZE;
19491955
}
1950-
unsigned int digest_size = EVP_MD_size(md);
1951-
assert(digest_size <= EVP_MAX_MD_SIZE);
1956+
int digest_size = EVP_MD_size(md);
1957+
/* digest_size < 0 iff EVP_MD context is NULL (which is impossible here) */
1958+
assert(digest_size >= 0);
1959+
assert(digest_size <= (int)EVP_MAX_MD_SIZE);
1960+
/* digest_size == 0 means that the context is not entirely initialized */
19521961
if (digest_size == 0) {
1953-
notify_ssl_error_occurred("invalid digest size");
1962+
raise_ssl_error(PyExc_ValueError, "missing digest size");
1963+
return BAD_DIGEST_SIZE;
19541964
}
1955-
return digest_size;
1965+
return (unsigned int)digest_size;
19561966
}
19571967

19581968
static int
@@ -2053,24 +2063,38 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg)
20532063
Py_RETURN_NONE;
20542064
}
20552065

2056-
static int
2057-
_hmac_digest(HMACobject *self, unsigned char *buf, unsigned int len)
2066+
/*
2067+
* Extract the MAC value to 'buf' and return the digest size.
2068+
*
2069+
* The buffer 'buf' must have at least hashlib_openssl_HMAC_digest_size(self)
2070+
* bytes. Smaller buffers lead to undefined behaviors.
2071+
*
2072+
* On error, set an exception and return -1.
2073+
*/
2074+
static Py_ssize_t
2075+
_hmac_digest(HMACobject *self, unsigned char *buf)
20582076
{
2077+
unsigned int digest_size = _hashlib_hmac_digest_size(self);
2078+
assert(digest_size <= EVP_MAX_MD_SIZE);
2079+
if (digest_size == BAD_DIGEST_SIZE) {
2080+
assert(PyErr_Occurred());
2081+
return -1;
2082+
}
20592083
HMAC_CTX *temp_ctx = py_openssl_wrapper_HMAC_CTX_new();
20602084
if (temp_ctx == NULL) {
2061-
return 0;
2085+
return -1;
20622086
}
20632087
if (locked_HMAC_CTX_copy(temp_ctx, self) < 0) {
20642088
HMAC_CTX_free(temp_ctx);
2065-
return 0;
2089+
return -1;
20662090
}
2067-
int r = HMAC_Final(temp_ctx, buf, &len);
2091+
int r = HMAC_Final(temp_ctx, buf, NULL);
20682092
HMAC_CTX_free(temp_ctx);
20692093
if (r == 0) {
20702094
notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Final));
2071-
return 0;
2095+
return -1;
20722096
}
2073-
return 1;
2097+
return digest_size;
20742098
}
20752099

20762100
/*[clinic input]
@@ -2082,16 +2106,9 @@ static PyObject *
20822106
_hashlib_HMAC_digest_impl(HMACobject *self)
20832107
/*[clinic end generated code: output=1b1424355af7a41e input=bff07f74da318fb4]*/
20842108
{
2085-
unsigned char digest[EVP_MAX_MD_SIZE];
2086-
unsigned int digest_size = _hashlib_hmac_digest_size(self);
2087-
if (digest_size == 0) {
2088-
return NULL;
2089-
}
2090-
int r = _hmac_digest(self, digest, digest_size);
2091-
if (r == 0) {
2092-
return NULL;
2093-
}
2094-
return PyBytes_FromStringAndSize((const char *)digest, digest_size);
2109+
unsigned char buf[EVP_MAX_MD_SIZE];
2110+
Py_ssize_t n = _hmac_digest(self, buf);
2111+
return n < 0 ? NULL : PyBytes_FromStringAndSize((const char *)buf, n);
20952112
}
20962113

20972114
/*[clinic input]
@@ -2109,24 +2126,17 @@ static PyObject *
21092126
_hashlib_HMAC_hexdigest_impl(HMACobject *self)
21102127
/*[clinic end generated code: output=80d825be1eaae6a7 input=5e48db83ab1a4d19]*/
21112128
{
2112-
unsigned char digest[EVP_MAX_MD_SIZE];
2113-
unsigned int digest_size = _hashlib_hmac_digest_size(self);
2114-
if (digest_size == 0) {
2115-
return NULL;
2116-
}
2117-
int r = _hmac_digest(self, digest, digest_size);
2118-
if (r == 0) {
2119-
return NULL;
2120-
}
2121-
return _Py_strhex((const char *)digest, digest_size);
2129+
unsigned char buf[EVP_MAX_MD_SIZE];
2130+
Py_ssize_t n = _hmac_digest(self, buf);
2131+
return n < 0 ? NULL : _Py_strhex((const char *)buf, n);
21222132
}
21232133

21242134
static PyObject *
21252135
_hashlib_hmac_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
21262136
{
21272137
HMACobject *self = HMACobject_CAST(op);
2128-
unsigned int digest_size = _hashlib_hmac_digest_size(self);
2129-
return digest_size == 0 ? NULL : PyLong_FromLong(digest_size);
2138+
unsigned int size = _hashlib_hmac_digest_size(self);
2139+
return size == BAD_DIGEST_SIZE ? NULL : PyLong_FromLong(size);
21302140
}
21312141

21322142
static PyObject *

0 commit comments

Comments
 (0)