From: Daniel Van Geest Date: Mon, 7 Apr 2025 11:21:47 +0000 (+0100) Subject: HKDF updates X-Git-Tag: openssl-3.6.0-alpha1~474 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6a1d8ea744abac1c467642dba0bbea88293ffef;p=thirdparty%2Fopenssl.git HKDF updates - prevent fixed-digest HKDF from having its digest changed - implement gettable params in HKDF - update fixed-digest HKDF tests Reviewed-by: Shane Lontis Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/27247) --- diff --git a/CHANGES.md b/CHANGES.md index 1b1b6bac2fb..666622378e7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -112,7 +112,7 @@ OpenSSL 3.6 *Dimitri John Ledkov* - * HKDF with (SHA-256,SHA-384,SHA-512) has assigned OIDs. Added ability to load + * HKDF with (SHA-256, SHA-384, SHA-512) has assigned OIDs. Added ability to load HKDF configured with these explicit digests by name or OID. *Daniel Van Geest (CryptoNext Security)* diff --git a/doc/man7/EVP_KDF-HKDF.pod b/doc/man7/EVP_KDF-HKDF.pod index bcfe01e4564..959a6f07d31 100644 --- a/doc/man7/EVP_KDF-HKDF.pod +++ b/doc/man7/EVP_KDF-HKDF.pod @@ -17,15 +17,6 @@ of the KDF). The output is considered to be keying material. -=head2 Fixed-Digest HKDF - -B, B and B are fixed-digest versions -of the B algorithm. Each algorithm has its own OID. These algorithms -are instantiated with the appropriate digest already configured, thus it is -not necessary to set the digest using the B parameter. -An attempt to set the digest to anything other than the pre-configured digest -will result in an error. - =head2 Identity The following algorithms are available for this implementation; they @@ -40,12 +31,20 @@ mere OID which came out in this form after a call to L). =item "HKDF" +The B parameter must be set for B before it can +be used. + =item "HKDF-SHA256", "id-alg-hkdf-with-sha256", "1.2.840.113549.1.9.16.3.28" =item "HKDF-SHA384", "id-alg-hkdf-with-sha384", "1.2.840.113549.1.9.16.3.29" =item "HKDF-SHA512", "id-alg-hkdf-with-sha512", "1.2.840.113549.1.9.16.3.30" +B, B and B are fixed-digest versions +of B with the appropriate digest already configured. +L will not reset the context's digest for fixed-digest +versions. + =back =head2 Supported parameters @@ -58,6 +57,8 @@ The supported parameters are: =item "digest" (B) +Attempting to set the digest on a fixed-digest B will result in an error. + =item "key" (B) =item "salt" (B) @@ -84,8 +85,9 @@ up for HKDF will perform an extract followed by an expand operation in one go. The derived key returned will be the result after the expand operation. The intermediate fixed-length pseudorandom key K is not returned. -In this mode the digest, key, salt and info values must be set before a key is -derived otherwise an error will occur. +In this mode the key, salt and info values must be set before a key is +derived otherwise an error will occur. For non-fixed mode (B) the digest +must also be set. =item "EXTRACT_ONLY" or B @@ -94,8 +96,9 @@ operation. The value returned will be the intermediate fixed-length pseudorandom key K. The I parameter must match the size of K, which can be looked up by calling EVP_KDF_CTX_get_kdf_size() after setting the mode and digest. -The digest, key and salt values must be set before a key is derived otherwise -an error will occur. +The key and salt values must be set before a key is derived otherwise +an error will occur. For non-fixed mode (B) the digest +must also be set. =item "EXPAND_ONLY" or B @@ -103,8 +106,9 @@ In this mode calling L will just perform the expand operation. The input key should be set to the intermediate fixed-length pseudorandom key K returned from a previous extract operation. -The digest, key and info values must be set before a key is derived otherwise -an error will occur. +The key and info values must be set before a key is derived otherwise +an error will occur. For non-fixed mode (B) the digest +must also be set. =back @@ -148,6 +152,8 @@ after setting the mode and digest on the B. =head1 EXAMPLES +=head2 HKDF Algorithm + This example derives 10 bytes using SHA-256 with the secret key "secret", salt value "salt" and info value "label": @@ -175,6 +181,33 @@ salt value "salt" and info value "label": EVP_KDF_CTX_free(kctx); +=head2 HKDF-SHA256 Algorithm + +This example derives 10 bytes using HKDF-SHA256 with the secret key "secret", +salt value "salt" and info value "label": + + EVP_KDF *kdf; + EVP_KDF_CTX *kctx; + unsigned char out[10]; + OSSL_PARAM params[4], *p = params; + + kdf = EVP_KDF_fetch(NULL, "HKDF-SHA256", NULL); + kctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, + "secret", (size_t)6); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, + "label", (size_t)5); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + "salt", (size_t)4); + *p = OSSL_PARAM_construct_end(); + if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) { + error("EVP_KDF_derive"); + } + + EVP_KDF_CTX_free(kctx); + =head1 CONFORMING TO RFC 5869 and RFC 8619 diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod index 79aa0ca8b9a..dbce55e3701 100644 --- a/doc/man7/OSSL_PROVIDER-FIPS.pod +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -588,7 +588,7 @@ L =head1 HISTORY -The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 digests were added in OpenSSL 3.6. +The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 algorithms were added in OpenSSL 3.6. All other functionality was added in OpenSSL 3.0. diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod index 0236b86ef76..a4021418b50 100644 --- a/doc/man7/OSSL_PROVIDER-default.pod +++ b/doc/man7/OSSL_PROVIDER-default.pod @@ -530,7 +530,7 @@ L The RIPEMD160 digest was added to the default provider in OpenSSL 3.0.7. -The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 digests were added in OpenSSL 3.6. +The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 algorithms were added in OpenSSL 3.6. All other functionality was added in OpenSSL 3.0. diff --git a/providers/defltprov.c b/providers/defltprov.c index 412737296c6..a76c7a53625 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -398,9 +398,6 @@ static const OSSL_ALGORITHM deflt_keyexch[] = { #endif { PROV_NAMES_TLS1_PRF, "provider=default", ossl_kdf_tls1_prf_keyexch_functions }, { PROV_NAMES_HKDF, "provider=default", ossl_kdf_hkdf_keyexch_functions }, - { PROV_NAMES_HKDF_SHA256, "provider=default", ossl_kdf_hkdf_sha256_keyexch_functions }, - { PROV_NAMES_HKDF_SHA384, "provider=default", ossl_kdf_hkdf_sha384_keyexch_functions }, - { PROV_NAMES_HKDF_SHA512, "provider=default", ossl_kdf_hkdf_sha512_keyexch_functions }, { PROV_NAMES_SCRYPT, "provider=default", ossl_kdf_scrypt_keyexch_functions }, { NULL, NULL, NULL } @@ -589,12 +586,6 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = { PROV_DESCS_TLS1_PRF_SIGN }, { PROV_NAMES_HKDF, "provider=default", ossl_kdf_keymgmt_functions, PROV_DESCS_HKDF_SIGN }, - { PROV_NAMES_HKDF_SHA256, "provider=default", ossl_kdf_keymgmt_functions, - PROV_DESCS_HKDF_SHA256_SIGN }, - { PROV_NAMES_HKDF_SHA384, "provider=default", ossl_kdf_keymgmt_functions, - PROV_DESCS_HKDF_SHA384_SIGN }, - { PROV_NAMES_HKDF_SHA512, "provider=default", ossl_kdf_keymgmt_functions, - PROV_DESCS_HKDF_SHA512_SIGN }, { PROV_NAMES_SCRYPT, "provider=default", ossl_kdf_keymgmt_functions, PROV_DESCS_SCRYPT_SIGN }, { PROV_NAMES_HMAC, "provider=default", ossl_mac_legacy_keymgmt_functions, diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 5a1e11c03f3..756ca874bb7 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -448,9 +448,6 @@ static const OSSL_ALGORITHM fips_keyexch[] = { { PROV_NAMES_TLS1_PRF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_tls1_prf_keyexch_functions }, { PROV_NAMES_HKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_hkdf_keyexch_functions }, - { PROV_NAMES_HKDF_SHA256, FIPS_DEFAULT_PROPERTIES, ossl_kdf_hkdf_sha256_keyexch_functions }, - { PROV_NAMES_HKDF_SHA384, FIPS_DEFAULT_PROPERTIES, ossl_kdf_hkdf_sha384_keyexch_functions }, - { PROV_NAMES_HKDF_SHA512, FIPS_DEFAULT_PROPERTIES, ossl_kdf_hkdf_sha512_keyexch_functions }, { NULL, NULL, NULL } }; @@ -618,12 +615,6 @@ static const OSSL_ALGORITHM fips_keymgmt[] = { PROV_DESCS_TLS1_PRF_SIGN }, { PROV_NAMES_HKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_keymgmt_functions, PROV_DESCS_HKDF_SIGN }, - { PROV_NAMES_HKDF_SHA256, FIPS_DEFAULT_PROPERTIES, ossl_kdf_keymgmt_functions, - PROV_DESCS_HKDF_SHA256_SIGN }, - { PROV_NAMES_HKDF_SHA384, FIPS_DEFAULT_PROPERTIES, ossl_kdf_keymgmt_functions, - PROV_DESCS_HKDF_SHA384_SIGN }, - { PROV_NAMES_HKDF_SHA512, FIPS_DEFAULT_PROPERTIES, ossl_kdf_keymgmt_functions, - PROV_DESCS_HKDF_SHA512_SIGN }, { PROV_NAMES_HMAC, FIPS_DEFAULT_PROPERTIES, ossl_mac_legacy_keymgmt_functions, PROV_DESCS_HMAC_SIGN }, #ifndef OPENSSL_NO_CMAC diff --git a/providers/implementations/exchange/kdf_exch.c b/providers/implementations/exchange/kdf_exch.c index 5e363737b0e..340a2663c58 100644 --- a/providers/implementations/exchange/kdf_exch.c +++ b/providers/implementations/exchange/kdf_exch.c @@ -79,9 +79,6 @@ err: KDF_NEWCTX(tls1_prf, "TLS1-PRF") KDF_NEWCTX(hkdf, "HKDF") -KDF_NEWCTX(hkdf_sha256, "HKDF-SHA256") -KDF_NEWCTX(hkdf_sha384, "HKDF-SHA384") -KDF_NEWCTX(hkdf_sha512, "HKDF-SHA512") KDF_NEWCTX(scrypt, "SCRYPT") static int kdf_init(void *vpkdfctx, void *vkdf, const OSSL_PARAM params[]) @@ -209,9 +206,6 @@ static const OSSL_PARAM *kdf_settable_ctx_params(ossl_unused void *vpkdfctx, KDF_SETTABLE_CTX_PARAMS(tls1_prf, "TLS1-PRF") KDF_SETTABLE_CTX_PARAMS(hkdf, "HKDF") -KDF_SETTABLE_CTX_PARAMS(hkdf_sha256, "HKDF-SHA256") -KDF_SETTABLE_CTX_PARAMS(hkdf_sha384, "HKDF-SHA384") -KDF_SETTABLE_CTX_PARAMS(hkdf_sha512, "HKDF-SHA512") KDF_SETTABLE_CTX_PARAMS(scrypt, "SCRYPT") static const OSSL_PARAM *kdf_gettable_ctx_params(ossl_unused void *vpkdfctx, @@ -240,9 +234,6 @@ static const OSSL_PARAM *kdf_gettable_ctx_params(ossl_unused void *vpkdfctx, KDF_GETTABLE_CTX_PARAMS(tls1_prf, "TLS1-PRF") KDF_GETTABLE_CTX_PARAMS(hkdf, "HKDF") -KDF_GETTABLE_CTX_PARAMS(hkdf_sha256, "HKDF-SHA256") -KDF_GETTABLE_CTX_PARAMS(hkdf_sha384, "HKDF-SHA384") -KDF_GETTABLE_CTX_PARAMS(hkdf_sha512, "HKDF-SHA512") KDF_GETTABLE_CTX_PARAMS(scrypt, "SCRYPT") #define KDF_KEYEXCH_FUNCTIONS(funcname) \ @@ -263,7 +254,4 @@ KDF_GETTABLE_CTX_PARAMS(scrypt, "SCRYPT") KDF_KEYEXCH_FUNCTIONS(tls1_prf) KDF_KEYEXCH_FUNCTIONS(hkdf) -KDF_KEYEXCH_FUNCTIONS(hkdf_sha256) -KDF_KEYEXCH_FUNCTIONS(hkdf_sha384) -KDF_KEYEXCH_FUNCTIONS(hkdf_sha512) KDF_KEYEXCH_FUNCTIONS(scrypt) diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index bfe8d8d533f..75a3364ec67 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -54,10 +54,9 @@ static OSSL_FUNC_kdf_get_ctx_params_fn kdf_tls1_3_get_ctx_params; static OSSL_FUNC_kdf_newctx_fn kdf_hkdf_sha256_new; static OSSL_FUNC_kdf_newctx_fn kdf_hkdf_sha384_new; static OSSL_FUNC_kdf_newctx_fn kdf_hkdf_sha512_new; -static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_hkdf_fixed_digest_settable_ctx_params; -static OSSL_FUNC_kdf_set_ctx_params_fn kdf_hkdf_fixed_digest_set_ctx_params; static void *kdf_hkdf_fixed_digest_new(void *provctx, const char *digest); +static void kdf_hkdf_reset_ex(void *vctx, int on_free); static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md, const unsigned char *salt, size_t salt_len, @@ -73,14 +72,12 @@ static int HKDF_Expand(const EVP_MD *evp_md, const unsigned char *info, size_t info_len, unsigned char *okm, size_t okm_len); -/* - * Settable context parameters that are common across HKDF (including - * implementations with a default digest) and the TLS KDF - */ -#define HKDF_COMMON_SETTABLES_NO_DIGEST \ +/* Settable context parameters that are common across HKDF and the TLS KDF */ +#define HKDF_COMMON_SETTABLES \ 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_PROPERTIES, NULL, 0), \ + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), \ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), \ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0) @@ -112,6 +109,7 @@ typedef struct { size_t data_len; unsigned char *info; size_t info_len; + int fixed_digest; OSSL_FIPS_IND_DECLARE } KDF_HKDF; @@ -134,17 +132,28 @@ static void kdf_hkdf_free(void *vctx) KDF_HKDF *ctx = (KDF_HKDF *)vctx; if (ctx != NULL) { - kdf_hkdf_reset(ctx); + kdf_hkdf_reset_ex(vctx, 1); OPENSSL_free(ctx); } } static void kdf_hkdf_reset(void *vctx) +{ + kdf_hkdf_reset_ex(vctx, 0); +} + +static void kdf_hkdf_reset_ex(void *vctx, int on_free) { KDF_HKDF *ctx = (KDF_HKDF *)vctx; void *provctx = ctx->provctx; - - ossl_prov_digest_reset(&ctx->digest); + int preserve_digest = on_free ? 0 : ctx->fixed_digest; + PROV_DIGEST save_prov_digest = { 0 }; + + /* For fixed digests just save and restore the PROV_DIGEST object */ + if (preserve_digest) + save_prov_digest = ctx->digest; + else + ossl_prov_digest_reset(&ctx->digest); #ifdef OPENSSL_PEDANTIC_ZEROIZATION OPENSSL_clear_free(ctx->salt, ctx->salt_len); #else @@ -157,6 +166,10 @@ static void kdf_hkdf_reset(void *vctx) OPENSSL_clear_free(ctx->info, ctx->info_len); memset(ctx, 0, sizeof(*ctx)); ctx->provctx = provctx; + if (preserve_digest) { + ctx->fixed_digest = preserve_digest; + ctx->digest = save_prov_digest; + } } static void *kdf_hkdf_dup(void *vctx) @@ -181,6 +194,7 @@ static void *kdf_hkdf_dup(void *vctx) || !ossl_prov_digest_copy(&dest->digest, &src->digest)) goto err; dest->mode = src->mode; + dest->fixed_digest = src->fixed_digest; OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -276,9 +290,15 @@ static int hkdf_common_set_ctx_params(KDF_HKDF *ctx, const OSSL_PARAM params[]) if (ossl_param_is_empty(params)) return 1; - if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) { + if ((p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST)) != NULL) { const EVP_MD *md = NULL; + if (ctx->fixed_digest) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, + "Setting the digest is not supported for fixed-digest HKDFs"); + return 0; + } + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) return 0; @@ -429,7 +449,7 @@ static int hkdf_common_get_ctx_params(KDF_HKDF *ctx, OSSL_PARAM params[]) 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)) + else if (!OSSL_PARAM_set_octet_string(p, ctx->salt, ctx->salt_len)) return 0; } @@ -503,6 +523,9 @@ static void *kdf_hkdf_fixed_digest_new(void *provctx, const char *digest) return NULL; } + /* Now the digest can no longer be changed */ + ctx->fixed_digest = 1; + return ctx; } @@ -516,33 +539,6 @@ KDF_HKDF_FIXED_DIGEST_NEW(sha256, "SHA256") KDF_HKDF_FIXED_DIGEST_NEW(sha384, "SHA384") KDF_HKDF_FIXED_DIGEST_NEW(sha512, "SHA512") -static const OSSL_PARAM *kdf_hkdf_fixed_digest_settable_ctx_params(ossl_unused void *ctx, - ossl_unused void *provctx) -{ - static const OSSL_PARAM known_settable_ctx_params[] = { - HKDF_COMMON_SETTABLES_NO_DIGEST, - OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), - OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_KEY_CHECK) - OSSL_PARAM_END - }; - return known_settable_ctx_params; -} - -static int kdf_hkdf_fixed_digest_set_ctx_params(void *vctx, const OSSL_PARAM params[]) -{ - if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) { - /* - * TODO: OPENSSL MAINTAINERS: should it fail an any attempt to set the digest or - * should it be allowed to set the digest to the current digest? - */ - ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED, - "Setting the digest is not supported for fixed-digest HKDFs"); - return 0; - } - - return kdf_hkdf_set_ctx_params(vctx, params); -} - #define MAKE_KDF_HKDF_FIXED_DIGEST_FUNCTIONS(hashname) \ const OSSL_DISPATCH ossl_kdf_hkdf_##hashname##_functions[] = { \ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_##hashname##_new }, \ @@ -550,9 +546,8 @@ static int kdf_hkdf_fixed_digest_set_ctx_params(void *vctx, const OSSL_PARAM par { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free }, \ { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset }, \ { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_hkdf_derive }, \ - { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, \ - (void(*)(void))kdf_hkdf_fixed_digest_settable_ctx_params }, \ - { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_hkdf_fixed_digest_set_ctx_params }, \ + { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS, (void(*)(void))kdf_hkdf_settable_ctx_params }, \ + { OSSL_FUNC_KDF_SET_CTX_PARAMS, (void(*)(void))kdf_hkdf_set_ctx_params }, \ { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS, (void(*)(void))kdf_hkdf_gettable_ctx_params }, \ { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_hkdf_get_ctx_params }, \ OSSL_DISPATCH_END \ diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index ddbb4fc1474..f537dc7b34d 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -240,42 +240,7 @@ static int test_kdf_hkdf(void) return ret; } -static int kdf_hkdf_fixed_digest(const char *kdf_name, char *digest) -{ - int ret; - EVP_KDF_CTX *kctx1 = NULL; - EVP_KDF_CTX *kctx2 = NULL; - unsigned char out1[10]; - unsigned char out2[10]; - OSSL_PARAM *params1; - OSSL_PARAM *params2; - - params1 = construct_hkdf_params(digest, "secret", 6, "salt", "label"); - params2 = construct_hkdf_params(NULL, "secret", 6, "salt", "label"); - - ret = TEST_ptr(params1) - && TEST_ptr(params2) - && TEST_ptr(kctx1 = get_kdfbyname(OSSL_KDF_NAME_HKDF)) - && TEST_ptr(kctx2 = get_kdfbyname(kdf_name)) - && TEST_int_gt(EVP_KDF_derive(kctx1, out1, sizeof(out1), params1), 0) - && TEST_int_gt(EVP_KDF_derive(kctx2, out2, sizeof(out2), params2), 0) - && TEST_mem_eq(out1, sizeof(out1), out2, sizeof(out2)); - - EVP_KDF_CTX_free(kctx1); - EVP_KDF_CTX_free(kctx2); - OPENSSL_free(params1); - OPENSSL_free(params2); - return ret; -} - -static int test_kdf_hkdf_fixed_digest(void) -{ - return kdf_hkdf_fixed_digest(OSSL_KDF_NAME_HKDF_SHA256, "sha256") - && kdf_hkdf_fixed_digest(OSSL_KDF_NAME_HKDF_SHA384, "sha384") - && kdf_hkdf_fixed_digest(OSSL_KDF_NAME_HKDF_SHA512, "sha512"); -} - -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; @@ -387,29 +352,147 @@ static int test_kdf_hkdf_invalid_digest(void) return ret; } -static int kdf_hkdf_fixed_digest_change_digest(const char *kdf_name, char *digest) +static int kdf_hkdf_fixed_digest_change_digest(const char *kdf_name, char *bad_digest) { int ret; EVP_KDF_CTX *kctx = NULL; - OSSL_PARAM *params; + char digestname[OSSL_MAX_NAME_SIZE]; + OSSL_PARAM params_get[2]; + OSSL_PARAM *params_set; - /* It is not allowed to change the digest in a fixed-digest KDF */ - params = construct_hkdf_params(digest, "secret", 6, "salt", "label"); + params_get[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST, + digestname, sizeof(digestname)); + params_get[1] = OSSL_PARAM_construct_end(); - ret = TEST_ptr(params) + params_set = construct_hkdf_params(bad_digest, "secret", 6, "salt", "label"); + + /* In a fixed-digest KDF it is not allowed to set the same digest nor change it */ + ret = TEST_ptr(params_get) && TEST_ptr(kctx = get_kdfbyname(kdf_name)) - && TEST_false(EVP_KDF_CTX_set_params(kctx, params)); + && TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1) + && TEST_false(EVP_KDF_CTX_set_params(kctx, params_get)) + && TEST_false(EVP_KDF_CTX_set_params(kctx, params_set)); EVP_KDF_CTX_free(kctx); - OPENSSL_free(params); + OPENSSL_free(params_set); return ret; } static int test_kdf_hkdf_fixed_digest_change_digest(void) { - return kdf_hkdf_fixed_digest_change_digest(OSSL_KDF_NAME_HKDF_SHA256, "sha256") - && kdf_hkdf_fixed_digest_change_digest(OSSL_KDF_NAME_HKDF_SHA384, "sha384") - && kdf_hkdf_fixed_digest_change_digest(OSSL_KDF_NAME_HKDF_SHA512, "sha512"); + return kdf_hkdf_fixed_digest_change_digest(OSSL_KDF_NAME_HKDF_SHA256, "sha512") + && kdf_hkdf_fixed_digest_change_digest(OSSL_KDF_NAME_HKDF_SHA384, "sha512") + && kdf_hkdf_fixed_digest_change_digest(OSSL_KDF_NAME_HKDF_SHA512, "sha256"); +} + +static int kdf_hkdf_fixed_digest_preserve_digest(const char *kdf_name, const char *expected_digest, + char *bad_digest) +{ + int ret = 0; + EVP_KDF_CTX *kctx = NULL; + EVP_KDF_CTX *kctx_copy = NULL; + char digestname[OSSL_MAX_NAME_SIZE] = { 0 }; + char salt[10] = { 0 }; + char info[10] = { 0 }; + OSSL_PARAM params_get[4]; + OSSL_PARAM params_set[2]; + OSSL_PARAM *params_init; + + params_get[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST, + digestname, sizeof(digestname)); + params_get[1] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + salt, sizeof(salt)); + params_get[2] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, + info, sizeof(info)); + params_get[3] = OSSL_PARAM_construct_end(); + + params_init = construct_hkdf_params(NULL, "secret", 6, "salt", "label"); + + ret = TEST_ptr(kctx = get_kdfbyname(kdf_name)) + && TEST_true(EVP_KDF_CTX_set_params(kctx, params_init)); + if (!ret) + goto end; + + params_set[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST, + bad_digest, strlen(bad_digest)); + params_set[1] = OSSL_PARAM_construct_end(); + + /* Reset context and ensure it's still fixed-digest */ + EVP_KDF_CTX_reset(kctx); + if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1) + || !TEST_size_t_gt(params_get[0].return_size, 0) + || !TEST_str_eq(digestname, expected_digest) + || !TEST_size_t_eq(params_get[1].return_size, 0) + || !TEST_size_t_eq(params_get[2].return_size, 0) + || !TEST_false(EVP_KDF_CTX_set_params(kctx, params_set))) + goto end; + + /* Duplicate context and ensure it's still fixed-digest */ + memset(digestname, 0, sizeof(digestname)); + if (!TEST_ptr(kctx_copy = EVP_KDF_CTX_dup(kctx)) + || !TEST_int_eq(EVP_KDF_CTX_get_params(kctx_copy, params_get), 1) + || !TEST_str_eq(digestname, expected_digest) + || !TEST_false(EVP_KDF_CTX_set_params(kctx_copy, params_set))) + goto end; + + ret = 1; +end: + EVP_KDF_CTX_free(kctx); + EVP_KDF_CTX_free(kctx_copy); + OPENSSL_free(params_init); + return ret; +} + +static int test_kdf_hkdf_fixed_digest_preserve_digest(void) +{ + return kdf_hkdf_fixed_digest_preserve_digest(OSSL_KDF_NAME_HKDF_SHA256, "SHA2-256", "SHA2-512") + && kdf_hkdf_fixed_digest_preserve_digest(OSSL_KDF_NAME_HKDF_SHA384, "SHA2-384", "SHA2-512") + && kdf_hkdf_fixed_digest_preserve_digest(OSSL_KDF_NAME_HKDF_SHA512, "SHA2-512", "SHA2-256"); +} + +static int test_kdf_hkdf_reset(void) +{ + int ret = 0; + EVP_KDF_CTX *kctx = NULL; + OSSL_PARAM *params_set; + OSSL_PARAM params_get[3]; + char digestname[OSSL_MAX_NAME_SIZE] = { 0 }; + char salt[10] = { 0 }; + char info[10] = { 0 }; + + params_set = construct_hkdf_params("sha256", "secret", 6, "salt", "label"); + + if (!TEST_ptr(params_set) + || !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)) + || ! TEST_true(EVP_KDF_CTX_set_params(kctx, params_set))) + goto end; + + /* Reset context and ensure it has been reset */ + EVP_KDF_CTX_reset(kctx); + + params_get[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST, + digestname, sizeof(digestname)); + params_get[1] = OSSL_PARAM_construct_end(); + /* Getting an unset digest results in an error */ + if (!TEST_int_le(EVP_KDF_CTX_get_params(kctx, params_get), 0)) + goto end; + + params_get[0] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + salt, sizeof(salt)); + params_get[1] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, + info, sizeof(info)); + params_get[2] = OSSL_PARAM_construct_end(); + /* Getting other unset params gives empty params */ + if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1) + || !TEST_size_t_eq(params_get[0].return_size, 0) + || !TEST_size_t_eq(params_get[1].return_size, 0)) + goto end; + + ret = 1; +end: + EVP_KDF_CTX_free(kctx); + OPENSSL_free(params_set); + return ret; } static int test_kdf_hkdf_derive_set_params_fail(void) @@ -1970,7 +2053,6 @@ static int test_kdf_hmac_drbg_settables(void) unsigned char out[32]; char digestname[32]; char macname[32]; - EVP_MD *shake256 = NULL; /* Test there are settables */ if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HMACDRBGKDF)) @@ -2031,7 +2113,6 @@ static int test_kdf_hmac_drbg_settables(void) ret = 1; err: - EVP_MD_free(shake256); EVP_KDF_CTX_free(kctx); return ret; } @@ -2156,9 +2237,10 @@ int setup_tests(void) ADD_TEST(test_kdf_tls1_prf_empty_seed); ADD_TEST(test_kdf_tls1_prf_1byte_seed); ADD_TEST(test_kdf_hkdf); - ADD_TEST(test_kdf_hkdf_fixed_digest); ADD_TEST(test_kdf_hkdf_invalid_digest); ADD_TEST(test_kdf_hkdf_fixed_digest_change_digest); + ADD_TEST(test_kdf_hkdf_fixed_digest_preserve_digest); + ADD_TEST(test_kdf_hkdf_reset); ADD_TEST(test_kdf_hkdf_zero_output_size); ADD_TEST(test_kdf_hkdf_empty_key); ADD_TEST(test_kdf_hkdf_1byte_key); diff --git a/test/recipes/30-test_evp_data/evpkdf_hkdf.txt b/test/recipes/30-test_evp_data/evpkdf_hkdf.txt index 71ae8c6f71a..102e24e7845 100644 --- a/test/recipes/30-test_evp_data/evpkdf_hkdf.txt +++ b/test/recipes/30-test_evp_data/evpkdf_hkdf.txt @@ -20,12 +20,6 @@ Ctrl.salt = hexsalt:000102030405060708090a0b0c Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 -KDF = HKDF-SHA256 -Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b -Ctrl.salt = hexsalt:000102030405060708090a0b0c -Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 -Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 - KDF = HKDF Ctrl.mode = mode:EXTRACT_ONLY Ctrl.digest = digest:SHA256 @@ -265,3 +259,45 @@ Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b Ctrl.salt = hexsalt:000102030405060708090a0b0c Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 Output = 085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896 + +Title = HKDF Fixed Digest Consistency Tests + +# From RFC5869 test vectors +FIPSversion = >=3.6.0 +KDF = HKDF-SHA256 +Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Ctrl.salt = hexsalt:000102030405060708090a0b0c +Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 +Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 + +# OpenSSL-derived test vectors, to check consistency between HKDF with SHA384 and HKDF-SHA384 +KDF = HKDF +Ctrl.digest = digest:SHA384 +Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Ctrl.salt = hexsalt:000102030405060708090a0b0c +Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 +Output = 9B5097A86038B805309076A44B3A9F38063E25B516DCBF369F394CFAB43685F748B6457763E4F0204FC5 + +# OpenSSL-derived test vectors, to check consistency between HKDF with SHA384 and HKDF-SHA384 +FIPSversion = >=3.6.0 +KDF = HKDF-SHA384 +Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Ctrl.salt = hexsalt:000102030405060708090a0b0c +Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 +Output = 9B5097A86038B805309076A44B3A9F38063E25B516DCBF369F394CFAB43685F748B6457763E4F0204FC5 + +# OpenSSL-derived test vectors, to check consistency between HKDF with SHA512 and HKDF-SHA512 +KDF = HKDF +Ctrl.digest = digest:SHA512 +Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Ctrl.salt = hexsalt:000102030405060708090a0b0c +Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 +Output = 832390086CDA71FB47625BB5CEB168E4C8E26A1A16ED34D9FC7FE92C1481579338DA362CB8D9F925D7CB + +# OpenSSL-derived test vectors, to check consistency between HKDF with SHA512 and HKDF-SHA512 +FIPSversion = >=3.6.0 +KDF = HKDF-SHA512 +Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Ctrl.salt = hexsalt:000102030405060708090a0b0c +Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 +Output = 832390086CDA71FB47625BB5CEB168E4C8E26A1A16ED34D9FC7FE92C1481579338DA362CB8D9F925D7CB diff --git a/test/recipes/30-test_evp_data/evppkey_kdf_hkdf.txt b/test/recipes/30-test_evp_data/evppkey_kdf_hkdf.txt index 932ada897e7..1fb24720012 100644 --- a/test/recipes/30-test_evp_data/evppkey_kdf_hkdf.txt +++ b/test/recipes/30-test_evp_data/evppkey_kdf_hkdf.txt @@ -20,12 +20,6 @@ Ctrl.salt = hexsalt:000102030405060708090a0b0c Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 -PKEYKDF = HKDF-SHA256 -Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b -Ctrl.salt = hexsalt:000102030405060708090a0b0c -Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 -Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 - PKEYKDF = HKDF Ctrl.mode = mode:EXTRACT_ONLY Ctrl.md = md:SHA256