]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add CTX copy function for EVP_MD to optimize the performance of EVP_MD_CTX_copy_ex.
authorwangcheng <bangwangnj@163.com>
Sat, 26 Oct 2024 09:10:38 +0000 (17:10 +0800)
committerTomas Mraz <tomas@openssl.org>
Wed, 20 Nov 2024 13:12:53 +0000 (14:12 +0100)
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
doc/man7/provider-digest.pod
include/crypto/evp.h
include/openssl/core_dispatch.h
providers/implementations/digests/blake2_prov.c
providers/implementations/digests/sha3_prov.c
providers/implementations/include/prov/digestcommon.h
test/evp_extra_test2.c

index 0fdd545306dcbae1502f8a5b00171a7324a68847..6aa175fb3f4beb7f63afaa1fbcae3bcd1d45f248 100644 (file)
@@ -617,23 +617,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;
+            }
         }
     }
 
@@ -1103,6 +1115,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 && fncnt != 6)
index d23da59e1a0218dfefc283fd79baa28d4adc248b..751321c84b20e510cad7322663164d0c82b661db 100644 (file)
@@ -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
@@ -273,6 +283,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
 
index 72d9995e8f0f417d0d5535c45b81598955b1e6f4..4775c05ecd7faa53f6803ff554391c51eb4a0d04 100644 (file)
@@ -285,6 +285,7 @@ struct evp_md_st {
     OSSL_FUNC_digest_squeeze_fn *dsqueeze;
     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;
index 03838ddd0e9750738aa59b6f833a51ff70151c90..9243aa9ec1bdccfe28c91c0b26817c0725956a8e 100644 (file)
@@ -305,6 +305,7 @@ OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx))
 # define OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS       12
 # define OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS       13
 # define OSSL_FUNC_DIGEST_SQUEEZE                   14
+# define OSSL_FUNC_DIGEST_COPYCTX                   15
 
 OSSL_CORE_MAKE_FUNC(void *, digest_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(int, digest_init, (void *dctx, const OSSL_PARAM params[]))
@@ -322,6 +323,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,
index be1ceb5ed6780917b21dcaf9664890333ff15c09..5495aab61a87275304208ae9579e5e78ae61d60b 100644 (file)
@@ -133,6 +133,15 @@ static void *blake##variantsize##_dupctx(void *ctx) \
     if (ret != NULL) \
         *ret = *in; \
     return ret; \
+} \
+\
+static void blake##variantsize##_copyctx(void *voutctx, void *vinctx) \
+{ \
+    struct blake##variant##_md_data_st *inctx, *outctx; \
+ \
+    outctx = (struct blake##variant##_md_data_st *)voutctx; \
+    inctx = (struct blake##variant##_md_data_st *)vinctx; \
+    *outctx = *inctx; \
 } \
  \
 static int blake##variantsize##_internal_final(void *ctx, unsigned char *out, \
@@ -169,6 +178,7 @@ const OSSL_DISPATCH ossl_blake##variantsize##_functions[] = { \
     {OSSL_FUNC_DIGEST_FINAL, (void (*)(void))blake##variantsize##_internal_final}, \
     {OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))blake##variantsize##_freectx}, \
     {OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))blake##variantsize##_dupctx}, \
+    {OSSL_FUNC_DIGEST_COPYCTX, (void (*)(void))blake##variantsize##_copyctx}, \
     {OSSL_FUNC_DIGEST_GET_PARAMS, (void (*)(void))blake##variantsize##_get_params}, \
     {OSSL_FUNC_DIGEST_GETTABLE_PARAMS, \
      (void (*)(void))ossl_digest_default_gettable_params}, \
index 4a4386ff8b4db632e3fb4302b255cd0adc119bc1..d4f6d9797cd3bb545994efcdad427d72b56fe70d 100644 (file)
@@ -33,6 +33,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_squeeze_fn shake_squeeze;
 static OSSL_FUNC_digest_get_ctx_params_fn shake_get_ctx_params;
@@ -534,6 +535,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)          \
@@ -560,6 +562,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;
index abdb8bb2ad55a8d5d9a84caee48e834e639881e4..332d473490274d425eb0bcf06930ca4baf613c47 100644 (file)
@@ -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                               \
index 1665ac42735878d56554b08ea08b8e39c4a8a060..27b5a07375e6bdd6c361b18fb7b587b837d9145d 100644 (file)
@@ -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;
@@ -1298,6 +1300,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)
 {
@@ -1391,6 +1433,7 @@ int setup_tests(void)
     ADD_TEST(test_rsa_pss_sign);
     ADD_TEST(test_evp_md_ctx_dup);
     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);