aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules/_hashopenssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_hashopenssl.c')
-rw-r--r--Modules/_hashopenssl.c1023
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},