Skip to content

Commit

Permalink
Expand support for EVP_PKEY_HMAC (#1933)
Browse files Browse the repository at this point in the history
  • Loading branch information
justsmth authored Oct 28, 2024
1 parent de33f5e commit 8d9809e
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 117 deletions.
40 changes: 40 additions & 0 deletions crypto/fipsmodule/evp/evp_ctx_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <openssl/rsa.h>

#include "../../internal.h"
#include "../../test/test_util.h"
#include "internal.h"

class EvpPkeyCtxCtrlStrTest : public ::testing::Test {
Expand Down Expand Up @@ -375,3 +376,42 @@ TEST_F(EvpPkeyCtxCtrlStrTest, HkdfExtract) {

ASSERT_EQ(OPENSSL_memcmp(actual_prk.get(), expected_prk.get(), prk_len), 0);
}

static const char *hmac_hexkey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";

TEST_F(EvpPkeyCtxCtrlStrTest, HMACKey) {

bssl::UniquePtr<EVP_PKEY> pkey_hex;
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx_hex(EVP_PKEY_CTX_new_id(EVP_PKEY_HMAC, NULL));
ASSERT_TRUE(ctx_hex);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx_hex.get()));

ASSERT_NE(1, EVP_PKEY_CTX_ctrl_str(ctx_hex.get(), "hexkey", "nonsense"));
ASSERT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx_hex.get(), "hexkey", hmac_hexkey));
EVP_PKEY* my_pkey = NULL;
ASSERT_TRUE(EVP_PKEY_keygen(ctx_hex.get(), &my_pkey));
pkey_hex.reset(my_pkey);
ASSERT_TRUE(pkey_hex);
}

bssl::UniquePtr<EVP_PKEY> pkey_raw;
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx_hex(EVP_PKEY_CTX_new_id(EVP_PKEY_HMAC, NULL));
ASSERT_TRUE(ctx_hex);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx_hex.get()));

std::vector<uint8_t> raw_key;
DecodeHex(&raw_key, hmac_hexkey);
raw_key.push_back(0);
ASSERT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx_hex.get(), "key", (char*)raw_key.data()));
EVP_PKEY* my_pkey = NULL;
ASSERT_TRUE(EVP_PKEY_keygen(ctx_hex.get(), &my_pkey));
pkey_raw.reset(my_pkey);
ASSERT_TRUE(pkey_raw);
}

ASSERT_TRUE(EVP_PKEY_cmp(pkey_hex.get(), pkey_raw.get()));
}


17 changes: 12 additions & 5 deletions crypto/fipsmodule/evp/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *
#define EVP_PKEY_CTRL_DH_PAD (EVP_PKEY_ALG_CTRL + 19)
#define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN (EVP_PKEY_ALG_CTRL + 20)
#define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR (EVP_PKEY_ALG_CTRL + 21)
#define EVP_PKEY_CTRL_SET_MAC_KEY (EVP_PKEY_ALG_CTRL + 22)

// EVP_PKEY_CTX_KEYGEN_INFO_COUNT is the maximum array length for
// |EVP_PKEY_CTX->keygen_info|. The array length corresponds to the number of
Expand Down Expand Up @@ -343,16 +344,22 @@ struct evp_pkey_method_st {
// operation.
int used_for_hmac(EVP_MD_CTX *ctx);

typedef struct {
const EVP_MD *md; // MD for HMAC use.
HMAC_CTX ctx;
} HMAC_PKEY_CTX;

typedef struct {
uint8_t *key;
size_t key_len;
} HMAC_KEY;

typedef struct {
const EVP_MD *md; // MD for HMAC use.
HMAC_CTX ctx;
HMAC_KEY ktmp;
} HMAC_PKEY_CTX;

// HMAC_KEY_set copies provided key into hmac_key. It frees any existing key
// on hmac_key. It returns 1 on success, and 0 otherwise.
int HMAC_KEY_set(HMAC_KEY* hmac_key, const uint8_t* key, const size_t key_len);
// HMAC_KEY_copy allocates and a new |HMAC_KEY| with identical contents (internal use).
int HMAC_KEY_copy(HMAC_KEY* dest, HMAC_KEY* src);
// HMAC_KEY_new allocates and zeroizes a |HMAC_KEY| for internal use.
HMAC_KEY *HMAC_KEY_new(void);

Expand Down
113 changes: 98 additions & 15 deletions crypto/fipsmodule/evp/p_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ static int hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
sctx = src->data;
dctx = dst->data;
dctx->md = sctx->md;
if(sctx->ktmp.key != NULL && !HMAC_KEY_copy(&sctx->ktmp, &dctx->ktmp)) {
OPENSSL_free(dctx);
return 0;
}
if (!HMAC_CTX_copy_ex(&dctx->ctx, &sctx->ctx)) {
OPENSSL_free(dctx);
return 0;
Expand All @@ -90,19 +94,82 @@ static int hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {

static void hmac_cleanup(EVP_PKEY_CTX *ctx) {
HMAC_PKEY_CTX *hctx = ctx->data;
OPENSSL_free(hctx->ktmp.key);
OPENSSL_free(hctx);
}

static int hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
static int hmac_ctrl(EVP_PKEY_CTX *ctx, int cmd, int p1, void *p2) {
int result = -2;

HMAC_PKEY_CTX *hctx = ctx->data;
switch (type) {
switch (cmd) {
case EVP_PKEY_CTRL_SET_MAC_KEY:
if (p1 >= 0 && p1 <= INT16_MAX) {
// p1 is the key length
// p2 is the key
if (HMAC_KEY_set(&hctx->ktmp, p2, p1)) {
result = 1;
} else {
result = 0;
}
}
break;
case EVP_PKEY_CTRL_MD:
hctx->md = p2;
result = 1;
break;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
}
return result;
}

static int hmac_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (!value) {
return 0;
}
if (strcmp(type, "key") == 0) {
// What if the key contains a 0-byte?
const size_t keylen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HMAC, EVP_PKEY_OP_KEYGEN,
EVP_PKEY_CTRL_SET_MAC_KEY, keylen, (void*)value);
}
if (strcmp(type, "hexkey") == 0) {
size_t hex_keylen = 0;
uint8_t *key = OPENSSL_hexstr2buf(value, &hex_keylen);
if (key == NULL) {
return 0;
}
int result =
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HMAC, EVP_PKEY_OP_KEYGEN,
EVP_PKEY_CTRL_SET_MAC_KEY, hex_keylen, key);
OPENSSL_free(key);
return result;
}
return -2;
}

static int hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
GUARD_PTR(pkey);
HMAC_KEY *hmac = NULL;
HMAC_PKEY_CTX *hctx = ctx->data;
if(hctx == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}

if (!(hmac = HMAC_KEY_new())) {
return 0;
}

if (!HMAC_KEY_copy(hmac, &hctx->ktmp) ||
!EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hmac)) {
OPENSSL_free(hmac->key);
OPENSSL_free(hmac);
return 0;
}

return 1;
}

Expand All @@ -111,20 +178,9 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hmac_pkey_meth) {
out->init = hmac_init;
out->copy = hmac_copy;
out->cleanup = hmac_cleanup;
out->keygen = NULL;
out->sign_init = NULL;
out->sign = NULL;
out->sign_message = NULL;
out->verify_init = NULL;
out->verify = NULL;
out->verify_message = NULL;
out->verify_recover = NULL;
out->encrypt = NULL;
out->decrypt = NULL;
out->derive = NULL;
out->paramgen = NULL;
out->keygen = hmac_keygen;
out->ctrl = hmac_ctrl;
out->ctrl_str = NULL;
out->ctrl_str = hmac_ctrl_str;
}

int used_for_hmac(EVP_MD_CTX *ctx) {
Expand All @@ -138,3 +194,30 @@ HMAC_KEY *HMAC_KEY_new(void) {
}
return key;
}

int HMAC_KEY_set(HMAC_KEY* hmac_key, const uint8_t* key, const size_t key_len) {
if(hmac_key == NULL ) {
return 0;
}
if (key == NULL || key_len == 0) {
hmac_key->key = NULL;
hmac_key->key_len = 0;
return 1;
}

uint8_t* new_key = OPENSSL_memdup(key, key_len);
if(new_key == NULL) {
return 0;
}
OPENSSL_free(hmac_key->key);
hmac_key->key = new_key;
hmac_key->key_len = key_len;
return 1;
}

int HMAC_KEY_copy(HMAC_KEY* dest, HMAC_KEY* src) {
GUARD_PTR(dest);
GUARD_PTR(src);

return HMAC_KEY_set(dest, src->key, src->key_len);
}
Loading

0 comments on commit 8d9809e

Please sign in to comment.