FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-159815: do not leave stale OpenSSL errors in `_hashlib` by picnixz · Pull Request #159816 · python/cpython · GitHub

Repository navigation

Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (1) .py  (1) .rst  (1) All 3 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
12 changes: 12 additions & 0 deletions Lib/test/test_hashlib.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,18 @@ def scrypt(password=b"password", /, **kwargs):
MAX_DKLEN = ((1 << 32) - 1) * 32 # see RFC 7914
self.assertRaises(numeric_exc_types, scrypt, dklen=MAX_DKLEN + 1)

def test_scrypt_stale_openssl_error(self):
# gh-159815: a failed algorithm lookup must not leave an error in
# the OpenSSL error queue that a later unrelated failure reports.
def get_error_message():
with self.assertRaises(ValueError) as cm:
hashlib.scrypt(b'password', salt=b'salt', n=2, r=0, p=1)
return str(cm.exception)

expect = get_error_message()
self.assertRaises(ValueError, _hashlib.new, 'no_such_algorithm')
self.assertEqual(get_error_message(), expect)


@threading_helper.requires_working_threading()
class TestTSAN(unittest.TestCase):
Expand Down
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:mod:`hashlib`: fix exception messages that reported an earlier and unrelated
OpenSSL error after a hash algorithm could not be found. Patch by Bénédikt Tran.
34 changes: 29 additions & 5 deletions Modules/_hashopenssl.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,10 @@ notify_smart_ssl_error_occurred_in(const char *funcname)
}

#ifdef Py_HAS_OPENSSL3_SUPPORT
/*
* The OpenSSL error queue must be cleared before calling the OpenSSL
* function whose failure is being reported.
*/
static void
raise_unsupported_algorithm_impl(PyObject *exc_type,
const char *fallback_format,
Expand All @@ -518,19 +522,21 @@ raise_unsupported_algorithm_impl(PyObject *exc_type,
int errcode = ERR_peek_last_error();
switch (ERR_GET_REASON(errcode)) {
case ERR_R_UNSUPPORTED: {
const char *lib = ERR_lib_error_string(errcode);
ERR_clear_error();
PyObject *text = PyUnicode_FromFormat(fallback_format, format_arg);
if (text != NULL) {
const char *lib = ERR_lib_error_string(errcode);
set_exception_with_ssl_errinfo(exc_type, text, lib, NULL);
Py_DECREF(text);
}
break;
}
case ERR_R_FETCH_FAILED: {
const char *lib = ERR_lib_error_string(errcode);
const char *reason = ERR_reason_error_string(errcode);
ERR_clear_error();
PyObject *text = PyUnicode_FromFormat(fallback_format, format_arg);
if (text != NULL) {
const char *lib = ERR_lib_error_string(errcode);
const char *reason = ERR_reason_error_string(errcode);
set_exception_with_ssl_errinfo(exc_type, text, lib, reason);
Py_DECREF(text);
}
Expand Down Expand Up @@ -601,6 +607,8 @@ get_hashentry_by_nid(int nid)
* Convert the NID to a string via OBJ_nid2*() functions.
*
* If 'nid' cannot be resolved, set an exception and return NULL.
*
* The OpenSSL error queue must be cleared before calling this function.
*/
static const char *
get_asn1_utf8name_by_nid(int nid)
Expand Down Expand Up @@ -639,7 +647,11 @@ static const char *
get_hashlib_utf8name_by_nid(int nid)
{
const py_hashentry_t *e = get_hashentry_by_nid(nid);
return e ? e->py_name : get_asn1_utf8name_by_nid(nid);
if (e != NULL) {
return e->py_name;
}
ERR_clear_error();
return get_asn1_utf8name_by_nid(nid);
}

#ifdef Py_HAS_OPENSSL3_SUPPORT
Expand All @@ -652,7 +664,11 @@ static const char *
get_openssl_utf8name_by_nid(int nid)
{
const py_hashentry_t *e = get_hashentry_by_nid(nid);
return e ? e->ossl_name : get_asn1_utf8name_by_nid(nid);
if (e != NULL) {
return e->ossl_name;
}
ERR_clear_error();
return get_asn1_utf8name_by_nid(nid);
}
#endif

Expand Down Expand Up @@ -700,6 +716,7 @@ get_openssl_evp_md_by_utf8name(_hashlibstate *state, const char *name,
if (!disable_fips_property(py_ht)) {
digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp);
if (digest == NULL) {
ERR_clear_error();
digest = PY_EVP_MD_fetch(entry->ossl_name, NULL);
#ifdef Py_GIL_DISABLED
// exchange just in case another thread did same thing at same time
Expand All @@ -712,6 +729,7 @@ get_openssl_evp_md_by_utf8name(_hashlibstate *state, const char *name,
else {
digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp_nosecurity);
if (digest == NULL) {
ERR_clear_error();
digest = PY_EVP_MD_fetch(entry->ossl_name, "-fips");
#ifdef Py_GIL_DISABLED
// exchange just in case another thread did same thing at same time
Expand All @@ -731,6 +749,7 @@ get_openssl_evp_md_by_utf8name(_hashlibstate *state, const char *name,
// Fall back for looking up an unindexed OpenSSL specific name.
const char *props = disable_fips_property(py_ht) ? "-fips" : NULL;
(void)props; // will only be used in OpenSSL 3.0 and later
ERR_clear_error();
digest = PY_EVP_MD_fetch(name, props);
}
if (digest == NULL) {
Expand Down Expand Up @@ -765,6 +784,7 @@ get_openssl_evp_md(_hashlibstate *state, PyObject *digestmod, Py_hash_type py_ht
}
if (name == NULL) {
if (!PyErr_Occurred()) {
ERR_clear_error();
raise_unsupported_algorithm_error(state, digestmod);
}
return NULL;
Expand Down Expand Up @@ -1898,6 +1918,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
assert(evp != NULL);
is_xof = PY_EVP_MD_xof(evp);

ERR_clear_error();
Py_BEGIN_ALLOW_THREADS
result = EVP_Q_mac(
NULL, OSSL_MAC_NAME_HMAC, NULL, NULL,
Expand All @@ -1916,6 +1937,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
}
is_xof = PY_EVP_MD_xof(evp);

ERR_clear_error();
Py_BEGIN_ALLOW_THREADS
result = HMAC(
evp,
Expand Down Expand Up @@ -2081,6 +2103,7 @@ hashlib_HMAC_CTX_new_from_digestmod(_hashlibstate *state,
return NULL;
}

ERR_clear_error();
r = EVP_MAC_init(
ctx,
(const unsigned char *)key->buf,
Expand All @@ -2101,6 +2124,7 @@ hashlib_HMAC_CTX_new_from_digestmod(_hashlibstate *state,
return NULL;
}

ERR_clear_error();
r = HMAC_Init_ex(ctx, key->buf, (int)key->len, md, NULL /* impl */);
PY_EVP_MD_free(md);
#endif
Expand Down
Loading

Back | FazBrowse Home | New Git URL