summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-03-10 09:38:09 +0000
committerPauli <ppzgs1@gmail.com>2022-03-13 11:43:26 +1100
commitc0b7dac66edde45b8da80918f5b5b62d1e766a0c (patch)
tree7f19cfd89b2ea3f1117b162bdfde6811f45c1b16 /crypto
parentabdb2278d2b65ae87bee3121be83322e4219b396 (diff)
EVP_MD performance fix (refcount cache contention)
Partial fix for #17064. Avoid excessive writes to the cache line containing the refcount for an EVP_MD object to avoid extreme cache contention when using a single EVP_MD at high frequency on multiple threads. This changes performance in 3.0 from being double that of 1.1 to only slightly higher than that of 1.1. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/17857)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/evp/digest.c32
-rw-r--r--crypto/evp/m_sigver.c2
2 files changed, 22 insertions, 12 deletions
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index db2eed6355..cd930ebd7a 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -40,7 +40,7 @@ static void cleanup_old_md_data(EVP_MD_CTX *ctx, int force)
}
}
-void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force)
+void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force, int keep_fetched)
{
if (ctx->algctx != NULL) {
if (ctx->digest != NULL && ctx->digest->freectx != NULL)
@@ -65,13 +65,14 @@ void evp_md_ctx_clear_digest(EVP_MD_CTX *ctx, int force)
#endif
/* Non legacy code, this has to be later than the ctx->digest cleaning */
- EVP_MD_free(ctx->fetched_digest);
- ctx->fetched_digest = NULL;
- ctx->reqdigest = NULL;
+ if (!keep_fetched) {
+ EVP_MD_free(ctx->fetched_digest);
+ ctx->fetched_digest = NULL;
+ ctx->reqdigest = NULL;
+ }
}
-/* This call frees resources associated with the context */
-int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
+static int evp_md_ctx_reset_ex(EVP_MD_CTX *ctx, int keep_fetched)
{
if (ctx == NULL)
return 1;
@@ -87,12 +88,19 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
}
#endif
- evp_md_ctx_clear_digest(ctx, 0);
- OPENSSL_cleanse(ctx, sizeof(*ctx));
+ evp_md_ctx_clear_digest(ctx, 0, keep_fetched);
+ if (!keep_fetched)
+ OPENSSL_cleanse(ctx, sizeof(*ctx));
return 1;
}
+/* This call frees resources associated with the context */
+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
+{
+ return evp_md_ctx_reset_ex(ctx, 0);
+}
+
#ifndef FIPS_MODULE
EVP_MD_CTX *evp_md_ctx_new_ex(EVP_PKEY *pkey, const ASN1_OCTET_STRING *id,
OSSL_LIB_CTX *libctx, const char *propq)
@@ -524,6 +532,7 @@ int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in)
int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
{
+ int digest_change = 0;
unsigned char *tmp_buf;
if (in == NULL) {
@@ -549,15 +558,16 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
return 0;
}
- EVP_MD_CTX_reset(out);
- if (out->fetched_digest != NULL)
+ 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 (in->fetched_digest != NULL)
+ if (digest_change && in->fetched_digest != NULL)
EVP_MD_up_ref(in->fetched_digest);
if (in->algctx != NULL) {
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index 0993de0937..371bca5001 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -231,7 +231,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
* We're about to get a new digest so clear anything associated with
* an old digest.
*/
- evp_md_ctx_clear_digest(ctx, 1);
+ evp_md_ctx_clear_digest(ctx, 1, 0);
/* legacy code support for engines */
ERR_set_mark();