[openssl] master update

Matt Caswell matt at openssl.org
Thu Oct 3 08:53:16 UTC 2019


The branch master has been updated
       via  14bec2c4b4a74f7de3bdf4b3fff764d8842c27ab (commit)
       via  15de965ff04ccecb068f3ce6c643555dce9372c6 (commit)
       via  9a071fef00a6d58cfbce4dab4848eda12f1c7dcf (commit)
       via  5f5c3b4f278bedea466bc4338649b8c540372264 (commit)
       via  a0b6c1ffd0261152c523c5c000e9c025b39fd630 (commit)
       via  aa64cf248f29b14ae4525e31445d247033c3dddb (commit)
       via  45a845e40bf68f1ed9aca6d465ddd508996d7d2f (commit)
       via  d8c98d79d1bb1dc3261d9b4fc2bc36074aec88f6 (commit)
      from  6a41156c20cbccc56c46bf6a5f7d2ac45cc1679a (commit)


- Log -----------------------------------------------------------------
commit 14bec2c4b4a74f7de3bdf4b3fff764d8842c27ab
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 26 14:55:00 2019 +0100

    Free a fetched digest during EVP_MD_CTX_reset() not EVP_MD_free()
    
    Otherwise a mem leak can occur since EVP_MD_free() calls
    EVP_MD_CTX_reset() which then clears the contents of the ctx.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit 15de965ff04ccecb068f3ce6c643555dce9372c6
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 26 14:31:56 2019 +0100

    Don't call EVP_MD_CTX_reset during EVP_DigestFinal
    
    This resets the fields of the EVP_MD_CTX and means we can no longer
    make calls using the EVP_MD_CTX, such as to query parameters.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit 9a071fef00a6d58cfbce4dab4848eda12f1c7dcf
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Sep 25 11:49:04 2019 +0100

    Add a test for the newly added md params code
    
    Previous commits added code for routing md related parameters via and
    EVP_SIGNATURE implementation during a DigestSign operation. This adds a
    test to make sure this works as expected.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit 5f5c3b4f278bedea466bc4338649b8c540372264
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 24 12:07:48 2019 +0100

    Update EVP_MD_CTX_get_params() et al to be EVP_DigestSign*() aware
    
    If doing an EVP_DigestSign*() or EVP_DigestVerify*() operation we use
    the embedded pctx for communication with the provider. Any MD params need
    to use that ctx instead.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit a0b6c1ffd0261152c523c5c000e9c025b39fd630
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 23 16:43:08 2019 +0100

    Update documentation
    
    Add documentation for EVP_DigestSignInit_ex() and
    EVP_DigestVerifyInit_ex(), and add an appropriate CHANGES entry.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit aa64cf248f29b14ae4525e31445d247033c3dddb
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 24 10:23:41 2019 +0100

    Ensure we look at EVP_MD_CTX_FLAG_KEEP_PKEY_CTX in non-legacy code
    
    This flag is still relevant even for non-legacy code so we should check
    it where appropriate.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit 45a845e40bf68f1ed9aca6d465ddd508996d7d2f
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 23 14:36:32 2019 +0100

    Add EVP_DigestSign/EVP_DigestVerify support for DSA
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

commit d8c98d79d1bb1dc3261d9b4fc2bc36074aec88f6
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 16 17:14:21 2019 +0100

    Add the provider function signatures for DigestSign*
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10013)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                           |   6 ++
 crypto/evp/digest.c               | 111 +++++++++++++-------
 crypto/evp/evp_local.h            |  10 ++
 crypto/evp/m_sigver.c             | 195 +++++++++++++++++++++++++++++++++--
 crypto/evp/pmeth_fn.c             | 107 +++++++++++++++++--
 doc/man3/EVP_DigestSignInit.pod   |  73 +++++++++----
 doc/man3/EVP_DigestVerifyInit.pod | 106 ++++++++++++++++---
 include/openssl/core_numbers.h    |  45 ++++++--
 include/openssl/evp.h             |  10 +-
 providers/common/signature/dsa.c  | 210 +++++++++++++++++++++++++++++++++++++-
 test/evp_extra_test.c             |  32 ++++++
 util/libcrypto.num                |   4 +
 12 files changed, 808 insertions(+), 101 deletions(-)

diff --git a/CHANGES b/CHANGES
index a4672fa21a..db1dc416e8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,12 @@
 
  Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
 
+  *) Introduced the new functions EVP_DigestSignInit_ex() and
+     EVP_DigestVerifyInit_ex(). The macros EVP_DigestSignUpdate() and
+     EVP_DigestVerifyUpdate() have been converted to functions. See the man
+     pages for further details.
+     [Matt Caswell]
+
   *) s390x assembly pack: add hardware-support for P-256, P-384, P-521,
      X25519, X448, Ed25519 and Ed448.
      [Patrick Steuer]
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 1ce529241f..874b16b6ee 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -24,8 +24,19 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
     if (ctx == NULL)
         return 1;
 
-    if (ctx->digest == NULL || ctx->digest->prov == NULL)
-        goto legacy;
+#ifndef FIPS_MODE
+    /* TODO(3.0): Temporarily no support for EVP_DigestSign* in FIPS module */
+    /*
+     * pctx should be freed by the user of EVP_MD_CTX
+     * if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set
+     */
+    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
+        EVP_PKEY_CTX_free(ctx->pctx);
+#endif
+
+    EVP_MD_free(ctx->fetched_digest);
+    ctx->fetched_digest = NULL;
+    ctx->reqdigest = NULL;
 
     if (ctx->provctx != NULL) {
         if (ctx->digest->freectx != NULL)
@@ -34,13 +45,7 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
         EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
     }
 
-    if (ctx->pctx != NULL)
-        goto legacy;
-
-    return 1;
-
     /* TODO(3.0): Remove legacy code below */
- legacy:
 
     /*
      * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
@@ -53,19 +58,13 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
         && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
         OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
     }
-    /*
-     * pctx should be freed by the user of EVP_MD_CTX
-     * if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set
-     */
-#ifndef FIPS_MODE
-    /* TODO(3.0): Temporarily no support for EVP_DigestSign* in FIPS module */
-    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
-        EVP_PKEY_CTX_free(ctx->pctx);
 
-# ifndef OPENSSL_NO_ENGINE
+#if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE)
     ENGINE_finish(ctx->engine);
-# endif
 #endif
+
+    /* TODO(3.0): End of legacy code */
+
     OPENSSL_cleanse(ctx, sizeof(*ctx));
 
     return 1;
@@ -81,23 +80,10 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
     if (ctx == NULL)
         return;
 
-    if (ctx->digest == NULL || ctx->digest->prov == NULL)
-        goto legacy;
-
     EVP_MD_CTX_reset(ctx);
 
-    EVP_MD_free(ctx->fetched_digest);
-    ctx->fetched_digest = NULL;
-    ctx->digest = NULL;
-    ctx->reqdigest = NULL;
-
     OPENSSL_free(ctx);
     return;
-
-    /* TODO(3.0): Remove legacy code below */
- legacy:
-    EVP_MD_CTX_reset(ctx);
-    OPENSSL_free(ctx);
 }
 
 int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
@@ -114,6 +100,16 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
 
     EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
 
+    if (ctx->provctx != NULL) {
+        if (!ossl_assert(ctx->digest != NULL)) {
+            EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
+            return 0;
+        }
+        if (ctx->digest->freectx != NULL)
+            ctx->digest->freectx(ctx->provctx);
+        ctx->provctx = NULL;
+    }
+
     if (type != NULL)
         ctx->reqdigest = type;
 
@@ -339,7 +335,6 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize)
         }
     }
 
-    EVP_MD_CTX_reset(ctx);
     return ret;
 
     /* TODO(3.0): Remove legacy code below */
@@ -545,8 +540,18 @@ const OSSL_PARAM *EVP_MD_gettable_params(const EVP_MD *digest)
 
 int EVP_MD_CTX_set_params(EVP_MD_CTX *ctx, const OSSL_PARAM params[])
 {
+    EVP_PKEY_CTX *pctx = ctx->pctx;
+
     if (ctx->digest != NULL && ctx->digest->set_ctx_params != NULL)
         return ctx->digest->set_ctx_params(ctx->provctx, params);
+
+    if (pctx != NULL
+            && (pctx->operation == EVP_PKEY_OP_VERIFYCTX
+                || pctx->operation == EVP_PKEY_OP_SIGNCTX)
+            && pctx->op.sig.sigprovctx != NULL
+            && pctx->op.sig.signature->set_ctx_md_params != NULL)
+        return pctx->op.sig.signature->set_ctx_md_params(pctx->op.sig.sigprovctx,
+                                                         params);
     return 0;
 }
 
@@ -559,18 +564,40 @@ const OSSL_PARAM *EVP_MD_settable_ctx_params(const EVP_MD *md)
 
 const OSSL_PARAM *EVP_MD_CTX_settable_params(EVP_MD_CTX *ctx)
 {
+    EVP_PKEY_CTX *pctx;
+
     if (ctx != NULL
             && ctx->digest != NULL
             && ctx->digest->settable_ctx_params != NULL)
         return ctx->digest->settable_ctx_params();
 
+    pctx = ctx->pctx;
+    if (pctx != NULL
+            && (pctx->operation == EVP_PKEY_OP_VERIFYCTX
+                || pctx->operation == EVP_PKEY_OP_SIGNCTX)
+            && pctx->op.sig.sigprovctx != NULL
+            && pctx->op.sig.signature->settable_ctx_md_params != NULL)
+        return pctx->op.sig.signature->settable_ctx_md_params(
+                   pctx->op.sig.sigprovctx);
+
     return NULL;
 }
 
 int EVP_MD_CTX_get_params(EVP_MD_CTX *ctx, OSSL_PARAM params[])
 {
+    EVP_PKEY_CTX *pctx = ctx->pctx;
+
     if (ctx->digest != NULL && ctx->digest->get_params != NULL)
         return ctx->digest->get_ctx_params(ctx->provctx, params);
+
+    if (pctx != NULL
+            && (pctx->operation == EVP_PKEY_OP_VERIFYCTX
+                || pctx->operation == EVP_PKEY_OP_SIGNCTX)
+            && pctx->op.sig.sigprovctx != NULL
+            && pctx->op.sig.signature->get_ctx_md_params != NULL)
+        return pctx->op.sig.signature->get_ctx_md_params(pctx->op.sig.sigprovctx,
+                                                         params);
+
     return 0;
 }
 
@@ -583,11 +610,22 @@ const OSSL_PARAM *EVP_MD_gettable_ctx_params(const EVP_MD *md)
 
 const OSSL_PARAM *EVP_MD_CTX_gettable_params(EVP_MD_CTX *ctx)
 {
+    EVP_PKEY_CTX *pctx;
+
     if (ctx != NULL
             && ctx->digest != NULL
             && ctx->digest->gettable_ctx_params != NULL)
         return ctx->digest->gettable_ctx_params();
 
+    pctx = ctx->pctx;
+    if (pctx != NULL
+            && (pctx->operation == EVP_PKEY_OP_VERIFYCTX
+                || pctx->operation == EVP_PKEY_OP_SIGNCTX)
+            && pctx->op.sig.sigprovctx != NULL
+            && pctx->op.sig.signature->gettable_ctx_md_params != NULL)
+        return pctx->op.sig.signature->gettable_ctx_md_params(
+                    pctx->op.sig.sigprovctx);
+
     return NULL;
 }
 
@@ -604,7 +642,10 @@ int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2)
         return 0;
     }
 
-    if (ctx->digest->prov == NULL)
+    if (ctx->digest->prov == NULL
+        && (ctx->pctx == NULL
+            || (ctx->pctx->operation != EVP_PKEY_OP_VERIFYCTX
+                && ctx->pctx->operation != EVP_PKEY_OP_SIGNCTX)))
         goto legacy;
 
     switch (cmd) {
@@ -622,9 +663,9 @@ int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2)
     }
 
     if (set_params)
-        ret = evp_do_md_ctx_setparams(ctx->digest, ctx->provctx, params);
+        ret = EVP_MD_CTX_set_params(ctx, params);
     else
-        ret = evp_do_md_ctx_getparams(ctx->digest, ctx->provctx, params);
+        ret = EVP_MD_CTX_get_params(ctx, params);
     return ret;
 
 
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index ec0f823bd5..b14d27c8ba 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -129,12 +129,22 @@ struct evp_signature_st {
     OSSL_OP_signature_verify_fn *verify;
     OSSL_OP_signature_verify_recover_init_fn *verify_recover_init;
     OSSL_OP_signature_verify_recover_fn *verify_recover;
+    OSSL_OP_signature_digest_sign_init_fn *digest_sign_init;
+    OSSL_OP_signature_digest_sign_update_fn *digest_sign_update;
+    OSSL_OP_signature_digest_sign_final_fn *digest_sign_final;
+    OSSL_OP_signature_digest_verify_init_fn *digest_verify_init;
+    OSSL_OP_signature_digest_verify_update_fn *digest_verify_update;
+    OSSL_OP_signature_digest_verify_final_fn *digest_verify_final;
     OSSL_OP_signature_freectx_fn *freectx;
     OSSL_OP_signature_dupctx_fn *dupctx;
     OSSL_OP_signature_get_ctx_params_fn *get_ctx_params;
     OSSL_OP_signature_gettable_ctx_params_fn *gettable_ctx_params;
     OSSL_OP_signature_set_ctx_params_fn *set_ctx_params;
     OSSL_OP_signature_settable_ctx_params_fn *settable_ctx_params;
+    OSSL_OP_signature_get_ctx_md_params_fn *get_ctx_md_params;
+    OSSL_OP_signature_gettable_ctx_md_params_fn *gettable_ctx_md_params;
+    OSSL_OP_signature_set_ctx_md_params_fn *set_ctx_md_params;
+    OSSL_OP_signature_settable_ctx_md_params_fn *settable_ctx_md_params;
 } /* EVP_SIGNATURE */;
 
 int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index 2e179bee27..85272c9516 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -13,6 +13,7 @@
 #include <openssl/objects.h>
 #include <openssl/x509.h>
 #include "crypto/evp.h"
+#include "internal/provider.h"
 #include "evp_local.h"
 
 static int update(EVP_MD_CTX *ctx, const void *data, size_t datalen)
@@ -22,14 +23,121 @@ static int update(EVP_MD_CTX *ctx, const void *data, size_t datalen)
 }
 
 static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
-                          const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
-                          int ver)
+                          const EVP_MD *type, const char *mdname,
+                          const char *props, ENGINE *e, EVP_PKEY *pkey,
+                          EVP_SIGNATURE *signature, int ver)
 {
-    if (ctx->pctx == NULL)
+    EVP_PKEY_CTX *locpctx = NULL;
+    void *provkey = NULL;
+    int ret;
+
+    if (ctx->provctx != NULL) {
+        if (!ossl_assert(ctx->digest != NULL)) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            return 0;
+        }
+        if (ctx->digest->freectx != NULL)
+            ctx->digest->freectx(ctx->provctx);
+        ctx->provctx = NULL;
+    }
+
+    if (ctx->pctx == NULL) {
         ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
-    if (ctx->pctx == NULL)
-        return 0;
+        if (ctx->pctx == NULL)
+            return 0;
+    } else if (pkey != NULL) {
+        if (!EVP_PKEY_up_ref(pkey))
+            return 0;
+        EVP_PKEY_free(ctx->pctx->pkey);
+        ctx->pctx->pkey = pkey;
+    }
+    locpctx = ctx->pctx;
+    evp_pkey_ctx_free_old_ops(locpctx);
+    if (locpctx->pkey == NULL)
+        goto legacy;
+
+    if (e != NULL || locpctx->engine != NULL)
+        goto legacy;
+
+    if (signature != NULL) {
+        if (!EVP_SIGNATURE_up_ref(signature))
+            goto err;
+    } else {
+        /*
+         * TODO(3.0): Check for legacy handling. Remove this once all all
+         * algorithms are moved to providers.
+         */
+        switch (locpctx->pkey->type) {
+        case NID_dsa:
+            break;
+        default:
+            goto legacy;
+        }
+        signature
+            = EVP_SIGNATURE_fetch(NULL, OBJ_nid2sn(locpctx->pkey->type), NULL);
+
+        if (signature == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+    }
+    locpctx->operation = ver ? EVP_PKEY_OP_VERIFYCTX
+                             : EVP_PKEY_OP_SIGNCTX;
+
+    locpctx->op.sig.signature = signature;
+
+    locpctx->op.sig.sigprovctx
+        = signature->newctx(ossl_provider_ctx(signature->prov));
+    if (locpctx->op.sig.sigprovctx == NULL) {
+        ERR_raise(ERR_LIB_EVP,  EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
+    provkey = evp_keymgmt_export_to_provider(locpctx->pkey, signature->keymgmt);
+    if (provkey == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
+
+    if (mdname == NULL) {
+        mdname = EVP_MD_name(type);
+        ctx->reqdigest = type;
+    } else {
+        /*
+         * This might be requested by a later call to EVP_MD_CTX_md(). In that
+         * case the "explicit fetch" rules apply for that function (as per
+         * man pages), i.e. the ref count is not updated so the EVP_MD should
+         * not be used beyound the lifetime of the EVP_MD_CTX.
+         */
+        ctx->reqdigest
+            = ctx->fetched_digest
+            = EVP_MD_fetch(
+                ossl_provider_library_context(EVP_SIGNATURE_provider(signature)),
+                mdname, props);
+    }
+
+    if (ver) {
+        if (signature->digest_verify_init == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+        ret = signature->digest_verify_init(locpctx->op.sig.sigprovctx, mdname,
+                                            props, provkey);
+    } else {
+        if (signature->digest_sign_init == NULL) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+        ret = signature->digest_sign_init(locpctx->op.sig.sigprovctx, mdname,
+                                          props, provkey);
+    }
 
+    return ret ? 1 : 0;
+ err:
+    evp_pkey_ctx_free_old_ops(locpctx);
+    locpctx->operation = EVP_PKEY_OP_UNDEFINED;
+    return 0;
+
+ legacy:
     if (!(ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)) {
 
         if (type == NULL) {
@@ -85,23 +193,85 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
     return 1;
 }
 
+int EVP_DigestSignInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                          const char *mdname, const char *props, EVP_PKEY *pkey,
+                          EVP_SIGNATURE *signature)
+{
+    return do_sigver_init(ctx, pctx, NULL, mdname, props, NULL, pkey, signature,
+                          0);
+}
+
 int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                        const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
 {
-    return do_sigver_init(ctx, pctx, type, e, pkey, 0);
+    return do_sigver_init(ctx, pctx, type, NULL, NULL, e, pkey, NULL, 0);
+}
+
+int EVP_DigestVerifyInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                            const char *mdname, const char *props,
+                            EVP_PKEY *pkey, EVP_SIGNATURE *signature)
+{
+    return do_sigver_init(ctx, pctx, NULL, mdname, props, NULL, pkey, signature,
+                          1);
 }
 
 int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                          const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
 {
-    return do_sigver_init(ctx, pctx, type, e, pkey, 1);
+    return do_sigver_init(ctx, pctx, type, NULL, NULL, e, pkey, NULL, 1);
+}
+
+int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize)
+{
+    EVP_PKEY_CTX *pctx = ctx->pctx;
+
+    if (pctx == NULL
+            || pctx->operation != EVP_PKEY_OP_SIGNCTX
+            || pctx->op.sig.sigprovctx == NULL
+            || pctx->op.sig.signature == NULL)
+        goto legacy;
+
+    return pctx->op.sig.signature->digest_sign_update(pctx->op.sig.sigprovctx,
+                                                      data, dsize);
+
+ legacy:
+    return EVP_DigestUpdate(ctx, data, dsize);
 }
 
+int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize)
+{
+    EVP_PKEY_CTX *pctx = ctx->pctx;
+
+    if (pctx == NULL
+            || pctx->operation != EVP_PKEY_OP_VERIFYCTX
+            || pctx->op.sig.sigprovctx == NULL
+            || pctx->op.sig.signature == NULL)
+        goto legacy;
+
+    return pctx->op.sig.signature->digest_verify_update(pctx->op.sig.sigprovctx,
+                                                        data, dsize);
+
+ legacy:
+    return EVP_DigestUpdate(ctx, data, dsize);
+}
+
+
 int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
                         size_t *siglen)
 {
     int sctx = 0, r = 0;
     EVP_PKEY_CTX *pctx = ctx->pctx;
+
+    if (pctx == NULL
+            || pctx->operation != EVP_PKEY_OP_SIGNCTX
+            || pctx->op.sig.sigprovctx == NULL
+            || pctx->op.sig.signature == NULL)
+        goto legacy;
+
+    return pctx->op.sig.signature->digest_sign_final(pctx->op.sig.sigprovctx,
+                                                     sigret, siglen, SIZE_MAX);
+
+ legacy:
     if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) {
         if (!sigret)
             return pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
@@ -177,7 +347,18 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
     int r = 0;
     unsigned int mdlen = 0;
     int vctx = 0;
+    EVP_PKEY_CTX *pctx = ctx->pctx;
+
+    if (pctx == NULL
+            || pctx->operation != EVP_PKEY_OP_VERIFYCTX
+            || pctx->op.sig.sigprovctx == NULL
+            || pctx->op.sig.signature == NULL)
+        goto legacy;
+
+    return pctx->op.sig.signature->digest_verify_final(pctx->op.sig.sigprovctx,
+                                                       sig, siglen);
 
+ legacy:
     if (ctx->pctx->pmeth->verifyctx)
         vctx = 1;
     else
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index e3af13ddf8..c7940e8e38 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -52,7 +52,8 @@ static void *evp_signature_from_dispatch(int name_id,
                                     keymgmt_data->properties);
     EVP_SIGNATURE *signature = NULL;
     int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0;
-    int gparamfncnt = 0, sparamfncnt = 0;
+    int digsignfncnt = 0, digverifyfncnt = 0;
+    int gparamfncnt = 0, sparamfncnt = 0, gmdparamfncnt = 0, smdparamfncnt = 0;
 
     if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) {
         ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE);
@@ -114,6 +115,48 @@ static void *evp_signature_from_dispatch(int name_id,
                 = OSSL_get_OP_signature_verify_recover(fns);
             verifyrecfncnt++;
             break;
+        case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT:
+            if (signature->digest_sign_init != NULL)
+                break;
+            signature->digest_sign_init
+                = OSSL_get_OP_signature_digest_sign_init(fns);
+            digsignfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE:
+            if (signature->digest_sign_update != NULL)
+                break;
+            signature->digest_sign_update
+                = OSSL_get_OP_signature_digest_sign_update(fns);
+            digsignfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL:
+            if (signature->digest_sign_final != NULL)
+                break;
+            signature->digest_sign_final
+                = OSSL_get_OP_signature_digest_sign_final(fns);
+            digsignfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT:
+            if (signature->digest_verify_init != NULL)
+                break;
+            signature->digest_verify_init
+                = OSSL_get_OP_signature_digest_verify_init(fns);
+            digverifyfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE:
+            if (signature->digest_verify_update != NULL)
+                break;
+            signature->digest_verify_update
+                = OSSL_get_OP_signature_digest_verify_update(fns);
+            digverifyfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL:
+            if (signature->digest_verify_final != NULL)
+                break;
+            signature->digest_verify_final
+                = OSSL_get_OP_signature_digest_verify_final(fns);
+            digverifyfncnt++;
+            break;
         case OSSL_FUNC_SIGNATURE_FREECTX:
             if (signature->freectx != NULL)
                 break;
@@ -153,21 +196,65 @@ static void *evp_signature_from_dispatch(int name_id,
                 = OSSL_get_OP_signature_settable_ctx_params(fns);
             sparamfncnt++;
             break;
+        case OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS:
+            if (signature->get_ctx_md_params != NULL)
+                break;
+            signature->get_ctx_md_params
+                = OSSL_get_OP_signature_get_ctx_md_params(fns);
+            gmdparamfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS:
+            if (signature->gettable_ctx_md_params != NULL)
+                break;
+            signature->gettable_ctx_md_params
+                = OSSL_get_OP_signature_gettable_ctx_md_params(fns);
+            gmdparamfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS:
+            if (signature->set_ctx_md_params != NULL)
+                break;
+            signature->set_ctx_md_params
+                = OSSL_get_OP_signature_set_ctx_md_params(fns);
+            smdparamfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS:
+            if (signature->settable_ctx_md_params != NULL)
+                break;
+            signature->settable_ctx_md_params
+                = OSSL_get_OP_signature_settable_ctx_md_params(fns);
+            smdparamfncnt++;
+            break;
         }
     }
     if (ctxfncnt != 2
-        || (signfncnt != 2 && verifyfncnt != 2 && verifyrecfncnt != 2)
+        || (signfncnt == 0
+            && verifyfncnt == 0
+            && verifyrecfncnt == 0
+            && digsignfncnt == 0
+            && digverifyfncnt == 0)
+        || (signfncnt != 0 && signfncnt != 2)
+        || (verifyfncnt != 0 && verifyfncnt != 2)
+        || (verifyrecfncnt != 0 && verifyrecfncnt != 2)
+        || (digsignfncnt != 0 && digsignfncnt != 3)
+        || (digverifyfncnt != 0 && digverifyfncnt != 3)
         || (gparamfncnt != 0 && gparamfncnt != 2)
-        || (sparamfncnt != 0 && sparamfncnt != 2)) {
+        || (sparamfncnt != 0 && sparamfncnt != 2)
+        || (gmdparamfncnt != 0 && gmdparamfncnt != 2)
+        || (smdparamfncnt != 0 && smdparamfncnt != 2)) {
         /*
          * In order to be a consistent set of functions we must have at least
-         * a set of context functions (newctx and freectx) as well as a pair of
-         * "signature" functions: (sign_init, sign) or (verify_init verify) or
-         * (verify_recover_init, verify_recover). set_ctx_params and
-         * settable_ctx_params are optional, but if one of them is present then
-         * the other one must also be present. The same applies to
-         * get_ctx_params and gettable_ctx_params. The dupctx function is
-         * optional.
+         * a set of context functions (newctx and freectx) as well as a set of
+         * "signature" functions:
+         *  (sign_init, sign) or
+         *  (verify_init verify) or
+         *  (verify_recover_init, verify_recover) or
+         *  (digest_sign_init, digest_sign_update, digest_sign_final) or
+         *  (digest_verify_init, digest_verify_update, digest_verify_final).
+         *
+         * set_ctx_params and settable_ctx_params are optional, but if one of
+         * them is present then the other one must also be present. The same
+         * applies to get_ctx_params and gettable_ctx_params. The same rules
+         * apply to the "md_params" functions. The dupctx function is optional.
          */
         ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
         goto err;
diff --git a/doc/man3/EVP_DigestSignInit.pod b/doc/man3/EVP_DigestSignInit.pod
index 0f9c952303..f730ba7b03 100644
--- a/doc/man3/EVP_DigestSignInit.pod
+++ b/doc/man3/EVP_DigestSignInit.pod
@@ -2,13 +2,16 @@
 
 =head1 NAME
 
-EVP_DigestSignInit, EVP_DigestSignUpdate, EVP_DigestSignFinal,
-EVP_DigestSign - EVP signing functions
+EVP_DigestSignInit_ex, EVP_DigestSignInit, EVP_DigestSignUpdate,
+EVP_DigestSignFinal, EVP_DigestSign - EVP signing functions
 
 =head1 SYNOPSIS
 
  #include <openssl/evp.h>
 
+ int EVP_DigestSignInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                           const char *mdname, const char *props,
+                           EVP_PKEY *pkey, EVP_SIGNATURE *signature);
  int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                         const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
  int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
@@ -21,22 +24,44 @@ EVP_DigestSign - EVP signing functions
 =head1 DESCRIPTION
 
 The EVP signature routines are a high level interface to digital signatures.
-
-EVP_DigestSignInit() sets up signing context B<ctx> to use digest B<type> from
-ENGINE B<e> and private key B<pkey>. B<ctx> must be created with
-EVP_MD_CTX_new() before calling this function. If B<pctx> is not NULL, the
-EVP_PKEY_CTX of the signing operation will be written to B<*pctx>: this can
-be used to set alternative signing options. Note that any existing value in
-B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must not be freed
-directly by the application if B<ctx> is not assigned an EVP_PKEY_CTX value before
-being passed to EVP_DigestSignInit() (which means the EVP_PKEY_CTX is created
-inside EVP_DigestSignInit() and it will be freed automatically when the
-EVP_MD_CTX is freed).
-
-The digest B<type> may be NULL if the signing algorithm supports it.
-
-No B<EVP_PKEY_CTX> will be created by EVP_DigestSignInit() if the passed B<ctx>
-has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also L<SM2(7)>.
+Input data is digested first before the signing takes place.
+
+EVP_DigestSignInit_ex() sets up signing context B<ctx> to use a digest with the
+name B<mdname> and private key B<pkey>. The signature algorithm B<signature>
+will be used for the actual signing which must be compatible with the private
+key. The name of the digest to be used is passed to the provider of the
+signature algorithm in use. How that provider interprets the digest name is
+provider specific. The provider may implement that digest directly itself or it
+may (optionally) choose to fetch it (which could result in a digest from a
+different provider being selected). If the provider supports fetching the digest
+then it may use the B<props> argument for the properties to be used during the
+fetch.
+
+The B<signature> parameter may be NULL in which case a suitable signature
+algorithm implementation will be implicitly fetched based on the type of key in
+use. See L<provider(7)> for further information about providers and fetching
+algorithms.
+
+The OpenSSL default and legacy providers support fetching digests and can fetch
+those digests from any available provider. The OpenSSL fips provider also
+supports fetching digests but will only fetch digests that are themselves
+implemented inside the fips provider.
+
+B<ctx> must be created with EVP_MD_CTX_new() before calling this function. If
+B<pctx> is not NULL, the EVP_PKEY_CTX of the signing operation will be written
+to B<*pctx>: this can be used to set alternative signing options. Note that any
+existing value in B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must
+not be freed directly by the application if B<ctx> is not assigned an
+EVP_PKEY_CTX value before being passed to EVP_DigestSignInit_ex() (which means
+the EVP_PKEY_CTX is created inside EVP_DigestSignInit_ex() and it will be freed
+automatically when the EVP_MD_CTX is freed).
+
+The digest B<mdname> may be NULL if the signing algorithm supports it. The
+B<props> argument can always be NULL.
+
+No B<EVP_PKEY_CTX> will be created by EVP_DigestSignInit_ex() if the passed
+B<ctx> has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also
+L<SM2(7)>.
 
 Only EVP_PKEY types that support signing can be used with these functions. This
 includes MAC algorithms where the MAC generation is considered as a form of
@@ -84,10 +109,14 @@ Will ignore any digest provided.
 
 If RSA-PSS is used and restrictions apply then the digest must match.
 
+EVP_DigestSignInit() works in the same way as EVP_DigestSignInit_ex() except
+that the B<mdname> parameter will be inferred from the supplied digest B<type>,
+and B<props> will be NULL. Where supplied the ENGINE B<e> will be used for the
+signing and digest algorithm implementations. B<e> may be NULL.
+
 EVP_DigestSignUpdate() hashes B<cnt> bytes of data at B<d> into the
 signature context B<ctx>. This function can be called several times on the
-same B<ctx> to include additional data. This function is currently implemented
-using a macro.
+same B<ctx> to include additional data.
 
 EVP_DigestSignFinal() signs the data in B<ctx> and places the signature in B<sig>.
 If B<sig> is B<NULL> then the maximum size of the output buffer is written to
@@ -156,6 +185,10 @@ L<RAND(7)>
 EVP_DigestSignInit(), EVP_DigestSignUpdate() and EVP_DigestSignFinal()
 were added in OpenSSL 1.0.0.
 
+EVP_DigestSignInit_ex() was added in OpenSSL 3.0.
+
+EVP_DigestSignUpdate() was converted from a macro to a function in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/EVP_DigestVerifyInit.pod b/doc/man3/EVP_DigestVerifyInit.pod
index 97bb773722..480c6cb72a 100644
--- a/doc/man3/EVP_DigestVerifyInit.pod
+++ b/doc/man3/EVP_DigestVerifyInit.pod
@@ -2,13 +2,16 @@
 
 =head1 NAME
 
-EVP_DigestVerifyInit, EVP_DigestVerifyUpdate, EVP_DigestVerifyFinal,
-EVP_DigestVerify - EVP signature verification functions
+EVP_DigestVerifyInit_ex, EVP_DigestVerifyInit, EVP_DigestVerifyUpdate,
+EVP_DigestVerifyFinal, EVP_DigestVerify - EVP signature verification functions
 
 =head1 SYNOPSIS
 
  #include <openssl/evp.h>
 
+ int EVP_DigestVerifyInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                             const char *mdname, const char *props,
+                             EVP_PKEY *pkey, EVP_SIGNATURE *signature);
  int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                           const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
  int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
@@ -20,25 +23,91 @@ EVP_DigestVerify - EVP signature verification functions
 =head1 DESCRIPTION
 
 The EVP signature routines are a high level interface to digital signatures.
+Input data is digested first before the signature verification takes place.
 
-EVP_DigestVerifyInit() sets up verification context B<ctx> to use digest
-B<type> from ENGINE B<e> and public key B<pkey>. B<ctx> must be created
-with EVP_MD_CTX_new() before calling this function. If B<pctx> is not NULL, the
-EVP_PKEY_CTX of the verification operation will be written to B<*pctx>: this
-can be used to set alternative verification options. Note that any existing
-value in B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must not be freed
-directly by the application if B<ctx> is not assigned an EVP_PKEY_CTX value before
-being passed to EVP_DigestVerifyInit() (which means the EVP_PKEY_CTX is created
-inside EVP_DigestVerifyInit() and it will be freed automatically when the
-EVP_MD_CTX is freed).
+EVP_DigestVerifyInit_ex() sets up verification context B<ctx> to use a digest
+with the name B<mdname> and public key B<pkey>. The signature algorithm
+B<signature> will be used for the actual signature verification which must be
+compatible with the public key. The name of the digest to be used is passed to
+the provider of the signature algorithm in use. How that provider interprets the
+digest name is provider specific. The provider may implement that digest
+directly itself or it may (optionally) choose to fetch it (which could result in
+a digest from a different provider being selected). If the provider supports
+fetching the digest then it may use the B<props> argument for the properties to
+be used during the fetch.
 
-No B<EVP_PKEY_CTX> will be created by EVP_DigestSignInit() if the passed B<ctx>
-has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also L<SM2(7)>.
+The B<signature> parameter may be NULL in which case a suitable signature
+algorithm implementation will be implicitly fetched based on the type of key in
+use. See L<provider(7)> for further information about providers and fetching
+algorithms.
+
+The OpenSSL default and legacy providers support fetching digests and can fetch
+those digests from any available provider. The OpenSSL fips provider also
+supports fetching digests but will only fetch digests that are themselves
+implemented inside the fips provider.
+
+B<ctx> must be created with EVP_MD_CTX_new() before calling this function. If
+B<pctx> is not NULL, the EVP_PKEY_CTX of the verification operation will be
+written to B<*pctx>: this can be used to set alternative verification options.
+Note that any existing value in B<*pctx> is overwritten. The EVP_PKEY_CTX value
+returned must not be freed directly by the application if B<ctx> is not assigned
+an EVP_PKEY_CTX value before being passed to EVP_DigestVerifyInit_ex() (which
+means the EVP_PKEY_CTX is created inside EVP_DigestVerifyInit_ex() and it will
+be freed automatically when the EVP_MD_CTX is freed).
+
+No B<EVP_PKEY_CTX> will be created by EVP_DigestSignInit_ex() if the passed
+B<ctx> has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also
+L<SM2(7)>.
+
+Not all digests can be used for all key types. The following combinations apply.
+
+=over 4
+
+=item DSA
+
+Supports SHA1, SHA224, SHA256, SHA384 and SHA512
+
+=item ECDSA
+
+Supports SHA1, SHA224, SHA256, SHA384, SHA512 and SM3
+
+=item RSA with no padding
+
+Supports no digests (the digest B<type> must be NULL)
+
+=item RSA with X931 padding
+
+Supports SHA1, SHA256, SHA384 and SHA512
+
+=item All other RSA padding types
+
+Support SHA1, SHA224, SHA256, SHA384, SHA512, MD5, MD5_SHA1, MD2, MD4, MDC2,
+SHA3-224, SHA3-256, SHA3-384, SHA3-512
+
+=item Ed25519 and Ed448
+
+Support no digests (the digest B<type> must be NULL)
+
+=item HMAC
+
+Supports any digest
+
+=item CMAC, Poly1305 and SipHash
+
+Will ignore any digest provided.
+
+=back
+
+If RSA-PSS is used and restrictions apply then the digest must match.
+
+EVP_DigestVerifyInit() works in the same way as EVP_DigestVerifyInit_ex() except
+that the B<mdname> parameter will be inferred from the supplied digest B<type>,
+and B<props> will be NULL. Where supplied the ENGINE B<e> will be used for the
+signature verification and digest algorithm implementations. B<e> may be NULL.
 
 EVP_DigestVerifyUpdate() hashes B<cnt> bytes of data at B<d> into the
 verification context B<ctx>. This function can be called several times on the
-same B<ctx> to include additional data. This function is currently implemented
-using a macro.
+same B<ctx> to include additional data.
 
 EVP_DigestVerifyFinal() verifies the data in B<ctx> against the signature in
 B<sig> of length B<siglen>.
@@ -102,6 +171,11 @@ L<RAND(7)>
 EVP_DigestVerifyInit(), EVP_DigestVerifyUpdate() and EVP_DigestVerifyFinal()
 were added in OpenSSL 1.0.0.
 
+EVP_DigestVerifyInit_ex() was added in OpenSSL 3.0.
+
+EVP_DigestVerifyUpdate() was converted from a macro to a function in OpenSSL
+3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h
index cec38069f2..5268aca21f 100644
--- a/include/openssl/core_numbers.h
+++ b/include/openssl/core_numbers.h
@@ -413,12 +413,22 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keyexch_settable_ctx_params,
 # define OSSL_FUNC_SIGNATURE_VERIFY                  5
 # define OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT     6
 # define OSSL_FUNC_SIGNATURE_VERIFY_RECOVER          7
-# define OSSL_FUNC_SIGNATURE_FREECTX                 8
-# define OSSL_FUNC_SIGNATURE_DUPCTX                  9
-# define OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS         10
-# define OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS    11
-# define OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS         12
-# define OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS    13
+# define OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT        8
+# define OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE      9
+# define OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL      10
+# define OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT     11
+# define OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE   12
+# define OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL    13
+# define OSSL_FUNC_SIGNATURE_FREECTX                14
+# define OSSL_FUNC_SIGNATURE_DUPCTX                 15
+# define OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS         16
+# define OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS    17
+# define OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS         18
+# define OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS    19
+# define OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS      20
+# define OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS 21
+# define OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS      22
+# define OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS 23
 
 OSSL_CORE_MAKE_FUNC(void *, OP_signature_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(int, OP_signature_sign_init, (void *ctx, void *provkey))
@@ -440,6 +450,21 @@ OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_recover, (void *ctx,
                                                        size_t routsize,
                                                        const unsigned char *sig,
                                                        size_t siglen))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_digest_sign_init,
+                    (void *ctx, const char *mdname, const char *props,
+                     void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_digest_sign_update,
+                    (void *ctx, const unsigned char *data, size_t datalen))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_digest_sign_final,
+                    (void *ctx, unsigned char *sig, size_t *siglen,
+                     size_t sigsize))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_digest_verify_init,
+                    (void *ctx, const char *mdname, const char *props,
+                     void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_digest_verify_update,
+                    (void *ctx, const unsigned char *data, size_t datalen))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_digest_verify_final,
+                    (void *ctx, const unsigned char *sig, size_t siglen))
 OSSL_CORE_MAKE_FUNC(void, OP_signature_freectx, (void *ctx))
 OSSL_CORE_MAKE_FUNC(void *, OP_signature_dupctx, (void *ctx))
 OSSL_CORE_MAKE_FUNC(int, OP_signature_get_ctx_params,
@@ -450,6 +475,14 @@ OSSL_CORE_MAKE_FUNC(int, OP_signature_set_ctx_params,
                     (void *ctx, const OSSL_PARAM params[]))
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_settable_ctx_params,
                     (void))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_get_ctx_md_params,
+                    (void *ctx, OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_gettable_ctx_md_params,
+                    (void *ctx))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_set_ctx_md_params,
+                    (void *ctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_settable_ctx_md_params,
+                    (void *ctx))
 
 # ifdef __cplusplus
 }
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index fd9855d380..99eef2461d 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -533,8 +533,6 @@ void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data);
 # define EVP_VerifyUpdate(a,b,c)         EVP_DigestUpdate(a,b,c)
 # define EVP_OpenUpdate(a,b,c,d,e)       EVP_DecryptUpdate(a,b,c,d,e)
 # define EVP_SealUpdate(a,b,c,d,e)       EVP_EncryptUpdate(a,b,c,d,e)
-# define EVP_DigestSignUpdate(a,b,c)     EVP_DigestUpdate(a,b,c)
-# define EVP_DigestVerifyUpdate(a,b,c)   EVP_DigestUpdate(a,b,c)
 
 # ifdef CONST_STRICT
 void BIO_set_md(BIO *, const EVP_MD *md);
@@ -670,15 +668,23 @@ __owur int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
                             size_t siglen, const unsigned char *tbs,
                             size_t tbslen);
 
+int EVP_DigestSignInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                          const char *mdname, const char *props, EVP_PKEY *pkey,
+                          EVP_SIGNATURE *signature);
 /*__owur*/ int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                                   const EVP_MD *type, ENGINE *e,
                                   EVP_PKEY *pkey);
+int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize);
 __owur int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
                                size_t *siglen);
 
+int EVP_DigestVerifyInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+                            const char *mdname, const char *props,
+                            EVP_PKEY *pkey, EVP_SIGNATURE *signature);
 __owur int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                                 const EVP_MD *type, ENGINE *e,
                                 EVP_PKEY *pkey);
+int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize);
 __owur int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
                                  size_t siglen);
 
diff --git a/providers/common/signature/dsa.c b/providers/common/signature/dsa.c
index dc4eb6c6d4..1d6b565d38 100644
--- a/providers/common/signature/dsa.c
+++ b/providers/common/signature/dsa.c
@@ -12,18 +12,31 @@
 #include <openssl/core_names.h>
 #include <openssl/dsa.h>
 #include <openssl/params.h>
+#include <openssl/evp.h>
 #include "internal/provider_algs.h"
+#include "internal/provider_ctx.h"
 
 static OSSL_OP_signature_newctx_fn dsa_newctx;
 static OSSL_OP_signature_sign_init_fn dsa_signature_init;
 static OSSL_OP_signature_verify_init_fn dsa_signature_init;
 static OSSL_OP_signature_sign_fn dsa_sign;
+static OSSL_OP_signature_verify_fn dsa_verify;
+static OSSL_OP_signature_digest_sign_init_fn dsa_digest_signverify_init;
+static OSSL_OP_signature_digest_sign_update_fn dsa_digest_signverify_update;
+static OSSL_OP_signature_digest_sign_final_fn dsa_digest_sign_final;
+static OSSL_OP_signature_digest_verify_init_fn dsa_digest_signverify_init;
+static OSSL_OP_signature_digest_verify_update_fn dsa_digest_signverify_update;
+static OSSL_OP_signature_digest_verify_final_fn dsa_digest_verify_final;
 static OSSL_OP_signature_freectx_fn dsa_freectx;
 static OSSL_OP_signature_dupctx_fn dsa_dupctx;
 static OSSL_OP_signature_get_ctx_params_fn dsa_get_ctx_params;
 static OSSL_OP_signature_gettable_ctx_params_fn dsa_gettable_ctx_params;
 static OSSL_OP_signature_set_ctx_params_fn dsa_set_ctx_params;
 static OSSL_OP_signature_settable_ctx_params_fn dsa_settable_ctx_params;
+static OSSL_OP_signature_get_ctx_md_params_fn dsa_get_ctx_md_params;
+static OSSL_OP_signature_gettable_ctx_md_params_fn dsa_gettable_ctx_md_params;
+static OSSL_OP_signature_set_ctx_md_params_fn dsa_set_ctx_md_params;
+static OSSL_OP_signature_settable_ctx_md_params_fn dsa_settable_ctx_md_params;
 
 /*
  * What's passed as an actual key is defined by the KEYMGMT interface.
@@ -32,15 +45,24 @@ static OSSL_OP_signature_settable_ctx_params_fn dsa_settable_ctx_params;
  */
 
 typedef struct {
+    OPENSSL_CTX *libctx;
     DSA *dsa;
     size_t mdsize;
     /* Should be big enough */
     char mdname[80];
+    EVP_MD *md;
+    EVP_MD_CTX *mdctx;
 } PROV_DSA_CTX;
 
 static void *dsa_newctx(void *provctx)
 {
-    return OPENSSL_zalloc(sizeof(PROV_DSA_CTX));
+    PROV_DSA_CTX *pdsactx = OPENSSL_zalloc(sizeof(PROV_DSA_CTX));
+
+    if (pdsactx == NULL)
+        return NULL;
+
+    pdsactx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+    return pdsactx;
 }
 
 static int dsa_signature_init(void *vpdsactx, void *vdsa)
@@ -93,12 +115,97 @@ static int dsa_verify(void *vpdsactx, const unsigned char *sig, size_t siglen,
     return DSA_verify(0, tbs, tbslen, sig, siglen, pdsactx->dsa);
 }
 
+static int dsa_digest_signverify_init(void *vpdsactx, const char *mdname,
+                                      const char *props, void *vdsa)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+    EVP_MD *md;
+
+    if (!dsa_signature_init(vpdsactx, vdsa))
+        return 0;
+
+    md = EVP_MD_fetch(pdsactx->libctx, mdname, props);
+    if (md == NULL)
+        return 0;
+    pdsactx->md = md;
+    pdsactx->mdsize = EVP_MD_size(md);
+    pdsactx->mdctx = EVP_MD_CTX_new();
+    if (pdsactx->mdctx == NULL)
+        return 0;
+
+    if (!EVP_DigestInit_ex(pdsactx->mdctx, md, NULL))
+        return 0;
+
+    return 1;
+}
+
+int dsa_digest_signverify_update(void *vpdsactx, const unsigned char *data,
+                                 size_t datalen)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx == NULL || pdsactx->mdctx == NULL)
+        return 0;
+
+    return EVP_DigestUpdate(pdsactx->mdctx, data, datalen);
+}
+
+int dsa_digest_sign_final(void *vpdsactx, unsigned char *sig, size_t *siglen,
+                          size_t sigsize)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+    unsigned char digest[EVP_MAX_MD_SIZE];
+    unsigned int dlen = 0;
+
+    if (pdsactx == NULL || pdsactx->mdctx == NULL)
+        return 0;
+
+    /*
+     * If sig is NULL then we're just finding out the sig size. Other fields
+     * are ignored. Defer to dsa_sign.
+     */
+    if (sig != NULL) {
+        /*
+         * TODO(3.0): There is the possibility that some externally provided
+         * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
+         * but that problem is much larger than just in DSA.
+         */
+        if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen))
+            return 0;
+    }
+
+    return dsa_sign(vpdsactx, sig, siglen, sigsize, digest, (size_t)dlen);
+}
+
+
+int dsa_digest_verify_final(void *vpdsactx, const unsigned char *sig,
+                            size_t siglen)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+    unsigned char digest[EVP_MAX_MD_SIZE];
+    unsigned int dlen = 0;
+
+    if (pdsactx == NULL || pdsactx->mdctx == NULL)
+        return 0;
+
+    /*
+     * TODO(3.0): There is the possibility that some externally provided
+     * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
+     * but that problem is much larger than just in DSA.
+     */
+    if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen))
+        return 0;
+
+    return dsa_verify(vpdsactx, sig, siglen, digest, (size_t)dlen);
+}
 
 static void dsa_freectx(void *vpdsactx)
 {
     PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
 
     DSA_free(pdsactx->dsa);
+    EVP_MD_CTX_free(pdsactx->mdctx);
+    EVP_MD_free(pdsactx->md);
 
     OPENSSL_free(pdsactx);
 }
@@ -113,12 +220,29 @@ static void *dsa_dupctx(void *vpdsactx)
         return NULL;
 
     *dstctx = *srcctx;
-    if (dstctx->dsa != NULL && !DSA_up_ref(dstctx->dsa)) {
-        OPENSSL_free(dstctx);
-        return NULL;
+    dstctx->dsa = NULL;
+    dstctx->md = NULL;
+    dstctx->mdctx = NULL;
+
+    if (srcctx->dsa != NULL && !DSA_up_ref(srcctx->dsa))
+        goto err;
+    dstctx->dsa = srcctx->dsa;
+
+    if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
+        goto err;
+    dstctx->md = srcctx->md;
+
+    if (srcctx->mdctx != NULL) {
+        dstctx->mdctx = EVP_MD_CTX_new();
+        if (dstctx->mdctx == NULL
+                || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
+            goto err;
     }
 
     return dstctx;
+ err:
+    dsa_freectx(dstctx);
+    return NULL;
 }
 
 static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params)
@@ -134,7 +258,9 @@ static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params)
         return 0;
 
     p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
-    if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdsactx->mdname))
+    if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdsactx->md == NULL
+                                                    ? pdsactx->mdname
+                                                    : EVP_MD_name(pdsactx->md)))
         return 0;
 
     return 1;
@@ -160,6 +286,14 @@ static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[])
     if (pdsactx == NULL || params == NULL)
         return 0;
 
+    if (pdsactx->md != NULL) {
+        /*
+         * You cannot set the digest name/size when doing a DigestSign or
+         * DigestVerify.
+         */
+        return 1;
+    }
+
     p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
     if (p != NULL && !OSSL_PARAM_get_size_t(p, &pdsactx->mdsize))
         return 0;
@@ -186,15 +320,73 @@ static const OSSL_PARAM known_settable_ctx_params[] = {
 
 static const OSSL_PARAM *dsa_settable_ctx_params(void)
 {
+    /*
+     * TODO(3.0): Should this function return a different set of settable ctx
+     * params if the ctx is being used for a DigestSign/DigestVerify? In that
+     * case it is not allowed to set the digest size/digest name because the
+     * digest is explicitly set as part of the init.
+     */
     return known_settable_ctx_params;
 }
 
+static int dsa_get_ctx_md_params(void *vpdsactx, OSSL_PARAM *params)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx->mdctx == NULL)
+        return 0;
+
+    return EVP_MD_CTX_get_params(pdsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *dsa_gettable_ctx_md_params(void *vpdsactx)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx->md == NULL)
+        return 0;
+
+    return EVP_MD_gettable_ctx_params(pdsactx->md);
+}
+
+static int dsa_set_ctx_md_params(void *vpdsactx, const OSSL_PARAM params[])
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx->mdctx == NULL)
+        return 0;
+
+    return EVP_MD_CTX_set_params(pdsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *dsa_settable_ctx_md_params(void *vpdsactx)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx->md == NULL)
+        return 0;
+
+    return EVP_MD_settable_ctx_params(pdsactx->md);
+}
+
 const OSSL_DISPATCH dsa_signature_functions[] = {
     { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))dsa_newctx },
     { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))dsa_signature_init },
     { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))dsa_sign },
     { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))dsa_signature_init },
     { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))dsa_verify },
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
+      (void (*)(void))dsa_digest_signverify_init },
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
+      (void (*)(void))dsa_digest_signverify_update },
+    { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
+      (void (*)(void))dsa_digest_sign_final },
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
+      (void (*)(void))dsa_digest_signverify_init },
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
+      (void (*)(void))dsa_digest_signverify_update },
+    { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
+      (void (*)(void))dsa_digest_verify_final },
     { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))dsa_freectx },
     { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))dsa_dupctx },
     { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))dsa_get_ctx_params },
@@ -203,5 +395,13 @@ const OSSL_DISPATCH dsa_signature_functions[] = {
     { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))dsa_set_ctx_params },
     { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
       (void (*)(void))dsa_settable_ctx_params },
+    { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
+      (void (*)(void))dsa_get_ctx_md_params },
+    { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
+      (void (*)(void))dsa_gettable_ctx_md_params },
+    { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
+      (void (*)(void))dsa_set_ctx_md_params },
+    { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
+      (void (*)(void))dsa_settable_ctx_md_params },
     { 0, NULL }
 };
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 12c21e195c..d7f63f0247 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -1077,6 +1077,7 @@ done:
 /* Test getting and setting parameters on an EVP_PKEY_CTX */
 static int test_EVP_PKEY_CTX_get_set_params(void)
 {
+    EVP_MD_CTX *mdctx = NULL;
     EVP_PKEY_CTX *ctx = NULL;
     EVP_SIGNATURE *dsaimpl = NULL;
     const OSSL_PARAM *params;
@@ -1087,6 +1088,7 @@ static int test_EVP_PKEY_CTX_get_set_params(void)
     int ret = 0;
     const EVP_MD *md;
     size_t mdsize = SHA512_DIGEST_LENGTH;
+    char ssl3ms[48];
 
     /*
      * Setup the parameters for our DSA object. For our purposes they don't have
@@ -1171,9 +1173,39 @@ static int test_EVP_PKEY_CTX_get_set_params(void)
             || !TEST_ptr_eq(md, EVP_sha256()))
         goto err;
 
+    /*
+     * Test getting MD parameters via an associated EVP_PKEY_CTX
+     */
+    mdctx = EVP_MD_CTX_new();
+    if (!TEST_ptr(mdctx)
+            || !TEST_true(EVP_DigestSignInit_ex(mdctx, NULL, "SHA1", NULL,
+                                                pkey, dsaimpl)))
+        goto err;
+
+    /*
+     * We now have an EVP_MD_CTX with an EVP_PKEY_CTX inside it. We should be
+     * able to obtain the digest's settable parameters from the provider.
+     */
+    params = EVP_MD_CTX_settable_params(mdctx);
+    if (!TEST_ptr(params)
+            || !TEST_int_eq(strcmp(params[0].key, OSSL_DIGEST_PARAM_SSL3_MS), 0)
+               /* The final key should be NULL */
+            || !TEST_ptr_null(params[1].key))
+        goto err;
+
+    param = ourparams;
+    memset(ssl3ms, 0, sizeof(ssl3ms));
+    *param++ = OSSL_PARAM_construct_octet_string(OSSL_DIGEST_PARAM_SSL3_MS,
+                                                 ssl3ms, sizeof(ssl3ms));
+    *param++ = OSSL_PARAM_construct_end();
+
+    if (!TEST_true(EVP_MD_CTX_set_params(mdctx, ourparams)))
+        goto err;
+
     ret = 1;
 
  err:
+    EVP_MD_CTX_free(mdctx);
     EVP_PKEY_CTX_free(ctx);
     EVP_SIGNATURE_free(dsaimpl);
     EVP_PKEY_free(pkey);
diff --git a/util/libcrypto.num b/util/libcrypto.num
index e8d71385ae..0b1e57e9e5 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4822,3 +4822,7 @@ OSSL_CMP_log_close                      4938	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_print_errors_cb                4939	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CRMF_CERTID_get0_issuer            4940	3_0_0	EXIST::FUNCTION:CRMF
 OSSL_CRMF_CERTID_get0_serialNumber      4941	3_0_0	EXIST::FUNCTION:CRMF
+EVP_DigestSignInit_ex                   4942	3_0_0	EXIST::FUNCTION:
+EVP_DigestSignUpdate                    4943	3_0_0	EXIST::FUNCTION:
+EVP_DigestVerifyInit_ex                 4944	3_0_0	EXIST::FUNCTION:
+EVP_DigestVerifyUpdate                  4945	3_0_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list