Commit 55aeaef7d5 for openssl.org

commit 55aeaef7d55fa792fde39146311450064b608196
Author: Pauli <paul.dale@oracle.com>
Date:   Tue Aug 25 11:19:35 2026 +1000

    rsa: use generated tries in crypto helpers

    Assisted-by: ChatGPT:gpt-5.6Sol

    Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    (Merged from https://github.com/openssl/openssl/pull/32502)

diff --git a/crypto/rsa/rsa_acvp_test_params.c b/crypto/rsa/rsa_acvp_test_params.c
index 77e1c39c3e..8fefbddaaf 100644
--- a/crypto/rsa/rsa_acvp_test_params.c
+++ b/crypto/rsa/rsa_acvp_test_params.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2026 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
@@ -11,12 +11,18 @@
 #include <openssl/core_names.h>
 #include <openssl/param_build.h>
 #include "crypto/rsa.h"
+#include "crypto/rsa_params.h"
 #include "rsa_local.h"

-int ossl_rsa_acvp_test_gen_params_new(OSSL_PARAM **dst, const OSSL_PARAM src[])
+int ossl_rsa_acvp_test_gen_params_new_parsed(OSSL_PARAM **dst,
+    const RSA_PARAMS *params)
 {
-    const OSSL_PARAM *p, *s;
     OSSL_PARAM *d, *alloc = NULL;
+    const OSSL_PARAM *src[] = {
+        params->fips.xp, params->fips.xp1, params->fips.xp2,
+        params->fips.xq, params->fips.xq1, params->fips.xq2
+    };
+    size_t i;
     int ret = 1;

     static const OSSL_PARAM settable[] = {
@@ -29,9 +35,11 @@ int ossl_rsa_acvp_test_gen_params_new(OSSL_PARAM **dst, const OSSL_PARAM src[])
         OSSL_PARAM_END
     };

-    /* Assume the first element is a required field if this feature is used */
-    p = OSSL_PARAM_locate_const(src, settable[0].key);
-    if (p == NULL)
+    if (dst == NULL || params == NULL)
+        return 0;
+
+    /* Xp is required whenever the ACVP test interface is used. */
+    if (src[0] == NULL)
         return 1;

     /* Zeroing here means the terminator is always set at the end */
@@ -40,16 +48,16 @@ int ossl_rsa_acvp_test_gen_params_new(OSSL_PARAM **dst, const OSSL_PARAM src[])
         return 0;

     d = alloc;
-    for (s = settable; s->key != NULL; ++s) {
-        /* If src contains a key from settable then copy the src to the dest */
-        p = OSSL_PARAM_locate_const(src, s->key);
-        if (p != NULL) {
-            *d = *s; /* shallow copy from the static settable[] */
-            d->data_size = p->data_size;
-            d->data = OPENSSL_memdup(p->data, p->data_size);
-            if (d->data == NULL)
+    for (i = 0; i < OSSL_NELEM(src); i++) {
+        if (src[i] != NULL) {
+            *d = settable[i];
+            d->data_size = src[i]->data_size;
+            d->data = OPENSSL_memdup(src[i]->data, src[i]->data_size);
+            if (d->data == NULL) {
                 ret = 0;
-            ++d;
+                break;
+            }
+            d++;
         }
     }
     if (ret == 0) {
@@ -62,6 +70,16 @@ int ossl_rsa_acvp_test_gen_params_new(OSSL_PARAM **dst, const OSSL_PARAM src[])
     return ret;
 }

+int ossl_rsa_acvp_test_gen_params_new(OSSL_PARAM **dst,
+    const OSSL_PARAM src[])
+{
+    RSA_PARAMS params;
+
+    if (!rsa_acvp_input_decoder(src, &params))
+        return 0;
+    return ossl_rsa_acvp_test_gen_params_new_parsed(dst, &params);
+}
+
 void ossl_rsa_acvp_test_gen_params_free(OSSL_PARAM *dst)
 {
     OSSL_PARAM *p;
@@ -76,10 +94,12 @@ void ossl_rsa_acvp_test_gen_params_free(OSSL_PARAM *dst)
     OPENSSL_free(dst);
 }

-int ossl_rsa_acvp_test_set_params(RSA *r, const OSSL_PARAM params[])
+static int rsa_acvp_test_set_params_parsed(RSA *r, const RSA_PARAMS *p)
 {
     RSA_ACVP_TEST *t;
-    const OSSL_PARAM *p;
+
+    if (r == NULL || p == NULL)
+        return 0;

     if (r->acvp_test != NULL) {
         ossl_rsa_acvp_test_free(r->acvp_test);
@@ -90,31 +110,25 @@ int ossl_rsa_acvp_test_set_params(RSA *r, const OSSL_PARAM params[])
     if (t == NULL)
         return 0;

-    /* Set the input parameters */
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_TEST_XP1)) != NULL
-        && !OSSL_PARAM_get_BN(p, &t->Xp1))
+    if (p->fips.xp1 != NULL && !OSSL_PARAM_get_BN(p->fips.xp1, &t->Xp1))
         goto err;
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_TEST_XP2)) != NULL
-        && !OSSL_PARAM_get_BN(p, &t->Xp2))
+    if (p->fips.xp2 != NULL && !OSSL_PARAM_get_BN(p->fips.xp2, &t->Xp2))
         goto err;
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_TEST_XP)) != NULL
-        && !OSSL_PARAM_get_BN(p, &t->Xp))
+    if (p->fips.xp != NULL && !OSSL_PARAM_get_BN(p->fips.xp, &t->Xp))
         goto err;
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_TEST_XQ1)) != NULL
-        && !OSSL_PARAM_get_BN(p, &t->Xq1))
+    if (p->fips.xq1 != NULL && !OSSL_PARAM_get_BN(p->fips.xq1, &t->Xq1))
         goto err;
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_TEST_XQ2)) != NULL
-        && !OSSL_PARAM_get_BN(p, &t->Xq2))
+    if (p->fips.xq2 != NULL && !OSSL_PARAM_get_BN(p->fips.xq2, &t->Xq2))
         goto err;
-    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_TEST_XQ)) != NULL
-        && !OSSL_PARAM_get_BN(p, &t->Xq))
+    if (p->fips.xq != NULL && !OSSL_PARAM_get_BN(p->fips.xq, &t->Xq))
         goto err;

-    /* Setup the output parameters */
     t->p1 = BN_new();
     t->p2 = BN_new();
     t->q1 = BN_new();
     t->q2 = BN_new();
+    if (t->p1 == NULL || t->p2 == NULL || t->q1 == NULL || t->q2 == NULL)
+        goto err;
     r->acvp_test = t;
     return 1;
 err:
@@ -122,32 +136,45 @@ err:
     return 0;
 }

-int ossl_rsa_acvp_test_get_params(RSA *r, OSSL_PARAM params[])
+int ossl_rsa_acvp_test_set_params(RSA *r, const OSSL_PARAM params[])
+{
+    RSA_PARAMS p;
+
+    if (!rsa_acvp_input_decoder(params, &p))
+        return 0;
+    return rsa_acvp_test_set_params_parsed(r, &p);
+}
+
+int ossl_rsa_acvp_test_get_params_parsed(RSA *r, const RSA_PARAMS *p)
 {
     RSA_ACVP_TEST *t;
-    OSSL_PARAM *p;

-    if (r == NULL)
+    if (r == NULL || p == NULL)
         return 0;

     t = r->acvp_test;
     if (t != NULL) {
-        if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_TEST_P1)) != NULL
-            && !OSSL_PARAM_set_BN(p, t->p1))
+        if (p->fips.p1 != NULL && !OSSL_PARAM_set_BN(p->fips.p1, t->p1))
             return 0;
-        if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_TEST_P2)) != NULL
-            && !OSSL_PARAM_set_BN(p, t->p2))
+        if (p->fips.p2 != NULL && !OSSL_PARAM_set_BN(p->fips.p2, t->p2))
             return 0;
-        if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_TEST_Q1)) != NULL
-            && !OSSL_PARAM_set_BN(p, t->q1))
+        if (p->fips.q1 != NULL && !OSSL_PARAM_set_BN(p->fips.q1, t->q1))
             return 0;
-        if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_TEST_Q2)) != NULL
-            && !OSSL_PARAM_set_BN(p, t->q2))
+        if (p->fips.q2 != NULL && !OSSL_PARAM_set_BN(p->fips.q2, t->q2))
             return 0;
     }
     return 1;
 }

+int ossl_rsa_acvp_test_get_params(RSA *r, OSSL_PARAM params[])
+{
+    RSA_PARAMS p;
+
+    if (!rsa_acvp_output_decoder(params, &p))
+        return 0;
+    return ossl_rsa_acvp_test_get_params_parsed(r, &p);
+}
+
 void ossl_rsa_acvp_test_free(RSA_ACVP_TEST *t)
 {
     if (t != NULL) {
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index 1eb4649481..4483b50cc6 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -23,6 +23,7 @@
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
 #include "crypto/rsa.h"
+#include "crypto/rsa_params.h"
 #include "rsa_local.h"

 /* Set any parameters associated with pkey */
@@ -850,10 +851,8 @@ err:
     return rv;
 }

-static int rsa_int_import_from(const OSSL_PARAM params[], void *vpctx,
-    int rsa_type)
+static int rsa_int_import_from(const RSA_PARAMS *p, EVP_PKEY_CTX *pctx, int rsa_type)
 {
-    EVP_PKEY_CTX *pctx = vpctx;
     EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
     RSA *rsa = ossl_rsa_new_with_ctx(pctx->libctx);
     RSA_PSS_PARAMS_30 rsa_pss_params = {
@@ -870,8 +869,9 @@ static int rsa_int_import_from(const OSSL_PARAM params[], void *vpctx,
     RSA_clear_flags(rsa, RSA_FLAG_TYPE_MASK);
     RSA_set_flags(rsa, rsa_type);

-    if (!ossl_rsa_pss_params_30_fromdata(&rsa_pss_params, &pss_defaults_set,
-            params, pctx->libctx))
+    if (!ossl_rsa_pss_params_30_fromdata_parsed(&rsa_pss_params,
+            &pss_defaults_set,
+            p, pctx->libctx))
         goto err;

     switch (rsa_type) {
@@ -907,7 +907,7 @@ static int rsa_int_import_from(const OSSL_PARAM params[], void *vpctx,
         goto err;
     }

-    if (!ossl_rsa_fromdata(rsa, params, 1))
+    if (!ossl_rsa_fromdata_parsed(rsa, p, 1))
         goto err;

     switch (rsa_type) {
@@ -943,12 +943,22 @@ static int rsa_pss_pkey_export_to(const EVP_PKEY *from, void *to_keydata,

 static int rsa_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
 {
-    return rsa_int_import_from(params, vpctx, RSA_FLAG_TYPE_RSA);
+    EVP_PKEY_CTX *pctx = vpctx;
+    RSA_PARAMS p;
+
+    if (pctx == NULL || !rsa_pkey_import_from_decoder(params, &p))
+        return 0;
+    return rsa_int_import_from(&p, pctx, RSA_FLAG_TYPE_RSA);
 }

 static int rsa_pss_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
 {
-    return rsa_int_import_from(params, vpctx, RSA_FLAG_TYPE_RSASSAPSS);
+    EVP_PKEY_CTX *pctx = vpctx;
+    RSA_PARAMS p;
+
+    if (pctx == NULL || !rsa_pss_pkey_import_from_decoder(params, &p))
+        return 0;
+    return rsa_int_import_from(&p, pctx, RSA_FLAG_TYPE_RSASSAPSS);
 }

 static int rsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c
index 161d9a9c56..67fe3ab099 100644
--- a/crypto/rsa/rsa_backend.c
+++ b/crypto/rsa/rsa_backend.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2026 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
@@ -25,6 +25,7 @@
 #include "internal/sizes.h"
 #include "internal/param_build_set.h"
 #include "crypto/rsa.h"
+#include "crypto/rsa_params.h"
 #include "rsa_local.h"

 /*
@@ -36,20 +37,18 @@
 DEFINE_STACK_OF(BIGNUM)

 static int collect_numbers(STACK_OF(BIGNUM) *numbers,
-    const OSSL_PARAM params[], const char *names[])
+    OSSL_PARAM *const params[], size_t num_params)
 {
-    const OSSL_PARAM *p = NULL;
-    int i;
+    size_t i;

     if (numbers == NULL)
         return 0;

-    for (i = 0; names[i] != NULL; i++) {
-        p = OSSL_PARAM_locate_const(params, names[i]);
-        if (p != NULL) {
+    for (i = 0; i < num_params; i++) {
+        if (params[i] != NULL) {
             BIGNUM *tmp = NULL;

-            if (!OSSL_PARAM_get_BN(p, &tmp))
+            if (!OSSL_PARAM_get_BN(params[i], &tmp))
                 return 0;
             if (sk_BIGNUM_push(numbers, tmp) == 0) {
                 BN_clear_free(tmp);
@@ -61,38 +60,30 @@ static int collect_numbers(STACK_OF(BIGNUM) *numbers,
     return 1;
 }

-int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private)
+int ossl_rsa_fromdata_parsed(RSA *rsa, const RSA_PARAMS *p,
+    int include_private)
 {
-    const OSSL_PARAM *param_n, *param_e, *param_d = NULL;
-    const OSSL_PARAM *param_derive = NULL;
     BIGNUM *n = NULL, *e = NULL, *d = NULL;
     STACK_OF(BIGNUM) *factors = NULL, *exps = NULL, *coeffs = NULL;
     int is_private = 0;
     int derive_from_pq = 0;
     BN_CTX *ctx = NULL;

-    if (rsa == NULL)
+    if (rsa == NULL || p == NULL)
         return 0;

-    param_n = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N);
-    param_e = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E);
-
-    if ((param_n == NULL || !OSSL_PARAM_get_BN(param_n, &n))
-        || (param_e == NULL || !OSSL_PARAM_get_BN(param_e, &e))) {
+    if ((p->n == NULL || !OSSL_PARAM_get_BN(p->n, &n))
+        || (p->e == NULL || !OSSL_PARAM_get_BN(p->e, &e))) {
         ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER);
         goto err;
     }

     if (include_private) {
-
-        param_derive = OSSL_PARAM_locate_const(params,
-            OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ);
-        if ((param_derive != NULL)
-            && !OSSL_PARAM_get_int(param_derive, &derive_from_pq))
+        if ((p->derive != NULL)
+            && !OSSL_PARAM_get_int(p->derive, &derive_from_pq))
             goto err;

-        param_d = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D);
-        if (param_d != NULL && !OSSL_PARAM_get_BN(param_d, &d)) {
+        if (p->d != NULL && !OSSL_PARAM_get_BN(p->d, &d)) {
             ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER);
             goto err;
         }
@@ -103,8 +94,7 @@ int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private)
                 goto err;

             /* we need at minimum p, q */
-            if (OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR1) == NULL
-                || OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR2) == NULL) {
+            if (p->mp.factors[0] == NULL || p->mp.factors[1] == NULL) {
                 ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER);
                 goto err;
             }
@@ -118,12 +108,12 @@ int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private)
     n = e = d = NULL;

     if (is_private) {
-        if (!collect_numbers(factors = sk_BIGNUM_new_null(), params,
-                ossl_rsa_mp_factor_names)
-            || !collect_numbers(exps = sk_BIGNUM_new_null(), params,
-                ossl_rsa_mp_exp_names)
-            || !collect_numbers(coeffs = sk_BIGNUM_new_null(), params,
-                ossl_rsa_mp_coeff_names))
+        if (!collect_numbers(factors = sk_BIGNUM_new_null(), p->mp.factors,
+                OSSL_NELEM(p->mp.factors))
+            || !collect_numbers(exps = sk_BIGNUM_new_null(), p->mp.exps,
+                OSSL_NELEM(p->mp.exps))
+            || !collect_numbers(coeffs = sk_BIGNUM_new_null(), p->mp.coeffs,
+                OSSL_NELEM(p->mp.coeffs)))
             goto err;

         if (derive_from_pq && sk_BIGNUM_num(exps) == 0
@@ -142,7 +132,7 @@ int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private)
              * been provided
              */
             if (sk_BIGNUM_num(factors) > 2
-                && (param_n == NULL || param_d == NULL)) {
+                && (p->n == NULL || p->d == NULL)) {
                 ERR_raise(ERR_LIB_RSA, ERR_R_PASSED_NULL_PARAMETER);
                 goto err;
             }
@@ -248,10 +238,38 @@ err:
     return 0;
 }

+int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[],
+    int include_private)
+{
+    RSA_PARAMS p;
+
+    if (!rsa_key_fromdata_decoder(params, &p))
+        return 0;
+    return ossl_rsa_fromdata_parsed(rsa, &p, include_private);
+}
+
 DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM)

-int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[],
-    int include_private)
+static int rsa_set_multi_key_bn(OSSL_PARAM_BLD *bld,
+    OSSL_PARAM *const params[], size_t num_params, const char *names[],
+    STACK_OF(BIGNUM_const) *numbers)
+{
+    int i, num_numbers = sk_BIGNUM_const_num(numbers);
+
+    for (i = 0; i < num_numbers && (size_t)i < num_params
+        && names[i] != NULL;
+        i++) {
+        const BIGNUM *bn = sk_BIGNUM_const_value(numbers, i);
+        OSSL_PARAM *p = bld == NULL ? params[i] : NULL;
+
+        if (bn != NULL && !ossl_param_build_set_bn(bld, p, names[i], bn))
+            return 0;
+    }
+    return 1;
+}
+
+int ossl_rsa_todata_parsed(RSA *rsa, OSSL_PARAM_BLD *bld,
+    const RSA_PARAMS *p, int include_private)
 {
     int ret = 0;
     const BIGNUM *rsa_d = NULL, *rsa_n = NULL, *rsa_e = NULL;
@@ -259,36 +277,42 @@ int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[],
     STACK_OF(BIGNUM_const) *exps = sk_BIGNUM_const_new_null();
     STACK_OF(BIGNUM_const) *coeffs = sk_BIGNUM_const_new_null();

-    if (rsa == NULL || factors == NULL || exps == NULL || coeffs == NULL)
+    if (rsa == NULL || (bld == NULL && p == NULL)
+        || factors == NULL || exps == NULL || coeffs == NULL)
         goto err;

     RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
     ossl_rsa_get0_all_params(rsa, factors, exps, coeffs);

-    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))
+    if (!ossl_param_build_set_bn(bld, p == NULL ? NULL : p->n,
+            OSSL_PKEY_PARAM_RSA_N, rsa_n)
+        || !ossl_param_build_set_bn(bld, p == NULL ? NULL : p->e,
+            OSSL_PKEY_PARAM_RSA_E, rsa_e))
         goto err;

     /* Check private key data integrity */
     if (include_private && rsa_d != NULL) {

-        if (!ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_RSA_D,
+        if (!ossl_param_build_set_bn(bld, p == NULL ? NULL : p->d,
+                OSSL_PKEY_PARAM_RSA_D,
                 rsa_d)
-            || !ossl_param_build_set_multi_key_bn(bld, params,
-                ossl_rsa_mp_factor_names,
-                factors)
-            || !ossl_param_build_set_multi_key_bn(bld, params,
-                ossl_rsa_mp_exp_names, exps)
-            || !ossl_param_build_set_multi_key_bn(bld, params,
-                ossl_rsa_mp_coeff_names,
-                coeffs))
+            || !rsa_set_multi_key_bn(bld,
+                p == NULL ? NULL : p->mp.factors,
+                OSSL_RSA_PARAM_MAX_PRIMES, ossl_rsa_mp_factor_names, factors)
+            || !rsa_set_multi_key_bn(bld,
+                p == NULL ? NULL : p->mp.exps,
+                OSSL_RSA_PARAM_MAX_PRIMES, ossl_rsa_mp_exp_names, exps)
+            || !rsa_set_multi_key_bn(bld,
+                p == NULL ? NULL : p->mp.coeffs,
+                OSSL_RSA_PARAM_MAX_PRIMES - 1,
+                ossl_rsa_mp_coeff_names, coeffs))
             goto err;
     }

 #if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS)
     /* The acvp test results are not meant for export so check for bld == NULL */
     if (bld == NULL)
-        ossl_rsa_acvp_test_get_params(rsa, params);
+        ossl_rsa_acvp_test_get_params_parsed(rsa, p);
 #endif
     ret = 1;
 err:
@@ -298,9 +322,25 @@ err:
     return ret;
 }

-int ossl_rsa_pss_params_30_todata(const RSA_PSS_PARAMS_30 *pss,
-    OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
+int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[],
+    int include_private)
+{
+    RSA_PARAMS p;
+
+    if (params != NULL) {
+        if (!rsa_key_todata_decoder(params, &p))
+            return 0;
+        return ossl_rsa_todata_parsed(rsa, bld, &p, include_private);
+    }
+    return ossl_rsa_todata_parsed(rsa, bld, NULL, include_private);
+}
+
+int ossl_rsa_pss_params_30_todata_parsed(const RSA_PSS_PARAMS_30 *pss,
+    OSSL_PARAM_BLD *bld, const RSA_PARAMS *p)
 {
+    if (bld == NULL && p == NULL)
+        return 0;
+
     if (!ossl_rsa_pss_params_30_is_unrestricted(pss)) {
         int hashalg_nid = ossl_rsa_pss_params_30_hashalg(pss);
         int maskgenalg_nid = ossl_rsa_pss_params_30_maskgenalg(pss);
@@ -329,42 +369,52 @@ int ossl_rsa_pss_params_30_todata(const RSA_PSS_PARAMS_30 *pss,
          * if it has a default value; saltlen.
          */
         if ((mdname != NULL
-                && !ossl_param_build_set_utf8_string(bld, params, key_md, mdname))
+                && !ossl_param_build_set_utf8_string(bld,
+                    p == NULL ? NULL : p->digest, key_md, mdname))
             || (mgfname != NULL
-                && !ossl_param_build_set_utf8_string(bld, params,
-                    key_mgf, mgfname))
+                && !ossl_param_build_set_utf8_string(bld,
+                    p == NULL ? NULL : p->maskgenfunc, key_mgf, mgfname))
             || (mgf1mdname != NULL
-                && !ossl_param_build_set_utf8_string(bld, params,
+                && !ossl_param_build_set_utf8_string(bld,
+                    p == NULL ? NULL : p->mgf1_digest,
                     key_mgf1_md, mgf1mdname))
-            || (!ossl_param_build_set_int(bld, params, key_saltlen, saltlen)))
+            || (!ossl_param_build_set_int(bld,
+                p == NULL ? NULL : p->pss_saltlen,
+                key_saltlen, saltlen)))
             return 0;
     }
     return 1;
 }

-int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
-    int *defaults_set,
-    const OSSL_PARAM params[],
-    OSSL_LIB_CTX *libctx)
+int ossl_rsa_pss_params_30_todata(const RSA_PSS_PARAMS_30 *pss,
+    OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
+{
+    RSA_PARAMS p;
+
+    if (params != NULL) {
+        if (!rsa_pss_todata_decoder(params, &p))
+            return 0;
+        return ossl_rsa_pss_params_30_todata_parsed(pss, bld, &p);
+    }
+    return ossl_rsa_pss_params_30_todata_parsed(pss, bld, NULL);
+}
+
+int ossl_rsa_pss_params_30_fromdata_parsed(RSA_PSS_PARAMS_30 *pss_params,
+    int *defaults_set, const RSA_PARAMS *p, OSSL_LIB_CTX *libctx)
 {
-    const OSSL_PARAM *param_md, *param_mgf, *param_mgf1md, *param_saltlen;
-    const OSSL_PARAM *param_propq;
     const char *propq = NULL;
     EVP_MD *md = NULL, *mgf1md = NULL;
     int saltlen;
     int ret = 0;

-    if (pss_params == NULL)
+    if (pss_params == NULL || defaults_set == NULL || p == NULL)
         return 0;
-    param_propq = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_DIGEST_PROPS);
-    param_md = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_DIGEST);
-    param_mgf = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_MASKGENFUNC);
-    param_mgf1md = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_MGF1_DIGEST);
-    param_saltlen = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_PSS_SALTLEN);
-
-    if (param_propq != NULL) {
-        if (param_propq->data_type == OSSL_PARAM_UTF8_STRING)
-            propq = param_propq->data;
+
+    if (p->digest_props != NULL) {
+        if (p->digest_props->data_type == OSSL_PARAM_UTF8_STRING)
+            propq = p->digest_props->data;
+        else if (!OSSL_PARAM_get_utf8_ptr(p->digest_props, &propq))
+            return 0;
     }
     /*
      * If we get any of the parameters, we know we have at least some
@@ -372,25 +422,26 @@ int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
      * parameter override their specific restriction data.
      */
     if (!*defaults_set
-        && (param_md != NULL || param_mgf != NULL || param_mgf1md != NULL
-            || param_saltlen != NULL)) {
+        && (p->digest != NULL || p->maskgenfunc != NULL || p->mgf1_digest != NULL
+            || p->pss_saltlen != NULL)) {
         if (!ossl_rsa_pss_params_30_set_defaults(pss_params))
             return 0;
         *defaults_set = 1;
     }

-    if (param_mgf != NULL) {
+    if (p->maskgenfunc != NULL) {
         int default_maskgenalg_nid = ossl_rsa_pss_params_30_maskgenalg(NULL);
         const char *mgfname = NULL;

-        if (param_mgf->data_type == OSSL_PARAM_UTF8_STRING)
-            mgfname = param_mgf->data;
-        else if (!OSSL_PARAM_get_utf8_ptr(param_mgf, &mgfname))
+        if (p->maskgenfunc->data_type == OSSL_PARAM_UTF8_STRING)
+            mgfname = p->maskgenfunc->data;
+        else if (!OSSL_PARAM_get_utf8_ptr(p->maskgenfunc, &mgfname))
             return 0;

-        if (OPENSSL_strcasecmp(param_mgf->data,
-                ossl_rsa_mgf_nid2name(default_maskgenalg_nid))
-            != 0)
+        if (mgfname == NULL
+            || OPENSSL_strcasecmp(mgfname,
+                   ossl_rsa_mgf_nid2name(default_maskgenalg_nid))
+                != 0)
             return 0;
     }

@@ -399,12 +450,12 @@ int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
      * exact propquery is unimportant in the EVP_MD_fetch() calls below.
      */

-    if (param_md != NULL) {
+    if (p->digest != NULL) {
         const char *mdname = NULL;

-        if (param_md->data_type == OSSL_PARAM_UTF8_STRING)
-            mdname = param_md->data;
-        else if (!OSSL_PARAM_get_utf8_ptr(param_mgf, &mdname))
+        if (p->digest->data_type == OSSL_PARAM_UTF8_STRING)
+            mdname = p->digest->data;
+        else if (!OSSL_PARAM_get_utf8_ptr(p->digest, &mdname))
             goto err;

         if ((md = EVP_MD_fetch(libctx, mdname, propq)) == NULL
@@ -413,12 +464,12 @@ int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
             goto err;
     }

-    if (param_mgf1md != NULL) {
+    if (p->mgf1_digest != NULL) {
         const char *mgf1mdname = NULL;

-        if (param_mgf1md->data_type == OSSL_PARAM_UTF8_STRING)
-            mgf1mdname = param_mgf1md->data;
-        else if (!OSSL_PARAM_get_utf8_ptr(param_mgf, &mgf1mdname))
+        if (p->mgf1_digest->data_type == OSSL_PARAM_UTF8_STRING)
+            mgf1mdname = p->mgf1_digest->data;
+        else if (!OSSL_PARAM_get_utf8_ptr(p->mgf1_digest, &mgf1mdname))
             goto err;

         if ((mgf1md = EVP_MD_fetch(libctx, mgf1mdname, propq)) == NULL
@@ -427,8 +478,8 @@ int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
             goto err;
     }

-    if (param_saltlen != NULL) {
-        if (!OSSL_PARAM_get_int(param_saltlen, &saltlen)
+    if (p->pss_saltlen != NULL) {
+        if (!OSSL_PARAM_get_int(p->pss_saltlen, &saltlen)
             || !ossl_rsa_pss_params_30_set_saltlen(pss_params, saltlen))
             goto err;
     }
@@ -441,6 +492,17 @@ err:
     return ret;
 }

+int ossl_rsa_pss_params_30_fromdata(RSA_PSS_PARAMS_30 *pss_params,
+    int *defaults_set, const OSSL_PARAM params[], OSSL_LIB_CTX *libctx)
+{
+    RSA_PARAMS p;
+
+    if (!rsa_pss_fromdata_decoder(params, &p))
+        return 0;
+    return ossl_rsa_pss_params_30_fromdata_parsed(pss_params, defaults_set,
+        &p, libctx);
+}
+
 int ossl_rsa_is_foreign(const RSA *rsa)
 {
 #ifndef FIPS_MODULE