Skip to content

Commit

Permalink
EVP_PKEY_CTX_ctrl_str w/ HKDF
Browse files Browse the repository at this point in the history
  • Loading branch information
justsmth committed Sep 13, 2024
1 parent b298c65 commit 60ca7c3
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 1 deletion.
103 changes: 103 additions & 0 deletions crypto/fipsmodule/evp/evp_ctx_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <openssl/ec_key.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/rsa.h>

#include "../../internal.h"
Expand Down Expand Up @@ -236,3 +237,105 @@ TEST_F(EvpPkeyCtxCtrlStrTest, DhPad) {

// There is no function to retrieve the DH pad value.
}

static const char *hkdf_hexsalt = "000102030405060708090a0b0c";
static const char *hkdf_hexinfo = "f0f1f2f3f4f5f6f7f8f9";
static const char *hkdf_hexkey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
static const char *hkdf_hex_expected_okm =
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5"
"b887185865";
static const char *hkdf_hex_expected_prk =
"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5";

TEST_F(EvpPkeyCtxCtrlStrTest, HkdfHex) {
// Test Cases from RFC 5869.

bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "mode", "EXTRACT_AND_EXPAND"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "md", "SHA256"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexsalt", hkdf_hexsalt), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexinfo", hkdf_hexinfo), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexkey", hkdf_hexkey), 1);

size_t okm_len;
bssl::UniquePtr<uint8_t> expected_okm(
OPENSSL_hexstr2buf(hkdf_hex_expected_okm, &okm_len));
ASSERT_TRUE(expected_okm);

bssl::UniquePtr<uint8_t> actual_okm(
static_cast<uint8_t *>(OPENSSL_zalloc(okm_len)));
ASSERT_TRUE(actual_okm);

ASSERT_TRUE(EVP_PKEY_derive(ctx.get(), actual_okm.get(), &okm_len));

ASSERT_EQ(OPENSSL_memcmp(actual_okm.get(), expected_okm.get(), okm_len), 0);
}

TEST_F(EvpPkeyCtxCtrlStrTest, HkdfRaw) {
// Test Cases from RFC 5869.

bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "mode", "EXTRACT_AND_EXPAND"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "md", "SHA256"), 1);

// The salt in the KAT contains a 0-byte so "salt" cannot be used.
ASSERT_EQ(
EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexsalt", "000102030405060708090a0b0c"),
1);

size_t _len;
bssl::UniquePtr<uint8_t> info(OPENSSL_hexstr2buf(hkdf_hexinfo, &_len));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "info",
reinterpret_cast<const char *>(info.get())),
1);
bssl::UniquePtr<uint8_t> key(OPENSSL_hexstr2buf(hkdf_hexkey, &_len));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "key",
reinterpret_cast<const char *>(key.get())),
1);

size_t okm_len;
bssl::UniquePtr<uint8_t> expected_okm(
OPENSSL_hexstr2buf(hkdf_hex_expected_okm, &okm_len));
ASSERT_TRUE(expected_okm);

bssl::UniquePtr<uint8_t> actual_okm(
static_cast<uint8_t *>(OPENSSL_zalloc(okm_len)));
ASSERT_TRUE(actual_okm);

ASSERT_TRUE(EVP_PKEY_derive(ctx.get(), actual_okm.get(), &okm_len));

ASSERT_EQ(OPENSSL_memcmp(actual_okm.get(), expected_okm.get(), okm_len), 0);
}

TEST_F(EvpPkeyCtxCtrlStrTest, HkdfExtract) {
// Test Cases from RFC 5869.

bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "mode", "EXTRACT_ONLY"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "md", "SHA256"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexsalt", hkdf_hexsalt), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexinfo", hkdf_hexinfo), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexkey", hkdf_hexkey), 1);

size_t prk_len;
bssl::UniquePtr<uint8_t> expected_prk(
OPENSSL_hexstr2buf(hkdf_hex_expected_prk, &prk_len));
ASSERT_TRUE(expected_prk);

bssl::UniquePtr<uint8_t> actual_prk(
static_cast<uint8_t *>(OPENSSL_zalloc(prk_len)));
ASSERT_TRUE(actual_prk);

ASSERT_TRUE(EVP_PKEY_derive(ctx.get(), actual_prk.get(), &prk_len));

ASSERT_EQ(OPENSSL_memcmp(actual_prk.get(), expected_prk.get(), prk_len), 0);
}
81 changes: 80 additions & 1 deletion crypto/fipsmodule/evp/p_hkdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,85 @@ static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
}
}

static int pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (strcmp(type, "mode") == 0) {
int mode;

if (strcmp(value, "EXTRACT_AND_EXPAND") == 0) {
mode = EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND;
} else if (strcmp(value, "EXTRACT_ONLY") == 0) {
mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY;
} else if (strcmp(value, "EXPAND_ONLY") == 0) {
mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY;
} else {
return 0;
}

return EVP_PKEY_CTX_hkdf_mode(ctx, mode);
}

if (strcmp(type, "md") == 0) {
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_HKDF_MD,
value);
OPENSSL_END_ALLOW_DEPRECATED
}

if (strcmp(type, "salt") == 0) {
// What if the salt contains a 0-byte?
const size_t saltlen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_set1_hkdf_salt(ctx, (const uint8_t *)value, saltlen);
}

if (strcmp(type, "hexsalt") == 0) {
size_t hex_saltlen = 0;
uint8_t *salt = OPENSSL_hexstr2buf(value, &hex_saltlen);
if (salt == NULL) {
return -2;
}
int result = EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, hex_saltlen);
OPENSSL_free(salt);
return result;
}

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_set1_hkdf_key(ctx, (const uint8_t *)value, keylen);
}

if (strcmp(type, "hexkey") == 0) {
size_t hex_keylen = 0;
uint8_t *key = OPENSSL_hexstr2buf(value, &hex_keylen);
if (key == NULL) {
return -2;
}
int result = EVP_PKEY_CTX_set1_hkdf_key(ctx, key, hex_keylen);
OPENSSL_free(key);
return result;
}

if (strcmp(type, "info") == 0) {
// What if info contains a 0-byte?
const size_t infolen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_add1_hkdf_info(ctx, (const uint8_t *)value, infolen);
}

if (strcmp(type, "hexinfo") == 0) {
size_t hex_infolen = 0;
uint8_t *info = OPENSSL_hexstr2buf(value, &hex_infolen);
if (info == NULL) {
return -2;
}
int result = EVP_PKEY_CTX_add1_hkdf_info(ctx, info, hex_infolen);
OPENSSL_free(info);
return result;
}

return -2;
}

DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hkdf_pkey_meth) {
out->pkey_id = EVP_PKEY_HKDF;
out->init = pkey_hkdf_init;
Expand All @@ -197,7 +276,7 @@ DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hkdf_pkey_meth) {
out->derive = pkey_hkdf_derive;
out->paramgen = NULL; /* paramgen */
out->ctrl = pkey_hkdf_ctrl;
out->ctrl_str = NULL;
out->ctrl_str = pkey_hkdf_ctrl_str;
}

int EVP_PKEY_CTX_hkdf_mode(EVP_PKEY_CTX *ctx, int mode) {
Expand Down

0 comments on commit 60ca7c3

Please sign in to comment.