From: Shane Lontis Date: Wed, 28 Oct 2020 05:33:05 +0000 (+1000) Subject: Add support for making all of KBKDF FixedInput fields optional. X-Git-Tag: openssl-3.0.0-alpha9~147 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4757a3475191b84954f8fa15202de44c8dbb5ea3;p=thirdparty%2Fopenssl.git Add support for making all of KBKDF FixedInput fields optional. Added settable integer parameters OSSL_KDF_PARAM_KBKDF_USE_L, OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR. This is required for CAVS tests that only use a combined blob of inputdata. A test showing this use case has been added. Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/13258) --- diff --git a/doc/man7/EVP_KDF-KB.pod b/doc/man7/EVP_KDF-KB.pod index fdaa483e776..c69a717a3cc 100644 --- a/doc/man7/EVP_KDF-KB.pod +++ b/doc/man7/EVP_KDF-KB.pod @@ -21,15 +21,21 @@ The supported parameters are: =over 4 -=item "properties" (B) - =item "mode" (B) +The mode parameter determines which flavor of KBKDF to use - currently the +choices are "counter" and "feedback". "counter" is the default, and will be +used if unspecified. + =item "mac" (B) +The value is either CMAC or HMAC. + =item "digest" (B) -=item "cipher" (B) +=item "cipher" (B) + +=item "properties" (B) =item "key" (B) @@ -39,18 +45,30 @@ The supported parameters are: =item "seed" (B) +The seed parameter is unused in counter mode. + +=item "use-l" (B) + +Set to B<0> to disable use of the optional Fixed Input data 'L' (see SP800-108). +The default value of B<1> will be used if unspecified. + +=item "use-separator" (B) + +Set to B<0> to disable use of the optional Fixed Input data 'zero separator' +(see SP800-108) that is placed between the Label and Context. +The default value of B<1> will be used if unspecified. + =back -The mode parameter determines which flavor of KBKDF to use - currently the -choices are "counter" and "feedback". Counter is the default, and will be -used if unspecified. The seed parameter is unused in counter mode. +Depending on whether mac is CMAC or HMAC, either digest or cipher is required +(respectively) and the other is unused. The parameters key, salt, info, and seed correspond to KI, Label, Context, and IV (respectively) in SP800-108. As in that document, salt, info, and seed are optional and may be omitted. -Depending on whether mac is CMAC or HMAC, either digest or cipher is required -(respectively) and the other is unused. +"mac", "digest", cipher" and "properties" are described in +L. =head1 NOTES diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 6a50f10da7a..43be4ae145b 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -200,6 +200,8 @@ extern "C" { #define OSSL_KDF_PARAM_CIPHER OSSL_ALG_PARAM_CIPHER /* utf8 string */ #define OSSL_KDF_PARAM_CONSTANT "constant" /* octet string */ #define OSSL_KDF_PARAM_PKCS12_ID "id" /* int */ +#define OSSL_KDF_PARAM_KBKDF_USE_L "use-l" /* int */ +#define OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR "use-separator" /* int */ /* Known KDF names */ #define OSSL_KDF_NAME_HKDF "HKDF" diff --git a/providers/implementations/kdfs/kbkdf.c b/providers/implementations/kdfs/kbkdf.c index 74a694e8eab..a8f09bdbff2 100644 --- a/providers/implementations/kdfs/kbkdf.c +++ b/providers/implementations/kdfs/kbkdf.c @@ -68,6 +68,8 @@ typedef struct { size_t context_len; unsigned char *iv; size_t iv_len; + int use_l; + int use_separator; } KBKDF; /* Definitions needed for typechecking. */ @@ -96,6 +98,12 @@ static uint32_t be32(uint32_t host) return big; } +static void init(KBKDF *ctx) +{ + ctx->use_l = 1; + ctx->use_separator = 1; +} + static void *kbkdf_new(void *provctx) { KBKDF *ctx; @@ -110,6 +118,7 @@ static void *kbkdf_new(void *provctx) } ctx->provctx = provctx; + init(ctx); return ctx; } @@ -135,20 +144,32 @@ static void kbkdf_reset(void *vctx) OPENSSL_clear_free(ctx->iv, ctx->iv_len); memset(ctx, 0, sizeof(*ctx)); ctx->provctx = provctx; + init(ctx); } /* SP800-108 section 5.1 or section 5.2 depending on mode. */ static int derive(EVP_MAC_CTX *ctx_init, kbkdf_mode mode, unsigned char *iv, size_t iv_len, unsigned char *label, size_t label_len, unsigned char *context, size_t context_len, - unsigned char *k_i, size_t h, uint32_t l, unsigned char *ko, - size_t ko_len) + unsigned char *k_i, size_t h, uint32_t l, int has_separator, + unsigned char *ko, size_t ko_len) { int ret = 0; EVP_MAC_CTX *ctx = NULL; size_t written = 0, to_write, k_i_len = iv_len; const unsigned char zero = 0; uint32_t counter, i; + /* + * From SP800-108: + * The fixed input data is a concatenation of a Label, + * a separation indicator 0x00, the Context, and L. + * One or more of these fixed input data fields may be omitted. + * + * has_separator == 0 means that the separator is omitted. + * Passing a value of l == 0 means that L is omitted. + * The Context and L are omitted automatically if a NULL buffer is passed. + */ + int has_l = (l != 0); /* Setup K(0) for feedback mode. */ if (iv_len > 0) @@ -167,9 +188,9 @@ static int derive(EVP_MAC_CTX *ctx_init, kbkdf_mode mode, unsigned char *iv, if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4) || !EVP_MAC_update(ctx, label, label_len) - || !EVP_MAC_update(ctx, &zero, 1) + || (has_separator && !EVP_MAC_update(ctx, &zero, 1)) || !EVP_MAC_update(ctx, context, context_len) - || !EVP_MAC_update(ctx, (unsigned char *)&l, 4) + || (has_l && !EVP_MAC_update(ctx, (unsigned char *)&l, 4)) || !EVP_MAC_final(ctx, k_i, NULL, h)) goto done; @@ -193,7 +214,7 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen) KBKDF *ctx = (KBKDF *)vctx; int ret = 0; unsigned char *k_i = NULL; - uint32_t l = be32(keylen * 8); + uint32_t l = 0; size_t h = 0; if (!ossl_prov_is_running()) @@ -226,13 +247,16 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen) goto done; } + if (ctx->use_l != 0) + l = be32(keylen * 8); + k_i = OPENSSL_zalloc(h); if (k_i == NULL) goto done; ret = derive(ctx->ctx_init, ctx->mode, ctx->iv, ctx->iv_len, ctx->label, ctx->label_len, ctx->context, ctx->context_len, k_i, h, l, - key, keylen); + ctx->use_separator, key, keylen); done: if (ret != 1) OPENSSL_cleanse(key, keylen); @@ -297,6 +321,14 @@ static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (p != NULL && !kbkdf_set_buffer(&ctx->iv, &ctx->iv_len, p)) return 0; + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KBKDF_USE_L); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->use_l)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR); + if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->use_separator)) + return 0; + /* Set up digest context, if we can. */ if (ctx->ctx_init != NULL && ctx->ki_len != 0) { mparams[0] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, @@ -322,8 +354,9 @@ static const OSSL_PARAM *kbkdf_settable_ctx_params(ossl_unused void *provctx) OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), - OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_int(OSSL_KDF_PARAM_KBKDF_USE_L, NULL), + OSSL_PARAM_int(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR, NULL), OSSL_PARAM_END, }; return known_settable_ctx_params; diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 173320a9176..2ff43a9c176 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -1,6 +1,6 @@ /* * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved. - * Copyright (c) 2018-2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018-2020, Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -1051,6 +1051,68 @@ static int test_kdf_kbkdf_8009_prf2(void) return ret; } +#if !defined(OPENSSL_NO_CMAC) +/* + * Test vector taken from + * https://csrc.nist.gov/CSRC/media/Projects/ + * Cryptographic-Algorithm-Validation-Program/documents/KBKDF800-108/CounterMode.zip + * Note: Only 32 bit counter is supported ([RLEN=32_BITS]) + */ +static int test_kdf_kbkdf_fixedinfo(void) +{ + int ret; + EVP_KDF_CTX *kctx; + OSSL_PARAM params[8], *p = params; + static char *cipher = "AES128"; + static char *mac = "CMAC"; + static char *mode = "COUNTER"; + int use_l = 0; + int use_separator = 0; + + static unsigned char input_key[] = { + 0xc1, 0x0b, 0x15, 0x2e, 0x8c, 0x97, 0xb7, 0x7e, + 0x18, 0x70, 0x4e, 0x0f, 0x0b, 0xd3, 0x83, 0x05, + }; + static unsigned char fixed_input[] = { + 0x98, 0xcd, 0x4c, 0xbb, 0xbe, 0xbe, 0x15, 0xd1, + 0x7d, 0xc8, 0x6e, 0x6d, 0xba, 0xd8, 0x00, 0xa2, + 0xdc, 0xbd, 0x64, 0xf7, 0xc7, 0xad, 0x0e, 0x78, + 0xe9, 0xcf, 0x94, 0xff, 0xdb, 0xa8, 0x9d, 0x03, + 0xe9, 0x7e, 0xad, 0xf6, 0xc4, 0xf7, 0xb8, 0x06, + 0xca, 0xf5, 0x2a, 0xa3, 0x8f, 0x09, 0xd0, 0xeb, + 0x71, 0xd7, 0x1f, 0x49, 0x7b, 0xcc, 0x69, 0x06, + 0xb4, 0x8d, 0x36, 0xc4, + + }; + static unsigned char output[] = { + 0x26, 0xfa, 0xf6, 0x19, 0x08, 0xad, 0x9e, 0xe8, + 0x81, 0xb8, 0x30, 0x5c, 0x22, 0x1d, 0xb5, 0x3f, + }; + unsigned char result[sizeof(output)] = { 0 }; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER, cipher, 0); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC, mac, 0); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MODE, mode, 0); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, input_key, + sizeof(input_key)); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, + fixed_input, sizeof(fixed_input)); + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_USE_L, &use_l); + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR, + &use_separator); + *p = OSSL_PARAM_construct_end(); + + kctx = get_kdfbyname("KBKDF"); + ret = TEST_ptr(kctx) + && TEST_true(EVP_KDF_CTX_set_params(kctx, params)) + && TEST_int_gt(EVP_KDF_derive(kctx, result, sizeof(result)), 0) + && TEST_mem_eq(result, sizeof(result), output, sizeof(output)); + + EVP_KDF_CTX_free(kctx); + return ret; +} +#endif /* OPENSSL_NO_CMAC */ + static int test_kdf_ss_hmac(void) { int ret; @@ -1322,6 +1384,9 @@ int setup_tests(void) ADD_TEST(test_kdf_kbkdf_1byte_key); ADD_TEST(test_kdf_kbkdf_8009_prf1); ADD_TEST(test_kdf_kbkdf_8009_prf2); +#if !defined(OPENSSL_NO_CMAC) + ADD_TEST(test_kdf_kbkdf_fixedinfo); +#endif ADD_TEST(test_kdf_get_kdf); ADD_TEST(test_kdf_tls1_prf); ADD_TEST(test_kdf_tls1_prf_invalid_digest);