]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Separate isc_hmac between pre and post OpenSSL 3.0
authorAydın Mercan <aydin@isc.org>
Wed, 17 Sep 2025 12:52:35 +0000 (14:52 +0200)
committerAydın Mercan <aydin@isc.org>
Mon, 2 Feb 2026 08:50:14 +0000 (11:50 +0300)
Instead of the `EVP_MD_CTX` based functions, use either the new
`EVP_MAC` or the old `HMAC_CTX` based functions.

`EVP_MAC` is the recommended way using using MAC functions in post-3.0
while `HMAC_CTX` is used internally by `EVP_MD_CTX`, making the latter
redundant.

lib/dns/dst_internal.h
lib/dns/hmac_link.c
lib/isc/crypto/ossl1_1.c
lib/isc/crypto/ossl3.c
lib/isc/hmac.c [deleted file]
lib/isc/include/isc/hmac.h
lib/isc/meson.build
tests/isc/hmac_test.c

index 51f8cd5d26cefce815e3caa04f627ba001184bae..bc48c9fec41ddec051fcbe937e522446a4c7970f 100644 (file)
@@ -62,8 +62,6 @@
 
 typedef struct dst_func dst_func_t;
 
-typedef struct dst_hmac_key dst_hmac_key_t;
-
 /*%
  * Indicate whether a DST context will be used for signing
  * or for verification
@@ -93,7 +91,7 @@ struct dst_key {
        union {
                void *generic;
                dns_gss_ctx_id_t gssctx;
-               dst_hmac_key_t *hmac_key;
+               isc_hmac_key_t *hmac_key;
                struct {
                        EVP_PKEY *pub;
                        EVP_PKEY *priv;
index 40a87aac70c087d0d0d83f1d90170e500a36e88c..aa3d5d7141dd69dcd02d6fb10cb09d55bc1ceb8b 100644 (file)
@@ -55,7 +55,7 @@
 #define hmac_register_algorithm(alg)                                           \
        static isc_result_t hmac##alg##_createctx(dst_key_t *key,              \
                                                  dst_context_t *dctx) {       \
-               return (hmac_createctx(ISC_MD_##alg, key, dctx));              \
+               return (hmac_createctx(key, dctx));                            \
        }                                                                      \
        static void hmac##alg##_destroyctx(dst_context_t *dctx) {              \
                hmac_destroyctx(dctx);                                         \
@@ -74,7 +74,7 @@
        }                                                                      \
        static bool hmac##alg##_compare(const dst_key_t *key1,                 \
                                        const dst_key_t *key2) {               \
-               return (hmac_compare(ISC_MD_##alg, key1, key2));               \
+               return (hmac_compare(key1, key2));                             \
        }                                                                      \
        static isc_result_t hmac##alg##_generate(                              \
                dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) {  \
        void dst__hmac##alg##_init(dst_func_t **funcp) {                       \
                REQUIRE(funcp != NULL);                                        \
                if (*funcp == NULL) {                                          \
-                       isc_hmac_t *ctx = isc_hmac_new();                      \
-                       if (isc_hmac_init(ctx, "test", 4, ISC_MD_##alg) ==     \
-                           ISC_R_SUCCESS)                                     \
+                       uint8_t data[] = "data";                               \
+                       uint8_t mac_buffer[ISC_MAX_MD_SIZE];                   \
+                       unsigned int mac_len = sizeof(mac_buffer);             \
+                       if (isc_hmac(ISC_MD_##alg, "test", 4, data, 4,         \
+                                    mac_buffer, &mac_len) == ISC_R_SUCCESS)   \
                        {                                                      \
                                *funcp = &hmac##alg##_functions;               \
                        }                                                      \
-                       isc_hmac_free(ctx);                                    \
                }                                                              \
        }
 
 static isc_result_t
 hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data);
 
-struct dst_hmac_key {
-       uint8_t key[ISC_MAX_BLOCK_SIZE];
-};
-
 static isc_result_t
 getkeybits(dst_key_t *key, struct dst_private_element *element) {
        uint16_t *bits = (uint16_t *)element->data;
@@ -161,13 +158,11 @@ getkeybits(dst_key_t *key, struct dst_private_element *element) {
 }
 
 static isc_result_t
-hmac_createctx(isc_md_type_t type, const dst_key_t *key, dst_context_t *dctx) {
+hmac_createctx(const dst_key_t *key, dst_context_t *dctx) {
        isc_result_t result;
-       const dst_hmac_key_t *hkey = key->keydata.hmac_key;
        isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */
 
-       result = isc_hmac_init(ctx, hkey->key, isc_md_type_get_block_size(type),
-                              type);
+       result = isc_hmac_init(ctx, key->keydata.hmac_key);
        if (result != ISC_R_SUCCESS) {
                isc_hmac_free(ctx);
                return DST_R_UNSUPPORTEDALG;
@@ -204,44 +199,35 @@ hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) {
 static isc_result_t
 hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) {
        isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
-       REQUIRE(ctx != NULL);
-       unsigned char digest[ISC_MAX_MD_SIZE];
-       unsigned int digestlen = sizeof(digest);
+       isc_result_t r;
 
-       if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
-               return DST_R_OPENSSLFAILURE;
-       }
+       REQUIRE(ctx != NULL);
 
-       if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
-               return DST_R_OPENSSLFAILURE;
-       }
+       r = isc_hmac_final(ctx, sig);
 
-       if (isc_buffer_availablelength(sig) < digestlen) {
-               return ISC_R_NOSPACE;
+       /* Turn CRYPTOFAILURE into OPENSSLFAILURE */
+       if (r == ISC_R_CRYPTOFAILURE) {
+               r = DST_R_OPENSSLFAILURE;
        }
 
-       isc_buffer_putmem(sig, digest, digestlen);
-
-       return ISC_R_SUCCESS;
+       return r;
 }
 
 static isc_result_t
 hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) {
        isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
        unsigned char digest[ISC_MAX_MD_SIZE];
-       unsigned int digestlen = sizeof(digest);
+       isc_buffer_t hmac;
 
        REQUIRE(ctx != NULL);
 
-       if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
-               return DST_R_OPENSSLFAILURE;
-       }
+       isc_buffer_init(&hmac, digest, sizeof(digest));
 
-       if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
+       if (isc_hmac_final(ctx, &hmac) != ISC_R_SUCCESS) {
                return DST_R_OPENSSLFAILURE;
        }
 
-       if (sig->length > digestlen) {
+       if (sig->length > isc_buffer_usedlength(&hmac)) {
                return DST_R_VERIFYFAILURE;
        }
 
@@ -251,8 +237,8 @@ hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) {
 }
 
 static bool
-hmac_compare(isc_md_type_t type, const dst_key_t *key1, const dst_key_t *key2) {
-       dst_hmac_key_t *hkey1, *hkey2;
+hmac_compare(const dst_key_t *key1, const dst_key_t *key2) {
+       isc_hmac_key_t *hkey1, *hkey2;
 
        hkey1 = key1->keydata.hmac_key;
        hkey2 = key2->keydata.hmac_key;
@@ -263,8 +249,7 @@ hmac_compare(isc_md_type_t type, const dst_key_t *key1, const dst_key_t *key2) {
                return false;
        }
 
-       return isc_safe_memequal(hkey1->key, hkey2->key,
-                                isc_md_type_get_block_size(type));
+       return isc_hmac_key_equal(hkey1, hkey2);
 }
 
 static isc_result_t
@@ -303,31 +288,28 @@ hmac_isprivate(const dst_key_t *key) {
 
 static void
 hmac_destroy(dst_key_t *key) {
-       dst_hmac_key_t *hkey = key->keydata.hmac_key;
-       isc_safe_memwipe(hkey, sizeof(*hkey));
-       isc_mem_put(key->mctx, hkey, sizeof(*hkey));
-       key->keydata.hmac_key = NULL;
+       isc_hmac_key_destroy(&key->keydata.hmac_key);
 }
 
 static isc_result_t
 hmac_todns(const dst_key_t *key, isc_buffer_t *data) {
+       isc_region_t raw_key;
+
        REQUIRE(key != NULL && key->keydata.hmac_key != NULL);
-       dst_hmac_key_t *hkey = key->keydata.hmac_key;
-       unsigned int bytes;
 
-       bytes = (key->key_size + 7) / 8;
-       if (isc_buffer_availablelength(data) < bytes) {
+       raw_key = isc_hmac_key_expose(key->keydata.hmac_key);
+
+       if (isc_buffer_availablelength(data) < raw_key.length) {
                return ISC_R_NOSPACE;
        }
-       isc_buffer_putmem(data, hkey->key, bytes);
 
-       return ISC_R_SUCCESS;
+       return isc_buffer_copyregion(data, &raw_key);
 }
 
 static isc_result_t
 hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) {
-       dst_hmac_key_t *hkey;
-       unsigned int keylen;
+       isc_hmac_key_t *hkey = NULL;
+       isc_result_t result;
        isc_region_t r;
 
        isc_buffer_remainingregion(data, &r);
@@ -335,24 +317,12 @@ hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) {
                return ISC_R_SUCCESS;
        }
 
-       hkey = isc_mem_get(key->mctx, sizeof(dst_hmac_key_t));
-
-       memset(hkey->key, 0, sizeof(hkey->key));
-
-       /* Hash the key if the key is longer then chosen MD block size */
-       if (r.length > (unsigned int)isc_md_type_get_block_size(type)) {
-               if (isc_md(type, r.base, r.length, hkey->key, &keylen) !=
-                   ISC_R_SUCCESS)
-               {
-                       isc_mem_put(key->mctx, hkey, sizeof(dst_hmac_key_t));
-                       return DST_R_OPENSSLFAILURE;
-               }
-       } else {
-               memmove(hkey->key, r.base, r.length);
-               keylen = r.length;
+       result = isc_hmac_key_create(type, r.base, r.length, key->mctx, &hkey);
+       if (result != ISC_R_SUCCESS) {
+               return DST_R_OPENSSLFAILURE;
        }
 
-       key->key_size = keylen * 8;
+       key->key_size = isc_hmac_key_expose(hkey).length * 8;
        key->keydata.hmac_key = hkey;
 
        isc_buffer_forward(data, r.length);
@@ -362,47 +332,48 @@ hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) {
 
 static int
 hmac__get_tag_key(isc_md_type_t type) {
-       if (type == ISC_MD_MD5) {
+       switch (type) {
+       case ISC_MD_MD5:
                return TAG_HMACMD5_KEY;
-       } else if (type == ISC_MD_SHA1) {
+       case ISC_MD_SHA1:
                return TAG_HMACSHA1_KEY;
-       } else if (type == ISC_MD_SHA224) {
+       case ISC_MD_SHA224:
                return TAG_HMACSHA224_KEY;
-       } else if (type == ISC_MD_SHA256) {
+       case ISC_MD_SHA256:
                return TAG_HMACSHA256_KEY;
-       } else if (type == ISC_MD_SHA384) {
+       case ISC_MD_SHA384:
                return TAG_HMACSHA384_KEY;
-       } else if (type == ISC_MD_SHA512) {
+       case ISC_MD_SHA512:
                return TAG_HMACSHA512_KEY;
-       } else {
+       default:
                UNREACHABLE();
        }
 }
 
 static int
 hmac__get_tag_bits(isc_md_type_t type) {
-       if (type == ISC_MD_MD5) {
+       switch (type) {
+       case ISC_MD_MD5:
                return TAG_HMACMD5_BITS;
-       } else if (type == ISC_MD_SHA1) {
+       case ISC_MD_SHA1:
                return TAG_HMACSHA1_BITS;
-       } else if (type == ISC_MD_SHA224) {
+       case ISC_MD_SHA224:
                return TAG_HMACSHA224_BITS;
-       } else if (type == ISC_MD_SHA256) {
+       case ISC_MD_SHA256:
                return TAG_HMACSHA256_BITS;
-       } else if (type == ISC_MD_SHA384) {
+       case ISC_MD_SHA384:
                return TAG_HMACSHA384_BITS;
-       } else if (type == ISC_MD_SHA512) {
+       case ISC_MD_SHA512:
                return TAG_HMACSHA512_BITS;
-       } else {
+       default:
                UNREACHABLE();
        }
 }
 
 static isc_result_t
 hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) {
-       dst_hmac_key_t *hkey;
+       isc_region_t raw_key;
        dst_private_t priv;
-       int bytes = (key->key_size + 7) / 8;
        uint16_t bits;
 
        if (key->keydata.hmac_key == NULL) {
@@ -413,11 +384,11 @@ hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) {
                return DST_R_EXTERNALKEY;
        }
 
-       hkey = key->keydata.hmac_key;
+       raw_key = isc_hmac_key_expose(key->keydata.hmac_key);
 
        priv.elements[0].tag = hmac__get_tag_key(type);
-       priv.elements[0].length = bytes;
-       priv.elements[0].data = hkey->key;
+       priv.elements[0].length = raw_key.length;
+       priv.elements[0].data = raw_key.base;
 
        bits = htons(key->key_bits);
 
index 6920273b67c851d798a91e33bf1525b8cd97093b..e47e294ddda83088a0d525665baeddc23ca5f07d 100644 (file)
  * information regarding copyright ownership.
  */
 
+#include <stdint.h>
+
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
 
+#include <isc/buffer.h>
 #include <isc/crypto.h>
+#include <isc/hmac.h>
 #include <isc/log.h>
+#include <isc/magic.h>
 #include <isc/md.h>
 #include <isc/mem.h>
+#include <isc/safe.h>
 #include <isc/tls.h>
 #include <isc/util.h>
 
 #include "crypto_p.h"
 
+#define HMAC_KEY_MAGIC ISC_MAGIC('H', 'M', 'A', 'C')
+
+struct isc_hmac_key {
+       uint32_t magic;
+       uint32_t len;
+       isc_mem_t *mctx;
+       EVP_MD *md;
+       uint8_t secret[];
+};
+
 static isc_mem_t *isc__crypto_mctx = NULL;
 
 #define md_register_algorithm(alg, upperalg)                              \
@@ -53,6 +69,175 @@ register_algorithms(void) {
 
 #undef md_unregister_algorithm
 
+/*
+ * HMAC Notes
+ *
+ * For pre-3.0 libcrypto, we use HMAC_CTX instead of the EVP_PKEY API.
+ *
+ * EVP_PKEY will call HMAC_* functions internally so there is no need to add
+ * even more vtables.
+ */
+
+isc_result_t
+isc_hmac(isc_md_type_t type, const void *key, const size_t keylen,
+        const unsigned char *buf, const size_t len, unsigned char *digest,
+        unsigned int *digestlen) {
+       EVP_MD *md;
+
+       REQUIRE(type < ISC_MD_MAX);
+
+       md = isc__crypto_md[type];
+       if (md == NULL) {
+               return ISC_R_NOTIMPLEMENTED;
+       }
+
+       if (HMAC(md, key, keylen, buf, len, digest, digestlen) == NULL) {
+               ERR_clear_error();
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len,
+                   isc_mem_t *mctx, isc_hmac_key_t **keyp) {
+       isc_hmac_key_t *key;
+       EVP_MD *md;
+
+       REQUIRE(keyp != NULL && *keyp == NULL);
+       REQUIRE(type < ISC_MD_MAX);
+
+       md = isc__crypto_md[type];
+       if (md == NULL) {
+               return ISC_R_NOTIMPLEMENTED;
+       }
+
+       key = isc_mem_get(mctx, STRUCT_FLEX_SIZE(key, secret, len));
+       *key = (isc_hmac_key_t){
+               .magic = HMAC_KEY_MAGIC,
+               .len = len,
+               .md = md,
+       };
+       memmove(key->secret, secret, len);
+       isc_mem_attach(mctx, &key->mctx);
+
+       *keyp = key;
+
+       return ISC_R_SUCCESS;
+}
+
+void
+isc_hmac_key_destroy(isc_hmac_key_t **keyp) {
+       isc_hmac_key_t *key;
+
+       REQUIRE(keyp != NULL && *keyp != NULL);
+       REQUIRE((*keyp)->magic == HMAC_KEY_MAGIC);
+
+       key = *keyp;
+       *keyp = NULL;
+
+       key->magic = 0x00;
+
+       isc_safe_memwipe(key->secret, sizeof(key->len));
+
+       isc_mem_putanddetach(&key->mctx, key,
+                            STRUCT_FLEX_SIZE(key, secret, key->len));
+}
+
+isc_region_t
+isc_hmac_key_expose(isc_hmac_key_t *key) {
+       REQUIRE(key != NULL && key->magic == HMAC_KEY_MAGIC);
+
+       return (isc_region_t){ .base = key->secret, .length = key->len };
+}
+
+bool
+isc_hmac_key_equal(isc_hmac_key_t *a, isc_hmac_key_t *b) {
+       REQUIRE(a != NULL && a->magic == HMAC_KEY_MAGIC);
+       REQUIRE(b != NULL && b->magic == HMAC_KEY_MAGIC);
+
+       if (a->md != b->md) {
+               return false;
+       }
+
+       if (a->len != b->len) {
+               return false;
+       }
+
+       return isc_safe_memequal(a->secret, b->secret, a->len);
+}
+
+isc_hmac_t *
+isc_hmac_new(void) {
+       HMAC_CTX *ctx = HMAC_CTX_new();
+       RUNTIME_CHECK(ctx != NULL);
+       return ctx;
+}
+
+void
+isc_hmac_free(isc_hmac_t *hmac) {
+       if (hmac != NULL) {
+               HMAC_CTX_free(hmac);
+       }
+}
+
+isc_result_t
+isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key) {
+       REQUIRE(hmac != NULL);
+       REQUIRE(key != NULL && key->magic == HMAC_KEY_MAGIC);
+
+       if (HMAC_Init_ex(hmac, key->secret, key->len, key->md, NULL) != 1) {
+               ERR_clear_error();
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len) {
+       REQUIRE(hmac != NULL);
+
+       if (buf == NULL || len == 0) {
+               return ISC_R_SUCCESS;
+       }
+
+       if (HMAC_Update(hmac, buf, len) != 1) {
+               ERR_clear_error();
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out) {
+       unsigned int len;
+
+       REQUIRE(hmac != NULL);
+       REQUIRE(out != NULL);
+
+       /*
+        * LibreSSL changes HMAC_size's return from size_t to int but keeps the
+        * size_t signature in its manpage.
+        *
+        * Cast it instead of accepting LibreSSL's man(page)splaining.
+        */
+       len = isc_buffer_availablelength(out);
+       if (len < (unsigned int)HMAC_size(hmac)) {
+               return ISC_R_NOSPACE;
+       }
+
+       if (HMAC_Final(hmac, isc_buffer_used(out), &len) != 1) {
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       isc_buffer_add(out, len);
+
+       return ISC_R_SUCCESS;
+}
+
 #ifndef LIBRESSL_VERSION_NUMBER
 /*
  * This was crippled with LibreSSL, so just skip it:
index 00ac7c82571c33a8149a241b71022c8b195dd84f..9b6e19bb27de5be2fe83dd81e44f86f722e5fdd7 100644 (file)
  * information regarding copyright ownership.
  */
 
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <openssl/core_names.h>
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
 
+#include <isc/buffer.h>
 #include <isc/crypto.h>
+#include <isc/hmac.h>
 #include <isc/log.h>
+#include <isc/magic.h>
 #include <isc/md.h>
 #include <isc/mem.h>
+#include <isc/region.h>
+#include <isc/safe.h>
 #include <isc/tls.h>
 #include <isc/util.h>
 
 #include "crypto_p.h"
 
+struct isc_hmac_key {
+       uint32_t magic;
+       uint32_t len;
+       isc_mem_t *mctx;
+       const OSSL_PARAM *params;
+       uint8_t secret[];
+};
+
+constexpr uint32_t hmac_key_magic = ISC_MAGIC('H', 'M', 'A', 'C');
+
 static isc_mem_t *isc__crypto_mctx = NULL;
 
 static OSSL_PROVIDER *base = NULL, *fips = NULL;
 
+static EVP_MAC *evp_hmac = NULL;
+
+static OSSL_PARAM md_to_hmac_params[ISC_MD_MAX][2] = {
+       [ISC_MD_UNKNOWN] = { OSSL_PARAM_END },
+       [ISC_MD_MD5] = {
+               OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("MD5"), sizeof("MD5") - 1),
+               OSSL_PARAM_END,
+       },
+       [ISC_MD_SHA1] = {
+               OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA1"), sizeof("SHA1") - 1),
+               OSSL_PARAM_END,
+       },
+       [ISC_MD_SHA224] = {
+               OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-224"), sizeof("SHA2-224") - 1),
+               OSSL_PARAM_END,
+       },
+       [ISC_MD_SHA256] = {
+               OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-256"), sizeof("SHA2-256") - 1),
+               OSSL_PARAM_END,
+       },
+       [ISC_MD_SHA384] = {
+               OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-384"), sizeof("SHA2-384") - 1),
+               OSSL_PARAM_END,
+       },
+       [ISC_MD_SHA512] = {
+               OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, UNCONST("SHA2-512"), sizeof("SHA2-512") - 1),
+               OSSL_PARAM_END,
+       },
+};
+
 #define md_register_algorithm(alg)                                             \
        {                                                                      \
                REQUIRE(isc__crypto_md[ISC_MD_##alg] == NULL);                 \
@@ -52,6 +101,15 @@ register_algorithms(void) {
        md_register_algorithm(SHA384);
        md_register_algorithm(SHA512);
 
+       /* We _must_ have HMAC */
+       evp_hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+       if (evp_hmac == NULL) {
+               ERR_clear_error();
+               FATAL_ERROR("OpenSSL failed to find an HMAC implementation. "
+                           "Please make sure the default provider has an "
+                           "EVP_MAC-HMAC implementation");
+       }
+
        return ISC_R_SUCCESS;
 }
 
@@ -63,10 +121,207 @@ unregister_algorithms(void) {
                        isc__crypto_md[i] = NULL;
                }
        }
+
+       INSIST(evp_hmac != NULL);
+       EVP_MAC_free(evp_hmac);
+       evp_hmac = NULL;
 }
 
 #undef md_register_algorithm
 
+/*
+ * HMAC
+ */
+
+/*
+ * Do not call EVP_Q_mac or HMAC (since it calls EVP_Q_mac internally)
+ *
+ * Each invocation of the EVP_Q_mac function causes an explicit fetch.
+ */
+isc_result_t
+isc_hmac(isc_md_type_t type, const void *key, const size_t keylen,
+        const unsigned char *buf, const size_t len, unsigned char *digest,
+        unsigned int *digestlen) {
+       EVP_MAC_CTX *ctx;
+       size_t maclen;
+
+       REQUIRE(type < ISC_MD_MAX);
+
+       if (isc__crypto_md[type] == NULL) {
+               return ISC_R_NOTIMPLEMENTED;
+       }
+
+       ctx = EVP_MAC_CTX_new(evp_hmac);
+       RUNTIME_CHECK(ctx != NULL);
+
+       if (EVP_MAC_init(ctx, key, keylen, md_to_hmac_params[type]) != 1) {
+               goto fail;
+       }
+
+       if (EVP_MAC_update(ctx, buf, len) != 1) {
+               goto fail;
+       }
+
+       maclen = *digestlen;
+       if (EVP_MAC_final(ctx, digest, &maclen, maclen) != 1) {
+               goto fail;
+       }
+
+       *digestlen = maclen;
+
+       EVP_MAC_CTX_free(ctx);
+       return ISC_R_SUCCESS;
+
+fail:
+       ERR_clear_error();
+       EVP_MAC_CTX_free(ctx);
+       return ISC_R_CRYPTOFAILURE;
+}
+
+/*
+ * You do not need to process the key to fit the block size.
+ *
+ * https://github.com/openssl/openssl/blob/925e4fba1098036e8f8d22652cff6f64c5c7d571/crypto/hmac/hmac.c#L61-L80
+ */
+isc_result_t
+isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len,
+                   isc_mem_t *mctx, isc_hmac_key_t **keyp) {
+       isc_hmac_key_t *key;
+       uint8_t digest[ISC_MAX_MD_SIZE];
+       unsigned int digest_len = sizeof(digest);
+       size_t key_len;
+
+       REQUIRE(keyp != NULL && *keyp == NULL);
+       REQUIRE(type < ISC_MD_MAX);
+
+       if (isc__crypto_md[type] == NULL) {
+               return ISC_R_NOTIMPLEMENTED;
+       }
+
+       if (len > (size_t)EVP_MD_block_size(isc__crypto_md[type])) {
+               RETERR(isc_md(type, secret, len, digest, &digest_len));
+               secret = digest;
+               key_len = digest_len;
+       } else {
+               key_len = len;
+       }
+
+       key = isc_mem_get(mctx, STRUCT_FLEX_SIZE(key, secret, key_len));
+       *key = (isc_hmac_key_t){
+               .magic = hmac_key_magic,
+               .len = key_len,
+               .params = md_to_hmac_params[type],
+       };
+       memmove(key->secret, secret, key_len);
+       isc_mem_attach(mctx, &key->mctx);
+
+       *keyp = key;
+
+       return ISC_R_SUCCESS;
+}
+
+void
+isc_hmac_key_destroy(isc_hmac_key_t **keyp) {
+       isc_hmac_key_t *key;
+
+       REQUIRE(keyp != NULL && *keyp != NULL);
+       REQUIRE((*keyp)->magic == hmac_key_magic);
+
+       key = *keyp;
+       *keyp = NULL;
+
+       key->magic = 0x00;
+
+       isc_safe_memwipe(key->secret, key->len);
+       isc_mem_putanddetach(&key->mctx, key,
+                            STRUCT_FLEX_SIZE(key, secret, key->len));
+}
+
+isc_region_t
+isc_hmac_key_expose(isc_hmac_key_t *key) {
+       REQUIRE(key != NULL && key->magic == hmac_key_magic);
+
+       return (isc_region_t){ .base = key->secret, .length = key->len };
+}
+
+bool
+isc_hmac_key_equal(isc_hmac_key_t *a, isc_hmac_key_t *b) {
+       REQUIRE(a != NULL && a->magic == hmac_key_magic);
+       REQUIRE(b != NULL && b->magic == hmac_key_magic);
+
+       if (a->params != b->params) {
+               return false;
+       }
+
+       if (a->len != b->len) {
+               return false;
+       }
+
+       return isc_safe_memequal(a->secret, b->secret, a->len);
+}
+
+isc_hmac_t *
+isc_hmac_new(void) {
+       EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(evp_hmac);
+       RUNTIME_CHECK(ctx != NULL);
+       return ctx;
+}
+
+void
+isc_hmac_free(isc_hmac_t *hmac) {
+       EVP_MAC_CTX_free(hmac);
+}
+
+isc_result_t
+isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key) {
+       REQUIRE(key != NULL && key->magic == hmac_key_magic);
+       REQUIRE(hmac != NULL);
+
+       if (EVP_MAC_init(hmac, key->secret, key->len, key->params) != 1) {
+               ERR_clear_error();
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len) {
+       REQUIRE(hmac != NULL);
+
+       if (buf == NULL || len == 0) {
+               return ISC_R_SUCCESS;
+       }
+
+       if (EVP_MAC_update(hmac, buf, len) != 1) {
+               ERR_clear_error();
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out) {
+       size_t len;
+
+       REQUIRE(hmac != NULL);
+
+       len = isc_buffer_availablelength(out);
+       if (len < EVP_MAC_CTX_get_mac_size(hmac)) {
+               return ISC_R_NOSPACE;
+       }
+
+       if (EVP_MAC_final(hmac, isc_buffer_used(out), &len, len) != 1) {
+               ERR_clear_error();
+               return ISC_R_CRYPTOFAILURE;
+       }
+
+       isc_buffer_add(out, len);
+
+       return ISC_R_SUCCESS;
+}
+
 #if ISC_MEM_TRACKLINES
 /*
  * We use the internal isc__mem API here, so we can pass the file and line
diff --git a/lib/isc/hmac.c b/lib/isc/hmac.c
deleted file mode 100644 (file)
index 05134cc..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/opensslv.h>
-
-#include <isc/assertions.h>
-#include <isc/hmac.h>
-#include <isc/md.h>
-#include <isc/safe.h>
-#include <isc/string.h>
-#include <isc/types.h>
-#include <isc/util.h>
-
-#include "crypto/crypto_p.h"
-#include "openssl_shim.h"
-
-isc_hmac_t *
-isc_hmac_new(void) {
-       EVP_MD_CTX *hmac_st = EVP_MD_CTX_new();
-       RUNTIME_CHECK(hmac_st != NULL);
-       return (isc_hmac_t *)hmac_st;
-}
-
-void
-isc_hmac_free(isc_hmac_t *hmac_st) {
-       if (hmac_st == NULL) {
-               return;
-       }
-
-       EVP_MD_CTX_free((EVP_MD_CTX *)hmac_st);
-}
-
-isc_result_t
-isc_hmac_init(isc_hmac_t *hmac_st, const void *key, const size_t keylen,
-             isc_md_type_t type) {
-       EVP_PKEY *pkey;
-       EVP_MD *md;
-
-       REQUIRE(hmac_st != NULL);
-       REQUIRE(key != NULL);
-       REQUIRE(keylen <= INT_MAX);
-       REQUIRE(type < ISC_MD_MAX);
-
-       md = isc__crypto_md[type];
-       if (md == NULL) {
-               return ISC_R_NOTIMPLEMENTED;
-       }
-
-       pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, keylen);
-       if (pkey == NULL) {
-               ERR_clear_error();
-               return ISC_R_CRYPTOFAILURE;
-       }
-
-       if (EVP_DigestSignInit(hmac_st, NULL, md, NULL, pkey) != 1) {
-               EVP_PKEY_free(pkey);
-               ERR_clear_error();
-               return ISC_R_CRYPTOFAILURE;
-       }
-
-       EVP_PKEY_free(pkey);
-
-       return ISC_R_SUCCESS;
-}
-
-isc_result_t
-isc_hmac_reset(isc_hmac_t *hmac_st) {
-       REQUIRE(hmac_st != NULL);
-
-       if (EVP_MD_CTX_reset(hmac_st) != 1) {
-               ERR_clear_error();
-               return ISC_R_CRYPTOFAILURE;
-       }
-
-       return ISC_R_SUCCESS;
-}
-
-isc_result_t
-isc_hmac_update(isc_hmac_t *hmac_st, const unsigned char *buf,
-               const size_t len) {
-       REQUIRE(hmac_st != NULL);
-
-       if (buf == NULL || len == 0) {
-               return ISC_R_SUCCESS;
-       }
-
-       if (EVP_DigestSignUpdate(hmac_st, buf, len) != 1) {
-               ERR_clear_error();
-               return ISC_R_CRYPTOFAILURE;
-       }
-
-       return ISC_R_SUCCESS;
-}
-
-isc_result_t
-isc_hmac_final(isc_hmac_t *hmac_st, unsigned char *digest,
-              unsigned int *digestlen) {
-       REQUIRE(hmac_st != NULL);
-       REQUIRE(digest != NULL);
-       REQUIRE(digestlen != NULL);
-
-       size_t len = *digestlen;
-
-       if (EVP_DigestSignFinal(hmac_st, digest, &len) != 1) {
-               ERR_clear_error();
-               return ISC_R_CRYPTOFAILURE;
-       }
-
-       *digestlen = (unsigned int)len;
-
-       return ISC_R_SUCCESS;
-}
-
-size_t
-isc_hmac_get_size(isc_hmac_t *hmac_st) {
-       REQUIRE(hmac_st != NULL);
-
-       return (size_t)EVP_MD_CTX_size(hmac_st);
-}
-
-int
-isc_hmac_get_block_size(isc_hmac_t *hmac_st) {
-       REQUIRE(hmac_st != NULL);
-
-       return EVP_MD_CTX_block_size(hmac_st);
-}
-
-isc_result_t
-isc_hmac(isc_md_type_t type, const void *key, const size_t keylen,
-        const unsigned char *buf, const size_t len, unsigned char *digest,
-        unsigned int *digestlen) {
-       isc_result_t res;
-       isc_hmac_t *hmac_st = isc_hmac_new();
-
-       res = isc_hmac_init(hmac_st, key, keylen, type);
-       if (res != ISC_R_SUCCESS) {
-               goto end;
-       }
-
-       res = isc_hmac_update(hmac_st, buf, len);
-       if (res != ISC_R_SUCCESS) {
-               goto end;
-       }
-
-       res = isc_hmac_final(hmac_st, digest, digestlen);
-       if (res != ISC_R_SUCCESS) {
-               goto end;
-       }
-end:
-       isc_hmac_free(hmac_st);
-
-       return res;
-}
index ecfc6e279c2932c2b1d0faa610c8cebf5fb421b1..06f0893f98597a662416f86e92ff10904a1994f4 100644 (file)
 
 #pragma once
 
+#include <stdbool.h>
+
 #include <isc/md.h>
 #include <isc/result.h>
 #include <isc/types.h>
 
 typedef void isc_hmac_t;
 
+typedef struct isc_hmac_key isc_hmac_key_t;
+
 /**
  * isc_hmac:
  * @type: the digest type
@@ -47,6 +51,46 @@ isc_hmac(isc_md_type_t type, const void *key, const size_t keylen,
         const unsigned char *buf, const size_t len, unsigned char *digest,
         unsigned int *digestlen);
 
+/*
+ * isc_hmac_key_create:
+ * @type: the digest type
+ * @secret: the secret key
+ * @len: length of the secret key
+ * @mctx: memory context
+ * @keyp: pointer to the key pointer
+ *
+ * This initializes the an HMAC key bound to a specific digest.
+ */
+isc_result_t
+isc_hmac_key_create(isc_md_type_t type, const void *secret, const size_t len,
+                   isc_mem_t *mctx, isc_hmac_key_t **keyp);
+
+void
+isc_hmac_key_destroy(isc_hmac_key_t **keyp);
+
+/**
+ * isc_hmac_key_expose:
+ * @key: The key to be exposed
+ *
+ * This function exposes the raw bytes of the HMAC key.
+ *
+ * The region is bound to the lifetime of the @key and MUST NOT be used after
+ * calling isc_hmac_key_destroy.
+ */
+isc_region_t
+isc_hmac_key_expose(isc_hmac_key_t *key);
+
+/**
+ * isc_hmac_key_equal:
+ * @key1: The first key to be compared
+ * @key2: The second key to be compared
+ *
+ * Returns true is the two HMAC keys have the same contents and use the same
+ * digest function.
+ */
+bool
+isc_hmac_key_equal(isc_hmac_key_t *key1, isc_hmac_key_t *key2);
+
 /**
  * isc_hmac_new:
  *
@@ -68,26 +112,11 @@ isc_hmac_free(isc_hmac_t *hmac);
  * isc_hmac_init:
  * @md: HMAC context
  * @key: HMAC key
- * @keylen: HMAC key length
- * @type: digest type
  *
- * This function sets up HMAC context to use a hash function of @type and key
- * @key which is @keylen bytes long.
+ * This function sets up HMAC context to use the secret specified in @key.
  */
-
 isc_result_t
-isc_hmac_init(isc_hmac_t *hmac, const void *key, const size_t keylen,
-             isc_md_type_t type);
-
-/**
- * isc_hmac_reset:
- * @hmac: HMAC context
- *
- * This function resets the HMAC context.  This can be used to reuse an already
- * existing context.
- */
-isc_result_t
-isc_hmac_reset(isc_hmac_t *hmac);
+isc_hmac_init(isc_hmac_t *hmac, isc_hmac_key_t *key);
 
 /**
  * isc_hmac_update:
@@ -104,34 +133,13 @@ isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len);
 /**
  * isc_hmac_final:
  * @hmac: HMAC context
- * @digest: the output buffer
- * @digestlen: in: the length of @digest
- *             out: the length of the data written to @digest
+ * @out: the output buffer
  *
  * This function retrieves the message authentication code from @hmac and places
- * it in @digest, which must have space for the hash function output. @digestlen
- * is used to pass in the length of the digest buffer and returns the length
- * of digest written to @digest.  After calling this function no additional
- * calls to isc_hmac_update() can be made.
- */
-isc_result_t
-isc_hmac_final(isc_hmac_t *hmac, unsigned char *digest,
-              unsigned int *digestlen);
-
-/**
- * isc_hmac_get_size:
+ * it in @out, which must have space for the hash function output.
  *
- * This function return the size of the message digest when passed an isc_hmac_t
- * structure, i.e. the size of the hash.
+ * After calling this function no additional calls to isc_hmac_update() can be
+ * made. Use isc_hmac_init() to reset/re-initialize the context.
  */
-size_t
-isc_hmac_get_size(isc_hmac_t *hmac);
-
-/**
- * isc_hmac_get_block_size:
- *
- * This function return the block size of the message digest when passed an
- * isc_hmac_t structure.
- */
-int
-isc_hmac_get_block_size(isc_hmac_t *hmac);
+isc_result_t
+isc_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out);
index 645ff469cf527f816fb35dd6ad1cd9cbb1eb3679..0836490f02fe972f45c9967176fe940bc9c65bbb 100644 (file)
@@ -88,7 +88,6 @@ isc_srcset.add(
         'helper.c',
         'hex.c',
         'histo.c',
-        'hmac.c',
         'ht.c',
         'httpd.c',
         'interfaceiter.c',
index 0245d6041b46817c6c347553ed3e704fd1bb47be..31797f7e448a062389ee6e003b8e2da08268786d 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-/*
- * As a workaround, include an OpenSSL header file before including cmocka.h,
- * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
- * redefined malloc in cmocka.h.
- */
-#include <openssl/err.h>
-
 #define UNIT_TESTING
 #include <cmocka.h>
 
 #include <isc/region.h>
 #include <isc/result.h>
 
-#include "hmac.c"
-
 #include <tests/isc.h>
 
 #define TEST_INPUT(x) (x), sizeof(x) - 1
 
-static int
-_setup(void **state) {
+ISC_SETUP_TEST_IMPL(hmac_state) {
        isc_hmac_t *hmac_st = isc_hmac_new();
        if (hmac_st == NULL) {
                return -1;
@@ -69,9 +59,7 @@ _reset(void **state) {
        if (*state == NULL) {
                return -1;
        }
-       if (isc_hmac_reset(*state) != ISC_R_SUCCESS) {
-               return -1;
-       }
+
        return 0;
 }
 
@@ -96,11 +84,16 @@ static void
 isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen,
              isc_md_type_t type, const char *buf, size_t buflen,
              const char *result, const size_t repeats) {
+       isc_hmac_key_t *hkey = NULL;
        isc_result_t res;
 
+       assert_int_equal(
+               isc_hmac_key_create(type, key, keylen, isc_g_mctx, &hkey),
+               ISC_R_SUCCESS);
        assert_non_null(hmac_st);
-       assert_int_equal(isc_hmac_init(hmac_st, key, keylen, type),
-                        ISC_R_SUCCESS);
+
+       res = isc_hmac_init(hmac_st, hkey);
+       assert_return_code(res, ISC_R_SUCCESS);
 
        for (size_t i = 0; i < repeats; i++) {
                assert_int_equal(isc_hmac_update(hmac_st,
@@ -109,14 +102,16 @@ isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen,
                                 ISC_R_SUCCESS);
        }
 
-       unsigned char digest[ISC_MAX_MD_SIZE];
-       unsigned int digestlen = sizeof(digest);
-       assert_int_equal(isc_hmac_final(hmac_st, digest, &digestlen),
-                        ISC_R_SUCCESS);
+       unsigned char raw_digest[ISC_MAX_MD_SIZE];
+       isc_buffer_t digest;
+
+       isc_buffer_init(&digest, raw_digest, sizeof(raw_digest));
+       assert_int_equal(isc_hmac_final(hmac_st, &digest), ISC_R_SUCCESS);
 
        char hexdigest[ISC_MAX_MD_SIZE * 2 + 3];
-       isc_region_t r = { .base = digest, .length = digestlen };
+       isc_region_t r;
        isc_buffer_t b;
+       isc_buffer_usedregion(&digest, &r);
        isc_buffer_init(&b, hexdigest, sizeof(hexdigest));
 
        res = isc_hex_totext(&r, 0, "", &b);
@@ -124,106 +119,86 @@ isc_hmac_test(isc_hmac_t *hmac_st, const void *key, size_t keylen,
        assert_return_code(res, ISC_R_SUCCESS);
 
        assert_memory_equal(hexdigest, result, result ? strlen(result) : 0);
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+
+       isc_hmac_key_destroy(&hkey);
 }
 
-ISC_RUN_TEST_IMPL(isc_hmac_init) {
-       isc_hmac_t *hmac_st = *state;
-       assert_non_null(hmac_st);
+ISC_RUN_TEST_IMPL(isc_hmac_key_create) {
+       isc_hmac_key_t *key = NULL;
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_UNKNOWN),
-                        ISC_R_NOTIMPLEMENTED);
+       assert_int_equal(
+               isc_hmac_key_create(ISC_MD_UNKNOWN, "", 0, isc_g_mctx, &key),
+               ISC_R_NOTIMPLEMENTED);
 
        if (!isc_crypto_fips_mode()) {
-               expect_assert_failure(isc_hmac_init(NULL, "", 0, ISC_MD_MD5));
-
-               expect_assert_failure(
-                       isc_hmac_init(hmac_st, NULL, 0, ISC_MD_MD5));
+               /*
+               expect_assert_failure(isc_hmac_key_create(ISC_MD_MD5, NULL, 0,
+                                                         isc_g_mctx, &key));
+               */
 
-               assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_MD5),
+               assert_int_equal(isc_hmac_key_create(ISC_MD_MD5, "", 0,
+                                                    isc_g_mctx, &key),
                                 ISC_R_SUCCESS);
-               assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+               isc_hmac_key_destroy(&key);
        }
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA1),
-                        ISC_R_SUCCESS);
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+       assert_int_equal(
+               isc_hmac_key_create(ISC_MD_SHA1, "", 0, isc_g_mctx, &key),
+               ISC_R_SUCCESS);
+       isc_hmac_key_destroy(&key);
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA224),
-                        ISC_R_SUCCESS);
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+       assert_int_equal(
+               isc_hmac_key_create(ISC_MD_SHA224, "", 0, isc_g_mctx, &key),
+               ISC_R_SUCCESS);
+       isc_hmac_key_destroy(&key);
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA256),
-                        ISC_R_SUCCESS);
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+       assert_int_equal(
+               isc_hmac_key_create(ISC_MD_SHA256, "", 0, isc_g_mctx, &key),
+               ISC_R_SUCCESS);
+       isc_hmac_key_destroy(&key);
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA384),
-                        ISC_R_SUCCESS);
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+       assert_int_equal(
+               isc_hmac_key_create(ISC_MD_SHA384, "", 0, isc_g_mctx, &key),
+               ISC_R_SUCCESS);
+       isc_hmac_key_destroy(&key);
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512),
-                        ISC_R_SUCCESS);
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
+       assert_int_equal(
+               isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key),
+               ISC_R_SUCCESS);
+       isc_hmac_key_destroy(&key);
 }
 
 ISC_RUN_TEST_IMPL(isc_hmac_update) {
        isc_hmac_t *hmac_st = *state;
        assert_non_null(hmac_st);
 
-       /* Uses message digest context initialized in isc_hmac_init_test() */
-       expect_assert_failure(isc_hmac_update(NULL, NULL, 0));
-
        assert_int_equal(isc_hmac_update(hmac_st, NULL, 100), ISC_R_SUCCESS);
        assert_int_equal(isc_hmac_update(hmac_st, (const unsigned char *)"", 0),
                         ISC_R_SUCCESS);
 }
 
-ISC_RUN_TEST_IMPL(isc_hmac_reset) {
+ISC_RUN_TEST_IMPL(isc_hmac_final) {
+       isc_hmac_key_t *key = NULL;
        isc_hmac_t *hmac_st = *state;
-#if 0
-       unsigned char digest[ISC_MAX_MD_SIZE] ISC_ATTR_UNUSED;
-       unsigned int digestlen ISC_ATTR_UNUSED;
-#endif /* if 0 */
-
        assert_non_null(hmac_st);
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512),
-                        ISC_R_SUCCESS);
-       assert_int_equal(
-               isc_hmac_update(hmac_st, (const unsigned char *)"a", 1),
-               ISC_R_SUCCESS);
        assert_int_equal(
-               isc_hmac_update(hmac_st, (const unsigned char *)"b", 1),
+               isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key),
                ISC_R_SUCCESS);
 
-       assert_int_equal(isc_hmac_reset(hmac_st), ISC_R_SUCCESS);
-
-#if 0
-       /*
-        * This test would require OpenSSL compiled with mock_assert(),
-        * so this could be only manually checked that the test will
-        * segfault when called by hand
-        */
-       expect_assert_failure(isc_hmac_final(hmac_st, digest, &digestlen));
-#endif /* if 0 */
-}
-
-ISC_RUN_TEST_IMPL(isc_hmac_final) {
-       isc_hmac_t *hmac_st = *state;
-       assert_non_null(hmac_st);
-
        unsigned char digest[ISC_MAX_MD_SIZE];
-       unsigned int digestlen = sizeof(digest);
+       isc_buffer_t digestbuf;
 
-       /* Fail when message digest context is empty */
-       expect_assert_failure(isc_hmac_final(NULL, digest, &digestlen));
        /* Fail when output buffer is empty */
-       expect_assert_failure(isc_hmac_final(hmac_st, NULL, &digestlen));
+       isc_buffer_init(&digestbuf, NULL, 0);
+       assert_int_equal(isc_hmac_final(hmac_st, &digestbuf), ISC_R_NOSPACE);
 
-       assert_int_equal(isc_hmac_init(hmac_st, "", 0, ISC_MD_SHA512),
-                        ISC_R_SUCCESS);
-       /* Fail when the digest length pointer is empty */
-       expect_assert_failure(isc_hmac_final(hmac_st, digest, NULL));
+       /* Fail when the digest length is empty */
+       assert_int_equal(isc_hmac_init(hmac_st, key), ISC_R_SUCCESS);
+       isc_buffer_init(&digestbuf, digest, 0);
+       assert_int_equal(isc_hmac_final(hmac_st, &digestbuf), ISC_R_NOSPACE);
+
+       isc_hmac_key_destroy(&key);
 }
 
 ISC_RUN_TEST_IMPL(isc_hmac_md5) {
@@ -919,10 +894,7 @@ ISC_RUN_TEST_IMPL(isc_hmac_sha512) {
 ISC_TEST_LIST_START
 
 ISC_TEST_ENTRY(isc_hmac_new)
-ISC_TEST_ENTRY_CUSTOM(isc_hmac_init, _reset, _reset)
-
-ISC_TEST_ENTRY_CUSTOM(isc_hmac_reset, _reset, _reset)
-
+ISC_TEST_ENTRY(isc_hmac_key_create)
 ISC_TEST_ENTRY(isc_hmac_md5)
 ISC_TEST_ENTRY(isc_hmac_sha1)
 ISC_TEST_ENTRY(isc_hmac_sha224)
@@ -937,4 +909,4 @@ ISC_TEST_ENTRY(isc_hmac_free)
 
 ISC_TEST_LIST_END
 
-ISC_TEST_MAIN_CUSTOM(_setup, _teardown)
+ISC_TEST_MAIN_CUSTOM(setup_test_hmac_state, _teardown)