gh-136968: fortify macro usage in cryptographic modules (#136973)

Macros used in cryptographic extension modules are partially rewritten
to use `static inline` functions when possible to help code completion.
This commit is contained in:
Bénédikt Tran 2025-07-28 09:36:15 +02:00 committed by GitHub
parent 4e40f2bea7
commit eefd70f0ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 116 additions and 78 deletions

View file

@ -1251,15 +1251,11 @@ _hashlib_HASH(_hashlibstate *state, const char *digestname, PyObject *data_obj,
return (PyObject *)self;
}
// In Python 3.19, we can remove the "STRING" argument and would also be able
// to remove the macro (or keep it as an alias for better naming) since calls
// to _hashlib_HASH_new_impl() would fit on 80 characters.
#define CALL_HASHLIB_NEW(MODULE, NAME, DATA, STRING, USEDFORSECURITY) \
do { \
PyObject *data_obj; \
if (_Py_hashlib_data_argument(&data_obj, DATA, STRING) < 0) { \
return NULL; \
} \
_hashlibstate *state = get_hashlib_state(MODULE); \
return _hashlib_HASH(state, NAME, data_obj, USEDFORSECURITY); \
} while (0)
return _hashlib_HASH_new_impl(MODULE, NAME, DATA, USEDFORSECURITY, STRING)
/* The module-level function: new() */
@ -1285,7 +1281,12 @@ _hashlib_HASH_new_impl(PyObject *module, const char *name, PyObject *data,
int usedforsecurity, PyObject *string)
/*[clinic end generated code: output=b905aaf9840c1bbd input=c34af6c6e696d44e]*/
{
CALL_HASHLIB_NEW(module, name, data, string, usedforsecurity);
PyObject *data_obj;
if (_Py_hashlib_data_argument(&data_obj, data, string) < 0) {
return NULL;
}
_hashlibstate *state = get_hashlib_state(module);
return _hashlib_HASH(state, name, data_obj, usedforsecurity);
}

View file

@ -12,34 +12,51 @@
#define HASHLIB_UNSUPPORTED_STR_ALGORITHM "unsupported hash algorithm %s"
/*
* Given a PyObject* obj, fill in the Py_buffer* viewp with the result
* of PyObject_GetBuffer. Sets an exception and issues the erraction
* on any errors, e.g. 'return NULL' or 'goto error'.
* Obtain a buffer view from a buffer-like object 'obj'.
*
* On success, store the result in 'view' and return 0.
* On error, set an exception and return -1.
*/
#define GET_BUFFER_VIEW_OR_ERROR(obj, viewp, erraction) do { \
if (PyUnicode_Check((obj))) { \
PyErr_SetString(PyExc_TypeError, \
"Strings must be encoded before hashing");\
erraction; \
} \
if (!PyObject_CheckBuffer((obj))) { \
PyErr_SetString(PyExc_TypeError, \
"object supporting the buffer API required"); \
erraction; \
} \
if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \
erraction; \
} \
if ((viewp)->ndim > 1) { \
PyErr_SetString(PyExc_BufferError, \
"Buffer must be single dimension"); \
PyBuffer_Release((viewp)); \
erraction; \
} \
} while(0)
static inline int
_Py_hashlib_get_buffer_view(PyObject *obj, Py_buffer *view)
{
if (PyUnicode_Check(obj)) {
PyErr_SetString(PyExc_TypeError,
"Strings must be encoded before hashing");
return -1;
}
if (!PyObject_CheckBuffer(obj)) {
PyErr_SetString(PyExc_TypeError,
"object supporting the buffer API required");
return -1;
}
if (PyObject_GetBuffer(obj, view, PyBUF_SIMPLE) == -1) {
return -1;
}
if (view->ndim > 1) {
PyErr_SetString(PyExc_BufferError,
"Buffer must be single dimension");
PyBuffer_Release(view);
return -1;
}
return 0;
}
#define GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) \
GET_BUFFER_VIEW_OR_ERROR(obj, viewp, return NULL)
/*
* Call _Py_hashlib_get_buffer_view() and check if it succeeded.
*
* On error, set an exception and execute the ERRACTION statements.
*/
#define GET_BUFFER_VIEW_OR_ERROR(OBJ, VIEW, ERRACTION) \
do { \
if (_Py_hashlib_get_buffer_view(OBJ, VIEW) < 0) { \
assert(PyErr_Occurred()); \
ERRACTION; \
} \
} while (0)
#define GET_BUFFER_VIEW_OR_ERROUT(OBJ, VIEW) \
GET_BUFFER_VIEW_OR_ERROR(OBJ, VIEW, return NULL)
/*
* Helper code to synchronize access to the hash object when the GIL is

View file

@ -1099,42 +1099,60 @@ _hmac_compute_digest_impl(PyObject *module, PyObject *key, PyObject *msg,
}
/*
* One-shot HMAC-HASH using the given HACL_HID.
* Obtain a view for 'key' and 'msg', storing it in 'keyview' and 'msgview'.
*
* Return 0 on success; otherwise set an exception and return -1.
*
* The length of the key and message buffers must not exceed UINT32_MAX,
* lest an OverflowError is raised. The Python implementation takes care
* of dispatching to the OpenSSL implementation in this case.
*/
#define Py_HMAC_HACL_ONESHOT(HACL_HID, KEY, MSG) \
do { \
Py_buffer keyview, msgview; \
GET_BUFFER_VIEW_OR_ERROUT((KEY), &keyview); \
if (!has_uint32_t_buffer_length(&keyview)) { \
PyBuffer_Release(&keyview); \
set_invalid_key_length_error(); \
return NULL; \
} \
GET_BUFFER_VIEW_OR_ERROR((MSG), &msgview, \
PyBuffer_Release(&keyview); \
return NULL); \
if (!has_uint32_t_buffer_length(&msgview)) { \
PyBuffer_Release(&msgview); \
PyBuffer_Release(&keyview); \
set_invalid_msg_length_error(); \
return NULL; \
} \
uint8_t out[Py_hmac_## HACL_HID ##_digest_size]; \
Py_hmac_## HACL_HID ##_compute_func( \
out, \
(uint8_t *)keyview.buf, (uint32_t)keyview.len, \
(uint8_t *)msgview.buf, (uint32_t)msgview.len \
); \
PyBuffer_Release(&msgview); \
PyBuffer_Release(&keyview); \
return PyBytes_FromStringAndSize( \
(const char *)out, \
Py_hmac_## HACL_HID ##_digest_size \
); \
static int
hmac_get_buffer_views(PyObject *key, Py_buffer *keyview,
PyObject *msg, Py_buffer *msgview)
{
if (_Py_hashlib_get_buffer_view(key, keyview) < 0) {
return -1;
}
if (!has_uint32_t_buffer_length(keyview)) {
PyBuffer_Release(keyview);
set_invalid_key_length_error();
return -1;
}
if (_Py_hashlib_get_buffer_view(msg, msgview) < 0) {
PyBuffer_Release(keyview);
return -1;
}
if (!has_uint32_t_buffer_length(msgview)) {
PyBuffer_Release(msgview);
PyBuffer_Release(keyview);
set_invalid_msg_length_error();
return -1;
}
return 0;
}
/*
* One-shot HMAC-HASH using the given HACL_HID.
*/
#define HACL_HMAC_COMPUTE_NAMED_DIGEST(HACL_HID, KEY, MSG) \
do { \
Py_buffer keyview, msgview; \
if (hmac_get_buffer_views(key, &keyview, msg, &msgview) < 0) { \
return NULL; \
} \
uint8_t out[Py_hmac_## HACL_HID ##_digest_size]; \
Py_hmac_## HACL_HID ##_compute_func( \
out, \
(uint8_t *)keyview.buf, (uint32_t)keyview.len, \
(uint8_t *)msgview.buf, (uint32_t)msgview.len \
); \
PyBuffer_Release(&msgview); \
PyBuffer_Release(&keyview); \
return PyBytes_FromStringAndSize( \
(const char *)out, \
Py_hmac_## HACL_HID ##_digest_size \
); \
} while (0)
/*[clinic input]
@ -1150,7 +1168,7 @@ static PyObject *
_hmac_compute_md5_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=7837a4ceccbbf636 input=77a4b774c7d61218]*/
{
Py_HMAC_HACL_ONESHOT(md5, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(md5, key, msg);
}
/*[clinic input]
@ -1166,7 +1184,7 @@ static PyObject *
_hmac_compute_sha1_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=79fd7689c83691d8 input=3b64dccc6bdbe4ba]*/
{
Py_HMAC_HACL_ONESHOT(sha1, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha1, key, msg);
}
/*[clinic input]
@ -1182,7 +1200,7 @@ static PyObject *
_hmac_compute_sha2_224_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=7f21f1613e53979e input=a1a75f25f23449af]*/
{
Py_HMAC_HACL_ONESHOT(sha2_224, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha2_224, key, msg);
}
/*[clinic input]
@ -1198,7 +1216,7 @@ static PyObject *
_hmac_compute_sha2_256_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=d4a291f7d9a82459 input=5c9ccf2df048ace3]*/
{
Py_HMAC_HACL_ONESHOT(sha2_256, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha2_256, key, msg);
}
/*[clinic input]
@ -1214,7 +1232,7 @@ static PyObject *
_hmac_compute_sha2_384_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=f211fa26e3700c27 input=2fee2c14766af231]*/
{
Py_HMAC_HACL_ONESHOT(sha2_384, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha2_384, key, msg);
}
/*[clinic input]
@ -1230,7 +1248,7 @@ static PyObject *
_hmac_compute_sha2_512_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=d5c20373762cecca input=3371eaac315c7864]*/
{
Py_HMAC_HACL_ONESHOT(sha2_512, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha2_512, key, msg);
}
/*[clinic input]
@ -1246,7 +1264,7 @@ static PyObject *
_hmac_compute_sha3_224_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=a242ccac9ad9c22b input=d0ab0c7d189c3d87]*/
{
Py_HMAC_HACL_ONESHOT(sha3_224, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha3_224, key, msg);
}
/*[clinic input]
@ -1262,7 +1280,7 @@ static PyObject *
_hmac_compute_sha3_256_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=b539dbb61af2fe0b input=f05d7b6364b35d02]*/
{
Py_HMAC_HACL_ONESHOT(sha3_256, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha3_256, key, msg);
}
/*[clinic input]
@ -1278,7 +1296,7 @@ static PyObject *
_hmac_compute_sha3_384_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=5eb372fb5c4ffd3a input=d842d393e7aa05ae]*/
{
Py_HMAC_HACL_ONESHOT(sha3_384, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha3_384, key, msg);
}
/*[clinic input]
@ -1294,7 +1312,7 @@ static PyObject *
_hmac_compute_sha3_512_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=154bcbf8c2eacac1 input=166fe5baaeaabfde]*/
{
Py_HMAC_HACL_ONESHOT(sha3_512, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(sha3_512, key, msg);
}
/*[clinic input]
@ -1310,7 +1328,7 @@ static PyObject *
_hmac_compute_blake2s_32_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=cfc730791bc62361 input=d22c36e7fe31a985]*/
{
Py_HMAC_HACL_ONESHOT(blake2s_32, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(blake2s_32, key, msg);
}
/*[clinic input]
@ -1326,9 +1344,11 @@ static PyObject *
_hmac_compute_blake2b_32_impl(PyObject *module, PyObject *key, PyObject *msg)
/*[clinic end generated code: output=765c5c4fb9124636 input=4a35ee058d172f4b]*/
{
Py_HMAC_HACL_ONESHOT(blake2b_32, key, msg);
HACL_HMAC_COMPUTE_NAMED_DIGEST(blake2b_32, key, msg);
}
#undef HACL_HMAC_COMPUTE_NAMED_DIGEST
// --- HMAC module methods ----------------------------------------------------
static PyMethodDef hmacmodule_methods[] = {