diff options
Diffstat (limited to 'Modules/_hashopenssl.c')
-rw-r--r-- | Modules/_hashopenssl.c | 1023 |
1 files changed, 585 insertions, 438 deletions
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 48eed5eac97..90a7391ebb0 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -38,6 +38,10 @@ #include <stdbool.h> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +# define Py_HAS_OPENSSL3_SUPPORT +#endif + #ifndef OPENSSL_THREADS # error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL" #endif @@ -55,7 +59,7 @@ #define PY_OPENSSL_HAS_BLAKE2 1 #endif -#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#ifdef Py_HAS_OPENSSL3_SUPPORT #define PY_EVP_MD EVP_MD #define PY_EVP_MD_fetch(algorithm, properties) EVP_MD_fetch(NULL, algorithm, properties) #define PY_EVP_MD_up_ref(md) EVP_MD_up_ref(md) @@ -77,12 +81,12 @@ * py_alias as keys. */ -enum Py_hash_type { - Py_ht_evp, // usedforsecurity=True / default - Py_ht_evp_nosecurity, // usedforsecurity=False - Py_ht_mac, // HMAC - Py_ht_pbkdf2, // PKBDF2 -}; +typedef enum Py_hash_type { + Py_ht_evp, // usedforsecurity=True / default + Py_ht_evp_nosecurity, // usedforsecurity=False + Py_ht_mac, // HMAC + Py_ht_pbkdf2, // PKBDF2 +} Py_hash_type; typedef struct { const char *py_name; @@ -251,14 +255,15 @@ py_hashentry_table_new(void) { return NULL; } -/* Module state */ +// --- Module state ----------------------------------------------------------- + static PyModuleDef _hashlibmodule; typedef struct { - PyTypeObject *EVPtype; - PyTypeObject *HMACtype; + PyTypeObject *HASH_type; // based on EVP_MD + PyTypeObject *HMAC_type; #ifdef PY_OPENSSL_HAS_SHAKE - PyTypeObject *EVPXOFtype; + PyTypeObject *HASHXOF_type; // based on EVP_MD #endif PyObject *constructs; PyObject *unsupported_digestmod_error; @@ -273,42 +278,41 @@ get_hashlib_state(PyObject *module) return (_hashlibstate *)state; } +// --- Module objects --------------------------------------------------------- + typedef struct { - PyObject_HEAD - EVP_MD_CTX *ctx; /* OpenSSL message digest context */ - // Prevents undefined behavior via multiple threads entering the C API. - bool use_mutex; - PyMutex mutex; /* OpenSSL context lock */ -} EVPobject; + HASHLIB_OBJECT_HEAD + EVP_MD_CTX *ctx; /* OpenSSL message digest context */ +} HASHobject; -#define EVPobject_CAST(op) ((EVPobject *)(op)) +#define HASHobject_CAST(op) ((HASHobject *)(op)) typedef struct { - PyObject_HEAD + HASHLIB_OBJECT_HEAD HMAC_CTX *ctx; /* OpenSSL hmac context */ - // Prevents undefined behavior via multiple threads entering the C API. - bool use_mutex; - PyMutex mutex; /* HMAC context lock */ } HMACobject; #define HMACobject_CAST(op) ((HMACobject *)(op)) -#include "clinic/_hashopenssl.c.h" +// --- Module clinic configuration -------------------------------------------- + /*[clinic input] module _hashlib -class _hashlib.HASH "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPtype" -class _hashlib.HASHXOF "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPXOFtype" -class _hashlib.HMAC "HMACobject *" "((_hashlibstate *)PyModule_GetState(module))->HMACtype" +class _hashlib.HASH "HASHobject *" "&PyType_Type" +class _hashlib.HASHXOF "HASHobject *" "&PyType_Type" +class _hashlib.HMAC "HMACobject *" "&PyType_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7df1bcf6f75cb8ef]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6b5c9ce5c28bdc58]*/ +#include "clinic/_hashopenssl.c.h" /* LCOV_EXCL_START */ /* Set an exception of given type using the given OpenSSL error code. */ static void -set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode) +set_ssl_exception_from_errcode(PyObject *exc_type, unsigned long errcode) { + assert(exc_type != NULL); assert(errcode != 0); /* ERR_ERROR_STRING(3) ensures that the messages below are ASCII */ @@ -317,13 +321,29 @@ set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode) const char *reason = ERR_reason_error_string(errcode); if (lib && func) { - PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); + PyErr_Format(exc_type, "[%s: %s] %s", lib, func, reason); } else if (lib) { - PyErr_Format(exc, "[%s] %s", lib, reason); + PyErr_Format(exc_type, "[%s] %s", lib, reason); } else { - PyErr_SetString(exc, reason); + PyErr_SetString(exc_type, reason); + } +} + +/* + * Get an appropriate exception type for the given OpenSSL error code. + * + * The exception type depends on the error code reason. + */ +static PyObject * +get_smart_ssl_exception_type(unsigned long errcode, PyObject *default_exc_type) +{ + switch (ERR_GET_REASON(errcode)) { + case ERR_R_MALLOC_FAILURE: + return PyExc_MemoryError; + default: + return default_exc_type; } } @@ -331,73 +351,171 @@ set_ssl_exception_from_errcode(PyObject *exc, unsigned long errcode) * 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. + * error that occurred. If no error occurred, the 'fallback_message' is used + * to create an exception message. */ static void -raise_ssl_error(PyObject *exc, const char *fallback_format, ...) +raise_ssl_error(PyObject *exc_type, const char *fallback_message) +{ + assert(fallback_message != NULL); + unsigned long errcode = ERR_peek_last_error(); + if (errcode) { + ERR_clear_error(); + set_ssl_exception_from_errcode(exc_type, errcode); + } + else { + PyErr_SetString(exc_type, fallback_message); + } +} + +/* Same as raise_ssl_error() but with a C-style formatted message. */ +static void +raise_ssl_error_f(PyObject *exc_type, 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); + set_ssl_exception_from_errcode(exc_type, errcode); } else { va_list vargs; va_start(vargs, fallback_format); - PyErr_FormatV(exc, fallback_format, vargs); + PyErr_FormatV(exc_type, fallback_format, vargs); + va_end(vargs); + } +} + +/* Same as raise_ssl_error_f() with smart exception types. */ +static void +raise_smart_ssl_error_f(PyObject *exc_type, const char *fallback_format, ...) +{ + unsigned long errcode = ERR_peek_last_error(); + if (errcode) { + ERR_clear_error(); + exc_type = get_smart_ssl_exception_type(errcode, exc_type); + set_ssl_exception_from_errcode(exc_type, errcode); + } + else { + va_list vargs; + va_start(vargs, fallback_format); + PyErr_FormatV(exc_type, 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. + * Raise a ValueError with a default message after an error occurred. + * It can also be used without previous calls to SSL built-in functions. */ static inline void -notify_ssl_error_occurred(void) +notify_ssl_error_occurred(const char *message) { - raise_ssl_error(PyExc_ValueError, "no reason supplied"); + raise_ssl_error(PyExc_ValueError, message); } -/* LCOV_EXCL_STOP */ -static PyObject* -py_digest_name(const EVP_MD *md) +/* Same as notify_ssl_error_occurred() for failed OpenSSL functions. */ +static inline void +notify_ssl_error_occurred_in(const char *funcname) { - assert(md != NULL); - int nid = EVP_MD_nid(md); - const char *name = NULL; - const py_hashentry_t *h; + raise_ssl_error_f(PyExc_ValueError, + "error in OpenSSL function %s()", funcname); +} + +/* Same as notify_ssl_error_occurred_in() with smart exception types. */ +static inline void +notify_smart_ssl_error_occurred_in(const char *funcname) +{ + raise_smart_ssl_error_f(PyExc_ValueError, + "error in OpenSSL function %s()", funcname); +} +/* LCOV_EXCL_STOP */ + +/* + * OpenSSL provides a way to go from NIDs to digest names for hash functions + * but lacks this granularity for MAC objects where it is not possible to get + * the underlying digest name (only the block size and digest size are allowed + * to be recovered). + * + * In addition, OpenSSL aliases pollute the list of known digest names + * as OpenSSL appears to have its own definition of alias. In particular, + * the resulting list still contains duplicate and alternate names for several + * algorithms. + * + * Therefore, digest names, whether they are used by hash functions or HMAC, + * are handled through EVP_MD objects or directly by using some NID. + */ - for (h = py_hashes; h->py_name != NULL; h++) { +/* Get a cached entry by OpenSSL NID. */ +static const py_hashentry_t * +get_hashentry_by_nid(int nid) +{ + for (const py_hashentry_t *h = py_hashes; h->py_name != NULL; h++) { if (h->ossl_nid == nid) { - name = h->py_name; - break; + return h; } } + return NULL; +} + +/* + * Convert the NID to a string via OBJ_nid2*() functions. + * + * If 'nid' cannot be resolved, set an exception and return NULL. + */ +static const char * +get_asn1_utf8name_by_nid(int nid) +{ + const char *name = OBJ_nid2ln(nid); if (name == NULL) { - /* 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); + // In OpenSSL 3.0 and later, OBJ_nid*() are thread-safe and may raise. + assert(ERR_peek_last_error() != 0); + if (ERR_GET_REASON(ERR_peek_last_error()) != OBJ_R_UNKNOWN_NID) { + goto error; + } + // fallback to short name and unconditionally propagate errors + name = OBJ_nid2sn(nid); + if (name == NULL) { + goto error; + } } + return name; - return PyUnicode_FromString(name); +error: + raise_ssl_error_f(PyExc_ValueError, "cannot resolve NID %d", nid); + return NULL; } -/* Get EVP_MD by HID and purpose */ -static PY_EVP_MD* -py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) +/* + * Convert the NID to an OpenSSL digest name. + * + * On error, set an exception and return NULL. + */ +static const char * +get_hashlib_utf8name_by_nid(int nid) { - PY_EVP_MD *digest = NULL; - PY_EVP_MD *other_digest = NULL; + const py_hashentry_t *e = get_hashentry_by_nid(nid); + return e ? e->py_name : get_asn1_utf8name_by_nid(nid); +} + +/* Same as get_hashlib_utf8name_by_nid() but using an EVP_MD object. */ +static const char * +get_hashlib_utf8name_by_evp_md(const EVP_MD *md) +{ + assert(md != NULL); + return get_hashlib_utf8name_by_nid(EVP_MD_nid(md)); +} + +/* + * Get a new reference to an EVP_MD object described by name and purpose. + * + * If 'name' is an OpenSSL indexed name, the return value is cached. + */ +static PY_EVP_MD * +get_openssl_evp_md_by_utf8name(PyObject *module, const char *name, + Py_hash_type py_ht) +{ + PY_EVP_MD *digest = NULL, *other_digest = NULL; _hashlibstate *state = get_hashlib_state(module); py_hashentry_t *entry = (py_hashentry_t *)_Py_hashtable_get( state->hashtable, (const void*)name @@ -431,15 +549,16 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) #endif } break; + default: + goto invalid_hash_type; } // if another thread same thing at same time make sure we got same ptr assert(other_digest == NULL || other_digest == digest); - if (digest != NULL) { - if (other_digest == NULL) { - PY_EVP_MD_up_ref(digest); - } + if (digest != NULL && other_digest == NULL) { + PY_EVP_MD_up_ref(digest); } - } else { + } + else { // Fall back for looking up an unindexed OpenSSL specific name. switch (py_ht) { case Py_ht_evp: @@ -450,66 +569,94 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) case Py_ht_evp_nosecurity: digest = PY_EVP_MD_fetch(name, "-fips"); break; + default: + goto invalid_hash_type; } } if (digest == NULL) { - raise_ssl_error(state->unsupported_digestmod_error, - "unsupported hash type %s", name); + raise_ssl_error_f(state->unsupported_digestmod_error, + "unsupported digest name: %s", name); return NULL; } return digest; + +invalid_hash_type: + assert(digest == NULL); + PyErr_Format(PyExc_SystemError, "unsupported hash type %d", py_ht); + return NULL; } -/* Get digest EVP from object +/* + * Raise an exception indicating that 'digestmod' is not supported. + */ +static void +raise_unsupported_digestmod_error(PyObject *module, PyObject *digestmod) +{ + _hashlibstate *state = get_hashlib_state(module); + PyErr_Format(state->unsupported_digestmod_error, + "Unsupported digestmod %R", digestmod); +} + +/* + * Get a new reference to an EVP_MD described by 'digestmod' and purpose. + * + * On error, set an exception and return NULL. * - * * string - * * _hashopenssl builtin function + * Parameters * - * on error returns NULL with exception set. + * digestmod A digest name or a _hashopenssl builtin function + * py_ht The message digest purpose. */ -static PY_EVP_MD* -py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type py_ht) { - PyObject *name_obj = NULL; +static PY_EVP_MD * +get_openssl_evp_md(PyObject *module, PyObject *digestmod, Py_hash_type py_ht) +{ const char *name; - if (PyUnicode_Check(digestmod)) { - name_obj = digestmod; - } else { - _hashlibstate *state = get_hashlib_state(module); - // borrowed ref - name_obj = PyDict_GetItemWithError(state->constructs, digestmod); + name = PyUnicode_AsUTF8(digestmod); + } + else { + PyObject *dict = get_hashlib_state(module)->constructs; + assert(dict != NULL); + PyObject *borrowed_ref = PyDict_GetItemWithError(dict, digestmod); + name = borrowed_ref == NULL ? NULL : PyUnicode_AsUTF8(borrowed_ref); } - if (name_obj == NULL) { + if (name == NULL) { if (!PyErr_Occurred()) { - _hashlibstate *state = get_hashlib_state(module); - PyErr_Format( - state->unsupported_digestmod_error, - "Unsupported digestmod %R", digestmod); + raise_unsupported_digestmod_error(module, digestmod); } return NULL; } + return get_openssl_evp_md_by_utf8name(module, name, py_ht); +} - name = PyUnicode_AsUTF8(name_obj); - if (name == NULL) { +// --- OpenSSL HASH wrappers -------------------------------------------------- + +/* Thin wrapper around EVP_MD_CTX_new() which sets an exception on failure. */ +static EVP_MD_CTX * +py_wrapper_EVP_MD_CTX_new(void) +{ + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (ctx == NULL) { + PyErr_NoMemory(); return NULL; } - - return py_digest_by_name(module, name, py_ht); + return ctx; } -static EVPobject * -newEVPobject(PyTypeObject *type) +// --- HASH interface --------------------------------------------------------- + +static HASHobject * +new_hash_object(PyTypeObject *type) { - EVPobject *retval = PyObject_New(EVPobject, type); + HASHobject *retval = PyObject_New(HASHobject, type); if (retval == NULL) { return NULL; } HASHLIB_INIT_MUTEX(retval); - retval->ctx = EVP_MD_CTX_new(); + retval->ctx = py_wrapper_EVP_MD_CTX_new(); if (retval->ctx == NULL) { Py_DECREF(retval); - PyErr_NoMemory(); return NULL; } @@ -517,7 +664,7 @@ newEVPobject(PyTypeObject *type) } static int -EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len) +_hashlib_HASH_hash(HASHobject *self, const void *vp, Py_ssize_t len) { unsigned int process; const unsigned char *cp = (const unsigned char *)vp; @@ -527,7 +674,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)) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestUpdate)); return -1; } len -= process; @@ -539,9 +686,9 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len) /* Internal methods for a hash object */ static void -EVP_dealloc(PyObject *op) +_hashlib_HASH_dealloc(PyObject *op) { - EVPobject *self = EVPobject_CAST(op); + HASHobject *self = HASHobject_CAST(op); PyTypeObject *tp = Py_TYPE(self); EVP_MD_CTX_free(self->ctx); PyObject_Free(self); @@ -549,120 +696,98 @@ EVP_dealloc(PyObject *op) } static int -locked_EVP_MD_CTX_copy(EVP_MD_CTX *new_ctx_p, EVPobject *self) +_hashlib_HASH_copy_locked(HASHobject *self, EVP_MD_CTX *new_ctx_p) { int result; - ENTER_HASHLIB(self); + HASHLIB_ACQUIRE_LOCK(self); result = EVP_MD_CTX_copy(new_ctx_p, self->ctx); - LEAVE_HASHLIB(self); - return result; + HASHLIB_RELEASE_LOCK(self); + if (result == 0) { + notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MD_CTX_copy)); + return -1; + } + return 0; } /* External methods for a hash object */ /*[clinic input] -_hashlib.HASH.copy as EVP_copy +_hashlib.HASH.copy Return a copy of the hash object. [clinic start generated code]*/ static PyObject * -EVP_copy_impl(EVPobject *self) -/*[clinic end generated code: output=b370c21cdb8ca0b4 input=31455b6a3e638069]*/ +_hashlib_HASH_copy_impl(HASHobject *self) +/*[clinic end generated code: output=2545541af18d53d7 input=814b19202cd08a26]*/ { - EVPobject *newobj; + HASHobject *newobj; - if ((newobj = newEVPobject(Py_TYPE(self))) == NULL) + if ((newobj = new_hash_object(Py_TYPE(self))) == NULL) return NULL; - if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) { + if (_hashlib_HASH_copy_locked(self, newobj->ctx) < 0) { Py_DECREF(newobj); - notify_ssl_error_occurred(); return NULL; } return (PyObject *)newobj; } -/*[clinic input] -_hashlib.HASH.digest as EVP_digest - -Return the digest value as a bytes object. -[clinic start generated code]*/ - -static PyObject * -EVP_digest_impl(EVPobject *self) -/*[clinic end generated code: output=0f6a3a0da46dc12d input=03561809a419bf00]*/ +static Py_ssize_t +_hashlib_HASH_digest_compute(HASHobject *self, unsigned char *digest) { - unsigned char digest[EVP_MAX_MD_SIZE]; - EVP_MD_CTX *temp_ctx; - PyObject *retval; - unsigned int digest_size; - - temp_ctx = EVP_MD_CTX_new(); - if (temp_ctx == NULL) { - PyErr_NoMemory(); - return NULL; + EVP_MD_CTX *ctx = py_wrapper_EVP_MD_CTX_new(); + if (ctx == NULL) { + return -1; } - - if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) { + if (_hashlib_HASH_copy_locked(self, ctx) < 0) { goto error; } - digest_size = EVP_MD_CTX_size(temp_ctx); - if (!EVP_DigestFinal(temp_ctx, digest, NULL)) { + Py_ssize_t digest_size = EVP_MD_CTX_size(ctx); + if (!EVP_DigestFinal(ctx, digest, NULL)) { + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinal)); goto error; } - - retval = PyBytes_FromStringAndSize((const char *)digest, digest_size); - EVP_MD_CTX_free(temp_ctx); - return retval; + EVP_MD_CTX_free(ctx); + return digest_size; error: - EVP_MD_CTX_free(temp_ctx); - notify_ssl_error_occurred(); - return NULL; + EVP_MD_CTX_free(ctx); + return -1; } /*[clinic input] -_hashlib.HASH.hexdigest as EVP_hexdigest +_hashlib.HASH.digest -Return the digest value as a string of hexadecimal digits. +Return the digest value as a bytes object. [clinic start generated code]*/ static PyObject * -EVP_hexdigest_impl(EVPobject *self) -/*[clinic end generated code: output=18e6decbaf197296 input=aff9cf0e4c741a9a]*/ +_hashlib_HASH_digest_impl(HASHobject *self) +/*[clinic end generated code: output=3fc6f9671d712850 input=d8d528d6e50af0de]*/ { unsigned char digest[EVP_MAX_MD_SIZE]; - EVP_MD_CTX *temp_ctx; - unsigned int digest_size; - - temp_ctx = EVP_MD_CTX_new(); - if (temp_ctx == NULL) { - PyErr_NoMemory(); - return NULL; - } - - /* Get the raw (binary) digest value */ - if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) { - goto error; - } - digest_size = EVP_MD_CTX_size(temp_ctx); - if (!EVP_DigestFinal(temp_ctx, digest, NULL)) { - goto error; - } + Py_ssize_t n = _hashlib_HASH_digest_compute(self, digest); + return n < 0 ? NULL : PyBytes_FromStringAndSize((const char *)digest, n); +} - EVP_MD_CTX_free(temp_ctx); +/*[clinic input] +_hashlib.HASH.hexdigest - return _Py_strhex((const char *)digest, (Py_ssize_t)digest_size); +Return the digest value as a string of hexadecimal digits. +[clinic start generated code]*/ -error: - EVP_MD_CTX_free(temp_ctx); - notify_ssl_error_occurred(); - return NULL; +static PyObject * +_hashlib_HASH_hexdigest_impl(HASHobject *self) +/*[clinic end generated code: output=1b8e60d9711e7f4d input=ae7553f78f8372d8]*/ +{ + unsigned char digest[EVP_MAX_MD_SIZE]; + Py_ssize_t n = _hashlib_HASH_digest_compute(self, digest); + return n < 0 ? NULL : _Py_strhex((const char *)digest, n); } /*[clinic input] -_hashlib.HASH.update as EVP_update +_hashlib.HASH.update obj: object / @@ -671,82 +796,70 @@ Update this hash object's state with the provided string. [clinic start generated code]*/ static PyObject * -EVP_update_impl(EVPobject *self, PyObject *obj) -/*[clinic end generated code: output=d56f91c68348f95f input=9b30ec848f015501]*/ +_hashlib_HASH_update_impl(HASHobject *self, PyObject *obj) +/*[clinic end generated code: output=62ad989754946b86 input=aa1ce20e3f92ceb6]*/ { int result; Py_buffer view; - GET_BUFFER_VIEW_OR_ERROUT(obj, &view); - - if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) { - self->use_mutex = true; - } - if (self->use_mutex) { - Py_BEGIN_ALLOW_THREADS - PyMutex_Lock(&self->mutex); - result = EVP_hash(self, view.buf, view.len); - PyMutex_Unlock(&self->mutex); - Py_END_ALLOW_THREADS - } else { - result = EVP_hash(self, view.buf, view.len); - } - + HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED( + self, view.len, + result = _hashlib_HASH_hash(self, view.buf, view.len) + ); PyBuffer_Release(&view); - - if (result == -1) - return NULL; - Py_RETURN_NONE; + return result < 0 ? NULL : Py_None; } -static PyMethodDef EVP_methods[] = { - EVP_UPDATE_METHODDEF - EVP_DIGEST_METHODDEF - EVP_HEXDIGEST_METHODDEF - EVP_COPY_METHODDEF +static PyMethodDef HASH_methods[] = { + _HASHLIB_HASH_COPY_METHODDEF + _HASHLIB_HASH_DIGEST_METHODDEF + _HASHLIB_HASH_HEXDIGEST_METHODDEF + _HASHLIB_HASH_UPDATE_METHODDEF {NULL, NULL} /* sentinel */ }; static PyObject * -EVP_get_block_size(PyObject *op, void *Py_UNUSED(closure)) +_hashlib_HASH_get_blocksize(PyObject *op, void *Py_UNUSED(closure)) { - EVPobject *self = EVPobject_CAST(op); + HASHobject *self = HASHobject_CAST(op); long block_size = EVP_MD_CTX_block_size(self->ctx); return PyLong_FromLong(block_size); } static PyObject * -EVP_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) +_hashlib_HASH_get_digestsize(PyObject *op, void *Py_UNUSED(closure)) { - EVPobject *self = EVPobject_CAST(op); + HASHobject *self = HASHobject_CAST(op); long size = EVP_MD_CTX_size(self->ctx); return PyLong_FromLong(size); } static PyObject * -EVP_get_name(PyObject *op, void *Py_UNUSED(closure)) +_hashlib_HASH_get_name(PyObject *op, void *Py_UNUSED(closure)) { - EVPobject *self = EVPobject_CAST(op); + HASHobject *self = HASHobject_CAST(op); const EVP_MD *md = EVP_MD_CTX_md(self->ctx); if (md == NULL) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred("missing EVP_MD for HASH context"); return NULL; } - return py_digest_name(md); + const char *name = get_hashlib_utf8name_by_evp_md(md); + assert(name != NULL || PyErr_Occurred()); + return name == NULL ? NULL : PyUnicode_FromString(name); } -static PyGetSetDef EVP_getseters[] = { - {"digest_size", EVP_get_digest_size, NULL, NULL, NULL}, - {"block_size", EVP_get_block_size, NULL, NULL, NULL}, - {"name", EVP_get_name, NULL, NULL, PyDoc_STR("algorithm name.")}, +static PyGetSetDef HASH_getsets[] = { + {"digest_size", _hashlib_HASH_get_digestsize, NULL, NULL, NULL}, + {"block_size", _hashlib_HASH_get_blocksize, NULL, NULL, NULL}, + {"name", _hashlib_HASH_get_name, NULL, NULL, PyDoc_STR("algorithm name.")}, {NULL} /* Sentinel */ }; static PyObject * -EVP_repr(PyObject *self) +_hashlib_HASH_repr(PyObject *self) { - PyObject *name = EVP_get_name(self, NULL); + PyObject *name = _hashlib_HASH_get_name(self, NULL); if (name == NULL) { return NULL; } @@ -756,7 +869,7 @@ EVP_repr(PyObject *self) return repr; } -PyDoc_STRVAR(hashtype_doc, +PyDoc_STRVAR(HASHobject_type_doc, "HASH(name, string=b\'\')\n" "--\n" "\n" @@ -774,27 +887,31 @@ PyDoc_STRVAR(hashtype_doc, "name -- the hash algorithm being used by this object\n" "digest_size -- number of bytes in this hashes output"); -static PyType_Slot EVPtype_slots[] = { - {Py_tp_dealloc, EVP_dealloc}, - {Py_tp_repr, EVP_repr}, - {Py_tp_doc, (char *)hashtype_doc}, - {Py_tp_methods, EVP_methods}, - {Py_tp_getset, EVP_getseters}, +static PyType_Slot HASHobject_type_slots[] = { + {Py_tp_dealloc, _hashlib_HASH_dealloc}, + {Py_tp_repr, _hashlib_HASH_repr}, + {Py_tp_doc, (char *)HASHobject_type_doc}, + {Py_tp_methods, HASH_methods}, + {Py_tp_getset, HASH_getsets}, {0, 0}, }; -static PyType_Spec EVPtype_spec = { - "_hashlib.HASH", /*tp_name*/ - sizeof(EVPobject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, - EVPtype_slots +static PyType_Spec HASHobject_type_spec = { + .name = "_hashlib.HASH", + .basicsize = sizeof(HASHobject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = HASHobject_type_slots }; #ifdef PY_OPENSSL_HAS_SHAKE /*[clinic input] -_hashlib.HASHXOF.digest as EVPXOF_digest +_hashlib.HASHXOF.digest length: Py_ssize_t @@ -802,30 +919,40 @@ Return the digest value as a bytes object. [clinic start generated code]*/ static PyObject * -EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length) -/*[clinic end generated code: output=ef9320c23280efad input=816a6537cea3d1db]*/ +_hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length) +/*[clinic end generated code: output=dcb09335dd2fe908 input=3eb034ce03c55b21]*/ { EVP_MD_CTX *temp_ctx; - PyObject *retval = PyBytes_FromStringAndSize(NULL, length); + PyObject *retval; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, "negative digest length"); + return NULL; + } + + if (length == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + } + + retval = PyBytes_FromStringAndSize(NULL, length); if (retval == NULL) { return NULL; } - temp_ctx = EVP_MD_CTX_new(); + temp_ctx = py_wrapper_EVP_MD_CTX_new(); if (temp_ctx == NULL) { Py_DECREF(retval); - PyErr_NoMemory(); return NULL; } - if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) { + if (_hashlib_HASH_copy_locked(self, temp_ctx) < 0) { goto error; } if (!EVP_DigestFinalXOF(temp_ctx, (unsigned char*)PyBytes_AS_STRING(retval), length)) { + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinalXOF)); goto error; } @@ -835,12 +962,11 @@ EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length) error: Py_DECREF(retval); EVP_MD_CTX_free(temp_ctx); - notify_ssl_error_occurred(); return NULL; } /*[clinic input] -_hashlib.HASHXOF.hexdigest as EVPXOF_hexdigest +_hashlib.HASHXOF.hexdigest length: Py_ssize_t @@ -848,31 +974,40 @@ Return the digest value as a string of hexadecimal digits. [clinic start generated code]*/ static PyObject * -EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length) -/*[clinic end generated code: output=eb3e6ee7788bf5b2 input=5f9d6a8f269e34df]*/ +_hashlib_HASHXOF_hexdigest_impl(HASHobject *self, Py_ssize_t length) +/*[clinic end generated code: output=519431cafa014f39 input=0e58f7238adb7ab8]*/ { unsigned char *digest; EVP_MD_CTX *temp_ctx; PyObject *retval; + if (length < 0) { + PyErr_SetString(PyExc_ValueError, "negative digest length"); + return NULL; + } + + if (length == 0) { + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); + } + digest = (unsigned char*)PyMem_Malloc(length); if (digest == NULL) { - PyErr_NoMemory(); + (void)PyErr_NoMemory(); return NULL; } - temp_ctx = EVP_MD_CTX_new(); + temp_ctx = py_wrapper_EVP_MD_CTX_new(); if (temp_ctx == NULL) { PyMem_Free(digest); - PyErr_NoMemory(); return NULL; } /* Get the raw (binary) digest value */ - if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) { + if (_hashlib_HASH_copy_locked(self, temp_ctx) < 0) { goto error; } if (!EVP_DigestFinalXOF(temp_ctx, digest, length)) { + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestFinalXOF)); goto error; } @@ -885,29 +1020,29 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length) error: PyMem_Free(digest); EVP_MD_CTX_free(temp_ctx); - notify_ssl_error_occurred(); return NULL; } -static PyMethodDef EVPXOF_methods[] = { - EVPXOF_DIGEST_METHODDEF - EVPXOF_HEXDIGEST_METHODDEF +static PyMethodDef HASHXOFobject_methods[] = { + _HASHLIB_HASHXOF_DIGEST_METHODDEF + _HASHLIB_HASHXOF_HEXDIGEST_METHODDEF {NULL, NULL} /* sentinel */ }; static PyObject * -EVPXOF_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) +_hashlib_HASHXOF_digest_size(PyObject *Py_UNUSED(self), + void *Py_UNUSED(closure)) { return PyLong_FromLong(0); } -static PyGetSetDef EVPXOF_getseters[] = { - {"digest_size", EVPXOF_get_digest_size, NULL, NULL, NULL}, +static PyGetSetDef HASHXOFobject_getsets[] = { + {"digest_size", _hashlib_HASHXOF_digest_size, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; -PyDoc_STRVAR(hashxoftype_doc, +PyDoc_STRVAR(HASHXOFobject_type_doc, "HASHXOF(name, string=b\'\')\n" "--\n" "\n" @@ -925,38 +1060,42 @@ PyDoc_STRVAR(hashxoftype_doc, "name -- the hash algorithm being used by this object\n" "digest_size -- number of bytes in this hashes output"); -static PyType_Slot EVPXOFtype_slots[] = { - {Py_tp_doc, (char *)hashxoftype_doc}, - {Py_tp_methods, EVPXOF_methods}, - {Py_tp_getset, EVPXOF_getseters}, +static PyType_Slot HASHXOFobject_type_slots[] = { + {Py_tp_doc, (char *)HASHXOFobject_type_doc}, + {Py_tp_methods, HASHXOFobject_methods}, + {Py_tp_getset, HASHXOFobject_getsets}, {0, 0}, }; -static PyType_Spec EVPXOFtype_spec = { - "_hashlib.HASHXOF", /*tp_name*/ - sizeof(EVPobject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, - EVPXOFtype_slots +static PyType_Spec HASHXOFobject_type_spec = { + .name = "_hashlib.HASHXOF", + .basicsize = sizeof(HASHobject), + .flags = ( + Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + ), + .slots = HASHXOFobject_type_slots }; #endif -static PyObject* -py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj, - int usedforsecurity) +static PyObject * +_hashlib_HASH(PyObject *module, const char *digestname, PyObject *data_obj, + int usedforsecurity) { Py_buffer view = { 0 }; PY_EVP_MD *digest = NULL; PyTypeObject *type; - EVPobject *self = NULL; + HASHobject *self = NULL; if (data_obj != NULL) { GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); } - digest = py_digest_by_name( + digest = get_openssl_evp_md_by_utf8name( module, digestname, usedforsecurity ? Py_ht_evp : Py_ht_evp_nosecurity ); if (digest == NULL) { @@ -964,12 +1103,12 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj, } if ((EVP_MD_flags(digest) & EVP_MD_FLAG_XOF) == EVP_MD_FLAG_XOF) { - type = get_hashlib_state(module)->EVPXOFtype; + type = get_hashlib_state(module)->HASHXOF_type; } else { - type = get_hashlib_state(module)->EVPtype; + type = get_hashlib_state(module)->HASH_type; } - self = newEVPobject(type); + self = new_hash_object(type); if (self == NULL) { goto exit; } @@ -984,21 +1123,18 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj, int result = EVP_DigestInit_ex(self->ctx, digest, NULL); if (!result) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_DigestInit_ex)); Py_CLEAR(self); goto exit; } if (view.buf && view.len) { - if (view.len >= HASHLIB_GIL_MINSIZE) { - /* We do not initialize self->lock here as this is the constructor - * where it is not yet possible to have concurrent access. */ - Py_BEGIN_ALLOW_THREADS - result = EVP_hash(self, view.buf, view.len); - Py_END_ALLOW_THREADS - } else { - result = EVP_hash(self, view.buf, view.len); - } + /* Do not use self->mutex here as this is the constructor + * where it is not yet possible to have concurrent access. */ + HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED( + view.len, + result = _hashlib_HASH_hash(self, view.buf, view.len) + ); if (result == -1) { assert(PyErr_Occurred()); Py_CLEAR(self); @@ -1017,16 +1153,25 @@ exit: return (PyObject *)self; } +#define CALL_HASHLIB_NEW(MODULE, NAME, DATA, STRING, USEDFORSECURITY) \ + do { \ + PyObject *data_obj; \ + if (_Py_hashlib_data_argument(&data_obj, DATA, STRING) < 0) { \ + return NULL; \ + } \ + return _hashlib_HASH(MODULE, NAME, data_obj, USEDFORSECURITY); \ + } while (0) /* The module-level function: new() */ /*[clinic input] -_hashlib.new as EVP_new +_hashlib.new as _hashlib_HASH_new - name as name_obj: object - string as data_obj: object(c_default="NULL") = b'' + name: str + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Return a new hash object using the named algorithm. @@ -1037,136 +1182,137 @@ The MD5 and SHA1 algorithms are always supported. [clinic start generated code]*/ static PyObject * -EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=ddd5053f92dffe90 input=c24554d0337be1b0]*/ +_hashlib_HASH_new_impl(PyObject *module, const char *name, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=b905aaf9840c1bbd input=c34af6c6e696d44e]*/ { - char *name; - if (!PyArg_Parse(name_obj, "s", &name)) { - PyErr_SetString(PyExc_TypeError, "name must be a string"); - return NULL; - } - return py_evp_fromname(module, name, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, name, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_md5 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a md5 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_md5_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=87b0186440a44f8c input=990e36d5e689b16e]*/ +_hashlib_openssl_md5_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=ca8cf184d90f7432 input=e7c0adbd6a867db1]*/ { - return py_evp_fromname(module, Py_hash_md5, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_md5, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha1 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha1 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=6813024cf690670d input=948f2f4b6deabc10]*/ +_hashlib_openssl_sha1_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=1736fb7b310d64be input=f7e5bb1711e952d8]*/ { - return py_evp_fromname(module, Py_hash_sha1, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha1, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha224 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha224 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=a2dfe7cc4eb14ebb input=f9272821fadca505]*/ +_hashlib_openssl_sha224_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=0d6ff57be5e5c140 input=3820fff7ed3a53b8]*/ { - return py_evp_fromname(module, Py_hash_sha224, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha224, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha256 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha256 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=1f874a34870f0a68 input=549fad9d2930d4c5]*/ +_hashlib_openssl_sha256_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=412ea7111555b6e7 input=9a2f115cf1f7e0eb]*/ { - return py_evp_fromname(module, Py_hash_sha256, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha256, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha384 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha384 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=58529eff9ca457b2 input=48601a6e3bf14ad7]*/ +_hashlib_openssl_sha384_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=2e0dc395b59ed726 input=1ea48f6f01e77cfb]*/ { - return py_evp_fromname(module, Py_hash_sha384, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha384, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha512 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha512 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=2c744c9e4a40d5f6 input=c5c46a2a817aa98f]*/ +_hashlib_openssl_sha512_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=4bdd760388dbfc0f input=3cf56903e07d1f5c]*/ { - return py_evp_fromname(module, Py_hash_sha512, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha512, data, string, usedforsecurity); } @@ -1175,77 +1321,81 @@ _hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj, /*[clinic input] _hashlib.openssl_sha3_224 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha3-224 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=144641c1d144b974 input=e3a01b2888916157]*/ +_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=6d8dc2a924f3ba35 input=7f14f16a9f6a3158]*/ { - return py_evp_fromname(module, Py_hash_sha3_224, data_obj, usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha3_224, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha3_256 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha3-256 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=c61f1ab772d06668 input=e2908126c1b6deed]*/ +_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=9e520f537b3a4622 input=7987150939d5e352]*/ { - return py_evp_fromname(module, Py_hash_sha3_256, data_obj , usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha3_256, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha3_384 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha3-384 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=f68e4846858cf0ee input=ec0edf5c792f8252]*/ +_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=d239ba0463fd6138 input=fc943401f67e3b81]*/ { - return py_evp_fromname(module, Py_hash_sha3_384, data_obj , usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha3_384, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_sha3_512 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a sha3-512 hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=2eede478c159354a input=64e2cc0c094d56f4]*/ +_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=17662f21038c2278 input=6601ddd2c6c1516d]*/ { - return py_evp_fromname(module, Py_hash_sha3_512, data_obj , usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_sha3_512, data, string, usedforsecurity); } #endif /* PY_OPENSSL_HAS_SHA3 */ @@ -1253,42 +1403,46 @@ _hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj, /*[clinic input] _hashlib.openssl_shake_128 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a shake-128 variable hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=bc49cdd8ada1fa97 input=6c9d67440eb33ec8]*/ +_hashlib_openssl_shake_128_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=4e6afed8d18980ad input=373c3f1c93d87b37]*/ { - return py_evp_fromname(module, Py_hash_shake_128, data_obj , usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_shake_128, data, string, usedforsecurity); } /*[clinic input] _hashlib.openssl_shake_256 - string as data_obj: object(py_default="b''") = NULL + data: object(c_default="NULL") = b'' * usedforsecurity: bool = True + string: object(c_default="NULL") = None Returns a shake-256 variable hash object; optionally initialized with a string [clinic start generated code]*/ static PyObject * -_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data_obj, - int usedforsecurity) -/*[clinic end generated code: output=358d213be8852df7 input=479cbe9fefd4a9f8]*/ +_hashlib_openssl_shake_256_impl(PyObject *module, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=62481bce4a77d16c input=101c139ea2ddfcbf]*/ { - return py_evp_fromname(module, Py_hash_shake_256, data_obj , usedforsecurity); + CALL_HASHLIB_NEW(module, Py_hash_shake_256, data, string, usedforsecurity); } #endif /* PY_OPENSSL_HAS_SHAKE */ +#undef CALL_HASHLIB_NEW + /*[clinic input] _hashlib.pbkdf2_hmac as pbkdf2_hmac @@ -1312,7 +1466,7 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name, long dklen; int retval; - PY_EVP_MD *digest = py_digest_by_name(module, hash_name, Py_ht_pbkdf2); + PY_EVP_MD *digest = get_openssl_evp_md_by_utf8name(module, hash_name, Py_ht_pbkdf2); if (digest == NULL) { goto end; } @@ -1375,7 +1529,7 @@ pbkdf2_hmac_impl(PyObject *module, const char *hash_name, if (!retval) { Py_CLEAR(key_obj); - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(PKCS5_PBKDF2_HMAC)); goto end; } @@ -1451,8 +1605,8 @@ _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) { - raise_ssl_error(PyExc_ValueError, - "Invalid parameter combination for n, r, p, maxmem."); + notify_ssl_error_occurred( + "Invalid parameter combination for n, r, p, maxmem."); return NULL; } @@ -1473,7 +1627,7 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt, if (!retval) { Py_CLEAR(key_obj); - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_PBE_scrypt)); return NULL; } return key_obj; @@ -1514,7 +1668,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, return NULL; } - evp = py_digest_by_digestmod(module, digest, Py_ht_mac); + evp = get_openssl_evp_md(module, digest, Py_ht_mac); if (evp == NULL) { return NULL; } @@ -1530,7 +1684,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, PY_EVP_MD_free(evp); if (result == NULL) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC)); return NULL; } return PyBytes_FromStringAndSize((const char*)md, md_len); @@ -1539,6 +1693,18 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, /* OpenSSL-based HMAC implementation */ +/* Thin wrapper around HMAC_CTX_new() which sets an exception on failure. */ +static HMAC_CTX * +py_openssl_wrapper_HMAC_CTX_new(void) +{ + HMAC_CTX *ctx = HMAC_CTX_new(); + if (ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + return ctx; +} + static int _hmac_update(HMACobject*, PyObject*); static const EVP_MD * @@ -1546,7 +1712,7 @@ _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"); + notify_ssl_error_occurred("missing EVP_MD for HMAC context"); } return md; } @@ -1583,27 +1749,26 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj, return NULL; } - digest = py_digest_by_digestmod(module, digestmod, Py_ht_mac); + digest = get_openssl_evp_md(module, digestmod, Py_ht_mac); if (digest == NULL) { return NULL; } - ctx = HMAC_CTX_new(); + ctx = py_openssl_wrapper_HMAC_CTX_new(); if (ctx == NULL) { PY_EVP_MD_free(digest); - PyErr_NoMemory(); goto error; } r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */); PY_EVP_MD_free(digest); if (r == 0) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Init_ex)); goto error; } _hashlibstate *state = get_hashlib_state(module); - self = PyObject_New(HMACobject, state->HMACtype); + self = PyObject_New(HMACobject, state->HMAC_type); if (self == NULL) { goto error; } @@ -1630,10 +1795,14 @@ static int locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self) { int result; - ENTER_HASHLIB(self); + HASHLIB_ACQUIRE_LOCK(self); result = HMAC_CTX_copy(new_ctx_p, self->ctx); - LEAVE_HASHLIB(self); - return result; + HASHLIB_RELEASE_LOCK(self); + if (result == 0) { + notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy)); + return -1; + } + return 0; } /* returning 0 means that an error occurred and an exception is set */ @@ -1647,7 +1816,7 @@ _hashlib_hmac_digest_size(HMACobject *self) unsigned int digest_size = EVP_MD_size(md); assert(digest_size <= EVP_MAX_MD_SIZE); if (digest_size == 0) { - raise_ssl_error(PyExc_ValueError, "invalid digest size"); + notify_ssl_error_occurred("invalid digest size"); } return digest_size; } @@ -1659,28 +1828,16 @@ _hmac_update(HMACobject *self, PyObject *obj) Py_buffer view = {0}; GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0); - - if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) { - self->use_mutex = true; - } - if (self->use_mutex) { - Py_BEGIN_ALLOW_THREADS - PyMutex_Lock(&self->mutex); - r = HMAC_Update(self->ctx, - (const unsigned char *)view.buf, - (size_t)view.len); - PyMutex_Unlock(&self->mutex); - Py_END_ALLOW_THREADS - } else { - r = HMAC_Update(self->ctx, - (const unsigned char *)view.buf, - (size_t)view.len); - } - + HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED( + self, view.len, + r = HMAC_Update( + self->ctx, (const unsigned char *)view.buf, (size_t)view.len + ) + ); PyBuffer_Release(&view); if (r == 0) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Update)); return 0; } return 1; @@ -1698,13 +1855,12 @@ _hashlib_HMAC_copy_impl(HMACobject *self) { HMACobject *retval; - HMAC_CTX *ctx = HMAC_CTX_new(); + HMAC_CTX *ctx = py_openssl_wrapper_HMAC_CTX_new(); if (ctx == NULL) { - return PyErr_NoMemory(); + return NULL; } - if (!locked_HMAC_CTX_copy(ctx, self)) { + if (locked_HMAC_CTX_copy(ctx, self) < 0) { HMAC_CTX_free(ctx); - notify_ssl_error_occurred(); return NULL; } @@ -1735,20 +1891,15 @@ _hmac_dealloc(PyObject *op) static PyObject * _hmac_repr(PyObject *op) { + const char *digest_name; HMACobject *self = HMACobject_CAST(op); const EVP_MD *md = _hashlib_hmac_get_md(self); - if (md == NULL) { - return NULL; - } - PyObject *digest_name = py_digest_name(md); + digest_name = md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md); if (digest_name == NULL) { + assert(PyErr_Occurred()); return NULL; } - PyObject *repr = PyUnicode_FromFormat( - "<%U HMAC object @ %p>", digest_name, self - ); - Py_DECREF(digest_name); - return repr; + return PyUnicode_FromFormat("<%s HMAC object @ %p>", digest_name, self); } /*[clinic input] @@ -1771,20 +1922,18 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg) static int _hmac_digest(HMACobject *self, unsigned char *buf, unsigned int len) { - HMAC_CTX *temp_ctx = HMAC_CTX_new(); + HMAC_CTX *temp_ctx = py_openssl_wrapper_HMAC_CTX_new(); if (temp_ctx == NULL) { - (void)PyErr_NoMemory(); return 0; } - if (!locked_HMAC_CTX_copy(temp_ctx, self)) { + if (locked_HMAC_CTX_copy(temp_ctx, self) < 0) { HMAC_CTX_free(temp_ctx); - notify_ssl_error_occurred(); return 0; } int r = HMAC_Final(temp_ctx, buf, &len); HMAC_CTX_free(temp_ctx); if (r == 0) { - notify_ssl_error_occurred(); + notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Final)); return 0; } return 1; @@ -1860,13 +2009,12 @@ _hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure)) if (md == NULL) { return NULL; } - PyObject *digest_name = py_digest_name(md); + const char *digest_name = get_hashlib_utf8name_by_evp_md(md); if (digest_name == NULL) { + assert(PyErr_Occurred()); return NULL; } - PyObject *name = PyUnicode_FromFormat("hmac-%U", digest_name); - Py_DECREF(digest_name); - return name; + return PyUnicode_FromFormat("hmac-%s", digest_name); } static PyMethodDef HMAC_methods[] = { @@ -1926,7 +2074,7 @@ 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 +#ifdef Py_HAS_OPENSSL3_SUPPORT _openssl_hash_name_mapper(EVP_MD *md, void *arg) #else _openssl_hash_name_mapper(const EVP_MD *md, const char *from, @@ -1942,7 +2090,9 @@ _openssl_hash_name_mapper(const EVP_MD *md, const char *from, return; } - py_name = py_digest_name(md); + const char *name = get_hashlib_utf8name_by_evp_md(md); + assert(name != NULL || PyErr_Occurred()); + py_name = name == NULL ? NULL : PyUnicode_FromString(name); if (py_name == NULL) { state->error = 1; } else { @@ -1966,7 +2116,7 @@ hashlib_md_meth_names(PyObject *module) return -1; } -#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#ifdef Py_HAS_OPENSSL3_SUPPORT // get algorithms from all activated providers in default context EVP_MD_do_all_provided(NULL, &_openssl_hash_name_mapper, &state); #else @@ -1999,21 +2149,18 @@ _hashlib_get_fips_mode_impl(PyObject *module) /*[clinic end generated code: output=87eece1bab4d3fa9 input=2db61538c41c6fef]*/ { -#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#ifdef Py_HAS_OPENSSL3_SUPPORT return EVP_default_properties_is_fips_enabled(NULL); #else ERR_clear_error(); int result = FIPS_mode(); - if (result == 0) { + if (result == 0 && ERR_peek_last_error()) { // "If the library was built without support of the FIPS Object Module, // then the function will return 0 with an error code of // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." // But 0 is also a valid result value. - unsigned long errcode = ERR_peek_last_error(); - if (errcode) { - notify_ssl_error_occurred(); - return -1; - } + notify_ssl_error_occurred_in(Py_STRINGIFY(FIPS_mode)); + return -1; } return result; #endif @@ -2134,7 +2281,7 @@ _hashlib_compare_digest_impl(PyObject *module, PyObject *a, PyObject *b) /* List of functions exported by this module */ static struct PyMethodDef EVP_functions[] = { - EVP_NEW_METHODDEF + _HASHLIB_HASH_NEW_METHODDEF PBKDF2_HMAC_METHODDEF _HASHLIB_SCRYPT_METHODDEF _HASHLIB_GET_FIPS_MODE_METHODDEF @@ -2163,10 +2310,10 @@ static int hashlib_traverse(PyObject *m, visitproc visit, void *arg) { _hashlibstate *state = get_hashlib_state(m); - Py_VISIT(state->EVPtype); - Py_VISIT(state->HMACtype); + Py_VISIT(state->HASH_type); + Py_VISIT(state->HMAC_type); #ifdef PY_OPENSSL_HAS_SHAKE - Py_VISIT(state->EVPXOFtype); + Py_VISIT(state->HASHXOF_type); #endif Py_VISIT(state->constructs); Py_VISIT(state->unsupported_digestmod_error); @@ -2177,10 +2324,10 @@ static int hashlib_clear(PyObject *m) { _hashlibstate *state = get_hashlib_state(m); - Py_CLEAR(state->EVPtype); - Py_CLEAR(state->HMACtype); + Py_CLEAR(state->HASH_type); + Py_CLEAR(state->HMAC_type); #ifdef PY_OPENSSL_HAS_SHAKE - Py_CLEAR(state->EVPXOFtype); + Py_CLEAR(state->HASHXOF_type); #endif Py_CLEAR(state->constructs); Py_CLEAR(state->unsupported_digestmod_error); @@ -2214,37 +2361,37 @@ hashlib_init_hashtable(PyObject *module) } static int -hashlib_init_evptype(PyObject *module) +hashlib_init_HASH_type(PyObject *module) { _hashlibstate *state = get_hashlib_state(module); - state->EVPtype = (PyTypeObject *)PyType_FromSpec(&EVPtype_spec); - if (state->EVPtype == NULL) { + state->HASH_type = (PyTypeObject *)PyType_FromSpec(&HASHobject_type_spec); + if (state->HASH_type == NULL) { return -1; } - if (PyModule_AddType(module, state->EVPtype) < 0) { + if (PyModule_AddType(module, state->HASH_type) < 0) { return -1; } return 0; } static int -hashlib_init_evpxoftype(PyObject *module) +hashlib_init_HASHXOF_type(PyObject *module) { #ifdef PY_OPENSSL_HAS_SHAKE _hashlibstate *state = get_hashlib_state(module); - if (state->EVPtype == NULL) { + if (state->HASH_type == NULL) { return -1; } - state->EVPXOFtype = (PyTypeObject *)PyType_FromSpecWithBases( - &EVPXOFtype_spec, (PyObject *)state->EVPtype + state->HASHXOF_type = (PyTypeObject *)PyType_FromSpecWithBases( + &HASHXOFobject_type_spec, (PyObject *)state->HASH_type ); - if (state->EVPXOFtype == NULL) { + if (state->HASHXOF_type == NULL) { return -1; } - if (PyModule_AddType(module, state->EVPXOFtype) < 0) { + if (PyModule_AddType(module, state->HASHXOF_type) < 0) { return -1; } #endif @@ -2256,11 +2403,11 @@ hashlib_init_hmactype(PyObject *module) { _hashlibstate *state = get_hashlib_state(module); - state->HMACtype = (PyTypeObject *)PyType_FromSpec(&HMACtype_spec); - if (state->HMACtype == NULL) { + state->HMAC_type = (PyTypeObject *)PyType_FromSpec(&HMACtype_spec); + if (state->HMAC_type == NULL) { return -1; } - if (PyModule_AddType(module, state->HMACtype) < 0) { + if (PyModule_AddType(module, state->HMAC_type) < 0) { return -1; } return 0; @@ -2341,8 +2488,8 @@ hashlib_constants(PyObject *module) static PyModuleDef_Slot hashlib_slots[] = { {Py_mod_exec, hashlib_init_hashtable}, - {Py_mod_exec, hashlib_init_evptype}, - {Py_mod_exec, hashlib_init_evpxoftype}, + {Py_mod_exec, hashlib_init_HASH_type}, + {Py_mod_exec, hashlib_init_HASHXOF_type}, {Py_mod_exec, hashlib_init_hmactype}, {Py_mod_exec, hashlib_md_meth_names}, {Py_mod_exec, hashlib_init_constructors}, |