/* EVP is the preferred interface to hashing in OpenSSL */
#include <openssl/evp.h>
-#include <openssl/hmac.h>
#include <openssl/crypto.h> // FIPS_mode()
/* We use the object interface to discover what hashes OpenSSL supports. */
#include <openssl/objects.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
# define Py_HAS_OPENSSL3_SUPPORT
+# include <openssl/core_names.h> // OSSL_MAC_PARAM_DIGEST
+# include <openssl/params.h> // OSSL_PARAM_*()
+#else
+# include <openssl/hmac.h> // HMAC()
#endif
#ifndef OPENSSL_THREADS
#define PY_EVP_MD_free(md) EVP_MD_free(md)
#define PY_EVP_MD_CTX_md(CTX) EVP_MD_CTX_get0_md(CTX)
+
+#define PY_HMAC_CTX_TYPE EVP_MAC_CTX
+#define PY_HMAC_CTX_free EVP_MAC_CTX_free
+#define PY_HMAC_update EVP_MAC_update
#else
#define PY_EVP_MD const EVP_MD
#define PY_EVP_MD_fetch(algorithm, properties) EVP_get_digestbyname(algorithm)
#define PY_EVP_MD_free(md) do {} while(0)
#define PY_EVP_MD_CTX_md(CTX) EVP_MD_CTX_md(CTX)
+
+#define PY_HMAC_CTX_TYPE HMAC_CTX
+#define PY_HMAC_CTX_free HMAC_CTX_free
+#define PY_HMAC_update HMAC_Update
#endif
/*
PyObject *constructs;
PyObject *unsupported_digestmod_error;
_Py_hashtable_t *hashtable;
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ EVP_MAC *evp_hmac;
+#endif
} _hashlibstate;
static inline _hashlibstate*
typedef struct {
HASHLIB_OBJECT_HEAD
- HMAC_CTX *ctx; /* OpenSSL hmac context */
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ EVP_MAC_CTX *ctx; /* OpenSSL HMAC EVP-based context */
+ int evp_md_nid; /* needed to find the message digest name */
+#else
+ HMAC_CTX *ctx; /* OpenSSL HMAC plain context */
+#endif
} HMACobject;
#define HMACobject_CAST(op) ((HMACobject *)(op))
return e ? e->py_name : get_asn1_utf8name_by_nid(nid);
}
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+/*
+ * Convert the NID to an OpenSSL "canonical" cached, SN_* or LN_* digest name.
+ *
+ * On error, set an exception and return NULL.
+ */
+static const char *
+get_openssl_utf8name_by_nid(int nid)
+{
+ const py_hashentry_t *e = get_hashentry_by_nid(nid);
+ return e ? e->ossl_name : get_asn1_utf8name_by_nid(nid);
+}
+#endif
+
/* 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)
return get_openssl_evp_md_by_utf8name(state, name, py_ht);
}
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+/*
+ * Get the "canonical" name of an EVP_MD described by 'digestmod' and purpose.
+ *
+ * On error, set an exception and return NULL.
+ *
+ * This function should not be used to construct the exposed Python name,
+ * but rather to invoke OpenSSL EVP_* functions.
+ */
+static const char *
+get_openssl_digest_name(_hashlibstate *state,
+ PyObject *digestmod, Py_hash_type py_ht,
+ EVP_MD **evp_md)
+{
+ PY_EVP_MD *md = get_openssl_evp_md(state, digestmod, py_ht);
+ if (md == NULL) {
+ if (evp_md != NULL) {
+ *evp_md = NULL;
+ }
+ return NULL;
+ }
+ int nid = EVP_MD_nid(md);
+ const char *name = get_openssl_utf8name_by_nid(nid);
+ if (name == NULL) {
+ if (evp_md != NULL) {
+ *evp_md = NULL;
+ }
+ PY_EVP_MD_free(md);
+ raise_unsupported_algorithm_error(state, digestmod);
+ return NULL;
+ }
+ if (evp_md != NULL) {
+ *evp_md = md;
+ }
+ else {
+ PY_EVP_MD_free(md);
+ }
+ return name;
+}
+#endif
+
// --- OpenSSL HASH wrappers --------------------------------------------------
/* Thin wrapper around EVP_MD_CTX_new() which sets an exception on failure. */
#undef HASHLIB_SCRYPT_MAX_DKLEN
#undef HASHLIB_SCRYPT_MAX_MAXMEM
-/* Fast HMAC for hmac.digest()
+// --- OpenSSL HMAC interface -------------------------------------------------
+
+/*
+ * Functions prefixed by hashlib_openssl_HMAC_* are wrappers around OpenSSL
+ * and implement "atomic" operations (e.g., "free"). These functions are used
+ * by those prefixed by _hashlib_HMAC_* that are methods for HMAC objects, or
+ * other (local) helper functions prefixed by hashlib_HMAC_*.
*/
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+/* EVP_MAC_CTX array of parameters specifying the "digest" */
+#define HASHLIB_HMAC_OSSL_PARAMS(DIGEST) \
+ (const OSSL_PARAM []) { \
+ OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, \
+ (char *)DIGEST, strlen(DIGEST)), \
+ OSSL_PARAM_END \
+ }
+#endif
+
+// --- One-shot HMAC interface ------------------------------------------------
+
/*[clinic input]
_hashlib.hmac_digest as _hashlib_hmac_singleshot
{
_hashlibstate *state = get_hashlib_state(module);
unsigned char md[EVP_MAX_MD_SIZE] = {0};
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ size_t md_len = 0;
+ const char *digest_name = NULL;
+#else
unsigned int md_len = 0;
- unsigned char *result;
- PY_EVP_MD *evp;
+#endif
+ unsigned char *result = NULL;
+ PY_EVP_MD *evp = NULL;
int is_xof;
if (key->len > INT_MAX) {
return NULL;
}
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ digest_name = get_openssl_digest_name(state, digest, Py_ht_mac, &evp);
+ if (digest_name == NULL) {
+ assert(evp == NULL);
+ return NULL;
+ }
+ assert(evp != NULL);
+ is_xof = PY_EVP_MD_xof(evp);
+
+ Py_BEGIN_ALLOW_THREADS
+ result = EVP_Q_mac(
+ NULL, OSSL_MAC_NAME_HMAC, NULL, NULL,
+ HASHLIB_HMAC_OSSL_PARAMS(digest_name),
+ (const void *)key->buf, (size_t)key->len,
+ (const unsigned char *)msg->buf, (size_t)msg->len,
+ md, sizeof(md), &md_len
+ );
+ Py_END_ALLOW_THREADS
+ PY_EVP_MD_free(evp);
+ assert(md_len < (size_t)PY_SSIZE_T_MAX);
+#else
evp = get_openssl_evp_md(state, digest, Py_ht_mac);
if (evp == NULL) {
return NULL;
}
+ is_xof = PY_EVP_MD_xof(evp);
Py_BEGIN_ALLOW_THREADS
- is_xof = PY_EVP_MD_xof(evp);
result = HMAC(
evp,
(const void *)key->buf, (int)key->len,
);
Py_END_ALLOW_THREADS
PY_EVP_MD_free(evp);
-
+#endif
if (result == NULL) {
if (is_xof) {
/* use a better default error message if an XOF is used */
raise_unsupported_algorithm_error(state, digest);
}
else {
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_Q_mac));
+#else
notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC));
+#endif
}
return NULL;
}
return PyBytes_FromStringAndSize((const char*)md, md_len);
}
-/* OpenSSL-based HMAC implementation
- */
+// --- HMAC Object ------------------------------------------------------------
+#ifndef Py_HAS_OPENSSL3_SUPPORT
/* Thin wrapper around HMAC_CTX_new() which sets an exception on failure. */
static HMAC_CTX *
py_openssl_wrapper_HMAC_CTX_new(void)
}
return ctx;
}
+#endif
static int _hmac_update(HMACobject*, PyObject*);
+#ifndef Py_HAS_OPENSSL3_SUPPORT
static const EVP_MD *
_hashlib_hmac_get_md(HMACobject *self)
{
+ assert(self->ctx != NULL);
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
if (md == NULL) {
notify_ssl_error_occurred("missing EVP_MD for HMAC context");
}
return md;
}
+#endif
+
+static const char *
+hashlib_HMAC_get_hashlib_digest_name(HMACobject *self)
+{
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ return get_hashlib_utf8name_by_nid(self->evp_md_nid);
+#else
+ const EVP_MD *md = _hashlib_hmac_get_md(self);
+ return md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md);
+#endif
+}
+
+static int
+hashlib_openssl_HMAC_update_once(PY_HMAC_CTX_TYPE *ctx, const Py_buffer *v)
+{
+ if (!PY_HMAC_update(ctx, (const unsigned char *)v->buf, (size_t)v->len)) {
+ notify_smart_ssl_error_occurred_in(Py_STRINGIFY(PY_HMAC_update));
+ return -1;
+ }
+ return 0;
+}
+
+/* Thin wrapper around PY_HMAC_CTX_free that allows to pass a NULL 'ctx'. */
+static inline void
+hashlib_openssl_HMAC_CTX_free(PY_HMAC_CTX_TYPE *ctx)
+{
+ /* The NULL check was not present in every OpenSSL versions. */
+ if (ctx) {
+ PY_HMAC_CTX_free(ctx);
+ }
+}
+
+static PY_HMAC_CTX_TYPE *
+hashlib_openssl_HMAC_ctx_copy_with_lock(HMACobject *self)
+{
+ PY_HMAC_CTX_TYPE *ctx = NULL;
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ HASHLIB_ACQUIRE_LOCK(self);
+ ctx = EVP_MAC_CTX_dup(self->ctx);
+ HASHLIB_RELEASE_LOCK(self);
+ if (ctx == NULL) {
+ notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_CTX_dup));
+ goto error;
+ }
+#else
+ int r;
+ ctx = py_openssl_wrapper_HMAC_CTX_new();
+ if (ctx == NULL) {
+ return NULL;
+ }
+ HASHLIB_ACQUIRE_LOCK(self);
+ r = HMAC_CTX_copy(ctx, self->ctx);
+ HASHLIB_RELEASE_LOCK(self);
+ if (r == 0) {
+ notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy));
+ goto error;
+ }
+#endif
+ return ctx;
+
+error:
+ hashlib_openssl_HMAC_CTX_free(ctx);
+ return NULL;
+}
+
+static PY_HMAC_CTX_TYPE *
+hashlib_HMAC_CTX_new_from_digestmod(_hashlibstate *state,
+ Py_buffer *key, PyObject *digestmod,
+ int *nid)
+{
+ PY_HMAC_CTX_TYPE *ctx = NULL;
+ PY_EVP_MD *md = NULL;
+ int is_xof, r;
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ const char *digest = NULL;
+#endif
+
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ /*
+ * OpenSSL 3.0 does not provide a way to extract the NID from an EVP_MAC
+ * object and does not expose the underlying digest name. The reason is
+ * that OpenSSL 3.0 treats HMAC objects as being the "same", differing
+ * only by their *context* parameters. While it is *required* to set
+ * the digest name when constructing EVP_MAC_CTX objects, that name
+ * is unfortunately not recoverable through EVP_MAC_CTX_get_params().
+ *
+ * On the other hand, the (deprecated) interface based on HMAC_CTX is
+ * based on EVP_MD, which allows to treat HMAC objects as if they were
+ * hash functions when querying the digest name.
+ *
+ * Since HMAC objects are constructed from DIGESTMOD values and since
+ * we have a way to map DIGESTMOD to EVP_MD objects, and then to NIDs,
+ * HMAC objects based on EVP_MAC will store the NID of the EVP_MD we
+ * used to deduce the digest name to pass to EVP_MAC_CTX_set_params().
+ */
+ assert(nid != NULL);
+ digest = get_openssl_digest_name(state, digestmod, Py_ht_mac, &md);
+ assert((digest == NULL && md == NULL) || (digest != NULL && md != NULL));
+ if (digest == NULL) {
+ *nid = NID_undef;
+ return NULL;
+ }
+ *nid = EVP_MD_nid(md);
+ is_xof = PY_EVP_MD_xof(md);
+ PY_EVP_MD_free(md);
+
+ /*
+ * OpenSSL is responsible for managing the EVP_MAC object's ref. count
+ * by calling EVP_MAC_up_ref() and EVP_MAC_free() in EVP_MAC_CTX_new()
+ * and EVP_MAC_CTX_free() respectively.
+ */
+ ctx = EVP_MAC_CTX_new(state->evp_hmac);
+ if (ctx == NULL) {
+ /* EVP_MAC_CTX_new() may also set an ERR_R_EVP_LIB error */
+ notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_CTX_new));
+ return NULL;
+ }
+
+ r = EVP_MAC_init(
+ ctx,
+ (const unsigned char *)key->buf,
+ (size_t)key->len,
+ HASHLIB_HMAC_OSSL_PARAMS(digest)
+ );
+#else
+ assert(nid == NULL);
+ md = get_openssl_evp_md(state, digestmod, Py_ht_mac);
+ if (md == NULL) {
+ return NULL;
+ }
+ is_xof = PY_EVP_MD_xof(md);
+
+ ctx = py_openssl_wrapper_HMAC_CTX_new();
+ if (ctx == NULL) {
+ PY_EVP_MD_free(md);
+ return NULL;
+ }
+
+ r = HMAC_Init_ex(ctx, key->buf, (int)key->len, md, NULL /* impl */);
+ PY_EVP_MD_free(md);
+#endif
+ if (r == 0) {
+ if (is_xof) {
+ /* use a better default error message if an XOF is used */
+ raise_unsupported_algorithm_error(state, digestmod);
+ }
+ else {
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_init));
+#else
+ notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Init_ex));
+#endif
+ }
+ return NULL;
+ }
+ return ctx;
+}
/*[clinic input]
_hashlib.hmac_new
/*[clinic end generated code: output=c20d9e4d9ed6d219 input=5f4071dcc7f34362]*/
{
_hashlibstate *state = get_hashlib_state(module);
- PY_EVP_MD *digest;
- HMAC_CTX *ctx = NULL;
+ PY_HMAC_CTX_TYPE *ctx = NULL;
HMACobject *self = NULL;
- int is_xof, r;
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ int nid;
+#endif
if (key->len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
return NULL;
}
- digest = get_openssl_evp_md(state, digestmod, Py_ht_mac);
- if (digest == NULL) {
- return NULL;
- }
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ ctx = hashlib_HMAC_CTX_new_from_digestmod(state, key, digestmod, &nid);
+#else
+ ctx = hashlib_HMAC_CTX_new_from_digestmod(state, key, digestmod, NULL);
+#endif
- ctx = py_openssl_wrapper_HMAC_CTX_new();
if (ctx == NULL) {
- PY_EVP_MD_free(digest);
- goto error;
- }
-
- is_xof = PY_EVP_MD_xof(digest);
- r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */);
- PY_EVP_MD_free(digest);
- if (r == 0) {
- if (is_xof) {
- /* use a better default error message if an XOF is used */
- raise_unsupported_algorithm_error(state, digestmod);
- }
- else {
- notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Init_ex));
- }
- goto error;
+ assert(PyErr_Occurred());
+ return NULL;
}
self = PyObject_New(HMACobject, state->HMAC_type);
self->ctx = ctx;
ctx = NULL; // 'ctx' is now owned by 'self'
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ assert(nid != NID_undef);
+ self->evp_md_nid = nid;
+#endif
HASHLIB_INIT_MUTEX(self);
+ /* feed initial data */
if ((msg_obj != NULL) && (msg_obj != Py_None)) {
- if (!_hmac_update(self, msg_obj)) {
+ if (_hmac_update(self, msg_obj) < 0) {
goto error;
}
}
return (PyObject *)self;
error:
- if (ctx) HMAC_CTX_free(ctx);
+ hashlib_openssl_HMAC_CTX_free(ctx);
Py_XDECREF(self);
return NULL;
}
/* helper functions */
-static int
-locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
-{
- int result;
- HASHLIB_ACQUIRE_LOCK(self);
- result = HMAC_CTX_copy(new_ctx_p, self->ctx);
- HASHLIB_RELEASE_LOCK(self);
- if (result == 0) {
- notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy));
- return -1;
- }
- return 0;
-}
-
#define BAD_DIGEST_SIZE 0
/*
static unsigned int
_hashlib_hmac_digest_size(HMACobject *self)
{
+ assert(EVP_MAX_MD_SIZE < INT_MAX);
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ assert(self->ctx != NULL);
+ size_t digest_size = EVP_MAC_CTX_get_mac_size(self->ctx);
+ assert(digest_size <= (size_t)EVP_MAX_MD_SIZE);
+#else
const EVP_MD *md = _hashlib_hmac_get_md(self);
if (md == NULL) {
return BAD_DIGEST_SIZE;
/* digest_size < 0 iff EVP_MD context is NULL (which is impossible here) */
assert(digest_size >= 0);
assert(digest_size <= (int)EVP_MAX_MD_SIZE);
+#endif
/* digest_size == 0 means that the context is not entirely initialized */
if (digest_size == 0) {
raise_ssl_error(PyExc_ValueError, "missing digest size");
{
int r;
Py_buffer view = {0};
-
- GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0);
+ GET_BUFFER_VIEW_OR_ERROR(obj, &view, return -1);
HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
self, view.len,
- r = HMAC_Update(
- self->ctx, (const unsigned char *)view.buf, (size_t)view.len
- )
+ r = hashlib_openssl_HMAC_update_once(self->ctx, &view)
);
PyBuffer_Release(&view);
-
- if (r == 0) {
- notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Update));
- return 0;
- }
- return 1;
+ return r;
}
/*[clinic input]
/*[clinic end generated code: output=29aa28b452833127 input=e2fa6a05db61a4d6]*/
{
HMACobject *retval;
-
- HMAC_CTX *ctx = py_openssl_wrapper_HMAC_CTX_new();
+ PY_HMAC_CTX_TYPE *ctx = hashlib_openssl_HMAC_ctx_copy_with_lock(self);
if (ctx == NULL) {
return NULL;
}
- if (locked_HMAC_CTX_copy(ctx, self) < 0) {
- HMAC_CTX_free(ctx);
- return NULL;
- }
-
retval = PyObject_New(HMACobject, Py_TYPE(self));
if (retval == NULL) {
- HMAC_CTX_free(ctx);
+ PY_HMAC_CTX_free(ctx);
return NULL;
}
retval->ctx = ctx;
HASHLIB_INIT_MUTEX(retval);
-
return (PyObject *)retval;
}
HMACobject *self = HMACobject_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
if (self->ctx != NULL) {
- HMAC_CTX_free(self->ctx);
+ PY_HMAC_CTX_free(self->ctx);
self->ctx = NULL;
}
PyObject_Free(self);
static PyObject *
_hmac_repr(PyObject *op)
{
- const char *digest_name;
HMACobject *self = HMACobject_CAST(op);
- const EVP_MD *md = _hashlib_hmac_get_md(self);
- digest_name = md == NULL ? NULL : get_hashlib_utf8name_by_evp_md(md);
+ const char *digest_name = hashlib_HMAC_get_hashlib_digest_name(self);
if (digest_name == NULL) {
assert(PyErr_Occurred());
return NULL;
_hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg)
/*[clinic end generated code: output=f31f0ace8c625b00 input=1829173bb3cfd4e6]*/
{
- if (!_hmac_update(self, msg)) {
+ if (_hmac_update(self, msg) < 0) {
return NULL;
}
Py_RETURN_NONE;
/*
* Extract the MAC value to 'buf' and return the digest size.
*
- * The buffer 'buf' must have at least hashlib_openssl_HMAC_digest_size(self)
+ * The buffer 'buf' must have at least _hashlib_hmac_digest_size(self)
* bytes. Smaller buffers lead to undefined behaviors.
*
* On error, set an exception and return -1.
assert(PyErr_Occurred());
return -1;
}
- HMAC_CTX *temp_ctx = py_openssl_wrapper_HMAC_CTX_new();
- if (temp_ctx == NULL) {
- return -1;
- }
- if (locked_HMAC_CTX_copy(temp_ctx, self) < 0) {
- HMAC_CTX_free(temp_ctx);
+ PY_HMAC_CTX_TYPE *ctx = hashlib_openssl_HMAC_ctx_copy_with_lock(self);
+ if (ctx == NULL) {
return -1;
}
- int r = HMAC_Final(temp_ctx, buf, NULL);
- HMAC_CTX_free(temp_ctx);
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ int r = EVP_MAC_final(ctx, buf, NULL, digest_size);
+#else
+ int r = HMAC_Final(ctx, buf, NULL);
+#endif
+ PY_HMAC_CTX_free(ctx);
if (r == 0) {
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ notify_ssl_error_occurred_in(Py_STRINGIFY(EVP_MAC_final));
+#else
notify_ssl_error_occurred_in(Py_STRINGIFY(HMAC_Final));
+#endif
return -1;
}
return digest_size;
_hashlib_hmac_get_block_size(PyObject *op, void *Py_UNUSED(closure))
{
HMACobject *self = HMACobject_CAST(op);
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ assert(self->ctx != NULL);
+ return PyLong_FromSize_t(EVP_MAC_CTX_get_block_size(self->ctx));
+#else
const EVP_MD *md = _hashlib_hmac_get_md(self);
return md == NULL ? NULL : PyLong_FromLong(EVP_MD_block_size(md));
+#endif
}
static PyObject *
_hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure))
{
HMACobject *self = HMACobject_CAST(op);
- const EVP_MD *md = _hashlib_hmac_get_md(self);
- if (md == NULL) {
- return NULL;
- }
- const char *digest_name = get_hashlib_utf8name_by_evp_md(md);
+ const char *digest_name = hashlib_HMAC_get_hashlib_digest_name(self);
if (digest_name == NULL) {
assert(PyErr_Occurred());
return NULL;
_Py_hashtable_destroy(state->hashtable);
state->hashtable = NULL;
}
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ if (state->evp_hmac != NULL) {
+ EVP_MAC_free(state->evp_hmac);
+ state->evp_hmac = NULL;
+ }
+#endif
return 0;
}
if (PyModule_AddType(module, state->HMAC_type) < 0) {
return -1;
}
+#ifdef Py_HAS_OPENSSL3_SUPPORT
+ state->evp_hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (state->evp_hmac == NULL) {
+ ERR_clear_error();
+ PyErr_SetString(PyExc_ImportError, "cannot initialize EVP_MAC HMAC");
+ return -1;
+ }
+#endif
+
return 0;
}