From 8d89050f0f676b429043fd5445e5a570d54ad225 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 1 Jan 2024 11:53:50 -0500 Subject: [PATCH] validate requested key length in kdf_pbkdf1_do_derive When using pbkdf1 key deriviation, it is possible to request a key length larger than the maximum digest size a given digest can produce, leading to a read of random stack memory. fix it by returning an error if the requested key size n is larger than the EVP_MD_size of the digest Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/23174) --- providers/implementations/kdfs/pbkdf1.c | 5 +++ test/evp_kdf_test.c | 50 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/providers/implementations/kdfs/pbkdf1.c b/providers/implementations/kdfs/pbkdf1.c index 6f95df071b..4fa6afd104 100644 --- a/providers/implementations/kdfs/pbkdf1.c +++ b/providers/implementations/kdfs/pbkdf1.c @@ -72,6 +72,11 @@ static int kdf_pbkdf1_do_derive(const unsigned char *pass, size_t passlen, mdsize = EVP_MD_size(md_type); if (mdsize < 0) goto err; + if (n > (size_t)mdsize) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + goto err; + } + for (i = 1; i < iter; i++) { if (!EVP_DigestInit_ex(ctx, md_type, NULL)) goto err; diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 85bae39988..a3dd4a5b03 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -544,6 +544,55 @@ err: return ret; } +static int test_kdf_pbkdf1_key_too_long(void) +{ + int ret = 0; + EVP_KDF_CTX *kctx = NULL; + unsigned char out[EVP_MAX_MD_SIZE + 1]; + unsigned int iterations = 4096; + OSSL_LIB_CTX *libctx = NULL; + OSSL_PARAM *params = NULL; + OSSL_PROVIDER *legacyprov = NULL; + OSSL_PROVIDER *defprov = NULL; + + if (!TEST_ptr(libctx = OSSL_LIB_CTX_new())) + goto err; + + /* PBKDF1 only available in the legacy provider */ + legacyprov = OSSL_PROVIDER_load(libctx, "legacy"); + if (legacyprov == NULL) { + OSSL_LIB_CTX_free(libctx); + return TEST_skip("PBKDF1 only available in legacy provider"); + } + + if (!TEST_ptr(defprov = OSSL_PROVIDER_load(libctx, "default"))) + goto err; + + params = construct_pbkdf1_params("passwordPASSWORDpassword", "sha256", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + &iterations); + + /* + * This is the same test sequence as test_kdf_pbkdf1, but we expect + * failure here as the requested key size is longer than the digest + * can provide + */ + if (!TEST_ptr(params) + || !TEST_ptr(kctx = get_kdfbyname_libctx(libctx, OSSL_KDF_NAME_PBKDF1)) + || !TEST_true(EVP_KDF_CTX_set_params(kctx, params)) + || !TEST_int_eq(EVP_KDF_derive(kctx, out, sizeof(out), NULL), 0)) + goto err; + + ret = 1; +err: + EVP_KDF_CTX_free(kctx); + OPENSSL_free(params); + OSSL_PROVIDER_unload(defprov); + OSSL_PROVIDER_unload(legacyprov); + OSSL_LIB_CTX_free(libctx); + return ret; +} + static OSSL_PARAM *construct_pbkdf2_params(char *pass, char *digest, char *salt, unsigned int *iter, int *mode) { @@ -1920,6 +1969,7 @@ err: int setup_tests(void) { ADD_TEST(test_kdf_pbkdf1); + ADD_TEST(test_kdf_pbkdf1_key_too_long); #if !defined(OPENSSL_NO_CMAC) && !defined(OPENSSL_NO_CAMELLIA) ADD_TEST(test_kdf_kbkdf_6803_128); ADD_TEST(test_kdf_kbkdf_6803_256); -- 2.34.1