[openssl] master update

Matt Caswell matt at openssl.org
Thu Nov 14 09:35:41 UTC 2019


The branch master has been updated
       via  d8fef6da579c23956c57b03488cb8702cd6d2066 (commit)
       via  c68f5050dbc1dc043accb4e28e3aaf4d5cfd1c65 (commit)
       via  11d876df50d90ec4b26364c4b7d317ea19139e13 (commit)
       via  89abd1b6f42ab93402a36db0f16f12dc7a392354 (commit)
       via  081d08fa58e300142f08ee670d63c84333a47cb0 (commit)
       via  2c938e2ee8b420e3a1260a2446f3f820f01e71d5 (commit)
       via  46ef075a99b3ea8e8bd5641405f745c43fdaefb2 (commit)
       via  b3f3ba7011c9afa3ac3b5ebf0c7462fb6ddee2cd (commit)
      from  10e7216e502916f8e7917ac4f21411fffd1fb882 (commit)


- Log -----------------------------------------------------------------
commit d8fef6da579c23956c57b03488cb8702cd6d2066
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 6 13:39:21 2019 +0000

    Document various new/changes EVP_PKEY_CTX_* functions
    
    We have converted a number of macros to functions and made them work
    with providers. We've also added some *_ex() variants that needed
    documenting.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit c68f5050dbc1dc043accb4e28e3aaf4d5cfd1c65
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 6 11:03:12 2019 +0000

    Document the public EVP_ASYM_CIPHER releated functions
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit 11d876df50d90ec4b26364c4b7d317ea19139e13
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Oct 29 09:24:24 2019 +0000

    Add documentation for the Asymmetric Cipher Operation
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit 89abd1b6f42ab93402a36db0f16f12dc7a392354
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 28 13:40:39 2019 +0000

    Move RSA Asym cipher code to the default provider
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit 081d08fa58e300142f08ee670d63c84333a47cb0
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 28 14:43:42 2019 +0000

    Increase OSSL_PARAM_BLD_MAX for multi-prime RSA
    
    The old value of 10 for OSSL_PARAM_BLD_MAX is insufficient for multi-prime
    RSA. That code has this assert:
    
            if (!ossl_assert(/* n, e */ 2 + /* d */ 1 + /* numprimes */ 1
                             + numprimes + numexps + numcoeffs
                             <= OSSL_PARAM_BLD_MAX))
                goto err;
    
    So we increase OSSL_PARAM_BLD_MAX which would be enough for 7 primes
    (more than you would ever reasonably want).
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit 2c938e2ee8b420e3a1260a2446f3f820f01e71d5
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Oct 1 09:40:57 2019 +0100

    Implement provider support for Asym Ciphers
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit 46ef075a99b3ea8e8bd5641405f745c43fdaefb2
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 17 17:19:21 2019 +0100

    Allow strings in params to be of zero length
    
    Sometimes it is useful to be able to pass NULL/zero length strings
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

commit b3f3ba7011c9afa3ac3b5ebf0c7462fb6ddee2cd
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 11 17:42:19 2019 +0100

    Allow setting a NULL pointer in a params structure
    
    Sometimes it is valid to send a NULL pointer in params.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10152)

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

Summary of changes:
 crypto/err/openssl.txt                             |   1 +
 crypto/evp/evp_local.h                             |  19 +
 crypto/evp/pmeth_fn.c                              | 381 ++++++++++++++++++--
 crypto/evp/pmeth_lib.c                             | 129 ++++++-
 crypto/params.c                                    |  10 +-
 crypto/rsa/rsa_ameth.c                             |   5 +-
 crypto/rsa/rsa_lib.c                               | 393 ++++++++++++++++++++-
 doc/man3/EVP_ASYM_CIPHER_free.pod                  |  88 +++++
 doc/man3/EVP_PKEY_CTX_ctrl.pod                     | 102 ++++--
 doc/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod    |   8 +-
 doc/man7/provider-asymcipher.pod                   | 242 +++++++++++++
 include/crypto/evp.h                               |   9 +
 include/internal/param_build.h                     |   2 +-
 include/openssl/core_names.h                       |  11 +-
 include/openssl/core_numbers.h                     |  42 ++-
 include/openssl/evp.h                              |  15 +
 include/openssl/rsa.h                              |  46 +--
 include/openssl/types.h                            |   2 +
 providers/common/include/prov/providercommonerr.h  |   1 +
 providers/common/provider_err.c                    |   1 +
 providers/defltprov.c                              |   6 +
 providers/implementations/asymciphers/build.info   |   4 +
 providers/implementations/asymciphers/rsa_enc.c    | 391 ++++++++++++++++++++
 providers/implementations/build.info               |   2 +-
 .../implementations/include/prov/implementations.h |   3 +
 util/libcrypto.num                                 |  20 ++
 26 files changed, 1828 insertions(+), 105 deletions(-)
 create mode 100644 doc/man3/EVP_ASYM_CIPHER_free.pod
 create mode 100644 doc/man7/provider-asymcipher.pod
 create mode 100644 providers/implementations/asymciphers/build.info
 create mode 100644 providers/implementations/asymciphers/rsa_enc.c

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index f3fb8a55d9..9c0f94413a 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2695,6 +2695,7 @@ PROV_R_INVALID_DIGEST:122:invalid digest
 PROV_R_INVALID_ITERATION_COUNT:123:invalid iteration count
 PROV_R_INVALID_IVLEN:116:invalid ivlen
 PROV_R_INVALID_IV_LENGTH:109:invalid iv length
+PROV_R_INVALID_KEY:158:invalid key
 PROV_R_INVALID_KEYLEN:117:invalid keylen
 PROV_R_INVALID_KEY_LEN:124:invalid key len
 PROV_R_INVALID_KEY_LENGTH:105:invalid key length
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index 803f7863a3..e229cf2971 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -143,6 +143,25 @@ struct evp_signature_st {
     OSSL_OP_signature_settable_ctx_md_params_fn *settable_ctx_md_params;
 } /* EVP_SIGNATURE */;
 
+struct evp_asym_cipher_st {
+    int name_id;
+    OSSL_PROVIDER *prov;
+    CRYPTO_REF_COUNT refcnt;
+    CRYPTO_RWLOCK *lock;
+
+    OSSL_OP_asym_cipher_newctx_fn *newctx;
+    OSSL_OP_asym_cipher_encrypt_init_fn *encrypt_init;
+    OSSL_OP_asym_cipher_encrypt_fn *encrypt;
+    OSSL_OP_asym_cipher_decrypt_init_fn *decrypt_init;
+    OSSL_OP_asym_cipher_decrypt_fn *decrypt;
+    OSSL_OP_asym_cipher_freectx_fn *freectx;
+    OSSL_OP_asym_cipher_dupctx_fn *dupctx;
+    OSSL_OP_asym_cipher_get_ctx_params_fn *get_ctx_params;
+    OSSL_OP_asym_cipher_gettable_ctx_params_fn *gettable_ctx_params;
+    OSSL_OP_asym_cipher_set_ctx_params_fn *set_ctx_params;
+    OSSL_OP_asym_cipher_settable_ctx_params_fn *settable_ctx_params;
+} /* EVP_ASYM_CIPHER */;
+
 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,
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index d49d80bffe..1115e18ba2 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -563,70 +563,391 @@ int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
         return ctx->pmeth->verify_recover(ctx, rout, routlen, sig, siglen);
 }
 
-int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx)
+static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
-        EVPerr(EVP_F_EVP_PKEY_ENCRYPT_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    int ret = 0;
+    void *provkey = NULL;
+    EVP_ASYM_CIPHER *cipher = NULL;
+
+    if (ctx == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
         return -2;
     }
-    ctx->operation = EVP_PKEY_OP_ENCRYPT;
-    if (!ctx->pmeth->encrypt_init)
-        return 1;
-    ret = ctx->pmeth->encrypt_init(ctx);
+
+    evp_pkey_ctx_free_old_ops(ctx);
+    ctx->operation = operation;
+
+    if (ctx->algorithm == NULL || ctx->engine != NULL)
+        goto legacy;
+
+    /*
+     * Because we cleared out old ops, we shouldn't need to worry about
+     * checking if exchange is already there.  Keymgmt is a different
+     * matter, as it isn't tied to a specific EVP_PKEY op.
+     */
+    cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, ctx->algorithm, ctx->propquery);
+    if (cipher != NULL && ctx->keymgmt == NULL) {
+        int name_id = EVP_ASYM_CIPHER_number(cipher);
+
+        ctx->keymgmt =
+            evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery);
+    }
+
+    if (ctx->keymgmt == NULL
+        || cipher == NULL
+        || (EVP_KEYMGMT_provider(ctx->keymgmt)
+            != EVP_ASYM_CIPHER_provider(cipher))) {
+        /*
+         * We don't have the full support we need with provided methods,
+         * let's go see if legacy does.  Also, we don't need to free
+         * ctx->keymgmt here, as it's not necessarily tied to this
+         * operation.  It will be freed by EVP_PKEY_CTX_free().
+         */
+        EVP_ASYM_CIPHER_free(cipher);
+        goto legacy;
+    }
+
+    ctx->op.ciph.cipher = cipher;
+
+    if (ctx->pkey != NULL) {
+        provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
+        if (provkey == NULL) {
+            EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+            goto err;
+        }
+    }
+    ctx->op.ciph.ciphprovctx = cipher->newctx(ossl_provider_ctx(cipher->prov));
+    if (ctx->op.ciph.ciphprovctx == NULL) {
+        /* The provider key can stay in the cache */
+        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
+
+    switch (operation) {
+    case EVP_PKEY_OP_ENCRYPT:
+        if (cipher->encrypt_init == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = cipher->encrypt_init(ctx->op.ciph.ciphprovctx, provkey);
+        break;
+    case EVP_PKEY_OP_DECRYPT:
+        if (cipher->decrypt_init == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            ret = -2;
+            goto err;
+        }
+        ret = cipher->decrypt_init(ctx->op.ciph.ciphprovctx, provkey);
+        break;
+    default:
+        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+        goto err;
+    }
+
+    if (ret <= 0) {
+        cipher->freectx(ctx->op.ciph.ciphprovctx);
+        ctx->op.ciph.ciphprovctx = NULL;
+        goto err;
+    }
+    return 1;
+
+ legacy:
+    if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) {
+        EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+    switch(ctx->operation) {
+    case EVP_PKEY_OP_ENCRYPT:
+        if (ctx->pmeth->encrypt_init == NULL)
+            return 1;
+        ret = ctx->pmeth->encrypt_init(ctx);
+        break;
+    case EVP_PKEY_OP_DECRYPT:
+        if (ctx->pmeth->decrypt_init == NULL)
+            return 1;
+        ret = ctx->pmeth->decrypt_init(ctx);
+        break;
+    default:
+        EVPerr(0, EVP_R_INITIALIZATION_ERROR);
+        ret = -1;
+    }
+
+ err:
     if (ret <= 0)
         ctx->operation = EVP_PKEY_OP_UNDEFINED;
     return ret;
 }
 
+int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx)
+{
+    return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_ENCRYPT);
+}
+
 int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,
                      unsigned char *out, size_t *outlen,
                      const unsigned char *in, size_t inlen)
 {
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
-        EVPerr(EVP_F_EVP_PKEY_ENCRYPT,
-               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_ENCRYPT) {
-        EVPerr(EVP_F_EVP_PKEY_ENCRYPT, EVP_R_OPERATON_NOT_INITIALIZED);
+        EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
+
+    if (ctx->op.ciph.ciphprovctx == NULL)
+        goto legacy;
+
+    ret = ctx->op.ciph.cipher->encrypt(ctx->op.ciph.ciphprovctx, out, outlen,
+                                       (out == NULL ? 0 : *outlen), in, inlen);
+    return ret;
+
+ legacy:
+    if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) {
+        EVPerr(EVP_F_EVP_PKEY_ENCRYPT,
+               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
     M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_ENCRYPT)
         return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
 }
 
 int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
-        EVPerr(EVP_F_EVP_PKEY_DECRYPT_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
-    ctx->operation = EVP_PKEY_OP_DECRYPT;
-    if (!ctx->pmeth->decrypt_init)
-        return 1;
-    ret = ctx->pmeth->decrypt_init(ctx);
-    if (ret <= 0)
-        ctx->operation = EVP_PKEY_OP_UNDEFINED;
-    return ret;
+    return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_DECRYPT);
 }
 
 int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
                      unsigned char *out, size_t *outlen,
                      const unsigned char *in, size_t inlen)
 {
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
-        EVPerr(EVP_F_EVP_PKEY_DECRYPT,
-               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_DECRYPT) {
-        EVPerr(EVP_F_EVP_PKEY_DECRYPT, EVP_R_OPERATON_NOT_INITIALIZED);
+        EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
+
+    if (ctx->op.ciph.ciphprovctx == NULL)
+        goto legacy;
+
+    ret = ctx->op.ciph.cipher->decrypt(ctx->op.ciph.ciphprovctx, out, outlen,
+                                       (out == NULL ? 0 : *outlen), in, inlen);
+    return ret;
+
+ legacy:
+    if (ctx->pmeth == NULL || ctx->pmeth->decrypt == NULL) {
+        EVPerr(EVP_F_EVP_PKEY_DECRYPT,
+               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
     M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_DECRYPT)
         return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
 }
+
+
+static EVP_ASYM_CIPHER *evp_asym_cipher_new(OSSL_PROVIDER *prov)
+{
+    EVP_ASYM_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_ASYM_CIPHER));
+
+    cipher->lock = CRYPTO_THREAD_lock_new();
+    if (cipher->lock == NULL) {
+        OPENSSL_free(cipher);
+        return NULL;
+    }
+    cipher->prov = prov;
+    ossl_provider_up_ref(prov);
+    cipher->refcnt = 1;
+
+    return cipher;
+}
+
+static void *evp_asym_cipher_from_dispatch(int name_id,
+                                           const OSSL_DISPATCH *fns,
+                                           OSSL_PROVIDER *prov)
+{
+    EVP_ASYM_CIPHER *cipher = NULL;
+    int ctxfncnt = 0, encfncnt = 0, decfncnt = 0;
+    int gparamfncnt = 0, sparamfncnt = 0;
+
+    if ((cipher = evp_asym_cipher_new(prov)) == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    cipher->name_id = name_id;
+
+    for (; fns->function_id != 0; fns++) {
+        switch (fns->function_id) {
+        case OSSL_FUNC_ASYM_CIPHER_NEWCTX:
+            if (cipher->newctx != NULL)
+                break;
+            cipher->newctx = OSSL_get_OP_asym_cipher_newctx(fns);
+            ctxfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT:
+            if (cipher->encrypt_init != NULL)
+                break;
+            cipher->encrypt_init = OSSL_get_OP_asym_cipher_encrypt_init(fns);
+            encfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_ENCRYPT:
+            if (cipher->encrypt != NULL)
+                break;
+            cipher->encrypt = OSSL_get_OP_asym_cipher_encrypt(fns);
+            encfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT:
+            if (cipher->decrypt_init != NULL)
+                break;
+            cipher->decrypt_init = OSSL_get_OP_asym_cipher_decrypt_init(fns);
+            decfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_DECRYPT:
+            if (cipher->decrypt != NULL)
+                break;
+            cipher->decrypt = OSSL_get_OP_asym_cipher_decrypt(fns);
+            decfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_FREECTX:
+            if (cipher->freectx != NULL)
+                break;
+            cipher->freectx = OSSL_get_OP_asym_cipher_freectx(fns);
+            ctxfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_DUPCTX:
+            if (cipher->dupctx != NULL)
+                break;
+            cipher->dupctx = OSSL_get_OP_asym_cipher_dupctx(fns);
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS:
+            if (cipher->get_ctx_params != NULL)
+                break;
+            cipher->get_ctx_params
+                = OSSL_get_OP_asym_cipher_get_ctx_params(fns);
+            gparamfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS:
+            if (cipher->gettable_ctx_params != NULL)
+                break;
+            cipher->gettable_ctx_params
+                = OSSL_get_OP_asym_cipher_gettable_ctx_params(fns);
+            gparamfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS:
+            if (cipher->set_ctx_params != NULL)
+                break;
+            cipher->set_ctx_params
+                = OSSL_get_OP_asym_cipher_set_ctx_params(fns);
+            sparamfncnt++;
+            break;
+        case OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS:
+            if (cipher->settable_ctx_params != NULL)
+                break;
+            cipher->settable_ctx_params
+                = OSSL_get_OP_asym_cipher_settable_ctx_params(fns);
+            sparamfncnt++;
+            break;
+        }
+    }
+    if (ctxfncnt != 2
+        || (encfncnt != 0 && encfncnt != 2)
+        || (decfncnt != 0 && decfncnt != 2)
+        || (encfncnt != 2 && decfncnt != 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
+         * "cipher" functions: (encrypt_init, encrypt) or
+         * (decrypt_init decrypt). 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 cipher;
+ err:
+    EVP_ASYM_CIPHER_free(cipher);
+    return NULL;
+}
+
+void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher)
+{
+    if (cipher != NULL) {
+        int i;
+
+        CRYPTO_DOWN_REF(&cipher->refcnt, &i, cipher->lock);
+        if (i > 0)
+            return;
+        ossl_provider_free(cipher->prov);
+        CRYPTO_THREAD_lock_free(cipher->lock);
+        OPENSSL_free(cipher);
+    }
+}
+
+int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&cipher->refcnt, &ref, cipher->lock);
+    return 1;
+}
+
+OSSL_PROVIDER *EVP_ASYM_CIPHER_provider(const EVP_ASYM_CIPHER *cipher)
+{
+    return cipher->prov;
+}
+
+EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                       const char *properties)
+{
+    return evp_generic_fetch(ctx, OSSL_OP_ASYM_CIPHER, algorithm, properties,
+                             evp_asym_cipher_from_dispatch,
+                             (int (*)(void *))EVP_ASYM_CIPHER_up_ref,
+                             (void (*)(void *))EVP_ASYM_CIPHER_free);
+}
+
+int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name)
+{
+    return evp_is_a(cipher->prov, cipher->name_id, name);
+}
+
+int EVP_ASYM_CIPHER_number(const EVP_ASYM_CIPHER *cipher)
+{
+    return cipher->name_id;
+}
+
+void EVP_ASYM_CIPHER_do_all_provided(OPENSSL_CTX *libctx,
+                                     void (*fn)(EVP_ASYM_CIPHER *cipher,
+                                                void *arg),
+                                     void *arg)
+{
+    evp_generic_do_all(libctx, OSSL_OP_ASYM_CIPHER,
+                       (void (*)(void *, void *))fn, arg,
+                       evp_asym_cipher_from_dispatch,
+                       (void (*)(void *))EVP_ASYM_CIPHER_free);
+}
+
+
+void EVP_ASYM_CIPHER_names_do_all(const EVP_ASYM_CIPHER *cipher,
+                                  void (*fn)(const char *name, void *data),
+                                  void *data)
+{
+    if (cipher->prov != NULL)
+        evp_names_do_all(cipher->prov, cipher->name_id, fn, data);
+}
+
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 30cff95077..ce1b051b74 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -15,6 +15,7 @@
 #include <openssl/x509v3.h>
 #include <openssl/core_names.h>
 #include <openssl/dh.h>
+#include <openssl/rsa.h>
 #include "internal/cryptlib.h"
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
@@ -237,6 +238,12 @@ void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx)
         EVP_SIGNATURE_free(ctx->op.sig.signature);
         ctx->op.sig.sigprovctx = NULL;
         ctx->op.sig.signature = NULL;
+    } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        if (ctx->op.ciph.ciphprovctx != NULL && ctx->op.ciph.cipher != NULL)
+            ctx->op.ciph.cipher->freectx(ctx->op.ciph.ciphprovctx);
+        EVP_ASYM_CIPHER_free(ctx->op.ciph.cipher);
+        ctx->op.ciph.ciphprovctx = NULL;
+        ctx->op.ciph.cipher = NULL;
     }
 }
 
@@ -401,6 +408,26 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx)
             }
             return rctx;
         }
+    } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(pctx)) {
+        if (pctx->op.ciph.cipher != NULL) {
+            rctx->op.ciph.cipher = pctx->op.ciph.cipher;
+            if (!EVP_ASYM_CIPHER_up_ref(rctx->op.ciph.cipher)) {
+                OPENSSL_free(rctx);
+                return NULL;
+            }
+        }
+        if (pctx->op.ciph.ciphprovctx != NULL) {
+            if (!ossl_assert(pctx->op.ciph.cipher != NULL))
+                return NULL;
+            rctx->op.ciph.ciphprovctx
+                = pctx->op.ciph.cipher->dupctx(pctx->op.ciph.ciphprovctx);
+            if (rctx->op.ciph.ciphprovctx == NULL) {
+                EVP_ASYM_CIPHER_free(rctx->op.ciph.cipher);
+                OPENSSL_free(rctx);
+                return NULL;
+            }
+            return rctx;
+        }
     }
 
     rctx->pmeth = pctx->pmeth;
@@ -500,6 +527,12 @@ int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
             && ctx->op.sig.signature->get_ctx_params != NULL)
         return ctx->op.sig.signature->get_ctx_params(ctx->op.sig.sigprovctx,
                                                      params);
+    if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+            && ctx->op.ciph.ciphprovctx != NULL
+            && ctx->op.ciph.cipher != NULL
+            && ctx->op.ciph.cipher->get_ctx_params != NULL)
+        return ctx->op.ciph.cipher->get_ctx_params(ctx->op.ciph.ciphprovctx,
+                                                   params);
     return 0;
 }
 
@@ -510,6 +543,11 @@ const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx)
             && ctx->op.sig.signature->gettable_ctx_params != NULL)
         return ctx->op.sig.signature->gettable_ctx_params();
 
+    if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+            && ctx->op.ciph.cipher != NULL
+            && ctx->op.ciph.cipher->gettable_ctx_params != NULL)
+        return ctx->op.ciph.cipher->gettable_ctx_params();
+
     return NULL;
 }
 
@@ -527,6 +565,12 @@ int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
             && ctx->op.sig.signature->set_ctx_params != NULL)
         return ctx->op.sig.signature->set_ctx_params(ctx->op.sig.sigprovctx,
                                                      params);
+    if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+            && ctx->op.ciph.ciphprovctx != NULL
+            && ctx->op.ciph.cipher != NULL
+            && ctx->op.ciph.cipher->set_ctx_params != NULL)
+        return ctx->op.ciph.cipher->set_ctx_params(ctx->op.ciph.ciphprovctx,
+                                                     params);
     return 0;
 }
 
@@ -540,6 +584,10 @@ const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx)
             && ctx->op.sig.signature != NULL
             && ctx->op.sig.signature->settable_ctx_params != NULL)
         return ctx->op.sig.signature->settable_ctx_params();
+    if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+            && ctx->op.ciph.cipher != NULL
+            && ctx->op.ciph.cipher->settable_ctx_params != NULL)
+        return ctx->op.ciph.cipher->settable_ctx_params();
 
     return NULL;
 }
@@ -654,6 +702,33 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
         return EVP_PKEY_CTX_set_signature_md(ctx, p2);
     case EVP_PKEY_CTRL_GET_MD:
         return EVP_PKEY_CTX_get_signature_md(ctx, p2);
+    case EVP_PKEY_CTRL_RSA_PADDING:
+        return EVP_PKEY_CTX_set_rsa_padding(ctx, p1);
+    case EVP_PKEY_CTRL_GET_RSA_PADDING:
+        return EVP_PKEY_CTX_get_rsa_padding(ctx, p2);
+    case EVP_PKEY_CTRL_RSA_OAEP_MD:
+        return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, p2);
+    case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
+        return EVP_PKEY_CTX_get_rsa_oaep_md(ctx, p2);
+    case EVP_PKEY_CTRL_RSA_MGF1_MD:
+        return EVP_PKEY_CTX_set_rsa_oaep_md(ctx, p2);
+    case EVP_PKEY_CTRL_GET_RSA_MGF1_MD:
+        return EVP_PKEY_CTX_get_rsa_oaep_md(ctx, p2);
+    case EVP_PKEY_CTRL_RSA_OAEP_LABEL:
+        return EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, p2, p1);
+    case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
+        return EVP_PKEY_CTX_get0_rsa_oaep_label(ctx, (unsigned char **)p2);
+    case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
+    case EVP_PKEY_CTRL_PKCS7_DECRYPT:
+#ifndef OPENSSL_NO_CMS
+    case EVP_PKEY_CTRL_CMS_DECRYPT:
+    case EVP_PKEY_CTRL_CMS_ENCRYPT:
+#endif
+        if (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+            return 1;
+        ERR_raise(ERR_LIB_EVP,
+                  EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
     }
     return 0;
 }
@@ -670,7 +745,9 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
 
     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))
+                && ctx->op.sig.sigprovctx != NULL)
+            || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && ctx->op.ciph.ciphprovctx != NULL))
         return legacy_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2);
 
     if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) {
@@ -735,6 +812,52 @@ static int legacy_ctrl_str_to_param(EVP_PKEY_CTX *ctx, const char *name,
         return ret;
     }
 
+    if (strcmp(name, "rsa_padding_mode") == 0) {
+        int pm;
+
+        if (strcmp(value, "pkcs1") == 0) {
+            pm = RSA_PKCS1_PADDING;
+        } else if (strcmp(value, "sslv23") == 0) {
+            pm = RSA_SSLV23_PADDING;
+        } else if (strcmp(value, "none") == 0) {
+            pm = RSA_NO_PADDING;
+        } else if (strcmp(value, "oeap") == 0) {
+            pm = RSA_PKCS1_OAEP_PADDING;
+        } else if (strcmp(value, "oaep") == 0) {
+            pm = RSA_PKCS1_OAEP_PADDING;
+        } else if (strcmp(value, "x931") == 0) {
+            pm = RSA_X931_PADDING;
+        } else if (strcmp(value, "pss") == 0) {
+            pm = RSA_PKCS1_PSS_PADDING;
+        } else {
+            ERR_raise(ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE);
+            return -2;
+        }
+        return EVP_PKEY_CTX_set_rsa_padding(ctx, pm);
+    }
+
+    if (strcmp(name, "rsa_mgf1_md") == 0)
+        return EVP_PKEY_CTX_set_rsa_mgf1_md_name(ctx, value, NULL);
+
+    if (strcmp(name, "rsa_oaep_md") == 0)
+        return EVP_PKEY_CTX_set_rsa_oaep_md_name(ctx, value, NULL);
+
+    if (strcmp(name, "rsa_oaep_label") == 0) {
+        unsigned char *lab;
+        long lablen;
+        int ret;
+
+        lab = OPENSSL_hexstr2buf(value, &lablen);
+        if (lab == NULL)
+            return 0;
+        ret = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, lab, lablen);
+        if (ret <= 0)
+            OPENSSL_free(lab);
+        return ret;
+    }
+
+
+
     return 0;
 }
 
@@ -748,7 +871,9 @@ int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx,
 
     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))
+                && ctx->op.sig.sigprovctx != NULL)
+            || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && ctx->op.ciph.ciphprovctx != NULL))
         return legacy_ctrl_str_to_param(ctx, name, value);
 
     if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) {
diff --git a/crypto/params.c b/crypto/params.c
index 0cd13e3b81..5d1fc6a6f2 100644
--- a/crypto/params.c
+++ b/crypto/params.c
@@ -776,6 +776,9 @@ static int get_string_internal(const OSSL_PARAM *p, void **val, size_t max_len,
     if (used_len != NULL)
         *used_len = sz;
 
+    if (sz == 0)
+        return 1;
+
     if (*val == NULL) {
         char *const q = OPENSSL_malloc(sz);
 
@@ -892,9 +895,8 @@ int OSSL_PARAM_set_utf8_ptr(OSSL_PARAM *p, const char *val)
     if (p == NULL)
         return 0;
     p->return_size = 0;
-    if (val == NULL)
-        return 0;
-    return set_ptr_internal(p, val, OSSL_PARAM_UTF8_PTR, strlen(val) + 1);
+    return set_ptr_internal(p, val, OSSL_PARAM_UTF8_PTR,
+                            val == NULL ? 0 : strlen(val) + 1);
 }
 
 int OSSL_PARAM_set_octet_ptr(OSSL_PARAM *p, const void *val,
@@ -903,8 +905,6 @@ int OSSL_PARAM_set_octet_ptr(OSSL_PARAM *p, const void *val,
     if (p == NULL)
         return 0;
     p->return_size = 0;
-    if (val == NULL)
-        return 0;
     return set_ptr_internal(p, val, OSSL_PARAM_OCTET_PTR, used_len);
 }
 
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index d2f976f681..ade3fe2578 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -1096,10 +1096,7 @@ static void *rsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
         if (numprimes < 2 || numexps < 2 || numcoeffs < 1)
             goto err;
 
-        /*
-         * assert that an OSSL_PARAM_BLD has enough space.
-         * (the current 10 places doesn't have space for multi-primes)
-         */
+        /* assert that an OSSL_PARAM_BLD has enough space. */
         if (!ossl_assert(/* n, e */ 2 + /* d */ 1 + /* numprimes */ 1
                          + numprimes + numexps + numcoeffs
                          <= OSSL_PARAM_BLD_MAX))
diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c
index 353b9d8725..71e4b78306 100644
--- a/crypto/rsa/rsa_lib.c
+++ b/crypto/rsa/rsa_lib.c
@@ -9,11 +9,12 @@
 
 #include <stdio.h>
 #include <openssl/crypto.h>
+#include <openssl/core_names.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
 #include "internal/cryptlib.h"
 #include "internal/refcount.h"
 #include "crypto/bn.h"
-#include <openssl/engine.h>
-#include <openssl/evp.h>
 #include "crypto/evp.h"
 #include "crypto/rsa.h"
 #include "rsa_local.h"
@@ -733,3 +734,391 @@ int rsa_get0_all_params(RSA *r, STACK_OF(BIGNUM_const) *primes,
 
     return 1;
 }
+
+int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad_mode)
+{
+    OSSL_PARAM pad_params[2], *p = pad_params;
+
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA or RSA-PSS return error */
+    if (ctx->pmeth != NULL
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+            || ctx->op.ciph.ciphprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_RSA_PADDING,
+                                 pad_mode, NULL);
+
+    *p++ = OSSL_PARAM_construct_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, &pad_mode);
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, pad_params);
+}
+
+int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *pad_mode)
+{
+    OSSL_PARAM pad_params[2], *p = pad_params;
+
+    if (ctx == NULL || pad_mode == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA or RSA-PSS return error */
+    if (ctx->pmeth != NULL
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+            || ctx->op.ciph.ciphprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0,
+                                 pad_mode);
+
+    *p++ = OSSL_PARAM_construct_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, pad_mode);
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_PKEY_CTX_get_params(ctx, pad_params))
+        return 0;
+
+    return 1;
+
+}
+
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
+{
+    const char *name;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.ciph.ciphprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                                 EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md);
+
+    name = (md == NULL) ? "" : EVP_MD_name(md);
+
+    return EVP_PKEY_CTX_set_rsa_oaep_md_name(ctx, name, NULL);
+}
+
+int EVP_PKEY_CTX_set_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
+                                      const char *mdprops)
+{
+    OSSL_PARAM rsa_params[3], *p = rsa_params;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA)
+        return -1;
+
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (char *)mdname,
+                                            strlen(mdname) + 1);
+    if (mdprops != NULL) {
+        *p++ = OSSL_PARAM_construct_utf8_string(
+                    OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS,
+                    /*
+                     * Cast away the const. This is read
+                     * only so should be safe
+                     */
+                    (char *)mdprops,
+                    strlen(mdprops) + 1);
+    }
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, rsa_params);
+}
+
+int EVP_PKEY_CTX_get_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, char *name,
+                                      size_t namelen)
+{
+    OSSL_PARAM rsa_params[2], *p = rsa_params;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA)
+        return -1;
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST,
+                                            name, namelen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_PKEY_CTX_get_params(ctx, rsa_params))
+        return -1;
+
+    return 1;
+}
+
+int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **md)
+{
+    /* 80 should be big enough */
+    char name[80] = "";
+
+    if (ctx == NULL || md == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.ciph.ciphprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                                 EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)md);
+
+    if (EVP_PKEY_CTX_get_rsa_oaep_md_name(ctx, name, sizeof(name)) <= 0)
+        return -1;
+
+    /* May be NULL meaning "unknown" */
+    *md = EVP_get_digestbyname(name);
+
+    return 1;
+}
+
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
+{
+    const char *name;
+
+    if (ctx == NULL
+            || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && !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;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if ((EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && ctx->op.ciph.ciphprovctx == NULL)
+            || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+                && ctx->op.sig.sigprovctx == NULL))
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+                                 EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+                                 EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)md);
+
+    name = (md == NULL) ? "" : EVP_MD_name(md);
+
+    return EVP_PKEY_CTX_set_rsa_mgf1_md_name(ctx, name, NULL);
+}
+
+int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
+                                      const char *mdprops)
+{
+    OSSL_PARAM rsa_params[3], *p = rsa_params;
+
+    if (ctx == NULL
+            || mdname == NULL
+            || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && !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;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+        return -1;
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (char *)mdname,
+                                            strlen(mdname) + 1);
+    if (mdprops != NULL) {
+        *p++ = OSSL_PARAM_construct_utf8_string(
+                    OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS,
+                    /*
+                     * Cast away the const. This is read
+                     * only so should be safe
+                     */
+                    (char *)mdprops,
+                    strlen(mdprops) + 1);
+    }
+    *p++ = OSSL_PARAM_construct_end();
+
+    return EVP_PKEY_CTX_set_params(ctx, rsa_params);
+}
+
+int EVP_PKEY_CTX_get_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, char *name,
+                                      size_t namelen)
+{
+    OSSL_PARAM rsa_params[2], *p = rsa_params;
+
+    if (ctx == NULL
+            || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && !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;
+    }
+
+    /* If key type not RSA or RSA-PSS return error */
+    if (ctx->pmeth != NULL
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+        return -1;
+
+    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST,
+                                            name, namelen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_PKEY_CTX_get_params(ctx, rsa_params))
+        return -1;
+
+    return 1;
+}
+
+int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md)
+{
+    /* 80 should be big enough */
+    char name[80] = "";
+
+    if (ctx == NULL
+            || (!EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && !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;
+    }
+
+    /* If key type not RSA or RSA-PSS return error */
+    if (ctx->pmeth != NULL
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA
+            && ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if ((EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
+                && ctx->op.ciph.ciphprovctx == NULL)
+            || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
+                && ctx->op.sig.sigprovctx == NULL))
+        return EVP_PKEY_CTX_ctrl(ctx, -1,
+                                 EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+                                 EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)md);
+
+    if (EVP_PKEY_CTX_get_rsa_mgf1_md_name(ctx, name, sizeof(name)) <= 0)
+        return -1;
+
+    /* May be NULL meaning "unknown" */
+    *md = EVP_get_digestbyname(name);
+
+    return 1;
+}
+
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, int llen)
+{
+    OSSL_PARAM rsa_params[2], *p = rsa_params;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.ciph.ciphprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                                 EVP_PKEY_CTRL_RSA_OAEP_LABEL, llen,
+                                 (void *)label);
+
+    *p++ = OSSL_PARAM_construct_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL,
+                                            /*
+                                             * Cast away the const. This is read
+                                             * only so should be safe
+                                             */
+                                            (void *)label,
+                                            (size_t)llen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_PKEY_CTX_set_params(ctx, rsa_params))
+        return 0;
+
+    OPENSSL_free(label);
+    return 1;
+}
+
+int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char **label)
+{
+    OSSL_PARAM rsa_params[3], *p = rsa_params;
+    size_t labellen;
+
+    if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
+        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
+        return -2;
+    }
+
+    /* If key type not RSA return error */
+    if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_RSA)
+        return -1;
+
+    /* TODO(3.0): Remove this eventually when no more legacy */
+    if (ctx->op.ciph.ciphprovctx == NULL)
+        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+                                 EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0,
+                                 (void *)label);
+
+    *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL,
+                                          (void **)label, 0);
+    *p++ = OSSL_PARAM_construct_size_t(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN,
+                                       &labellen);
+    *p++ = OSSL_PARAM_construct_end();
+
+    if (!EVP_PKEY_CTX_get_params(ctx, rsa_params))
+        return -1;
+
+    if (labellen > INT_MAX)
+        return -1;
+
+    return (int)labellen;
+}
diff --git a/doc/man3/EVP_ASYM_CIPHER_free.pod b/doc/man3/EVP_ASYM_CIPHER_free.pod
new file mode 100644
index 0000000000..d7f9991c26
--- /dev/null
+++ b/doc/man3/EVP_ASYM_CIPHER_free.pod
@@ -0,0 +1,88 @@
+=pod
+
+=head1 NAME
+
+EVP_ASYM_CIPHER_fetch, EVP_ASYM_CIPHER_free, EVP_ASYM_CIPHER_up_ref,
+EVP_ASYM_CIPHER_number, EVP_ASYM_CIPHER_is_a, EVP_ASYM_CIPHER_provider,
+EVP_ASYM_CIPHER_do_all_provided, EVP_ASYM_CIPHER_names_do_all
+- Functions to manage EVP_ASYM_CIPHER algorithm objects
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                        const char *properties);
+ void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher);
+ int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher);
+ int EVP_ASYM_CIPHER_number(const EVP_ASYM_CIPHER *cipher);
+ int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name);
+ OSSL_PROVIDER *EVP_ASYM_CIPHER_provider(const EVP_ASYM_CIPHER *cipher);
+ void EVP_ASYM_CIPHER_do_all_provided(OPENSSL_CTX *libctx,
+                                      void (*fn)(EVP_ASYM_CIPHER *cipher,
+                                                 void *arg),
+                                      void *arg);
+ void EVP_ASYM_CIPHER_names_do_all(const EVP_ASYM_CIPHER *cipher,
+                                   void (*fn)(const char *name, void *data),
+                                   void *data);
+
+=head1 DESCRIPTION
+
+EVP_ASYM_CIPHER_fetch() fetches the implementation for the given
+B<algorithm> from any provider offering it, within the criteria given
+by the B<properties> and in the scope of the given library context B<ctx> (see
+L<OPENSSL_CTX(3)>). The algorithm will be one offering functions for performing
+asymmetric cipher related tasks such as asymmetric encryption and decryption.
+See L<provider(7)/Fetching algorithms> for further information.
+
+The returned value must eventually be freed with EVP_ASYM_CIPHER_free().
+
+EVP_ASYM_CIPHER_free() decrements the reference count for the B<EVP_ASYM_CIPHER>
+structure. Typically this structure will have been obtained from an earlier call
+to EVP_ASYM_CIPHER_fetch(). If the reference count drops to 0 then the
+structure is freed.
+
+EVP_ASYM_CIPHER_up_ref() increments the reference count for an
+B<EVP_ASYM_CIPHER> structure.
+
+EVP_ASYM_CIPHER_is_a() returns 1 if I<cipher> is an implementation of an
+algorithm that's identifiable with I<name>, otherwise 0.
+
+EVP_ASYM_CIPHER_provider() returns the provider that I<cipher> was fetched from.
+
+EVP_ASYM_CIPHER_do_all_provided() traverses all EVP_ASYM_CIPHERs implemented by
+all activated providers in the given library context I<libctx>, and for each of
+the implementations, calls the given function I<fn> with the implementation
+method and the given I<arg> as argument.
+
+EVP_ASYM_CIPHER_number() returns the internal dynamic number assigned to
+I<cipher>.
+
+EVP_ASYM_CIPHER_names_do_all() traverses all names for I<cipher>, and calls
+I<fn> with each name and I<data>.
+
+=head1 RETURN VALUES
+
+EVP_ASYM_CIPHER_fetch() returns a pointer to an B<EVP_ASYM_CIPHER> for success
+or B<NULL> for failure.
+
+EVP_ASYM_CIPHER_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/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index fe12b09043..06151d4a5c 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -20,10 +20,14 @@ EVP_PKEY_CTX_get_rsa_pss_saltlen,
 EVP_PKEY_CTX_set_rsa_keygen_bits,
 EVP_PKEY_CTX_set_rsa_keygen_pubexp,
 EVP_PKEY_CTX_set_rsa_keygen_primes,
+EVP_PKEY_CTX_set_rsa_mgf1_md_name,
 EVP_PKEY_CTX_set_rsa_mgf1_md,
 EVP_PKEY_CTX_get_rsa_mgf1_md,
+EVP_PKEY_CTX_get_rsa_mgf1_md_name,
+EVP_PKEY_CTX_set_rsa_oaep_md_name,
 EVP_PKEY_CTX_set_rsa_oaep_md,
 EVP_PKEY_CTX_get_rsa_oaep_md,
+EVP_PKEY_CTX_get_rsa_oaep_md_name,
 EVP_PKEY_CTX_set0_rsa_oaep_label,
 EVP_PKEY_CTX_get0_rsa_oaep_label,
 EVP_PKEY_CTX_set_dsa_paramgen_bits,
@@ -95,10 +99,18 @@ EVP_PKEY_CTX_set1_id, EVP_PKEY_CTX_get1_id, EVP_PKEY_CTX_get1_id_len
  int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int mbits);
  int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *pubexp);
  int EVP_PKEY_CTX_set_rsa_keygen_primes(EVP_PKEY_CTX *ctx, int primes);
+ int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
+                                     const char *mdprops);
  int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
  int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
+ int EVP_PKEY_CTX_get_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, char *name,
+                                       size_t namelen);
+ int EVP_PKEY_CTX_set_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
+                                       const char *mdprops);
  int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
  int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
+ int EVP_PKEY_CTX_get_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, char *name,
+                                       size_t namelen)
  int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char *label, int len);
  int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char **label);
 
@@ -241,7 +253,7 @@ supported by the L<EVP_PKEY_new_raw_private_key(3)> function.
 
 =head2 RSA parameters
 
-The EVP_PKEY_CTX_set_rsa_padding() macro sets the RSA padding mode for B<ctx>.
+The EVP_PKEY_CTX_set_rsa_padding() function sets the RSA padding mode for B<ctx>.
 The B<pad> parameter can take the value B<RSA_PKCS1_PADDING> for PKCS#1
 padding, B<RSA_SSLV23_PADDING> for SSLv23 padding, B<RSA_NO_PADDING> for
 no padding, B<RSA_PKCS1_OAEP_PADDING> for OAEP padding (encrypt and
@@ -258,7 +270,7 @@ padding for RSA the algorithm identifier byte is added or checked and removed
 if this control is called. If it is not called then the first byte of the plaintext
 buffer is expected to be the algorithm identifier byte.
 
-The EVP_PKEY_CTX_get_rsa_padding() macro gets the RSA padding mode for B<ctx>.
+The EVP_PKEY_CTX_get_rsa_padding() function gets the RSA padding mode for B<ctx>.
 
 The EVP_PKEY_CTX_set_rsa_pss_saltlen() macro sets the RSA PSS salt length to
 B<len>. As its name implies it is only supported for PSS padding. Three special
@@ -283,30 +295,59 @@ modified or freed after the call. If not specified 65537 is used.
 The EVP_PKEY_CTX_set_rsa_keygen_primes() macro sets the number of primes for
 RSA key generation to B<primes>. If not specified 2 is used.
 
-The EVP_PKEY_CTX_set_rsa_mgf1_md() macro sets the MGF1 digest for RSA padding
-schemes to B<md>. If not explicitly set the signing digest is used. The
-padding mode must have been set to B<RSA_PKCS1_OAEP_PADDING>
+The EVP_PKEY_CTX_set_rsa_mgf1_md_name() function sets the MGF1 digest for RSA
+padding schemes to the digest named B<mdname>. If the RSA algorithm
+implementation for the selected provider supports it then the digest will be
+fetched using the properties B<mdprops>. If not explicitly set the signing
+digest is used. The padding mode must have been set to B<RSA_PKCS1_OAEP_PADDING>
 or B<RSA_PKCS1_PSS_PADDING>.
 
-The EVP_PKEY_CTX_get_rsa_mgf1_md() macro gets the MGF1 digest for B<ctx>.
-If not explicitly set the signing digest is used. The padding mode must have
-been set to B<RSA_PKCS1_OAEP_PADDING> or B<RSA_PKCS1_PSS_PADDING>.
-
-The EVP_PKEY_CTX_set_rsa_oaep_md() macro sets the message digest type used
-in RSA OAEP to B<md>. The padding mode must have been set to
+The EVP_PKEY_CTX_set_rsa_mgf1_md() function does the same as
+EVP_PKEY_CTX_set_rsa_mgf1_md_name() except that the name of the digest is
+inferred from the supplied B<md> and it is not possible to specify any
+properties.
+
+The EVP_PKEY_CTX_get_rsa_mgf1_md_name() function gets the name of the MGF1
+digest algorithm for B<ctx>. If not explicitly set the signing digest is used.
+The padding mode must have been set to B<RSA_PKCS1_OAEP_PADDING> or
+B<RSA_PKCS1_PSS_PADDING>.
+
+The EVP_PKEY_CTX_get_rsa_mgf1_md() function does the same as
+EVP_PKEY_CTX_get_rsa_mgf1_md_name() except that it returns a pointer to an
+EVP_MD object instead. Note that only known, built-in EVP_MD objects will be
+returned. The EVP_MD object may be NULL if the digest is not one of these (such
+as a digest only implemented in a third party provider).
+
+The EVP_PKEY_CTX_set_rsa_oaep_md_name() function sets the message digest type
+used in RSA OAEP to the digest named B<mdname>.  If the RSA algorithm
+implementation for the selected provider supports it then the digest will be
+fetched using the properties B<mdprops>. The padding mode must have been set to
 B<RSA_PKCS1_OAEP_PADDING>.
 
-The EVP_PKEY_CTX_get_rsa_oaep_md() macro gets the message digest type used
-in RSA OAEP to B<md>. The padding mode must have been set to
-B<RSA_PKCS1_OAEP_PADDING>.
+The EVP_PKEY_CTX_set_rsa_oaep_md() function does the same as
+EVP_PKEY_CTX_set_rsa_oaep_md_name() except that the name of the digest is
+inferred from the supplied B<md> and it is not possible to specify any
+properties.
+
+The EVP_PKEY_CTX_get_rsa_oaep_md_name() function gets the message digest
+algorithm name used in RSA OAEP and stores it in the buffer B<name> which is of
+size B<namelen>. The padding mode must have been set to
+B<RSA_PKCS1_OAEP_PADDING>. The buffer should be sufficiently large for any
+expected digest algorithm names or the function will fail.
 
-The EVP_PKEY_CTX_set0_rsa_oaep_label() macro sets the RSA OAEP label to
+The EVP_PKEY_CTX_get_rsa_oaep_md() function does the same as
+EVP_PKEY_CTX_get_rsa_oaep_md_name() except that it returns a pointer to an
+EVP_MD object instead. Note that only known, built-in EVP_MD objects will be
+returned. The EVP_MD object may be NULL if the digest is not one of these (such
+as a digest only implemented in a third party provider).
+
+The EVP_PKEY_CTX_set0_rsa_oaep_label() function sets the RSA OAEP label to
 B<label> and its length to B<len>. If B<label> is NULL or B<len> is 0,
 the label is cleared. The library takes ownership of the label so the
 caller should not free the original memory pointed to by B<label>.
 The padding mode must have been set to B<RSA_PKCS1_OAEP_PADDING>.
 
-The EVP_PKEY_CTX_get0_rsa_oaep_label() macro gets the RSA OAEP label to
+The EVP_PKEY_CTX_get0_rsa_oaep_label() function gets the RSA OAEP label to
 B<label>. The return value is the label length. The padding mode
 must have been set to B<RSA_PKCS1_OAEP_PADDING>. The resulting pointer is owned
 by the library and should not be freed by the caller.
@@ -497,10 +538,9 @@ 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.
+All other functions and macros described on this page 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
 
@@ -515,13 +555,21 @@ L<EVP_PKEY_keygen(3)>
 
 =head1 HISTORY
 
-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_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.
+EVP_PKEY_CTX_get_signature_md(), EVP_PKEY_CTX_set_signature_md(),
+EVP_PKEY_CTX_set_dh_pad(), EVP_PKEY_CTX_set_rsa_padding(),
+EVP_PKEY_CTX_get_rsa_padding(), EVP_PKEY_CTX_get_rsa_mgf1_md(),
+EVP_PKEY_CTX_set_rsa_mgf1_md(), EVP_PKEY_CTX_set_rsa_oaep_md(),
+EVP_PKEY_CTX_get_rsa_oaep_md(), EVP_PKEY_CTX_set0_rsa_oaep_label(),
+EVP_PKEY_CTX_get0_rsa_oaep_label() were macros in OpenSSL 1.1.1 and below. From
+OpenSSL 3.0 they are functions.
+
+EVP_PKEY_CTX_get_rsa_oaep_md_name(), EVP_PKEY_CTX_get_rsa_mgf1_md_name(),
+EVP_PKEY_CTX_set_rsa_mgf1_md_name() and EVP_PKEY_CTX_set_rsa_oaep_md_name() were
+added in OpenSSL 3.0.
+
+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.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod b/doc/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod
index 6d42ab8b0f..e3ed14cfc6 100644
--- a/doc/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod
+++ b/doc/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_md.pod
@@ -35,10 +35,10 @@ to the B<RSA> operation except detection of the salt length (using
 RSA_PSS_SALTLEN_AUTO) is not supported for verification if the key has
 usage restrictions.
 
-The EVP_PKEY_CTX_set_signature_md() and EVP_PKEY_CTX_set_rsa_mgf1_md() macros
-are used to set the digest and MGF1 algorithms respectively. If the key has
-usage restrictions then an error is returned if an attempt is made to set the
-digest to anything other than the restricted value. Otherwise these are
+The L<EVP_PKEY_CTX_set_signature_md(3)> and L<EVP_PKEY_CTX_set_rsa_mgf1_md(3)>
+fuunctions are used to set the digest and MGF1 algorithms respectively. If the
+key has usage restrictions then an error is returned if an attempt is made to
+set the digest to anything other than the restricted value. Otherwise these are
 similar to the B<RSA> versions.
 
 =head2 Key Generation
diff --git a/doc/man7/provider-asymcipher.pod b/doc/man7/provider-asymcipher.pod
new file mode 100644
index 0000000000..d0effa89b1
--- /dev/null
+++ b/doc/man7/provider-asymcipher.pod
@@ -0,0 +1,242 @@
+=pod
+
+=head1 NAME
+
+provider-asym_cipher - The asym_cipher library E<lt>-E<gt> provider functions
+
+=head1 SYNOPSIS
+
+=for openssl 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_asym_cipher_newctx(void *provctx);
+ void OP_asym_cipher_freectx(void *ctx);
+ void *OP_asym_cipher_dupctx(void *ctx);
+
+ /* Encryption */
+ int OP_asym_cipher_encrypt_init(void *ctx, void *provkey);
+ int OP_asym_cipher_encrypt(void *ctx, unsigned char *out, size_t *outlen,
+                            size_t outsize, const unsigned char *in,
+                            size_t inlen);
+
+ /* Decryption */
+ int OP_asym_cipher_decrypt_init(void *ctx, void *provkey);
+ int OP_asym_cipher_decrypt(void *ctx, unsigned char *out, size_t *outlen,
+                            size_t outsize, const unsigned char *in,
+                            size_t inlen);
+
+ /* Asymmetric Cipher parameters */
+ int OP_asym_cipher_get_ctx_params(void *ctx, OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_asym_cipher_gettable_ctx_params(void);
+ int OP_asym_cipher_set_ctx_params(void *ctx, const OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_asym_cipher_settable_ctx_params(void);
+
+=head1 DESCRIPTION
+
+This documentation is primarily aimed at provider authors. See L<provider(7)>
+for further information.
+
+The asymmetric cipher (OSSL_OP_ASYM_CIPHER) operation enables providers to
+implement asymmetric cipher algorithms and make them available to applications
+via the API functions L<EVP_PKEY_encrypt_init_ex(3)>, L<EVP_PKEY_encrypt(3)>,
+L<EVP_PKEY_decrypt_init_ex(3)>, L<EVP_PKEY_decrypt(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_asym_cipher_newctx() has these:
+
+ typedef void *(OSSL_OP_asym_cipher_newctx_fn)(void *provctx);
+ static ossl_inline OSSL_OP_asym_cipher_newctx_fn
+     OSSL_get_OP_asym_cipher_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_asym_cipher_newctx               OSSL_FUNC_ASYM_CIPHER_NEWCTX
+ OP_asym_cipher_freectx              OSSL_FUNC_ASYM_CIPHER_FREECTX
+ OP_asym_cipher_dupctx               OSSL_FUNC_ASYM_CIPHER_DUPCTX
+
+ OP_asym_cipher_encrypt_init         OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT
+ OP_asym_cipher_encrypt              OSSL_FUNC_ASYM_CIPHER_ENCRYPT
+
+ OP_asym_cipher_decrypt_init         OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT
+ OP_asym_cipher_decrypt              OSSL_FUNC_ASYM_CIPHER_DECRYPT
+
+ OP_asym_cipher_get_ctx_params       OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS
+ OP_asym_cipher_gettable_ctx_params  OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS
+ OP_asym_cipher_set_ctx_params       OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS
+ OP_asym_cipher_settable_ctx_params  OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS
+
+An asymmetric cipher algorithm implementation may not implement all of these
+functions.
+In order to be a consistent set of functions a provider must implement
+OP_asym_cipher_newctx and OP_asym_cipher_freectx.
+It must also implement both of OP_asym_cipher_encrypt_init and
+OP_asym_cipher_encrypt, or both of OP_asym_cipher_decrypt_init and
+OP_asym_cipher_decrypt.
+OP_asym_cipher_get_ctx_params is optional but if it is present then so must
+OP_asym_cipher_gettable_ctx_params.
+Similarly, OP_asym_cipher_set_ctx_params is optional but if it is present then
+so must OP_asym_cipher_settable_ctx_params.
+
+An asymmetric cipher 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_asym_cipher_newctx() should create and return a pointer to a provider side
+structure for holding context information during an asymmetric cipher operation.
+A pointer to this context will be passed back in a number of the other
+asymmetric cipher operation function calls.
+The parameter I<provctx> is the provider context generated during provider
+initialisation (see L<provider(3)>).
+
+OP_asym_cipher_freectx() is passed a pointer to the provider side asymmetric
+cipher context in the I<ctx> parameter.
+This function should free any resources associated with that context.
+
+OP_asym_cipher_dupctx() should duplicate the provider side asymmetric cipher
+context in the I<ctx> parameter and return the duplicate copy.
+
+=head2 Encryption Functions
+
+OP_asym_cipher_encrypt_init() initialises a context for an asymmetric encryption
+given a provider side asymmetric cipher context in the I<ctx> parameter, and a
+pointer to a provider key object in the I<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_asym_cipher_encrypt() performs the actual encryption itself.
+A previously initialised asymmetric cipher context is passed in the I<ctx>
+parameter.
+The data to be encrypted is pointed to by the I<in> parameter which is I<inlen>
+bytes long.
+Unless I<out> is NULL, the encrypted data should be written to the location
+pointed to by the I<out> parameter and it should not exceed I<outsize> bytes in
+length.
+The length of the encrypted data should be written to I<*outlen>.
+If I<out> is NULL then the maximum length of the encrypted data should be
+written to I<*outlen>.
+
+=head2 Decryption Functions
+
+OP_asym_cipher_decrypt_init() initialises a context for an asymmetric decryption
+given a provider side asymmetric cipher context in the I<ctx> parameter, and a
+pointer to a provider key object in the I<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_asym_cipher_decrypt() performs the actual decryption itself.
+A previously initialised asymmetric cipher context is passed in the I<ctx>
+parameter.
+The data to be decrypted is pointed to by the I<in> parameter which is I<inlen>
+bytes long.
+Unless I<out> is NULL, the decrypted data should be written to the location
+pointed to by the I<out> parameter and it should not exceed I<outsize> bytes in
+length.
+The length of the decrypted data should be written to I<*outlen>.
+If I<out> is NULL then the maximum length of the decrypted data should be
+written to I<*outlen>.
+
+=head2 Asymmetric Cipher Parameters
+
+See L<OSSL_PARAM(3)> for further details on the parameters structure used by
+the OP_asym_cipher_get_ctx_params() and OP_asym_cipher_set_ctx_params()
+functions.
+
+OP_asym_cipher_get_ctx_params() gets asymmetric cipher parameters associated
+with the given provider side asymmetric cipher context I<ctx> and stores them in
+I<params>.
+OP_asym_cipher_set_ctx_params() sets the asymmetric cipher parameters associated
+with the given provider side asymmetric cipher context I<ctx> to I<params>.
+Any parameter settings are additional to any that were previously set.
+
+Parameters currently recognised by built-in asymmetric cipher algorithms are as
+follows.
+Not all parameters are relevant to, or are understood by all asymmetric cipher
+algorithms:
+
+=over 4
+
+=item "pad-mode" (B<OSSL_ASYM_CIPHER_PARAM_PAD_MODE>) <integer>
+
+=item "digest" (B<OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST>) <UTF8 string>
+
+Gets or sets the name of the OAEP digest algorithm used when OAEP padding is in
+use.
+
+=item "digest-props" (B<OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS>) <UTF8 string>
+
+Gets or sets the properties to use when fetching the OAEP digest algorithm.
+
+=item "mgf1-digest" (B<OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST>) <UTF8 string>
+
+Gets or sets the name of the MGF1 digest algorithm used when OAEP or PSS padding
+is in use.
+
+=item "mgf1-digest-props" (B<OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS>) <UTF8 string>
+
+Gets or sets the properties to use when fetching the MGF1 digest algorithm.
+
+=item "oaep-label" (B<OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL>) <octet string>
+
+Gets or sets the OAEP label used when OAEP padding is in use.
+
+=item "oaep-label-len" (B<OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN>) <size_t>
+
+Gets the length of an OAEP label when OAEP padding is in use.
+
+=back
+
+OP_asym_cipher_gettable_ctx_params() and OP_asym_cipher_settable_ctx_params()
+get a constant B<OSSL_PARAM> array that describes the gettable and settable
+parameters, i.e. parameters that can be used with OP_asym_cipherget_ctx_params()
+and OP_asym_cipher_set_ctx_params() respectively.
+See L<OSSL_PARAM(3)> for the use of B<OSSL_PARAM> as parameter descriptor.
+
+=head1 RETURN VALUES
+
+OP_asym_cipher_newctx() and OP_asym_cipher_dupctx() should return the newly
+created provider side asymmetric cipher context, 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 ASYM_CIPHER 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/crypto/evp.h b/include/crypto/evp.h
index 7753bc0e42..7f5e405486 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -42,6 +42,11 @@ struct evp_pkey_ctx_st {
             EVP_SIGNATURE *signature;
             void *sigprovctx;
         } sig;
+
+        struct {
+            EVP_ASYM_CIPHER *cipher;
+            void *ciphprovctx;
+        } ciph;
     } op;
 
     /* Legacy fields below */
@@ -572,6 +577,10 @@ struct evp_pkey_st {
 #define EVP_PKEY_CTX_IS_DERIVE_OP(ctx) \
     ((ctx)->operation == EVP_PKEY_OP_DERIVE)
 
+#define EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) \
+    ((ctx)->operation == EVP_PKEY_OP_ENCRYPT \
+     || (ctx)->operation == EVP_PKEY_OP_DECRYPT)
+
 void openssl_add_all_ciphers_int(void);
 void openssl_add_all_digests_int(void);
 void evp_cleanup_int(void);
diff --git a/include/internal/param_build.h b/include/internal/param_build.h
index a5297b843d..a8116e35cd 100644
--- a/include/internal/param_build.h
+++ b/include/internal/param_build.h
@@ -11,7 +11,7 @@
 #include <openssl/params.h>
 #include <openssl/types.h>
 
-#define OSSL_PARAM_BLD_MAX 10
+#define OSSL_PARAM_BLD_MAX 25
 
 typedef struct {
     const char *key;
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 42350e80d1..cdc493bae1 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -190,9 +190,18 @@ extern "C" {
 #define OSSL_EXCHANGE_PARAM_PAD      "pad" /* uint */
 
 /* Signature parameters */
-#define OSSL_SIGNATURE_PARAM_DIGEST         "digest"
+#define OSSL_SIGNATURE_PARAM_DIGEST         OSSL_ALG_PARAM_DIGEST
 #define OSSL_SIGNATURE_PARAM_DIGEST_SIZE    "digest-size"
 
+/* Asym cipher parameters */
+#define OSSL_ASYM_CIPHER_PARAM_PAD_MODE             "pad-mode"
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST          OSSL_ALG_PARAM_DIGEST
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS    "digest-props"
+#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST          "mgf1-digest"
+#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS    "mgf1-digest-props"
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL           "oaep-label"
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN       "oaep-label-len"
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h
index 5268aca21f..54241c7623 100644
--- a/include/openssl/core_numbers.h
+++ b/include/openssl/core_numbers.h
@@ -157,8 +157,9 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ITEM *,provider_get_reason_strings,
 # define OSSL_OP_KEYMGMT                            10
 # define OSSL_OP_KEYEXCH                            11
 # define OSSL_OP_SIGNATURE                          12
+# define OSSL_OP_ASYM_CIPHER                        13
 /* Highest known operation number */
-# define OSSL_OP__HIGHEST                           12
+# define OSSL_OP__HIGHEST                           13
 
 /* Digests */
 
@@ -484,6 +485,45 @@ OSSL_CORE_MAKE_FUNC(int, OP_signature_set_ctx_md_params,
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_settable_ctx_md_params,
                     (void *ctx))
 
+
+/* Asymmetric Ciphers */
+
+# define OSSL_FUNC_ASYM_CIPHER_NEWCTX                  1
+# define OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT            2
+# define OSSL_FUNC_ASYM_CIPHER_ENCRYPT                 3
+# define OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT            4
+# define OSSL_FUNC_ASYM_CIPHER_DECRYPT                 5
+# define OSSL_FUNC_ASYM_CIPHER_FREECTX                 6
+# define OSSL_FUNC_ASYM_CIPHER_DUPCTX                  7
+# define OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS          8
+# define OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS     9
+# define OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS         10
+# define OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS    11
+
+OSSL_CORE_MAKE_FUNC(void *, OP_asym_cipher_newctx, (void *provctx))
+OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_encrypt_init, (void *ctx, void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_encrypt, (void *ctx, unsigned char *out,
+                                                  size_t *outlen,
+                                                  size_t outsize,
+                                                  const unsigned char *in,
+                                                  size_t inlen))
+OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_decrypt_init, (void *ctx, void *provkey))
+OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_decrypt, (void *ctx, unsigned char *out,
+                                                  size_t *outlen,
+                                                  size_t outsize,
+                                                  const unsigned char *in,
+                                                  size_t inlen))
+OSSL_CORE_MAKE_FUNC(void, OP_asym_cipher_freectx, (void *ctx))
+OSSL_CORE_MAKE_FUNC(void *, OP_asym_cipher_dupctx, (void *ctx))
+OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_get_ctx_params,
+                    (void *ctx, OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_asym_cipher_gettable_ctx_params,
+                    (void))
+OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_set_ctx_params,
+                    (void *ctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_asym_cipher_settable_ctx_params,
+                    (void))
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 05bf87147c..e6b08d0b72 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -1531,6 +1531,21 @@ void EVP_SIGNATURE_names_do_all(const EVP_SIGNATURE *signature,
                                 void (*fn)(const char *name, void *data),
                                 void *data);
 
+void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher);
+int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher);
+OSSL_PROVIDER *EVP_ASYM_CIPHER_provider(const EVP_ASYM_CIPHER *cipher);
+EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                       const char *properties);
+int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name);
+int EVP_ASYM_CIPHER_number(const EVP_ASYM_CIPHER *cipher);
+void EVP_ASYM_CIPHER_do_all_provided(OPENSSL_CTX *libctx,
+                                     void (*fn)(EVP_ASYM_CIPHER *cipher,
+                                                void *arg),
+                                     void *arg);
+void EVP_ASYM_CIPHER_names_do_all(const EVP_ASYM_CIPHER *cipher,
+                                  void (*fn)(const char *name, void *data),
+                                  void *data);
+
 int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
                   unsigned char *sig, size_t *siglen,
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
index eba0604455..852981dfcf 100644
--- a/include/openssl/rsa.h
+++ b/include/openssl/rsa.h
@@ -100,11 +100,8 @@ extern "C" {
 #  define RSA_FLAG_NO_EXP_CONSTTIME RSA_FLAG_NO_CONSTTIME
 # endif
 
-# define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \
-        RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL)
-
-# define EVP_PKEY_CTX_get_rsa_padding(ctx, ppad) \
-        RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad)
+int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad_mode);
+int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *pad_mode);
 
 # define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \
         RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \
@@ -138,39 +135,34 @@ extern "C" {
         RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \
                           EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES, primes, NULL)
 
-# define  EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \
-        RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \
-                          EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md))
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
+                                      const char *mdprops);
+int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
+int EVP_PKEY_CTX_get_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, char *name,
+                                      size_t namelen);
+
 
 # define  EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx, md) \
         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, EVP_PKEY_OP_KEYGEN, \
                           EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md))
 
-# define  EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) \
-        EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,  \
-                          EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)(md))
-
-# define  EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, pmd) \
-        RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \
-                          EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)(pmd))
-
-# define  EVP_PKEY_CTX_get_rsa_oaep_md(ctx, pmd) \
-        EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,  \
-                          EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)(pmd))
-
-# define  EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, l, llen) \
-        EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,  \
-                          EVP_PKEY_CTRL_RSA_OAEP_LABEL, llen, (void *)(l))
-
-# define  EVP_PKEY_CTX_get0_rsa_oaep_label(ctx, l) \
-        EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,  \
-                          EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, (void *)(l))
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+int EVP_PKEY_CTX_set_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
+                                      const char *mdprops);
+int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **md);
+int EVP_PKEY_CTX_get_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, char *name,
+                                      size_t namelen);
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label,
+                                     int llen);
+int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char **label);
 
 # define  EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx, md) \
         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS,  \
                           EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_MD,  \
                           0, (void *)(md))
 
+
 # define EVP_PKEY_CTRL_RSA_PADDING       (EVP_PKEY_ALG_CTRL + 1)
 # define EVP_PKEY_CTRL_RSA_PSS_SALTLEN   (EVP_PKEY_ALG_CTRL + 2)
 
diff --git a/include/openssl/types.h b/include/openssl/types.h
index 8cfeb6ee22..151e3f1713 100644
--- a/include/openssl/types.h
+++ b/include/openssl/types.h
@@ -116,6 +116,8 @@ typedef struct evp_keyexch_st EVP_KEYEXCH;
 
 typedef struct evp_signature_st EVP_SIGNATURE;
 
+typedef struct evp_asym_cipher_st EVP_ASYM_CIPHER;
+
 typedef struct evp_Encode_Ctx_st EVP_ENCODE_CTX;
 
 typedef struct hmac_ctx_st HMAC_CTX;
diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h
index 48daf69861..503f0270c5 100644
--- a/providers/common/include/prov/providercommonerr.h
+++ b/providers/common/include/prov/providercommonerr.h
@@ -67,6 +67,7 @@ int ERR_load_PROV_strings(void);
 # define PROV_R_INVALID_ITERATION_COUNT                   123
 # define PROV_R_INVALID_IVLEN                             116
 # define PROV_R_INVALID_IV_LENGTH                         109
+# define PROV_R_INVALID_KEY                               158
 # define PROV_R_INVALID_KEYLEN                            117
 # define PROV_R_INVALID_KEY_LEN                           124
 # define PROV_R_INVALID_KEY_LENGTH                        105
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index 589f37be70..2b7bac037d 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -42,6 +42,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     "invalid iteration count"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IVLEN), "invalid ivlen"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IV_LENGTH), "invalid iv length"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY), "invalid key"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEYLEN), "invalid keylen"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY_LEN), "invalid key len"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY_LENGTH),
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 5384028a8d..ceb3fd0896 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -365,6 +365,10 @@ static const OSSL_ALGORITHM deflt_signature[] = {
     { NULL, NULL, NULL }
 };
 
+static const OSSL_ALGORITHM deflt_asym_cipher[] = {
+    { "RSA:rsaEncryption", "default=yes", rsa_asym_cipher_functions },
+    { NULL, NULL, NULL }
+};
 
 static const OSSL_ALGORITHM deflt_keymgmt[] = {
 #ifndef OPENSSL_NO_DH
@@ -397,6 +401,8 @@ static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov,
         return deflt_keyexch;
     case OSSL_OP_SIGNATURE:
         return deflt_signature;
+    case OSSL_OP_ASYM_CIPHER:
+        return deflt_asym_cipher;
     }
     return NULL;
 }
diff --git a/providers/implementations/asymciphers/build.info b/providers/implementations/asymciphers/build.info
new file mode 100644
index 0000000000..aa050803d4
--- /dev/null
+++ b/providers/implementations/asymciphers/build.info
@@ -0,0 +1,4 @@
+LIBS=../../../libcrypto
+SOURCE[../../../libcrypto]=rsa_enc.c
+
+
diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c
new file mode 100644
index 0000000000..9b17377783
--- /dev/null
+++ b/providers/implementations/asymciphers/rsa_enc.c
@@ -0,0 +1,391 @@
+/*
+ * 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/evp.h>
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/rsa.h>
+#include <openssl/params.h>
+#include <openssl/err.h>
+#include "internal/constant_time.h"
+#include "prov/providercommonerr.h"
+#include "prov/provider_ctx.h"
+#include "prov/implementations.h"
+
+#include <stdlib.h>
+
+static OSSL_OP_asym_cipher_newctx_fn rsa_newctx;
+static OSSL_OP_asym_cipher_encrypt_init_fn rsa_init;
+static OSSL_OP_asym_cipher_encrypt_fn rsa_encrypt;
+static OSSL_OP_asym_cipher_decrypt_init_fn rsa_init;
+static OSSL_OP_asym_cipher_decrypt_fn rsa_decrypt;
+static OSSL_OP_asym_cipher_freectx_fn rsa_freectx;
+static OSSL_OP_asym_cipher_dupctx_fn rsa_dupctx;
+static OSSL_OP_asym_cipher_get_ctx_params_fn rsa_get_ctx_params;
+static OSSL_OP_asym_cipher_gettable_ctx_params_fn rsa_gettable_ctx_params;
+static OSSL_OP_asym_cipher_set_ctx_params_fn rsa_set_ctx_params;
+static OSSL_OP_asym_cipher_settable_ctx_params_fn rsa_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 RSA structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+    OPENSSL_CTX *libctx;
+    RSA *rsa;
+    int pad_mode;
+    /* OAEP message digest */
+    EVP_MD *oaep_md;
+    /* message digest for MGF1 */
+    EVP_MD *mgf1_md;
+    /* OAEP label */
+    unsigned char *oaep_label;
+    size_t oaep_labellen;
+} PROV_RSA_CTX;
+
+static void *rsa_newctx(void *provctx)
+{
+    PROV_RSA_CTX *prsactx =  OPENSSL_zalloc(sizeof(PROV_RSA_CTX));
+
+    if (prsactx == NULL)
+        return NULL;
+    prsactx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+
+    return prsactx;
+}
+
+static int rsa_init(void *vprsactx, void *vrsa)
+{
+    PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+    if (prsactx == NULL || vrsa == NULL || !RSA_up_ref(vrsa))
+        return 0;
+    RSA_free(prsactx->rsa);
+    prsactx->rsa = vrsa;
+    prsactx->pad_mode = RSA_PKCS1_PADDING;
+    return 1;
+}
+
+static int rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen,
+                       size_t outsize, const unsigned char *in, size_t inlen)
+{
+    PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+    int ret;
+
+    if (out == NULL) {
+        size_t len = RSA_size(prsactx->rsa);
+
+        if (len == 0) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+            return 0;
+        }
+        *outlen = len;
+        return 1;
+    }
+
+    if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+        int rsasize = RSA_size(prsactx->rsa);
+        unsigned char *tbuf;
+
+        if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) {
+            PROVerr(0, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        ret = RSA_padding_add_PKCS1_OAEP_mgf1(tbuf, rsasize, in, inlen,
+                                              prsactx->oaep_label,
+                                              prsactx->oaep_labellen,
+                                              prsactx->oaep_md,
+                                              prsactx->mgf1_md);
+
+        if (!ret) {
+            OPENSSL_free(tbuf);
+            return 0;
+        }
+        ret = RSA_public_encrypt(rsasize, tbuf, out, prsactx->rsa,
+                                 RSA_NO_PADDING);
+        OPENSSL_free(tbuf);
+    } else {
+        ret = RSA_public_encrypt(inlen, in, out, prsactx->rsa,
+                                 prsactx->pad_mode);
+    }
+    /* A ret value of 0 is not an error */
+    if (ret < 0)
+        return ret;
+    *outlen = ret;
+    return 1;
+}
+
+static int rsa_decrypt(void *vprsactx, unsigned char *out, size_t *outlen,
+                       size_t outsize, const unsigned char *in, size_t inlen)
+{
+    PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+    int ret;
+
+    if (out == NULL) {
+        size_t len = RSA_size(prsactx->rsa);
+
+        if (len == 0) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+            return 0;
+        }
+        *outlen = len;
+        return 1;
+    }
+
+    if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+        int rsasize = RSA_size(prsactx->rsa);
+        unsigned char *tbuf;
+
+        if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) {
+            PROVerr(0, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        ret = RSA_private_decrypt(inlen, in, tbuf, prsactx->rsa,
+                                  RSA_NO_PADDING);
+        if (ret <= 0) {
+            OPENSSL_free(tbuf);
+            return 0;
+        }
+        ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, ret, tbuf,
+                                                ret, ret,
+                                                prsactx->oaep_label,
+                                                prsactx->oaep_labellen,
+                                                prsactx->oaep_md,
+                                                prsactx->mgf1_md);
+        OPENSSL_free(tbuf);
+    } else {
+        ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa,
+                                  prsactx->pad_mode);
+    }
+    *outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret);
+    ret = constant_time_select_int(constant_time_msb(ret), 0, 1);
+    return ret;
+}
+
+static void rsa_freectx(void *vprsactx)
+{
+    PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+    RSA_free(prsactx->rsa);
+
+    EVP_MD_free(prsactx->oaep_md);
+    EVP_MD_free(prsactx->mgf1_md);
+
+    OPENSSL_free(prsactx);
+}
+
+static void *rsa_dupctx(void *vprsactx)
+{
+    PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx;
+    PROV_RSA_CTX *dstctx;
+
+    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+    if (dstctx == NULL)
+        return NULL;
+
+    *dstctx = *srcctx;
+    if (dstctx->rsa != NULL && !RSA_up_ref(dstctx->rsa)) {
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    if (dstctx->oaep_md != NULL && !EVP_MD_up_ref(dstctx->oaep_md)) {
+        RSA_free(dstctx->rsa);
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    if (dstctx->mgf1_md != NULL && !EVP_MD_up_ref(dstctx->mgf1_md)) {
+        RSA_free(dstctx->rsa);
+        EVP_MD_free(dstctx->oaep_md);
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    return dstctx;
+}
+
+static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
+{
+    PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+    OSSL_PARAM *p;
+
+    if (prsactx == NULL || params == NULL)
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE);
+    if (p != NULL && !OSSL_PARAM_set_int(p, prsactx->pad_mode))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST);
+    if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->oaep_md == NULL
+                                                    ? ""
+                                                    : EVP_MD_name(prsactx->oaep_md)))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST);
+    if (p != NULL) {
+        EVP_MD *mgf1_md = prsactx->mgf1_md == NULL ? prsactx->oaep_md
+                                                   : prsactx->mgf1_md;
+
+        if (!OSSL_PARAM_set_utf8_string(p, mgf1_md == NULL
+                                           ? ""
+                                           : EVP_MD_name(mgf1_md)))
+        return 0;
+    }
+
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL);
+    if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, prsactx->oaep_label, 0))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, prsactx->oaep_labellen))
+        return 0;
+
+    return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+    OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0),
+    OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL),
+    OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0),
+    OSSL_PARAM_DEFN(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, OSSL_PARAM_OCTET_PTR,
+                    NULL, 0),
+    OSSL_PARAM_size_t(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN, NULL),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_gettable_ctx_params(void)
+{
+    return known_gettable_ctx_params;
+}
+
+static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
+{
+    PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+    const OSSL_PARAM *p;
+    /* Should be big enough */
+    char mdname[80], mdprops[80] = { '\0' };
+    char *str = mdname;
+    int pad_mode;
+
+    if (prsactx == NULL || params == NULL)
+        return 0;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST);
+    if (p != NULL) {
+        if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname)))
+            return 0;
+
+        str = mdprops;
+        p = OSSL_PARAM_locate_const(params,
+                                    OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS);
+        if (p != NULL) {
+            if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
+                return 0;
+        }
+
+        EVP_MD_free(prsactx->oaep_md);
+        prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, mdname, mdprops);
+
+        if (prsactx->oaep_md == NULL)
+            return 0;
+    }
+
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE);
+    if (p != NULL) {
+        if (!OSSL_PARAM_get_int(p, &pad_mode))
+            return 0;
+        /*
+         * PSS padding is for signatures only so is not compatible with
+         * asymmetric cipher use.
+         */
+        if (pad_mode == RSA_PKCS1_PSS_PADDING)
+            return 0;
+        if (pad_mode == RSA_PKCS1_OAEP_PADDING && prsactx->oaep_md == NULL) {
+            prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, "SHA1", mdprops);
+            if (prsactx->oaep_md == NULL)
+                return 0;
+        }
+        prsactx->pad_mode = pad_mode;
+    }
+
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST);
+    if (p != NULL) {
+        if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname)))
+            return 0;
+
+        str = mdprops;
+        p = OSSL_PARAM_locate_const(params,
+                                    OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS);
+        if (p != NULL) {
+            if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
+                return 0;
+        } else {
+            str = NULL;
+        }
+
+        EVP_MD_free(prsactx->mgf1_md);
+        prsactx->mgf1_md = EVP_MD_fetch(prsactx->libctx, mdname, str);
+
+        if (prsactx->mgf1_md == NULL)
+            return 0;
+    }
+
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL);
+    if (p != NULL) {
+        void *tmp_label = NULL;
+        size_t tmp_labellen;
+
+        if (!OSSL_PARAM_get_octet_string(p, &tmp_label, 0, &tmp_labellen))
+            return 0;
+        OPENSSL_free(prsactx->oaep_label);
+        prsactx->oaep_label = (unsigned char *)tmp_label;
+        prsactx->oaep_labellen = tmp_labellen;
+    }
+
+    return 1;
+}
+
+static const OSSL_PARAM known_settable_ctx_params[] = {
+    OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0),
+    OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL),
+    OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0),
+    OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0),
+    OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_settable_ctx_params(void)
+{
+    return known_settable_ctx_params;
+}
+
+const OSSL_DISPATCH rsa_asym_cipher_functions[] = {
+    { OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))rsa_newctx },
+    { OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, (void (*)(void))rsa_init },
+    { OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))rsa_encrypt },
+    { OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))rsa_init },
+    { OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))rsa_decrypt },
+    { OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))rsa_freectx },
+    { OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))rsa_dupctx },
+    { OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS,
+      (void (*)(void))rsa_get_ctx_params },
+    { OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS,
+      (void (*)(void))rsa_gettable_ctx_params },
+    { OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS,
+      (void (*)(void))rsa_set_ctx_params },
+    { OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS,
+      (void (*)(void))rsa_settable_ctx_params },
+    { 0, NULL }
+};
diff --git a/providers/implementations/build.info b/providers/implementations/build.info
index 0fc0822074..a2fbf45a22 100644
--- a/providers/implementations/build.info
+++ b/providers/implementations/build.info
@@ -1 +1 @@
-SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature
+SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature asymciphers
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index e241e6b49a..490843c544 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -258,3 +258,6 @@ extern const OSSL_DISPATCH dh_keyexch_functions[];
 
 /* Signature */
 extern const OSSL_DISPATCH dsa_signature_functions[];
+
+/* Asym Cipher */
+extern const OSSL_DISPATCH rsa_asym_cipher_functions[];
diff --git a/util/libcrypto.num b/util/libcrypto.num
index c68eb9d8c9..6bdfcb328c 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4854,3 +4854,23 @@ EVP_PKEY_key_fromdata_init              ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_fromdata                       ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_param_fromdata_settable        ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_key_fromdata_settable          ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_free                    ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_up_ref                  ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_provider                ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_fetch                   ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_is_a                    ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_number                  ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_do_all_provided         ?	3_0_0	EXIST::FUNCTION:
+EVP_ASYM_CIPHER_names_do_all            ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_CTX_set_rsa_padding            ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_get_rsa_padding            ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_set_rsa_mgf1_md            ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_set_rsa_mgf1_md_name       ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_get_rsa_mgf1_md            ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_set_rsa_oaep_md            ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_set_rsa_oaep_md_name       ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_get_rsa_oaep_md            ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_set0_rsa_oaep_label        ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_get0_rsa_oaep_label        ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_get_rsa_mgf1_md_name       ?	3_0_0	EXIST::FUNCTION:RSA
+EVP_PKEY_CTX_get_rsa_oaep_md_name       ?	3_0_0	EXIST::FUNCTION:RSA


More information about the openssl-commits mailing list