From: Shane Lontis Date: Fri, 2 Jul 2021 04:26:07 +0000 (+1000) Subject: Add HKDF negative tests X-Git-Tag: openssl-3.0.0-beta2~109 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d300aa21b02f13d3429931417f4320350b9f891;p=thirdparty%2Fopenssl.git 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 (Merged from https://github.com/openssl/openssl/pull/15977) --- diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index 83d9d1ecce7..167b64f0b30 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -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; } diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 94d2b0ac58e..4b3df38b5f4 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -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); diff --git a/test/recipes/30-test_evp_data/evpkdf_hkdf.txt b/test/recipes/30-test_evp_data/evpkdf_hkdf.txt index 8d486c672ac..c7f94cc6448 100644 --- a/test/recipes/30-test_evp_data/evpkdf_hkdf.txt +++ b/test/recipes/30-test_evp_data/evpkdf_hkdf.txt @@ -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