]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
HKDF updates
authorDaniel Van Geest <daniel.vangeest@cryptonext-security.com>
Mon, 7 Apr 2025 11:21:47 +0000 (12:21 +0100)
committerPauli <ppzgs1@gmail.com>
Thu, 10 Jul 2025 01:14:19 +0000 (11:14 +1000)
- prevent fixed-digest HKDF from having its digest changed
- implement gettable params in HKDF
- update fixed-digest HKDF tests

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/27247)

CHANGES.md
doc/man7/EVP_KDF-HKDF.pod
doc/man7/OSSL_PROVIDER-FIPS.pod
doc/man7/OSSL_PROVIDER-default.pod
providers/defltprov.c
providers/fips/fipsprov.c
providers/implementations/exchange/kdf_exch.c
providers/implementations/kdfs/hkdf.c
test/evp_kdf_test.c
test/recipes/30-test_evp_data/evpkdf_hkdf.txt
test/recipes/30-test_evp_data/evppkey_kdf_hkdf.txt

index 1b1b6bac2fb9e3347c5f281730f0ea14d4a604ac..666622378e7915d263a0962c5ca76a787181a9e8 100644 (file)
@@ -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)*
index bcfe01e456473b0d08b52140af72a78733451ed2..959a6f07d31c11e6da74c003d4940d6de54567c3 100644 (file)
@@ -17,15 +17,6 @@ of the KDF).
 
 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
@@ -40,12 +31,20 @@ mere OID which came out in this form after a call to L<OBJ_obj2txt(3)>).
 
 =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
@@ -58,6 +57,8 @@ The supported parameters are:
 
 =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>
@@ -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<HKDF>) the digest
+must also be set.
 
 =item "EXTRACT_ONLY" or B<EVP_KDF_HKDF_MODE_EXTRACT_ONLY>
 
@@ -94,8 +96,9 @@ operation. The value returned will be the intermediate fixed-length pseudorandom
 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>
 
@@ -103,8 +106,9 @@ In this mode calling L<EVP_KDF_derive(3)> 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<HKDF>) the digest
+must also be set.
 
 =back
 
@@ -148,6 +152,8 @@ after setting the mode and digest on the B<EVP_KDF_CTX>.
 
 =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
index 79aa0ca8b9ac6d82f9d31dd7affa29c73da8e353..dbce55e3701570889cb0e5f94a6953d715370e19 100644 (file)
@@ -588,7 +588,7 @@ L<https://www.openssl.org/source/>
 
 =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.
 
index 0236b86ef7638dfa11d98420361d512e13c357f9..a4021418b50e4e2b7523c87c8dda89d4e705bdc9 100644 (file)
@@ -530,7 +530,7 @@ L<OSSL_PROVIDER-base(7)>
 
 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.
 
index 412737296c65045604e2c186bc991511666ecdc7..a76c7a536252e1b0ccf46b9c4c9a03a307d7faad 100644 (file)
@@ -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,
index 5a1e11c03f3623d9d94f475106f806338994c998..756ca874bb737acd61a57a51d48d2f61043a29a0 100644 (file)
@@ -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
index 5e363737b0e20dc6acce0d401e8b0842cd3045aa..340a2663c588ee820ec8d5ee49b590f4967efc35 100644 (file)
@@ -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)
index bfe8d8d533fab17148e78fbc83b26c4160d6b90a..75a3364ec67e84eee4bb03262be3f551c3cf50e2 100644 (file)
@@ -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 \
index ddbb4fc147430d0042786984f6b5e1ba714cca70..f537dc7b34d4cff112487dd157d043c4d06095da 100644 (file)
@@ -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);
index 71ae8c6f71acbfe494020b2231e56d7170a03ebc..102e24e78451e22037bd841b540b2c074c9bfd0d 100644 (file)
@@ -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
index 932ada897e717a3cee6996872fa2f974ff24308b..1fb24720012bb75ad88cc427877e4eb9b6a01df4 100644 (file)
@@ -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