[openssl] master update

Matt Caswell matt at openssl.org
Mon Sep 9 13:04:45 UTC 2019


The branch master has been updated
       via  20bf3d8b22f8c1a3529034007d3618fd1fc4fa16 (commit)
       via  864b89ce497c57207d04a83e23f96f50dae9d164 (commit)
       via  9c45222ddc36124b8826d98dc0794f3eef1e5f0b (commit)
       via  21fb7067228e39633755aeba251e925634e64870 (commit)
       via  4f62f5d9af4fb4c7765859967ee39252e34ceeb9 (commit)
       via  11031468c38c801b6acefe9bba9d531d92653da3 (commit)
       via  390acbebfa90500c79c5014e6659eacda861550c (commit)
       via  4889dadcb8511176c30888c748f1981adc38451d (commit)
       via  dfcb5d29b525f5d2b6bd80602dca5efe5fca77bb (commit)
      from  2b95e8efcf8b99892106070d9ac745a0a369f503 (commit)


- Log -----------------------------------------------------------------
commit 20bf3d8b22f8c1a3529034007d3618fd1fc4fa16
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Sep 5 14:57:06 2019 +0100

    Use simple names in core_names.h
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 864b89ce497c57207d04a83e23f96f50dae9d164
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Sep 4 23:13:25 2019 +0100

    Move EVP_PKEY algorithm implementations into a union
    
    An EVP_PKEY can be used for multiple different algorithm operations.
    Only one can be used at a time, so we move those into a union.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 9c45222ddc36124b8826d98dc0794f3eef1e5f0b
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Sep 4 12:46:02 2019 +0100

    Revise EVP_PKEY param handling
    
    We add new functions for getting parameters and discovering the gettable
    and settable parameters. We also make EVP_PKEY_CTX_get_signature_md() a
    function and implement it in terms of the new functions.
    
    This enables applications to discover the set of parameters that are
    supported for a given algorithm implementation.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 21fb7067228e39633755aeba251e925634e64870
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Sep 4 10:58:59 2019 +0100

    Enable DH "keys" which only contain domain parameters
    
    It is valid for a pub_key and priv_key to be missing from a DH "key".
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 4f62f5d9af4fb4c7765859967ee39252e34ceeb9
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 3 17:05:52 2019 +0100

    Add docs for the provider interface for signature operations
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 11031468c38c801b6acefe9bba9d531d92653da3
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Sep 3 16:15:21 2019 +0100

    Add public API docs for newly added EVP_SIGNATURE related functions
    
    Documentation for EVP_SIGNATURE_*() as well as EVP_PKEY_sign_init_ex(),
    EVP_PKEY_verify_init_ex() and EVP_PKEY_verify_recover_init_ex().
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 390acbebfa90500c79c5014e6659eacda861550c
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Sep 2 16:48:26 2019 +0100

    Add support for verify/verify_recover functions to EVP_SIGNATURE
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit 4889dadcb8511176c30888c748f1981adc38451d
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Aug 30 13:33:37 2019 +0100

    Implement DSA in the default provider
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

commit dfcb5d29b525f5d2b6bd80602dca5efe5fca77bb
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Aug 30 13:33:10 2019 +0100

    Add the ability to perform signatures in a provider
    
    This makes EVP_PKEY_sign and EVP_PKEY_sign_init provider aware. It
    also introduces the new type EVP_SIGNATURE to represent signature
    algorithms. This also automatically makes the EVP_Sign* APIs provider
    aware because they use EVP_Digest* (which is already provider aware)
    and EVP_PKEY_sign(_init) under the covers.
    
    At this stage there are no signature algorithms in any providers. That
    will come in the following commits.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9753)

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

Summary of changes:
 crypto/cms/cms_sd.c                                |  24 ++
 crypto/dh/dh_ameth.c                               |  25 +-
 crypto/dsa/dsa_ameth.c                             |  71 +++-
 crypto/dsa/dsa_gen.c                               |   2 +
 crypto/dsa/dsa_key.c                               |   1 +
 crypto/dsa/dsa_lib.c                               |   2 +
 crypto/dsa/dsa_locl.h                              |   3 +
 crypto/evp/digest.c                                |   9 +-
 crypto/evp/evp_locl.h                              |  33 +-
 crypto/evp/exchange.c                              |  62 ++-
 crypto/evp/pmeth_fn.c                              | 470 ++++++++++++++++++---
 crypto/evp/pmeth_lib.c                             | 233 +++++++++-
 crypto/include/internal/evp_int.h                  |  27 +-
 crypto/pkcs7/pk7_doit.c                            |  36 ++
 doc/man3/EVP_PKEY_CTX_ctrl.pod                     |  62 ++-
 doc/man3/EVP_PKEY_derive.pod                       |   6 +-
 doc/man3/EVP_PKEY_sign.pod                         |  19 +-
 doc/man3/EVP_PKEY_verify.pod                       |  22 +-
 doc/man3/EVP_PKEY_verify_recover.pod               |  21 +-
 doc/man3/EVP_SIGNATURE_free.pod                    |  64 +++
 doc/man7/provider-keyexch.pod                      |  28 +-
 doc/man7/provider-signature.pod                    | 239 +++++++++++
 include/openssl/core_names.h                       |  23 +-
 include/openssl/core_numbers.h                     |  59 ++-
 include/openssl/evp.h                              |  23 +-
 include/openssl/ossl_typ.h                         |   2 +
 providers/common/build.info                        |   2 +-
 providers/common/exchange/dh_exch.c                |  18 +-
 providers/common/include/internal/provider_algs.h  |   4 +
 providers/common/keymgmt/build.info                |   2 +-
 providers/common/keymgmt/dh_kmgmt.c                |   4 +-
 providers/common/keymgmt/dsa_kmgmt.c               |  91 ++++
 .../common/{exchange => signature}/build.info      |   4 +-
 providers/common/signature/dsa.c                   | 207 +++++++++
 providers/default/defltprov.c                      |  13 +
 test/evp_extra_test.c                              | 114 +++++
 util/libcrypto.num                                 |  12 +
 37 files changed, 1853 insertions(+), 184 deletions(-)
 create mode 100644 doc/man3/EVP_SIGNATURE_free.pod
 create mode 100644 doc/man7/provider-signature.pod
 create mode 100644 providers/common/keymgmt/dsa_kmgmt.c
 copy providers/common/{exchange => signature}/build.info (58%)
 create mode 100644 providers/common/signature/dsa.c

diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c
index 4de750bd72..6715e84d2f 100644
--- a/crypto/cms/cms_sd.c
+++ b/crypto/cms/cms_sd.c
@@ -706,11 +706,23 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
         si->pctx = pctx;
     }
 
+    /*
+     * TODO(3.0): This causes problems when providers are in use, so disabled
+     * for now. Can we get rid of this completely? AFAICT this ctrl has been
+     * present since CMS was first put in - but has never been used to do
+     * anything. All internal implementations just return 1 and ignore this ctrl
+     * and have always done so by the looks of things. To fix this we could
+     * convert this ctrl into a param, which would require us to send all the
+     * signer info data as a set of params...but that is non-trivial and since
+     * this isn't used by anything it may be better just to remove it.
+     */
+#if 0
     if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
                           EVP_PKEY_CTRL_CMS_SIGN, 0, si) <= 0) {
         CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
         goto err;
     }
+#endif
 
     alen = ASN1_item_i2d((ASN1_VALUE *)si->signedAttrs, &abuf,
                          ASN1_ITEM_rptr(CMS_Attributes_Sign));
@@ -727,11 +739,23 @@ int CMS_SignerInfo_sign(CMS_SignerInfo *si)
     if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
         goto err;
 
+    /*
+     * TODO(3.0): This causes problems when providers are in use, so disabled
+     * for now. Can we get rid of this completely? AFAICT this ctrl has been
+     * present since CMS was first put in - but has never been used to do
+     * anything. All internal implementations just return 1 and ignore this ctrl
+     * and have always done so by the looks of things. To fix this we could
+     * convert this ctrl into a param, which would require us to send all the
+     * signer info data as a set of params...but that is non-trivial and since
+     * this isn't used by anything it may be better just to remove it.
+     */
+#if 0
     if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
                           EVP_PKEY_CTRL_CMS_SIGN, 1, si) <= 0) {
         CMSerr(CMS_F_CMS_SIGNERINFO_SIGN, CMS_R_CTRL_ERROR);
         goto err;
     }
+#endif
 
     EVP_MD_CTX_reset(mctx);
 
diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index 6da4878200..84f1f8b952 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -559,24 +559,33 @@ static void *dh_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     OSSL_PARAM *params;
     void *provkey = NULL;
 
-    if (p == NULL || g == NULL || pub_key == NULL)
+    if (p == NULL || g == NULL)
         return NULL;
 
     ossl_param_bld_init(&tmpl);
-    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_P, p)
-        || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_G, g)
-        || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_key))
+    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_P, p)
+        || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_G, g))
         return NULL;
 
     if (q != NULL) {
-        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_Q, q))
+        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_Q, q))
             return NULL;
     }
 
-    if (priv_key != NULL) {
-        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PRIV_KEY,
-                                    priv_key))
+    /*
+     * This may be used to pass domain parameters only without any key data -
+     * so "pub_key" is optional. We can never have a "priv_key" without a
+     * corresponding "pub_key" though.
+     */
+    if (pub_key != NULL) {
+        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_key))
             return NULL;
+
+        if (priv_key != NULL) {
+            if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PRIV_KEY,
+                                        priv_key))
+                return NULL;
+        }
     }
 
     params = ossl_param_bld_to_param(&tmpl);
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index ef6fc7632a..4e0ed01970 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -8,14 +8,16 @@
  */
 
 #include <stdio.h>
-#include "internal/cryptlib.h"
 #include <openssl/x509.h>
 #include <openssl/asn1.h>
-#include "dsa_locl.h"
 #include <openssl/bn.h>
 #include <openssl/cms.h>
+#include <openssl/core_names.h>
+#include "internal/cryptlib.h"
 #include "internal/asn1_int.h"
 #include "internal/evp_int.h"
+#include "internal/param_build.h"
+#include "dsa_locl.h"
 
 static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
 {
@@ -63,6 +65,7 @@ static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
         goto err;
     }
 
+    dsa->dirty_cnt++;
     ASN1_INTEGER_free(public_key);
     EVP_PKEY_assign_DSA(pkey, dsa);
     return 1;
@@ -185,6 +188,7 @@ static int dsa_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
         goto dsaerr;
     }
 
+    dsa->dirty_cnt++;
     EVP_PKEY_assign_DSA(pkey, dsa);
 
     ret = 1;
@@ -300,6 +304,7 @@ static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
         return 0;
     BN_free(to->pkey.dsa->g);
     to->pkey.dsa->g = a;
+    to->pkey.dsa->dirty_cnt++;
     return 1;
 }
 
@@ -381,6 +386,7 @@ static int dsa_param_decode(EVP_PKEY *pkey,
         DSAerr(DSA_F_DSA_PARAM_DECODE, ERR_R_DSA_LIB);
         return 0;
     }
+    dsa->dirty_cnt++;
     EVP_PKEY_assign_DSA(pkey, dsa);
     return 1;
 }
@@ -417,6 +423,7 @@ static int old_dsa_priv_decode(EVP_PKEY *pkey,
         DSAerr(DSA_F_OLD_DSA_PRIV_DECODE, ERR_R_DSA_LIB);
         return 0;
     }
+    dsa->dirty_cnt++;
     EVP_PKEY_assign_DSA(pkey, dsa);
     return 1;
 }
@@ -514,6 +521,56 @@ static int dsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
 
 }
 
+static size_t dsa_pkey_dirty_cnt(const EVP_PKEY *pkey)
+{
+    return pkey->pkey.dsa->dirty_cnt;
+}
+
+static void *dsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
+{
+    DSA *dsa = pk->pkey.dsa;
+    OSSL_PARAM_BLD tmpl;
+    const BIGNUM *p = DSA_get0_p(dsa), *g = DSA_get0_g(dsa);
+    const BIGNUM *q = DSA_get0_q(dsa), *pub_key = DSA_get0_pub_key(dsa);
+    const BIGNUM *priv_key = DSA_get0_priv_key(dsa);
+    OSSL_PARAM *params;
+    void *provkey = NULL;
+
+    if (p == NULL || q == NULL || g == NULL)
+        return NULL;
+
+    ossl_param_bld_init(&tmpl);
+    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_P, p)
+        || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_Q, q)
+        || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_G, g))
+        return NULL;
+
+    /*
+     * This may be used to pass domain parameters only without any key data -
+     * so "pub_key" is optional. We can never have a "priv_key" without a
+     * corresponding "pub_key" though.
+     */
+    if (pub_key != NULL) {
+        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DSA_PUB_KEY,
+                                    pub_key))
+            return NULL;
+
+        if (priv_key != NULL) {
+            if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DSA_PRIV_KEY,
+                                        priv_key))
+                return NULL;
+        }
+    }
+
+    params = ossl_param_bld_to_param(&tmpl);
+
+    /* We export, the provider imports */
+    provkey = evp_keymgmt_importkey(keymgmt, params);
+
+    ossl_param_bld_free(params);
+    return provkey;
+}
+
 /* NB these are sorted in pkey_id order, lowest first */
 
 const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5] = {
@@ -570,5 +627,13 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5] = {
      int_dsa_free,
      dsa_pkey_ctrl,
      old_dsa_priv_decode,
-     old_dsa_priv_encode}
+     old_dsa_priv_encode,
+
+     NULL, NULL, NULL,
+     NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL,
+
+     dsa_pkey_dirty_cnt,
+     dsa_pkey_export_to
+    }
 };
diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c
index 858f127315..14cb8e9f53 100644
--- a/crypto/dsa/dsa_gen.c
+++ b/crypto/dsa/dsa_gen.c
@@ -281,6 +281,7 @@ int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits,
         ret->p = BN_dup(p);
         ret->q = BN_dup(q);
         ret->g = BN_dup(g);
+        ret->dirty_cnt++;
         if (ret->p == NULL || ret->q == NULL || ret->g == NULL) {
             ok = 0;
             goto err;
@@ -598,6 +599,7 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N,
             ok = -1;
             goto err;
         }
+        ret->dirty_cnt++;
         if (counter_ret != NULL)
             *counter_ret = counter;
         if (h_ret != NULL)
diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c
index 333bff959e..86f79b804e 100644
--- a/crypto/dsa/dsa_key.c
+++ b/crypto/dsa/dsa_key.c
@@ -65,6 +65,7 @@ static int dsa_builtin_keygen(DSA *dsa)
 
     dsa->priv_key = priv_key;
     dsa->pub_key = pub_key;
+    dsa->dirty_cnt++;
     ok = 1;
 
  err:
diff --git a/crypto/dsa/dsa_lib.c b/crypto/dsa/dsa_lib.c
index 1068f1da77..034300fc7e 100644
--- a/crypto/dsa/dsa_lib.c
+++ b/crypto/dsa/dsa_lib.c
@@ -273,6 +273,7 @@ int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
         BN_free(d->g);
         d->g = g;
     }
+    d->dirty_cnt++;
 
     return 1;
 }
@@ -303,6 +304,7 @@ int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
         BN_free(d->priv_key);
         d->priv_key = priv_key;
     }
+    d->dirty_cnt++;
 
     return 1;
 }
diff --git a/crypto/dsa/dsa_locl.h b/crypto/dsa/dsa_locl.h
index 5c464e7c25..e56ff06977 100644
--- a/crypto/dsa/dsa_locl.h
+++ b/crypto/dsa/dsa_locl.h
@@ -31,6 +31,9 @@ struct dsa_st {
     /* functional reference if 'meth' is ENGINE-provided */
     ENGINE *engine;
     CRYPTO_RWLOCK *lock;
+
+    /* Provider data */
+    size_t dirty_cnt; /* If any key material changes, increment this */
 };
 
 struct DSA_SIG_st {
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 6cb9064b6c..0da934a691 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -266,8 +266,13 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
  skip_to_init:
 #endif
 #ifndef FIPS_MODE
-    /* TODO(3.0): Temporarily no support for EVP_DigestSign* in FIPS module */
-    if (ctx->pctx != NULL) {
+    /*
+     * TODO(3.0): Temporarily no support for EVP_DigestSign* inside FIPS module
+     * or when using providers.
+     */
+    if (ctx->pctx != NULL
+            && (!EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx)
+                 || ctx->pctx->op.sig.signature == NULL)) {
         int r;
         r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
                               EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h
index 750e593b66..fd684c4b4c 100644
--- a/crypto/evp/evp_locl.h
+++ b/crypto/evp/evp_locl.h
@@ -91,6 +91,11 @@ struct evp_keymgmt_st {
     OSSL_OP_keymgmt_exportkey_types_fn *exportkey_types;
 } /* EVP_KEYMGMT */ ;
 
+struct keymgmt_data_st {
+    OPENSSL_CTX *ctx;
+    const char *properties;
+};
+
 struct evp_keyexch_st {
     char *name;
     OSSL_PROVIDER *prov;
@@ -105,9 +110,33 @@ struct evp_keyexch_st {
     OSSL_OP_keyexch_derive_fn *derive;
     OSSL_OP_keyexch_freectx_fn *freectx;
     OSSL_OP_keyexch_dupctx_fn *dupctx;
-    OSSL_OP_keyexch_set_params_fn *set_params;
+    OSSL_OP_keyexch_set_ctx_params_fn *set_ctx_params;
+    OSSL_OP_keyexch_settable_ctx_params_fn *settable_ctx_params;
 } /* EVP_KEYEXCH */;
 
+struct evp_signature_st {
+    char *name;
+    OSSL_PROVIDER *prov;
+    CRYPTO_REF_COUNT refcnt;
+    CRYPTO_RWLOCK *lock;
+
+    EVP_KEYMGMT *keymgmt;
+
+    OSSL_OP_signature_newctx_fn *newctx;
+    OSSL_OP_signature_sign_init_fn *sign_init;
+    OSSL_OP_signature_sign_fn *sign;
+    OSSL_OP_signature_verify_init_fn *verify_init;
+    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_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;
+} /* EVP_SIGNATURE */;
+
 int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
                              int passlen, ASN1_TYPE *param,
                              const EVP_CIPHER *c, const EVP_MD *md,
@@ -203,3 +232,5 @@ OSSL_PARAM *evp_pkey_to_param(EVP_PKEY *pkey, size_t *sz);
             return 0;                                             \
         }                                                         \
     }
+
+void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx);
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index e69e4fd0b2..7c61a12b3b 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -32,11 +32,6 @@ static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
     return exchange;
 }
 
-struct keymgmt_data_st {
-    OPENSSL_CTX *ctx;
-    const char *properties;
-};
-
 static void *evp_keyexch_from_dispatch(const char *name,
                                        const OSSL_DISPATCH *fns,
                                        OSSL_PROVIDER *prov,
@@ -55,7 +50,7 @@ static void *evp_keyexch_from_dispatch(const char *name,
     EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name,
                                              keymgmt_data->properties);
     EVP_KEYEXCH *exchange = NULL;
-    int fncnt = 0;
+    int fncnt = 0, paramfncnt = 0;
 
     if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) {
         ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE);
@@ -107,19 +102,28 @@ static void *evp_keyexch_from_dispatch(const char *name,
                 break;
             exchange->dupctx = OSSL_get_OP_keyexch_dupctx(fns);
             break;
-        case OSSL_FUNC_KEYEXCH_SET_PARAMS:
-            if (exchange->set_params != NULL)
+        case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS:
+            if (exchange->set_ctx_params != NULL)
+                break;
+            exchange->set_ctx_params = OSSL_get_OP_keyexch_set_ctx_params(fns);
+            paramfncnt++;
+            break;
+        case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS:
+            if (exchange->settable_ctx_params != NULL)
                 break;
-            exchange->set_params = OSSL_get_OP_keyexch_set_params(fns);
+            exchange->settable_ctx_params
+                = OSSL_get_OP_keyexch_settable_ctx_params(fns);
+            paramfncnt++;
             break;
         }
     }
-    if (fncnt != 4) {
+    if (fncnt != 4 || (paramfncnt != 0 && paramfncnt != 2)) {
         /*
          * In order to be a consistent set of functions we must have at least
          * a complete set of "exchange" functions: init, derive, newctx,
-         * and freectx. The dupctx, set_peer and set_params functions are
-         * optional.
+         * and freectx. The set_ctx_params and settable_ctx_params functions are
+         * optional, but if one of them is present then the other one must also
+         * be present. The dupctx and set_peer functions are optional.
          */
         EVPerr(EVP_F_EVP_KEYEXCH_FROM_DISPATCH,
                EVP_R_INVALID_PROVIDER_FUNCTIONS);
@@ -184,6 +188,7 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)
     int ret;
     void *provkey = NULL;
 
+    evp_pkey_ctx_free_old_ops(ctx);
     ctx->operation = EVP_PKEY_OP_DERIVE;
 
     if (ctx->engine != NULL)
@@ -217,10 +222,7 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)
         }
     }
 
-    if (ctx->exchprovctx != NULL && ctx->exchange != NULL)
-        ctx->exchange->freectx(ctx->exchprovctx);
-    EVP_KEYEXCH_free(ctx->exchange);
-    ctx->exchange = exchange;
+    ctx->op.kex.exchange = exchange;
     if (ctx->pkey != NULL) {
         provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt);
         if (provkey == NULL) {
@@ -228,13 +230,13 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)
             goto err;
         }
     }
-    ctx->exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
-    if (ctx->exchprovctx == NULL) {
+    ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
+    if (ctx->op.kex.exchprovctx == NULL) {
         /* The provider key can stay in the cache */
         EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
         goto err;
     }
-    ret = exchange->init(ctx->exchprovctx, provkey);
+    ret = exchange->init(ctx->op.kex.exchprovctx, provkey);
 
     return ret ? 1 : 0;
  err:
@@ -272,27 +274,22 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
         return -2;
     }
 
-    if (ctx->exchprovctx == NULL)
+    if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL)
         goto legacy;
 
-    if (ctx->operation != EVP_PKEY_OP_DERIVE) {
-        EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
-               EVP_R_OPERATON_NOT_INITIALIZED);
-        return -1;
-    }
-
-    if (ctx->exchange->set_peer == NULL) {
+    if (ctx->op.kex.exchange->set_peer == NULL) {
         EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
                EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
         return -2;
     }
 
-    provkey = evp_keymgmt_export_to_provider(peer, ctx->exchange->keymgmt);
+    provkey = evp_keymgmt_export_to_provider(peer,
+                                             ctx->op.kex.exchange->keymgmt);
     if (provkey == NULL) {
         EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, ERR_R_INTERNAL_ERROR);
         return 0;
     }
-    return ctx->exchange->set_peer(ctx->exchprovctx, provkey);
+    return ctx->op.kex.exchange->set_peer(ctx->op.kex.exchprovctx, provkey);
 
  legacy:
     if (ctx->pmeth == NULL
@@ -367,15 +364,16 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
         return -2;
     }
 
-    if (ctx->operation != EVP_PKEY_OP_DERIVE) {
+    if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
         EVPerr(EVP_F_EVP_PKEY_DERIVE, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
 
-    if (ctx->exchprovctx == NULL)
+    if (ctx->op.kex.exchprovctx == NULL)
         goto legacy;
 
-    ret = ctx->exchange->derive(ctx->exchprovctx, key, pkeylen, SIZE_MAX);
+    ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen,
+                                       SIZE_MAX);
 
     return ret;
  legacy:
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index 51df2be4d4..b46c92d633 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -13,105 +13,479 @@
 #include <openssl/evp.h>
 #include "internal/cryptlib.h"
 #include "internal/evp_int.h"
+#include "internal/provider.h"
 #include "evp_locl.h"
 
-int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx)
+static EVP_SIGNATURE *evp_signature_new(OSSL_PROVIDER *prov)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
-        EVPerr(EVP_F_EVP_PKEY_SIGN_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    EVP_SIGNATURE *signature = OPENSSL_zalloc(sizeof(EVP_SIGNATURE));
+
+    signature->lock = CRYPTO_THREAD_lock_new();
+    if (signature->lock == NULL) {
+        OPENSSL_free(signature);
+        return NULL;
+    }
+    signature->prov = prov;
+    ossl_provider_up_ref(prov);
+    signature->refcnt = 1;
+
+    return signature;
+}
+
+static void *evp_signature_from_dispatch(const char *name,
+                                         const OSSL_DISPATCH *fns,
+                                         OSSL_PROVIDER *prov,
+                                         void *vkeymgmt_data)
+{
+    /*
+     * Signature functions cannot work without a key, and key management
+     * from the same provider to manage its keys.  We therefore fetch
+     * a key management method using the same algorithm and properties
+     * and pass that down to evp_generic_fetch to be passed on to our
+     * evp_signature_from_dispatch, which will attach the key management
+     * method to the newly created key exchange method as long as the
+     * provider matches.
+     */
+    struct keymgmt_data_st *keymgmt_data = vkeymgmt_data;
+    EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name,
+                                             keymgmt_data->properties);
+    EVP_SIGNATURE *signature = NULL;
+    int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0;
+    int gparamfncnt = 0, sparamfncnt = 0;
+
+    if (keymgmt == NULL || EVP_KEYMGMT_provider(keymgmt) != prov) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE);
+        goto err;
+    }
+
+    if ((signature = evp_signature_new(prov)) == NULL
+        || (signature->name = OPENSSL_strdup(name)) == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    signature->keymgmt = keymgmt;
+    keymgmt = NULL;              /* avoid double free on failure below */
+
+    for (; fns->function_id != 0; fns++) {
+        switch (fns->function_id) {
+        case OSSL_FUNC_SIGNATURE_NEWCTX:
+            if (signature->newctx != NULL)
+                break;
+            signature->newctx = OSSL_get_OP_signature_newctx(fns);
+            ctxfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SIGN_INIT:
+            if (signature->sign_init != NULL)
+                break;
+            signature->sign_init = OSSL_get_OP_signature_sign_init(fns);
+            signfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SIGN:
+            if (signature->sign != NULL)
+                break;
+            signature->sign = OSSL_get_OP_signature_sign(fns);
+            signfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY_INIT:
+            if (signature->verify_init != NULL)
+                break;
+            signature->verify_init = OSSL_get_OP_signature_verify_init(fns);
+            verifyfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY:
+            if (signature->verify != NULL)
+                break;
+            signature->verify = OSSL_get_OP_signature_verify(fns);
+            verifyfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT:
+            if (signature->verify_recover_init != NULL)
+                break;
+            signature->verify_recover_init
+                = OSSL_get_OP_signature_verify_recover_init(fns);
+            verifyrecfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_VERIFY_RECOVER:
+            if (signature->verify_recover != NULL)
+                break;
+            signature->verify_recover
+                = OSSL_get_OP_signature_verify_recover(fns);
+            verifyrecfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_FREECTX:
+            if (signature->freectx != NULL)
+                break;
+            signature->freectx = OSSL_get_OP_signature_freectx(fns);
+            ctxfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_DUPCTX:
+            if (signature->dupctx != NULL)
+                break;
+            signature->dupctx = OSSL_get_OP_signature_dupctx(fns);
+            break;
+        case OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS:
+            if (signature->get_ctx_params != NULL)
+                break;
+            signature->get_ctx_params
+                = OSSL_get_OP_signature_get_ctx_params(fns);
+            gparamfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS:
+            if (signature->gettable_ctx_params != NULL)
+                break;
+            signature->gettable_ctx_params
+                = OSSL_get_OP_signature_gettable_ctx_params(fns);
+            gparamfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS:
+            if (signature->set_ctx_params != NULL)
+                break;
+            signature->set_ctx_params
+                = OSSL_get_OP_signature_set_ctx_params(fns);
+            sparamfncnt++;
+            break;
+        case OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS:
+            if (signature->settable_ctx_params != NULL)
+                break;
+            signature->settable_ctx_params
+                = OSSL_get_OP_signature_settable_ctx_params(fns);
+            sparamfncnt++;
+            break;
+        }
+    }
+    if (ctxfncnt != 2
+        || (signfncnt != 2 && verifyfncnt != 2 && verifyrecfncnt != 2)
+        || (gparamfncnt != 0 && gparamfncnt != 2)
+        || (sparamfncnt != 0 && sparamfncnt != 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.
+         */
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
+        goto err;
+    }
+
+    return signature;
+ err:
+    EVP_SIGNATURE_free(signature);
+    EVP_KEYMGMT_free(keymgmt);
+    return NULL;
+}
+
+void EVP_SIGNATURE_free(EVP_SIGNATURE *signature)
+{
+    if (signature != NULL) {
+        int i;
+
+        CRYPTO_DOWN_REF(&signature->refcnt, &i, signature->lock);
+        if (i > 0)
+            return;
+        EVP_KEYMGMT_free(signature->keymgmt);
+        ossl_provider_free(signature->prov);
+        OPENSSL_free(signature->name);
+        CRYPTO_THREAD_lock_free(signature->lock);
+        OPENSSL_free(signature);
+    }
+}
+
+int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&signature->refcnt, &ref, signature->lock);
+    return 1;
+}
+
+OSSL_PROVIDER *EVP_SIGNATURE_provider(const EVP_SIGNATURE *signature)
+{
+    return signature->prov;
+}
+
+EVP_SIGNATURE *EVP_SIGNATURE_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                   const char *properties)
+{
+    struct keymgmt_data_st keymgmt_data;
+
+    /*
+     * A signature operation cannot work without a key, so we need key
+     * management from the same provider to manage its keys.
+     */
+    keymgmt_data.ctx = ctx;
+    keymgmt_data.properties = properties;
+    return evp_generic_fetch(ctx, OSSL_OP_SIGNATURE, algorithm, properties,
+                             evp_signature_from_dispatch, &keymgmt_data,
+                             (int (*)(void *))EVP_SIGNATURE_up_ref,
+                             (void (*)(void *))EVP_SIGNATURE_free);
+}
+
+static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature,
+                                   int operation)
+{
+    int ret = 0;
+    void *provkey = NULL;
+
+    if (ctx == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
         return -2;
     }
-    ctx->operation = EVP_PKEY_OP_SIGN;
-    if (!ctx->pmeth->sign_init)
-        return 1;
-    ret = ctx->pmeth->sign_init(ctx);
+
+    evp_pkey_ctx_free_old_ops(ctx);
+    ctx->operation = operation;
+
+    if (ctx->engine != NULL)
+        goto legacy;
+
+    if (signature != NULL) {
+        if (!EVP_SIGNATURE_up_ref(signature))
+            goto err;
+    } else {
+        int nid = ctx->pkey != NULL ? ctx->pkey->type : ctx->pmeth->pkey_id;
+
+        /*
+         * TODO(3.0): Check for legacy handling. Remove this once all all
+         * algorithms are moved to providers.
+         */
+        if (ctx->pkey != NULL) {
+            switch (ctx->pkey->type) {
+            case NID_dsa:
+                break;
+            default:
+                goto legacy;
+            }
+            signature = EVP_SIGNATURE_fetch(NULL, OBJ_nid2sn(nid), NULL);
+        } else {
+            goto legacy;
+        }
+
+        if (signature == NULL) {
+            EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+    }
+
+    ctx->op.sig.signature = signature;
+    if (ctx->pkey != NULL) {
+        provkey = evp_keymgmt_export_to_provider(ctx->pkey, signature->keymgmt);
+        if (provkey == NULL) {
+            EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+    }
+    ctx->op.sig.sigprovctx = signature->newctx(ossl_provider_ctx(signature->prov));
+    if (ctx->op.sig.sigprovctx == NULL) {
+        /* The provider key can stay in the cache */
+        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
+
+    switch (operation) {
+    case EVP_PKEY_OP_SIGN:
+        if (signature->sign_init == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = signature->sign_init(ctx->op.sig.sigprovctx, provkey);
+        break;
+    case EVP_PKEY_OP_VERIFY:
+        if (signature->verify_init == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = signature->verify_init(ctx->op.sig.sigprovctx, provkey);
+        break;
+    case EVP_PKEY_OP_VERIFYRECOVER:
+        if (signature->verify_recover_init == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = signature->verify_recover_init(ctx->op.sig.sigprovctx, provkey);
+        break;
+    default:
+        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
+
+    if (ret <= 0) {
+        signature->freectx(ctx->op.sig.sigprovctx);
+        ctx->op.sig.sigprovctx = NULL;
+        goto err;
+    }
+    return 1;
+
+ legacy:
+    if (ctx->pmeth == NULL
+            || (operation == EVP_PKEY_OP_SIGN && ctx->pmeth->sign == NULL)
+            || (operation == EVP_PKEY_OP_VERIFY && ctx->pmeth->verify == NULL)
+            || (operation == EVP_PKEY_OP_VERIFYRECOVER
+                && ctx->pmeth->verify_recover == NULL)) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
+    switch (operation) {
+    case EVP_PKEY_OP_SIGN:
+        if (ctx->pmeth->sign_init == NULL)
+            return 1;
+        ret = ctx->pmeth->sign_init(ctx);
+        break;
+    case EVP_PKEY_OP_VERIFY:
+        if (ctx->pmeth->verify_init == NULL)
+            return 1;
+        ret = ctx->pmeth->verify_init(ctx);
+        break;
+    case EVP_PKEY_OP_VERIFYRECOVER:
+        if (ctx->pmeth->verify_recover_init == NULL)
+            return 1;
+        ret = ctx->pmeth->verify_recover_init(ctx);
+        break;
+    default:
+        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
     if (ret <= 0)
-        ctx->operation = EVP_PKEY_OP_UNDEFINED;
+        goto err;
+    return ret;
+
+ err:
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
     return ret;
 }
 
+int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature)
+{
+    return evp_pkey_signature_init(ctx, signature, EVP_PKEY_OP_SIGN);
+}
+
+int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx)
+{
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_SIGN);
+}
+
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
                   unsigned char *sig, size_t *siglen,
                   const unsigned char *tbs, size_t tbslen)
 {
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
-        EVPerr(EVP_F_EVP_PKEY_SIGN,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    int ret;
+
+    if (ctx == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
         return -2;
     }
+
     if (ctx->operation != EVP_PKEY_OP_SIGN) {
-        EVPerr(EVP_F_EVP_PKEY_SIGN, EVP_R_OPERATON_NOT_INITIALIZED);
+        EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
+
+    if (ctx->op.sig.sigprovctx == NULL)
+        goto legacy;
+
+    ret = ctx->op.sig.signature->sign(ctx->op.sig.sigprovctx, sig, siglen,
+                                      SIZE_MAX, tbs, tbslen);
+
+    return ret;
+ legacy:
+ 
+    if (ctx->pmeth == NULL || ctx->pmeth->sign == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
     M_check_autoarg(ctx, sig, siglen, EVP_F_EVP_PKEY_SIGN)
         return ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen);
 }
 
+int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature)
+{
+    return evp_pkey_signature_init(ctx, signature, EVP_PKEY_OP_VERIFY);
+}
+
 int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
-        EVPerr(EVP_F_EVP_PKEY_VERIFY_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
-    ctx->operation = EVP_PKEY_OP_VERIFY;
-    if (!ctx->pmeth->verify_init)
-        return 1;
-    ret = ctx->pmeth->verify_init(ctx);
-    if (ret <= 0)
-        ctx->operation = EVP_PKEY_OP_UNDEFINED;
-    return ret;
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFY);
 }
 
 int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
                     const unsigned char *sig, size_t siglen,
                     const unsigned char *tbs, size_t tbslen)
 {
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
-        EVPerr(EVP_F_EVP_PKEY_VERIFY,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    int ret;
+
+    if (ctx == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
         return -2;
     }
+
     if (ctx->operation != EVP_PKEY_OP_VERIFY) {
-        EVPerr(EVP_F_EVP_PKEY_VERIFY, EVP_R_OPERATON_NOT_INITIALIZED);
+        EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
+
+    if (ctx->op.sig.sigprovctx == NULL)
+        goto legacy;
+
+    ret = ctx->op.sig.signature->verify(ctx->op.sig.sigprovctx, sig, siglen,
+                                        tbs, tbslen);
+
+    return ret;
+ legacy:
+    if (ctx->pmeth == NULL || ctx->pmeth->verify == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
     return ctx->pmeth->verify(ctx, sig, siglen, tbs, tbslen);
 }
 
+int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature)
+{
+    return evp_pkey_signature_init(ctx, signature, EVP_PKEY_OP_VERIFYRECOVER);
+}
+
 int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
-        EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
-    ctx->operation = EVP_PKEY_OP_VERIFYRECOVER;
-    if (!ctx->pmeth->verify_recover_init)
-        return 1;
-    ret = ctx->pmeth->verify_recover_init(ctx);
-    if (ret <= 0)
-        ctx->operation = EVP_PKEY_OP_UNDEFINED;
-    return ret;
+    return evp_pkey_signature_init(ctx, NULL, EVP_PKEY_OP_VERIFYRECOVER);
 }
 
 int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
                             unsigned char *rout, size_t *routlen,
                             const unsigned char *sig, size_t siglen)
 {
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
-        EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    int ret;
+
+    if (ctx == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
         return -2;
     }
+
     if (ctx->operation != EVP_PKEY_OP_VERIFYRECOVER) {
-        EVPerr(EVP_F_EVP_PKEY_VERIFY_RECOVER, EVP_R_OPERATON_NOT_INITIALIZED);
+        EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
+
+    if (ctx->op.sig.sigprovctx == NULL)
+        goto legacy;
+
+    ret = ctx->op.sig.signature->verify_recover(ctx->op.sig.sigprovctx, rout,
+                                                routlen,
+                                                (rout == NULL ? 0 : *routlen),
+                                                sig, siglen);
+    return ret;
+ legacy:
+    if (ctx->pmeth == NULL || ctx->pmeth->verify_recover == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
     M_check_autoarg(ctx, rout, routlen, EVP_F_EVP_PKEY_VERIFY_RECOVER)
         return ctx->pmeth->verify_recover(ctx, rout, routlen, sig, siglen);
 }
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index d2b28f825b..2be51f155f 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -19,6 +19,7 @@
 #include "internal/asn1_int.h"
 #include "internal/evp_int.h"
 #include "internal/numbers.h"
+#include "internal/provider.h"
 #include "evp_locl.h"
 
 typedef int sk_cmp_fn_type(const char *const *a, const char *const *b);
@@ -182,6 +183,19 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
     return ret;
 }
 
+void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx)
+{
+    if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+        if (ctx->op.kex.exchprovctx != NULL && ctx->op.kex.exchange != NULL)
+            ctx->op.kex.exchange->freectx(ctx->op.kex.exchprovctx);
+        EVP_KEYEXCH_free(ctx->op.kex.exchange);
+    } else if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)) {
+        if (ctx->op.sig.sigprovctx != NULL && ctx->op.sig.signature != NULL)
+            ctx->op.sig.signature->freectx(ctx->op.sig.sigprovctx);
+        EVP_SIGNATURE_free(ctx->op.sig.signature);
+    }
+}
+
 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags)
 {
     EVP_PKEY_METHOD *pmeth;
@@ -270,7 +284,10 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
     EVP_PKEY_CTX *rctx;
 
     if (((pctx->pmeth == NULL) || (pctx->pmeth->copy == NULL))
-            && pctx->exchprovctx == NULL)
+            && ((EVP_PKEY_CTX_IS_DERIVE_OP(pctx)
+                 && pctx->op.kex.exchprovctx == NULL)
+                || (EVP_PKEY_CTX_IS_SIGNATURE_OP(pctx)
+                    && pctx->op.sig.sigprovctx == NULL)))
         return NULL;
 #ifndef OPENSSL_NO_ENGINE
     /* Make sure it's safe to copy a pkey context using an ENGINE */
@@ -290,21 +307,46 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
     rctx->pkey = pctx->pkey;
     rctx->operation = pctx->operation;
 
-    if (pctx->exchprovctx != NULL) {
-        if (!ossl_assert(pctx->exchange != NULL))
-            return NULL;
-        rctx->exchange = pctx->exchange;
-        if (!EVP_KEYEXCH_up_ref(rctx->exchange)) {
-            OPENSSL_free(rctx);
-            return NULL;
+    if (EVP_PKEY_CTX_IS_DERIVE_OP(pctx)) {
+        if (pctx->op.kex.exchange != NULL) {
+            rctx->op.kex.exchange = pctx->op.kex.exchange;
+            if (!EVP_KEYEXCH_up_ref(rctx->op.kex.exchange)) {
+                OPENSSL_free(rctx);
+                return NULL;
+            }
         }
-        rctx->exchprovctx = pctx->exchange->dupctx(pctx->exchprovctx);
-        if (rctx->exchprovctx == NULL) {
-            EVP_KEYEXCH_free(rctx->exchange);
-            OPENSSL_free(rctx);
-            return NULL;
+        if (pctx->op.kex.exchprovctx != NULL) {
+            if (!ossl_assert(pctx->op.kex.exchange != NULL))
+                return NULL;
+            rctx->op.kex.exchprovctx
+                = pctx->op.kex.exchange->dupctx(pctx->op.kex.exchprovctx);
+            if (rctx->op.kex.exchprovctx == NULL) {
+                EVP_KEYEXCH_free(rctx->op.kex.exchange);
+                OPENSSL_free(rctx);
+                return NULL;
+            }
+            return rctx;
+        }
+    } else if (EVP_PKEY_CTX_IS_SIGNATURE_OP(pctx)) {
+        if (pctx->op.sig.signature != NULL) {
+            rctx->op.sig.signature = pctx->op.sig.signature;
+            if (!EVP_SIGNATURE_up_ref(rctx->op.sig.signature)) {
+                OPENSSL_free(rctx);
+                return NULL;
+            }
+        }
+        if (pctx->op.sig.sigprovctx != NULL) {
+            if (!ossl_assert(pctx->op.sig.signature != NULL))
+                return NULL;
+            rctx->op.sig.sigprovctx
+                = pctx->op.sig.signature->dupctx(pctx->op.sig.sigprovctx);
+            if (rctx->op.sig.sigprovctx == NULL) {
+                EVP_SIGNATURE_free(rctx->op.sig.signature);
+                OPENSSL_free(rctx);
+                return NULL;
+            }
+            return rctx;
         }
-        return rctx;
     }
 
     rctx->pmeth = pctx->pmeth;
@@ -385,10 +427,7 @@ void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx)
     if (ctx->pmeth && ctx->pmeth->cleanup)
         ctx->pmeth->cleanup(ctx);
 
-    if (ctx->exchprovctx != NULL && ctx->exchange != NULL)
-        ctx->exchange->freectx(ctx->exchprovctx);
-
-    EVP_KEYEXCH_free(ctx->exchange);
+    evp_pkey_ctx_free_old_ops(ctx);
 
     EVP_PKEY_free(ctx->pkey);
     EVP_PKEY_free(ctx->peerkey);
@@ -398,21 +437,72 @@ void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx)
     OPENSSL_free(ctx);
 }
 
+int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
+{
+    if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+            && ctx->op.sig.sigprovctx != NULL
+            && ctx->op.sig.signature != NULL
+            && ctx->op.sig.signature->get_ctx_params != NULL)
+        return ctx->op.sig.signature->get_ctx_params(ctx->op.sig.sigprovctx,
+                                                     params);
+    return 0;
+}
+
+const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx)
+{
+    if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+            && ctx->op.sig.signature != NULL
+            && ctx->op.sig.signature->gettable_ctx_params != NULL)
+        return ctx->op.sig.signature->gettable_ctx_params();
+
+    return NULL;
+}
+
 int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
 {
-    if (ctx->exchprovctx != NULL && ctx->exchange != NULL)
-        return ctx->exchange->set_params(ctx->exchprovctx, params);
+    if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx)
+            && ctx->op.kex.exchprovctx != NULL
+            && ctx->op.kex.exchange != NULL
+            && ctx->op.kex.exchange->set_ctx_params != NULL)
+        return ctx->op.kex.exchange->set_ctx_params(ctx->op.kex.exchprovctx,
+                                                    params);
+    if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+            && ctx->op.sig.sigprovctx != NULL
+            && ctx->op.sig.signature != NULL
+            && ctx->op.sig.signature->set_ctx_params != NULL)
+        return ctx->op.sig.signature->set_ctx_params(ctx->op.sig.sigprovctx,
+                                                     params);
     return 0;
 }
 
+const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx)
+{
+    if (EVP_PKEY_CTX_IS_DERIVE_OP(ctx)
+            && ctx->op.kex.exchange != NULL
+            && ctx->op.kex.exchange->settable_ctx_params != NULL)
+        return ctx->op.kex.exchange->settable_ctx_params();
+    if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+            && ctx->op.sig.signature != NULL
+            && ctx->op.sig.signature->settable_ctx_params != NULL)
+        return ctx->op.sig.signature->settable_ctx_params();
+
+    return NULL;
+}
+
 #ifndef OPENSSL_NO_DH
 int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
 {
     OSSL_PARAM dh_pad_params[2];
     unsigned int upad = pad;
 
+    /* We use EVP_PKEY_CTX_ctrl return values */
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        return -2;
+    }
+
     /* TODO(3.0): Remove this eventually when no more legacy */
-    if (ctx->exchprovctx == NULL)
+    if (ctx->op.kex.exchprovctx == NULL)
         return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE,
                                  EVP_PKEY_CTRL_DH_PAD, pad, NULL);
 
@@ -423,6 +513,80 @@ int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
 }
 #endif
 
+int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md)
+{
+    OSSL_PARAM sig_md_params[3], *p = sig_md_params;
+    /* 80 should be big enough */
+    char name[80] = "";
+    const EVP_MD *tmp;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.sig.sigprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,
+                                 EVP_PKEY_CTRL_GET_MD, 0, (void *)(md));
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST,
+                                            name,
+                                            sizeof(name));
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_PKEY_CTX_get_params(ctx, sig_md_params))
+        return 0;
+
+    tmp = EVP_get_digestbyname(name);
+    if (tmp == NULL)
+        return 0;
+
+    *md = tmp;
+
+    return 1;
+}
+
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
+{
+    OSSL_PARAM sig_md_params[3], *p = sig_md_params;
+    size_t mdsize;
+    const char *name;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.sig.sigprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,
+                                 EVP_PKEY_CTRL_MD, 0, (void *)(md));
+
+    if (md == NULL) {
+        name = "";
+        mdsize = 0;
+    } else {
+        mdsize = EVP_MD_size(md);
+        name = EVP_MD_name(md);
+    }
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (char *)name,
+                                            strlen(name) + 1);
+    *p++ = OSSL_PARAM_construct_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE,
+                                       &mdsize);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, sig_md_params);
+}
+
 static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
                                 int cmd, int p1, void *p2)
 {
@@ -431,6 +595,10 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
     case EVP_PKEY_CTRL_DH_PAD:
         return EVP_PKEY_CTX_set_dh_pad(ctx, p1);
 #endif
+    case EVP_PKEY_CTRL_MD:
+        return EVP_PKEY_CTX_set_signature_md(ctx, p2);
+    case EVP_PKEY_CTRL_GET_MD:
+        return EVP_PKEY_CTX_get_signature_md(ctx, p2);
     }
     return 0;
 }
@@ -445,7 +613,9 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
         return -2;
     }
 
-    if (ctx->exchprovctx != NULL)
+    if ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchprovctx != NULL)
+            || (EVP_PKEY_CTX_IS_DERIVE_OP(ctx)
+                && ctx->op.sig.sigprovctx != NULL))
         return legacy_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2);
 
     if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) {
@@ -495,6 +665,21 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
         return EVP_PKEY_CTX_set_dh_pad(ctx, pad);
     }
 #endif
+    if (strcmp(name, "digest") == 0) {
+        int ret;
+        EVP_MD *md;
+
+        if (!EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) || ctx->op.sig.signature == NULL)
+            return 0;
+        md = EVP_MD_fetch(ossl_provider_library_context(ctx->op.sig.signature->prov),
+                          value, NULL);
+        if (md == NULL)
+            return 0;
+        ret = EVP_PKEY_CTX_set_signature_md(ctx, md);
+        EVP_MD_meth_free(md);
+        return ret;
+    }
+
     return 0;
 }
 
@@ -506,7 +691,9 @@ int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx,
         return -2;
     }
 
-    if (ctx->exchprovctx != NULL)
+    if ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchprovctx != NULL)
+            || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+                && ctx->op.sig.sigprovctx != NULL))
         return legacy_ctrl_str_to_param(ctx, name, value);
 
     if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) {
diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h
index d54edc78d3..caf0ca1dd9 100644
--- a/crypto/include/internal/evp_int.h
+++ b/crypto/include/internal/evp_int.h
@@ -18,8 +18,20 @@
 #define EVP_MD_CTX_FLAG_KEEP_PKEY_CTX   0x0400
 
 struct evp_pkey_ctx_st {
-    EVP_KEYEXCH *exchange;
-    void *exchprovctx;
+    /* Actual operation */
+    int operation;
+
+    union {
+        struct {
+            EVP_KEYEXCH *exchange;
+            void *exchprovctx;
+        } kex;
+
+        struct {
+            EVP_SIGNATURE *signature;
+            void *sigprovctx;
+        } sig;
+    } op;
 
     /* Legacy fields below */
 
@@ -31,8 +43,6 @@ struct evp_pkey_ctx_st {
     EVP_PKEY *pkey;
     /* Peer key for key agreement, may be NULL */
     EVP_PKEY *peerkey;
-    /* Actual operation */
-    int operation;
     /* Algorithm specific data */
     void *data;
     /* Application specific data */
@@ -547,6 +557,15 @@ struct evp_pkey_st {
     size_t dirty_cnt_copy;
 } /* EVP_PKEY */ ;
 
+#define EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) \
+    ((ctx)->operation == EVP_PKEY_OP_SIGN \
+     || (ctx)->operation == EVP_PKEY_OP_SIGNCTX \
+     || (ctx)->operation == EVP_PKEY_OP_VERIFY \
+     || (ctx)->operation == EVP_PKEY_OP_VERIFYCTX \
+     || (ctx)->operation == EVP_PKEY_OP_VERIFYRECOVER)
+
+#define EVP_PKEY_CTX_IS_DERIVE_OP(ctx) \
+    ((ctx)->operation == EVP_PKEY_OP_DERIVE)
 
 void openssl_add_all_ciphers_int(void);
 void openssl_add_all_digests_int(void);
diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c
index 38277095ad..cc09bbf1f2 100644
--- a/crypto/pkcs7/pk7_doit.c
+++ b/crypto/pkcs7/pk7_doit.c
@@ -834,11 +834,29 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
     if (EVP_DigestSignInit(mctx, &pctx, md, NULL, si->pkey) <= 0)
         goto err;
 
+    /*
+     * TODO(3.0): This causes problems when providers are in use, so disabled
+     * for now. Can we get rid of this completely? AFAICT this ctrl has never
+     * been used since it was first put in. All internal implementations just
+     * return 1 and ignore this ctrl and have always done so by the looks of
+     * things. To fix this we could convert this ctrl into a param, which would
+     * require us to send all the signer info data as a set of params...but that
+     * is non-trivial and since this isn't used by anything it may be better
+     * just to remove it. The original commit that added it had this
+     * justification in CHANGES:
+     *
+     * "During PKCS7 signing pass the PKCS7 SignerInfo structure to the
+     *  EVP_PKEY_METHOD before and after signing via the
+     *  EVP_PKEY_CTRL_PKCS7_SIGN ctrl. It can then customise the structure
+     *  before and/or after signing if necessary."
+     */
+#if 0
     if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
                           EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) {
         PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
         goto err;
     }
+#endif
 
     alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr, &abuf,
                          ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
@@ -856,11 +874,29 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
     if (EVP_DigestSignFinal(mctx, abuf, &siglen) <= 0)
         goto err;
 
+    /*
+     * TODO(3.0): This causes problems when providers are in use, so disabled
+     * for now. Can we get rid of this completely? AFAICT this ctrl has never
+     * been used since it was first put in. All internal implementations just
+     * return 1 and ignore this ctrl and have always done so by the looks of
+     * things. To fix this we could convert this ctrl into a param, which would
+     * require us to send all the signer info data as a set of params...but that
+     * is non-trivial and since this isn't used by anything it may be better
+     * just to remove it. The original commit that added it had this
+     * justification in CHANGES:
+     *
+     * "During PKCS7 signing pass the PKCS7 SignerInfo structure to the
+     *  EVP_PKEY_METHOD before and after signing via the
+     *  EVP_PKEY_CTRL_PKCS7_SIGN ctrl. It can then customise the structure
+     *  before and/or after signing if necessary."
+     */
+#if 0
     if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
                           EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) {
         PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
         goto err;
     }
+#endif
 
     EVP_MD_CTX_free(mctx);
 
diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index 1787e19ab7..13ea570865 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -2,7 +2,10 @@
 
 =head1 NAME
 
+EVP_PKEY_CTX_get_params,
+EVP_PKEY_CTX_gettable_params,
 EVP_PKEY_CTX_set_params,
+EVP_PKEY_CTX_settable_params,
 EVP_PKEY_CTX_ctrl,
 EVP_PKEY_CTX_ctrl_str,
 EVP_PKEY_CTX_ctrl_uint64,
@@ -63,7 +66,10 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
 
  #include <openssl/evp.h>
 
+ int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params);
+ const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params);
+ const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx);
 
  int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
                        int cmd, int p1, void *p2);
@@ -144,16 +150,20 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
 
 =head1 DESCRIPTION
 
-The EVP_PKEY_CTX_set_params() function sends arbitrary parameters to the
-algorithm implementation.
+The EVP_PKEY_CTX_get_params() and EVP_PKEY_CTX_set_params() functions get and
+send arbitrary parameters from and to the algorithm implementation respectively.
 Not all parameters may be supported by all providers.
 See L<OSSL_PROVIDER(3)> for more information on providers.
 See L<OSSL_PARAM(3)> for more information on parameters.
+These functions must only be called after the EVP_PKEY_CTX has been initialised
+for use in an operation (for example by L<EVP_PKEY_sign_init_ex(3)>,
+L<EVP_PKEY_derive_init_ex(3)> or other similar functions).
+
 The parameters currently supported by the default provider are:
 
 =over 4
 
-=item OSSL_EXCHANGE_PARAM_PAD (uint type)
+=item "pad" (B<OSSL_EXCHANGE_PARAM_PAD>) <uint>
 
 Sets the DH padding mode.
 If B<OSSL_EXCHANGE_PARAM_PAD> is 1 then the  shared secret is padded with zeroes
@@ -161,8 +171,29 @@ up to the size of the DH prime B<p>.
 If B<OSSL_EXCHANGE_PARAM_PAD> is zero (the default) then no padding is
 performed.
 
+=item "digest" (B<OSSL_SIGNATURE_PARAM_DIGEST>) <utf8 string>
+
+Gets and sets the name of the digest algorithm used for the input to the
+signature functions.
+
+=item "digest-size" (B<OSSL_SIGNATURE_PARAM_DIGEST_SIZE>) <size_t>
+
+Gets and sets the output size of the digest algorithm used for the input to the
+signature functions.
+The internal algorithm that supports this parameter is DSA.
+
 =back
 
+EVP_PKEY_CTX_gettable_params() and EVP_PKEY_CTX_settable_params() gets a
+constant B<OSSL_PARAM> array that decribes the  gettable and
+settable parameters for the current algorithm implementation, i.e. parameters
+that can be used with EVP_PKEY_CTX_get_params() and EVP_PKEY_CTX_set_params()
+respectively.
+See L<OSSL_PARAM(3)> for the use of B<OSSL_PARAM> as parameter descriptor.
+These functions must only be called after the EVP_PKEY_CTX has been initialised
+for use in an operation (for example by L<EVP_PKEY_sign_init_ex(3)>,
+L<EVP_PKEY_derive_init_ex(3)> or other similar functions).
+
 The function EVP_PKEY_CTX_ctrl() sends a control operation to the context
 B<ctx>. The key type used must match B<keytype> if it is not -1. The parameter
 B<optype> is a mask indicating which operations the control can be applied to.
@@ -188,13 +219,13 @@ B<pkeyutl>, B<genpkey> and B<req> commands.
 The function EVP_PKEY_CTX_md() sends a message digest control operation
 to the context B<ctx>. The message digest is specified by its name B<md>.
 
-All the remaining "functions" are implemented as macros.
+The EVP_PKEY_CTX_set_signature_md() function sets the message digest type used
+in a signature. It can be used in the RSA, DSA and ECDSA algorithms.
 
-The EVP_PKEY_CTX_set_signature_md() macro sets the message digest type used
+The EVP_PKEY_CTX_get_signature_md() function gets the message digest type used
 in a signature. It can be used in the RSA, DSA and ECDSA algorithms.
 
-The EVP_PKEY_CTX_get_signature_md() macro gets the message digest type used in a
-signature. It can be used in the RSA, DSA and ECDSA algorithms.
+All the remaining "functions" are implemented as macros.
 
 Key generation typically involves setting up parameters to be used and
 generating the private and public key data. Some algorithm implementations
@@ -460,9 +491,15 @@ allocate adequate memory space for the B<id> before calling EVP_PKEY_CTX_get1_id
 
 =head1 RETURN VALUES
 
-EVP_PKEY_CTX_ctrl() and its macros return a positive value for success and 0
-or a negative value for failure. In particular a return value of -2
-indicates the operation is not supported by the public key algorithm.
+EVP_PKEY_CTX_set_params() returns 1 for success or 0 otherwise.
+EVP_PKEY_CTX_settable_params() returns an OSSL_PARAM array on success or NULL on
+error.
+It may also return NULL if there are no settable parameters available.
+
+EVP_PKEY_CTX_set_signature_md(), EVP_PKEY_CTX_set_dh_pad(), EVP_PKEY_CTX_ctrl()
+and its macros return a positive value for success and 0 or a negative value for
+failure. In particular a return value of -2 indicates the operation is not
+supported by the public key algorithm.
 
 =head1 SEE ALSO
 
@@ -481,8 +518,9 @@ The
 EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len()
 macros were added in 1.1.1, other functions were added in OpenSSL 1.0.0.
 
-EVP_PKEY_CTX_set_dh_pad() was a macro in OpenSSL 1.1.1 and below.
-From OpenSSL 3.0 it is a function.
+EVP_PKEY_CTX_get_signature_md(), EVP_PKEY_CTX_set_signature_md() and
+EVP_PKEY_CTX_set_dh_pad() were macros in OpenSSL 1.1.1 and below. From OpenSSL
+3.0 they are functions.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/EVP_PKEY_derive.pod b/doc/man3/EVP_PKEY_derive.pod
index d6516e7933..832498ba76 100644
--- a/doc/man3/EVP_PKEY_derive.pod
+++ b/doc/man3/EVP_PKEY_derive.pod
@@ -25,10 +25,10 @@ The EVP_PKEY object associated with B<ctx> must be compatible with that
 algorithm.
 B<exchange> may be NULL in which case the EVP_KEYEXCH algorithm is fetched
 implicitly based on the type of EVP_PKEY associated with B<ctx>.
-See L<EVP_KEYEXCH_fetch(3)> for more information about implict fetches.
+See L<provider(7)/Implicit fetch> for more information about implict fetches.
 
-The EVP_PKEY_derive_init() function is the same as EVP_PKEY_derive() except that
-the EVP_KEYEXCH algorithm is always implicitly fetched.
+The EVP_PKEY_derive_init() function is the same as EVP_PKEY_derive_init_ex()
+except that the EVP_KEYEXCH algorithm is always implicitly fetched.
 
 The EVP_PKEY_derive_set_peer() function sets the peer key: this will normally
 be a public key.
diff --git a/doc/man3/EVP_PKEY_sign.pod b/doc/man3/EVP_PKEY_sign.pod
index d48edb5025..f30affd459 100644
--- a/doc/man3/EVP_PKEY_sign.pod
+++ b/doc/man3/EVP_PKEY_sign.pod
@@ -2,12 +2,14 @@
 
 =head1 NAME
 
-EVP_PKEY_sign_init, EVP_PKEY_sign - sign using a public key algorithm
+EVP_PKEY_sign_init_ex, EVP_PKEY_sign_init, EVP_PKEY_sign
+- sign using a public key algorithm
 
 =head1 SYNOPSIS
 
  #include <openssl/evp.h>
 
+ int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature);
  int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
                    unsigned char *sig, size_t *siglen,
@@ -15,8 +17,18 @@ EVP_PKEY_sign_init, EVP_PKEY_sign - sign using a public key algorithm
 
 =head1 DESCRIPTION
 
-The EVP_PKEY_sign_init() function initializes a public key algorithm
-context using key B<pkey> for a signing operation.
+The EVP_PKEY_sign_init_ex() function initializes a public key algorithm
+context for performing signing using the signature algorithm B<signature>.
+The signature algorithm B<signature> should be fetched using a call to
+L<EVP_SIGNATURE_fetch(3)>.
+The EVP_PKEY object associated with B<ctx> must be compatible with that
+algorithm.
+B<signature> may be NULL in which case the EVP_SIGNATURE algorithm is fetched
+implicitly based on the type of EVP_PKEY associated with B<ctx>.
+See L<provider(7)/Implicit fetch> for more information about implict fetches.
+
+The EVP_PKEY_sign_init() function is the same as EVP_PKEY_sign_init_ex() except
+that the EVP_SIGNATURE algorithm is always implicitly fetched.
 
 The EVP_PKEY_sign() function performs a public key signing operation
 using B<ctx>. The data to be signed is specified using the B<tbs> and
@@ -101,6 +113,7 @@ L<EVP_PKEY_derive(3)>
 
 =head1 HISTORY
 
+EVP_PKEY_sign_init_ex() was added in OpenSSL 3.0.
 These functions were added in OpenSSL 1.0.0.
 
 =head1 COPYRIGHT
diff --git a/doc/man3/EVP_PKEY_verify.pod b/doc/man3/EVP_PKEY_verify.pod
index 0212202514..1e04a85ca9 100644
--- a/doc/man3/EVP_PKEY_verify.pod
+++ b/doc/man3/EVP_PKEY_verify.pod
@@ -2,12 +2,14 @@
 
 =head1 NAME
 
-EVP_PKEY_verify_init, EVP_PKEY_verify - signature verification using a public key algorithm
+EVP_PKEY_verify_init_ex, EVP_PKEY_verify_init, EVP_PKEY_verify
+- signature verification using a public key algorithm
 
 =head1 SYNOPSIS
 
  #include <openssl/evp.h>
 
+ int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature);
  int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
                      const unsigned char *sig, size_t siglen,
@@ -15,8 +17,19 @@ EVP_PKEY_verify_init, EVP_PKEY_verify - signature verification using a public ke
 
 =head1 DESCRIPTION
 
-The EVP_PKEY_verify_init() function initializes a public key algorithm
-context using key B<pkey> for a signature verification operation.
+The EVP_PKEY_verify_init_ex() function initializes a public key algorithm
+context for performing signature verification using the signature algorithm
+B<signature>.
+The signature algorithm B<signature> should be fetched using a call to
+L<EVP_SIGNATURE_fetch(3)>.
+The EVP_PKEY object associated with B<ctx> must be compatible with that
+algorithm.
+B<signature> may be NULL in which case the EVP_SIGNATURE algorithm is fetched
+implicitly based on the type of EVP_PKEY associated with B<ctx>.
+See L<provider(7)/Implicit fetch> for more information about implict fetches.
+
+The EVP_PKEY_verify_init() function is the same as EVP_PKEY_verify_init_ex()
+except that the EVP_SIGNATURE algorithm is always implicitly fetched.
 
 The EVP_PKEY_verify() function performs a public key verification operation
 using B<ctx>. The signature is specified using the B<sig> and
@@ -89,7 +102,8 @@ L<EVP_PKEY_derive(3)>
 
 =head1 HISTORY
 
-These functions were added in OpenSSL 1.0.0.
+EVP_PKEY_verify_init_ex() was added in OpenSSL 3.0.
+All other functions were added in OpenSSL 1.0.0.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/EVP_PKEY_verify_recover.pod b/doc/man3/EVP_PKEY_verify_recover.pod
index 2b425a3852..737c372dd1 100644
--- a/doc/man3/EVP_PKEY_verify_recover.pod
+++ b/doc/man3/EVP_PKEY_verify_recover.pod
@@ -2,12 +2,15 @@
 
 =head1 NAME
 
-EVP_PKEY_verify_recover_init, EVP_PKEY_verify_recover - recover signature using a public key algorithm
+EVP_PKEY_verify_recover_init_ex, EVP_PKEY_verify_recover_init,
+EVP_PKEY_verify_recover - recover signature using a public key algorithm
 
 =head1 SYNOPSIS
 
  #include <openssl/evp.h>
 
+ int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx,
+                                     EVP_SIGNATURE *signature);
  int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
  int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
                              unsigned char *rout, size_t *routlen,
@@ -15,8 +18,20 @@ EVP_PKEY_verify_recover_init, EVP_PKEY_verify_recover - recover signature using
 
 =head1 DESCRIPTION
 
-The EVP_PKEY_verify_recover_init() function initializes a public key algorithm
-context using key B<pkey> for a verify recover operation.
+The EVP_PKEY_verify_recover_init_ex() function initializes a public key
+algorithm context for performing signature signed data recovery using the
+signature algorithm B<signature>.
+The signature algorithm B<signature> should be fetched using a call to
+L<EVP_SIGNATURE_fetch(3)>.
+The EVP_PKEY object associated with B<ctx> must be compatible with that
+algorithm.
+B<signature> may be NULL in which case the EVP_SIGNATURE algorithm is fetched
+implicitly based on the type of EVP_PKEY associated with B<ctx>.
+See L<provider(7)/Implicit fetch> for more information about implict fetches.
+
+The EVP_PKEY_verify_recover_init() function is the same as
+EVP_PKEY_verify_recover_init_ex() except that the EVP_SIGNATURE algorithm is
+always implicitly fetched.
 
 The EVP_PKEY_verify_recover() function recovers signed data
 using B<ctx>. The signature is specified using the B<sig> and
diff --git a/doc/man3/EVP_SIGNATURE_free.pod b/doc/man3/EVP_SIGNATURE_free.pod
new file mode 100644
index 0000000000..3e39b915e7
--- /dev/null
+++ b/doc/man3/EVP_SIGNATURE_free.pod
@@ -0,0 +1,64 @@
+=pod
+
+=head1 NAME
+
+EVP_SIGNATURE_fetch, EVP_SIGNATURE_free, EVP_SIGNATURE_up_ref,
+EVP_SIGNATURE_provider
+- Functions to manage EVP_SIGNATURE algorithm objects
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ EVP_SIGNATURE *EVP_SIGNATURE_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                    const char *properties);
+ void EVP_SIGNATURE_free(EVP_SIGNATURE *signature);
+ int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature);
+ OSSL_PROVIDER *EVP_SIGNATURE_provider(const EVP_SIGNATURE *signature);
+
+=head1 DESCRIPTION
+
+EVP_SIGNATURE_fetch() fetches the implementation for the given
+B<algorithm> from any provider offering it, within the criteria given
+by the B<properties>.
+The algorithm will be one offering functions for performing signature related
+tasks such as signing and verifying.
+See L<provider(7)/Fetching algorithms> for further information.
+
+The returned value must eventually be freed with EVP_SIGNATURE_free().
+
+EVP_SIGNATURE_free() decrements the reference count for the B<EVP_SIGNATURE>
+structure. Typically this structure will have been obtained from an earlier call
+to EVP_SIGNATURE_fetch(). If the reference count drops to 0 then the
+structure is freed.
+
+EVP_SIGNATURE_up_ref() increments the reference count for an B<EVP_SIGNATURE>
+structure.
+
+EVP_SIGNATURE_provider() returns the provider that I<signature> was fetched from.
+
+=head1 RETURN VALUES
+
+EVP_SIGNATURE_fetch() returns a pointer to an B<EVP_SIGNATURE> for success
+or B<NULL> for failure.
+
+EVP_SIGNATURE_up_ref() returns 1 for success or 0 otherwise.
+
+=head1 SEE ALSO
+
+L<provider(7)/Fetching algorithms>, L<OSSL_PROVIDER(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man7/provider-keyexch.pod b/doc/man7/provider-keyexch.pod
index 71830c12c6..9ef294395c 100644
--- a/doc/man7/provider-keyexch.pod
+++ b/doc/man7/provider-keyexch.pod
@@ -29,8 +29,8 @@ provider-keyexch - The keyexch library E<lt>-E<gt> provider functions
                        size_t outlen);
 
  /* Key Exchange parameters */
- int OP_keyexch_set_params(void *ctx, const OSSL_PARAM params[]);
-
+ int OP_keyexch_set_ctx_params(void *ctx, const OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_keyexch_settable_ctx_params(void);
 
 =head1 DESCRIPTION
 
@@ -61,15 +61,16 @@ For example, the "function" OP_keyexch_newctx() has these:
 B<OSSL_DISPATCH> arrays are indexed by numbers that are provided as
 macros in L<openssl-core_numbers.h(7)>, as follows:
 
- OP_keyexch_newctx           OSSL_FUNC_KEYEXCH_NEWCTX
- OP_keyexch_freectx          OSSL_FUNC_KEYEXCH_FREECTX
- OP_keyexch_dupctx           OSSL_FUNC_KEYEXCH_DUPCTX
+ OP_keyexch_newctx                OSSL_FUNC_KEYEXCH_NEWCTX
+ OP_keyexch_freectx               OSSL_FUNC_KEYEXCH_FREECTX
+ OP_keyexch_dupctx                OSSL_FUNC_KEYEXCH_DUPCTX
 
- OP_keyexch_init             OSSL_FUNC_KEYEXCH_INIT
- OP_keyexch_set_peer         OSSL_FUNC_KEYEXCH_SET_PEER
- OP_keyexch_derive           OSSL_FUNC_KEYEXCH_DERIVE
+ OP_keyexch_init                  OSSL_FUNC_KEYEXCH_INIT
+ OP_keyexch_set_peer              OSSL_FUNC_KEYEXCH_SET_PEER
+ OP_keyexch_derive                OSSL_FUNC_KEYEXCH_DERIVE
 
- OP_keyexch_set_params       OSSL_FUNC_KEYEXCH_SET_PARAMS
+ OP_keyexch_set_ctx_params        OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS
+ OP_keyexch_settable_ctx_params   OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS
 
 A key exchange algorithm implementation may not implement all of these functions.
 In order to be a consistent set of functions a provider must implement
@@ -127,8 +128,8 @@ written to B<*secretlen>.
 See L<OSSL_PARAM(3)> for further details on the parameters structure used by
 the OP_keyexch_set_params() function.
 
-OP_keyexch_set_params() sets key exchange parameters associated with the given
-provider side key exchange context B<ctx> to B<params>.
+OP_keyexch_set_ctx_params() sets key exchange parameters associated with the
+given provider side key exchange context B<ctx> to B<params>.
 Any parameter settings are additional to any that were previously set.
 
 Parameters currently recognised by built-in key exchange algorithms are as
@@ -151,6 +152,11 @@ possible secret size.
 
 =back
 
+OP_keyexch_settable_ctx_params() gets a constant B<OSSL_PARAM> array that
+decribes the settable parameters, i.e. parameters that can be used with
+OP_signature_set_ctx_params().
+See L<OSSL_PARAM(3)> for the use of B<OSSL_PARAM> as parameter descriptor.
+
 =head1 RETURN VALUES
 
 OP_keyexch_newctx() and OP_keyexch_dupctx() should return the newly created
diff --git a/doc/man7/provider-signature.pod b/doc/man7/provider-signature.pod
new file mode 100644
index 0000000000..1ab4831035
--- /dev/null
+++ b/doc/man7/provider-signature.pod
@@ -0,0 +1,239 @@
+=pod
+
+=head1 NAME
+
+provider-signature - The signature library E<lt>-E<gt> provider functions
+
+=head1 SYNOPSIS
+
+=for comment multiple includes
+
+ #include <openssl/core_numbers.h>
+ #include <openssl/core_names.h>
+
+ /*
+  * None of these are actual functions, but are displayed like this for
+  * the function signatures for functions that are offered as function
+  * pointers in OSSL_DISPATCH arrays.
+  */
+
+ /* Context management */
+ void *OP_signature_newctx(void *provctx);
+ void OP_signature_freectx(void *ctx);
+ void *OP_signature_dupctx(void *ctx);
+
+ /* Signing */
+ int OP_signature_sign_init(void *ctx, void *provkey);
+ int OP_signature_sign(void *ctx, unsigned char *sig, size_t *siglen,
+                       size_t sigsize, const unsigned char *tbs, size_t tbslen);
+
+ /* Verifying */
+ int OP_signature_verify_init(void *ctx, void *provkey);
+ int OP_signature_verify(void *ctx, const unsigned char *sig, size_t siglen,
+                         const unsigned char *tbs, size_t tbslen);
+
+ /* Verify Recover */
+ int OP_signature_verify_recover_init(void *ctx, void *provkey);
+ int OP_signature_verify_recover(void *ctx, unsigned char *rout,
+                                 size_t *routlen, size_t routsize,
+                                 const unsigned char *sig, size_t siglen);
+
+ /* Signature parameters */
+ int OP_signature_get_ctx_params(void *ctx, OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_signature_gettable_ctx_params(void);
+ int OP_signature_set_ctx_params(void *ctx, const OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_signature_settable_ctx_params(void);
+
+=head1 DESCRIPTION
+
+This documentation is primarily aimed at provider authors. See L<provider(7)>
+for further information.
+
+The signature (OSSL_OP_SIGNATURE) operation enables providers to implement
+signature algorithms and make them available to applications via the API
+functions L<EVP_PKEY_sign_init_ex(3)>, L<EVP_PKEY_sign(3)>,
+L<EVP_PKEY_verify_init_ex(3)>, L<EVP_PKEY_verify(3)>,
+L<EVP_PKEY_verify_recover_init_ex(3)> and L<EVP_PKEY_verify_recover(3)> (as well
+as other related functions).
+
+All "functions" mentioned here are passed as function pointers between
+F<libcrypto> and the provider in B<OSSL_DISPATCH> arrays via
+B<OSSL_ALGORITHM> arrays that are returned by the provider's
+provider_query_operation() function
+(see L<provider-base(7)/Provider Functions>).
+
+All these "functions" have a corresponding function type definition
+named B<OSSL_{name}_fn>, and a helper function to retrieve the
+function pointer from an B<OSSL_DISPATCH> element named
+B<OSSL_get_{name}>.
+For example, the "function" OP_signature_newctx() has these:
+
+ typedef void *(OSSL_OP_signature_newctx_fn)(void *provctx);
+ static ossl_inline OSSL_OP_signature_newctx_fn
+     OSSL_get_OP_signature_newctx(const OSSL_DISPATCH *opf);
+
+B<OSSL_DISPATCH> arrays are indexed by numbers that are provided as
+macros in L<openssl-core_numbers.h(7)>, as follows:
+
+ OP_signature_newctx                 OSSL_FUNC_SIGNATURE_NEWCTX
+ OP_signature_freectx                OSSL_FUNC_SIGNATURE_FREECTX
+ OP_signature_dupctx                 OSSL_FUNC_SIGNATURE_DUPCTX
+
+ OP_signature_sign_init              OSSL_FUNC_SIGNATURE_SIGN_INIT
+ OP_signature_sign                   OSSL_FUNC_SIGNATURE_SIGN
+
+ OP_signature_verify_init            OSSL_FUNC_SIGNATURE_VERIFY_INIT
+ OP_signature_verify                 OSSL_FUNC_SIGNATURE_VERIFY
+
+ OP_signature_verify_recover_init    OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT
+ OP_signature_verify_recover         OSSL_FUNC_SIGNATURE_VERIFY_RECOVER
+
+ OP_signature_get_ctx_params         OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS
+ OP_signature_gettable_ctx_params    OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS
+ OP_signature_set_ctx_params         OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS
+ OP_signature_settable_ctx_params    OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS
+
+A signature algorithm implementation may not implement all of these functions.
+In order to be a consistent set of functions a provider must implement
+OP_signature_newctx and OP_signature_freectx.
+It must also implement both of OP_signature_sign_init and OP_signature_sign,
+or both of OP_signature_verify_init and OP_signature_verify, or both of
+OP_signature_verify_recover_init and OP_signature_verify_recover.
+All other functions are optional.
+
+A signature algorithm must also implement some mechanism for generating,
+loading or importing keys via the key management (OSSL_OP_KEYMGMT) operation.
+See L<provider-keymgmt(7)> for further details.
+
+=head2 Context Management Functions
+
+OP_signature_newctx() should create and return a pointer to a provider side
+structure for holding context information during a signature operation.
+A pointer to this context will be passed back in a number of the other signature
+operation function calls.
+The parameter B<provctx> is the provider context generated during provider
+initialisation (see L<provider(3)>).
+
+OP_signature_freectx() is passed a pointer to the provider side signature
+context in the B<ctx> parameter.
+This function should free any resources associated with that context.
+
+OP_signature_dupctx() should duplicate the provider side signature context in
+the B<ctx> parameter and return the duplicate copy.
+
+=head2 Signing Functions
+
+OP_signature_sign_init() initialises a context for signing given a provider side
+signature context in the B<ctx> parameter, and a pointer to a provider key object
+in the B<provkey> parameter.
+The key object should have been previously generated, loaded or imported into
+the provider using the key management (OSSL_OP_KEYMGMT) operation (see
+provider-keymgmt(7)>.
+
+OP_signature_sign() performs the actual signing itself.
+A previously initialised signature context is passed in the B<ctx>
+parameter.
+The data to be signed is pointed to be the B<tbs> parameter which is B<tbslen>
+bytes long.
+Unless B<sig> is NULL, the signature should be written to the location pointed
+to by the B<sig> parameter and it should not exceed B<sigsize> bytes in length.
+The length of the signature should be written to B<*siglen>.
+If B<sig> is NULL then the maximum length of the signature should be written to
+B<*siglen>.
+
+=head2 Verify Functions
+
+OP_signature_verify_init() initialises a context for verifying a signature given
+a provider side signature context in the B<ctx> parameter, and a pointer to a
+provider key object in the B<provkey> parameter.
+The key object should have been previously generated, loaded or imported into
+the provider using the key management (OSSL_OP_KEYMGMT) operation (see
+provider-keymgmt(7)>.
+
+OP_signature_verify() performs the actual verification itself.
+A previously initialised signature context is passed in the B<ctx> parameter.
+The data that the signature covers is pointed to be the B<tbs> parameter which
+is B<tbslen> bytes long.
+The signature is pointed to by the B<sig> parameter which is B<siglen> bytes
+long.
+
+=head2 Verify Recover Functions
+
+OP_signature_verify_recover_init() initialises a context for recovering the
+signed data given a provider side signature context in the B<ctx> parameter, and
+a pointer to a provider key object in the B<provkey> parameter.
+The key object should have been previously generated, loaded or imported into
+the provider using the key management (OSSL_OP_KEYMGMT) operation (see
+provider-keymgmt(7)>.
+
+OP_signature_verify_recover() performs the actual verify recover itself.
+A previously initialised signature context is passed in the B<ctx> parameter.
+The signature is pointed to by the B<sig> parameter which is B<siglen> bytes
+long.
+Unless B<rout> is NULL, the recovered data should be written to the location
+pointed to by B<rout> which should not exceed B<routsize> bytes in length.
+The length of the recovered data should be written to B<*routlen>.
+If B<rout> is B<NULL> then the maximum size of the output buffer is written to
+the B<routlen> parameter.
+
+=head2 Signature Parameters
+
+See L<OSSL_PARAM(3)> for further details on the parameters structure used by
+the OP_signature_get_ctx_params() and OP_signature_set_ctx_params() functions.
+
+OP_signature_get_ctx_params() gets signature parameters associated with the
+given provider side signature context B<ctx> and stored them in B<params>.
+OP_signature_set_ctx_params() sets the signature parameters associated with the
+given provider side signature context B<ctx> to B<params>.
+Any parameter settings are additional to any that were previously set.
+
+Parameters currently recognised by built-in signature algorithms are as
+follows.
+Not all parameters are relevant to, or are understood by all signature
+algorithms:
+
+=over 4
+
+=item "digest" (B<OSSL_SIGNATURE_PARAM_DIGEST>) <utf8 string>
+
+Get or sets the name of the digest algorithm used for the input to the signature
+functions.
+
+=item "digest-size" (B<OSSL_SIGNATURE_PARAM_DIGEST_SIZE>) <size_t>
+
+Gets or sets the output size of the digest algorithm used for the input to the
+signature functions.
+
+=back
+
+OP_signature_gettable_ctx_params() and OP_signature_settable_ctx_params() get a
+constant B<OSSL_PARAM> array that decribes the gettable and settable parameters,
+i.e. parameters that can be used with OP_signature_get_ctx_params() and
+OP_signature_set_ctx_params() respectively.
+See L<OSSL_PARAM(3)> for the use of B<OSSL_PARAM> as parameter descriptor.
+
+=head1 RETURN VALUES
+
+OP_signature_newctx() and OP_signature_dupctx() should return the newly created
+provider side signature, or NULL on failure.
+
+All other functions should return 1 for success or 0 on error.
+
+=head1 SEE ALSO
+
+L<provider(7)>
+
+=head1 HISTORY
+
+The provider SIGNATURE interface was introduced in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index b78a0978fd..27b4588ce1 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -129,17 +129,26 @@ extern "C" {
 #define OSSL_KDF_PARAM_SIZE         "size"      /* size_t */
 
 /* PKEY parameters */
-/* Diffie-Hellman Parameters */
-#define OSSL_PKEY_PARAM_DH_P         "dh-p"
-#define OSSL_PKEY_PARAM_DH_G         "dh-g"
-#define OSSL_PKEY_PARAM_DH_Q         "dh-q"
+/* Diffie-Hellman/DSA Parameters */
+#define OSSL_PKEY_PARAM_FFC_P        "p"
+#define OSSL_PKEY_PARAM_FFC_G        "g"
+#define OSSL_PKEY_PARAM_FFC_Q        "q"
+
 /* Diffie-Hellman Keys */
-#define OSSL_PKEY_PARAM_DH_PUB_KEY   "dh-pub"
-#define OSSL_PKEY_PARAM_DH_PRIV_KEY  "dh-priv"
+#define OSSL_PKEY_PARAM_DH_PUB_KEY   "pub"
+#define OSSL_PKEY_PARAM_DH_PRIV_KEY  "priv"
+
+/* DSA Keys */
+#define OSSL_PKEY_PARAM_DSA_PUB_KEY  "pub"
+#define OSSL_PKEY_PARAM_DSA_PRIV_KEY "priv"
 
 /* Key Exchange parameters */
 
-#define OSSL_EXCHANGE_PARAM_PAD      "exchange-pad" /* uint */
+#define OSSL_EXCHANGE_PARAM_PAD      "pad" /* uint */
+
+/* Signature parameters */
+#define OSSL_SIGNATURE_PARAM_DIGEST         "digest"
+#define OSSL_SIGNATURE_PARAM_DIGEST_SIZE    "digest-size"
 
 # ifdef __cplusplus
 }
diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h
index 521cd8c800..002582012e 100644
--- a/include/openssl/core_numbers.h
+++ b/include/openssl/core_numbers.h
@@ -156,8 +156,9 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ITEM *,provider_get_reason_strings,
 # define OSSL_OP_KDF                                 4
 # define OSSL_OP_KEYMGMT                            10
 # define OSSL_OP_KEYEXCH                            11
+# define OSSL_OP_SIGNATURE                          12
 /* Highest known operation number */
-# define OSSL_OP__HIGHEST                           11
+# define OSSL_OP__HIGHEST                           12
 
 /* Digests */
 
@@ -388,7 +389,8 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_exportkey_types, (void))
 # define OSSL_FUNC_KEYEXCH_SET_PEER                    4
 # define OSSL_FUNC_KEYEXCH_FREECTX                     5
 # define OSSL_FUNC_KEYEXCH_DUPCTX                      6
-# define OSSL_FUNC_KEYEXCH_SET_PARAMS                  7
+# define OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS              7
+# define OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS         8
 
 OSSL_CORE_MAKE_FUNC(void *, OP_keyexch_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(int, OP_keyexch_init, (void *ctx, void *provkey))
@@ -397,8 +399,57 @@ OSSL_CORE_MAKE_FUNC(int, OP_keyexch_derive, (void *ctx,  unsigned char *secret,
 OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_peer, (void *ctx, void *provkey))
 OSSL_CORE_MAKE_FUNC(void, OP_keyexch_freectx, (void *ctx))
 OSSL_CORE_MAKE_FUNC(void *, OP_keyexch_dupctx, (void *ctx))
-OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_params, (void *ctx,
-                                                 const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(int, OP_keyexch_set_ctx_params, (void *ctx,
+                                                     const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keyexch_settable_ctx_params,
+                    (void))
+
+/* Signature */
+
+# define OSSL_FUNC_SIGNATURE_NEWCTX                  1
+# define OSSL_FUNC_SIGNATURE_SIGN_INIT               2
+# define OSSL_FUNC_SIGNATURE_SIGN                    3
+# define OSSL_FUNC_SIGNATURE_VERIFY_INIT             4
+# 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
+
+OSSL_CORE_MAKE_FUNC(void *, OP_signature_newctx, (void *provctx))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_sign_init, (void *ctx, void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_sign, (void *ctx,  unsigned char *sig,
+                                             size_t *siglen, size_t sigsize,
+                                             const unsigned char *tbs,
+                                             size_t tbslen))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_init, (void *ctx, void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_verify, (void *ctx,
+                                               const unsigned char *sig,
+                                               size_t siglen,
+                                               const unsigned char *tbs,
+                                               size_t tbslen))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_recover_init, (void *ctx,
+                                                            void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_signature_verify_recover, (void *ctx,
+                                                       unsigned char *rout,
+                                                       size_t *routlen,
+                                                       size_t routsize,
+                                                       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,
+                    (void *ctx, OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_gettable_ctx_params,
+                    (void))
+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))
 
 # ifdef __cplusplus
 }
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index d1bd0b69d0..69d70e5e9c 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -1337,6 +1337,9 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
                                      int (*pkey_security_bits) (const EVP_PKEY
                                                                 *pk));
 
+int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
 # define EVP_PKEY_OP_UNDEFINED           0
 # define EVP_PKEY_OP_PARAMGEN            (1<<1)
 # define EVP_PKEY_OP_KEYGEN              (1<<2)
@@ -1362,14 +1365,6 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
 # define EVP_PKEY_OP_TYPE_GEN \
                 (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN)
 
-# define  EVP_PKEY_CTX_set_signature_md(ctx, md) \
-                EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,  \
-                                        EVP_PKEY_CTRL_MD, 0, (void *)(md))
-
-# define  EVP_PKEY_CTX_get_signature_md(ctx, pmd)        \
-                EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,  \
-                                        EVP_PKEY_CTRL_GET_MD, 0, (void *)(pmd))
-
 # define  EVP_PKEY_CTX_set_mac_key(ctx, key, len)        \
                 EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN,  \
                                   EVP_PKEY_CTRL_SET_MAC_KEY, len, (void *)(key))
@@ -1429,7 +1424,10 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
 EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *ctx);
 void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
 
+int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params);
+const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params);
+const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
                       int cmd, int p1, void *p2);
 int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
@@ -1470,14 +1468,23 @@ EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx);
 void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
 void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
 
+void EVP_SIGNATURE_free(EVP_SIGNATURE *signature);
+int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature);
+OSSL_PROVIDER *EVP_SIGNATURE_provider(const EVP_SIGNATURE *signature);
+EVP_SIGNATURE *EVP_SIGNATURE_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                   const char *properties);
+
+int EVP_PKEY_sign_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature);
 int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
                   unsigned char *sig, size_t *siglen,
                   const unsigned char *tbs, size_t tbslen);
+int EVP_PKEY_verify_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature);
 int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
                     const unsigned char *sig, size_t siglen,
                     const unsigned char *tbs, size_t tbslen);
+int EVP_PKEY_verify_recover_init_ex(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature);
 int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
                             unsigned char *rout, size_t *routlen,
diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h
index 7eec053bee..530de2d20c 100644
--- a/include/openssl/ossl_typ.h
+++ b/include/openssl/ossl_typ.h
@@ -108,6 +108,8 @@ typedef struct evp_kdf_ctx_st EVP_KDF_CTX;
 
 typedef struct evp_keyexch_st EVP_KEYEXCH;
 
+typedef struct evp_signature_st EVP_SIGNATURE;
+
 typedef struct evp_Encode_Ctx_st EVP_ENCODE_CTX;
 
 typedef struct hmac_ctx_st HMAC_CTX;
diff --git a/providers/common/build.info b/providers/common/build.info
index b098ca6958..916cc3e4ea 100644
--- a/providers/common/build.info
+++ b/providers/common/build.info
@@ -1,4 +1,4 @@
-SUBDIRS=digests ciphers macs kdfs exchange keymgmt
+SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature
 $COMMON=provider_util.c
 
 SOURCE[../../libcrypto]=$COMMON provider_err.c provlib.c
diff --git a/providers/common/exchange/dh_exch.c b/providers/common/exchange/dh_exch.c
index 5ff8318725..cfbda43fb8 100644
--- a/providers/common/exchange/dh_exch.c
+++ b/providers/common/exchange/dh_exch.c
@@ -20,6 +20,8 @@ static OSSL_OP_keyexch_set_peer_fn dh_set_peer;
 static OSSL_OP_keyexch_derive_fn dh_derive;
 static OSSL_OP_keyexch_freectx_fn dh_freectx;
 static OSSL_OP_keyexch_dupctx_fn dh_dupctx;
+static OSSL_OP_keyexch_set_ctx_params_fn dh_set_ctx_params;
+static OSSL_OP_keyexch_settable_ctx_params_fn dh_settable_ctx_params;
 
 /*
  * What's passed as an actual key is defined by the KEYMGMT interface.
@@ -124,7 +126,7 @@ static void *dh_dupctx(void *vpdhctx)
     return dstctx;
 }
 
-static int dh_set_params(void *vpdhctx, const OSSL_PARAM params[])
+static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])
 {
     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
     const OSSL_PARAM *p;
@@ -140,6 +142,16 @@ static int dh_set_params(void *vpdhctx, const OSSL_PARAM params[])
     return 1;
 }
 
+static const OSSL_PARAM known_settable_ctx_params[] = {
+    OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *dh_settable_ctx_params(void)
+{
+    return known_settable_ctx_params;
+}
+
 const OSSL_DISPATCH dh_keyexch_functions[] = {
     { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx },
     { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init },
@@ -147,6 +159,8 @@ const OSSL_DISPATCH dh_keyexch_functions[] = {
     { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer },
     { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx },
     { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx },
-    { OSSL_FUNC_KEYEXCH_SET_PARAMS, (void (*)(void))dh_set_params },
+    { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params },
+    { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
+      (void (*)(void))dh_settable_ctx_params },
     { 0, NULL }
 };
diff --git a/providers/common/include/internal/provider_algs.h b/providers/common/include/internal/provider_algs.h
index b9d257649f..92aa64772e 100644
--- a/providers/common/include/internal/provider_algs.h
+++ b/providers/common/include/internal/provider_algs.h
@@ -161,6 +161,10 @@ extern const OSSL_DISPATCH kdf_x942_kdf_functions[];
 
 /* Key management */
 extern const OSSL_DISPATCH dh_keymgmt_functions[];
+extern const OSSL_DISPATCH dsa_keymgmt_functions[];
 
 /* Key Exchange */
 extern const OSSL_DISPATCH dh_keyexch_functions[];
+
+/* Signature */
+extern const OSSL_DISPATCH dsa_signature_functions[];
diff --git a/providers/common/keymgmt/build.info b/providers/common/keymgmt/build.info
index a41f3dac6e..4e7bc750f5 100644
--- a/providers/common/keymgmt/build.info
+++ b/providers/common/keymgmt/build.info
@@ -1,5 +1,5 @@
 LIBS=../../../libcrypto
 IF[{- !$disabled{dh} -}]
   SOURCE[../../../libcrypto]=\
-          dh_kmgmt.c
+          dh_kmgmt.c dsa_kmgmt.c
 ENDIF
diff --git a/providers/common/keymgmt/dh_kmgmt.c b/providers/common/keymgmt/dh_kmgmt.c
index 67e3205edc..c13f07546b 100644
--- a/providers/common/keymgmt/dh_kmgmt.c
+++ b/providers/common/keymgmt/dh_kmgmt.c
@@ -24,8 +24,8 @@ static int params_to_key(DH *dh, const OSSL_PARAM params[])
     if (dh == NULL)
         return 0;
 
-    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_P);
-    param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_G);
+    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
+    param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
     param_priv_key =
         OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_KEY);
     param_pub_key =
diff --git a/providers/common/keymgmt/dsa_kmgmt.c b/providers/common/keymgmt/dsa_kmgmt.c
new file mode 100644
index 0000000000..a53c0b212c
--- /dev/null
+++ b/providers/common/keymgmt/dsa_kmgmt.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/params.h>
+#include "internal/provider_algs.h"
+
+static OSSL_OP_keymgmt_importkey_fn dsa_importkey;
+
+static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_p, *param_q, *param_g, *param_priv_key;
+    const OSSL_PARAM *param_pub_key;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL;
+
+    if (dsa == NULL)
+        return 0;
+
+    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
+    param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_Q);
+    param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
+    param_priv_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DSA_PRIV_KEY);
+    param_pub_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DSA_PUB_KEY);
+
+    /*
+     * DSA documentation says that a public key must be present if a private key
+     * is.
+     */
+    if (param_priv_key != NULL && param_pub_key == NULL)
+        return 0;
+
+    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
+        || (param_q != NULL && !OSSL_PARAM_get_BN(param_q, &q))
+        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g))
+        || (param_priv_key != NULL
+            && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
+        || (param_pub_key != NULL
+            && !OSSL_PARAM_get_BN(param_pub_key, &pub_key)))
+        goto err;
+
+    if (!DSA_set0_pqg(dsa, p, q, g))
+        goto err;
+    p = q = g = NULL;
+
+    if (pub_key != NULL && !DSA_set0_key(dsa, pub_key, priv_key))
+        goto err;
+    priv_key = pub_key = NULL;
+
+    return 1;
+
+ err:
+    BN_free(p);
+    BN_free(q);
+    BN_free(g);
+    BN_free(priv_key);
+    BN_free(pub_key);
+    return 0;
+}
+
+static void *dsa_importkey(void *provctx, const OSSL_PARAM params[])
+{
+    DSA *dsa;
+
+    if ((dsa = DSA_new()) == NULL
+        || !params_to_key(dsa, params)) {
+        DSA_free(dsa);
+        dsa = NULL;
+    }
+    return dsa;
+}
+
+const OSSL_DISPATCH dsa_keymgmt_functions[] = {
+    /*
+     * TODO(3.0) When implementing OSSL_FUNC_KEYMGMT_GENKEY, remember to also
+     * implement OSSL_FUNC_KEYMGMT_EXPORTKEY.
+     */
+    { OSSL_FUNC_KEYMGMT_IMPORTKEY, (void (*)(void))dsa_importkey },
+    { OSSL_FUNC_KEYMGMT_FREEKEY, (void (*)(void))DSA_free },
+    { 0, NULL }
+};
diff --git a/providers/common/exchange/build.info b/providers/common/signature/build.info
similarity index 58%
copy from providers/common/exchange/build.info
copy to providers/common/signature/build.info
index c99c9d81b5..5b64229dfc 100644
--- a/providers/common/exchange/build.info
+++ b/providers/common/signature/build.info
@@ -1,7 +1,7 @@
 LIBS=../../../libcrypto
-IF[{- !$disabled{dh} -}]
+IF[{- !$disabled{dsa} -}]
   SOURCE[../../../libcrypto]=\
-          dh_exch.c
+          dsa.c
 ENDIF
 
 
diff --git a/providers/common/signature/dsa.c b/providers/common/signature/dsa.c
new file mode 100644
index 0000000000..dc4eb6c6d4
--- /dev/null
+++ b/providers/common/signature/dsa.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/dsa.h>
+#include <openssl/params.h>
+#include "internal/provider_algs.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_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;
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes DSA structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+    DSA *dsa;
+    size_t mdsize;
+    /* Should be big enough */
+    char mdname[80];
+} PROV_DSA_CTX;
+
+static void *dsa_newctx(void *provctx)
+{
+    return OPENSSL_zalloc(sizeof(PROV_DSA_CTX));
+}
+
+static int dsa_signature_init(void *vpdsactx, void *vdsa)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx == NULL || vdsa == NULL || !DSA_up_ref(vdsa))
+        return 0;
+    DSA_free(pdsactx->dsa);
+    pdsactx->dsa = vdsa;
+    return 1;
+}
+
+static int dsa_sign(void *vpdsactx, unsigned char *sig, size_t *siglen,
+                    size_t sigsize, const unsigned char *tbs, size_t tbslen)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+    int ret;
+    unsigned int sltmp;
+    size_t dsasize = DSA_size(pdsactx->dsa);
+
+    if (sig == NULL) {
+        *siglen = dsasize;
+        return 1;
+    }
+
+    if (sigsize < (size_t)dsasize)
+        return 0;
+
+    if (pdsactx->mdsize != 0 && tbslen != pdsactx->mdsize)
+        return 0;
+
+    ret = DSA_sign(0, tbs, tbslen, sig, &sltmp, pdsactx->dsa);
+
+    if (ret <= 0)
+        return 0;
+
+    *siglen = sltmp;
+    return 1;
+}
+
+static int dsa_verify(void *vpdsactx, const unsigned char *sig, size_t siglen,
+                      const unsigned char *tbs, size_t tbslen)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    if (pdsactx->mdsize != 0 && tbslen != pdsactx->mdsize)
+        return 0;
+
+    return DSA_verify(0, tbs, tbslen, sig, siglen, pdsactx->dsa);
+}
+
+
+static void dsa_freectx(void *vpdsactx)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+    DSA_free(pdsactx->dsa);
+
+    OPENSSL_free(pdsactx);
+}
+
+static void *dsa_dupctx(void *vpdsactx)
+{
+    PROV_DSA_CTX *srcctx = (PROV_DSA_CTX *)vpdsactx;
+    PROV_DSA_CTX *dstctx;
+
+    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+    if (dstctx == NULL)
+        return NULL;
+
+    *dstctx = *srcctx;
+    if (dstctx->dsa != NULL && !DSA_up_ref(dstctx->dsa)) {
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    return dstctx;
+}
+
+static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params)
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+    OSSL_PARAM *p;
+
+    if (pdsactx == NULL || params == NULL)
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, pdsactx->mdsize))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
+    if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdsactx->mdname))
+        return 0;
+
+    return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+    OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL),
+    OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *dsa_gettable_ctx_params(void)
+{
+    return known_gettable_ctx_params;
+}
+
+static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[])
+{
+    PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+    const OSSL_PARAM *p;
+    char *mdname;
+
+    if (pdsactx == NULL || params == NULL)
+        return 0;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
+    if (p != NULL && !OSSL_PARAM_get_size_t(p, &pdsactx->mdsize))
+        return 0;
+
+    /*
+     * We never actually use the mdname, but we do support getting it later.
+     * This can be useful for applications that want to know the MD that they
+     * previously set.
+     */
+    p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+    mdname = pdsactx->mdname;
+    if (p != NULL
+            && !OSSL_PARAM_get_utf8_string(p, &mdname, sizeof(pdsactx->mdname)))
+        return 0;
+
+    return 1;
+}
+
+static const OSSL_PARAM known_settable_ctx_params[] = {
+    OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL),
+    OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *dsa_settable_ctx_params(void)
+{
+    return known_settable_ctx_params;
+}
+
+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_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 },
+    { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
+      (void (*)(void))dsa_gettable_ctx_params },
+    { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))dsa_set_ctx_params },
+    { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
+      (void (*)(void))dsa_settable_ctx_params },
+    { 0, NULL }
+};
diff --git a/providers/default/defltprov.c b/providers/default/defltprov.c
index 8a950482c8..9ce918aea5 100644
--- a/providers/default/defltprov.c
+++ b/providers/default/defltprov.c
@@ -234,9 +234,20 @@ static const OSSL_ALGORITHM deflt_keyexch[] = {
     { NULL, NULL, NULL }
 };
 
+static const OSSL_ALGORITHM deflt_signature[] = {
+#ifndef OPENSSL_NO_DSA
+    { "DSA", "default=yes", dsa_signature_functions },
+#endif
+    { NULL, NULL, NULL }
+};
+
+
 static const OSSL_ALGORITHM deflt_keymgmt[] = {
 #ifndef OPENSSL_NO_DH
     { "dhKeyAgreement", "default=yes", dh_keymgmt_functions },
+#endif
+#ifndef OPENSSL_NO_DSA
+    { "DSA", "default=yes", dsa_keymgmt_functions },
 #endif
     { NULL, NULL, NULL }
 };
@@ -259,6 +270,8 @@ static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov,
         return deflt_keymgmt;
     case OSSL_OP_KEYEXCH:
         return deflt_keyexch;
+    case OSSL_OP_SIGNATURE:
+        return deflt_signature;
     }
     return NULL;
 }
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 1ad62d2f79..7b7c632dd1 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -19,6 +19,8 @@
 #include <openssl/pem.h>
 #include <openssl/kdf.h>
 #include <openssl/provider.h>
+#include <openssl/core_names.h>
+#include <openssl/dsa.h>
 #include "testutil.h"
 #include "internal/nelem.h"
 #include "internal/evp_int.h"
@@ -1393,6 +1395,117 @@ static int test_EVP_CIPHER_fetch(int tst)
     return ret;
 }
 
+/* Test getting and setting parameters on an EVP_PKEY_CTX */
+static int test_EVP_PKEY_CTX_get_set_params(void)
+{
+    EVP_PKEY_CTX *ctx = NULL;
+    EVP_SIGNATURE *dsaimpl = NULL;
+    const OSSL_PARAM *params;
+    OSSL_PARAM ourparams[2], *param = ourparams;
+    DSA *dsa = NULL;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL;
+    EVP_PKEY *pkey = NULL;
+    int ret = 0;
+    const EVP_MD *md;
+    size_t mdsize = SHA512_DIGEST_LENGTH;
+
+    /*
+     * Setup the parameters for our DSA object. For our purposes they don't have
+     * to actually be *valid* parameters. We just need to set something. We
+     * don't even need a pub_key/priv_key.
+     */
+    dsa = DSA_new();
+    p = BN_new();
+    q = BN_new();
+    g = BN_new();
+    if (!TEST_ptr(dsa)
+            || !TEST_ptr(p)
+            || !TEST_ptr(q)
+            || !TEST_ptr(g)
+            || !DSA_set0_pqg(dsa, p, q, g))
+        goto err;
+    p = q = g = NULL;
+
+    pkey = EVP_PKEY_new();
+    if (!TEST_ptr(pkey)
+            || !TEST_true(EVP_PKEY_assign_DSA(pkey, dsa)))
+        goto err;
+
+    dsa = NULL;
+
+    /* Initialise a sign operation */
+    ctx = EVP_PKEY_CTX_new(pkey, NULL);
+    dsaimpl = EVP_SIGNATURE_fetch(NULL, "DSA", NULL);
+    if (!TEST_ptr(ctx)
+            || !TEST_ptr(dsaimpl)
+            || !TEST_int_gt(EVP_PKEY_sign_init_ex(ctx, dsaimpl), 0))
+        goto err;
+
+    /*
+     * We should be able to query the parameters now. The default DSA
+     * implementation supports exactly one parameter - so we expect to see that
+     * returned and no more.
+     */
+    params = EVP_PKEY_CTX_settable_params(ctx);
+    if (!TEST_ptr(params)
+            || !TEST_int_eq(strcmp(params[0].key,
+                            OSSL_SIGNATURE_PARAM_DIGEST_SIZE), 0)
+            || !TEST_int_eq(strcmp(params[1].key, OSSL_SIGNATURE_PARAM_DIGEST),
+                            0)
+               /* The final key should be NULL */
+            || !TEST_ptr_null(params[2].key))
+        goto err;
+
+    /* Gettable params are the same as the settable ones */
+    params = EVP_PKEY_CTX_gettable_params(ctx);
+    if (!TEST_ptr(params)
+            || !TEST_int_eq(strcmp(params[0].key,
+                            OSSL_SIGNATURE_PARAM_DIGEST_SIZE), 0)
+            || !TEST_int_eq(strcmp(params[1].key, OSSL_SIGNATURE_PARAM_DIGEST),
+                            0)
+               /* The final key should be NULL */
+            || !TEST_ptr_null(params[2].key))
+        goto err;
+
+    /*
+     * Test getting and setting params via EVP_PKEY_CTX_set_params() and
+     * EVP_PKEY_CTX_get_params()
+     */
+    *param++ = OSSL_PARAM_construct_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE,
+                                           &mdsize);
+    *param++ = OSSL_PARAM_construct_end();
+
+    if (!TEST_true(EVP_PKEY_CTX_set_params(ctx, ourparams)))
+        goto err;
+
+    mdsize = 0;
+    if (!TEST_true(EVP_PKEY_CTX_get_params(ctx, ourparams))
+            || !TEST_size_t_eq(mdsize, SHA512_DIGEST_LENGTH))
+        goto err;
+
+    /*
+     * Test the TEST_PKEY_CTX_set_signature_md() and
+     * TEST_PKEY_CTX_get_signature_md() functions
+     */
+    if (!TEST_int_gt(EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()), 0)
+            || !TEST_int_gt(EVP_PKEY_CTX_get_signature_md(ctx, &md), 0)
+            || !TEST_ptr_eq(md, EVP_sha256()))
+        goto err;
+
+    ret = 1;
+
+ err:
+    EVP_PKEY_CTX_free(ctx);
+    EVP_SIGNATURE_free(dsaimpl);
+    EVP_PKEY_free(pkey);
+    DSA_free(dsa);
+    BN_free(p);
+    BN_free(q);
+    BN_free(g);
+
+    return ret;
+}
+
 int setup_tests(void)
 {
     ADD_TEST(test_EVP_DigestSignInit);
@@ -1429,5 +1542,6 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_EVP_MD_fetch, 5);
     ADD_ALL_TESTS(test_EVP_CIPHER_fetch, 5);
 #endif
+    ADD_TEST(test_EVP_PKEY_CTX_get_set_params);
     return 1;
 }
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 442a6bb02f..e5c869af44 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4740,3 +4740,15 @@ EVP_KDF_gettable_params                 4856	3_0_0	EXIST::FUNCTION:
 EVP_KDF_CTX_gettable_params             4857	3_0_0	EXIST::FUNCTION:
 EVP_KDF_CTX_settable_params             4858	3_0_0	EXIST::FUNCTION:
 EVP_KDF_do_all_ex                       4859	3_0_0	EXIST::FUNCTION:
+EVP_SIGNATURE_free                      4860	3_0_0	EXIST::FUNCTION:
+EVP_SIGNATURE_up_ref                    4861	3_0_0	EXIST::FUNCTION:
+EVP_SIGNATURE_provider                  4862	3_0_0	EXIST::FUNCTION:
+EVP_SIGNATURE_fetch                     4863	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_sign_init_ex                   4864	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_CTX_set_signature_md           4865	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_verify_init_ex                 4866	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_verify_recover_init_ex         4867	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_CTX_get_signature_md           4868	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_CTX_get_params                 4869	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_CTX_gettable_params            4870	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_CTX_settable_params            4871	3_0_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list