mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 08:09:59 -04:00
Separate isc_hmac between pre and post OpenSSL 3.0
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.
This commit is contained in:
parent
f9ec4a1cdf
commit
8f106f2b66
8 changed files with 618 additions and 395 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)) { \
|
||||
|
|
@ -130,23 +130,20 @@
|
|||
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;
|
||||
isc_result_t r;
|
||||
|
||||
REQUIRE(ctx != NULL);
|
||||
unsigned char digest[ISC_MAX_MD_SIZE];
|
||||
unsigned int digestlen = sizeof(digest);
|
||||
|
||||
if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
|
||||
return DST_R_OPENSSLFAILURE;
|
||||
r = isc_hmac_final(ctx, sig);
|
||||
|
||||
/* Turn CRYPTOFAILURE into OPENSSLFAILURE */
|
||||
if (r == ISC_R_CRYPTOFAILURE) {
|
||||
r = DST_R_OPENSSLFAILURE;
|
||||
}
|
||||
|
||||
if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
|
||||
return DST_R_OPENSSLFAILURE;
|
||||
}
|
||||
|
||||
if (isc_buffer_availablelength(sig) < digestlen) {
|
||||
return ISC_R_NOSPACE;
|
||||
}
|
||||
|
||||
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) {
|
||||
isc_buffer_init(&hmac, digest, sizeof(digest));
|
||||
|
||||
if (isc_hmac_final(ctx, &hmac) != ISC_R_SUCCESS) {
|
||||
return DST_R_OPENSSLFAILURE;
|
||||
}
|
||||
|
||||
if (isc_hmac_reset(ctx) != 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) {
|
||||
REQUIRE(key != NULL && key->keydata.hmac_key != NULL);
|
||||
dst_hmac_key_t *hkey = key->keydata.hmac_key;
|
||||
unsigned int bytes;
|
||||
isc_region_t raw_key;
|
||||
|
||||
bytes = (key->key_size + 7) / 8;
|
||||
if (isc_buffer_availablelength(data) < bytes) {
|
||||
REQUIRE(key != NULL && key->keydata.hmac_key != NULL);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,21 +11,37 @@
|
|||
* 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:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
* 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>
|
||||
|
|
@ -18,19 +22,64 @@
|
|||
#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
|
||||
|
|
|
|||
165
lib/isc/hmac.c
165
lib/isc/hmac.c
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -18,12 +18,16 @@
|
|||
|
||||
#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.
|
||||
*/
|
||||
|
||||
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.
|
||||
* This function sets up HMAC context to use the secret specified in @key.
|
||||
*/
|
||||
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.
|
||||
* it in @out, which must have space for the hash function output.
|
||||
*
|
||||
* After calling this function no additional calls to isc_hmac_update() can be
|
||||
* made. Use isc_hmac_init() to reset/re-initialize the context.
|
||||
*/
|
||||
isc_result_t
|
||||
isc_hmac_final(isc_hmac_t *hmac, unsigned char *digest,
|
||||
unsigned int *digestlen);
|
||||
|
||||
/**
|
||||
* isc_hmac_get_size:
|
||||
*
|
||||
* This function return the size of the message digest when passed an isc_hmac_t
|
||||
* structure, i.e. the size of the hash.
|
||||
*/
|
||||
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_hmac_final(isc_hmac_t *hmac, isc_buffer_t *out);
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ isc_srcset.add(
|
|||
'helper.c',
|
||||
'hex.c',
|
||||
'histo.c',
|
||||
'hmac.c',
|
||||
'ht.c',
|
||||
'httpd.c',
|
||||
'interfaceiter.c',
|
||||
|
|
|
|||
|
|
@ -21,13 +21,6 @@
|
|||
#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>
|
||||
|
||||
|
|
@ -39,14 +32,11 @@
|
|||
#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_key_create(ISC_MD_MD5, NULL, 0,
|
||||
isc_g_mctx, &key));
|
||||
*/
|
||||
|
||||
expect_assert_failure(
|
||||
isc_hmac_init(hmac_st, NULL, 0, ISC_MD_MD5));
|
||||
|
||||
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_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_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_key_t *key = NULL;
|
||||
isc_hmac_t *hmac_st = *state;
|
||||
assert_non_null(hmac_st);
|
||||
|
||||
assert_int_equal(
|
||||
isc_hmac_key_create(ISC_MD_SHA512, "", 0, isc_g_mctx, &key),
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue