◐ Shell
clean mode source ↗

[3.8] bpo-38153: Normalize hashlib algorithm names (GH-16083) (GH-16144) by tiran · Pull Request #16144 · python/cpython

Expand Up @@ -34,6 +34,14 @@
#define MUNCH_SIZE INT_MAX
#if defined(NID_sha3_224) && defined(EVP_MD_FLAG_XOF) #define PY_OPENSSL_HAS_SHA3 1 #endif
#ifdef NID_blake2b512 #define PY_OPENSSL_HAS_BLAKE2 1 #endif
typedef struct { PyObject_HEAD EVP_MD_CTX *ctx; /* OpenSSL message digest context */ Expand Down Expand Up @@ -82,6 +90,135 @@ _setException(PyObject *exc) } /* LCOV_EXCL_STOP */
static PyObject* py_digest_name(const EVP_MD *md) { int nid = EVP_MD_nid(md); const char *name = NULL;
/* Hard-coded names for well-known hashing algorithms. * OpenSSL uses slightly different names algorithms like SHA3. */ switch (nid) { case NID_md5: name = "md5"; break; case NID_sha1: name = "sha1"; break; case NID_sha224: name ="sha224"; break; case NID_sha256: name ="sha256"; break; case NID_sha384: name ="sha384"; break; case NID_sha512: name ="sha512"; break; #ifdef NID_sha512_224 case NID_sha512_224: name ="sha512_224"; break; case NID_sha512_256: name ="sha512_256"; break; #endif #ifdef PY_OPENSSL_HAS_SHA3 case NID_sha3_224: name ="sha3_224"; break; case NID_sha3_256: name ="sha3_256"; break; case NID_sha3_384: name ="sha3_384"; break; case NID_sha3_512: name ="sha3_512"; break; case NID_shake128: name ="shake_128"; break; case NID_shake256: name ="shake_256"; break; #endif #ifdef PY_OPENSSL_HAS_BLAKE2 case NID_blake2s256: name ="blake2s"; break; case NID_blake2b512: name ="blake2b"; break; #endif default: /* Ignore aliased names and only use long, lowercase name. The aliases * pollute the list and OpenSSL appears to have its own definition of * alias as the resulting list still contains duplicate and alternate * names for several algorithms. */ name = OBJ_nid2ln(nid); if (name == NULL) name = OBJ_nid2sn(nid); break; }
return PyUnicode_FromString(name); }
static const EVP_MD* py_digest_by_name(const char *name) { const EVP_MD *digest = EVP_get_digestbyname(name);
/* OpenSSL uses dash instead of underscore in names of some algorithms * like SHA3 and SHAKE. Detect different spellings. */ if (digest == NULL) { #ifdef NID_sha512_224 if (!strcmp(name, "sha512_224") || !strcmp(name, "SHA512_224")) { digest = EVP_sha512_224(); } else if (!strcmp(name, "sha512_256") || !strcmp(name, "SHA512_256")) { digest = EVP_sha512_256(); } #endif #ifdef PY_OPENSSL_HAS_SHA3 /* could be sha3_ or shake_, Python never defined upper case */ else if (!strcmp(name, "sha3_224")) { digest = EVP_sha3_224(); } else if (!strcmp(name, "sha3_256")) { digest = EVP_sha3_256(); } else if (!strcmp(name, "sha3_384")) { digest = EVP_sha3_384(); } else if (!strcmp(name, "sha3_512")) { digest = EVP_sha3_512(); } else if (!strcmp(name, "shake_128")) { digest = EVP_shake128(); } else if (!strcmp(name, "shake_256")) { digest = EVP_shake256(); } #endif #ifdef PY_OPENSSL_HAS_BLAKE2 else if (!strcmp(name, "blake2s256")) { digest = EVP_blake2s256(); } else if (!strcmp(name, "blake2b512")) { digest = EVP_blake2b512(); } #endif }
return digest; }
static EVPobject * newEVPobject(void) { Expand Down Expand Up @@ -304,16 +441,7 @@ EVP_get_digest_size(EVPobject *self, void *closure) static PyObject * EVP_get_name(EVPobject *self, void *closure) { const char *name = EVP_MD_name(EVP_MD_CTX_md(self->ctx)); PyObject *name_obj, *name_lower;
name_obj = PyUnicode_FromString(name); if (!name_obj) { return NULL; } name_lower = PyObject_CallMethod(name_obj, "lower", NULL); Py_DECREF(name_obj); return name_lower; return py_digest_name(EVP_MD_CTX_md(self->ctx)); }
static PyGetSetDef EVP_getseters[] = { Expand All @@ -337,7 +465,7 @@ static PyObject * EVP_repr(EVPobject *self) { PyObject *name_obj, *repr; name_obj = EVP_get_name(self, NULL); name_obj = py_digest_name(EVP_MD_CTX_md(self->ctx)); if (!name_obj) { return NULL; } Expand Down Expand Up @@ -403,6 +531,7 @@ static PyTypeObject EVPtype = { 0, /* tp_dictoffset */ };
\ static PyObject * EVPnew(const EVP_MD *digest, const unsigned char *cp, Py_ssize_t len) Expand Down Expand Up @@ -475,7 +604,7 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj) if (data_obj) GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
digest = EVP_get_digestbyname(name); digest = py_digest_by_name(name);
ret_obj = EVPnew(digest, (unsigned char*)view.buf, view.len);
Expand Down Expand Up @@ -889,21 +1018,17 @@ typedef struct _internal_name_mapper_state {
/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */ static void _openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg) _openssl_hash_name_mapper(const EVP_MD *md, const char *from, const char *to, void *arg) { _InternalNameMapperState *state = (_InternalNameMapperState *)arg; PyObject *py_name;
assert(state != NULL); if (openssl_obj_name == NULL) return; /* Ignore aliased names, they pollute the list and OpenSSL appears to * have its own definition of alias as the resulting list still * contains duplicate and alternate names for several algorithms. */ if (openssl_obj_name->alias) if (md == NULL) return;
py_name = PyUnicode_FromString(openssl_obj_name->name); py_name = py_digest_name(md); if (py_name == NULL) { state->error = 1; } else { Expand All @@ -925,7 +1050,7 @@ generate_hash_name_list(void) return NULL; state.error = 0;
OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state); EVP_MD_do_all(&_openssl_hash_name_mapper, &state);
if (state.error) { Py_DECREF(state.set); Expand Down