Cache Digest constants
authorMatt Caswell <matt@openssl.org>
Tue, 22 Dec 2020 11:36:30 +0000 (11:36 +0000)
committerDmitry Belyavskiy <beldmit@gmail.com>
Wed, 23 Dec 2020 20:12:18 +0000 (21:12 +0100)
EVP_CIPHER already caches certain constants so that we don't have to
query the provider every time. We do the same thing with EVP_MD constants.
Without this we can get performance issues, e.g. running "speed" with
small blocks of data to digest can spend a long time in EVP_MD_size(),
which should be quick.

Partialy fixes #13578

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/13730)

crypto/evp/digest.c
crypto/evp/evp_lib.c

index 1d16c52060c0b6d89472a2d8497edf9e60ee42db..46f4d201d99e2fc9a95a2d748bf7abedf4778ec7 100644 (file)
@@ -827,6 +827,29 @@ static void set_legacy_nid(const char *name, void *vlegacy_nid)
 }
 #endif
 
+static int evp_md_cache_constants(EVP_MD *md)
+{
+    int ok;
+    size_t blksz = 0;
+    size_t mdsize = 0;
+    unsigned long flags = 0;
+    OSSL_PARAM params[4];
+
+    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, &blksz);
+    params[1] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE, &mdsize);
+    params[2] = OSSL_PARAM_construct_ulong(OSSL_DIGEST_PARAM_FLAGS, &flags);
+    params[3] = OSSL_PARAM_construct_end();
+    ok = evp_do_md_getparams(md, params);
+    if (mdsize > INT_MAX || blksz > INT_MAX)
+        ok = 0;
+    if (ok) {
+        md->block_size = (int)blksz;
+        md->md_size = (int)mdsize;
+        md->flags = flags;
+    }
+    return ok;
+}
+
 static void *evp_md_from_dispatch(int name_id,
                                   const OSSL_DISPATCH *fns,
                                   OSSL_PROVIDER *prov)
@@ -938,6 +961,12 @@ static void *evp_md_from_dispatch(int name_id,
     if (prov != NULL)
         ossl_provider_up_ref(prov);
 
+    if (!evp_md_cache_constants(md)) {
+        EVP_MD_free(md);
+        ERR_raise(ERR_LIB_EVP, EVP_R_CACHE_CONSTANTS_FAILED);
+        md = NULL;
+    }
+
     return md;
 }
 
index 48fa330ac33b78a890702125b6b1352b95cfcd2e..954acaae0d3244ee185412925216944bdbb3a062 100644 (file)
@@ -688,19 +688,7 @@ const OSSL_PROVIDER *EVP_MD_provider(const EVP_MD *md)
 
 int EVP_MD_block_size(const EVP_MD *md)
 {
-    int ok;
-    size_t v;
-    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
-
-    if (md == NULL) {
-        ERR_raise(ERR_LIB_EVP, EVP_R_MESSAGE_DIGEST_IS_NULL);
-        return -1;
-    }
-    v = md->block_size;
-    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, &v);
-    ok = evp_do_md_getparams(md, params);
-
-    return ok != 0 ? (int)v : -1;
+    return md->block_size;
 }
 
 int EVP_MD_type(const EVP_MD *md)
@@ -715,31 +703,16 @@ int EVP_MD_pkey_type(const EVP_MD *md)
 
 int EVP_MD_size(const EVP_MD *md)
 {
-    int ok;
-    size_t v;
-    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
-
     if (md == NULL) {
         ERR_raise(ERR_LIB_EVP, EVP_R_MESSAGE_DIGEST_IS_NULL);
         return -1;
     }
-    v = md->md_size;
-    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_SIZE, &v);
-    ok = evp_do_md_getparams(md, params);
-
-    return ok != 0 ? (int)v : -1;
+    return md->md_size;
 }
 
 unsigned long EVP_MD_flags(const EVP_MD *md)
 {
-    int ok;
-    unsigned long v = md->flags;
-    OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
-
-    params[0] = OSSL_PARAM_construct_ulong(OSSL_CIPHER_PARAM_FLAGS, &v);
-    ok = evp_do_md_getparams(md, params);
-
-    return ok != 0 ? v : 0;
+    return md->flags;
 }
 
 EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type)