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 <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13258)
This commit is contained in:
Shane Lontis 2020-10-28 15:33:05 +10:00
parent 2c90e80dec
commit 4757a34751
4 changed files with 134 additions and 16 deletions

View File

@ -21,15 +21,21 @@ The supported parameters are:
=over 4
=item "properties" (B<OSSL_KDF_PARAM_PROPERTIES>) <UTF8 string>
=item "mode" (B<OSSL_KDF_PARAM_MODE>) <UTF8 string>
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<OSSL_KDF_PARAM_MAC>) <UTF8 string>
The value is either CMAC or HMAC.
=item "digest" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
=item "cipher" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
=item "cipher" (B<OSSL_KDF_PARAM_CIPHER>) <UTF8 string>
=item "properties" (B<OSSL_KDF_PARAM_PROPERTIES>) <UTF8 string>
=item "key" (B<OSSL_KDF_PARAM_KEY>) <octet string>
@ -39,18 +45,30 @@ The supported parameters are:
=item "seed" (B<OSSL_KDF_PARAM_SEED>) <octet string>
The seed parameter is unused in counter mode.
=item "use-l" (B<OSSL_KDF_PARAM_KBKDF_USE_L>) <int>
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<OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR>) <int>
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<EVP_KDF(3)/PARAMETERS>.
=head1 NOTES

View File

@ -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"

View File

@ -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;

View File

@ -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);