Commit 5b70427d03 for openssl.org

commit 5b70427d031f71754097346c321bf6c7adebb58f
Author: Pauli <paul.dale@oracle.com>
Date:   Wed Jul 8 13:57:34 2026 +1000

    rsa: define generated parameter tries

    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/.gitignore b/.gitignore
index 9122acd77e..d9eb14a8bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@
 # Auto generated headers
 /crypto/buildinf.h
 /include/crypto/*_conf.h
+/include/crypto/rsa_params.h
 /include/openssl/asn1.h
 /include/openssl/asn1t.h
 /include/openssl/bio.h
diff --git a/build.info b/build.info
index d7982a9553..cb30708f5f 100644
--- a/build.info
+++ b/build.info
@@ -45,6 +45,7 @@ DEPEND[]=include/openssl/asn1.h \
          include/openssl/x509_acert.h \
          include/openssl/x509_vfy.h \
          include/crypto/dso_conf.h \
+         include/crypto/rsa_params.h \
          providers/implementations/asymciphers/rsa_enc.inc \
          providers/implementations/asymciphers/sm2_enc.inc \
          providers/implementations/exchange/dh_exch.inc \
@@ -262,8 +263,11 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \
        providers/implementations/rands/seed_src.inc \
        providers/implementations/rands/seed_src_jitter.inc \
        providers/implementations/rands/test_rng.inc \
+       include/crypto/rsa_params.h \
        include/openssl/core_names.h]=util/perl|OpenSSL/paramnames.pm

+GENERATE[include/crypto/rsa_params.h]=\
+    include/crypto/rsa_params.h.in
 GENERATE[providers/implementations/asymciphers/rsa_enc.inc]=\
     providers/implementations/asymciphers/rsa_enc.inc.in
 GENERATE[providers/implementations/asymciphers/sm2_enc.inc]=\
diff --git a/include/crypto/rsa.h b/include/crypto/rsa.h
index 0b853f9a80..a57702aa1d 100644
--- a/include/crypto/rsa.h
+++ b/include/crypto/rsa.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-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
@@ -17,6 +17,58 @@

 #define RSA_MIN_MODULUS_BITS 512

+#ifdef FIPS_MODULE
+#define OSSL_RSA_PARAM_MAX_PRIMES 2
+#else
+#define OSSL_RSA_PARAM_MAX_PRIMES 10
+#endif
+
+typedef struct rsa_params_st {
+    OSSL_PARAM *n;
+    OSSL_PARAM *e;
+    OSSL_PARAM *d;
+    OSSL_PARAM *a;
+    OSSL_PARAM *b;
+    OSSL_PARAM *bits;
+    OSSL_PARAM *secbits;
+    OSSL_PARAM *maxsize;
+    OSSL_PARAM *seccat;
+    OSSL_PARAM *default_digest;
+    OSSL_PARAM *mandatory_digest;
+
+    /* PSS specific params */
+    OSSL_PARAM *digest;
+    OSSL_PARAM *digest_props;
+    OSSL_PARAM *maskgenfunc;
+    OSSL_PARAM *mgf1_digest;
+    OSSL_PARAM *pss_saltlen;
+
+    /* import specific params */
+    OSSL_PARAM *derive;
+
+#ifdef FIPS_MODULE
+    struct {
+        OSSL_PARAM *xp;
+        OSSL_PARAM *xp1;
+        OSSL_PARAM *xp2;
+        OSSL_PARAM *xq;
+        OSSL_PARAM *xq1;
+        OSSL_PARAM *xq2;
+        OSSL_PARAM *p1;
+        OSSL_PARAM *p2;
+        OSSL_PARAM *q1;
+        OSSL_PARAM *q2;
+    } fips;
+#endif
+
+    OSSL_PARAM *primes;
+    struct {
+        OSSL_PARAM *factors[OSSL_RSA_PARAM_MAX_PRIMES];
+        OSSL_PARAM *exps[OSSL_RSA_PARAM_MAX_PRIMES];
+        OSSL_PARAM *coeffs[OSSL_RSA_PARAM_MAX_PRIMES - 1];
+    } mp;
+} RSA_PARAMS;
+
 typedef struct rsa_pss_params_30_st {
     int hash_algorithm_nid;
     struct {
@@ -73,13 +125,19 @@ RSA *ossl_rsa_dup(const RSA *rsa, int selection);

 int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[],
     int include_private);
+int ossl_rsa_todata_parsed(RSA *rsa, OSSL_PARAM_BLD *bld,
+    const RSA_PARAMS *params, int include_private);
 int ossl_rsa_fromdata(RSA *rsa, const OSSL_PARAM params[], int include_private);
+int ossl_rsa_fromdata_parsed(RSA *rsa, const RSA_PARAMS *params,
+    int include_private);
 int ossl_rsa_pss_params_30_todata(const RSA_PSS_PARAMS_30 *pss,
     OSSL_PARAM_BLD *bld, OSSL_PARAM params[]);
+int ossl_rsa_pss_params_30_todata_parsed(const RSA_PSS_PARAMS_30 *pss,
+    OSSL_PARAM_BLD *bld, const RSA_PARAMS *params);
 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 *defaults_set, const OSSL_PARAM params[], OSSL_LIB_CTX *libctx);
+int ossl_rsa_pss_params_30_fromdata_parsed(RSA_PSS_PARAMS_30 *pss_params,
+    int *defaults_set, const RSA_PARAMS *params, OSSL_LIB_CTX *libctx);
 int ossl_rsa_set0_pss_params(RSA *r, RSA_PSS_PARAMS *pss);
 int ossl_rsa_pss_get_param_unverified(const RSA_PSS_PARAMS *pss,
     const EVP_MD **pmd, const EVP_MD **pmgf1md,
@@ -130,10 +188,13 @@ int ossl_rsa_generate_multi_prime_key(RSA *rsa, int bits, int primes,

 #if defined(FIPS_MODULE) && !defined(OPENSSL_NO_ACVP_TESTS)
 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);
 void ossl_rsa_acvp_test_gen_params_free(OSSL_PARAM *dst);

 int ossl_rsa_acvp_test_set_params(RSA *r, const OSSL_PARAM params[]);
 int ossl_rsa_acvp_test_get_params(RSA *r, OSSL_PARAM params[]);
+int ossl_rsa_acvp_test_get_params_parsed(RSA *r, const RSA_PARAMS *params);
 typedef struct rsa_acvp_test_st RSA_ACVP_TEST;
 void ossl_rsa_acvp_test_free(RSA_ACVP_TEST *t);
 #else
diff --git a/include/crypto/rsa_params.h.in b/include/crypto/rsa_params.h.in
new file mode 100644
index 0000000000..10188299df
--- /dev/null
+++ b/include/crypto/rsa_params.h.in
@@ -0,0 +1,206 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+{-
+use OpenSSL::paramnames qw(produce_param_decoder);
+-}
+
+#include "crypto/rsa.h"
+#include <openssl/err.h>
+#include <openssl/proverr.h>
+
+{-
+our @RSA_KEY_MP_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_FACTOR1',      'mp.factors[0]', 'BN'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR2',      'mp.factors[1]', 'BN'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR3',      'mp.factors[2]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR4',      'mp.factors[3]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR5',      'mp.factors[4]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR6',      'mp.factors[5]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR7',      'mp.factors[6]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR8',      'mp.factors[7]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR9',      'mp.factors[8]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_FACTOR10',     'mp.factors[9]', 'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT1',    'mp.exps[0]',    'BN'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT2',    'mp.exps[1]',    'BN'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT3',    'mp.exps[2]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT4',    'mp.exps[3]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT5',    'mp.exps[4]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT6',    'mp.exps[5]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT7',    'mp.exps[6]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT8',    'mp.exps[7]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT9',    'mp.exps[8]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_EXPONENT10',   'mp.exps[9]',    'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT1', 'mp.coeffs[0]',  'BN'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT2', 'mp.coeffs[1]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT3', 'mp.coeffs[2]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT4', 'mp.coeffs[3]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT5', 'mp.coeffs[4]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT6', 'mp.coeffs[5]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT7', 'mp.coeffs[6]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT8', 'mp.coeffs[7]',  'BN', '!fips'],
+    ['OSSL_PKEY_PARAM_RSA_COEFFICIENT9', 'mp.coeffs[8]',  'BN', '!fips'],
+);
+
+our @RSA_KEY_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_N', 'n', 'BN'],
+    ['OSSL_PKEY_PARAM_RSA_E', 'e', 'BN'],
+    ['OSSL_PKEY_PARAM_RSA_D', 'd', 'BN'],
+    @RSA_KEY_MP_TYPES
+);
+
+our @RSA_PSS_IMPORT_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_DIGEST',       'digest',       'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_DIGEST_PROPS', 'digest_props', 'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_MASKGENFUNC',  'maskgenfunc',  'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_MGF1_DIGEST',  'mgf1_digest',  'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_PSS_SALTLEN',  'pss_saltlen',  'int'],
+);
+
+our @RSA_PSS_EXPORT_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_DIGEST',      'digest',      'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_MASKGENFUNC', 'maskgenfunc', 'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_MGF1_DIGEST', 'mgf1_digest', 'utf8_string'],
+    ['OSSL_PKEY_PARAM_RSA_PSS_SALTLEN', 'pss_saltlen', 'int'],
+);
+
+our @RSA_GEN_BASIC_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_BITS',   'bits',   'size_t'],
+    ['OSSL_PKEY_PARAM_RSA_PRIMES', 'primes', 'size_t'],
+    ['OSSL_PKEY_PARAM_RSA_E',      'e',      'BN'],
+    ['OSSL_PKEY_PARAM_RSA_A',      'a',      'uint32'],
+    ['OSSL_PKEY_PARAM_RSA_B',      'b',      'uint32'],
+);
+
+our @RSA_ACVP_INPUT_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_TEST_XP',  'fips.xp',  'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_XP1', 'fips.xp1', 'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_XP2', 'fips.xp2', 'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_XQ',  'fips.xq',  'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_XQ1', 'fips.xq1', 'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_XQ2', 'fips.xq2', 'BN', 'fips'],
+);
+
+our @RSA_ACVP_OUTPUT_TYPES = (
+    ['OSSL_PKEY_PARAM_RSA_TEST_P1', 'fips.p1', 'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_P2', 'fips.p2', 'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_Q1', 'fips.q1', 'BN', 'fips'],
+    ['OSSL_PKEY_PARAM_RSA_TEST_Q2', 'fips.q2', 'BN', 'fips'],
+);
+
+return "";
+-}
+
+/* Key component parsing used by the public compatibility wrappers. */
+#define rsa_key_fromdata_st rsa_params_st
+{- produce_param_decoder('rsa_key_fromdata',
+                         (@RSA_KEY_TYPES,
+                          ['OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ', 'derive', 'int']
+                         )); -}
+
+#define rsa_key_todata_st rsa_params_st
+{- produce_param_decoder('rsa_key_todata',
+                         (@RSA_KEY_TYPES, @RSA_ACVP_OUTPUT_TYPES)); -}
+
+#define rsa_pss_fromdata_st rsa_params_st
+{- produce_param_decoder('rsa_pss_fromdata', @RSA_PSS_IMPORT_TYPES); -}
+
+#define rsa_pss_todata_st rsa_params_st
+{- produce_param_decoder('rsa_pss_todata', @RSA_PSS_EXPORT_TYPES); -}
+
+/* The provider keymgmt import path parses its input only once. */
+#define rsa_import_st rsa_params_st
+{- produce_param_decoder('rsa_import',
+                         (@RSA_KEY_TYPES,
+                          ['OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ', 'derive', 'int'],
+                          @RSA_PSS_IMPORT_TYPES
+                         )); -}
+
+/* Parameters processed by rsa_get_params(), including conditional ACVP data. */
+#define rsa_get_params_st rsa_params_st
+{- produce_param_decoder('rsa_get_params',
+                         (['OSSL_PKEY_PARAM_BITS',              'bits',            'int'],
+                          ['OSSL_PKEY_PARAM_SECURITY_BITS',     'secbits',          'int'],
+                          ['OSSL_PKEY_PARAM_MAX_SIZE',          'maxsize',          'int'],
+                          ['OSSL_PKEY_PARAM_SECURITY_CATEGORY', 'seccat',           'int'],
+                          ['OSSL_PKEY_PARAM_DEFAULT_DIGEST',    'default_digest',   'utf8_string'],
+                          ['OSSL_PKEY_PARAM_MANDATORY_DIGEST',  'mandatory_digest', 'utf8_string'],
+                          @RSA_KEY_TYPES,
+                          @RSA_PSS_EXPORT_TYPES,
+                          @RSA_ACVP_OUTPUT_TYPES
+                         )); -}
+
+/* Plain RSA generation parameters. */
+#define rsa_gen_set_params_st rsa_params_st
+{- produce_param_decoder('rsa_gen_set_params',
+                         (@RSA_GEN_BASIC_TYPES,
+                          @RSA_ACVP_INPUT_TYPES
+                         )); -}
+
+#define rsapss_gen_set_params_st rsa_params_st
+{- produce_param_decoder('rsapss_gen_set_params',
+                         (@RSA_GEN_BASIC_TYPES,
+                          @RSA_PSS_IMPORT_TYPES,
+                          @RSA_ACVP_INPUT_TYPES
+                         )); -}
+
+/* Legacy EVP_PKEY import-from callbacks retain their existing signatures. */
+#define rsa_pkey_import_from_st rsa_params_st
+{- produce_param_decoder('rsa_pkey_import_from',
+                         (@RSA_KEY_TYPES,
+                          ['OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ', 'derive', 'int'],
+                          @RSA_PSS_IMPORT_TYPES
+                         )); -}
+
+#define rsa_pss_pkey_import_from_st rsa_params_st
+{- produce_param_decoder('rsa_pss_pkey_import_from',
+                         (@RSA_KEY_TYPES,
+                          ['OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ', 'derive', 'int'],
+                          @RSA_PSS_IMPORT_TYPES
+                         )); -}
+
+/* FIPS ACVP helpers also use the generated trie. */
+#define rsa_acvp_input_st rsa_params_st
+{- produce_param_decoder('rsa_acvp_input', @RSA_ACVP_INPUT_TYPES); -}
+
+#define rsa_acvp_output_st rsa_params_st
+{- produce_param_decoder('rsa_acvp_output', @RSA_ACVP_OUTPUT_TYPES); -}
+
+/* Selection-specific import and export declarations. */
+#define rsa_key_import_types_st
+#define rsa_key_import_types_decoder
+{- produce_param_decoder('rsa_key_import_types',
+                         (@RSA_KEY_TYPES,
+                          ['OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ', 'derive', 'int']
+                         )); -}
+
+#define rsa_key_export_types_st
+#define rsa_key_export_types_decoder
+{- produce_param_decoder('rsa_key_export_types', @RSA_KEY_TYPES); -}
+
+#define rsa_other_import_types_st
+#define rsa_other_import_types_decoder
+{- produce_param_decoder('rsa_other_import_types', @RSA_PSS_IMPORT_TYPES); -}
+
+#define rsa_other_export_types_st
+#define rsa_other_export_types_decoder
+{- produce_param_decoder('rsa_other_export_types', @RSA_PSS_EXPORT_TYPES); -}
+
+#define rsa_all_import_types_st
+#define rsa_all_import_types_decoder
+{- produce_param_decoder('rsa_all_import_types',
+                         (@RSA_KEY_TYPES,
+                          ['OSSL_PKEY_PARAM_RSA_DERIVE_FROM_PQ', 'derive', 'int'],
+                          @RSA_PSS_IMPORT_TYPES
+                         )); -}
+
+#define rsa_all_export_types_st
+#define rsa_all_export_types_decoder
+{- produce_param_decoder('rsa_all_export_types',
+                         (@RSA_KEY_TYPES, @RSA_PSS_EXPORT_TYPES)); -}