https://github.com/python/cpython/commit/304ef8440b46caa36c295bd0a47c5c24bbd1a245
commit: 304ef8440b46caa36c295bd0a47c5c24bbd1a245
branch: 3.12
author: Bénédikt Tran <[email protected]>
committer: picnixz <[email protected]>
date: 2025-03-18T10:16:26+01:00
summary:
[3.12] gh-127667: refactor and improve `_hashopenssl.c` error branches
(#131145) (#131348)
gh-127667: refactor and improve `_hashopenssl.c` error branches (#131145)
Refactor `_setException()` into different helpers that can be used separately:
- set_ssl_exception_from_errcode(): set an exception from an explicit SSL error
code.
- raise_ssl_error(): set an exception from the last SSL error code or use a
user-defined message.
- notify_ssl_error_occurred(): same as raise_ssl_error() but with a generic
default message.
(cherry-picked from commit ac50ece6cea8745834e4ec0a9617809a51245bfc).
files:
M Modules/_hashopenssl.c
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index 48d7fd03feb16b..41ec16426b09b5 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -300,30 +300,17 @@ class _hashlib.HMAC "HMACobject *" "((_hashlibstate
*)PyModule_GetState(module))
/* LCOV_EXCL_START */
-static PyObject *
-_setException(PyObject *exc, const char* altmsg, ...)
-{
- unsigned long errcode = ERR_peek_last_error();
- const char *lib, *func, *reason;
- va_list vargs;
- va_start(vargs, altmsg);
- if (!errcode) {
- if (altmsg == NULL) {
- PyErr_SetString(exc, "no reason supplied");
- } else {
- PyErr_FormatV(exc, altmsg, vargs);
- }
- va_end(vargs);
- return NULL;
- }
- va_end(vargs);
- ERR_clear_error();
+/* Set an exception of given type using the given OpenSSL error code. */
+static void
+set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode)
+{
+ assert(errcode != 0);
/* ERR_ERROR_STRING(3) ensures that the messages below are ASCII */
- lib = ERR_lib_error_string(errcode);
- func = ERR_func_error_string(errcode);
- reason = ERR_reason_error_string(errcode);
+ const char *lib = ERR_lib_error_string(errcode);
+ const char *func = ERR_func_error_string(errcode);
+ const char *reason = ERR_reason_error_string(errcode);
if (lib && func) {
PyErr_Format(exc, "[%s: %s] %s", lib, func, reason);
@@ -334,13 +321,49 @@ _setException(PyObject *exc, const char* altmsg, ...)
else {
PyErr_SetString(exc, reason);
}
- return NULL;
+}
+
+/*
+ * Set an exception of given type.
+ *
+ * By default, the exception's message is constructed by using the last SSL
+ * error that occurred. If no error occurred, the 'fallback_format' is used
+ * to create a C-style formatted fallback message.
+ */
+static void
+raise_ssl_error(PyObject *exc, const char *fallback_format, ...)
+{
+ assert(fallback_format != NULL);
+ unsigned long errcode = ERR_peek_last_error();
+ if (errcode) {
+ ERR_clear_error();
+ set_ssl_exception_from_errcode(exc, errcode);
+ }
+ else {
+ va_list vargs;
+ va_start(vargs, fallback_format);
+ PyErr_FormatV(exc, fallback_format, vargs);
+ va_end(vargs);
+ }
+}
+
+/*
+ * Set an exception with a generic default message after an error occurred.
+ *
+ * It can also be used without previous calls to SSL built-in functions,
+ * in which case a generic error message is provided.
+ */
+static inline void
+notify_ssl_error_occurred(void)
+{
+ raise_ssl_error(PyExc_ValueError, "no reason supplied");
}
/* LCOV_EXCL_STOP */
static PyObject*
py_digest_name(const EVP_MD *md)
{
+ assert(md != NULL);
int nid = EVP_MD_nid(md);
const char *name = NULL;
const py_hashentry_t *h;
@@ -409,8 +432,8 @@ py_digest_by_name(PyObject *module, const char *name, enum
Py_hash_type py_ht)
}
}
if (digest == NULL) {
- (void)_setException(state->unsupported_digestmod_error,
- "unsupported hash type %s", name);
+ raise_ssl_error(state->unsupported_digestmod_error,
+ "unsupported hash type %s", name);
return NULL;
}
return digest;
@@ -484,7 +507,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
else
process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
if (!EVP_DigestUpdate(self->ctx, (const void*)cp, process)) {
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
return -1;
}
len -= process;
@@ -535,7 +558,8 @@ EVP_copy_impl(EVPobject *self)
if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) {
Py_DECREF(newobj);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
return (PyObject *)newobj;
}
@@ -575,7 +599,8 @@ EVP_digest_impl(EVPobject *self)
error:
EVP_MD_CTX_free(temp_ctx);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
/*[clinic input]
@@ -613,7 +638,8 @@ EVP_hexdigest_impl(EVPobject *self)
error:
EVP_MD_CTX_free(temp_ctx);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
/*[clinic input]
@@ -685,7 +711,8 @@ EVP_get_name(EVPobject *self, void *closure)
{
const EVP_MD *md = EVP_MD_CTX_md(self->ctx);
if (md == NULL) {
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
return py_digest_name(md);
}
@@ -800,7 +827,8 @@ EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
error:
Py_DECREF(retval);
EVP_MD_CTX_free(temp_ctx);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
/*[clinic input]
@@ -849,7 +877,8 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
error:
PyMem_Free(digest);
EVP_MD_CTX_free(temp_ctx);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
static PyMethodDef EVPXOF_methods[] = {
@@ -950,7 +979,7 @@ py_evp_fromname(PyObject *module, const char *digestname,
PyObject *data_obj,
int result = EVP_DigestInit_ex(self->ctx, digest, NULL);
if (!result) {
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
Py_CLEAR(self);
goto exit;
}
@@ -966,6 +995,7 @@ py_evp_fromname(PyObject *module, const char *digestname,
PyObject *data_obj,
result = EVP_hash(self, view.buf, view.len);
}
if (result == -1) {
+ assert(PyErr_Occurred());
Py_CLEAR(self);
goto exit;
}
@@ -1332,19 +1362,19 @@ pbkdf2_hmac_impl(PyObject *module, const char
*hash_name,
key = PyBytes_AS_STRING(key_obj);
Py_BEGIN_ALLOW_THREADS
- retval = PKCS5_PBKDF2_HMAC((char*)password->buf, (int)password->len,
- (unsigned char *)salt->buf, (int)salt->len,
+ retval = PKCS5_PBKDF2_HMAC((const char *)password->buf, (int)password->len,
+ (const unsigned char *)salt->buf,
(int)salt->len,
iterations, digest, dklen,
(unsigned char *)key);
Py_END_ALLOW_THREADS
if (!retval) {
Py_CLEAR(key_obj);
- _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
goto end;
}
- end:
+end:
if (digest != NULL) {
PY_EVP_MD_free(digest);
}
@@ -1446,8 +1476,9 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer
*password, Py_buffer *salt,
/* let OpenSSL validate the rest */
retval = EVP_PBE_scrypt(NULL, 0, NULL, 0, n, r, p, maxmem, NULL, 0);
if (!retval) {
- return _setException(PyExc_ValueError,
- "Invalid parameter combination for n, r, p,
maxmem.");
+ raise_ssl_error(PyExc_ValueError,
+ "Invalid parameter combination for n, r, p, maxmem.");
+ return NULL;
}
key_obj = PyBytes_FromStringAndSize(NULL, dklen);
@@ -1467,7 +1498,8 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer
*password, Py_buffer *salt,
if (!retval) {
Py_CLEAR(key_obj);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
return key_obj;
}
@@ -1515,15 +1547,16 @@ _hashlib_hmac_singleshot_impl(PyObject *module,
Py_buffer *key,
Py_BEGIN_ALLOW_THREADS
result = HMAC(
evp,
- (const void*)key->buf, (int)key->len,
- (const unsigned char*)msg->buf, (int)msg->len,
+ (const void *)key->buf, (int)key->len,
+ (const unsigned char *)msg->buf, (size_t)msg->len,
md, &md_len
);
Py_END_ALLOW_THREADS
PY_EVP_MD_free(evp);
if (result == NULL) {
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
return PyBytes_FromStringAndSize((const char*)md, md_len);
}
@@ -1533,6 +1566,16 @@ _hashlib_hmac_singleshot_impl(PyObject *module,
Py_buffer *key,
static int _hmac_update(HMACobject*, PyObject*);
+static const EVP_MD *
+_hashlib_hmac_get_md(HMACobject *self)
+{
+ const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+ if (md == NULL) {
+ raise_ssl_error(PyExc_ValueError, "missing EVP_MD for HMAC context");
+ }
+ return md;
+}
+
/*[clinic input]
_hashlib.hmac_new
@@ -1580,7 +1623,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key,
PyObject *msg_obj,
r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */);
PY_EVP_MD_free(digest);
if (r == 0) {
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
goto error;
}
@@ -1620,17 +1663,16 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject
*self)
/* returning 0 means that an error occurred and an exception is set */
static unsigned int
-_hmac_digest_size(HMACobject *self)
+_hashlib_hmac_digest_size(HMACobject *self)
{
- const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+ const EVP_MD *md = _hashlib_hmac_get_md(self);
if (md == NULL) {
- (void)_setException(PyExc_ValueError, NULL);
return 0;
}
unsigned int digest_size = EVP_MD_size(md);
assert(digest_size <= EVP_MAX_MD_SIZE);
if (digest_size == 0) {
- (void)_setException(PyExc_ValueError, NULL);
+ raise_ssl_error(PyExc_ValueError, "invalid digest size");
}
return digest_size;
}
@@ -1651,17 +1693,21 @@ _hmac_update(HMACobject *self, PyObject *obj)
if (self->lock != NULL) {
Py_BEGIN_ALLOW_THREADS
PyThread_acquire_lock(self->lock, 1);
- r = HMAC_Update(self->ctx, (const unsigned char*)view.buf, view.len);
+ r = HMAC_Update(self->ctx,
+ (const unsigned char*)view.buf,
+ (size_t)view.len);
PyThread_release_lock(self->lock);
Py_END_ALLOW_THREADS
} else {
- r = HMAC_Update(self->ctx, (const unsigned char*)view.buf, view.len);
+ r = HMAC_Update(self->ctx,
+ (const unsigned char *)view.buf,
+ (size_t)view.len);
}
PyBuffer_Release(&view);
if (r == 0) {
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
return 0;
}
return 1;
@@ -1685,7 +1731,8 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
}
if (!locked_HMAC_CTX_copy(ctx, self)) {
HMAC_CTX_free(ctx);
- return _setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
+ return NULL;
}
retval = PyObject_New(HMACobject, Py_TYPE(self));
@@ -1717,9 +1764,9 @@ _hmac_dealloc(HMACobject *self)
static PyObject *
_hmac_repr(HMACobject *self)
{
- const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+ const EVP_MD *md = _hashlib_hmac_get_md(self);
if (md == NULL) {
- return _setException(PyExc_ValueError, NULL);
+ return NULL;
}
PyObject *digest_name = py_digest_name(md);
if (digest_name == NULL) {
@@ -1759,13 +1806,13 @@ _hmac_digest(HMACobject *self, unsigned char *buf,
unsigned int len)
}
if (!locked_HMAC_CTX_copy(temp_ctx, self)) {
HMAC_CTX_free(temp_ctx);
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
return 0;
}
int r = HMAC_Final(temp_ctx, buf, &len);
HMAC_CTX_free(temp_ctx);
if (r == 0) {
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
return 0;
}
return 1;
@@ -1781,7 +1828,7 @@ _hashlib_HMAC_digest_impl(HMACobject *self)
/*[clinic end generated code: output=1b1424355af7a41e input=bff07f74da318fb4]*/
{
unsigned char digest[EVP_MAX_MD_SIZE];
- unsigned int digest_size = _hmac_digest_size(self);
+ unsigned int digest_size = _hashlib_hmac_digest_size(self);
if (digest_size == 0) {
return NULL;
}
@@ -1806,7 +1853,7 @@ _hashlib_HMAC_hexdigest_impl(HMACobject *self)
/*[clinic end generated code: output=80d825be1eaae6a7 input=5abc42702874ddcf]*/
{
unsigned char digest[EVP_MAX_MD_SIZE];
- unsigned int digest_size = _hmac_digest_size(self);
+ unsigned int digest_size = _hashlib_hmac_digest_size(self);
if (digest_size == 0) {
return NULL;
}
@@ -1820,29 +1867,23 @@ _hashlib_HMAC_hexdigest_impl(HMACobject *self)
static PyObject *
_hashlib_hmac_get_digest_size(HMACobject *self, void *closure)
{
- unsigned int digest_size = _hmac_digest_size(self);
- if (digest_size == 0) {
- return NULL;
- }
- return PyLong_FromLong(digest_size);
+ unsigned int digest_size = _hashlib_hmac_digest_size(self);
+ return digest_size == 0 ? NULL : PyLong_FromLong(digest_size);
}
static PyObject *
_hashlib_hmac_get_block_size(HMACobject *self, void *closure)
{
- const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
- if (md == NULL) {
- return _setException(PyExc_ValueError, NULL);
- }
- return PyLong_FromLong(EVP_MD_block_size(md));
+ const EVP_MD *md = _hashlib_hmac_get_md(self);
+ return md == NULL ? NULL : PyLong_FromLong(EVP_MD_block_size(md));
}
static PyObject *
_hashlib_hmac_get_name(HMACobject *self, void *closure)
{
- const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+ const EVP_MD *md = _hashlib_hmac_get_md(self);
if (md == NULL) {
- return _setException(PyExc_ValueError, NULL);
+ return NULL;
}
PyObject *digest_name = py_digest_name(md);
if (digest_name == NULL) {
@@ -2000,7 +2041,7 @@ _hashlib_get_fips_mode_impl(PyObject *module)
// But 0 is also a valid result value.
unsigned long errcode = ERR_peek_last_error();
if (errcode) {
- (void)_setException(PyExc_ValueError, NULL);
+ notify_ssl_error_occurred();
return -1;
}
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]