Skip to content

Commit

Permalink
Support different R_BITS lengths for KBKDF
Browse files Browse the repository at this point in the history
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from #17063)

(cherry picked from commit 0e9a265)
  • Loading branch information
puiterwijk authored and t8m committed Nov 11, 2022
1 parent e8f1d76 commit bc15591
Show file tree
Hide file tree
Showing 7 changed files with 1,924 additions and 11 deletions.
7 changes: 7 additions & 0 deletions doc/man7/EVP_KDF-KB.pod
Expand Up @@ -58,6 +58,13 @@ 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.

=item "r" (B<OSSL_KDF_PARAM_KBKDF_R>) <integer>

Set the fixed value 'r', indicating the length of the counter in bits.

Supported values are B<8>, B<16>, B<24>, and B<32>.
The default value of B<32> will be used if unspecified.

=back

Depending on whether mac is CMAC or HMAC, either digest or cipher is required
Expand Down
1 change: 1 addition & 0 deletions include/openssl/core_names.h
Expand Up @@ -217,6 +217,7 @@ extern "C" {
#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 */
#define OSSL_KDF_PARAM_KBKDF_R "r" /* int */
#define OSSL_KDF_PARAM_X942_ACVPINFO "acvp-info"
#define OSSL_KDF_PARAM_X942_PARTYUINFO "partyu-info"
#define OSSL_KDF_PARAM_X942_PARTYVINFO "partyv-info"
Expand Down
30 changes: 27 additions & 3 deletions providers/implementations/kdfs/kbkdf.c
Expand Up @@ -60,6 +60,7 @@ typedef struct {
EVP_MAC_CTX *ctx_init;

/* Names are lowercased versions of those found in SP800-108. */
int r;
unsigned char *ki;
size_t ki_len;
unsigned char *label;
Expand Down Expand Up @@ -100,6 +101,7 @@ static uint32_t be32(uint32_t host)

static void init(KBKDF *ctx)
{
ctx->r = 32;
ctx->use_l = 1;
ctx->use_separator = 1;
}
Expand Down Expand Up @@ -152,7 +154,7 @@ 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, int has_separator,
unsigned char *ko, size_t ko_len)
unsigned char *ko, size_t ko_len, int r)
{
int ret = 0;
EVP_MAC_CTX *ctx = NULL;
Expand Down Expand Up @@ -186,7 +188,7 @@ static int derive(EVP_MAC_CTX *ctx_init, kbkdf_mode mode, unsigned char *iv,
if (mode == FEEDBACK && !EVP_MAC_update(ctx, k_i, k_i_len))
goto done;

if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4)
if (!EVP_MAC_update(ctx, 4 - (r / 8) + (unsigned char *)&i, r / 8)
|| !EVP_MAC_update(ctx, label, label_len)
|| (has_separator && !EVP_MAC_update(ctx, &zero, 1))
|| !EVP_MAC_update(ctx, context, context_len)
Expand Down Expand Up @@ -217,6 +219,7 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen,
unsigned char *k_i = NULL;
uint32_t l = 0;
size_t h = 0;
uint64_t counter_max;

if (!ossl_prov_is_running() || !kbkdf_set_ctx_params(ctx, params))
return 0;
Expand Down Expand Up @@ -248,6 +251,15 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen,
goto done;
}

if (ctx->mode == COUNTER) {
/* Fail if keylen is too large for r */
counter_max = (uint64_t)1 << (uint64_t)ctx->r;
if ((uint64_t)(keylen / h) >= counter_max) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
goto done;
}
}

if (ctx->use_l != 0)
l = be32(keylen * 8);

Expand All @@ -257,7 +269,7 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen,

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,
ctx->use_separator, key, keylen);
ctx->use_separator, key, keylen, ctx->r);
done:
if (ret != 1)
OPENSSL_cleanse(key, keylen);
Expand Down Expand Up @@ -329,6 +341,17 @@ static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
if (p != NULL && !OSSL_PARAM_get_int(p, &ctx->use_l))
return 0;

p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KBKDF_R);
if (p != NULL) {
int new_r = 0;

if (!OSSL_PARAM_get_int(p, &new_r))
return 0;
if (new_r != 8 && new_r != 16 && new_r != 24 && new_r != 32)
return 0;
ctx->r = new_r;
}

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;
Expand All @@ -355,6 +378,7 @@ static const OSSL_PARAM *kbkdf_settable_ctx_params(ossl_unused void *ctx,
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_int(OSSL_KDF_PARAM_KBKDF_R, NULL),
OSSL_PARAM_END,
};
return known_settable_ctx_params;
Expand Down
47 changes: 39 additions & 8 deletions test/evp_kdf_test.c
Expand Up @@ -1068,9 +1068,9 @@ static int test_kdf_kbkdf_6803_256(void)
#endif

static OSSL_PARAM *construct_kbkdf_params(char *digest, char *mac, unsigned char *key,
size_t keylen, char *salt, char *info)
size_t keylen, char *salt, char *info, int *r)
{
OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 7);
OSSL_PARAM *params = OPENSSL_malloc(sizeof(OSSL_PARAM) * 8);
OSSL_PARAM *p = params;

if (params == NULL)
Expand All @@ -1088,6 +1088,8 @@ static OSSL_PARAM *construct_kbkdf_params(char *digest, char *mac, unsigned char
OSSL_KDF_PARAM_SALT, salt, strlen(salt));
*p++ = OSSL_PARAM_construct_octet_string(
OSSL_KDF_PARAM_INFO, info, strlen(info));
*p++ = OSSL_PARAM_construct_int(
OSSL_KDF_PARAM_KBKDF_R, r);
*p = OSSL_PARAM_construct_end();

return params;
Expand All @@ -1100,8 +1102,9 @@ static int test_kdf_kbkdf_invalid_digest(void)
OSSL_PARAM *params;

static unsigned char key[] = {0x01};
int r = 32;

params = construct_kbkdf_params("blah", "HMAC", key, 1, "prf", "test");
params = construct_kbkdf_params("blah", "HMAC", key, 1, "prf", "test", &r);
if (!TEST_ptr(params))
return 0;

Expand All @@ -1122,8 +1125,9 @@ static int test_kdf_kbkdf_invalid_mac(void)
OSSL_PARAM *params;

static unsigned char key[] = {0x01};
int r = 32;

params = construct_kbkdf_params("sha256", "blah", key, 1, "prf", "test");
params = construct_kbkdf_params("sha256", "blah", key, 1, "prf", "test", &r);
if (!TEST_ptr(params))
return 0;

Expand All @@ -1137,6 +1141,30 @@ static int test_kdf_kbkdf_invalid_mac(void)
return ret;
}

static int test_kdf_kbkdf_invalid_r(void)
{
int ret;
EVP_KDF_CTX *kctx;
OSSL_PARAM *params;

static unsigned char key[] = {0x01};
int r = 31;

params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test", &r);
if (!TEST_ptr(params))
return 0;

/* Negative test case - derive should fail */
kctx = get_kdfbyname("KBKDF");
ret = TEST_ptr(kctx)
&& TEST_false(EVP_KDF_CTX_set_params(kctx, params));

EVP_KDF_CTX_free(kctx);
OPENSSL_free(params);
return ret;
}


static int test_kdf_kbkdf_empty_key(void)
{
int ret;
Expand All @@ -1145,8 +1173,9 @@ static int test_kdf_kbkdf_empty_key(void)

static unsigned char key[] = {0x01};
unsigned char result[32] = { 0 };
int r = 32;

params = construct_kbkdf_params("sha256", "HMAC", key, 0, "prf", "test");
params = construct_kbkdf_params("sha256", "HMAC", key, 0, "prf", "test", &r);
if (!TEST_ptr(params))
return 0;

Expand All @@ -1169,8 +1198,9 @@ static int test_kdf_kbkdf_1byte_key(void)

static unsigned char key[] = {0x01};
unsigned char result[32] = { 0 };
int r = 32;

params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test");
params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test", &r);
if (!TEST_ptr(params))
return 0;

Expand All @@ -1191,8 +1221,9 @@ static int test_kdf_kbkdf_zero_output_size(void)

static unsigned char key[] = {0x01};
unsigned char result[32] = { 0 };
int r = 32;

params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test");
params = construct_kbkdf_params("sha256", "HMAC", key, 1, "prf", "test", &r);
if (!TEST_ptr(params))
return 0;

Expand Down Expand Up @@ -1298,7 +1329,6 @@ static int test_kdf_kbkdf_8009_prf2(void)
* 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)
{
Expand Down Expand Up @@ -1628,6 +1658,7 @@ int setup_tests(void)
#endif
ADD_TEST(test_kdf_kbkdf_invalid_digest);
ADD_TEST(test_kdf_kbkdf_invalid_mac);
ADD_TEST(test_kdf_kbkdf_invalid_r);
ADD_TEST(test_kdf_kbkdf_zero_output_size);
ADD_TEST(test_kdf_kbkdf_empty_key);
ADD_TEST(test_kdf_kbkdf_1byte_key);
Expand Down
6 changes: 6 additions & 0 deletions test/evp_test.c
Expand Up @@ -2781,6 +2781,12 @@ static int kdf_test_ctrl(EVP_TEST *t, EVP_KDF_CTX *kctx,
TEST_info("skipping, '%s' is disabled", p);
t->skip = 1;
}
if (p != NULL
&& (strcmp(name, "mac") == 0)
&& is_mac_disabled(p)) {
TEST_info("skipping, '%s' is disabled", p);
t->skip = 1;
}
OPENSSL_free(name);
return 1;
}
Expand Down
1 change: 1 addition & 0 deletions test/recipes/30-test_evp.t
Expand Up @@ -45,6 +45,7 @@ my @files = qw(
evpciph_aes_stitched.txt
evpciph_des3_common.txt
evpkdf_hkdf.txt
evpkdf_kbkdf_counter.txt
evpkdf_pbkdf1.txt
evpkdf_pbkdf2.txt
evpkdf_ss.txt
Expand Down

0 comments on commit bc15591

Please sign in to comment.