Add EVP_PKEY_gettable_params support for accessing EVP_PKEY key data fields

Currently only RSA, EC and ECX are supported (DH and DSA need to be added to the keygen
PR's seperately because the fields supported have changed significantly).

The API's require the keys to be provider based.

Made the keymanagement export and get_params functions share the same code by supplying
support functions that work for both a OSSL_PARAM_BLD as well as a OSSL_PARAM[].
This approach means that complex code is not required to build an
empty OSSL_PARAM[] with the correct sized fields before then doing a second
pass to populate the array.

The RSA factor arrays have been changed to use unique key names to simplify the interface
needed by the user.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11365)
diff --git a/crypto/build.info b/crypto/build.info
index a688248..baa31ee 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -70,7 +70,8 @@
 $UTIL_COMMON=\
         cryptlib.c params.c params_from_text.c bsearch.c ex_data.c o_str.c \
         ctype.c threads_pthread.c threads_win.c threads_none.c initthread.c \
-        context.c sparse_array.c asn1_dsa.c packet.c param_build.c $CPUIDASM
+        context.c sparse_array.c asn1_dsa.c packet.c param_build.c $CPUIDASM \
+        param_build_set.c
 $UTIL_DEFINE=$CPUIDDEF
 
 SOURCE[../libcrypto]=$UTIL_COMMON \
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 9ed238e..b176f10 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -1459,3 +1459,163 @@
     return 0;     /* No downgrade, but at least the key is restored */
 }
 #endif  /* FIPS_MODE */
+
+const OSSL_PARAM *EVP_PKEY_gettable_params(EVP_PKEY *pkey)
+{
+    if (pkey == NULL
+        || pkey->keymgmt == NULL
+        || pkey->keydata == NULL)
+        return 0;
+    return evp_keymgmt_gettable_params(pkey->keymgmt);
+}
+
+/*
+ * For the following methods param->return_size is set to a value
+ * larger than can be returned by the call to evp_keymgmt_get_params().
+ * If it is still this value then the parameter was ignored - and in this
+ * case it returns an error..
+ */
+
+int EVP_PKEY_get_bn_param(EVP_PKEY *pkey, const char *key_name, BIGNUM **bn)
+{
+    int ret = 0;
+    OSSL_PARAM params[2];
+    unsigned char buffer[2048];
+    /*
+     * Use -1 as the terminator here instead of sizeof(buffer) + 1 since
+     * -1 is less likely to be a valid value.
+     */
+    const size_t not_set = (size_t)-1;
+    unsigned char *buf = NULL;
+    size_t buf_sz = 0;
+
+    if (pkey == NULL
+        || pkey->keymgmt == NULL
+        || pkey->keydata == NULL
+        || key_name == NULL
+        || bn == NULL)
+        return 0;
+
+    memset(buffer, 0, sizeof(buffer));
+    params[0] = OSSL_PARAM_construct_BN(key_name, buffer, sizeof(buffer));
+    /* If the return_size is still not_set then we know it was not found */
+    params[0].return_size = not_set;
+    params[1] = OSSL_PARAM_construct_end();
+    if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params)) {
+        if (params[0].return_size == not_set
+            || params[0].return_size == 0)
+            return 0;
+        buf_sz = params[0].return_size;
+        /*
+         * If it failed because the buffer was too small then allocate the
+         * required buffer size and retry.
+         */
+        buf = OPENSSL_zalloc(buf_sz);
+        if (buf == NULL)
+            return 0;
+        params[0].data = buf;
+        params[0].data_size = buf_sz;
+
+        if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+            goto err;
+    }
+    /* Fail if the param was not found */
+    if (params[0].return_size == not_set)
+        goto err;
+    ret = OSSL_PARAM_get_BN(params, bn);
+err:
+    OPENSSL_free(buf);
+    return ret;
+}
+
+int EVP_PKEY_get_octet_string_param(EVP_PKEY *pkey, const char *key_name,
+                                    unsigned char *buf, size_t max_buf_sz,
+                                    size_t *out_sz)
+{
+    OSSL_PARAM params[2];
+    const size_t not_set = max_buf_sz + 1;
+
+    if (pkey == NULL
+        || pkey->keymgmt == NULL
+        || pkey->keydata == NULL
+        || key_name == NULL)
+        return 0;
+
+    params[0] = OSSL_PARAM_construct_octet_string(key_name, buf, max_buf_sz);
+    params[0].return_size = not_set;
+    params[1] = OSSL_PARAM_construct_end();
+    if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+        return 0;
+    if (params[0].return_size == not_set)
+        return 0;
+    if (out_sz != NULL)
+        *out_sz = params[0].return_size;
+    return 1;
+}
+
+int EVP_PKEY_get_utf8_string_param(EVP_PKEY *pkey, const char *key_name,
+                                    char *str, size_t max_buf_sz,
+                                    size_t *out_sz)
+{
+    OSSL_PARAM params[2];
+    const size_t not_set = max_buf_sz + 1;
+
+    if (pkey == NULL
+        || pkey->keymgmt == NULL
+        || pkey->keydata == NULL
+        || key_name == NULL)
+        return 0;
+
+    params[0] = OSSL_PARAM_construct_utf8_string(key_name, str, max_buf_sz);
+    params[0].return_size = not_set;
+    params[1] = OSSL_PARAM_construct_end();
+    if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+        return 0;
+    if (params[0].return_size == not_set)
+        return 0;
+    if (out_sz != NULL)
+        *out_sz = params[0].return_size;
+    return 1;
+}
+
+int EVP_PKEY_get_int_param(EVP_PKEY *pkey, const char *key_name, int *out)
+{
+    OSSL_PARAM params[2];
+    const size_t not_set = sizeof(int) + 1;
+
+    if (pkey == NULL
+        || pkey->keymgmt == NULL
+        || pkey->keydata == NULL
+        || key_name == NULL)
+        return 0;
+
+    params[0] = OSSL_PARAM_construct_int(key_name, out);
+    params[0].return_size = not_set;
+    params[1] = OSSL_PARAM_construct_end();
+    if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+        return 0;
+    if (params[0].return_size == not_set)
+        return 0;
+    return 1;
+}
+
+int EVP_PKEY_get_size_t_param(EVP_PKEY *pkey, const char *key_name, size_t *out)
+{
+    OSSL_PARAM params[2];
+    const size_t not_set = sizeof(size_t) + 1;
+
+    if (pkey == NULL
+        || pkey->keymgmt == NULL
+        || pkey->keydata == NULL
+        || key_name == NULL)
+        return 0;
+
+    params[0] = OSSL_PARAM_construct_size_t(key_name, out);
+    params[0].return_size = not_set;
+    params[1] = OSSL_PARAM_construct_end();
+    if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+        return 0;
+    if (params[0].return_size == not_set)
+        return 0;
+    return 1;
+}
diff --git a/crypto/param_build_set.c b/crypto/param_build_set.c
new file mode 100644
index 0000000..b74b0d5
--- /dev/null
+++ b/crypto/param_build_set.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 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
+ */
+
+/*
+ * Key Management utility functions to share functionality between the export()
+ * and get_params() methods.
+ * export() uses OSSL_PARAM_BLD, and get_params() used the OSSL_PARAM[] to
+ * fill in parameter data for the same key and data fields.
+ */
+
+#include <openssl/core_names.h>
+#include "internal/param_build_set.h"
+
+DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM)
+
+int ossl_param_build_set_int(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                             const char *key, int num)
+{
+    if (bld != NULL)
+        return OSSL_PARAM_BLD_push_int(bld, key, num);
+    p = OSSL_PARAM_locate(p, key);
+    if (p != NULL)
+        return OSSL_PARAM_set_int(p, num);
+    return 1;
+}
+
+int ossl_param_build_set_utf8_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                     const char *key, const char *buf)
+{
+    if (bld != NULL)
+        return OSSL_PARAM_BLD_push_utf8_string(bld, key, buf, 0);
+    p = OSSL_PARAM_locate(p, key);
+    if (p != NULL)
+        return OSSL_PARAM_set_utf8_string(p, buf);
+    return 1;
+}
+
+int ossl_param_build_set_octet_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                      const char *key,
+                                      const unsigned char *data,
+                                      size_t data_len)
+{
+    if (bld != NULL)
+        return OSSL_PARAM_BLD_push_octet_string(bld, key, data, data_len);
+
+    p = OSSL_PARAM_locate(p, key);
+    if (p != NULL)
+        return OSSL_PARAM_set_octet_string(p, data, data_len);
+    return 1;
+}
+
+int ossl_param_build_set_bn_pad(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                const char *key, const BIGNUM *bn,  size_t sz)
+{
+    if (bld != NULL)
+        return OSSL_PARAM_BLD_push_BN_pad(bld, key, bn, sz);
+    p = OSSL_PARAM_locate(p, key);
+    if (p != NULL) {
+        if (sz > p->data_size)
+            return 0;
+        /* TODO(3.0) Change to use OSSL_PARAM_set_BN_pad */
+        p->data_size = sz;
+        return OSSL_PARAM_set_BN(p, bn);
+    }
+    return 1;
+}
+
+int ossl_param_build_set_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                            const char *key, const BIGNUM *bn)
+{
+    if (bld != NULL)
+        return OSSL_PARAM_BLD_push_BN(bld, key, bn);
+
+    p = OSSL_PARAM_locate(p, key);
+    if (p != NULL)
+        return OSSL_PARAM_set_BN(p, bn) > 0;
+    return 1;
+}
+
+int ossl_param_build_set_multi_key_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *params,
+                                      const char *names[],
+                                      STACK_OF(BIGNUM_const) *stk)
+{
+    int i, sz = sk_BIGNUM_const_num(stk);
+    OSSL_PARAM *p;
+
+
+    if (bld != NULL) {
+        for (i = 0; i < sz && names[i] != NULL; ++i) {
+            if (!OSSL_PARAM_BLD_push_BN(bld, names[i],
+                                        sk_BIGNUM_const_value(stk, i)))
+                return 0;
+        }
+        return 1;
+    }
+
+    for (i = 0; i < sz && names[i] != NULL; ++i) {
+        p = OSSL_PARAM_locate(params, names[i]);
+        if (p != NULL) {
+            if (!OSSL_PARAM_set_BN(p, sk_BIGNUM_const_value(stk, i)))
+                return 0;
+        }
+    }
+    return 1;
+}
diff --git a/crypto/rsa/build.info b/crypto/rsa/build.info
index c1d1a37..7921202 100644
--- a/crypto/rsa/build.info
+++ b/crypto/rsa/build.info
@@ -2,7 +2,8 @@
 
 $COMMON=rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_aid.c rsa_pk1.c \
         rsa_none.c rsa_oaep.c rsa_chk.c rsa_pss.c rsa_x931.c rsa_crpt.c \
-        rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c rsa_backend.c
+        rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c rsa_backend.c \
+        rsa_mp_names.c
 
 SOURCE[../../libcrypto]=$COMMON\
         rsa_saos.c rsa_err.c rsa_asn1.c rsa_depr.c rsa_ameth.c rsa_prn.c \
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index ec8df4a..fb378ae 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -20,7 +20,7 @@
 #include <openssl/bn.h>
 #include <openssl/cms.h>
 #include <openssl/core_names.h>
-#include "openssl/param_build.h"
+#include <openssl/param_build.h>
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
 #include "crypto/rsa.h"
@@ -1142,27 +1142,24 @@
             goto err;
         selection |= OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
 
-        for (i = 0; i < numprimes; i++) {
+        for (i = 0; i < numprimes  && rsa_mp_factor_names[i] != NULL; i++) {
             const BIGNUM *num = sk_BIGNUM_const_value(primes, i);
 
-            if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR,
-                                        num))
+            if (!OSSL_PARAM_BLD_push_BN(tmpl, rsa_mp_factor_names[i], num))
                 goto err;
         }
 
-        for (i = 0; i < numexps; i++) {
+        for (i = 0; i < numexps && rsa_mp_exp_names[i] != NULL; i++) {
             const BIGNUM *num = sk_BIGNUM_const_value(exps, i);
 
-            if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT,
-                                        num))
+            if (!OSSL_PARAM_BLD_push_BN(tmpl, rsa_mp_exp_names[i], num))
                 goto err;
         }
 
-        for (i = 0; i < numcoeffs; i++) {
+        for (i = 0; i < numcoeffs && rsa_mp_coeff_names[i] != NULL; i++) {
             const BIGNUM *num = sk_BIGNUM_const_value(coeffs, i);
 
-            if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_COEFFICIENT,
-                                        num))
+            if (!OSSL_PARAM_BLD_push_BN(tmpl, rsa_mp_coeff_names[i], num))
                 goto err;
         }
     }
diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c
index f68d38c..57a539c 100644
--- a/crypto/rsa/rsa_backend.c
+++ b/crypto/rsa/rsa_backend.c
@@ -20,19 +20,23 @@
 DEFINE_STACK_OF(BIGNUM)
 
 static int collect_numbers(STACK_OF(BIGNUM) *numbers,
-                           const OSSL_PARAM params[], const char *key)
+                           const OSSL_PARAM params[], const char *names[])
 {
     const OSSL_PARAM *p = NULL;
+    int i;
 
     if (numbers == NULL)
         return 0;
 
-    for (p = params; (p = OSSL_PARAM_locate_const(p, key)) != NULL; p++) {
-        BIGNUM *tmp = NULL;
+    for (i = 0; names[i] != NULL; i++){
+        p = OSSL_PARAM_locate_const(params, names[i]);
+        if (p != NULL) {
+            BIGNUM *tmp = NULL;
 
-        if (!OSSL_PARAM_get_BN(p, &tmp)
-            || sk_BIGNUM_push(numbers, tmp) == 0)
-            return 0;
+            if (!OSSL_PARAM_get_BN(p, &tmp)
+                || sk_BIGNUM_push(numbers, tmp) == 0)
+                return 0;
+        }
     }
 
     return 1;
@@ -65,11 +69,11 @@
 
     if (is_private) {
         if (!collect_numbers(factors = sk_BIGNUM_new_null(), params,
-                             OSSL_PKEY_PARAM_RSA_FACTOR)
+                             rsa_mp_factor_names)
             || !collect_numbers(exps = sk_BIGNUM_new_null(), params,
-                                OSSL_PKEY_PARAM_RSA_EXPONENT)
+                                rsa_mp_exp_names)
             || !collect_numbers(coeffs = sk_BIGNUM_new_null(), params,
-                                OSSL_PKEY_PARAM_RSA_COEFFICIENT))
+                                rsa_mp_coeff_names))
             goto err;
 
         /* It's ok if this private key just has n, e and d */
diff --git a/crypto/rsa/rsa_mp_names.c b/crypto/rsa/rsa_mp_names.c
new file mode 100644
index 0000000..e69321a
--- /dev/null
+++ b/crypto/rsa/rsa_mp_names.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_names.h>
+#include "crypto/rsa.h"
+
+/*
+ * The following tables are constants used during RSA parameter building
+ * operations. It is easier to point to one of these fixed strings than have
+ * to dynamically add and generate the names on the fly.
+ */
+
+/*
+ * A fixed table of names for the RSA prime factors starting with
+ * P,Q and up to 8 additional primes.
+ */
+const char *rsa_mp_factor_names[] = {
+    OSSL_PKEY_PARAM_RSA_FACTOR1,
+    OSSL_PKEY_PARAM_RSA_FACTOR2,
+#ifndef FIPS_MODE
+    OSSL_PKEY_PARAM_RSA_FACTOR3,
+    OSSL_PKEY_PARAM_RSA_FACTOR4,
+    OSSL_PKEY_PARAM_RSA_FACTOR5,
+    OSSL_PKEY_PARAM_RSA_FACTOR6,
+    OSSL_PKEY_PARAM_RSA_FACTOR7,
+    OSSL_PKEY_PARAM_RSA_FACTOR8,
+    OSSL_PKEY_PARAM_RSA_FACTOR9,
+    OSSL_PKEY_PARAM_RSA_FACTOR10,
+#endif
+    NULL
+};
+
+/*
+ * A fixed table of names for the RSA exponents starting with
+ * DP,DQ and up to 8 additional exponents.
+ */
+const char *rsa_mp_exp_names[] = {
+    OSSL_PKEY_PARAM_RSA_EXPONENT1,
+    OSSL_PKEY_PARAM_RSA_EXPONENT2,
+#ifndef FIPS_MODE
+    OSSL_PKEY_PARAM_RSA_EXPONENT3,
+    OSSL_PKEY_PARAM_RSA_EXPONENT4,
+    OSSL_PKEY_PARAM_RSA_EXPONENT5,
+    OSSL_PKEY_PARAM_RSA_EXPONENT6,
+    OSSL_PKEY_PARAM_RSA_EXPONENT7,
+    OSSL_PKEY_PARAM_RSA_EXPONENT8,
+    OSSL_PKEY_PARAM_RSA_EXPONENT9,
+    OSSL_PKEY_PARAM_RSA_EXPONENT10,
+#endif
+    NULL
+};
+
+/*
+ * A fixed table of names for the RSA coefficients starting with
+ * QINV and up to 8 additional exponents.
+ */
+const char *rsa_mp_coeff_names[] = {
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT1,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT2,
+#ifndef FIPS_MODE
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT3,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT4,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT5,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT6,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT7,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT8,
+    OSSL_PKEY_PARAM_RSA_COEFFICIENT9,
+#endif
+    NULL
+};
diff --git a/doc/man3/EVP_PKEY_fromdata.pod b/doc/man3/EVP_PKEY_fromdata.pod
index 2d0059d..e3ddf68 100644
--- a/doc/man3/EVP_PKEY_fromdata.pod
+++ b/doc/man3/EVP_PKEY_fromdata.pod
@@ -52,7 +52,7 @@
 
 =head1 SEE ALSO
 
-L<EVP_PKEY_CTX_new(3)>, L<provider(7)>
+L<EVP_PKEY_CTX_new(3)>, L<provider(7)>, L<EVP_PKEY_gettable_params(3)>
 
 =head1 HISTORY
 
diff --git a/doc/man3/EVP_PKEY_gettable_params.pod b/doc/man3/EVP_PKEY_gettable_params.pod
new file mode 100644
index 0000000..87d25c7
--- /dev/null
+++ b/doc/man3/EVP_PKEY_gettable_params.pod
@@ -0,0 +1,108 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY_gettable_params, EVP_PKEY_get_int_param, EVP_PKEY_get_size_t_param,
+EVP_PKEY_get_bn_param, EVP_PKEY_get_utf8_string_param,
+EVP_PKEY_get_octet_string_param
+- retrieve key parameters from a key
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ const OSSL_PARAM *EVP_PKEY_gettable_params(EVP_PKEY *pkey);
+ int EVP_PKEY_get_int_param(EVP_PKEY *pkey, const char *key_name, int *out);
+ int EVP_PKEY_get_size_t_param(EVP_PKEY *pkey, const char *key_name, size_t *out);
+ int EVP_PKEY_get_bn_param(EVP_PKEY *pkey, const char *key_name, BIGNUM **bn);
+ int EVP_PKEY_get_utf8_string_param(EVP_PKEY *pkey, const char *key_name,
+                                    char *str, size_t max_buf_sz, size_t *out_sz);
+ int EVP_PKEY_get_octet_string_param(EVP_PKEY *pkey, const char *key_name,
+                                    unsigned char *buf, size_t max_buf_sz,
+                                    size_t *out_sz);
+
+=head1 DESCRIPTION
+
+EVP_PKEY_gettable_params() returns a constant list of I<params> indicating
+the names and types of key parameters that can be retrieved.
+See L<OSSL_PARAM(3)> for information about parameters.
+
+EVP_PKEY_get_int_param() retrieves a key I<pkey> integer value I<*out>
+associated with a name of I<key_name>.
+
+EVP_PKEY_get_size_t_param() retrieves a key I<pkey> size_t value I<*out>
+associated with a name of I<key_name>.
+
+EVP_PKEY_get_bn_param() retrieves a key I<pkey> BIGNUM value I<**bn>
+associated with a name of I<key_name>. If I<*bn> is NULL then the BIGNUM
+is allocated by the method.
+
+EVP_PKEY_get_utf8_string_param() get a key I<pkey> UTF8 string value int a buffer
+I<str> of maximum size I<max_buf_sz> associated with a name of I<key_name>.
+I<*out_sz> is the returned size of the string if it is not NULL.
+
+EVP_PKEY_get_octet_string_param() copy a I<pkey>'s octet string value into a buffer
+I<buf> of maximum size I<max_buf_sz> associated with a name of I<key_name>.
+I<*out_sz> is the returned size of the buffer if it is not NULL.
+
+=head1 NOTES
+
+These functions only work for B<EVP_PKEY>s that contain a provider side key.
+
+=head1 RETURN VALUES
+
+EVP_PKEY_gettable_params() returns NULL on error or if it is not supported,
+
+All other methods return 1 if a value associated with the key's I<key_name> was
+successfully returned, or 0 if there was an error.
+An error may be returned by methods EVP_PKEY_get_utf8_string_param() and
+EVP_PKEY_get_octet_string_param() if I<max_buf_sz> is not big enough to hold the
+value.
+
+=head1 EXAMPLES
+
+ #include <openssl/evp.h>
+
+ char *curve_name[64];
+ unsigned char pub[256];
+ BIGNUM *bn_priv = NULL;
+
+ /*
+  * NB: assumes 'key' is set up before the next step. In this example the key
+  * is an EC key.
+  */
+
+ if (!EVP_PKEY_get_utf8_string_param(key, OSSL_PKEY_PARAM_EC_NAME,
+                                     curve_name, sizeof(curve_name), &len)) {
+   /* Error */
+ }
+ if (!EVP_PKEY_get_octet_string_param(key, OSSL_PKEY_PARAM_PUB_KEY,
+                                      pub, sizeof(pub), &len)) {
+     /* Error */
+ }
+ if (!EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_PRIV_KEY, &bn_priv)) {
+     /* Error */
+ }
+
+
+ BN_clear_free(bn_priv);
+
+=head1 SEE ALSO
+
+L<EVP_PKEY_CTX_new(3)>, L<provider-keymgmt(7)>, L<OSSL_PARAM(3)>
+
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
+
diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod
index 59e538d..00596a0 100644
--- a/doc/man7/provider-keymgmt.pod
+++ b/doc/man7/provider-keymgmt.pod
@@ -334,20 +334,74 @@
 
 The RSA "d" value.
 
-=item "rsa-factor" (B<OSSL_PKEY_PARAM_RSA_FACTOR>) <unsigned integer>
+=item "rsa-factor1" (B<OSSL_PKEY_PARAM_RSA_FACTOR1>) <unsigned integer>
 
-An RSA factor. In 2 prime RSA these are often known as "p" or "q". This value
-may be repeated up to 10 times in a single key.
+=item "rsa-factor2" (B<OSSL_PKEY_PARAM_RSA_FACTOR2>) <unsigned integer>
 
-=item "rsa-exponent" (B<OSSL_PKEY_PARAM_RSA_EXPONENT>) <unsigned integer>
+=item "rsa-factor3" (B<OSSL_PKEY_PARAM_RSA_FACTOR3>) <unsigned integer>
 
-An RSA CRT (Chinese Remainder Theorem) exponent. This value may be repeated up
-to 10 times in a single key.
+=item "rsa-factor4" (B<OSSL_PKEY_PARAM_RSA_FACTOR4>) <unsigned integer>
 
-=item "rsa-coefficient" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT>) <unsigned integer>
+=item "rsa-factor5" (B<OSSL_PKEY_PARAM_RSA_FACTOR5>) <unsigned integer>
 
-An RSA CRT (Chinese Remainder Theorem) coefficient. This value may be repeated
-up to 9 times in a single key.
+=item "rsa-factor6" (B<OSSL_PKEY_PARAM_RSA_FACTOR6>) <unsigned integer>
+
+=item "rsa-factor7" (B<OSSL_PKEY_PARAM_RSA_FACTOR7>) <unsigned integer>
+
+=item "rsa-factor8" (B<OSSL_PKEY_PARAM_RSA_FACTOR8>) <unsigned integer>
+
+=item "rsa-factor9" (B<OSSL_PKEY_PARAM_RSA_FACTOR9>) <unsigned integer>
+
+=item "rsa-factor10" (B<OSSL_PKEY_PARAM_RSA_FACTOR10>) <unsigned integer>
+
+RSA prime factors. The factors are known as "p", "q" and "r_i" in RFC8017.
+Up to eight additional "r_i" prime factors are supported.
+
+=item "rsa-exponent1" (B<OSSL_PKEY_PARAM_RSA_EXPONENT1>) <unsigned integer>
+
+=item "rsa-exponent2" (B<OSSL_PKEY_PARAM_RSA_EXPONENT2>) <unsigned integer>
+
+=item "rsa-exponent3" (B<OSSL_PKEY_PARAM_RSA_EXPONENT3>) <unsigned integer>
+
+=item "rsa-exponent4" (B<OSSL_PKEY_PARAM_RSA_EXPONENT4>) <unsigned integer>
+
+=item "rsa-exponent5" (B<OSSL_PKEY_PARAM_RSA_EXPONENT5>) <unsigned integer>
+
+=item "rsa-exponent6" (B<OSSL_PKEY_PARAM_RSA_EXPONENT6>) <unsigned integer>
+
+=item "rsa-exponent7" (B<OSSL_PKEY_PARAM_RSA_EXPONENT7>) <unsigned integer>
+
+=item "rsa-exponent8" (B<OSSL_PKEY_PARAM_RSA_EXPONENT8>) <unsigned integer>
+
+=item "rsa-exponent9" (B<OSSL_PKEY_PARAM_RSA_EXPONENT9>) <unsigned integer>
+
+=item "rsa-exponent10" (B<OSSL_PKEY_PARAM_RSA_EXPONENT10>) <unsigned integer>
+
+RSA CRT (Chinese Remainder Theorem) exponents. The exponents are known
+as "dP", "dQ" and "d_i in RFC8017".
+Up to eight additional "d_i" exponents are supported.
+
+=item "rsa-coefficient1" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT1>) <unsigned integer>
+
+=item "rsa-coefficient2" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT2>) <unsigned integer>
+
+=item "rsa-coefficient3" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT3>) <unsigned integer>
+
+=item "rsa-coefficient4" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT4>) <unsigned integer>
+
+=item "rsa-coefficient5" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT5>) <unsigned integer>
+
+=item "rsa-coefficient6" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT6>) <unsigned integer>
+
+=item "rsa-coefficient7" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT7>) <unsigned integer>
+
+=item "rsa-coefficient8" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT8>) <unsigned integer>
+
+=item "rsa-coefficient9" (B<OSSL_PKEY_PARAM_RSA_COEFFICIENT9>) <unsigned integer>
+
+RSA CRT (Chinese Remainder Theorem) coefficients. The coefficients are known as
+"qInv" and "t_i".
+Up to eight additional "t_i" exponents are supported.
 
 =back
 
@@ -427,11 +481,13 @@
 
 See L<OSSL_PARAM(3)> for further details on the parameters structure.
 
-Parameters currently recognised by built-in keymgmt algorithms
-are as follows.
+The Built-in Import/Export Types listed above are also Information Parameters.
 Not all parameters are relevant to, or are understood by all keymgmt
 algorithms:
 
+Parameters currently recognised by built-in keymgmt algorithms
+also include the following.
+
 =over 4
 
 =item "bits" (B<OSSL_PKEY_PARAM_BITS>) <integer>
diff --git a/include/crypto/rsa.h b/include/crypto/rsa.h
index a92e666..3a85510 100644
--- a/include/crypto/rsa.h
+++ b/include/crypto/rsa.h
@@ -40,4 +40,8 @@
 const unsigned char *rsa_digestinfo_encoding(int md_nid, size_t *len);
 const unsigned char *rsa_algorithmidentifier_encoding(int md_nid, size_t *len);
 
+extern const char *rsa_mp_factor_names[];
+extern const char *rsa_mp_exp_names[];
+extern const char *rsa_mp_coeff_names[];
+
 #endif
diff --git a/include/internal/param_build_set.h b/include/internal/param_build_set.h
new file mode 100644
index 0000000..36d3b91
--- /dev/null
+++ b/include/internal/param_build_set.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 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/safestack.h>
+#include <openssl/param_build.h>
+
+int ossl_param_build_set_int(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                             const char *key, int num);
+int ossl_param_build_set_utf8_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                     const char *key, const char *buf);
+int ossl_param_build_set_octet_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                      const char *key,
+                                      const unsigned char *data,
+                                      size_t data_len);
+int ossl_param_build_set_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                            const char *key, const BIGNUM *bn);
+int ossl_param_build_set_bn_pad(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                const char *key, const BIGNUM *bn,  size_t sz);
+int ossl_param_build_set_multi_key_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+                                      const char *names[],
+                                      STACK_OF(BIGNUM_const) *stk);
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 2d48f00..c8a8828 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -220,6 +220,37 @@
 #define OSSL_PKEY_PARAM_RSA_FACTOR      "rsa-factor"
 #define OSSL_PKEY_PARAM_RSA_EXPONENT    "rsa-exponent"
 #define OSSL_PKEY_PARAM_RSA_COEFFICIENT "rsa-coefficient"
+#define OSSL_PKEY_PARAM_RSA_FACTOR1      OSSL_PKEY_PARAM_RSA_FACTOR"1"
+#define OSSL_PKEY_PARAM_RSA_FACTOR2      OSSL_PKEY_PARAM_RSA_FACTOR"2"
+#define OSSL_PKEY_PARAM_RSA_FACTOR3      OSSL_PKEY_PARAM_RSA_FACTOR"3"
+#define OSSL_PKEY_PARAM_RSA_FACTOR4      OSSL_PKEY_PARAM_RSA_FACTOR"4"
+#define OSSL_PKEY_PARAM_RSA_FACTOR5      OSSL_PKEY_PARAM_RSA_FACTOR"5"
+#define OSSL_PKEY_PARAM_RSA_FACTOR6      OSSL_PKEY_PARAM_RSA_FACTOR"6"
+#define OSSL_PKEY_PARAM_RSA_FACTOR7      OSSL_PKEY_PARAM_RSA_FACTOR"7"
+#define OSSL_PKEY_PARAM_RSA_FACTOR8      OSSL_PKEY_PARAM_RSA_FACTOR"8"
+#define OSSL_PKEY_PARAM_RSA_FACTOR9      OSSL_PKEY_PARAM_RSA_FACTOR"9"
+#define OSSL_PKEY_PARAM_RSA_FACTOR10     OSSL_PKEY_PARAM_RSA_FACTOR"10"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT1    OSSL_PKEY_PARAM_RSA_EXPONENT"1"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT2    OSSL_PKEY_PARAM_RSA_EXPONENT"2"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT3    OSSL_PKEY_PARAM_RSA_EXPONENT"3"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT4    OSSL_PKEY_PARAM_RSA_EXPONENT"4"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT5    OSSL_PKEY_PARAM_RSA_EXPONENT"5"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT6    OSSL_PKEY_PARAM_RSA_EXPONENT"6"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT7    OSSL_PKEY_PARAM_RSA_EXPONENT"7"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT8    OSSL_PKEY_PARAM_RSA_EXPONENT"8"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT9    OSSL_PKEY_PARAM_RSA_EXPONENT"9"
+#define OSSL_PKEY_PARAM_RSA_EXPONENT10   OSSL_PKEY_PARAM_RSA_EXPONENT"10"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT1 OSSL_PKEY_PARAM_RSA_COEFFICIENT"1"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT2 OSSL_PKEY_PARAM_RSA_COEFFICIENT"2"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT3 OSSL_PKEY_PARAM_RSA_COEFFICIENT"3"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT4 OSSL_PKEY_PARAM_RSA_COEFFICIENT"4"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT5 OSSL_PKEY_PARAM_RSA_COEFFICIENT"5"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT6 OSSL_PKEY_PARAM_RSA_COEFFICIENT"6"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT7 OSSL_PKEY_PARAM_RSA_COEFFICIENT"7"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT8 OSSL_PKEY_PARAM_RSA_COEFFICIENT"8"
+#define OSSL_PKEY_PARAM_RSA_COEFFICIENT9 OSSL_PKEY_PARAM_RSA_COEFFICIENT"9"
+
+
 /* Key generation parameters */
 #define OSSL_PKEY_PARAM_RSA_BITS        OSSL_PKEY_PARAM_BITS
 #define OSSL_PKEY_PARAM_RSA_PRIMES      "primes"
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index d461f24..4903fc5 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -1593,6 +1593,16 @@
 int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM param[]);
 const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx);
 const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx);
+const OSSL_PARAM *EVP_PKEY_gettable_params(EVP_PKEY *pkey);
+int EVP_PKEY_get_int_param(EVP_PKEY *pkey, const char *key_name, int *out);
+int EVP_PKEY_get_size_t_param(EVP_PKEY *pkey, const char *key_name, size_t *out);
+int EVP_PKEY_get_bn_param(EVP_PKEY *pkey, const char *key_name, BIGNUM **bn);
+int EVP_PKEY_get_utf8_string_param(EVP_PKEY *pkey, const char *key_name,
+                                    char *str, size_t max_buf_sz, size_t *out_sz);
+int EVP_PKEY_get_octet_string_param(EVP_PKEY *pkey, const char *key_name,
+                                    unsigned char *buf, size_t max_buf_sz,
+                                    size_t *out_sz);
+
 int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
 int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
diff --git a/providers/implementations/keymgmt/build.info b/providers/implementations/keymgmt/build.info
index 89d33e3..92cac52 100644
--- a/providers/implementations/keymgmt/build.info
+++ b/providers/implementations/keymgmt/build.info
@@ -4,7 +4,6 @@
 $DH_GOAL=../../libimplementations.a
 $DSA_GOAL=../../libimplementations.a
 $EC_GOAL=../../libimplementations.a
-$RSA_GOAL=../../libimplementations.a
 $ECX_GOAL=../../libimplementations.a
 
 IF[{- !$disabled{dh} -}]
@@ -16,7 +15,9 @@
 IF[{- !$disabled{ec} -}]
   SOURCE[$EC_GOAL]=ec_kmgmt.c
 ENDIF
-SOURCE[$RSA_GOAL]=rsa_kmgmt.c
 IF[{- !$disabled{ec} -}]
   SOURCE[$ECX_GOAL]=ecx_kmgmt.c
 ENDIF
+
+SOURCE[../../libfips.a]=rsa_kmgmt.c
+SOURCE[../../libnonfips.a]=rsa_kmgmt.c
diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index 82ef3d3..77d4753 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -17,13 +17,12 @@
 #include <openssl/core_names.h>
 #include <openssl/bn.h>
 #include <openssl/objects.h>
-#include <openssl/params.h>
 #include "crypto/bn.h"
 #include "crypto/ec.h"
-#include "openssl/param_build.h"
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
 #include "prov/provider_ctx.h"
+#include "internal/param_build_set.h"
 
 static OSSL_OP_keymgmt_new_fn ec_newdata;
 static OSSL_OP_keymgmt_free_fn ec_freedata;
@@ -40,8 +39,8 @@
 static OSSL_OP_keymgmt_export_types_fn ec_export_types;
 static OSSL_OP_keymgmt_query_operation_name_fn ec_query_operation_name;
 
-#define EC_POSSIBLE_SELECTIONS                 \
-    (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS )
+#define EC_POSSIBLE_SELECTIONS                                                 \
+    (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS)
 
 static
 const char *ec_query_operation_name(int operation_id)
@@ -56,7 +55,8 @@
 }
 
 static ossl_inline
-int domparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
+int domparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl,
+                        OSSL_PARAM params[])
 {
     const EC_GROUP *ecg;
     int curve_nid;
@@ -71,11 +71,7 @@
     curve_nid = EC_GROUP_get_curve_name(ecg);
 
     if (curve_nid == NID_undef) {
-        /* explicit parameters */
-
-        /*
-         * TODO(3.0): should we support explicit parameters curves?
-         */
+        /* TODO(3.0): should we support explicit parameters curves? */
         return 0;
     } else {
         /* named curve */
@@ -83,9 +79,10 @@
 
         if ((curve_name = ec_curve_nid2name(curve_nid)) == NULL)
             return 0;
+        if (!ossl_param_build_set_utf8_string(tmpl, params,
+                                              OSSL_PKEY_PARAM_EC_NAME,
+                                              curve_name))
 
-        if (!OSSL_PARAM_BLD_push_utf8_string(tmpl, OSSL_PKEY_PARAM_EC_NAME,
-                                             curve_name, 0))
             return 0;
     }
 
@@ -100,12 +97,13 @@
  * parameters are exported separately.
  */
 static ossl_inline
-int key_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl, int include_private)
+int key_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl,
+                  OSSL_PARAM params[], int include_private,
+                  unsigned char **pub_key)
 {
     const BIGNUM *priv_key = NULL;
     const EC_POINT *pub_point = NULL;
     const EC_GROUP *ecg = NULL;
-    unsigned char *pub_key = NULL;
     size_t pub_key_len = 0;
     int ret = 0;
 
@@ -120,10 +118,10 @@
         /* convert pub_point to a octet string according to the SECG standard */
         if ((pub_key_len = EC_POINT_point2buf(ecg, pub_point,
                                               POINT_CONVERSION_COMPRESSED,
-                                              &pub_key, NULL)) == 0
-            || !OSSL_PARAM_BLD_push_octet_string(tmpl,
-                                                 OSSL_PKEY_PARAM_PUB_KEY,
-                                                 pub_key, pub_key_len))
+                                              pub_key, NULL)) == 0
+            || !ossl_param_build_set_octet_string(tmpl, params,
+                                                  OSSL_PKEY_PARAM_PUB_KEY,
+                                                  *pub_key, pub_key_len))
             goto err;
     }
 
@@ -168,21 +166,20 @@
         if (ecbits <= 0)
             goto err;
         sz = (ecbits + 7 ) / 8;
-        if (!OSSL_PARAM_BLD_push_BN_pad(tmpl,
-                                        OSSL_PKEY_PARAM_PRIV_KEY,
-                                        priv_key, sz))
+
+        if (!ossl_param_build_set_bn_pad(tmpl, params,
+                                         OSSL_PKEY_PARAM_PRIV_KEY,
+                                         priv_key, sz))
             goto err;
     }
-
     ret = 1;
-
  err:
-    OPENSSL_free(pub_key);
     return ret;
 }
 
 static ossl_inline
-int otherparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl)
+int otherparams_to_params(const EC_KEY *ec, OSSL_PARAM_BLD *tmpl,
+                          OSSL_PARAM params[])
 {
     int ecdh_cofactor_mode = 0;
 
@@ -191,12 +188,9 @@
 
     ecdh_cofactor_mode =
         (EC_KEY_get_flags(ec) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
-    if (!OSSL_PARAM_BLD_push_int(tmpl,
-                OSSL_PKEY_PARAM_USE_COFACTOR_ECDH,
-                ecdh_cofactor_mode))
-        return 0;
-
-    return 1;
+    return ossl_param_build_set_int(tmpl, params,
+                                    OSSL_PKEY_PARAM_USE_COFACTOR_ECDH,
+                                    ecdh_cofactor_mode);
 }
 
 static
@@ -314,6 +308,7 @@
     EC_KEY *ec = keydata;
     OSSL_PARAM_BLD *tmpl;
     OSSL_PARAM *params = NULL;
+    unsigned char *pub_key = NULL;
     int ok = 1;
 
     if (ec == NULL)
@@ -346,15 +341,16 @@
         return 0;
 
     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
-        ok = ok && domparams_to_params(ec, tmpl);
+        ok = ok && domparams_to_params(ec, tmpl, NULL);
+
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
         int include_private =
             selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
 
-        ok = ok && key_to_params(ec, tmpl, include_private);
+        ok = ok && key_to_params(ec, tmpl, NULL, include_private, &pub_key);
     }
     if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
-        ok = ok && otherparams_to_params(ec, tmpl);
+        ok = ok && otherparams_to_params(ec, tmpl, NULL);
 
     if (!ok
         || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL)
@@ -364,6 +360,7 @@
     OSSL_PARAM_BLD_free_params(params);
 err:
     OSSL_PARAM_BLD_free(tmpl);
+    OPENSSL_free(pub_key);
     return ok;
 }
 
@@ -423,9 +420,11 @@
 static
 int ec_get_params(void *key, OSSL_PARAM params[])
 {
+    int ret;
     EC_KEY *eck = key;
     const EC_GROUP *ecg = NULL;
     OSSL_PARAM *p;
+    unsigned char *pub_key = NULL;
 
     ecg = EC_KEY_get0_group(eck);
     if (ecg == NULL)
@@ -485,15 +484,21 @@
         if (!OSSL_PARAM_set_int(p, ecdh_cofactor_mode))
             return 0;
     }
-
-    return 1;
+    ret = domparams_to_params(eck, NULL, params)
+          && key_to_params(eck, NULL, params, 1, &pub_key)
+          && otherparams_to_params(eck, NULL, params);
+    OPENSSL_free(pub_key);
+    return ret;
 }
 
 static const OSSL_PARAM ec_known_gettable_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
-    OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL),
+    EC_IMEXPORTABLE_DOM_PARAMETERS,
+    EC_IMEXPORTABLE_PUBLIC_KEY,
+    EC_IMEXPORTABLE_PRIVATE_KEY,
+    EC_IMEXPORTABLE_OTHER_PARAMETERS,
     OSSL_PARAM_END
 };
 
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c
index be11f0b..ca53a93 100644
--- a/providers/implementations/keymgmt/ecx_kmgmt.c
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -10,11 +10,10 @@
 #include <assert.h>
 #include <openssl/core_numbers.h>
 #include <openssl/core_names.h>
-#include <openssl/params.h>
-#include "openssl/param_build.h"
 #include "crypto/ecx.h"
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
+#include "internal/param_build_set.h"
 
 static OSSL_OP_keymgmt_new_fn x25519_new_key;
 static OSSL_OP_keymgmt_new_fn x448_new_key;
@@ -90,18 +89,21 @@
     return ok;
 }
 
-static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl)
+static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl,
+                         OSSL_PARAM params[])
 {
     if (key == NULL)
         return 0;
 
-    if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY,
-                                          key->pubkey, key->keylen))
+    if (!ossl_param_build_set_octet_string(tmpl, params,
+                                           OSSL_PKEY_PARAM_PUB_KEY,
+                                           key->pubkey, key->keylen))
         return 0;
 
     if (key->privkey != NULL
-        && !OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PRIV_KEY,
-                                             key->privkey, key->keylen))
+        && !ossl_param_build_set_octet_string(tmpl, params,
+                                              OSSL_PKEY_PARAM_PRIV_KEY,
+                                              key->privkey, key->keylen))
         return 0;
 
     return 1;
@@ -113,7 +115,7 @@
     ECX_KEY *key = keydata;
     OSSL_PARAM_BLD *tmpl;
     OSSL_PARAM *params = NULL;
-    int ret;
+    int ret = 0;
 
     if (key == NULL)
         return 0;
@@ -123,24 +125,30 @@
         return 0;
 
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0
-            && !key_to_params(key, tmpl)) {
-        OSSL_PARAM_BLD_free(tmpl);
-        return 0;
-    }
+         && !key_to_params(key, tmpl, NULL))
+        goto err;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0
+         && !key_to_params(key, tmpl, NULL))
+        goto err;
 
     params = OSSL_PARAM_BLD_to_param(tmpl);
-    OSSL_PARAM_BLD_free(tmpl);
     if (params == NULL)
-        return 0;
+        goto err;
 
     ret = param_cb(params, cbarg);
     OSSL_PARAM_BLD_free_params(params);
+err:
+    OSSL_PARAM_BLD_free(tmpl);
     return ret;
 }
 
+#define ECX_KEY_TYPES()                                                        \
+OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),                     \
+OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
+
 static const OSSL_PARAM ecx_key_types[] = {
-    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
-    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
+    ECX_KEY_TYPES(),
     OSSL_PARAM_END
 };
 static const OSSL_PARAM *ecx_imexport_types(int selection)
@@ -150,9 +158,10 @@
     return NULL;
 }
 
-static int ecx_get_params(OSSL_PARAM params[], int bits, int secbits,
+static int ecx_get_params(void *key, OSSL_PARAM params[], int bits, int secbits,
                           int size)
 {
+    ECX_KEY *ecx = key;
     OSSL_PARAM *p;
 
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
@@ -164,33 +173,38 @@
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
         && !OSSL_PARAM_set_int(p, size))
         return 0;
-    return 1;
+    return key_to_params(ecx, NULL, params);
 }
 
 static int x25519_get_params(void *key, OSSL_PARAM params[])
 {
-    return ecx_get_params(params, X25519_BITS, X25519_SECURITY_BITS, X25519_KEYLEN);
+    return ecx_get_params(key, params, X25519_BITS, X25519_SECURITY_BITS,
+                          X25519_KEYLEN);
 }
 
 static int x448_get_params(void *key, OSSL_PARAM params[])
 {
-    return ecx_get_params(params, X448_BITS, X448_SECURITY_BITS, X448_KEYLEN);
+    return ecx_get_params(key, params, X448_BITS, X448_SECURITY_BITS,
+                          X448_KEYLEN);
 }
 
 static int ed25519_get_params(void *key, OSSL_PARAM params[])
 {
-    return ecx_get_params(params, ED25519_BITS, ED25519_SECURITY_BITS, ED25519_KEYLEN);
+    return ecx_get_params(key, params, ED25519_BITS, ED25519_SECURITY_BITS,
+                          ED25519_KEYLEN);
 }
 
 static int ed448_get_params(void *key, OSSL_PARAM params[])
 {
-    return ecx_get_params(params, ED448_BITS, ED448_SECURITY_BITS, ED448_KEYLEN);
+    return ecx_get_params(key, params, ED448_BITS, ED448_SECURITY_BITS,
+                          ED448_KEYLEN);
 }
 
 static const OSSL_PARAM ecx_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
+    ECX_KEY_TYPES(),
     OSSL_PARAM_END
 };
 
diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c
index 50647eb..8ea3941 100644
--- a/providers/implementations/keymgmt/rsa_kmgmt.c
+++ b/providers/implementations/keymgmt/rsa_kmgmt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 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
@@ -19,13 +19,11 @@
 #include <openssl/err.h>
 #include <openssl/rsa.h>
 #include <openssl/evp.h>
-#include <openssl/params.h>
-#include <openssl/types.h>
-#include "openssl/param_build.h"
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
 #include "prov/provider_ctx.h"
 #include "crypto/rsa.h"
+#include "internal/param_build_set.h"
 
 static OSSL_OP_keymgmt_new_fn rsa_newdata;
 static OSSL_OP_keymgmt_gen_init_fn rsa_gen_init;
@@ -45,32 +43,13 @@
 static OSSL_OP_keymgmt_export_types_fn rsa_export_types;
 
 #define RSA_DEFAULT_MD "SHA256"
-#define RSA_POSSIBLE_SELECTIONS                 \
+#define RSA_POSSIBLE_SELECTIONS                                                \
     (OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS)
 
 DEFINE_STACK_OF(BIGNUM)
 DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM)
 
-static int export_numbers(OSSL_PARAM_BLD *tmpl, const char *key,
-                          STACK_OF(BIGNUM_const) *numbers)
-{
-    int i, nnum;
-
-    if (numbers == NULL)
-        return 0;
-
-    nnum = sk_BIGNUM_const_num(numbers);
-
-    for (i = 0; i < nnum; i++) {
-        if (!OSSL_PARAM_BLD_push_BN(tmpl, key,
-                                    sk_BIGNUM_const_value(numbers, i)))
-            return 0;
-    }
-
-    return 1;
-}
-
-static int key_to_params(RSA *rsa, OSSL_PARAM_BLD *tmpl)
+static int key_to_params(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
 {
     int ret = 0;
     const BIGNUM *rsa_d = NULL, *rsa_n = NULL, *rsa_e = NULL;
@@ -84,21 +63,16 @@
     RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
     rsa_get0_all_params(rsa, factors, exps, coeffs);
 
-    if (rsa_n != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_N, rsa_n))
+    if (!ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_RSA_N, rsa_n)
+        || !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_RSA_E, rsa_e)
+        || !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_RSA_D, rsa_d)
+        || !ossl_param_build_set_multi_key_bn(bld, params, rsa_mp_factor_names,
+                                              factors)
+        || !ossl_param_build_set_multi_key_bn(bld, params, rsa_mp_exp_names,
+                                              exps)
+        || !ossl_param_build_set_multi_key_bn(bld, params, rsa_mp_coeff_names,
+                                              coeffs))
         goto err;
-    if (rsa_e != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_E, rsa_e))
-        goto err;
-    if (rsa_d != NULL
-        && !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_RSA_D, rsa_d))
-        goto err;
-
-    if (!export_numbers(tmpl, OSSL_PKEY_PARAM_RSA_FACTOR, factors)
-        || !export_numbers(tmpl, OSSL_PKEY_PARAM_RSA_EXPONENT, exps)
-        || !export_numbers(tmpl, OSSL_PKEY_PARAM_RSA_COEFFICIENT, coeffs))
-        goto err;
-
     ret = 1;
  err:
     sk_BIGNUM_const_free(factors);
@@ -189,20 +163,70 @@
         return 0;
 
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
-        ok = ok && key_to_params(rsa, tmpl);
+        ok = ok && key_to_params(rsa, tmpl, NULL);
 
     if (!ok
-        || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) {
-        OSSL_PARAM_BLD_free(tmpl);
-        return 0;
-    }
-    OSSL_PARAM_BLD_free(tmpl);
+        || (params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL)
+        goto err;
 
     ok = param_callback(params, cbarg);
     OSSL_PARAM_BLD_free_params(params);
+err:
+    OSSL_PARAM_BLD_free(tmpl);
     return ok;
 }
 
+#ifdef FIPS_MODE
+/* In fips mode there are no multi-primes. */
+# define RSA_KEY_MP_TYPES()                                                    \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR1, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR2, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT1, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT2, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, NULL, 0),
+#else
+/*
+ * We allow up to 10 prime factors (starting with p, q).
+ * NOTE: there is only 9 OSSL_PKEY_PARAM_RSA_COEFFICIENT
+ */
+# define RSA_KEY_MP_TYPES()                                                    \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR1, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR2, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR3, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR4, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR5, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR6, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR7, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR8, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR9, NULL, 0),                           \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR10, NULL, 0),                          \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT1, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT2, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT3, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT4, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT5, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT6, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT7, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT8, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT9, NULL, 0),                         \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT10, NULL, 0),                        \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT2, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT3, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT4, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT5, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT6, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT7, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT8, NULL, 0),                      \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT9, NULL, 0),
+#endif
+
+#define RSA_KEY_TYPES()                                                        \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0),                                 \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0),                                 \
+OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_D, NULL, 0),                                 \
+RSA_KEY_MP_TYPES()
+
 /*
  * This provider can export everything in an RSA key, so we use the exact
  * same type description for export as for import.  Other providers might
@@ -211,41 +235,8 @@
  * different arrays.
  */
 static const OSSL_PARAM rsa_key_types[] = {
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_D, NULL, 0),
-    /* We tolerate up to 10 factors... */
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR, NULL, 0),
-    /* ..., up to 10 CRT exponents... */
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT, NULL, 0),
-    /* ..., and up to 9 CRT coefficients */
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT, NULL, 0),
+    RSA_KEY_TYPES()
+    OSSL_PARAM_END
 };
 /*
  * We lied about the amount of factors, exponents and coefficients, the
@@ -266,7 +257,6 @@
     return rsa_imexport_types(selection);
 }
 
-
 static const OSSL_PARAM *rsa_export_types(int selection)
 {
     return rsa_imexport_types(selection);
@@ -312,8 +302,7 @@
         if (!OSSL_PARAM_set_utf8_string(p, RSA_DEFAULT_MD))
             return 0;
     }
-
-    return 1;
+    return key_to_params(rsa, NULL, params);
 }
 
 static const OSSL_PARAM rsa_params[] = {
@@ -321,6 +310,7 @@
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
     OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0),
+    RSA_KEY_TYPES()
     OSSL_PARAM_END
 };
 
diff --git a/providers/implementations/serializers/serializer_rsa.c b/providers/implementations/serializers/serializer_rsa.c
index ddc7074..21898f9 100644
--- a/providers/implementations/serializers/serializer_rsa.c
+++ b/providers/implementations/serializers/serializer_rsa.c
@@ -116,4 +116,3 @@
     sk_BIGNUM_const_free(coeffs);
     return ret;
 }
-
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c
index 6ba61c3..9f8d008 100644
--- a/test/evp_pkey_provided_test.c
+++ b/test/evp_pkey_provided_test.c
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <string.h> /* memset */
 #include <openssl/evp.h>
 #include <openssl/pem.h>
 #include <openssl/serializer.h>
@@ -260,7 +261,7 @@
 
 static int test_fromdata_rsa(void)
 {
-    int ret = 0;
+    int ret = 0, i;
     EVP_PKEY_CTX *ctx = NULL, *key_ctx = NULL;
     EVP_PKEY *pk = NULL, *copy_pk = NULL;
     /*
@@ -283,13 +284,15 @@
         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_N, &key_numbers[N]),
         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_E, &key_numbers[E]),
         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_D, &key_numbers[D]),
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_FACTOR, &key_numbers[P]),
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_FACTOR, &key_numbers[Q]),
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_EXPONENT, &key_numbers[DP]),
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_EXPONENT, &key_numbers[DQ]),
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_COEFFICIENT, &key_numbers[QINV]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_FACTOR1, &key_numbers[P]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_FACTOR2, &key_numbers[Q]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_EXPONENT1, &key_numbers[DP]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_EXPONENT2, &key_numbers[DQ]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &key_numbers[QINV]),
         OSSL_PARAM_END
     };
+    BIGNUM *bn = BN_new();
+    BIGNUM *bn_from = BN_new();
 
     if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)))
         goto err;
@@ -315,10 +318,17 @@
         || !TEST_false(EVP_PKEY_copy_parameters(copy_pk, pk)))
         goto err;
 
+    for (i = 0; fromdata_params[i].key != NULL; ++i) {
+        if (!TEST_true(BN_set_word(bn_from, key_numbers[i]))
+            || !TEST_true(EVP_PKEY_get_bn_param(pk, fromdata_params[i].key, &bn))
+            || !TEST_BN_eq(bn, bn_from))
+            goto err;
+    }
     ret = test_print_key_using_pem("RSA", pk)
           && test_print_key_using_serializer("RSA", pk);
-
  err:
+    BN_free(bn_from);
+    BN_free(bn);
     EVP_PKEY_free(pk);
     EVP_PKEY_free(copy_pk);
     EVP_PKEY_CTX_free(key_ctx);
@@ -327,6 +337,59 @@
     return ret;
 }
 
+static int test_evp_pkey_get_bn_param_large(void)
+{
+    int ret = 0;
+    EVP_PKEY_CTX *ctx = NULL, *key_ctx = NULL;
+    EVP_PKEY *pk = NULL;
+    OSSL_PARAM_BLD *bld = NULL;
+    OSSL_PARAM *fromdata_params = NULL;
+    BIGNUM *n = NULL, *e = NULL, *d = NULL, *n_out = NULL;
+    /*
+     * The buffer size chosen here for n_data larger than the buffer used
+     * internally in EVP_PKEY_get_bn_param.
+     */
+    static unsigned char n_data[2050];
+    static const unsigned char e_data[] = {
+        0x1, 0x00, 0x01
+    };
+    static const unsigned char d_data[]= {
+       0x99, 0x33, 0x13, 0x7b
+    };
+
+    /* N is a large buffer */
+    memset(n_data, 0xCE, sizeof(n_data));
+
+    if (!TEST_ptr(bld = OSSL_PARAM_BLD_new())
+        || !TEST_ptr(n = BN_bin2bn(n_data, sizeof(n_data), NULL))
+        || !TEST_ptr(e = BN_bin2bn(e_data, sizeof(e_data), NULL))
+        || !TEST_ptr(d = BN_bin2bn(d_data, sizeof(d_data), NULL))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e))
+        || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d))
+        || !TEST_ptr(fromdata_params = OSSL_PARAM_BLD_to_param(bld))
+        || !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL))
+        || !TEST_true(EVP_PKEY_key_fromdata_init(ctx))
+        || !TEST_true(EVP_PKEY_fromdata(ctx, &pk, fromdata_params))
+        || !TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pk, ""))
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_N, &n_out))
+        || !TEST_BN_eq(n, n_out))
+        goto err;
+    ret = 1;
+ err:
+    BN_free(n_out);
+    BN_free(n);
+    BN_free(e);
+    BN_free(d);
+    EVP_PKEY_free(pk);
+    EVP_PKEY_CTX_free(key_ctx);
+    EVP_PKEY_CTX_free(ctx);
+    OSSL_PARAM_BLD_free_params(fromdata_params);
+    OSSL_PARAM_BLD_free(bld);
+    return ret;
+}
+
+
 #ifndef OPENSSL_NO_DH
 /* Array indexes used in test_fromdata_dh */
 #define PRIV_KEY        0
@@ -412,6 +475,9 @@
     EVP_PKEY_CTX *ctx = NULL;
     EVP_PKEY *pk = NULL, *copy_pk = NULL;
     const char *alg = NULL;
+    size_t len;
+    unsigned char out_pub[ED448_KEYLEN];
+    unsigned char out_priv[ED448_KEYLEN];
 
     /* ED448_KEYLEN > X448_KEYLEN > X25519_KEYLEN == ED25519_KEYLEN */
     static unsigned char key_numbers[4][2][ED448_KEYLEN] = {
@@ -580,6 +646,20 @@
         || !TEST_false(EVP_PKEY_copy_parameters(copy_pk, pk)))
         goto err;
 
+    if (!TEST_true(EVP_PKEY_get_octet_string_param(
+                       pk, fromdata_params[PRIV_KEY].key,
+                       out_priv, sizeof(out_priv), &len))
+        || !TEST_mem_eq(out_priv, len,
+                        fromdata_params[PRIV_KEY].data,
+                        fromdata_params[PRIV_KEY].data_size)
+        || !TEST_true(EVP_PKEY_get_octet_string_param(
+                          pk, fromdata_params[PUB_KEY].key,
+                          out_pub, sizeof(out_pub), &len))
+        || !TEST_mem_eq(out_pub, len,
+                        fromdata_params[PUB_KEY].data,
+                        fromdata_params[PUB_KEY].data_size))
+        goto err;
+
     ret = test_print_key_using_pem(alg, pk)
           && test_print_key_using_serializer(alg, pk);
 
@@ -591,6 +671,8 @@
     return ret;
 }
 
+#define CURVE_NAME 2
+
 static int test_fromdata_ec(void)
 {
     int ret = 0;
@@ -598,10 +680,13 @@
     EVP_PKEY *pk = NULL, *copy_pk = NULL;
     OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
     BIGNUM *ec_priv_bn = NULL;
+    BIGNUM *bn_priv = NULL;
     OSSL_PARAM *fromdata_params = NULL;
     const char *alg = "EC";
+    const char *curve = "prime256v1";
+    /* UNCOMPRESSED FORMAT */
     static const unsigned char ec_pub_keydata[] = {
-       0x04,
+       POINT_CONVERSION_UNCOMPRESSED,
        0x1b, 0x93, 0x67, 0x55, 0x1c, 0x55, 0x9f, 0x63,
        0xd1, 0x22, 0xa4, 0xd8, 0xd1, 0x0a, 0x60, 0x6d,
        0x02, 0xa5, 0x77, 0x57, 0xc8, 0xa3, 0x47, 0x73,
@@ -617,6 +702,12 @@
         0xcc, 0x0d, 0x9a, 0x24, 0x6c, 0x86, 0x1b, 0x2e,
         0xdc, 0x4b, 0x4d, 0x35, 0x43, 0xe1, 0x1b, 0xad
     };
+    const int compressed_sz = 1 + (sizeof(ec_pub_keydata) - 1) / 2;
+    unsigned char out_pub[sizeof(ec_pub_keydata)];
+    char out_curve_name[80];
+    const OSSL_PARAM *gettable = NULL;
+    size_t len;
+
 
     if (!TEST_ptr(bld))
         goto err;
@@ -625,7 +716,7 @@
         goto err;
 
     if (OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_EC_NAME,
-                                        "prime256v1", 0) <= 0)
+                                        curve, 0) <= 0)
         goto err;
     if (OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY,
                                          ec_pub_keydata,
@@ -650,9 +741,30 @@
         || !TEST_true(EVP_PKEY_copy_parameters(copy_pk, pk)))
         goto err;
 
+    if (!TEST_ptr(gettable = EVP_PKEY_gettable_params(pk))
+        || !TEST_ptr(OSSL_PARAM_locate_const(gettable, OSSL_PKEY_PARAM_EC_NAME))
+        || !TEST_ptr(OSSL_PARAM_locate_const(gettable, OSSL_PKEY_PARAM_PUB_KEY))
+        || !TEST_ptr(OSSL_PARAM_locate_const(gettable, OSSL_PKEY_PARAM_PRIV_KEY)))
+        goto err;
+
+    if (!EVP_PKEY_get_utf8_string_param(pk, OSSL_PKEY_PARAM_EC_NAME,
+                                        out_curve_name, sizeof(out_curve_name),
+                                        &len)
+        || !TEST_str_eq(out_curve_name, curve)
+        || !EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY,
+                                            out_pub, sizeof(out_pub), &len)
+        || !TEST_true(out_pub[0] == (POINT_CONVERSION_COMPRESSED + 1))
+        || !TEST_mem_eq(out_pub + 1, len - 1,
+                        ec_pub_keydata + 1, compressed_sz - 1)
+        || !TEST_true(EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_PRIV_KEY,
+                                            &bn_priv))
+        || !TEST_BN_eq(ec_priv_bn, bn_priv))
+        goto err;
+
     ret = test_print_key_using_pem(alg, pk)
           && test_print_key_using_serializer(alg, pk);
 err:
+    BN_free(bn_priv);
     BN_free(ec_priv_bn);
     OSSL_PARAM_BLD_free_params(fromdata_params);
     OSSL_PARAM_BLD_free(bld);
@@ -674,6 +786,7 @@
     if (!TEST_ptr(datadir = test_get_argument(0)))
         return 0;
 
+    ADD_TEST(test_evp_pkey_get_bn_param_large);
     ADD_TEST(test_fromdata_rsa);
 #ifndef OPENSSL_NO_DH
     ADD_TEST(test_fromdata_dh);
diff --git a/test/keymgmt_internal_test.c b/test/keymgmt_internal_test.c
index fd60893..d30b3a7 100644
--- a/test/keymgmt_internal_test.c
+++ b/test/keymgmt_internal_test.c
@@ -66,7 +66,7 @@
 #define DQ      7
 #define E3      8                /* Extra exponent */
 #define QINV    9
-#define C3      10               /* Extra coefficient */
+#define C2      10               /* Extra coefficient */
 
 /*
  * We have to do this because OSSL_PARAM_get_ulong() can't handle params
@@ -92,10 +92,6 @@
 {
     unsigned long *keydata = arg;
     const OSSL_PARAM *p = NULL;
-    int factors_idx;
-    int exponents_idx;
-    int coefficients_idx;
-    int ret = 1;                 /* Ever so hopeful */
 
     if (keydata == NULL)
         return 0;
@@ -106,35 +102,31 @@
         || !TEST_true(get_ulong_via_BN(p, &keydata[E]))
         || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D))
         || !TEST_true(get_ulong_via_BN(p, &keydata[D])))
-        ret = 0;
+        return 0;
 
-    for (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR),
-             factors_idx = P;
-         p != NULL && factors_idx <= F3;
-         p = OSSL_PARAM_locate_const(p + 1, OSSL_PKEY_PARAM_RSA_FACTOR),
-         factors_idx++)
-        if (!TEST_true(get_ulong_via_BN(p, &keydata[factors_idx])))
-            ret = 0;
-    for (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT),
-             exponents_idx = DP;
-         p != NULL && exponents_idx <= E3;
-         p = OSSL_PARAM_locate_const(p + 1, OSSL_PKEY_PARAM_RSA_EXPONENT),
-         exponents_idx++)
-        if (!TEST_true(get_ulong_via_BN(p, &keydata[exponents_idx])))
-            ret = 0;
-    for (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT),
-             coefficients_idx = QINV;
-         p != NULL && coefficients_idx <= C3;
-         p = OSSL_PARAM_locate_const(p + 1, OSSL_PKEY_PARAM_RSA_COEFFICIENT),
-         coefficients_idx++)
-        if (!TEST_true(get_ulong_via_BN(p, &keydata[coefficients_idx])))
-            ret = 0;
+    if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR1))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[P]))
+        || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR2))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[Q]))
+        || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR3))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[F3])))
+        return 0;
 
-    if (!TEST_int_le(factors_idx, F3)
-        || !TEST_int_le(exponents_idx, E3)
-        || !TEST_int_le(coefficients_idx, C3))
-        ret = 0;
-    return ret;
+    if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT1))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[DP]))
+        || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT2))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[DQ]))
+        || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_EXPONENT3))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[E3])))
+        return 0;
+
+    if (!TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT1))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[QINV]))
+        || !TEST_ptr(p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT2))
+        || !TEST_true(get_ulong_via_BN(p, &keydata[C2])))
+        return 0;
+
+    return 1;
 }
 
 static int test_pass_rsa(FIXTURE *fixture)
@@ -146,9 +138,13 @@
     EVP_PKEY *pk = NULL;
     EVP_KEYMGMT *km1 = NULL, *km2 = NULL;
     void *provkey = NULL;
+    BIGNUM *bn_primes[1] = { NULL };
+    BIGNUM *bn_exps[1] = { NULL };
+    BIGNUM *bn_coeffs[1] = { NULL };
     /*
      * 32-bit RSA key, extracted from this command,
      * executed with OpenSSL 1.0.2:
+     * An extra factor was added just for testing purposes.
      *
      * openssl genrsa 32 | openssl rsa -text
      */
@@ -158,12 +154,12 @@
         0x7b133399,              /* D */
         0xe963,                  /* P */
         0xceb7,                  /* Q */
-        0,                       /* F3 */
+        1,                       /* F3 */
         0x8599,                  /* DP */
         0xbd87,                  /* DQ */
-        0,                       /* E3 */
+        2,                       /* E3 */
         0xcc3b,                  /* QINV */
-        0,                       /* C3 */
+        3,                       /* C3 */
         0                        /* Extra, should remain zero */
     };
     static unsigned long keydata[OSSL_NELEM(expected)] = { 0, };
@@ -197,6 +193,16 @@
         goto err;
     bn1 = bn2 = bn3 = NULL;
 
+    if (!TEST_ptr(bn_primes[0] = BN_new())
+        || !TEST_true(BN_set_word(bn_primes[0], expected[F3]))
+        || !TEST_ptr(bn_exps[0] = BN_new())
+        || !TEST_true(BN_set_word(bn_exps[0], expected[E3]))
+        || !TEST_ptr(bn_coeffs[0] = BN_new())
+        || !TEST_true(BN_set_word(bn_coeffs[0], expected[C2]))
+        || !TEST_true(RSA_set0_multi_prime_params(rsa, bn_primes, bn_exps,
+                                                  bn_coeffs, 1)))
+        goto err;
+
     if (!TEST_ptr(pk = EVP_PKEY_new())
         || !TEST_true(EVP_PKEY_assign_RSA(pk, rsa)))
         goto err;
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 9fc7cfc..cd0a7d8 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5030,3 +5030,9 @@
 SRP_Calc_x_ex                           ?	3_0_0	EXIST::FUNCTION:SRP
 SRP_Calc_client_key_ex                  ?	3_0_0	EXIST::FUNCTION:SRP
 X509v3_cache_extensions                 ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_gettable_params                ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_get_int_param                  ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_get_size_t_param               ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_get_bn_param                   ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_get_utf8_string_param          ?	3_0_0	EXIST::FUNCTION:
+EVP_PKEY_get_octet_string_param         ?	3_0_0	EXIST::FUNCTION: