The branch openssl-3.0 has been updated via afaa7755aa3e577348e1267d5ad34da695292917 (commit) via fa2029250e38947ebd68a9b5861bedaa2384d85d (commit) via 43927f81a5d1ea1d32508430eee2df85736ba105 (commit) from 617203e64f17371b95fc8d64fc7fde9f8bc6e9db (commit)
- Log ----------------------------------------------------------------- commit afaa7755aa3e577348e1267d5ad34da695292917 Author: Matt Caswell <m...@openssl.org> Date: Wed Dec 29 16:39:11 2021 +0000 Add a test for a custom digest created via EVP_MD_meth_new() We check that the init and cleanup functions for the custom method are called as expected. Based on an original reproducer by Dmitry Belyavsky from issue #17149. Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/17255) (cherry picked from commit fbbe7202eba9fba243c18513f4f0316dafb3496d) commit fa2029250e38947ebd68a9b5861bedaa2384d85d Author: Matt Caswell <m...@openssl.org> Date: Fri Dec 10 17:17:27 2021 +0000 Fix a leak in EVP_DigestInit_ex() If an EVP_MD_CTX is reused then memory allocated and stored in md_data can be leaked unless the EVP_MD's cleanup function is called. Fixes #17149 Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/17255) (cherry picked from commit 357bccc8ba64ec8a5f587b04b5d6b6ca9e8dcbdc) commit 43927f81a5d1ea1d32508430eee2df85736ba105 Author: Matt Caswell <m...@openssl.org> Date: Fri Dec 10 16:53:02 2021 +0000 Ensure that MDs created via EVP_MD_meth_new() go down the legacy route MDs created via EVP_MD_meth_new() are inherently legacy and therefore need to go down the legacy route when they are used. Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/17255) (cherry picked from commit d9ad5b16b32172df6f7d02cfb1c339cc85d0db01) ----------------------------------------------------------------------- Summary of changes: crypto/evp/digest.c | 34 ++++++++++++--------- test/evp_extra_test.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 15 deletions(-) diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index d92059cbcc..eb6ccfaca2 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -25,6 +25,19 @@ #include "crypto/evp.h" #include "evp_local.h" +static void cleanup_old_md_data(EVP_MD_CTX *ctx, int force) +{ + if (ctx->digest != NULL) { + if (ctx->digest->cleanup != NULL + && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED)) + ctx->digest->cleanup(ctx); + if (ctx->md_data != NULL && ctx->digest->ctx_size > 0 + && (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE) + || force)) + OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); + ctx->md_data = NULL; + } +} void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force) { @@ -41,12 +54,7 @@ void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force) * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because * sometimes only copies of the context are ever finalised. */ - if (ctx->digest && ctx->digest->cleanup - && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED)) - ctx->digest->cleanup(ctx); - if (ctx->digest && ctx->digest->ctx_size && ctx->md_data - && (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE) || force)) - OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); + cleanup_old_md_data(ctx, force); if (force) ctx->digest = NULL; @@ -207,7 +215,8 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) || tmpimpl != NULL #endif - || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0) { + || (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) != 0 + || type->origin == EVP_ORIG_METH) { if (ctx->digest == ctx->fetched_digest) ctx->digest = NULL; EVP_MD_free(ctx->fetched_digest); @@ -215,10 +224,7 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, goto legacy; } - if (ctx->digest != NULL && ctx->digest->ctx_size > 0) { - OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); - ctx->md_data = NULL; - } + cleanup_old_md_data(ctx, 1); /* Start of non-legacy code below */ @@ -307,10 +313,8 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type, } #endif if (ctx->digest != type) { - if (ctx->digest && ctx->digest->ctx_size) { - OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); - ctx->md_data = NULL; - } + cleanup_old_md_data(ctx, 1); + ctx->digest = type; if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) { ctx->update = type->update; diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 47ef35ca67..21bc2eb4df 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -4179,6 +4179,90 @@ static int test_evp_md_cipher_meth(void) return testresult; } +typedef struct { + int data; +} custom_dgst_ctx; + +static int custom_md_init_called = 0; +static int custom_md_cleanup_called = 0; + +static int custom_md_init(EVP_MD_CTX *ctx) +{ + custom_dgst_ctx *p = EVP_MD_CTX_md_data(ctx); + + if (p == NULL) + return 0; + + custom_md_init_called++; + return 1; +} + +static int custom_md_cleanup(EVP_MD_CTX *ctx) +{ + custom_dgst_ctx *p = EVP_MD_CTX_md_data(ctx); + + if (p == NULL) + /* Nothing to do */ + return 1; + + custom_md_cleanup_called++; + return 1; +} + +static int test_custom_md_meth(void) +{ + EVP_MD_CTX *mdctx = NULL; + EVP_MD *tmp = NULL; + char mess[] = "Test Message\n"; + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; + int testresult = 0; + int nid; + + /* + * We are testing deprecated functions. We don't support a non-default + * library context in this test. + */ + if (testctx != NULL) + return 1; + + custom_md_init_called = custom_md_cleanup_called = 0; + + nid = OBJ_create("1.3.6.1.4.1.16604.998866.1", "custom-md", "custom-md"); + if (!TEST_int_ne(nid, NID_undef)) + goto err; + tmp = EVP_MD_meth_new(nid, NID_undef); + if (!TEST_ptr(tmp)) + goto err; + + if (!TEST_true(EVP_MD_meth_set_init(tmp, custom_md_init)) + || !TEST_true(EVP_MD_meth_set_cleanup(tmp, custom_md_cleanup)) + || !TEST_true(EVP_MD_meth_set_app_datasize(tmp, + sizeof(custom_dgst_ctx)))) + goto err; + + mdctx = EVP_MD_CTX_new(); + if (!TEST_ptr(mdctx) + /* + * Initing our custom md and then initing another md should + * result in the init and cleanup functions of the custom md + * from being called. + */ + || !TEST_true(EVP_DigestInit_ex(mdctx, tmp, NULL)) + || !TEST_true(EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) + || !TEST_true(EVP_DigestUpdate(mdctx, mess, strlen(mess))) + || !TEST_true(EVP_DigestFinal_ex(mdctx, md_value, &md_len)) + || !TEST_int_eq(custom_md_init_called, 1) + || !TEST_int_eq(custom_md_cleanup_called, 1)) + goto err; + + testresult = 1; + err: + EVP_MD_CTX_free(mdctx); + EVP_MD_meth_free(tmp); + return testresult; +} + # ifndef OPENSSL_NO_DYNAMIC_ENGINE /* Test we can create a signature keys with an associated ENGINE */ static int test_signatures_with_engine(int tst) @@ -4473,6 +4557,7 @@ int setup_tests(void) #ifndef OPENSSL_NO_DEPRECATED_3_0 ADD_ALL_TESTS(test_custom_pmeth, 12); ADD_TEST(test_evp_md_cipher_meth); + ADD_TEST(test_custom_md_meth); # ifndef OPENSSL_NO_DYNAMIC_ENGINE /* Tests only support the default libctx */