Browse Source

Add HKDF negative tests

Fix memory leak if legacy test is skipped.
Using EVP_KDF_CTX_get_params() to get OSSL_KDF_PARAM_SIZE will now
return 0 if the returned size is 0.

Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15977)
master
Shane Lontis 11 months ago
committed by Pauli
parent
commit
9d300aa21b
3 changed files with 178 additions and 10 deletions
  1. +8
    -5
      providers/implementations/kdfs/hkdf.c
  2. +161
    -5
      test/evp_kdf_test.c
  3. +9
    -0
      test/recipes/30-test_evp_data/evpkdf_hkdf.txt

+ 8
- 5
providers/implementations/kdfs/hkdf.c View File

@ -149,6 +149,7 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
switch (ctx->mode) {
case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
default:
return HKDF(libctx, md, ctx->salt, ctx->salt_len,
ctx->key, ctx->key_len, ctx->info, ctx->info_len, key, keylen);
@ -159,9 +160,6 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
case EVP_KDF_HKDF_MODE_EXPAND_ONLY:
return HKDF_Expand(md, ctx->key, ctx->key_len, ctx->info,
ctx->info_len, key, keylen);
default:
return 0;
}
}
@ -262,8 +260,13 @@ static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
OSSL_PARAM *p;
if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
return OSSL_PARAM_set_size_t(p, kdf_hkdf_size(ctx));
if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) {
size_t sz = kdf_hkdf_size(ctx);
if (sz == 0)
return 0;
return OSSL_PARAM_set_size_t(p, sz);
}
return -2;
}


+ 161
- 5
test/evp_kdf_test.c View File

@ -199,14 +199,19 @@ static OSSL_PARAM *construct_hkdf_params(char *digest, char *key,
if (params == NULL)
return NULL;
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
digest, 0);
if (digest != NULL)
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
digest, 0);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
salt, strlen(salt));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
(unsigned char *)key, keylen);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
info, strlen(info));
if (info != NULL)
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
info, strlen(info));
else
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MODE,
"EXTRACT_ONLY", 0);
*p = OSSL_PARAM_construct_end();
return params;
@ -234,6 +239,66 @@ static int test_kdf_hkdf(void)
return ret;
}
static int do_kdf_hkdf_gettables(int expand_only, int has_digest)
{
int ret = 0;
size_t sz = 0;
OSSL_PARAM *params;
OSSL_PARAM params_get[2];
const OSSL_PARAM *gettables, *p;
EVP_KDF_CTX *kctx = NULL;
if (!TEST_ptr(params = construct_hkdf_params(
has_digest ? "sha256" : NULL,
"secret", 6, "salt",
expand_only ? NULL : "label"))
|| !TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF))
|| !TEST_true(EVP_KDF_CTX_set_params(kctx, params)))
goto err;
/* Check OSSL_KDF_PARAM_SIZE is gettable */
if (!TEST_ptr(gettables = EVP_KDF_CTX_gettable_params(kctx))
|| !TEST_ptr(p = OSSL_PARAM_locate_const(gettables, OSSL_KDF_PARAM_SIZE)))
goto err;
/* Get OSSL_KDF_PARAM_SIZE as a size_t */
params_get[0] = OSSL_PARAM_construct_size_t(OSSL_KDF_PARAM_SIZE, &sz);
params_get[1] = OSSL_PARAM_construct_end();
if (has_digest) {
if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1)
|| !TEST_size_t_eq(sz, expand_only ? SHA256_DIGEST_LENGTH : SIZE_MAX))
goto err;
} else {
if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 0))
goto err;
}
/* Get params returns -2 if an unsupported parameter is requested */
params_get[0] = OSSL_PARAM_construct_end();
if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), -2))
goto err;
ret = 1;
err:
EVP_KDF_CTX_free(kctx);
OPENSSL_free(params);
return ret;
}
static int test_kdf_hkdf_gettables(void)
{
return do_kdf_hkdf_gettables(0, 1);
}
static int test_kdf_hkdf_gettables_expandonly(void)
{
return do_kdf_hkdf_gettables(1, 1);
}
static int test_kdf_hkdf_gettables_no_digest(void)
{
return do_kdf_hkdf_gettables(1, 0);
}
static int test_kdf_hkdf_invalid_digest(void)
{
int ret;
@ -251,6 +316,89 @@ static int test_kdf_hkdf_invalid_digest(void)
return ret;
}
static int test_kdf_hkdf_derive_set_params_fail(void)
{
int ret = 0, i = 0;
EVP_KDF_CTX *kctx = NULL;
OSSL_PARAM params[2];
unsigned char out[10];
if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)))
goto end;
/*
* Set the wrong type for the digest so that it causes a failure
* inside kdf_hkdf_derive() when kdf_hkdf_set_ctx_params() is called
*/
params[0] = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_DIGEST, &i);
params[1] = OSSL_PARAM_construct_end();
if (!TEST_int_eq(EVP_KDF_derive(kctx, out, sizeof(out), params), 0))
goto end;
ret = 1;
end:
EVP_KDF_CTX_free(kctx);
return ret;
}
static int test_kdf_hkdf_set_invalid_mode(void)
{
int ret = 0, bad_mode = 100;
EVP_KDF_CTX *kctx = NULL;
OSSL_PARAM params[2];
if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)))
goto end;
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MODE,
"BADMODE", 0);
params[1] = OSSL_PARAM_construct_end();
if (!TEST_int_eq(EVP_KDF_CTX_set_params(kctx, params), 0))
goto end;
params[0] = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &bad_mode);
if (!TEST_int_eq(EVP_KDF_CTX_set_params(kctx, params), 0))
goto end;
ret = 1;
end:
EVP_KDF_CTX_free(kctx);
return ret;
}
static int do_kdf_hkdf_set_invalid_param(const char *key, int type)
{
int ret = 0;
EVP_KDF_CTX *kctx = NULL;
OSSL_PARAM params[2];
unsigned char buf[2];
if (!TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_HKDF)))
goto end;
/* Set the wrong type for the key so that it causes a failure */
if (type == OSSL_PARAM_UTF8_STRING)
params[0] = OSSL_PARAM_construct_utf8_string(key, "BAD", 0);
else
params[0] = OSSL_PARAM_construct_octet_string(key, buf, sizeof(buf));
params[1] = OSSL_PARAM_construct_end();
if (!TEST_int_eq(EVP_KDF_CTX_set_params(kctx, params), 0))
goto end;
ret = 1;
end:
EVP_KDF_CTX_free(kctx);
return ret;
}
static int test_kdf_hkdf_set_ctx_param_fail(void)
{
return do_kdf_hkdf_set_invalid_param(OSSL_KDF_PARAM_MODE,
OSSL_PARAM_OCTET_STRING)
&& do_kdf_hkdf_set_invalid_param(OSSL_KDF_PARAM_KEY,
OSSL_PARAM_UTF8_STRING)
&& do_kdf_hkdf_set_invalid_param(OSSL_KDF_PARAM_SALT,
OSSL_PARAM_UTF8_STRING)
&& do_kdf_hkdf_set_invalid_param(OSSL_KDF_PARAM_INFO,
OSSL_PARAM_UTF8_STRING);
}
static int test_kdf_hkdf_zero_output_size(void)
{
int ret;
@ -366,8 +514,10 @@ static int test_kdf_pbkdf1(void)
/* PBKDF1 only available in the legacy provider */
prov = OSSL_PROVIDER_load(libctx, "legacy");
if (prov == NULL)
if (prov == NULL) {
OSSL_LIB_CTX_free(libctx);
return TEST_skip("PBKDF1 only available in legacy provider");
}
params = construct_pbkdf1_params("passwordPASSWORDpassword", "sha256",
"saltSALTsaltSALTsaltSALTsaltSALTsalt",
@ -1495,6 +1645,12 @@ int setup_tests(void)
ADD_TEST(test_kdf_hkdf_empty_key);
ADD_TEST(test_kdf_hkdf_1byte_key);
ADD_TEST(test_kdf_hkdf_empty_salt);
ADD_TEST(test_kdf_hkdf_gettables);
ADD_TEST(test_kdf_hkdf_gettables_expandonly);
ADD_TEST(test_kdf_hkdf_gettables_no_digest);
ADD_TEST(test_kdf_hkdf_derive_set_params_fail);
ADD_TEST(test_kdf_hkdf_set_invalid_mode);
ADD_TEST(test_kdf_hkdf_set_ctx_param_fail);
ADD_TEST(test_kdf_pbkdf2);
ADD_TEST(test_kdf_pbkdf2_small_output);
ADD_TEST(test_kdf_pbkdf2_large_output);


+ 9
- 0
test/recipes/30-test_evp_data/evpkdf_hkdf.txt View File

@ -193,3 +193,12 @@ Ctrl.digest = digest:SHA1
Ctrl.IKM = hexkey:0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
Ctrl.salt = salt:
Output = 2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48
# The output key size should match the digest size for EXTRACT_ONLY mode
KDF = HKDF
Ctrl.mode = mode:EXTRACT_ONLY
Ctrl.digest = digest:SHA1
Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
Ctrl.salt = salt:
Output = da8c8a73
Result = KDF_DERIVE_ERROR

Loading…
Cancel
Save