Skip to content

Commit c30ca29

Browse files
committed
improve how we set exceptions in _hashopenssl.c
1 parent 0b6e98c commit c30ca29

File tree

1 file changed

+84
-48
lines changed

1 file changed

+84
-48
lines changed

Modules/_hashopenssl.c

Lines changed: 84 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -304,30 +304,17 @@ class _hashlib.HMAC "HMACobject *" "((_hashlibstate *)PyModule_GetState(module))
304304

305305

306306
/* LCOV_EXCL_START */
307-
static PyObject *
308-
_setException(PyObject *exc, const char* altmsg, ...)
309-
{
310-
unsigned long errcode = ERR_peek_last_error();
311-
const char *lib, *func, *reason;
312-
va_list vargs;
313307

314-
va_start(vargs, altmsg);
315-
if (!errcode) {
316-
if (altmsg == NULL) {
317-
PyErr_SetString(exc, "no reason supplied");
318-
} else {
319-
PyErr_FormatV(exc, altmsg, vargs);
320-
}
321-
va_end(vargs);
322-
return NULL;
323-
}
324-
va_end(vargs);
325-
ERR_clear_error();
308+
/* Set an exception of given type using the given OpenSSL error code. */
309+
static void
310+
set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode)
311+
{
312+
assert(errcode != 0);
326313

327314
/* ERR_ERROR_STRING(3) ensures that the messages below are ASCII */
328-
lib = ERR_lib_error_string(errcode);
329-
func = ERR_func_error_string(errcode);
330-
reason = ERR_reason_error_string(errcode);
315+
const char *lib = ERR_lib_error_string(errcode);
316+
const char *func = ERR_func_error_string(errcode);
317+
const char *reason = ERR_reason_error_string(errcode);
331318

332319
if (lib && func) {
333320
PyErr_Format(exc, "[%s: %s] %s", lib, func, reason);
@@ -338,7 +325,42 @@ _setException(PyObject *exc, const char* altmsg, ...)
338325
else {
339326
PyErr_SetString(exc, reason);
340327
}
341-
return NULL;
328+
}
329+
330+
/*
331+
* Set an exception of given type.
332+
*
333+
* By default, the exception's message is constructed by using the last SSL
334+
* error that occurred. If no error occurred, the 'fallback_format' is used
335+
* to create a C-style formatted fallback message.
336+
*/
337+
static void
338+
raise_ssl_error(PyObject *exc, const char *fallback_format, ...)
339+
{
340+
assert(fallback_format != NULL);
341+
unsigned long errcode = ERR_peek_last_error();
342+
if (errcode) {
343+
ERR_clear_error();
344+
set_ssl_exception_from_errcode(exc, errcode);
345+
}
346+
else {
347+
va_list vargs;
348+
va_start(vargs, fallback_format);
349+
PyErr_FormatV(exc, fallback_format, vargs);
350+
va_end(vargs);
351+
}
352+
}
353+
354+
/*
355+
* Set an exception with a generic default message after an error occurred.
356+
*
357+
* It can also be used without previous calls to SSL built-in functions,
358+
* in which case a generic error message is provided.
359+
*/
360+
static inline void
361+
notify_ssl_error_occurred(void)
362+
{
363+
raise_ssl_error(PyExc_ValueError, "no reason supplied");
342364
}
343365
/* LCOV_EXCL_STOP */
344366

@@ -430,8 +452,8 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
430452
}
431453
}
432454
if (digest == NULL) {
433-
(void)_setException(state->unsupported_digestmod_error,
434-
"unsupported hash type %s", name);
455+
raise_ssl_error(state->unsupported_digestmod_error,
456+
"unsupported hash type %s", name);
435457
return NULL;
436458
}
437459
return digest;
@@ -504,7 +526,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
504526
else
505527
process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
506528
if (!EVP_DigestUpdate(self->ctx, (const void*)cp, process)) {
507-
(void)_setException(PyExc_ValueError, NULL);
529+
notify_ssl_error_occurred();
508530
return -1;
509531
}
510532
len -= process;
@@ -554,7 +576,8 @@ EVP_copy_impl(EVPobject *self)
554576

555577
if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) {
556578
Py_DECREF(newobj);
557-
return _setException(PyExc_ValueError, NULL);
579+
notify_ssl_error_occurred();
580+
return NULL;
558581
}
559582
return (PyObject *)newobj;
560583
}
@@ -594,7 +617,8 @@ EVP_digest_impl(EVPobject *self)
594617

595618
error:
596619
EVP_MD_CTX_free(temp_ctx);
597-
return _setException(PyExc_ValueError, NULL);
620+
notify_ssl_error_occurred();
621+
return NULL;
598622
}
599623

600624
/*[clinic input]
@@ -632,7 +656,8 @@ EVP_hexdigest_impl(EVPobject *self)
632656

633657
error:
634658
EVP_MD_CTX_free(temp_ctx);
635-
return _setException(PyExc_ValueError, NULL);
659+
notify_ssl_error_occurred();
660+
return NULL;
636661
}
637662

638663
/*[clinic input]
@@ -703,7 +728,8 @@ EVP_get_name(PyObject *op, void *Py_UNUSED(closure))
703728
EVPobject *self = EVPobject_CAST(op);
704729
const EVP_MD *md = EVP_MD_CTX_md(self->ctx);
705730
if (md == NULL) {
706-
return _setException(PyExc_ValueError, NULL);
731+
notify_ssl_error_occurred();
732+
return NULL;
707733
}
708734
return py_digest_name(md);
709735
}
@@ -808,7 +834,8 @@ EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
808834
error:
809835
Py_DECREF(retval);
810836
EVP_MD_CTX_free(temp_ctx);
811-
return _setException(PyExc_ValueError, NULL);
837+
notify_ssl_error_occurred();
838+
return NULL;
812839
}
813840

814841
/*[clinic input]
@@ -857,7 +884,8 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
857884
error:
858885
PyMem_Free(digest);
859886
EVP_MD_CTX_free(temp_ctx);
860-
return _setException(PyExc_ValueError, NULL);
887+
notify_ssl_error_occurred();
888+
return NULL;
861889
}
862890

863891
static PyMethodDef EVPXOF_methods[] = {
@@ -955,7 +983,7 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
955983

956984
int result = EVP_DigestInit_ex(self->ctx, digest, NULL);
957985
if (!result) {
958-
(void)_setException(PyExc_ValueError, NULL);
986+
notify_ssl_error_occurred();
959987
Py_CLEAR(self);
960988
goto exit;
961989
}
@@ -971,6 +999,7 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
971999
result = EVP_hash(self, view.buf, view.len);
9721000
}
9731001
if (result == -1) {
1002+
assert(PyErr_Occurred());
9741003
Py_CLEAR(self);
9751004
goto exit;
9761005
}
@@ -1345,7 +1374,7 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name,
13451374

13461375
if (!retval) {
13471376
Py_CLEAR(key_obj);
1348-
_setException(PyExc_ValueError, NULL);
1377+
notify_ssl_error_occurred();
13491378
goto end;
13501379
}
13511380

@@ -1451,8 +1480,9 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
14511480
/* let OpenSSL validate the rest */
14521481
retval = EVP_PBE_scrypt(NULL, 0, NULL, 0, n, r, p, maxmem, NULL, 0);
14531482
if (!retval) {
1454-
return _setException(PyExc_ValueError,
1455-
"Invalid parameter combination for n, r, p, maxmem.");
1483+
raise_ssl_error(PyExc_ValueError,
1484+
"Invalid parameter combination for n, r, p, maxmem.");
1485+
return NULL;
14561486
}
14571487

14581488
key_obj = PyBytes_FromStringAndSize(NULL, dklen);
@@ -1472,7 +1502,8 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
14721502

14731503
if (!retval) {
14741504
Py_CLEAR(key_obj);
1475-
return _setException(PyExc_ValueError, NULL);
1505+
notify_ssl_error_occurred();
1506+
return NULL;
14761507
}
14771508
return key_obj;
14781509
}
@@ -1528,7 +1559,8 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
15281559
PY_EVP_MD_free(evp);
15291560

15301561
if (result == NULL) {
1531-
return _setException(PyExc_ValueError, NULL);
1562+
notify_ssl_error_occurred();
1563+
return NULL;
15321564
}
15331565
return PyBytes_FromStringAndSize((const char*)md, md_len);
15341566
}
@@ -1585,7 +1617,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
15851617
r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */);
15861618
PY_EVP_MD_free(digest);
15871619
if (r == 0) {
1588-
(void)_setException(PyExc_ValueError, NULL);
1620+
notify_ssl_error_occurred();
15891621
goto error;
15901622
}
15911623

@@ -1629,13 +1661,13 @@ _hmac_digest_size(HMACobject *self)
16291661
{
16301662
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
16311663
if (md == NULL) {
1632-
(void)_setException(PyExc_ValueError, NULL);
1664+
notify_ssl_error_occurred();
16331665
return 0;
16341666
}
16351667
unsigned int digest_size = EVP_MD_size(md);
16361668
assert(digest_size <= EVP_MAX_MD_SIZE);
16371669
if (digest_size == 0) {
1638-
(void)_setException(PyExc_ValueError, NULL);
1670+
notify_ssl_error_occurred();
16391671
}
16401672
return digest_size;
16411673
}
@@ -1664,7 +1696,7 @@ _hmac_update(HMACobject *self, PyObject *obj)
16641696
PyBuffer_Release(&view);
16651697

16661698
if (r == 0) {
1667-
(void)_setException(PyExc_ValueError, NULL);
1699+
notify_ssl_error_occurred();
16681700
return 0;
16691701
}
16701702
return 1;
@@ -1688,7 +1720,8 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
16881720
}
16891721
if (!locked_HMAC_CTX_copy(ctx, self)) {
16901722
HMAC_CTX_free(ctx);
1691-
return _setException(PyExc_ValueError, NULL);
1723+
notify_ssl_error_occurred();
1724+
return NULL;
16921725
}
16931726

16941727
retval = PyObject_New(HMACobject, Py_TYPE(self));
@@ -1721,7 +1754,8 @@ _hmac_repr(PyObject *op)
17211754
HMACobject *self = HMACobject_CAST(op);
17221755
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
17231756
if (md == NULL) {
1724-
return _setException(PyExc_ValueError, NULL);
1757+
notify_ssl_error_occurred();
1758+
return NULL;
17251759
}
17261760
PyObject *digest_name = py_digest_name(md);
17271761
if (digest_name == NULL) {
@@ -1761,13 +1795,13 @@ _hmac_digest(HMACobject *self, unsigned char *buf, unsigned int len)
17611795
}
17621796
if (!locked_HMAC_CTX_copy(temp_ctx, self)) {
17631797
HMAC_CTX_free(temp_ctx);
1764-
(void)_setException(PyExc_ValueError, NULL);
1798+
notify_ssl_error_occurred();
17651799
return 0;
17661800
}
17671801
int r = HMAC_Final(temp_ctx, buf, &len);
17681802
HMAC_CTX_free(temp_ctx);
17691803
if (r == 0) {
1770-
(void)_setException(PyExc_ValueError, NULL);
1804+
notify_ssl_error_occurred();
17711805
return 0;
17721806
}
17731807
return 1;
@@ -1836,7 +1870,8 @@ _hashlib_hmac_get_block_size(PyObject *op, void *Py_UNUSED(closure))
18361870
HMACobject *self = HMACobject_CAST(op);
18371871
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
18381872
if (md == NULL) {
1839-
return _setException(PyExc_ValueError, NULL);
1873+
notify_ssl_error_occurred();
1874+
return NULL;
18401875
}
18411876
return PyLong_FromLong(EVP_MD_block_size(md));
18421877
}
@@ -1847,7 +1882,8 @@ _hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure))
18471882
HMACobject *self = HMACobject_CAST(op);
18481883
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
18491884
if (md == NULL) {
1850-
return _setException(PyExc_ValueError, NULL);
1885+
notify_ssl_error_occurred();
1886+
return NULL;
18511887
}
18521888
PyObject *digest_name = py_digest_name(md);
18531889
if (digest_name == NULL) {
@@ -2000,7 +2036,7 @@ _hashlib_get_fips_mode_impl(PyObject *module)
20002036
// But 0 is also a valid result value.
20012037
unsigned long errcode = ERR_peek_last_error();
20022038
if (errcode) {
2003-
(void)_setException(PyExc_ValueError, NULL);
2039+
notify_ssl_error_occurred();
20042040
return -1;
20052041
}
20062042
}

0 commit comments

Comments
 (0)