From 5b800192f2f9b7b0d3a8add2117fb1ecdd029684 Mon Sep 17 00:00:00 2001 From: Daniel Van Geest Date: Sun, 13 Apr 2025 01:49:09 +0100 Subject: [PATCH] Expand gettable params for HKDF Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/27365) --- providers/implementations/kdfs/hkdf.c | 53 ++++++++++++++++++++++++++- test/evp_kdf_test.c | 50 +++++++++++++++++++++---- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index d6dfcb78b3e..f1d4a44f67f 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -32,6 +32,7 @@ #include "prov/securitycheck.h" #include "internal/e_os.h" #include "internal/params.h" +#include "internal/sizes.h" #define HKDF_MAXBUF 2048 #define HKDF_MAXINFO (32*1024) @@ -74,9 +75,16 @@ static int HKDF_Expand(const EVP_MD *evp_md, OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), \ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0) -/* Gettable context parameters that are common across HKDF and the TLS KDF */ +/* + * Gettable context parameters that are common across HKDF and the TLS KDF. + * OSSL_KDF_PARAM_KEY is not gettable because it is a secret value. + */ #define HKDF_COMMON_GETTABLES \ OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), \ + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), \ + OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL), \ + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), \ + OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), \ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0) typedef struct { @@ -373,6 +381,49 @@ static int hkdf_common_get_ctx_params(KDF_HKDF *ctx, OSSL_PARAM params[]) return 0; } + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + + if (md == NULL) + return 0; + else if (!OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(md))) + return 0; + } + + /* OSSL_KDF_PARAM_MODE has multiple parameter types, so look for all instances */ + p = params; + while ((p = OSSL_PARAM_locate(p, OSSL_KDF_PARAM_MODE)) != NULL) { + if (p->data_type == OSSL_PARAM_UTF8_STRING) { + switch (ctx->mode) { + case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: + if (!OSSL_PARAM_set_utf8_string(p, "EXTRACT_AND_EXPAND")) + return 0; + break; + case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: + if (!OSSL_PARAM_set_utf8_string(p, "EXTRACT_ONLY")) + return 0; + break; + case EVP_KDF_HKDF_MODE_EXPAND_ONLY: + if (!OSSL_PARAM_set_utf8_string(p, "EXPAND_ONLY")) + return 0; + break; + default: + return 0; + } + } else if (p->data_type == OSSL_PARAM_INTEGER) { + if (!OSSL_PARAM_set_int(p, ctx->mode)) + return 0; + } + p++; + } + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SALT)) != NULL) { + if (ctx->salt == NULL || ctx->salt_len == 0) + p->return_size = 0; + if (!OSSL_PARAM_set_octet_string(p, ctx->salt, ctx->salt_len)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_INFO)) != NULL) { if (ctx->info == NULL || ctx->info_len == 0) p->return_size = 0; diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 721b495ef09..1de2cff02a3 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -17,6 +17,7 @@ #include #include #include "internal/numbers.h" +#include "internal/sizes.h" #include "testutil.h" @@ -239,26 +240,35 @@ static int test_kdf_hkdf(void) return ret; } -static int do_kdf_hkdf_gettables(int expand_only, int has_digest) +static int do_kdf_hkdf_gettables(int extract_only, int has_digest) { int ret = 0; size_t sz = 0; OSSL_PARAM *params; - OSSL_PARAM params_get[2]; + OSSL_PARAM params_get[5]; + char digest[OSSL_MAX_NAME_SIZE]; + char mode_utf8[OSSL_MAX_NAME_SIZE]; + int mode_int = -1; + char salt[16] = { 0 }; + char info[16] = { 0 }; const OSSL_PARAM *gettables, *p; EVP_KDF_CTX *kctx = NULL; if (!TEST_ptr(params = construct_hkdf_params( has_digest ? "sha256" : NULL, "secret", 6, "salt", - expand_only ? NULL : "label")) + extract_only ? NULL : "label")) || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) || !TEST_true(EVP_KDF_CTX_set_params(kctx, params))) goto err; /* Check OSSL_KDF_PARAM_SIZE is gettable */ if (!TEST_ptr(gettables = EVP_KDF_CTX_gettable_params(kctx)) - || !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_SIZE))) + || !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_SIZE)) + || !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_MODE)) + || !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_DIGEST)) + || !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_SALT)) + || !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_INFO))) goto err; /* Get OSSL_KDF_PARAM_SIZE as a size_t */ @@ -266,13 +276,39 @@ static int do_kdf_hkdf_gettables(int expand_only, int has_digest) params_get[1] = OSSL_PARAM_construct_end(); if (has_digest) { if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1) - || !TEST_size_t_eq(sz, expand_only ? SHA256_DIGEST_LENGTH : SIZE_MAX)) + || !TEST_size_t_eq(sz, extract_only ? SHA256_DIGEST_LENGTH : SIZE_MAX)) goto err; } else { if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 0)) goto err; } + params_get[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, digest, + sizeof(digest)); + params_get[1] = OSSL_PARAM_construct_end(); + if (has_digest) { + if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1) + || !TEST_str_eq(digest, "SHA2-256")) + goto err; + } else { + if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 0)) + goto err; + } + + params_get[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MODE, mode_utf8, + sizeof(mode_utf8)); + params_get[1] = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode_int); + params_get[2] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, salt, sizeof(salt)); + params_get[3] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info, sizeof(info)); + params_get[4] = OSSL_PARAM_construct_end(); + if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1) + || !TEST_str_eq(mode_utf8, extract_only ? "EXTRACT_ONLY" : "EXTRACT_AND_EXPAND") + || !TEST_int_eq(mode_int, extract_only ? EVP_KDF_HKDF_MODE_EXTRACT_ONLY : + EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND) + || !TEST_str_eq(info, extract_only ? "" : "label") + || !TEST_str_eq(salt, "salt")) + goto err; + /* Get params returns 1 if an unsupported parameter is requested */ params_get[0] = OSSL_PARAM_construct_end(); if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1)) @@ -289,7 +325,7 @@ static int test_kdf_hkdf_gettables(void) return do_kdf_hkdf_gettables(0, 1); } -static int test_kdf_hkdf_gettables_expandonly(void) +static int test_kdf_hkdf_gettables_extractonly(void) { return do_kdf_hkdf_gettables(1, 1); } @@ -2066,7 +2102,7 @@ int setup_tests(void) ADD_TEST(test_kdf_hkdf_1byte_key); ADD_TEST(test_kdf_hkdf_empty_salt); ADD_TEST(test_kdf_hkdf_gettables); - ADD_TEST(test_kdf_hkdf_gettables_expandonly); + ADD_TEST(test_kdf_hkdf_gettables_extractonly); ADD_TEST(test_kdf_hkdf_gettables_no_digest); ADD_TEST(test_kdf_hkdf_derive_set_params_fail); ADD_TEST(test_kdf_hkdf_set_invalid_mode); -- 2.47.2