SSKDF with KMAC should return SIZE_MAX when EVP_KDF_CTX_get_kdf_size()
authorslontis <shane.lontis@oracle.com>
Tue, 20 Dec 2022 03:44:18 +0000 (13:44 +1000)
committerTomas Mraz <tomas@openssl.org>
Thu, 12 Jan 2023 11:13:47 +0000 (12:13 +0100)
is used.

Fixes #19934

The existing code was looking for the digest size, and then returned
zero.

The example code in EVP_KDF-SS.pod has been corrected to not use a
digest.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19935)

doc/man7/EVP_KDF-SS.pod
providers/implementations/kdfs/sskdf.c
test/evp_kdf_test.c

index 7f7f992fe18745c1e3d81802f91592cb8b90c79e..fbc4a6acec1a51fe2a098a1f3f57c0b75ddd8d37 100644 (file)
@@ -43,6 +43,8 @@ The supported parameters are:
 
 =item "digest" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
 
+This parameter is ignored for KMAC.
+
 =item "mac" (B<OSSL_KDF_PARAM_MAC>) <UTF8 string>
 
 =item "maclen" (B<OSSL_KDF_PARAM_MAC_SIZE>) <unsigned integer>
@@ -133,7 +135,7 @@ fixedinfo value "label", salt of "salt" and KMAC outlen of 20:
  EVP_KDF *kdf;
  EVP_KDF_CTX *kctx;
  unsigned char out[10];
- OSSL_PARAM params[7], *p = params;
+ OSSL_PARAM params[6], *p = params;
 
  kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
  kctx = EVP_KDF_CTX_new(kdf);
@@ -141,8 +143,6 @@ fixedinfo value "label", salt of "salt" and KMAC outlen of 20:
 
  *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
                                          SN_kmac128, strlen(SN_kmac128));
- *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
-                                         SN_sha256, strlen(SN_sha256));
  *p++ = OSSL_PARAM_construct_octet_string(EVP_KDF_CTRL_SET_KEY,
                                           "secret", (size_t)6);
  *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
index 378aeb5d30a291d449627d715910deee46855a52..68408bb03bf66d296ee768112688008dcd6be0df 100644 (file)
@@ -62,6 +62,7 @@ typedef struct {
     unsigned char *salt;
     size_t salt_len;
     size_t out_len; /* optional KMAC parameter */
+    int is_kmac;
 } KDF_SSKDF;
 
 #define SSKDF_MAX_INLEN (1<<30)
@@ -340,6 +341,7 @@ static void *sskdf_dup(void *vctx)
                 || !ossl_prov_digest_copy(&dest->digest, &src->digest))
             goto err;
         dest->out_len = src->out_len;
+        dest->is_kmac = src->is_kmac;
     }
     return dest;
 
@@ -361,8 +363,12 @@ static int sskdf_set_buffer(unsigned char **out, size_t *out_len,
 static size_t sskdf_size(KDF_SSKDF *ctx)
 {
     int len;
-    const EVP_MD *md = ossl_prov_digest_md(&ctx->digest);
+    const EVP_MD *md = NULL;
 
+    if (ctx->is_kmac)
+        return SIZE_MAX;
+
+    md = ossl_prov_digest_md(&ctx->digest);
     if (md == NULL) {
         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
         return 0;
@@ -402,8 +408,7 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen,
             default_salt_len = EVP_MD_get_size(md);
             if (default_salt_len <= 0)
                 return 0;
-        } else if (EVP_MAC_is_a(mac, OSSL_MAC_NAME_KMAC128)
-                   || EVP_MAC_is_a(mac, OSSL_MAC_NAME_KMAC256)) {
+        } else if (ctx->is_kmac) {
             /* H(x) = KMACzzz(x, salt, custom) */
             custom = kmac_custom_str;
             custom_len = sizeof(kmac_custom_str);
@@ -479,12 +484,20 @@ static int sskdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     if (params == NULL)
         return 1;
 
-    if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
-        return 0;
-
     if (!ossl_prov_macctx_load_from_params(&ctx->macctx, params,
                                            NULL, NULL, NULL, libctx))
         return 0;
+   if (ctx->macctx != NULL) {
+        if (EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx),
+                         OSSL_MAC_NAME_KMAC128)
+            || EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx),
+                            OSSL_MAC_NAME_KMAC256)) {
+            ctx->is_kmac = 1;
+        }
+   }
+
+   if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx))
+       return 0;
 
     if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL
         || (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
index e020c0e47db364df9741aa1035d997b625854c64..fb30fca1ef929036f7437c729e29e430ff35e35a 100644 (file)
@@ -1528,6 +1528,7 @@ static int test_kdf_kbkdf_kmac(void)
 
     kctx = get_kdfbyname("KBKDF");
     ret = TEST_ptr(kctx)
+        && TEST_size_t_eq(EVP_KDF_CTX_get_kdf_size(kctx), SIZE_MAX)
         && TEST_int_gt(EVP_KDF_derive(kctx, result, sizeof(result), params), 0)
         && TEST_mem_eq(result, sizeof(result), output, sizeof(output));
 
@@ -1580,7 +1581,7 @@ static int test_kdf_ss_kmac(void)
 {
     int ret;
     EVP_KDF_CTX *kctx;
-    OSSL_PARAM params[6], *p = params;
+    OSSL_PARAM params[7], *p = params;
     unsigned char out[64];
     size_t mac_size = 20;
     static unsigned char z[] = {
@@ -1603,6 +1604,9 @@ static int test_kdf_ss_kmac(void)
 
     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
                                             (char *)OSSL_MAC_NAME_KMAC128, 0);
+    /* The digest parameter is not needed here and should be ignored */
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
+                                            (char *)"SHA256", 0);
     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, z, sizeof(z));
     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, other,
                                              sizeof(other));
@@ -1613,7 +1617,12 @@ static int test_kdf_ss_kmac(void)
 
     ret =
         TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_SSKDF))
-        && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), params), 0)
+        && TEST_size_t_eq(EVP_KDF_CTX_get_kdf_size(kctx), 0)
+        && TEST_int_eq(EVP_KDF_CTX_set_params(kctx, params), 1)
+        /* The bug fix for KMAC returning SIZE_MAX was added in 3.0.8 */
+        && (fips_provider_version_lt(NULL, 3, 0, 8)
+            || TEST_size_t_eq(EVP_KDF_CTX_get_kdf_size(kctx), SIZE_MAX))
+        && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0)
         && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected));
 
     EVP_KDF_CTX_free(kctx);