Implement EVP_MD_fetch()
authorMatt Caswell <matt@openssl.org>
Wed, 13 Mar 2019 14:49:40 +0000 (14:49 +0000)
committerMatt Caswell <matt@openssl.org>
Thu, 21 Mar 2019 09:23:38 +0000 (09:23 +0000)
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8513)

crypto/evp/digest.c
crypto/evp/evp_lib.c
crypto/include/internal/evp_int.h
include/openssl/core_numbers.h
include/openssl/evp.h
util/libcrypto.num

index 86be9ae..08b5198 100644 (file)
@@ -13,6 +13,7 @@
 #include <openssl/evp.h>
 #include <openssl/engine.h>
 #include "internal/evp_int.h"
+#include "internal/provider.h"
 #include "evp_locl.h"
 
 /* This call frees resources associated with the context */
@@ -296,3 +297,94 @@ int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2)
     }
     return 0;
 }
+
+static void *evp_md_from_dispatch(int mdtype, const OSSL_DISPATCH *fns,
+                                    OSSL_PROVIDER *prov)
+{
+    EVP_MD *md = NULL;
+
+    if ((md = EVP_MD_meth_new(mdtype, NID_undef)) == NULL)
+        return NULL;
+
+    for (; fns->function_id != 0; fns++) {
+        int fncnt = 0;
+
+        switch (fns->function_id) {
+        case OSSL_FUNC_DIGEST_NEWCTX:
+            if (md->newctx != NULL)
+                break;
+            md->newctx = OSSL_get_OP_digest_newctx(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_DIGEST_INIT:
+            if (md->dinit != NULL)
+                break;
+            md->dinit = OSSL_get_OP_digest_init(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_DIGEST_UPDDATE:
+            if (md->dupdate != NULL)
+                break;
+            md->dupdate = OSSL_get_OP_digest_update(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_DIGEST_FINAL:
+            if (md->dfinal != NULL)
+                break;
+            md->dfinal = OSSL_get_OP_digest_final(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_DIGEST_DIGEST:
+            if (md->digest != NULL)
+                break;
+            md->digest = OSSL_get_OP_digest_digest(fns);
+            /* We don't increment fnct for this as it is stand alone */
+            break;
+        case OSSL_FUNC_DIGEST_CLEANCTX:
+            if (md->cleanctx != NULL)
+                break;
+            md->cleanctx = OSSL_get_OP_digest_cleanctx(fns);
+            fncnt++;
+            break;
+        case OSSL_FUNC_DIGEST_FREECTX:
+            if (md->freectx != NULL)
+                break;
+            md->freectx = OSSL_get_OP_digest_freectx(fns);
+            fncnt++;
+            break;
+        }
+        if ((fncnt != 0 && fncnt != 6) || (fncnt == 0 && md->digest == NULL)) {
+            /*
+             * In order to be a consistent set of functions we either need the
+             * whole set of init/update/final etc functions or none of them.
+             * The "digest" function can standalone. We at least need one way to
+             * generate digests.
+             */
+            EVP_MD_meth_free(md);
+            return NULL;
+        }
+    }
+    md->prov = prov;
+    if (prov != NULL)
+        ossl_provider_upref(prov);
+
+    return md;
+}
+
+static int evp_md_upref(void *md)
+{
+    return EVP_MD_upref(md);
+}
+
+static void evp_md_free(void *md)
+{
+    EVP_MD_meth_free(md);
+}
+
+EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                     const char *properties)
+{
+    return evp_generic_fetch(ctx, OSSL_OP_DIGEST, algorithm, properties,
+                             evp_md_from_dispatch, evp_md_upref,
+                             evp_md_free);
+}
index f0ee6ab..ed95dd5 100644 (file)
@@ -12,6 +12,7 @@
 #include <openssl/evp.h>
 #include <openssl/objects.h>
 #include "internal/evp_int.h"
+#include "internal/provider.h"
 #include "evp_locl.h"
 
 int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
@@ -331,6 +332,12 @@ EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type)
     if (md != NULL) {
         md->type = md_type;
         md->pkey_type = pkey_type;
+        md->lock = CRYPTO_THREAD_lock_new();
+        if (md->lock == NULL) {
+            OPENSSL_free(md);
+            return NULL;
+        }
+        md->refcnt = 1;
     }
     return md;
 }
@@ -342,9 +349,27 @@ EVP_MD *EVP_MD_meth_dup(const EVP_MD *md)
         memcpy(to, md, sizeof(*to));
     return to;
 }
+
+int EVP_MD_upref(EVP_MD *md)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&md->refcnt, &ref, md->lock);
+    return 1;
+}
+
 void EVP_MD_meth_free(EVP_MD *md)
 {
-    OPENSSL_free(md);
+    if (md != NULL) {
+        int i;
+
+        CRYPTO_DOWN_REF(&md->refcnt, &i, md->lock);
+        if (i > 0)
+            return;
+        ossl_provider_free(md->prov);
+        CRYPTO_THREAD_lock_free(md->lock);
+        OPENSSL_free(md);
+    }
 }
 int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize)
 {
index f6f99ed..ba0eedd 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <openssl/evp.h>
+#include <openssl/core_numbers.h>
 #include "internal/refcount.h"
 
 /*
@@ -172,7 +173,11 @@ extern const EVP_KDF_METHOD sshkdf_kdf_meth;
 extern const EVP_KDF_METHOD ss_kdf_meth;
 
 struct evp_md_st {
+    /* nid */
     int type;
+
+    /* Legacy structure members */
+    /* TODO(3.0): Remove these */
     int pkey_type;
     int md_size;
     unsigned long flags;
@@ -185,6 +190,19 @@ struct evp_md_st {
     int ctx_size;               /* how big does the ctx->md_data need to be */
     /* control function */
     int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
+
+    /* New structure members */
+    /* TODO(3.0): Remove above comment when legacy has gone */
+    OSSL_PROVIDER *prov;
+    CRYPTO_REF_COUNT refcnt;
+    CRYPTO_RWLOCK *lock;
+    OSSL_OP_digest_newctx_fn *newctx;
+    OSSL_OP_digest_init_fn *dinit;
+    OSSL_OP_digest_update_fn *dupdate;
+    OSSL_OP_digest_final_fn *dfinal;
+    OSSL_OP_digest_digest_fn *digest;
+    OSSL_OP_digest_freectx_fn *freectx;
+
 } /* EVP_MD */ ;
 
 struct evp_cipher_st {
index 7be2a2b..9bce619 100644 (file)
@@ -72,6 +72,28 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ALGORITHM *,provider_query_operation,
                     (const OSSL_PROVIDER *, int operation_id,
                      const int *no_store))
 
+/* Digests */
+
+# define OSSL_OP_DIGEST                     1
+
+# define OSSL_FUNC_DIGEST_NEWCTX            1
+# define OSSL_FUNC_DIGEST_INIT              2
+# define OSSL_FUNC_DIGEST_UPDDATE           3
+# define OSSL_FUNC_DIGEST_FINAL             4
+# define OSSL_FUNC_DIGEST_DIGEST            5
+# define OSSL_FUNC_DIGEST_FREECTX           6
+
+OSSL_CORE_MAKE_FUNC(void *, OP_digest_newctx, (void))
+OSSL_CORE_MAKE_FUNC(int, OP_digest_init, (void *vctx))
+OSSL_CORE_MAKE_FUNC(int, OP_digest_update,
+                    (void *vctx, unsigned char *in, size_t inl))
+OSSL_CORE_MAKE_FUNC(int, OP_digest_final,
+                    (void *vctx, unsigned char *out, size_t *outl))
+OSSL_CORE_MAKE_FUNC(int, OP_digest_digest,
+                    (unsigned char *in, size_t inl, unsigned char *out,
+                     size_t *out_l))
+OSSL_CORE_MAKE_FUNC(void, OP_digest_cleanctx, (void *vctx))
+OSSL_CORE_MAKE_FUNC(void, OP_digest_freectx, (void *vctx))
 
 # ifdef __cplusplus
 }
index ca7655d..db8eec1 100644 (file)
@@ -77,6 +77,7 @@ extern "C" {
 # ifndef EVP_MD
 EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type);
 EVP_MD *EVP_MD_meth_dup(const EVP_MD *md);
+int EVP_MD_upref(EVP_MD *md);
 void EVP_MD_meth_free(EVP_MD *md);
 
 int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize);
@@ -561,6 +562,9 @@ __owur int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md,
 __owur int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md,
                               size_t len);
 
+__owur EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                            const char *properties);
+
 int EVP_read_pw_string(char *buf, int length, const char *prompt, int verify);
 int EVP_read_pw_string_min(char *buf, int minlen, int maxlen,
                            const char *prompt, int verify);
index bf14bbd..5b488d0 100644 (file)
@@ -4791,3 +4791,5 @@ OSSL_PARAM_set_octet_ptr                4738      3_0_0   EXIST::FUNCTION:
 X509_set_sm2_id                         4739   3_0_0   EXIST::FUNCTION:SM2
 X509_get0_sm2_id                        4740   3_0_0   EXIST::FUNCTION:SM2
 EVP_PKEY_get0_engine                    4741   3_0_0   EXIST::FUNCTION:ENGINE
+EVP_MD_upref                            4742   3_0_0   EXIST::FUNCTION:
+EVP_MD_fetch                            4743   3_0_0   EXIST::FUNCTION: