gh-134531: use EVP_MAC API for _hashlib.HMAC when possible (#135235)

Use `EVP_MAC` API for HMAC on builds with OpenSSL 3.0 or later.
This commit is contained in:
Bénédikt Tran 2025-09-10 10:35:01 +02:00 committed by GitHub
parent d6d054853d
commit b9c50b4988
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 362 additions and 88 deletions

View file

@ -0,0 +1,3 @@
:mod:`hmac`: use the :manpage:`EVP_MAC(3ssl)` interface for HMAC when Python
is built with OpenSSL 3.0 and later instead of the deprecated
:manpage:`HMAC_CTX(3ssl) <hmac(3)>` interface. Patch by Bénédikt Tran.

View file

@ -30,7 +30,6 @@
/* 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>
@ -40,6 +39,10 @@
#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
@ -65,6 +68,10 @@
#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)
@ -72,6 +79,10 @@
#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
/*
@ -283,6 +294,9 @@ typedef struct {
PyObject *constructs;
PyObject *unsupported_digestmod_error;
_Py_hashtable_t *hashtable;
#ifdef Py_HAS_OPENSSL3_SUPPORT
EVP_MAC *evp_hmac;
#endif
} _hashlibstate;
static inline _hashlibstate*
@ -304,7 +318,12 @@ typedef struct {
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))
@ -617,6 +636,20 @@ get_hashlib_utf8name_by_nid(int nid)
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)
@ -733,6 +766,47 @@ get_openssl_evp_md(_hashlibstate *state, PyObject *digestmod, Py_hash_type py_ht
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. */
@ -1742,9 +1816,27 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
#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
@ -1762,9 +1854,14 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
{
_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) {
@ -1778,13 +1875,34 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
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,
@ -1793,23 +1911,27 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
);
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)
@ -1821,18 +1943,179 @@ 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
@ -1850,10 +2133,11 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
/*[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,
@ -1867,29 +2151,15 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
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);
@ -1899,36 +2169,27 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
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
/*
@ -1939,6 +2200,12 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
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;
@ -1947,6 +2214,7 @@ _hashlib_hmac_digest_size(HMACobject *self)
/* 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");
@ -1960,21 +2228,13 @@ _hmac_update(HMACobject *self, PyObject *obj)
{
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]
@ -1988,24 +2248,17 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
/*[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;
}
@ -2015,7 +2268,7 @@ _hmac_dealloc(PyObject *op)
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);
@ -2025,10 +2278,8 @@ _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);
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;
@ -2047,7 +2298,7 @@ static PyObject *
_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;
@ -2056,7 +2307,7 @@ _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg)
/*
* 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.
@ -2070,18 +2321,22 @@ _hmac_digest(HMACobject *self, unsigned char *buf)
assert(PyErr_Occurred());
return -1;
}
HMAC_CTX *temp_ctx = py_openssl_wrapper_HMAC_CTX_new();
if (temp_ctx == NULL) {
PY_HMAC_CTX_TYPE *ctx = hashlib_openssl_HMAC_ctx_copy_with_lock(self);
if (ctx == NULL) {
return -1;
}
if (locked_HMAC_CTX_copy(temp_ctx, self) < 0) {
HMAC_CTX_free(temp_ctx);
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;
@ -2133,19 +2388,20 @@ static PyObject *
_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;
@ -2472,6 +2728,12 @@ hashlib_clear(PyObject *m)
_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;
}
@ -2546,6 +2808,15 @@ hashlib_init_hmactype(PyObject *module)
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;
}