diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 214bc3cb2b187c..f845c7a76e7cb9 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -223,6 +223,10 @@ def test_algorithms_guaranteed(self): def test_algorithms_available(self): self.assertTrue(set(hashlib.algorithms_guaranteed). issubset(hashlib.algorithms_available)) + # all available algorithms must be loadable, bpo-47101 + self.assertNotIn("undefined", hashlib.algorithms_available) + for name in hashlib.algorithms_available: + digest = hashlib.new(name, usedforsecurity=False) def test_usedforsecurity_true(self): hashlib.new("sha256", usedforsecurity=True) diff --git a/Misc/NEWS.d/next/Library/2022-03-23-15-31-02.bpo-47101.rVSld-.rst b/Misc/NEWS.d/next/Library/2022-03-23-15-31-02.bpo-47101.rVSld-.rst new file mode 100644 index 00000000000000..1a65024e69fbdc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-23-15-31-02.bpo-47101.rVSld-.rst @@ -0,0 +1,4 @@ +:const:`hashlib.algorithms_available` now lists only algorithms that are +provided by activated crypto providers on OpenSSL 3.0. Legacy algorithms are +not listed unless the legacy provider has been loaded into the default +OSSL context. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 4873bb11aa0cd6..4db058c06275ff 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -1860,15 +1860,21 @@ typedef struct _internal_name_mapper_state { /* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */ static void +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +_openssl_hash_name_mapper(EVP_MD *md, void *arg) +#else _openssl_hash_name_mapper(const EVP_MD *md, const char *from, const char *to, void *arg) +#endif { _InternalNameMapperState *state = (_InternalNameMapperState *)arg; PyObject *py_name; assert(state != NULL); - if (md == NULL) + // ignore all undefined providers + if ((md == NULL) || (EVP_MD_nid(md) == NID_undef)) { return; + } py_name = py_digest_name(md); if (py_name == NULL) { @@ -1894,7 +1900,12 @@ hashlib_md_meth_names(PyObject *module) return -1; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + // get algorithms from all activated providers in default context + EVP_MD_do_all_provided(NULL, &_openssl_hash_name_mapper, &state); +#else EVP_MD_do_all(&_openssl_hash_name_mapper, &state); +#endif if (state.error) { Py_DECREF(state.set);