*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)*
The output is considered to be keying material.
-=head2 Fixed-Digest HKDF
-
-B<HKDF-SHA256>, B<HKDF-SHA384> and B<HKDF-SHA512> are fixed-digest versions
-of the B<HKDF> 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<OSSL_KDF_PARAM_DIGEST> 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
=item "HKDF"
+The B<OSSL_KDF_PARAM_DIGEST> parameter must be set for B<HKDF> 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<HKDF-SHA256>, B<HKDF-SHA384> and B<HKDF-SHA512> are fixed-digest versions
+of B<HKDF> with the appropriate digest already configured.
+L<EVP_KDF_CTX_reset(3)> will not reset the context's digest for fixed-digest
+versions.
+
=back
=head2 Supported parameters
=item "digest" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
+Attempting to set the digest on a fixed-digest B<HKDF> will result in an error.
+
=item "key" (B<OSSL_KDF_PARAM_KEY>) <octet string>
=item "salt" (B<OSSL_KDF_PARAM_SALT>) <octet string>
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<HKDF>) the digest
+must also be set.
=item "EXTRACT_ONLY" or B<EVP_KDF_HKDF_MODE_EXTRACT_ONLY>
key K. The I<keylen> 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<HKDF>) the digest
+must also be set.
=item "EXPAND_ONLY" or B<EVP_KDF_HKDF_MODE_EXPAND_ONLY>
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<HKDF>) the digest
+must also be set.
=back
=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":
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
=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.
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.
#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 }
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,
{ 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 }
};
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
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[])
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,
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) \
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)
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,
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)
size_t data_len;
unsigned char *info;
size_t info_len;
+ int fixed_digest;
OSSL_FIPS_IND_DECLARE
} KDF_HKDF;
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
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)
|| !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;
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;
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;
}
return NULL;
}
+ /* Now the digest can no longer be changed */
+ ctx->fixed_digest = 1;
+
return ctx;
}
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 }, \
{ 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 \
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;
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)
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))
ret = 1;
err:
- EVP_MD_free(shake256);
EVP_KDF_CTX_free(kctx);
return ret;
}
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);
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
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
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