307 lines
13 KiB
Diff
307 lines
13 KiB
Diff
From 4c41aa4b338ca181a394483c8bb6aeb6366c6f96 Mon Sep 17 00:00:00 2001
|
|
From: wangcheng <bangwangnj@163.com>
|
|
Date: Sat, 26 Oct 2024 17:10:38 +0800
|
|
Subject: [PATCH] Add CTX copy function for EVP_MD to optimize the performance
|
|
of EVP_MD_CTX_copy_ex.
|
|
|
|
1. Add OSSL_FUNC_digest_copyctx_fn function for EVP_MD, which is used to copy algctx from the old EVP_MD_CTX to the new one.
|
|
|
|
2. Add implementation of OSSL_FUNC_digest_copyctx_fn function for default providers.
|
|
|
|
3. Modify EVP_MD_CTX_copy_ex: When the fetched digest is the same in in and out contexts, use the copy function to copy the members in EVP_MD_CTX if the OSSL_FUNC_digest_copyctx_fn function exists. Otherwise, use the previous method to copy.
|
|
|
|
4. Add documentation for OSSL_FUNC_digest_copyctx function in doc/man7/provider-digest.pod.
|
|
|
|
5. Add testcase.
|
|
|
|
Fixes #25703
|
|
|
|
Signed-off-by: wangcheng <bangwangnj@163.com>
|
|
|
|
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
|
|
Reviewed-by: Tomas Mraz <tomas@openssl.org>
|
|
(Merged from https://github.com/openssl/openssl/pull/25726)
|
|
---
|
|
crypto/evp/digest.c | 47 +++++++++++++------
|
|
doc/man7/provider-digest.pod | 11 +++++
|
|
include/crypto/evp.h | 1 +
|
|
include/openssl/core_dispatch.h | 2 +
|
|
providers/implementations/digests/sha3_prov.c | 10 ++++
|
|
.../include/prov/digestcommon.h | 7 +++
|
|
test/evp_extra_test2.c | 43 +++++++++++++++++
|
|
7 files changed, 106 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
|
|
index eefed52..f5c44b1 100644
|
|
--- a/crypto/evp/digest.c
|
|
+++ b/crypto/evp/digest.c
|
|
@@ -548,23 +548,35 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
|
|
return 0;
|
|
}
|
|
|
|
- evp_md_ctx_reset_ex(out, 1);
|
|
- digest_change = (out->fetched_digest != in->fetched_digest);
|
|
- if (digest_change && out->fetched_digest != NULL)
|
|
- EVP_MD_free(out->fetched_digest);
|
|
- *out = *in;
|
|
- /* NULL out pointers in case of error */
|
|
- out->pctx = NULL;
|
|
- out->algctx = NULL;
|
|
+ if (out->digest == in->digest && in->digest->copyctx != NULL) {
|
|
|
|
- if (digest_change && in->fetched_digest != NULL)
|
|
- EVP_MD_up_ref(in->fetched_digest);
|
|
+ in->digest->copyctx(out->algctx, in->algctx);
|
|
|
|
- if (in->algctx != NULL) {
|
|
- out->algctx = in->digest->dupctx(in->algctx);
|
|
- if (out->algctx == NULL) {
|
|
- ERR_raise(ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX);
|
|
- return 0;
|
|
+ EVP_PKEY_CTX_free(out->pctx);
|
|
+ out->pctx = NULL;
|
|
+ cleanup_old_md_data(out, 0);
|
|
+
|
|
+ out->flags = in->flags;
|
|
+ out->update = in->update;
|
|
+ } else {
|
|
+ evp_md_ctx_reset_ex(out, 1);
|
|
+ digest_change = (out->fetched_digest != in->fetched_digest);
|
|
+ if (digest_change && out->fetched_digest != NULL)
|
|
+ EVP_MD_free(out->fetched_digest);
|
|
+ *out = *in;
|
|
+ /* NULL out pointers in case of error */
|
|
+ out->pctx = NULL;
|
|
+ out->algctx = NULL;
|
|
+
|
|
+ if (digest_change && in->fetched_digest != NULL)
|
|
+ EVP_MD_up_ref(in->fetched_digest);
|
|
+
|
|
+ if (in->algctx != NULL) {
|
|
+ out->algctx = in->digest->dupctx(in->algctx);
|
|
+ if (out->algctx == NULL) {
|
|
+ ERR_raise(ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX);
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -1029,6 +1041,11 @@ static void *evp_md_from_algorithm(int name_id,
|
|
md->gettable_ctx_params =
|
|
OSSL_FUNC_digest_gettable_ctx_params(fns);
|
|
break;
|
|
+ case OSSL_FUNC_DIGEST_COPYCTX:
|
|
+ if (md->copyctx == NULL)
|
|
+ md->copyctx =
|
|
+ OSSL_FUNC_digest_copyctx(fns);
|
|
+ break;
|
|
}
|
|
}
|
|
if ((fncnt != 0 && fncnt != 5)
|
|
diff --git a/doc/man7/provider-digest.pod b/doc/man7/provider-digest.pod
|
|
index cac53ac..0ed0d3b 100644
|
|
--- a/doc/man7/provider-digest.pod
|
|
+++ b/doc/man7/provider-digest.pod
|
|
@@ -20,6 +20,7 @@ provider-digest - The digest library E<lt>-E<gt> provider functions
|
|
void *OSSL_FUNC_digest_newctx(void *provctx);
|
|
void OSSL_FUNC_digest_freectx(void *dctx);
|
|
void *OSSL_FUNC_digest_dupctx(void *dctx);
|
|
+ void OSSL_FUNC_digest_copyctx(void *voutctx, void *vinctx);
|
|
|
|
/* Digest generation */
|
|
int OSSL_FUNC_digest_init(void *dctx, const OSSL_PARAM params[]);
|
|
@@ -76,6 +77,7 @@ macros in L<openssl-core_dispatch.h(7)>, as follows:
|
|
OSSL_FUNC_digest_newctx OSSL_FUNC_DIGEST_NEWCTX
|
|
OSSL_FUNC_digest_freectx OSSL_FUNC_DIGEST_FREECTX
|
|
OSSL_FUNC_digest_dupctx OSSL_FUNC_DIGEST_DUPCTX
|
|
+ OSSL_FUNC_digest_copyctx OSSL_FUNC_DIGEST_COPYCTX
|
|
|
|
OSSL_FUNC_digest_init OSSL_FUNC_DIGEST_INIT
|
|
OSSL_FUNC_digest_update OSSL_FUNC_DIGEST_UPDATE
|
|
@@ -111,6 +113,14 @@ This function should free any resources associated with that context.
|
|
OSSL_FUNC_digest_dupctx() should duplicate the provider side digest context in the
|
|
I<dctx> parameter and return the duplicate copy.
|
|
|
|
+OSSL_FUNC_digest_copyctx() should copy the provider side digest context in the
|
|
+I<vinctx> parameter to the I<voutctx> parameter which is the another provider side
|
|
+context.
|
|
+The OSSL_FUNC_digest_copyctx function is used in the EVP_MD_CTX_copy_ex function to
|
|
+speed up HMAC operations in the PBKDF2.
|
|
+This function is optional, and dupctx will be used if there is no EVP_MD_CTX_copy_ex
|
|
+function.
|
|
+
|
|
=head2 Digest Generation Functions
|
|
|
|
OSSL_FUNC_digest_init() initialises a digest operation given a newly created
|
|
@@ -274,6 +284,7 @@ L<life_cycle-digest(7)>, L<EVP_DigestInit(3)>
|
|
=head1 HISTORY
|
|
|
|
The provider DIGEST interface was introduced in OpenSSL 3.0.
|
|
+OSSL_FUNC_digest_copyctx() was added in 3.5 version.
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
|
|
index e70d8e9..f17b569 100644
|
|
--- a/include/crypto/evp.h
|
|
+++ b/include/crypto/evp.h
|
|
@@ -277,6 +277,7 @@ struct evp_md_st {
|
|
OSSL_FUNC_digest_final_fn *dfinal;
|
|
OSSL_FUNC_digest_digest_fn *digest;
|
|
OSSL_FUNC_digest_freectx_fn *freectx;
|
|
+ OSSL_FUNC_digest_copyctx_fn *copyctx;
|
|
OSSL_FUNC_digest_dupctx_fn *dupctx;
|
|
OSSL_FUNC_digest_get_params_fn *get_params;
|
|
OSSL_FUNC_digest_set_ctx_params_fn *set_ctx_params;
|
|
diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h
|
|
index 99fcda0..e6fa38d 100644
|
|
--- a/include/openssl/core_dispatch.h
|
|
+++ b/include/openssl/core_dispatch.h
|
|
@@ -283,6 +283,7 @@ OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx))
|
|
# define OSSL_FUNC_DIGEST_GETTABLE_PARAMS 11
|
|
# define OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS 12
|
|
# define OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS 13
|
|
+# define OSSL_FUNC_DIGEST_COPYCTX 14
|
|
|
|
OSSL_CORE_MAKE_FUNC(void *, digest_newctx, (void *provctx))
|
|
OSSL_CORE_MAKE_FUNC(int, digest_init, (void *dctx, const OSSL_PARAM params[]))
|
|
@@ -297,6 +298,7 @@ OSSL_CORE_MAKE_FUNC(int, digest_digest,
|
|
|
|
OSSL_CORE_MAKE_FUNC(void, digest_freectx, (void *dctx))
|
|
OSSL_CORE_MAKE_FUNC(void *, digest_dupctx, (void *dctx))
|
|
+OSSL_CORE_MAKE_FUNC(void, digest_copyctx, (void *outctx, void *inctx))
|
|
|
|
OSSL_CORE_MAKE_FUNC(int, digest_get_params, (OSSL_PARAM params[]))
|
|
OSSL_CORE_MAKE_FUNC(int, digest_set_ctx_params,
|
|
diff --git a/providers/implementations/digests/sha3_prov.c b/providers/implementations/digests/sha3_prov.c
|
|
index 168825d..3929f97 100644
|
|
--- a/providers/implementations/digests/sha3_prov.c
|
|
+++ b/providers/implementations/digests/sha3_prov.c
|
|
@@ -32,6 +32,7 @@ static OSSL_FUNC_digest_init_fn keccak_init_params;
|
|
static OSSL_FUNC_digest_update_fn keccak_update;
|
|
static OSSL_FUNC_digest_final_fn keccak_final;
|
|
static OSSL_FUNC_digest_freectx_fn keccak_freectx;
|
|
+static OSSL_FUNC_digest_copyctx_fn keccak_copyctx;
|
|
static OSSL_FUNC_digest_dupctx_fn keccak_dupctx;
|
|
static OSSL_FUNC_digest_set_ctx_params_fn shake_set_ctx_params;
|
|
static OSSL_FUNC_digest_settable_ctx_params_fn shake_settable_ctx_params;
|
|
@@ -236,6 +237,7 @@ const OSSL_DISPATCH ossl_##name##_functions[] = { \
|
|
{ OSSL_FUNC_DIGEST_FINAL, (void (*)(void))keccak_final }, \
|
|
{ OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))keccak_freectx }, \
|
|
{ OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))keccak_dupctx }, \
|
|
+ { OSSL_FUNC_DIGEST_COPYCTX, (void (*)(void))keccak_copyctx }, \
|
|
PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name)
|
|
|
|
#define PROV_FUNC_SHA3_DIGEST(name, bitlen, blksize, dgstsize, flags) \
|
|
@@ -258,6 +260,14 @@ static void keccak_freectx(void *vctx)
|
|
OPENSSL_clear_free(ctx, sizeof(*ctx));
|
|
}
|
|
|
|
+static void keccak_copyctx(void *voutctx, void *vinctx)
|
|
+{
|
|
+ KECCAK1600_CTX *outctx = (KECCAK1600_CTX *)voutctx;
|
|
+ KECCAK1600_CTX *inctx = (KECCAK1600_CTX *)vinctx;
|
|
+
|
|
+ *outctx = *inctx;
|
|
+}
|
|
+
|
|
static void *keccak_dupctx(void *ctx)
|
|
{
|
|
KECCAK1600_CTX *in = (KECCAK1600_CTX *)ctx;
|
|
diff --git a/providers/implementations/include/prov/digestcommon.h b/providers/implementations/include/prov/digestcommon.h
|
|
index abdb8bb..332d473 100644
|
|
--- a/providers/implementations/include/prov/digestcommon.h
|
|
+++ b/providers/implementations/include/prov/digestcommon.h
|
|
@@ -70,6 +70,12 @@ static void *name##_dupctx(void *ctx) \
|
|
*ret = *in; \
|
|
return ret; \
|
|
} \
|
|
+static void name##_copyctx(void *voutctx, void *vinctx) \
|
|
+{ \
|
|
+ CTX *outctx = (CTX *)voutctx; \
|
|
+ CTX *inctx = (CTX *)vinctx; \
|
|
+ *outctx = *inctx; \
|
|
+} \
|
|
PROV_FUNC_DIGEST_FINAL(name, dgstsize, fin) \
|
|
PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \
|
|
const OSSL_DISPATCH ossl_##name##_functions[] = { \
|
|
@@ -78,6 +84,7 @@ const OSSL_DISPATCH ossl_##name##_functions[] = { \
|
|
{ OSSL_FUNC_DIGEST_FINAL, (void (*)(void))name##_internal_final }, \
|
|
{ OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))name##_freectx }, \
|
|
{ OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))name##_dupctx }, \
|
|
+ { OSSL_FUNC_DIGEST_COPYCTX, (void (*)(void))name##_copyctx }, \
|
|
PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name)
|
|
|
|
# define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END \
|
|
diff --git a/test/evp_extra_test2.c b/test/evp_extra_test2.c
|
|
index 68329b0..be7db00 100644
|
|
--- a/test/evp_extra_test2.c
|
|
+++ b/test/evp_extra_test2.c
|
|
@@ -27,6 +27,8 @@
|
|
|
|
#include "testutil.h"
|
|
#include "internal/nelem.h"
|
|
+#include "crypto/evp.h"
|
|
+#include "../crypto/evp/evp_local.h"
|
|
|
|
static OSSL_LIB_CTX *mainctx = NULL;
|
|
static OSSL_PROVIDER *nullprov = NULL;
|
|
@@ -1193,6 +1195,46 @@ static int test_evp_md_ctx_copy(void)
|
|
return ret;
|
|
}
|
|
|
|
+static int test_evp_md_ctx_copy2(void)
|
|
+{
|
|
+ int ret = 0;
|
|
+ EVP_MD *md = NULL;
|
|
+ OSSL_LIB_CTX *ctx = NULL;
|
|
+ EVP_MD_CTX *inctx = NULL, *outctx = NULL;
|
|
+ void *origin_algctx = NULL;
|
|
+
|
|
+ if (!TEST_ptr(ctx = OSSL_LIB_CTX_new())
|
|
+ || !TEST_ptr(md = EVP_MD_fetch(ctx, "sha256", NULL)))
|
|
+ goto end;
|
|
+
|
|
+ inctx = EVP_MD_CTX_new();
|
|
+ outctx = EVP_MD_CTX_new();
|
|
+
|
|
+ if (!TEST_ptr(inctx) || !TEST_ptr(outctx))
|
|
+ goto end;
|
|
+
|
|
+ /* init inctx and outctx, now the contexts are from same providers */
|
|
+ if (!TEST_true(EVP_DigestInit_ex2(inctx, md, NULL)))
|
|
+ goto end;
|
|
+ if (!TEST_true(EVP_DigestInit_ex2(outctx, md, NULL)))
|
|
+ goto end;
|
|
+
|
|
+ /*
|
|
+ * Test the EVP_MD_CTX_copy_ex function. After copying,
|
|
+ * outctx->algctx should be the same as the original.
|
|
+ */
|
|
+ origin_algctx = outctx->algctx;
|
|
+ ret = TEST_true(EVP_MD_CTX_copy_ex(outctx, inctx))
|
|
+ && TEST_true(outctx->algctx == origin_algctx);
|
|
+
|
|
+end:
|
|
+ EVP_MD_free(md);
|
|
+ EVP_MD_CTX_free(inctx);
|
|
+ EVP_MD_CTX_free(outctx);
|
|
+ OSSL_LIB_CTX_free(ctx);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
#if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_MD5
|
|
static int test_evp_pbe_alg_add(void)
|
|
{
|
|
@@ -1262,6 +1304,7 @@ int setup_tests(void)
|
|
ADD_ALL_TESTS(test_PEM_read_bio_negative_wrong_password, 2);
|
|
ADD_TEST(test_rsa_pss_sign);
|
|
ADD_TEST(test_evp_md_ctx_copy);
|
|
+ ADD_TEST(test_evp_md_ctx_copy2);
|
|
ADD_ALL_TESTS(test_provider_unload_effective, 2);
|
|
#if !defined OPENSSL_NO_DES && !defined OPENSSL_NO_MD5
|
|
ADD_TEST(test_evp_pbe_alg_add);
|
|
--
|
|
2.33.0
|
|
|