Support multi-prime RSA (RFC 8017)
authorPaul Yang <yang.yang@baishancloud.com>
Tue, 1 Aug 2017 18:19:43 +0000 (02:19 +0800)
committerPaul Yang <yang.yang@baishancloud.com>
Tue, 21 Nov 2017 06:38:42 +0000 (14:38 +0800)
* Introduce RSA_generate_multi_prime_key to generate multi-prime
  RSA private key. As well as the following functions:
    RSA_get_multi_prime_extra_count
    RSA_get0_multi_prime_factors
    RSA_get0_multi_prime_crt_params
    RSA_set0_multi_prime_params
    RSA_get_version
* Support EVP operations for multi-prime RSA
* Support ASN.1 operations for multi-prime RSA
* Support multi-prime check in RSA_check_key_ex
* Support multi-prime RSA in apps/genrsa and apps/speed
* Support multi-prime RSA manipulation functions
* Test cases and documentation are added
* CHANGES is updated

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
(Merged from https://github.com/openssl/openssl/pull/4241)

29 files changed:
CHANGES
apps/genrsa.c
apps/speed.c
crypto/err/openssl.txt
crypto/rsa/build.info
crypto/rsa/rsa_ameth.c
crypto/rsa/rsa_asn1.c
crypto/rsa/rsa_chk.c
crypto/rsa/rsa_err.c
crypto/rsa/rsa_gen.c
crypto/rsa/rsa_lib.c
crypto/rsa/rsa_locl.h
crypto/rsa/rsa_meth.c
crypto/rsa/rsa_mp.c [new file with mode: 0644]
crypto/rsa/rsa_ossl.c
crypto/rsa/rsa_pmeth.c
doc/man1/genpkey.pod
doc/man1/genrsa.pod
doc/man1/speed.pod
doc/man3/RSA_generate_key.pod
doc/man3/RSA_get0_key.pod
doc/man3/RSA_meth_new.pod
include/openssl/rsa.h
include/openssl/rsaerr.h
test/build.info
test/recipes/15-test_mp_rsa.t [new file with mode: 0644]
test/recipes/15-test_mp_rsa_data/plain_text [new file with mode: 0644]
test/rsa_mp_test.c [new file with mode: 0644]
util/libcrypto.num

diff --git a/CHANGES b/CHANGES
index 0b0c3ca..3ae8b4d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,9 @@
 
  Changes between 1.1.0f and 1.1.1 [xx XXX xxxx]
 
 
  Changes between 1.1.0f and 1.1.1 [xx XXX xxxx]
 
+  *) Add multi-prime RSA (RFC 8017) support.
+     [Paul Yang]
+
   *) Add SM3 implemented according to GB/T 32905-2016
      [ Jack Lloyd <jack.lloyd@ribose.com>,
        Ronald Tse <ronald.tse@ribose.com>,
   *) Add SM3 implemented according to GB/T 32905-2016
      [ Jack Lloyd <jack.lloyd@ribose.com>,
        Ronald Tse <ronald.tse@ribose.com>,
index b4a986c..f147852 100644 (file)
@@ -27,13 +27,14 @@ NON_EMPTY_TRANSLATION_UNIT
 # include <openssl/rand.h>
 
 # define DEFBITS 2048
 # include <openssl/rand.h>
 
 # define DEFBITS 2048
+# define DEFPRIMES 2
 
 static int genrsa_cb(int p, int n, BN_GENCB *cb);
 
 typedef enum OPTION_choice {
     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
     OPT_3, OPT_F4, OPT_ENGINE,
 
 static int genrsa_cb(int p, int n, BN_GENCB *cb);
 
 typedef enum OPTION_choice {
     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
     OPT_3, OPT_F4, OPT_ENGINE,
-    OPT_OUT, OPT_PASSOUT, OPT_CIPHER,
+    OPT_OUT, OPT_PASSOUT, OPT_CIPHER, OPT_PRIMES,
     OPT_R_ENUM
 } OPTION_CHOICE;
 
     OPT_R_ENUM
 } OPTION_CHOICE;
 
@@ -49,6 +50,7 @@ const OPTIONS genrsa_options[] = {
 # ifndef OPENSSL_NO_ENGINE
     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
 # endif
 # ifndef OPENSSL_NO_ENGINE
     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
 # endif
+    {"primes", OPT_PRIMES, 'p', "Specify number of primes"},
     {NULL}
 };
 
     {NULL}
 };
 
@@ -62,7 +64,7 @@ int genrsa_main(int argc, char **argv)
     const BIGNUM *e;
     RSA *rsa = NULL;
     const EVP_CIPHER *enc = NULL;
     const BIGNUM *e;
     RSA *rsa = NULL;
     const EVP_CIPHER *enc = NULL;
-    int ret = 1, num = DEFBITS, private = 0;
+    int ret = 1, num = DEFBITS, private = 0, primes = DEFPRIMES;
     unsigned long f4 = RSA_F4;
     char *outfile = NULL, *passoutarg = NULL, *passout = NULL;
     char *prog, *hexe, *dece;
     unsigned long f4 = RSA_F4;
     char *outfile = NULL, *passoutarg = NULL, *passout = NULL;
     char *prog, *hexe, *dece;
@@ -108,6 +110,10 @@ opthelp:
             if (!opt_cipher(opt_unknown(), &enc))
                 goto end;
             break;
             if (!opt_cipher(opt_unknown(), &enc))
                 goto end;
             break;
+        case OPT_PRIMES:
+            if (!opt_int(opt_arg(), &primes))
+                goto end;
+            break;
         }
     }
     argc = opt_num_rest();
         }
     }
     argc = opt_num_rest();
@@ -131,13 +137,14 @@ opthelp:
     if (out == NULL)
         goto end;
 
     if (out == NULL)
         goto end;
 
-    BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus\n",
-               num);
+    BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus (%d primes)\n",
+               num, primes);
     rsa = eng ? RSA_new_method(eng) : RSA_new();
     if (rsa == NULL)
         goto end;
 
     rsa = eng ? RSA_new_method(eng) : RSA_new();
     if (rsa == NULL)
         goto end;
 
-    if (!BN_set_word(bn, f4) || !RSA_generate_key_ex(rsa, num, bn, cb))
+    if (!BN_set_word(bn, f4)
+        || !RSA_generate_multi_prime_key(rsa, num, primes, bn, cb))
         goto end;
 
     RSA_get0_key(rsa, NULL, &e, NULL);
         goto end;
 
     RSA_get0_key(rsa, NULL, &e, NULL);
index 063bc1c..c52dac6 100644 (file)
@@ -339,7 +339,8 @@ static int found(const char *name, const OPT_PAIR *pairs, int *result)
 typedef enum OPTION_choice {
     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
     OPT_ELAPSED, OPT_EVP, OPT_DECRYPT, OPT_ENGINE, OPT_MULTI,
 typedef enum OPTION_choice {
     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
     OPT_ELAPSED, OPT_EVP, OPT_DECRYPT, OPT_ENGINE, OPT_MULTI,
-    OPT_MR, OPT_MB, OPT_MISALIGN, OPT_ASYNCJOBS, OPT_R_ENUM
+    OPT_MR, OPT_MB, OPT_MISALIGN, OPT_ASYNCJOBS, OPT_R_ENUM,
+    OPT_PRIMES
 } OPTION_CHOICE;
 
 const OPTIONS speed_options[] = {
 } OPTION_CHOICE;
 
 const OPTIONS speed_options[] = {
@@ -366,6 +367,7 @@ const OPTIONS speed_options[] = {
 #ifndef OPENSSL_NO_ENGINE
     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
 #endif
 #ifndef OPENSSL_NO_ENGINE
     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
 #endif
+    {"primes", OPT_PRIMES, 'p', "Specify number of primes (for RSA only)"},
     {NULL},
 };
 
     {NULL},
 };
 
@@ -1325,6 +1327,7 @@ int speed_main(int argc, char **argv)
         sizeof(test15360)
     };
     int rsa_doit[RSA_NUM] = { 0 };
         sizeof(test15360)
     };
     int rsa_doit[RSA_NUM] = { 0 };
+    int primes = RSA_DEFAULT_PRIME_NUM;
 #endif
 #ifndef OPENSSL_NO_DSA
     static const unsigned int dsa_bits[DSA_NUM] = { 512, 1024, 2048 };
 #endif
 #ifndef OPENSSL_NO_DSA
     static const unsigned int dsa_bits[DSA_NUM] = { 512, 1024, 2048 };
@@ -1459,6 +1462,10 @@ int speed_main(int argc, char **argv)
             if (!opt_rand(o))
                 goto end;
             break;
             if (!opt_rand(o))
                 goto end;
             break;
+        case OPT_PRIMES:
+            if (!opt_int(opt_arg(), &primes))
+                goto end;
+            break;
         }
     }
     argc = opt_num_rest();
         }
     }
     argc = opt_num_rest();
@@ -1615,6 +1622,10 @@ int speed_main(int argc, char **argv)
 
 #ifndef OPENSSL_NO_RSA
     for (i = 0; i < loopargs_len; i++) {
 
 #ifndef OPENSSL_NO_RSA
     for (i = 0; i < loopargs_len; i++) {
+        if (primes > RSA_DEFAULT_PRIME_NUM) {
+            /* for multi-prime RSA, skip this */
+            break;
+        }
         for (k = 0; k < RSA_NUM; k++) {
             const unsigned char *p;
 
         for (k = 0; k < RSA_NUM; k++) {
             const unsigned char *p;
 
@@ -2395,6 +2406,34 @@ int speed_main(int argc, char **argv)
         if (!rsa_doit[testnum])
             continue;
         for (i = 0; i < loopargs_len; i++) {
         if (!rsa_doit[testnum])
             continue;
         for (i = 0; i < loopargs_len; i++) {
+            if (primes > 2) {
+                /* we haven't set keys yet,  generate multi-prime RSA keys */
+                BIGNUM *bn = BN_new();
+
+                if (bn == NULL)
+                    goto end;
+                if (!BN_set_word(bn, RSA_F4)) {
+                    BN_free(bn);
+                    goto end;
+                }
+
+                BIO_printf(bio_err, "Generate multi-prime RSA key for %s\n",
+                           rsa_choices[testnum].name);
+
+                loopargs[i].rsa_key[testnum] = RSA_new();
+                if (loopargs[i].rsa_key[testnum] == NULL) {
+                    BN_free(bn);
+                    goto end;
+                }
+
+                if (!RSA_generate_multi_prime_key(loopargs[i].rsa_key[testnum],
+                                                  rsa_bits[testnum],
+                                                  primes, bn, NULL)) {
+                    BN_free(bn);
+                    goto end;
+                }
+                BN_free(bn);
+            }
             st = RSA_sign(NID_md5_sha1, loopargs[i].buf, 36, loopargs[i].buf2,
                           &loopargs[i].siglen, loopargs[i].rsa_key[testnum]);
             if (st == 0)
             st = RSA_sign(NID_md5_sha1, loopargs[i].buf, 36, loopargs[i].buf2,
                           &loopargs[i].siglen, loopargs[i].rsa_key[testnum]);
             if (st == 0)
index 8547d07..e7353aa 100644 (file)
@@ -2224,6 +2224,7 @@ RSA_R_INVALID_HEADER:137:invalid header
 RSA_R_INVALID_LABEL:160:invalid label
 RSA_R_INVALID_MESSAGE_LENGTH:131:invalid message length
 RSA_R_INVALID_MGF1_MD:156:invalid mgf1 md
 RSA_R_INVALID_LABEL:160:invalid label
 RSA_R_INVALID_MESSAGE_LENGTH:131:invalid message length
 RSA_R_INVALID_MGF1_MD:156:invalid mgf1 md
+RSA_R_INVALID_MULTI_PRIME_KEY:167:invalid multi prime key
 RSA_R_INVALID_OAEP_PARAMETERS:161:invalid oaep parameters
 RSA_R_INVALID_PADDING:138:invalid padding
 RSA_R_INVALID_PADDING_MODE:141:invalid padding mode
 RSA_R_INVALID_OAEP_PARAMETERS:161:invalid oaep parameters
 RSA_R_INVALID_PADDING:138:invalid padding
 RSA_R_INVALID_PADDING_MODE:141:invalid padding mode
@@ -2233,12 +2234,17 @@ RSA_R_INVALID_SALT_LENGTH:150:invalid salt length
 RSA_R_INVALID_TRAILER:139:invalid trailer
 RSA_R_INVALID_X931_DIGEST:142:invalid x931 digest
 RSA_R_IQMP_NOT_INVERSE_OF_Q:126:iqmp not inverse of q
 RSA_R_INVALID_TRAILER:139:invalid trailer
 RSA_R_INVALID_X931_DIGEST:142:invalid x931 digest
 RSA_R_IQMP_NOT_INVERSE_OF_Q:126:iqmp not inverse of q
+RSA_R_KEY_PRIME_NUM_INVALID:165:key prime num invalid
 RSA_R_KEY_SIZE_TOO_SMALL:120:key size too small
 RSA_R_LAST_OCTET_INVALID:134:last octet invalid
 RSA_R_MGF1_DIGEST_NOT_ALLOWED:152:mgf1 digest not allowed
 RSA_R_MODULUS_TOO_LARGE:105:modulus too large
 RSA_R_KEY_SIZE_TOO_SMALL:120:key size too small
 RSA_R_LAST_OCTET_INVALID:134:last octet invalid
 RSA_R_MGF1_DIGEST_NOT_ALLOWED:152:mgf1 digest not allowed
 RSA_R_MODULUS_TOO_LARGE:105:modulus too large
+RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R:168:mp coefficient not inverse of r
+RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D:169:mp exponent not congruent to d
+RSA_R_MP_R_NOT_PRIME:170:mp r not prime
 RSA_R_NO_PUBLIC_EXPONENT:140:no public exponent
 RSA_R_NULL_BEFORE_BLOCK_MISSING:113:null before block missing
 RSA_R_NO_PUBLIC_EXPONENT:140:no public exponent
 RSA_R_NULL_BEFORE_BLOCK_MISSING:113:null before block missing
+RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES:172:n does not equal product of primes
 RSA_R_N_DOES_NOT_EQUAL_P_Q:127:n does not equal p q
 RSA_R_OAEP_DECODING_ERROR:121:oaep decoding error
 RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:148:\
 RSA_R_N_DOES_NOT_EQUAL_P_Q:127:n does not equal p q
 RSA_R_OAEP_DECODING_ERROR:121:oaep decoding error
 RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:148:\
index 4575b28..87f9249 100644 (file)
@@ -3,4 +3,4 @@ SOURCE[../../libcrypto]=\
         rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_saos.c rsa_err.c \
         rsa_pk1.c rsa_ssl.c rsa_none.c rsa_oaep.c rsa_chk.c \
         rsa_pss.c rsa_x931.c rsa_asn1.c rsa_depr.c rsa_ameth.c rsa_prn.c \
         rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_saos.c rsa_err.c \
         rsa_pk1.c rsa_ssl.c rsa_none.c rsa_oaep.c rsa_chk.c \
         rsa_pss.c rsa_x931.c rsa_asn1.c rsa_depr.c rsa_ameth.c rsa_prn.c \
-        rsa_pmeth.c rsa_crpt.c rsa_x931g.c rsa_meth.c
+        rsa_pmeth.c rsa_crpt.c rsa_x931g.c rsa_meth.c rsa_mp.c
index 97a37ba..98121b5 100644 (file)
@@ -316,10 +316,11 @@ static int pkey_rsa_print(BIO *bp, const EVP_PKEY *pkey, int off, int priv)
     const RSA *x = pkey->pkey.rsa;
     char *str;
     const char *s;
     const RSA *x = pkey->pkey.rsa;
     char *str;
     const char *s;
-    int ret = 0, mod_len = 0;
+    int ret = 0, mod_len = 0, ex_primes;
 
     if (x->n != NULL)
         mod_len = BN_num_bits(x->n);
 
     if (x->n != NULL)
         mod_len = BN_num_bits(x->n);
+    ex_primes = sk_RSA_PRIME_INFO_num(x->prime_infos);
 
     if (!BIO_indent(bp, off, 128))
         goto err;
 
     if (!BIO_indent(bp, off, 128))
         goto err;
@@ -328,7 +329,8 @@ static int pkey_rsa_print(BIO *bp, const EVP_PKEY *pkey, int off, int priv)
         goto err;
 
     if (priv && x->d) {
         goto err;
 
     if (priv && x->d) {
-        if (BIO_printf(bp, "Private-Key: (%d bit)\n", mod_len) <= 0)
+        if (BIO_printf(bp, "Private-Key: (%d bit, %d primes)\n",
+                       mod_len, ex_primes <= 0 ? 2 : ex_primes + 2) <= 0)
             goto err;
         str = "modulus:";
         s = "publicExponent:";
             goto err;
         str = "modulus:";
         s = "publicExponent:";
@@ -343,6 +345,8 @@ static int pkey_rsa_print(BIO *bp, const EVP_PKEY *pkey, int off, int priv)
     if (!ASN1_bn_print(bp, s, x->e, NULL, off))
         goto err;
     if (priv) {
     if (!ASN1_bn_print(bp, s, x->e, NULL, off))
         goto err;
     if (priv) {
+        int i;
+
         if (!ASN1_bn_print(bp, "privateExponent:", x->d, NULL, off))
             goto err;
         if (!ASN1_bn_print(bp, "prime1:", x->p, NULL, off))
         if (!ASN1_bn_print(bp, "privateExponent:", x->d, NULL, off))
             goto err;
         if (!ASN1_bn_print(bp, "prime1:", x->p, NULL, off))
@@ -355,6 +359,39 @@ static int pkey_rsa_print(BIO *bp, const EVP_PKEY *pkey, int off, int priv)
             goto err;
         if (!ASN1_bn_print(bp, "coefficient:", x->iqmp, NULL, off))
             goto err;
             goto err;
         if (!ASN1_bn_print(bp, "coefficient:", x->iqmp, NULL, off))
             goto err;
+        for (i = 0; i < sk_RSA_PRIME_INFO_num(x->prime_infos); i++) {
+            /* print multi-prime info */
+            BIGNUM *bn = NULL;
+            RSA_PRIME_INFO *pinfo;
+            int j;
+
+            pinfo = sk_RSA_PRIME_INFO_value(x->prime_infos, i);
+            for (j = 0; j < 3; j++) {
+                if (!BIO_indent(bp, off, 128))
+                    goto err;
+                switch (j) {
+                case 0:
+                    if (BIO_printf(bp, "prime%d:", i + 3) <= 0)
+                        goto err;
+                    bn = pinfo->r;
+                    break;
+                case 1:
+                    if (BIO_printf(bp, "exponent%d:", i + 3) <= 0)
+                        goto err;
+                    bn = pinfo->d;
+                    break;
+                case 2:
+                    if (BIO_printf(bp, "coefficient%d:", i + 3) <= 0)
+                        goto err;
+                    bn = pinfo->t;
+                    break;
+                default:
+                    break;
+                }
+                if (!ASN1_bn_print(bp, "", bn, NULL, off))
+                    goto err;
+            }
+        }
     }
     if (pkey_is_pss(pkey) && !rsa_pss_param_print(bp, 1, x->pss, off))
         goto err;
     }
     if (pkey_is_pss(pkey) && !rsa_pss_param_print(bp, 1, x->pss, off))
         goto err;
index 43c8fc2..9fe62c8 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #include <openssl/asn1t.h>
 #include "rsa_locl.h"
 
 #include <openssl/asn1t.h>
 #include "rsa_locl.h"
 
-/* Override the default free and new methods */
+/*
+ * Override the default free and new methods,
+ * and calculate helper products for multi-prime
+ * RSA keys.
+ */
 static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                   void *exarg)
 {
 static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                   void *exarg)
 {
@@ -27,10 +31,23 @@ static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
         RSA_free((RSA *)*pval);
         *pval = NULL;
         return 2;
         RSA_free((RSA *)*pval);
         *pval = NULL;
         return 2;
+    } else if (operation == ASN1_OP_D2I_POST) {
+        if (((RSA *)*pval)->version != RSA_ASN1_VERSION_MULTI) {
+            /* not a multi-prime key, skip */
+            return 1;
+        }
+        return (rsa_multip_calc_product((RSA *)*pval) == 1) ? 2 : 0;
     }
     return 1;
 }
 
     }
     return 1;
 }
 
+/* Based on definitions in RFC 8017 appendix A.1.2 */
+ASN1_SEQUENCE(RSA_PRIME_INFO) = {
+        ASN1_SIMPLE(RSA_PRIME_INFO, r, CBIGNUM),
+        ASN1_SIMPLE(RSA_PRIME_INFO, d, CBIGNUM),
+        ASN1_SIMPLE(RSA_PRIME_INFO, t, CBIGNUM),
+} ASN1_SEQUENCE_END(RSA_PRIME_INFO)
+
 ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
         ASN1_EMBED(RSA, version, INT32),
         ASN1_SIMPLE(RSA, n, BIGNUM),
 ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
         ASN1_EMBED(RSA, version, INT32),
         ASN1_SIMPLE(RSA, n, BIGNUM),
@@ -40,7 +57,8 @@ ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
         ASN1_SIMPLE(RSA, q, CBIGNUM),
         ASN1_SIMPLE(RSA, dmp1, CBIGNUM),
         ASN1_SIMPLE(RSA, dmq1, CBIGNUM),
         ASN1_SIMPLE(RSA, q, CBIGNUM),
         ASN1_SIMPLE(RSA, dmp1, CBIGNUM),
         ASN1_SIMPLE(RSA, dmq1, CBIGNUM),
-        ASN1_SIMPLE(RSA, iqmp, CBIGNUM)
+        ASN1_SIMPLE(RSA, iqmp, CBIGNUM),
+        ASN1_SEQUENCE_OF_OPT(RSA, prime_infos, RSA_PRIME_INFO)
 } ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey)
 
 
 } ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey)
 
 
index 00260fb..4cf6822 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -20,7 +20,8 @@ int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
 {
     BIGNUM *i, *j, *k, *l, *m;
     BN_CTX *ctx;
 {
     BIGNUM *i, *j, *k, *l, *m;
     BN_CTX *ctx;
-    int ret = 1;
+    int ret = 1, ex_primes = 0, idx;
+    RSA_PRIME_INFO *pinfo;
 
     if (key->p == NULL || key->q == NULL || key->n == NULL
             || key->e == NULL || key->d == NULL) {
 
     if (key->p == NULL || key->q == NULL || key->n == NULL
             || key->e == NULL || key->d == NULL) {
@@ -28,6 +29,13 @@ int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
         return 0;
     }
 
         return 0;
     }
 
+    /* multi-prime? */
+    if (key->version == RSA_ASN1_VERSION_MULTI
+        && (ex_primes = sk_RSA_PRIME_INFO_num(key->prime_infos)) <= 0) {
+        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_INVALID_MULTI_PRIME_KEY);
+        return 0;
+    }
+
     i = BN_new();
     j = BN_new();
     k = BN_new();
     i = BN_new();
     j = BN_new();
     k = BN_new();
@@ -62,17 +70,37 @@ int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
         RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_Q_NOT_PRIME);
     }
 
         RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_Q_NOT_PRIME);
     }
 
-    /* n = p*q? */
+    /* r_i prime? */
+    for (idx = 0; idx < ex_primes; idx++) {
+        pinfo = sk_RSA_PRIME_INFO_value(key->prime_infos, idx);
+        if (BN_is_prime_ex(pinfo->r, BN_prime_checks, NULL, cb) != 1) {
+            ret = 0;
+            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_MP_R_NOT_PRIME);
+        }
+    }
+
+    /* n = p*q * r_3...r_i? */
     if (!BN_mul(i, key->p, key->q, ctx)) {
         ret = -1;
         goto err;
     }
     if (!BN_mul(i, key->p, key->q, ctx)) {
         ret = -1;
         goto err;
     }
+    for (idx = 0; idx < ex_primes; idx++) {
+        pinfo = sk_RSA_PRIME_INFO_value(key->prime_infos, idx);
+        if (!BN_mul(i, i, pinfo->r, ctx)) {
+            ret = -1;
+            goto err;
+        }
+    }
     if (BN_cmp(i, key->n) != 0) {
         ret = 0;
     if (BN_cmp(i, key->n) != 0) {
         ret = 0;
-        RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_N_DOES_NOT_EQUAL_P_Q);
+        if (ex_primes)
+            RSAerr(RSA_F_RSA_CHECK_KEY_EX,
+                   RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES);
+        else
+            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_N_DOES_NOT_EQUAL_P_Q);
     }
 
     }
 
-    /* d*e = 1  mod lcm(p-1,q-1)? */
+    /* d*e = 1  mod \lambda(n)? */
     if (!BN_sub(i, key->p, BN_value_one())) {
         ret = -1;
         goto err;
     if (!BN_sub(i, key->p, BN_value_one())) {
         ret = -1;
         goto err;
@@ -82,7 +110,7 @@ int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
         goto err;
     }
 
         goto err;
     }
 
-    /* now compute k = lcm(i,j) */
+    /* now compute k = \lambda(n) = LCM(i, j, r_3 - 1...) */
     if (!BN_mul(l, i, j, ctx)) {
         ret = -1;
         goto err;
     if (!BN_mul(l, i, j, ctx)) {
         ret = -1;
         goto err;
@@ -91,6 +119,21 @@ int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
         ret = -1;
         goto err;
     }
         ret = -1;
         goto err;
     }
+    for (idx = 0; idx < ex_primes; idx++) {
+        pinfo = sk_RSA_PRIME_INFO_value(key->prime_infos, idx);
+        if (!BN_sub(k, pinfo->r, BN_value_one())) {
+            ret = -1;
+            goto err;
+        }
+        if (!BN_mul(l, l, k, ctx)) {
+            ret = -1;
+            goto err;
+        }
+        if (!BN_gcd(m, m, k, ctx)) {
+            ret = -1;
+            goto err;
+        }
+    }
     if (!BN_div(k, NULL, l, m, ctx)) { /* remainder is 0 */
         ret = -1;
         goto err;
     if (!BN_div(k, NULL, l, m, ctx)) { /* remainder is 0 */
         ret = -1;
         goto err;
@@ -145,6 +188,32 @@ int RSA_check_key_ex(const RSA *key, BN_GENCB *cb)
         }
     }
 
         }
     }
 
+    for (idx = 0; idx < ex_primes; idx++) {
+        pinfo = sk_RSA_PRIME_INFO_value(key->prime_infos, idx);
+        /* d_i = d mod (r_i - 1)? */
+        if (!BN_sub(i, pinfo->r, BN_value_one())) {
+            ret = -1;
+            goto err;
+        }
+        if (!BN_mod(j, key->d, i, ctx)) {
+            ret = -1;
+            goto err;
+        }
+        if (BN_cmp(j, pinfo->d) != 0) {
+            ret = 0;
+            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D);
+        }
+        /* t_i = R_i ^ -1 mod r_i ? */
+        if (!BN_mod_inverse(i, pinfo->pp, pinfo->r, ctx)) {
+            ret = -1;
+            goto err;
+        }
+        if (BN_cmp(i, pinfo->t) != 0) {
+            ret = 0;
+            RSAerr(RSA_F_RSA_CHECK_KEY_EX, RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R);
+        }
+    }
+
  err:
     BN_free(i);
     BN_free(j);
  err:
     BN_free(i);
     BN_free(j);
index 74b0fee..f7d29e1 100644 (file)
@@ -147,6 +147,8 @@ static const ERR_STRING_DATA RSA_str_reasons[] = {
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MESSAGE_LENGTH),
     "invalid message length"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MGF1_MD), "invalid mgf1 md"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MESSAGE_LENGTH),
     "invalid message length"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MGF1_MD), "invalid mgf1 md"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MULTI_PRIME_KEY),
+    "invalid multi prime key"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_OAEP_PARAMETERS),
     "invalid oaep parameters"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_PADDING), "invalid padding"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_OAEP_PARAMETERS),
     "invalid oaep parameters"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_PADDING), "invalid padding"},
@@ -163,14 +165,23 @@ static const ERR_STRING_DATA RSA_str_reasons[] = {
     "invalid x931 digest"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_IQMP_NOT_INVERSE_OF_Q),
     "iqmp not inverse of q"},
     "invalid x931 digest"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_IQMP_NOT_INVERSE_OF_Q),
     "iqmp not inverse of q"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_KEY_PRIME_NUM_INVALID),
+    "key prime num invalid"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_KEY_SIZE_TOO_SMALL), "key size too small"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_LAST_OCTET_INVALID), "last octet invalid"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MGF1_DIGEST_NOT_ALLOWED),
     "mgf1 digest not allowed"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MODULUS_TOO_LARGE), "modulus too large"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_KEY_SIZE_TOO_SMALL), "key size too small"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_LAST_OCTET_INVALID), "last octet invalid"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MGF1_DIGEST_NOT_ALLOWED),
     "mgf1 digest not allowed"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MODULUS_TOO_LARGE), "modulus too large"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R),
+    "mp coefficient not inverse of r"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D),
+    "mp exponent not congruent to d"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MP_R_NOT_PRIME), "mp r not prime"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NO_PUBLIC_EXPONENT), "no public exponent"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NULL_BEFORE_BLOCK_MISSING),
     "null before block missing"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NO_PUBLIC_EXPONENT), "no public exponent"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NULL_BEFORE_BLOCK_MISSING),
     "null before block missing"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES),
+    "n does not equal product of primes"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_N_DOES_NOT_EQUAL_P_Q),
     "n does not equal p q"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OAEP_DECODING_ERROR),
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_N_DOES_NOT_EQUAL_P_Q),
     "n does not equal p q"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OAEP_DECODING_ERROR),
index 4ced965..f7f6075 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -19,7 +19,7 @@
 #include <openssl/bn.h>
 #include "rsa_locl.h"
 
 #include <openssl/bn.h>
 #include "rsa_locl.h"
 
-static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
+static int rsa_builtin_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value,
                               BN_GENCB *cb);
 
 /*
                               BN_GENCB *cb);
 
 /*
@@ -31,17 +31,43 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
  */
 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb)
 {
  */
 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb)
 {
-    if (rsa->meth->rsa_keygen)
+    if (rsa->meth->rsa_keygen != NULL)
         return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
         return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
-    return rsa_builtin_keygen(rsa, bits, e_value, cb);
+
+    return RSA_generate_multi_prime_key(rsa, bits, RSA_DEFAULT_PRIME_NUM,
+                                        e_value, cb);
 }
 
 }
 
-static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
+int RSA_generate_multi_prime_key(RSA *rsa, int bits, int primes,
+                                 BIGNUM *e_value, BN_GENCB *cb)
+{
+    /* multi-prime is only supported with the builtin key generation */
+    if (rsa->meth->rsa_multi_prime_keygen != NULL)
+        return rsa->meth->rsa_multi_prime_keygen(rsa, bits, primes,
+                                                 e_value, cb);
+    return rsa_builtin_keygen(rsa, bits, primes, e_value, cb);
+}
+
+static int rsa_builtin_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value,
                               BN_GENCB *cb)
 {
                               BN_GENCB *cb)
 {
-    BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
-    int bitsp, bitsq, ok = -1, n = 0;
+    BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *tmp, *prime;
+    int ok = -1, n = 0, bitsr[RSA_MAX_PRIME_NUM], bitse = 0;
+    int i = 0, quo = 0, rmd = 0, adj = 0, retries = 0;
+    RSA_PRIME_INFO *pinfo = NULL;
+    STACK_OF(RSA_PRIME_INFO) *prime_infos = NULL;
     BN_CTX *ctx = NULL;
     BN_CTX *ctx = NULL;
+    BN_ULONG bitst = 0;
+
+    /*
+     * From Github pull request #4241:
+     *
+     * We are in disagreement on how to handle security trade-off, in other
+     * words:
+     *
+     * mechanical-check-for-maximum-of-16-prime-factors vs.
+     * limiting-number-depending-on-length-less-factors-for-shorter-keys.
+     */
 
     /*
      * When generating ridiculously small keys, we can get stuck
 
     /*
      * When generating ridiculously small keys, we can get stuck
@@ -53,6 +79,12 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
         goto err;
     }
 
         goto err;
     }
 
+    if (primes < RSA_DEFAULT_PRIME_NUM
+        || primes > RSA_MAX_PRIME_NUM || bits <= primes) {
+        RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_PRIME_NUM_INVALID);
+        goto err;
+    }
+
     ctx = BN_CTX_new();
     if (ctx == NULL)
         goto err;
     ctx = BN_CTX_new();
     if (ctx == NULL)
         goto err;
@@ -60,12 +92,29 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
     r0 = BN_CTX_get(ctx);
     r1 = BN_CTX_get(ctx);
     r2 = BN_CTX_get(ctx);
     r0 = BN_CTX_get(ctx);
     r1 = BN_CTX_get(ctx);
     r2 = BN_CTX_get(ctx);
-    r3 = BN_CTX_get(ctx);
-    if (r3 == NULL)
+    if (r2 == NULL)
+        goto err;
+
+    /* divide bits into 'primes' pieces evenly */
+    quo = bits / primes;
+    rmd = bits % primes;
+
+    if (primes > RSA_DEFAULT_PRIME_NUM && quo < RSA_MIN_PRIME_SIZE) {
+        /*
+         * this means primes are too many for the key bits.
+         *
+         * This only affects multi-prime keys. For normal RSA,
+         * it's limited above (bits >= 16, hence each prime >= 8).
+         *
+         * This is done in this way because the original normal
+         * RSA's behavior should not alter at least in OpenSSL 1.1.1.
+         */
+        RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_PRIME_NUM_INVALID);
         goto err;
         goto err;
+    }
 
 
-    bitsp = (bits + 1) / 2;
-    bitsq = bits - bitsp;
+    for (i = 0; i < primes; i++)
+        bitsr[i] = (i < rmd) ? quo + 1 : quo;
 
     /* We need the RSA components non-NULL */
     if (!rsa->n && ((rsa->n = BN_new()) == NULL))
 
     /* We need the RSA components non-NULL */
     if (!rsa->n && ((rsa->n = BN_new()) == NULL))
@@ -85,62 +134,191 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
     if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL))
         goto err;
 
     if (!rsa->iqmp && ((rsa->iqmp = BN_secure_new()) == NULL))
         goto err;
 
+    /* initialize multi-prime components */
+    if (primes > RSA_DEFAULT_PRIME_NUM) {
+        rsa->version = RSA_ASN1_VERSION_MULTI;
+        prime_infos = sk_RSA_PRIME_INFO_new_reserve(NULL, primes - 2);
+        if (prime_infos == NULL)
+            goto err;
+        if (rsa->prime_infos != NULL) {
+            /* could this happen? */
+            sk_RSA_PRIME_INFO_pop_free(rsa->prime_infos, rsa_multip_info_free);
+        }
+        rsa->prime_infos = prime_infos;
+
+        /* prime_info from 2 to |primes| -1 */
+        for (i = 2; i < primes; i++) {
+            pinfo = rsa_multip_info_new();
+            if (pinfo == NULL)
+                goto err;
+            (void)sk_RSA_PRIME_INFO_push(prime_infos, pinfo);
+        }
+    }
+
     if (BN_copy(rsa->e, e_value) == NULL)
         goto err;
 
     if (BN_copy(rsa->e, e_value) == NULL)
         goto err;
 
-    /* generate p and q */
-    for (;;) {
-        if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb))
-            goto err;
-        if (!BN_sub(r2, rsa->p, BN_value_one()))
-            goto err;
-        if (!BN_gcd(r1, r2, rsa->e, ctx))
-            goto err;
-        if (BN_is_one(r1))
-            break;
-        if (!BN_GENCB_call(cb, 2, n++))
+    /* generate p, q and other primes (if any) */
+    for (i = 0; i < primes; i++) {
+        adj = 0;
+        retries = 0;
+
+        if (i == 0) {
+            prime = rsa->p;
+        } else if (i == 1) {
+            prime = rsa->q;
+        } else {
+            pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2);
+            prime = pinfo->r;
+        }
+
+        for (;;) {
+ redo:
+            if (!BN_generate_prime_ex(prime, bitsr[i] + adj, 0, NULL, NULL, cb))
+                goto err;
+            /*
+             * prime should not be equal to p, q, r_3...
+             * (those primes prior to this one)
+             */
+            {
+                int j;
+
+                for (j = 0; j < i; j++) {
+                    BIGNUM *prev_prime;
+
+                    if (j == 0)
+                        prev_prime = rsa->p;
+                    else if (j == 1)
+                        prev_prime = rsa->q;
+                    else
+                        prev_prime = sk_RSA_PRIME_INFO_value(prime_infos,
+                                                             j - 2)->r;
+
+                    if (!BN_cmp(prime, prev_prime)) {
+                        goto redo;
+                    }
+                }
+            }
+            if (!BN_sub(r2, prime, BN_value_one()))
+                goto err;
+            if (!BN_gcd(r1, r2, rsa->e, ctx))
+                goto err;
+            if (BN_is_one(r1))
+                break;
+            if (!BN_GENCB_call(cb, 2, n++))
+                goto err;
+        }
+
+        bitse += bitsr[i];
+
+        /* calculate n immediately to see if it's sufficient */
+        if (i == 1) {
+            /* we get at least 2 primes */
+            if (!BN_mul(r1, rsa->p, rsa->q, ctx))
+                goto err;
+        } else if (i != 0) {
+            /* modulus n = p * q * r_3 * r_4 ... */
+            if (!BN_mul(r1, rsa->n, prime, ctx))
+                goto err;
+        } else {
+            /* i == 0, do nothing */
+            if (!BN_GENCB_call(cb, 3, i))
+                goto err;
+            continue;
+        }
+        /*
+         * if |r1|, product of factors so far, is not as long as expected
+         * (by checking the first 4 bits are less than 0x9 or greater than
+         * 0xF). If so, re-generate the last prime.
+         *
+         * NOTE: This actually can't happen in two-prime case, because of
+         * the way factors are generated.
+         *
+         * Besides, another consideration is, for multi-prime case, even the
+         * length modulus is as long as expected, the modulus could start at
+         * 0x8, which could be utilized to distinguish a multi-prime private
+         * key by using the modulus in a certificate. This is also covered
+         * by checking the length should not be less than 0x9.
+         */
+        if (!BN_rshift(r2, r1, bitse - 4))
             goto err;
             goto err;
-    }
-    if (!BN_GENCB_call(cb, 3, 0))
-        goto err;
-    for (;;) {
-        do {
-            if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb))
+        bitst = BN_get_word(r2);
+
+        if (bitst < 0x9 || bitst > 0xF) {
+            /*
+             * For keys with more than 4 primes, we attempt longer factor to
+             * meet length requirement.
+             *
+             * Otherwise, we just re-generate the prime with the same length.
+             *
+             * This strategy has the following goals:
+             *
+             * 1. 1024-bit factors are effcient when using 3072 and 4096-bit key
+             * 2. stay the same logic with normal 2-prime key
+             */
+            bitse -= bitsr[i];
+            if (!BN_GENCB_call(cb, 2, n++))
                 goto err;
                 goto err;
-        } while (BN_cmp(rsa->p, rsa->q) == 0);
-        if (!BN_sub(r2, rsa->q, BN_value_one()))
+            if (primes > 4) {
+                if (bitst < 0x9)
+                    adj++;
+                else
+                    adj--;
+            } else if (retries == 4) {
+                /*
+                 * re-generate all primes from scratch, mainly used
+                 * in 4 prime case to avoid long loop. Max retry times
+                 * is set to 4.
+                 */
+                i = -1;
+                bitse = 0;
+                continue;
+            }
+            retries++;
+            goto redo;
+        }
+        /* save product of primes for further use, for multi-prime only */
+        if (i > 1 && BN_copy(pinfo->pp, rsa->n) == NULL)
             goto err;
             goto err;
-        if (!BN_gcd(r1, r2, rsa->e, ctx))
+        if (BN_copy(rsa->n, r1) == NULL)
             goto err;
             goto err;
-        if (BN_is_one(r1))
-            break;
-        if (!BN_GENCB_call(cb, 2, n++))
+        if (!BN_GENCB_call(cb, 3, i))
             goto err;
     }
             goto err;
     }
-    if (!BN_GENCB_call(cb, 3, 1))
-        goto err;
+
     if (BN_cmp(rsa->p, rsa->q) < 0) {
         tmp = rsa->p;
         rsa->p = rsa->q;
         rsa->q = tmp;
     }
 
     if (BN_cmp(rsa->p, rsa->q) < 0) {
         tmp = rsa->p;
         rsa->p = rsa->q;
         rsa->q = tmp;
     }
 
-    /* calculate n */
-    if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx))
-        goto err;
-
     /* calculate d */
     /* calculate d */
+
+    /* p - 1 */
     if (!BN_sub(r1, rsa->p, BN_value_one()))
     if (!BN_sub(r1, rsa->p, BN_value_one()))
-        goto err;               /* p-1 */
+        goto err;
+    /* q - 1 */
     if (!BN_sub(r2, rsa->q, BN_value_one()))
     if (!BN_sub(r2, rsa->q, BN_value_one()))
-        goto err;               /* q-1 */
+        goto err;
+    /* (p - 1)(q - 1) */
     if (!BN_mul(r0, r1, r2, ctx))
     if (!BN_mul(r0, r1, r2, ctx))
-        goto err;               /* (p-1)(q-1) */
+        goto err;
+    /* multi-prime */
+    for (i = 2; i < primes; i++) {
+        pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2);
+        /* save r_i - 1 to pinfo->d temporarily */
+        if (!BN_sub(pinfo->d, pinfo->r, BN_value_one()))
+            goto err;
+        if (!BN_mul(r0, r0, pinfo->d, ctx))
+            goto err;
+    }
+
     {
         BIGNUM *pr0 = BN_new();
 
         if (pr0 == NULL)
             goto err;
     {
         BIGNUM *pr0 = BN_new();
 
         if (pr0 == NULL)
             goto err;
+
         BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
         if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
             BN_free(pr0);
         BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
         if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
             BN_free(pr0);
@@ -155,15 +333,26 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
 
         if (d == NULL)
             goto err;
 
         if (d == NULL)
             goto err;
+
         BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
 
         BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
 
-        if (   /* calculate d mod (p-1) */
-               !BN_mod(rsa->dmp1, d, r1, ctx)
-               /* calculate d mod (q-1) */
+        /* calculate d mod (p-1) and d mod (q - 1) */
+        if (!BN_mod(rsa->dmp1, d, r1, ctx)
             || !BN_mod(rsa->dmq1, d, r2, ctx)) {
             BN_free(d);
             goto err;
         }
             || !BN_mod(rsa->dmq1, d, r2, ctx)) {
             BN_free(d);
             goto err;
         }
+
+        /* calculate CRT exponents */
+        for (i = 2; i < primes; i++) {
+            pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2);
+            /* pinfo->d == r_i - 1 */
+            if (!BN_mod(pinfo->d, d, pinfo->d, ctx)) {
+                BN_free(d);
+                goto err;
+            }
+        }
+
         /* We MUST free d before any further use of rsa->d */
         BN_free(d);
     }
         /* We MUST free d before any further use of rsa->d */
         BN_free(d);
     }
@@ -180,6 +369,17 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
             BN_free(p);
             goto err;
         }
             BN_free(p);
             goto err;
         }
+
+        /* calculate CRT coefficient for other primes */
+        for (i = 2; i < primes; i++) {
+            pinfo = sk_RSA_PRIME_INFO_value(prime_infos, i - 2);
+            BN_with_flags(p, pinfo->r, BN_FLG_CONSTTIME);
+            if (!BN_mod_inverse(pinfo->t, pinfo->pp, p, ctx)) {
+                BN_free(p);
+                goto err;
+            }
+        }
+
         /* We MUST free p before any further use of rsa->p */
         BN_free(p);
     }
         /* We MUST free p before any further use of rsa->p */
         BN_free(p);
     }
@@ -193,6 +393,5 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value,
     if (ctx != NULL)
         BN_CTX_end(ctx);
     BN_CTX_free(ctx);
     if (ctx != NULL)
         BN_CTX_end(ctx);
     BN_CTX_free(ctx);
-
     return ok;
 }
     return ok;
 }
index e43d823..198dbd3 100644 (file)
@@ -134,6 +134,7 @@ void RSA_free(RSA *r)
     BN_clear_free(r->dmq1);
     BN_clear_free(r->iqmp);
     RSA_PSS_PARAMS_free(r->pss);
     BN_clear_free(r->dmq1);
     BN_clear_free(r->iqmp);
     RSA_PSS_PARAMS_free(r->pss);
+    sk_RSA_PRIME_INFO_pop_free(r->prime_infos, rsa_multip_info_free);
     BN_BLINDING_free(r->blinding);
     BN_BLINDING_free(r->mt_blinding);
     OPENSSL_free(r->bignum_data);
     BN_BLINDING_free(r->blinding);
     BN_BLINDING_free(r->mt_blinding);
     OPENSSL_free(r->bignum_data);
@@ -240,6 +241,71 @@ int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
     return 1;
 }
 
     return 1;
 }
 
+/*
+ * Is it better to export RSA_PRIME_INFO structure
+ * and related functions to let user pass a triplet?
+ */
+int RSA_set0_multi_prime_params(RSA *r, BIGNUM *primes[], BIGNUM *exps[],
+                                BIGNUM *coeffs[], int pnum)
+{
+    STACK_OF(RSA_PRIME_INFO) *prime_infos, *old = NULL;
+    RSA_PRIME_INFO *pinfo;
+    int i;
+
+    if (primes == NULL || exps == NULL || coeffs == NULL || pnum == 0)
+        return 0;
+
+    prime_infos = sk_RSA_PRIME_INFO_new_reserve(NULL, pnum);
+    if (prime_infos == NULL)
+        return 0;
+
+    if (r->prime_infos != NULL)
+        old = r->prime_infos;
+
+    for (i = 0; i < pnum; i++) {
+        pinfo = rsa_multip_info_new();
+        if (pinfo == NULL)
+            goto err;
+        if (primes[i] != NULL && exps[i] != NULL && coeffs[i] != NULL) {
+            BN_free(pinfo->r);
+            BN_free(pinfo->d);
+            BN_free(pinfo->t);
+            pinfo->r = primes[i];
+            pinfo->d = exps[i];
+            pinfo->t = coeffs[i];
+        } else {
+            rsa_multip_info_free(pinfo);
+            goto err;
+        }
+        (void)sk_RSA_PRIME_INFO_push(prime_infos, pinfo);
+    }
+
+    r->prime_infos = prime_infos;
+
+    if (!rsa_multip_calc_product(r)) {
+        r->prime_infos = old;
+        goto err;
+    }
+
+    if (old != NULL) {
+        /*
+         * This is hard to deal with, since the old infos could
+         * also be set by this function and r, d, t should not
+         * be freed in that case. So currently, stay consistent
+         * with other *set0* functions: just free it...
+         */
+        sk_RSA_PRIME_INFO_pop_free(old, rsa_multip_info_free);
+    }
+
+    r->version = RSA_ASN1_VERSION_MULTI;
+
+    return 1;
+ err:
+    /* r, d, t should not be freed */
+    sk_RSA_PRIME_INFO_pop_free(prime_infos, rsa_multip_info_free_ex);
+    return 0;
+}
+
 void RSA_get0_key(const RSA *r,
                   const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
 {
 void RSA_get0_key(const RSA *r,
                   const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
 {
@@ -259,6 +325,36 @@ void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
         *q = r->q;
 }
 
         *q = r->q;
 }
 
+int RSA_get_multi_prime_extra_count(const RSA *r)
+{
+    int pnum;
+
+    pnum = sk_RSA_PRIME_INFO_num(r->prime_infos);
+    if (pnum <= 0)
+        pnum = 0;
+    return pnum;
+}
+
+int RSA_get0_multi_prime_factors(const RSA *r, const BIGNUM *primes[])
+{
+    int pnum, i;
+    RSA_PRIME_INFO *pinfo;
+
+    if ((pnum = RSA_get_multi_prime_extra_count(r)) == 0)
+        return 0;
+
+    /*
+     * return other primes
+     * it's caller's responsibility to allocate oth_primes[pnum]
+     */
+    for (i = 0; i < pnum; i++) {
+        pinfo = sk_RSA_PRIME_INFO_value(r->prime_infos, i);
+        primes[i] = pinfo->r;
+    }
+
+    return 1;
+}
+
 void RSA_get0_crt_params(const RSA *r,
                          const BIGNUM **dmp1, const BIGNUM **dmq1,
                          const BIGNUM **iqmp)
 void RSA_get0_crt_params(const RSA *r,
                          const BIGNUM **dmp1, const BIGNUM **dmq1,
                          const BIGNUM **iqmp)
@@ -271,6 +367,32 @@ void RSA_get0_crt_params(const RSA *r,
         *iqmp = r->iqmp;
 }
 
         *iqmp = r->iqmp;
 }
 
+int RSA_get0_multi_prime_crt_params(const RSA *r, const BIGNUM *exps[],
+                                    const BIGNUM *coeffs[])
+{
+    int pnum;
+
+    if ((pnum = RSA_get_multi_prime_extra_count(r)) == 0)
+        return 0;
+
+    /* return other primes */
+    if (exps != NULL || coeffs != NULL) {
+        RSA_PRIME_INFO *pinfo;
+        int i;
+
+        /* it's the user's job to guarantee the buffer length */
+        for (i = 0; i < pnum; i++) {
+            pinfo = sk_RSA_PRIME_INFO_value(r->prime_infos, i);
+            if (exps != NULL)
+                exps[i] = pinfo->d;
+            if (coeffs != NULL)
+                coeffs[i] = pinfo->t;
+        }
+    }
+
+    return 1;
+}
+
 void RSA_clear_flags(RSA *r, int flags)
 {
     r->flags &= ~flags;
 void RSA_clear_flags(RSA *r, int flags)
 {
     r->flags &= ~flags;
@@ -286,6 +408,12 @@ void RSA_set_flags(RSA *r, int flags)
     r->flags |= flags;
 }
 
     r->flags |= flags;
 }
 
+int RSA_get_version(RSA *r)
+{
+    /* { two-prime(0), multi(1) } */
+    return r->version;
+}
+
 ENGINE *RSA_get0_engine(const RSA *r)
 {
     return r->engine;
 ENGINE *RSA_get0_engine(const RSA *r)
 {
     return r->engine;
index be3ef0c..6a53d89 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #include <openssl/rsa.h>
 #include "internal/refcount.h"
 
 #include <openssl/rsa.h>
 #include "internal/refcount.h"
 
+#define RSA_MAX_PRIME_NUM 16
+#define RSA_MIN_PRIME_SIZE 64
+
+typedef struct rsa_prime_info_st {
+    BIGNUM *r;
+    BIGNUM *d;
+    BIGNUM *t;
+    /* save product of primes prior to this one */
+    BIGNUM *pp;
+    BN_MONT_CTX *m;
+} RSA_PRIME_INFO;
+
+DECLARE_ASN1_ITEM(RSA_PRIME_INFO)
+DEFINE_STACK_OF(RSA_PRIME_INFO)
+
 struct rsa_st {
     /*
      * The first parameter is used to pickup errors where this is passed
 struct rsa_st {
     /*
      * The first parameter is used to pickup errors where this is passed
@@ -28,6 +43,8 @@ struct rsa_st {
     BIGNUM *dmp1;
     BIGNUM *dmq1;
     BIGNUM *iqmp;
     BIGNUM *dmp1;
     BIGNUM *dmq1;
     BIGNUM *iqmp;
+    /* for multi-prime RSA, defined in RFC 8017 */
+    STACK_OF(RSA_PRIME_INFO) *prime_infos;
     /* If a PSS only key this contains the parameter restrictions */
     RSA_PSS_PARAMS *pss;
     /* be careful using this if the RSA structure is shared */
     /* If a PSS only key this contains the parameter restrictions */
     RSA_PSS_PARAMS *pss;
     /* be careful using this if the RSA structure is shared */
@@ -91,6 +108,8 @@ struct rsa_meth_st {
      * things as "builtin software" implementations.
      */
     int (*rsa_keygen) (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
      * things as "builtin software" implementations.
      */
     int (*rsa_keygen) (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+    int (*rsa_multi_prime_keygen) (RSA *rsa, int bits, int primes,
+                                   BIGNUM *e, BN_GENCB *cb);
 };
 
 extern int int_rsa_verify(int dtype, const unsigned char *m,
 };
 
 extern int int_rsa_verify(int dtype, const unsigned char *m,
@@ -105,3 +124,8 @@ RSA_PSS_PARAMS *rsa_pss_params_create(const EVP_MD *sigmd,
                                       const EVP_MD *mgf1md, int saltlen);
 int rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd,
                       const EVP_MD **pmgf1md, int *psaltlen);
                                       const EVP_MD *mgf1md, int saltlen);
 int rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd,
                       const EVP_MD **pmgf1md, int *psaltlen);
+/* internal function to clear and free multi-prime parameters */
+void rsa_multip_info_free_ex(RSA_PRIME_INFO *pinfo);
+void rsa_multip_info_free(RSA_PRIME_INFO *pinfo);
+RSA_PRIME_INFO *rsa_multip_info_new(void);
+int rsa_multip_calc_product(RSA *rsa);
index 9480abd..5dccc33 100644 (file)
@@ -271,3 +271,17 @@ int RSA_meth_set_keygen(RSA_METHOD *meth,
     return 1;
 }
 
     return 1;
 }
 
+int (*RSA_meth_get_multi_prime_keygen(const RSA_METHOD *meth))
+    (RSA *rsa, int bits, int primes, BIGNUM *e, BN_GENCB *cb)
+{
+    return meth->rsa_multi_prime_keygen;
+}
+
+int RSA_meth_set_multi_prime_keygen(RSA_METHOD *meth,
+                                    int (*keygen) (RSA *rsa, int bits,
+                                                   int primes, BIGNUM *e,
+                                                   BN_GENCB *cb))
+{
+    meth->rsa_multi_prime_keygen = keygen;
+    return 1;
+}
diff --git a/crypto/rsa/rsa_mp.c b/crypto/rsa/rsa_mp.c
new file mode 100644 (file)
index 0000000..d970564
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017 BaishanCloud. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (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/bn.h>
+#include "rsa_locl.h"
+
+void rsa_multip_info_free_ex(RSA_PRIME_INFO *pinfo)
+{
+    /* free pp and pinfo only */
+    BN_clear_free(pinfo->pp);
+    OPENSSL_free(pinfo);
+}
+
+void rsa_multip_info_free(RSA_PRIME_INFO *pinfo)
+{
+    /* free a RSA_PRIME_INFO structure */
+    BN_clear_free(pinfo->r);
+    BN_clear_free(pinfo->d);
+    BN_clear_free(pinfo->t);
+    rsa_multip_info_free_ex(pinfo);
+}
+
+RSA_PRIME_INFO *rsa_multip_info_new(void)
+{
+    RSA_PRIME_INFO *pinfo;
+
+    /* create a RSA_PRIME_INFO structure */
+    pinfo = OPENSSL_zalloc(sizeof(RSA_PRIME_INFO));
+    if (pinfo == NULL)
+        return NULL;
+    if ((pinfo->r = BN_secure_new()) == NULL)
+        goto err;
+    if ((pinfo->d = BN_secure_new()) == NULL)
+        goto err;
+    if ((pinfo->t = BN_secure_new()) == NULL)
+        goto err;
+    if ((pinfo->pp = BN_secure_new()) == NULL)
+        goto err;
+
+    return pinfo;
+
+ err:
+    BN_free(pinfo->r);
+    BN_free(pinfo->d);
+    BN_free(pinfo->t);
+    BN_free(pinfo->pp);
+    return NULL;
+}
+
+/* Refill products of primes */
+int rsa_multip_calc_product(RSA *rsa)
+{
+    RSA_PRIME_INFO *pinfo;
+    BIGNUM *p1 = NULL, *p2 = NULL;
+    BN_CTX *ctx = NULL;
+    int i, rv = 0, ex_primes;
+
+    if ((ex_primes = sk_RSA_PRIME_INFO_num(rsa->prime_infos)) <= 0) {
+        /* invalid */
+        goto err;
+    }
+
+    if ((ctx = BN_CTX_new()) == NULL)
+        goto err;
+
+    /* calculate pinfo->pp = p * q for first 'extra' prime */
+    p1 = rsa->p;
+    p2 = rsa->q;
+
+    for (i = 0; i < ex_primes; i++) {
+        pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+        if (pinfo->pp == NULL) {
+            pinfo->pp = BN_secure_new();
+            if (pinfo->pp == NULL)
+                goto err;
+        }
+        if (!BN_mul(pinfo->pp, p1, p2, ctx))
+            goto err;
+        /* save previous one */
+        p1 = pinfo->pp;
+        p2 = pinfo->r;
+    }
+
+    rv = 1;
+ err:
+    BN_CTX_free(ctx);
+    return rv;
+}
index 40c84dd..ced11ad 100644 (file)
@@ -38,7 +38,8 @@ static RSA_METHOD rsa_pkcs1_ossl_meth = {
     NULL,
     0,                          /* rsa_sign */
     0,                          /* rsa_verify */
     NULL,
     0,                          /* rsa_sign */
     0,                          /* rsa_verify */
-    NULL                        /* rsa_keygen */
+    NULL,                       /* rsa_keygen */
+    NULL                        /* rsa_multi_prime_keygen */
 };
 
 static const RSA_METHOD *default_RSA_meth = &rsa_pkcs1_ossl_meth;
 };
 
 static const RSA_METHOD *default_RSA_meth = &rsa_pkcs1_ossl_meth;
@@ -308,6 +309,7 @@ static int rsa_ossl_private_encrypt(int flen, const unsigned char *from,
     }
 
     if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
     }
 
     if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
+        (rsa->version == RSA_ASN1_VERSION_MULTI) ||
         ((rsa->p != NULL) &&
          (rsa->q != NULL) &&
          (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
         ((rsa->p != NULL) &&
          (rsa->q != NULL) &&
          (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
@@ -437,6 +439,7 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from,
 
     /* do the decrypt */
     if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
 
     /* do the decrypt */
     if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
+        (rsa->version == RSA_ASN1_VERSION_MULTI) ||
         ((rsa->p != NULL) &&
          (rsa->q != NULL) &&
          (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
         ((rsa->p != NULL) &&
          (rsa->q != NULL) &&
          (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
@@ -601,17 +604,23 @@ static int rsa_ossl_public_decrypt(int flen, const unsigned char *from,
 
 static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
 {
 
 static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
 {
-    BIGNUM *r1, *m1, *vrfy;
-    int ret = 0;
+    BIGNUM *r1, *m1, *vrfy, *r2, *m[RSA_MAX_PRIME_NUM];
+    int ret = 0, i, ex_primes = 0;
+    RSA_PRIME_INFO *pinfo;
 
     BN_CTX_start(ctx);
 
     r1 = BN_CTX_get(ctx);
 
     BN_CTX_start(ctx);
 
     r1 = BN_CTX_get(ctx);
+    r2 = BN_CTX_get(ctx);
     m1 = BN_CTX_get(ctx);
     vrfy = BN_CTX_get(ctx);
     if (vrfy == NULL)
         goto err;
 
     m1 = BN_CTX_get(ctx);
     vrfy = BN_CTX_get(ctx);
     if (vrfy == NULL)
         goto err;
 
+    if (rsa->version == RSA_ASN1_VERSION_MULTI
+        && (ex_primes = sk_RSA_PRIME_INFO_num(rsa->prime_infos)) <= 0)
+        goto err;
+
     {
         BIGNUM *p = BN_new(), *q = BN_new();
 
     {
         BIGNUM *p = BN_new(), *q = BN_new();
 
@@ -636,6 +645,28 @@ static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
                 BN_free(q);
                 goto err;
             }
                 BN_free(q);
                 goto err;
             }
+            if (ex_primes > 0) {
+                /* cache BN_MONT_CTX for other primes */
+                BIGNUM *r = BN_new();
+
+                if (r == NULL) {
+                    BN_free(p);
+                    BN_free(q);
+                    goto err;
+                }
+
+                for (i = 0; i < ex_primes; i++) {
+                    pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+                    BN_with_flags(r, pinfo->r, BN_FLG_CONSTTIME);
+                    if (!BN_MONT_CTX_set_locked(&pinfo->m, rsa->lock, r, ctx)) {
+                        BN_free(p);
+                        BN_free(q);
+                        BN_free(r);
+                        goto err;
+                    }
+                }
+                BN_free(r);
+            }
         }
         /*
          * We MUST free p and q before any further use of rsa->p and rsa->q
         }
         /*
          * We MUST free p and q before any further use of rsa->p and rsa->q
@@ -705,6 +736,56 @@ static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
         BN_free(dmp1);
     }
 
         BN_free(dmp1);
     }
 
+    /*
+     * calculate m_i in multi-prime case
+     *
+     * TODO:
+     * 1. squash the following two loops and calculate |m_i| there.
+     * 2. remove cc and reuse |c|.
+     * 3. remove |dmq1| and |dmp1| in previous block and use |di|.
+     *
+     * If these things are done, the code will be more readable.
+     */
+    if (ex_primes > 0) {
+        BIGNUM *di = BN_new(), *cc = BN_new();
+
+        if (cc == NULL || di == NULL) {
+            BN_free(cc);
+            BN_free(di);
+            goto err;
+        }
+
+        for (i = 0; i < ex_primes; i++) {
+            /* prepare m_i */
+            if ((m[i] = BN_CTX_get(ctx)) == NULL) {
+                BN_free(cc);
+                BN_free(di);
+                goto err;
+            }
+
+            pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+
+            /* prepare c and d_i */
+            BN_with_flags(cc, I, BN_FLG_CONSTTIME);
+            BN_with_flags(di, pinfo->d, BN_FLG_CONSTTIME);
+
+            if (!BN_mod(r1, cc, pinfo->r, ctx)) {
+                BN_free(cc);
+                BN_free(di);
+                goto err;
+            }
+            /* compute r1 ^ d_i mod r_i */
+            if (!rsa->meth->bn_mod_exp(m[i], r1, di, pinfo->r, ctx, pinfo->m)) {
+                BN_free(cc);
+                BN_free(di);
+                goto err;
+            }
+        }
+
+        BN_free(cc);
+        BN_free(di);
+    }
+
     if (!BN_sub(r0, r0, m1))
         goto err;
     /*
     if (!BN_sub(r0, r0, m1))
         goto err;
     /*
@@ -747,6 +828,49 @@ static int rsa_ossl_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
     if (!BN_add(r0, r1, m1))
         goto err;
 
     if (!BN_add(r0, r1, m1))
         goto err;
 
+    /* add m_i to m in multi-prime case */
+    if (ex_primes > 0) {
+        BIGNUM *pr2 = BN_new();
+
+        if (pr2 == NULL)
+            goto err;
+
+        for (i = 0; i < ex_primes; i++) {
+            pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+            if (!BN_sub(r1, m[i], r0)) {
+                BN_free(pr2);
+                goto err;
+            }
+
+            if (!BN_mul(r2, r1, pinfo->t, ctx)) {
+                BN_free(pr2);
+                goto err;
+            }
+
+            BN_with_flags(pr2, r2, BN_FLG_CONSTTIME);
+
+            if (!BN_mod(r1, pr2, pinfo->r, ctx)) {
+                BN_free(pr2);
+                goto err;
+            }
+
+            if (BN_is_negative(r1))
+                if (!BN_add(r1, r1, pinfo->r)) {
+                    BN_free(pr2);
+                    goto err;
+                }
+            if (!BN_mul(r1, r1, pinfo->pp, ctx)) {
+                BN_free(pr2);
+                goto err;
+            }
+            if (!BN_add(r0, r0, r1)) {
+                BN_free(pr2);
+                goto err;
+            }
+        }
+        BN_free(pr2);
+    }
+
     if (rsa->e && rsa->n) {
         if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
                                    rsa->_method_mod_n))
     if (rsa->e && rsa->n) {
         if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
                                    rsa->_method_mod_n))
@@ -799,8 +923,15 @@ static int rsa_ossl_init(RSA *rsa)
 
 static int rsa_ossl_finish(RSA *rsa)
 {
 
 static int rsa_ossl_finish(RSA *rsa)
 {
+    int i;
+    RSA_PRIME_INFO *pinfo;
+
     BN_MONT_CTX_free(rsa->_method_mod_n);
     BN_MONT_CTX_free(rsa->_method_mod_p);
     BN_MONT_CTX_free(rsa->_method_mod_q);
     BN_MONT_CTX_free(rsa->_method_mod_n);
     BN_MONT_CTX_free(rsa->_method_mod_p);
     BN_MONT_CTX_free(rsa->_method_mod_q);
+    for (i = 0; i < sk_RSA_PRIME_INFO_num(rsa->prime_infos); i++) {
+        pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+        BN_MONT_CTX_free(pinfo->m);
+    }
     return 1;
 }
     return 1;
 }
index 5e2df3e..8a114cf 100644 (file)
@@ -25,6 +25,7 @@ typedef struct {
     /* Key gen parameters */
     int nbits;
     BIGNUM *pub_exp;
     /* Key gen parameters */
     int nbits;
     BIGNUM *pub_exp;
+    int primes;
     /* Keygen callback info */
     int gentmp[2];
     /* RSA padding mode */
     /* Keygen callback info */
     int gentmp[2];
     /* RSA padding mode */
@@ -54,6 +55,7 @@ static int pkey_rsa_init(EVP_PKEY_CTX *ctx)
     if (rctx == NULL)
         return 0;
     rctx->nbits = 1024;
     if (rctx == NULL)
         return 0;
     rctx->nbits = 1024;
+    rctx->primes = RSA_DEFAULT_PRIME_NUM;
     if (pkey_ctx_is_pss(ctx))
         rctx->pad_mode = RSA_PKCS1_PSS_PADDING;
     else
     if (pkey_ctx_is_pss(ctx))
         rctx->pad_mode = RSA_PKCS1_PSS_PADDING;
     else
@@ -473,6 +475,14 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
         rctx->pub_exp = p2;
         return 1;
 
         rctx->pub_exp = p2;
         return 1;
 
+    case EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES:
+        if (p1 < RSA_DEFAULT_PRIME_NUM || p1 > RSA_MAX_PRIME_NUM) {
+            RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_KEY_PRIME_NUM_INVALID);
+            return -2;
+        }
+        rctx->primes = p1;
+        return 1;
+
     case EVP_PKEY_CTRL_RSA_OAEP_MD:
     case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
         if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
     case EVP_PKEY_CTRL_RSA_OAEP_MD:
     case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
         if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
@@ -583,6 +593,7 @@ static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
     }
     if (strcmp(type, "rsa_padding_mode") == 0) {
         int pm;
     }
     if (strcmp(type, "rsa_padding_mode") == 0) {
         int pm;
+
         if (strcmp(value, "pkcs1") == 0) {
             pm = RSA_PKCS1_PADDING;
         } else if (strcmp(value, "sslv23") == 0) {
         if (strcmp(value, "pkcs1") == 0) {
             pm = RSA_PKCS1_PADDING;
         } else if (strcmp(value, "sslv23") == 0) {
@@ -606,6 +617,7 @@ static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
 
     if (strcmp(type, "rsa_pss_saltlen") == 0) {
         int saltlen;
 
     if (strcmp(type, "rsa_pss_saltlen") == 0) {
         int saltlen;
+
         if (!strcmp(value, "digest"))
             saltlen = RSA_PSS_SALTLEN_DIGEST;
         else if (!strcmp(value, "max"))
         if (!strcmp(value, "digest"))
             saltlen = RSA_PSS_SALTLEN_DIGEST;
         else if (!strcmp(value, "max"))
@@ -618,13 +630,14 @@ static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
     }
 
     if (strcmp(type, "rsa_keygen_bits") == 0) {
     }
 
     if (strcmp(type, "rsa_keygen_bits") == 0) {
-        int nbits;
-        nbits = atoi(value);
+        int nbits = atoi(value);
+
         return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, nbits);
     }
 
     if (strcmp(type, "rsa_keygen_pubexp") == 0) {
         int ret;
         return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, nbits);
     }
 
     if (strcmp(type, "rsa_keygen_pubexp") == 0) {
         int ret;
+
         BIGNUM *pubexp = NULL;
         if (!BN_asc2bn(&pubexp, value))
             return 0;
         BIGNUM *pubexp = NULL;
         if (!BN_asc2bn(&pubexp, value))
             return 0;
@@ -634,6 +647,12 @@ static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
         return ret;
     }
 
         return ret;
     }
 
+    if (strcmp(type, "rsa_keygen_primes") == 0) {
+        int nprimes = atoi(value);
+
+        return EVP_PKEY_CTX_set_rsa_keygen_primes(ctx, nprimes);
+    }
+
     if (strcmp(type, "rsa_mgf1_md") == 0)
         return EVP_PKEY_CTX_md(ctx,
                                EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
     if (strcmp(type, "rsa_mgf1_md") == 0)
         return EVP_PKEY_CTX_md(ctx,
                                EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
@@ -664,6 +683,7 @@ static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
         unsigned char *lab;
         long lablen;
         int ret;
         unsigned char *lab;
         long lablen;
         int ret;
+
         lab = OPENSSL_hexstr2buf(value, &lablen);
         if (!lab)
             return 0;
         lab = OPENSSL_hexstr2buf(value, &lablen);
         if (!lab)
             return 0;
@@ -718,7 +738,8 @@ static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     } else {
         pcb = NULL;
     }
     } else {
         pcb = NULL;
     }
-    ret = RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, pcb);
+    ret = RSA_generate_multi_prime_key(rsa, rctx->nbits, rctx->primes,
+                                       rctx->pub_exp, pcb);
     BN_GENCB_free(pcb);
     if (ret > 0 && !rsa_set_pss_param(rsa, ctx)) {
         RSA_free(rsa);
     BN_GENCB_free(pcb);
     if (ret > 0 && !rsa_set_pss_param(rsa, ctx)) {
         RSA_free(rsa);
index ddfd040..d8f1c24 100644 (file)
@@ -105,6 +105,29 @@ below.
 
 The number of bits in the generated key. If not specified 1024 is used.
 
 
 The number of bits in the generated key. If not specified 1024 is used.
 
+=item B<rsa_keygen_primes:numprimes>
+
+The number of primes in the generated key. If not specified 2 is used.
+
+=item B<rsa_keygen_pubexp:value>
+
+The RSA public exponent value. This can be a large decimal or
+hexadecimal value if preceded by B<0x>. Default value is 65537.
+
+=back
+
+=head1 RSA-PSS KEY GENERATION OPTIONS
+
+Note: by default an B<RSA-PSS> key has no parameter restrictions.
+
+=over 4
+
+=item B<rsa_keygen_bits:numbits>, B<rsa_keygen_pubexp:value>
+
+These options have the same meaning as the B<RSA> algorithm.
+
+=item B<rsa_pss_keygen_md:digest>
+
 =item B<rsa_keygen_pubexp:value>
 
 The RSA public exponent value. This can be a large decimal or
 =item B<rsa_keygen_pubexp:value>
 
 The RSA public exponent value. This can be a large decimal or
index f6a2d8a..3e42c98 100644 (file)
@@ -28,6 +28,7 @@ B<openssl> B<genrsa>
 [B<-rand file...>]
 [B<-writerand file>]
 [B<-engine id>]
 [B<-rand file...>]
 [B<-writerand file>]
 [B<-engine id>]
+[B<-primes num>]
 [B<numbits>]
 
 =head1 DESCRIPTION
 [B<numbits>]
 
 =head1 DESCRIPTION
@@ -83,6 +84,13 @@ to attempt to obtain a functional reference to the specified engine,
 thus initialising it if needed. The engine will then be set as the default
 for all available algorithms.
 
 thus initialising it if needed. The engine will then be set as the default
 for all available algorithms.
 
+=item B<-primes num>
+
+Specify the number of primes to use while generating the RSA key. The B<num>
+parameter must be a positive integer that is greater than 1 and less than 16.
+If B<num> is greater than 2, then the generated key is called a 'multi-prime'
+RSA key, which is defined in RFC 8017.
+
 =item B<numbits>
 
 The size of the private key to generate in bits. This must be the last option
 =item B<numbits>
 
 The size of the private key to generate in bits. This must be the last option
@@ -92,15 +100,17 @@ specified. The default is 2048.
 
 =head1 NOTES
 
 
 =head1 NOTES
 
-RSA private key generation essentially involves the generation of two prime
-numbers. When generating a private key various symbols will be output to
+RSA private key generation essentially involves the generation of two or more
+prime numbers. When generating a private key various symbols will be output to
 indicate the progress of the generation. A B<.> represents each number which
 has passed an initial sieve test, B<+> means a number has passed a single
 indicate the progress of the generation. A B<.> represents each number which
 has passed an initial sieve test, B<+> means a number has passed a single
-round of the Miller-Rabin primality test. A newline means that the number has
-passed all the prime tests (the actual number depends on the key size).
+round of the Miller-Rabin primality test, B<*> means the current prime starts
+a regenerating progress due to some failed tests. A newline means that the number
+has passed all the prime tests (the actual number depends on the key size).
 
 Because key generation is a random process the time taken to generate a key
 
 Because key generation is a random process the time taken to generate a key
-may vary somewhat.
+may vary somewhat. But in general, more primes lead to less generation time
+of a key.
 
 =head1 BUGS
 
 
 =head1 BUGS
 
index d8d5f6f..80602a4 100644 (file)
@@ -15,6 +15,7 @@ B<openssl speed>
 [B<-decrypt>]
 [B<-rand file...>]
 [B<-writerand file>]
 [B<-decrypt>]
 [B<-rand file...>]
 [B<-writerand file>]
+[B<-primes num>]
 [B<algorithm...>]
 
 =head1 DESCRIPTION
 [B<algorithm...>]
 
 =head1 DESCRIPTION
@@ -65,6 +66,11 @@ all others.
 Writes random data to the specified I<file> upon exit.
 This can be used with a subsequent B<-rand> flag.
 
 Writes random data to the specified I<file> upon exit.
 This can be used with a subsequent B<-rand> flag.
 
+=item B<-primes num>
+
+Generate a B<num>-prime RSA key and use it to run the benchmarks. This option
+is only effective if RSA algorithm is specified to test.
+
 =item B<[zero or more test algorithms]>
 
 If any options are given, B<speed> tests those algorithms, otherwise all of
 =item B<[zero or more test algorithms]>
 
 If any options are given, B<speed> tests those algorithms, otherwise all of
index be18ae2..6e8e50c 100644 (file)
@@ -2,13 +2,15 @@
 
 =head1 NAME
 
 
 =head1 NAME
 
-RSA_generate_key_ex, RSA_generate_key - generate RSA key pair
+RSA_generate_key_ex, RSA_generate_key,
+RSA_generate_multi_prime_key - generate RSA key pair
 
 =head1 SYNOPSIS
 
  #include <openssl/rsa.h>
 
  int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
 
 =head1 SYNOPSIS
 
  #include <openssl/rsa.h>
 
  int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+ int RSA_generate_multi_prime_key(RSA *rsa, int bits, int primes, BIGNUM *e, BN_GENCB *cb);
 
 Deprecated:
 
 
 Deprecated:
 
@@ -19,13 +21,19 @@ Deprecated:
 
 =head1 DESCRIPTION
 
 
 =head1 DESCRIPTION
 
-RSA_generate_key_ex() generates a key pair and stores it in the B<RSA>
-structure provided in B<rsa>. The pseudo-random number generator must
+RSA_generate_key_ex() generates a 2-prime RSA key pair and stores it in the
+B<RSA> structure provided in B<rsa>. The pseudo-random number generator must
 be seeded prior to calling RSA_generate_key_ex().
 
 be seeded prior to calling RSA_generate_key_ex().
 
-The modulus size will be of length B<bits>, and the public exponent will be
-B<e>. Key sizes with B<num> E<lt> 1024 should be considered insecure.
-The exponent is an odd number, typically 3, 17 or 65537.
+RSA_generate_multi_prime_key() generates a multi-prime RSA key pair and stores
+it in the B<RSA> structure provided in B<rsa>. The number of primes is given by
+the B<primes> parameter. The pseudo-random number generator must be seeded prior
+to calling RSA_generate_multi_prime_key().
+
+The modulus size will be of length B<bits>, the number of primes to form the
+modulus will be B<primes>, and the public exponent will be B<e>. Key sizes
+with B<num> E<lt> 1024 should be considered insecure. The exponent is an odd
+number, typically 3, 17 or 65537.
 
 A callback function may be used to provide feedback about the
 progress of the key generation. If B<cb> is not B<NULL>, it
 
 A callback function may be used to provide feedback about the
 progress of the key generation. If B<cb> is not B<NULL>, it
@@ -55,10 +63,12 @@ it is called as B<BN_GENCB_call(cb, 3, 0)>.
 
 =back
 
 
 =back
 
-The process is then repeated for prime q with B<BN_GENCB_call(cb, 3, 1)>.
+The process is then repeated for prime q and other primes (if any)
+with B<BN_GENCB_call(cb, 3, i)> where B<i> indicates the i-th prime.
 
 =head1 RETURN VALUE
 
 
 =head1 RETURN VALUE
 
+RSA_generate_multi_prime_key() returns 1 on success or 0 on error.
 RSA_generate_key_ex() returns 1 on success or 0 on error.
 The error codes can be obtained by L<ERR_get_error(3)>.
 
 RSA_generate_key_ex() returns 1 on success or 0 on error.
 The error codes can be obtained by L<ERR_get_error(3)>.
 
@@ -81,7 +91,7 @@ RSA_generate_key_ex() intsead.
 
 =head1 COPYRIGHT
 
 
 =head1 COPYRIGHT
 
-Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index 55a39a3..6e6576e 100644 (file)
@@ -4,8 +4,10 @@
 
 RSA_set0_key, RSA_set0_factors, RSA_set0_crt_params, RSA_get0_key,
 RSA_get0_factors, RSA_get0_crt_params, RSA_clear_flags,
 
 RSA_set0_key, RSA_set0_factors, RSA_set0_crt_params, RSA_get0_key,
 RSA_get0_factors, RSA_get0_crt_params, RSA_clear_flags,
-RSA_test_flags, RSA_set_flags, RSA_get0_engine - Routines for getting
-and setting data in an RSA object
+RSA_test_flags, RSA_set_flags, RSA_get0_engine, RSA_get_multi_prime_extra_count,
+RSA_get0_multi_prime_factors, RSA_get0_multi_prime_crt_params,
+RSA_set0_multi_prime_params, RSA_get_version
+- Routines for getting and setting data in an RSA object
 
 =head1 SYNOPSIS
 
 
 =head1 SYNOPSIS
 
@@ -24,6 +26,13 @@ and setting data in an RSA object
  int RSA_test_flags(const RSA *r, int flags);
  void RSA_set_flags(RSA *r, int flags);
  ENGINE *RSA_get0_engine(RSA *r);
  int RSA_test_flags(const RSA *r, int flags);
  void RSA_set_flags(RSA *r, int flags);
  ENGINE *RSA_get0_engine(RSA *r);
+ int RSA_get_multi_prime_extra_count(const RSA *r);
+ int RSA_get0_multi_prime_factors(const RSA *r, const BIGNUM *primes[]);
+ int RSA_get0_multi_prime_crt_params(const RSA *r, const BIGNUM *exps[],
+                                     const BIGNUM *coeffs[]);
+ int RSA_set0_multi_prime_params(RSA *r, BIGNUM *primes[], BIGNUM *exps[],
+                                BIGNUM *coeffs[], int pnum);
+ int RSA_get_version(RSA *r);
 
 =head1 DESCRIPTION
 
 
 =head1 DESCRIPTION
 
@@ -36,6 +45,11 @@ private key (see PKCS#1 section 3 Key Types), where B<p> and B<q> are
 the first and second factor of B<n> and B<dmp1>, B<dmq1> and B<iqmp>
 are the exponents and coefficient for CRT calculations.
 
 the first and second factor of B<n> and B<dmp1>, B<dmq1> and B<iqmp>
 are the exponents and coefficient for CRT calculations.
 
+For multi-prime RSA (defined in RFC 8017), there are also one or more
+'triplet' in an RSA object. A triplet contains three members, B<r>, B<d>
+and B<t>. B<r> is the additional prime besides B<p> and B<q>. B<d> and
+B<t> are the exponent and coefficient for CRT calculations.
+
 The B<n>, B<e> and B<d> parameters can be obtained by calling
 RSA_get0_key().  If they have not been set yet, then B<*n>, B<*e> and
 B<*d> will be set to NULL.  Otherwise, they are set to pointers to
 The B<n>, B<e> and B<d> parameters can be obtained by calling
 RSA_get0_key().  If they have not been set yet, then B<*n>, B<*e> and
 B<*d> will be set to NULL.  Otherwise, they are set to pointers to
@@ -59,9 +73,15 @@ B<dmq1> and B<iqmp> parameters can be obtained and set with
 RSA_get0_crt_params() and RSA_set0_crt_params().
 
 For RSA_get0_key(), RSA_get0_factors(), and RSA_get0_crt_params(),
 RSA_get0_crt_params() and RSA_set0_crt_params().
 
 For RSA_get0_key(), RSA_get0_factors(), and RSA_get0_crt_params(),
-NULL value BIGNUM ** output parameters are permitted.  The functions
+NULL value BIGNUM ** output parameters are permitted. The functions
 ignore NULL parameters but return values for other, non-NULL, parameters.
 
 ignore NULL parameters but return values for other, non-NULL, parameters.
 
+For multi-prime RSA, RSA_get0_multi_prime_factors() and RSA_get0_multi_prime_params()
+can be used to obtain other primes and related CRT parameters. The
+return values are stored in an array of B<BIGNUM *>. RSA_set0_multi_prime_params()
+sets a collect of multi-prime 'triplet' members (prime, exponent and coefficient)
+into an RSA object.
+
 RSA_set_flags() sets the flags in the B<flags> parameter on the RSA
 object. Multiple flags can be passed in one go (bitwise ORed together).
 Any flags that are already set are left set. RSA_test_flags() tests to
 RSA_set_flags() sets the flags in the B<flags> parameter on the RSA
 object. Multiple flags can be passed in one go (bitwise ORed together).
 Any flags that are already set are left set. RSA_test_flags() tests to
@@ -74,6 +94,8 @@ RSA object.
 RSA_get0_engine() returns a handle to the ENGINE that has been set for
 this RSA object, or NULL if no such ENGINE has been set.
 
 RSA_get0_engine() returns a handle to the ENGINE that has been set for
 this RSA object, or NULL if no such ENGINE has been set.
 
+RSA_get_version() returns the version of an RSA object B<r>.
+
 =head1 NOTES
 
 Values retrieved with RSA_get0_key() are owned by the RSA object used
 =head1 NOTES
 
 Values retrieved with RSA_get0_key() are owned by the RSA object used
@@ -82,10 +104,27 @@ needed, duplicate the received value using BN_dup() and pass the
 duplicate.  The same applies to RSA_get0_factors() and RSA_set0_factors()
 as well as RSA_get0_crt_params() and RSA_set0_crt_params().
 
 duplicate.  The same applies to RSA_get0_factors() and RSA_set0_factors()
 as well as RSA_get0_crt_params() and RSA_set0_crt_params().
 
+The caller should obtain the size by calling RSA_get_multi_prime_extra_count()
+in advance and allocate sufficient buffer to store the return values before
+calling RSA_get0_multi_prime_factors() and RSA_get0_multi_prime_params().
+
+RSA_set0_multi_prime_params() always clears the original multi-prime
+triplets in RSA object B<r> and assign the new set of triplets into it.
+
 =head1 RETURN VALUES
 
 =head1 RETURN VALUES
 
-RSA_set0_key(), RSA_set0_factors and RSA_set0_crt_params() return 1 on
-success or 0 on failure.
+RSA_set0_key(), RSA_set0_factors(), RSA_set0_crt_params() and
+RSA_set0_multi_prime_params() return 1 on success or 0 on failure.
+
+RSA_get0_multi_prime_factors() and RSA_get0_multi_prime_crt_params() return
+1 on success or 0 on failure.
+
+RSA_get_multi_prime_extra_count() returns two less than the number of primes
+in use, which is 0 for traditional RSA and the number of extra primes for
+multi-prime RSA.
+
+RSA_get_version() returns B<RSA_ASN1_VERSION_MULTI> for multi-prime RSA and
+B<RSA_ASN1_VERSION_DEFAULT> for normal two-prime RSA, as defined in RFC 8017.
 
 RSA_test_flags() returns the current state of the flags in the RSA object.
 
 
 RSA_test_flags() returns the current state of the flags in the RSA object.
 
@@ -98,11 +137,15 @@ L<RSA_new(3)>, L<RSA_size(3)>
 
 =head1 HISTORY
 
 
 =head1 HISTORY
 
-The functions described here were added in OpenSSL 1.1.0.
+RSA_get_multi_prime_extra_count(), RSA_get0_multi_prime_factors(),
+RSA_get0_multi_prime_crt_params(), RSA_set0_multi_prime_params(),
+and RSA_get_version() functions were added in OpenSSL 1.1.1.
+
+Other functions described here were added in OpenSSL 1.1.0.
 
 =head1 COPYRIGHT
 
 
 =head1 COPYRIGHT
 
-Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index a578389..fde1a41 100644 (file)
@@ -12,7 +12,8 @@ RSA_meth_set_priv_dec, RSA_meth_get_mod_exp, RSA_meth_set_mod_exp,
 RSA_meth_get_bn_mod_exp, RSA_meth_set_bn_mod_exp, RSA_meth_get_init,
 RSA_meth_set_init, RSA_meth_get_finish, RSA_meth_set_finish,
 RSA_meth_get_sign, RSA_meth_set_sign, RSA_meth_get_verify,
 RSA_meth_get_bn_mod_exp, RSA_meth_set_bn_mod_exp, RSA_meth_get_init,
 RSA_meth_set_init, RSA_meth_get_finish, RSA_meth_set_finish,
 RSA_meth_get_sign, RSA_meth_set_sign, RSA_meth_get_verify,
-RSA_meth_set_verify, RSA_meth_get_keygen, RSA_meth_set_keygen
+RSA_meth_set_verify, RSA_meth_get_keygen, RSA_meth_set_keygen,
+RSA_meth_get_multi_prime_keygen, RSA_meth_set_multi_prime_keygen
 - Routines to build up RSA methods
 
 =head1 SYNOPSIS
 - Routines to build up RSA methods
 
 =head1 SYNOPSIS
@@ -111,6 +112,15 @@ RSA_meth_set_verify, RSA_meth_get_keygen, RSA_meth_set_keygen
                          int (*keygen)(RSA *rsa, int bits, BIGNUM *e,
                                        BN_GENCB *cb));
 
                          int (*keygen)(RSA *rsa, int bits, BIGNUM *e,
                                        BN_GENCB *cb));
 
+ int (*RSA_meth_get_multi_prime_keygen(const RSA_METHOD *meth))(RSA *rsa, int bits,
+                                                                int primes, BIGNUM *e,
+                                                                BN_GENCB *cb);
+
+ int RSA_meth_set_multi_prime_keygen(RSA_METHOD *meth,
+                                     int (*keygen) (RSA *rsa, int bits,
+                                                    int primes, BIGNUM *e,
+                                                    BN_GENCB *cb));
+
 =head1 DESCRIPTION
 
 The B<RSA_METHOD> type is a structure used for the provision of custom
 =head1 DESCRIPTION
 
 The B<RSA_METHOD> type is a structure used for the provision of custom
@@ -193,8 +203,14 @@ by this function. This function may be NULL.
 RSA_meth_get_keygen() and RSA_meth_set_keygen() get and set the
 function used for generating a new RSA key pair respectively. This
 function will be called in response to the application calling
 RSA_meth_get_keygen() and RSA_meth_set_keygen() get and set the
 function used for generating a new RSA key pair respectively. This
 function will be called in response to the application calling
-RSA_generate_key(). The parameter for the function has the same
-meaning as for RSA_generate_key().
+RSA_generate_key_ex(). The parameter for the function has the same
+meaning as for RSA_generate_key_ex().
+
+RSA_meth_get_multi_prime_keygen() and RSA_meth_set_multi_prime_keygen() get
+and set the function used for generating a new multi-prime RSA key pair
+respectively. This function will be called in response to the application calling
+RSA_generate_multi_prime_key(). The parameter for the function has the same
+meaning as for RSA_generate_multi_prime_key().
 
 RSA_meth_get_pub_enc(), RSA_meth_set_pub_enc(),
 RSA_meth_get_pub_dec(), RSA_meth_set_pub_dec(),
 
 RSA_meth_get_pub_enc(), RSA_meth_set_pub_enc(),
 RSA_meth_get_pub_dec(), RSA_meth_set_pub_dec(),
@@ -223,12 +239,16 @@ success or 0 on failure.
 
 =head1 SEE ALSO
 
 
 =head1 SEE ALSO
 
-L<RSA_new(3)>, L<RSA_generate_key(3)>, L<RSA_sign(3)>,
-L<RSA_set_method(3)>, L<RSA_size(3)>, L<RSA_get0_key(3)>
+L<RSA_new(3)>, L<RSA_generate_key_ex(3)>, L<RSA_sign(3)>,
+L<RSA_set_method(3)>, L<RSA_size(3)>, L<RSA_get0_key(3)>,
+L<RSA_generate_multi_prime_key(3)>
 
 =head1 HISTORY
 
 
 =head1 HISTORY
 
-The functions described here were added in OpenSSL 1.1.0.
+RSA_meth_get_multi_prime_keygen() and RSA_meth_set_multi_prime_keygen() were
+added in OpenSSL 1.1.1.
+
+Other functions described here were added in OpenSSL 1.1.0.
 
 =head1 COPYRIGHT
 
 
 =head1 COPYRIGHT
 
index f45ea2e..8985219 100644 (file)
@@ -45,6 +45,12 @@ extern "C" {
 # define RSA_3   0x3L
 # define RSA_F4  0x10001L
 
 # define RSA_3   0x3L
 # define RSA_F4  0x10001L
 
+/* based on RFC 8017 appendix A.1.2 */
+# define RSA_ASN1_VERSION_DEFAULT        0
+# define RSA_ASN1_VERSION_MULTI          1
+
+# define RSA_DEFAULT_PRIME_NUM           2
+
 # define RSA_METHOD_FLAG_NO_CHECK        0x0001/* don't check pub/private
                                                 * match */
 
 # define RSA_METHOD_FLAG_NO_CHECK        0x0001/* don't check pub/private
                                                 * match */
 
@@ -120,6 +126,10 @@ extern "C" {
         RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \
                           EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp)
 
         RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \
                           EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp)
 
+# define EVP_PKEY_CTX_set_rsa_keygen_primes(ctx, primes) \
+        RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \
+                          EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES, primes, NULL)
+
 # define  EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \
         RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \
                           EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md))
 # define  EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \
         RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \
                           EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md))
@@ -170,6 +180,8 @@ extern "C" {
 # define EVP_PKEY_CTRL_GET_RSA_OAEP_MD   (EVP_PKEY_ALG_CTRL + 11)
 # define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12)
 
 # define EVP_PKEY_CTRL_GET_RSA_OAEP_MD   (EVP_PKEY_ALG_CTRL + 11)
 # define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12)
 
+# define EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES  (EVP_PKEY_ALG_CTRL + 13)
+
 # define RSA_PKCS1_PADDING       1
 # define RSA_SSLV23_PADDING      2
 # define RSA_NO_PADDING          3
 # define RSA_PKCS1_PADDING       1
 # define RSA_SSLV23_PADDING      2
 # define RSA_NO_PADDING          3
@@ -192,15 +204,22 @@ int RSA_security_bits(const RSA *rsa);
 int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
 int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
 int RSA_set0_crt_params(RSA *r,BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
 int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
 int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
 int RSA_set0_crt_params(RSA *r,BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+int RSA_set0_multi_prime_params(RSA *r, BIGNUM *primes[], BIGNUM *exps[],
+                                BIGNUM *coeffs[], int pnum);
 void RSA_get0_key(const RSA *r,
                   const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
 void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
 void RSA_get0_key(const RSA *r,
                   const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
 void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+int RSA_get_multi_prime_extra_count(const RSA *r);
+int RSA_get0_multi_prime_factors(const RSA *r, const BIGNUM *primes[]);
 void RSA_get0_crt_params(const RSA *r,
                          const BIGNUM **dmp1, const BIGNUM **dmq1,
                          const BIGNUM **iqmp);
 void RSA_get0_crt_params(const RSA *r,
                          const BIGNUM **dmp1, const BIGNUM **dmq1,
                          const BIGNUM **iqmp);
+int RSA_get0_multi_prime_crt_params(const RSA *r, const BIGNUM *exps[],
+                                    const BIGNUM *coeffs[]);
 void RSA_clear_flags(RSA *r, int flags);
 int RSA_test_flags(const RSA *r, int flags);
 void RSA_set_flags(RSA *r, int flags);
 void RSA_clear_flags(RSA *r, int flags);
 int RSA_test_flags(const RSA *r, int flags);
 void RSA_set_flags(RSA *r, int flags);
+int RSA_get_version(RSA *r);
 ENGINE *RSA_get0_engine(const RSA *r);
 
 /* Deprecated version */
 ENGINE *RSA_get0_engine(const RSA *r);
 
 /* Deprecated version */
@@ -210,6 +229,9 @@ DEPRECATEDIN_0_9_8(RSA *RSA_generate_key(int bits, unsigned long e, void
 
 /* New version */
 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
 
 /* New version */
 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+/* Multi-prime version */
+int RSA_generate_multi_prime_key(RSA *rsa, int bits, int primes,
+                                 BIGNUM *e, BN_GENCB *cb);
 
 int RSA_X931_derive_ex(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1,
                        BIGNUM *q2, const BIGNUM *Xp1, const BIGNUM *Xp2,
 
 int RSA_X931_derive_ex(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1,
                        BIGNUM *q2, const BIGNUM *Xp1, const BIGNUM *Xp2,
@@ -468,6 +490,12 @@ int (*RSA_meth_get_keygen(const RSA_METHOD *meth))
 int RSA_meth_set_keygen(RSA_METHOD *rsa,
                         int (*keygen) (RSA *rsa, int bits, BIGNUM *e,
                                        BN_GENCB *cb));
 int RSA_meth_set_keygen(RSA_METHOD *rsa,
                         int (*keygen) (RSA *rsa, int bits, BIGNUM *e,
                                        BN_GENCB *cb));
+int (*RSA_meth_get_multi_prime_keygen(const RSA_METHOD *meth))
+    (RSA *rsa, int bits, int primes, BIGNUM *e, BN_GENCB *cb);
+int RSA_meth_set_multi_prime_keygen(RSA_METHOD *meth,
+                                    int (*keygen) (RSA *rsa, int bits,
+                                                   int primes, BIGNUM *e,
+                                                   BN_GENCB *cb));
 int ERR_load_RSA_strings(void);
 
 #  ifdef  __cplusplus
 int ERR_load_RSA_strings(void);
 
 #  ifdef  __cplusplus
index 6e6aac2..94bfd93 100644 (file)
@@ -114,6 +114,7 @@ int ERR_load_RSA_strings(void);
 # define RSA_R_INVALID_LABEL                              160
 # define RSA_R_INVALID_MESSAGE_LENGTH                     131
 # define RSA_R_INVALID_MGF1_MD                            156
 # define RSA_R_INVALID_LABEL                              160
 # define RSA_R_INVALID_MESSAGE_LENGTH                     131
 # define RSA_R_INVALID_MGF1_MD                            156
+# define RSA_R_INVALID_MULTI_PRIME_KEY                    167
 # define RSA_R_INVALID_OAEP_PARAMETERS                    161
 # define RSA_R_INVALID_PADDING                            138
 # define RSA_R_INVALID_PADDING_MODE                       141
 # define RSA_R_INVALID_OAEP_PARAMETERS                    161
 # define RSA_R_INVALID_PADDING                            138
 # define RSA_R_INVALID_PADDING_MODE                       141
@@ -123,12 +124,17 @@ int ERR_load_RSA_strings(void);
 # define RSA_R_INVALID_TRAILER                            139
 # define RSA_R_INVALID_X931_DIGEST                        142
 # define RSA_R_IQMP_NOT_INVERSE_OF_Q                      126
 # define RSA_R_INVALID_TRAILER                            139
 # define RSA_R_INVALID_X931_DIGEST                        142
 # define RSA_R_IQMP_NOT_INVERSE_OF_Q                      126
+# define RSA_R_KEY_PRIME_NUM_INVALID                      165
 # define RSA_R_KEY_SIZE_TOO_SMALL                         120
 # define RSA_R_LAST_OCTET_INVALID                         134
 # define RSA_R_MGF1_DIGEST_NOT_ALLOWED                    152
 # define RSA_R_MODULUS_TOO_LARGE                          105
 # define RSA_R_KEY_SIZE_TOO_SMALL                         120
 # define RSA_R_LAST_OCTET_INVALID                         134
 # define RSA_R_MGF1_DIGEST_NOT_ALLOWED                    152
 # define RSA_R_MODULUS_TOO_LARGE                          105
+# define RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R            168
+# define RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D             169
+# define RSA_R_MP_R_NOT_PRIME                             170
 # define RSA_R_NO_PUBLIC_EXPONENT                         140
 # define RSA_R_NULL_BEFORE_BLOCK_MISSING                  113
 # define RSA_R_NO_PUBLIC_EXPONENT                         140
 # define RSA_R_NULL_BEFORE_BLOCK_MISSING                  113
+# define RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES         172
 # define RSA_R_N_DOES_NOT_EQUAL_P_Q                       127
 # define RSA_R_OAEP_DECODING_ERROR                        121
 # define RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE   148
 # define RSA_R_N_DOES_NOT_EQUAL_P_Q                       127
 # define RSA_R_OAEP_DECODING_ERROR                        121
 # define RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE   148
index d7cfd7e..3d7af31 100644 (file)
@@ -46,7 +46,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
           x509_time_test x509_dup_cert_test x509_check_cert_pkey_test \
           recordlentest drbgtest sslbuffertest \
           time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \
           x509_time_test x509_dup_cert_test x509_check_cert_pkey_test \
           recordlentest drbgtest sslbuffertest \
           time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \
-          servername_test ocspapitest
+          servername_test ocspapitest rsa_mp_test
 
   SOURCE[aborttest]=aborttest.c
   INCLUDE[aborttest]=../include
 
   SOURCE[aborttest]=aborttest.c
   INCLUDE[aborttest]=../include
@@ -152,6 +152,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
   INCLUDE[rsa_test]=.. ../include
   DEPEND[rsa_test]=../libcrypto libtestutil.a
 
   INCLUDE[rsa_test]=.. ../include
   DEPEND[rsa_test]=../libcrypto libtestutil.a
 
+  SOURCE[rsa_mp_test]=rsa_mp_test.c
+  INCLUDE[rsa_mp_test]=.. ../include
+  DEPEND[rsa_mp_test]=../libcrypto libtestutil.a
+
   SOURCE[evp_test]=evp_test.c
   INCLUDE[evp_test]=../include
   DEPEND[evp_test]=../libcrypto libtestutil.a
   SOURCE[evp_test]=evp_test.c
   INCLUDE[evp_test]=../include
   DEPEND[evp_test]=../libcrypto libtestutil.a
diff --git a/test/recipes/15-test_mp_rsa.t b/test/recipes/15-test_mp_rsa.t
new file mode 100644 (file)
index 0000000..f601c4c
--- /dev/null
@@ -0,0 +1,126 @@
+#! /usr/bin/env perl
+# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2017 BaishanCloud. All rights reserved.
+#
+# Licensed under the OpenSSL license (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 strict;
+use warnings;
+
+use File::Spec;
+use OpenSSL::Test qw/:DEFAULT data_file/;
+use OpenSSL::Test::Utils;
+
+setup("test_mp_rsa");
+
+plan tests => 61;
+
+ok(run(test(["rsa_mp_test"])), "running rsa multi prime test");
+
+my $cleartext = data_file("plain_text");
+
+my @test_param = (
+    # 3 primes, 2048-bit
+    {
+        primes => '3',
+        bits => '2048',
+    },
+    # 4 primes, 2048-bit
+    {
+        primes => '4',
+        bits => '2048',
+    },
+    # 8 primes, 2048-bit
+    {
+        primes => '8',
+        bits => '2048',
+    },
+    # 15 primes, 2048-bit
+    {
+        primes => '15',
+        bits => '2048',
+    },
+    # 8 primes, 15360-bit (3 & 4 primes for 15360 bit is too long to gen a key)
+    {
+        primes => '8',
+        bits => '15360',
+    },
+    # 15 primes, 15360-bit
+    {
+        primes => '15',
+        bits => '15360',
+    },
+);
+
+# genrsa
+run_mp_tests(0);
+# evp
+run_mp_tests(1);
+
+sub run_mp_tests {
+    my $evp = shift;
+
+    foreach my $param (@test_param) {
+        my $primes = $param->{primes};
+        my $bits = $param->{bits};
+        my $name = ($evp ? "evp" : "") . "${bits}p${primes}";
+
+        if ($evp) {
+            ok(run(app([ 'openssl', 'genpkey', '-out', 'rsamptest.pem',
+                         '-algorithm', 'RSA', '-pkeyopt', "rsa_keygen_primes:$primes",
+                         '-pkeyopt', "rsa_keygen_bits:$bits"])), "genrsa $name");
+        } else {
+            ok(run(app([ 'openssl', 'genrsa', '-out', 'rsamptest.pem',
+                         '-primes', $primes, $bits])), "genrsa $name");
+        }
+
+        ok(run(app([ 'openssl', 'rsa', '-check', '-in', 'rsamptest.pem',
+                     '-noout'])), "rsa -check $name");
+        if ($evp) {
+            ok(run(app([ 'openssl', 'pkeyutl', '-inkey', 'rsamptest.pem',
+                         '-encrypt', '-in', $cleartext,
+                         '-out', 'rsamptest.enc' ])), "rsa $name encrypt");
+            ok(run(app([ 'openssl', 'pkeyutl', '-inkey', 'rsamptest.pem',
+                         '-decrypt', '-in', 'rsamptest.enc',
+                         '-out', 'rsamptest.dec' ])), "rsa $name decrypt");
+        } else {
+            ok(run(app([ 'openssl', 'rsautl', '-inkey', 'rsamptest.pem',
+                         '-encrypt', '-in', $cleartext,
+                         '-out', 'rsamptest.enc' ])), "rsa $name encrypt");
+            ok(run(app([ 'openssl', 'rsautl', '-inkey', 'rsamptest.pem',
+                         '-decrypt', '-in', 'rsamptest.enc',
+                         '-out', 'rsamptest.dec' ])), "rsa $name decrypt");
+        }
+
+        ok(check_msg(), "rsa $name check result");
+
+        # clean up temp files
+        unlink 'rsamptest.pem';
+        unlink 'rsamptest.enc';
+        unlink 'rsamptest.dec';
+    }
+}
+
+sub check_msg {
+    my $msg;
+    my $dec;
+
+    open(my $fh, "<", $cleartext) or return 0;
+    binmode $fh;
+    read($fh, $msg, 10240);
+    close $fh;
+    open($fh, "<", "rsamptest.dec") or return 0;
+    binmode $fh;
+    read($fh, $dec, 10240);
+    close $fh;
+
+    if ($msg ne $dec) {
+        print STDERR "cleartext and decrypted are not the same";
+        return 0;
+    }
+    return 1;
+}
diff --git a/test/recipes/15-test_mp_rsa_data/plain_text b/test/recipes/15-test_mp_rsa_data/plain_text
new file mode 100644 (file)
index 0000000..60d11c0
--- /dev/null
@@ -0,0 +1,4 @@
+It was the best of times, it was the worst of times,
+it was the age of wisdom, it was the age of foolishness,
+it was the epoch of belief, it was the epoch of incredulity,
+it was the season of Light, it was the season of Darkness.
diff --git a/test/rsa_mp_test.c b/test/rsa_mp_test.c
new file mode 100644 (file)
index 0000000..ea4701e
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017 BaishanCloud. All rights reserved.
+ *
+ * Licensed under the OpenSSL license (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
+ */
+
+/* This aims to test the setting functions */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/bn.h>
+
+#include "testutil.h"
+
+#ifndef OPENSSL_NO_RSA
+# include <openssl/rsa.h>
+
+#define NUM_EXTRA_PRIMES 5
+
+static int key4096p7(RSA *key)
+{
+    /* C90 requires string should <= 509 bytes */
+    static unsigned char n1[] =
+        "\x00\xeb\xa2\x2b\x74\x76\x32\x33\xbf\xb9\x9a\xe4\xb0\x84\xac"
+        "\x9a\x20\x1b\xe6\x1a\x22\x3f\xcd\x13\xe1\x42\xee\xd8\x1a\x6e"
+        "\xe3\xd5\x91\x1e\xee\x32\x5c\x78\x76\x8b\x5d\x82\x6f\xd0\xaf"
+        "\xa3\x56\xd6\x15\x5f\x64\xb3\x5a\xcf\xc8\x7d\xa3\xb1\x3d\x10"
+        "\xbf\x47\x00\xa9\xc9\x96\x9d\xfd\x7c\x82\x4f\xb5\x70\x39\xd4"
+        "\xd9\x0f\xd7\xd9\x86\xd4\xd4\x35\x06\x35\x07\xa3\x1b\x8c\xf4"
+        "\x35\xb8\xb2\xd4\xa3\xbe\x6c\x64\x7d\x74\x17\x88\x36\x07\x32"
+        "\x6f\x84\x48\xd4\xb8\x4a\x12\xba\xe8\x40\x5b\xc6\xa5\xa4\x11"
+        "\x0d\x8a\xa6\x60\x3d\x98\x8b\xf8\x11\x8f\x43\xab\x2f\x95\x0f"
+        "\x3b\x20\x3f\x48\x88\xaa\x3d\x20\xa6\xaf\x6a\xdf\xc0\x95\x38"
+        "\xff\x47\x7c\x8a\x8b\xec\x76\x45\x43\xd0\x06\x7c\x71\x76\x5f"
+        "\x0d\x11\x58\x0a\xa9\x0e\x7e\x07\xe9\x89\xc1\x9e\x56\x6d\x08"
+        "\xe4\xe3\x16\xb4\xa0\x03\x7a\x49\x96\xa8\x88\xcf\x89\xe3\xdb"
+        "\x47\x0c\xd2\x1b\x6f\x67\x4d\xc8\xee\x53\xe9\x0b\x3d\xe5\x11"
+        "\x9d\x85\x75\xfe\x26\x4a\x99\x58\x79\x28\x91\x03\x8b\xe4\xbf"
+        "\x49\xd3\xfa\x8e\x25\xe3\xb1\xb2\xc2\x33\xd9\x8b\xe0\x9d\x1b"
+        "\xa4\xa0\xcf\x05\x5f\xb9\x19\x65\x74\x24\xae\x2e\x33\xc8\xd9";
+
+    static unsigned char n2[] =
+        "\x55\xae\xcb\x37\xa1\x3b\x95\xf7\x5f\xff\x1f\x06\x4a\xab\x85"
+        "\x94\x37\x15\x6f\xf2\xc8\x9b\x73\xb9\x1d\x8e\x30\x63\x5a\xa1"
+        "\x84\x31\xa8\xbe\x7e\x4f\xeb\xa0\xe6\x73\xc7\xbe\xd4\x5e\xe7"
+        "\x5e\xae\x5d\xfd\xf7\xf5\xa4\xb6\xb8\x3c\x15\xac\x1b\xcd\x3a"
+        "\xb6\xbd\xa9\x11\xd0\x44\xa5\x08\x7e\x60\x1d\x1d\x4d\xa6\xd7"
+        "\x06\xe5\x4f\x37\x0d\x5c\xbd\xad\x8d\x40\x18\xbd\xc7\x58\x20"
+        "\xed\xa8\x4d\xd8\x29\xdc\x42\x4f\x50\xa6\x03\xf0\xa5\xa2\x18"
+        "\x2b\xdd\x1c\x0e\x89\x3f\xbc\x5d\x35\xac\xa8\x55\x6d\x17\x28"
+        "\xae\xee\x78\xeb\x6d\x7a\x21\xd6\x6c\xdd\x21\x1d\xcc\xe5\xb0"
+        "\xf2\xef\x7f\x1d\x8a\xb7\x95\xaf\x40\xb5\x5c\x8b\x0d\x59\x45"
+        "\x21\x86\x34\x6d\x13\xd7\x14\xa5\x0e\xca\x88\x32\x57\xfe\x2d"
+        "\xd1\xcb\xad\x14\xbe\x30\xb1\x69\x9b\x72\x82\xad\x47\xb5\x45"
+        "\xc8\x65\x83\xce\x07\x21\x15\x6b\x65\x9d\xf3\x4d\x92\x19\xbe"
+        "\x67\x73\xd0\x60\x9f\xc7\xef\xee\xfa\xb0\xd3\xa4\x95\x81\xb0"
+        "\xbd\x4b\xd5\xf8\xbd\xbd\x9f\x41\x41\xc0\xfd\xe9\x17\xe3\x16"
+        "\xd3\xdc\xc8\xe2\xa5\xca\xff\xea\x91\xf4\x33\xc0\xfb\xdc\x02"
+        "\x62\x0a\x4e\x26\x92\xb5\x13\xec\x43\xd2\x25\x19\xe2\x6d\xef"
+        "\xea\x38\x75";
+
+    static unsigned char e[] = "\x01\x00\x01";
+
+    static unsigned char d1[] =
+        "\x60\x43\x92\x69\x33\xd8\x72\x97\xc3\x25\xea\x83\xca\xd0\x10"
+        "\xef\x49\x36\x8a\x3a\xaf\xc2\x02\x7b\x26\xb3\x19\x0a\x43\x7f"
+        "\x44\xc2\xd2\xd6\x11\x31\x01\xed\xbc\x25\xe9\xa1\xf0\xa9\xb0"
+        "\x9b\x4b\x3e\xd4\x07\xf9\xd6\x01\xc9\x30\xba\xed\x2f\xbb\x65"
+        "\xc9\x86\x15\xd7\x4b\x77\x24\x15\xf7\xce\xc4\x9b\x21\x62\x4d"
+        "\xde\x77\xf0\x1e\x62\x49\x54\xda\xda\xcd\xdd\x0f\x53\xe2\xd2"
+        "\x39\x4f\x60\x8e\xec\xe3\x49\x1b\xe7\x9a\x3e\x17\x8e\x5a\x77"
+        "\x4a\x15\xf6\x57\xc5\xfe\x2b\xa5\x94\x04\x94\x9c\xe7\xa8\xcc"
+        "\x07\x4b\xd8\xb8\x55\xaa\xdf\x33\xca\x2c\x8c\xee\x61\x1a\x89"
+        "\x0d\x3b\xcd\x16\x28\xb5\x50\x62\x2f\xb1\x9e\x61\x27\xd7\xf1"
+        "\xe1\x22\x58\x84\xcd\x18\xc3\xbf\xde\x52\x25\xdd\xc1\xcd\x2a"
+        "\x20\x78\x5e\xde\x65\x6a\x25\x12\x2d\x78\x28\xdb\x2c\x6f\x1b"
+        "\x65\x71\x1b\x2e\x1c\x18\x62\xf6\x71\x82\xdc\xa8\x80\x0e\xb5"
+        "\x8b\x09\x97\xc3\x81\xe1\x23\x2e\x40\x75\xbf\xd3\x78\xdc\xd5"
+        "\xc3\xe6\x75\x8b\xb0\x48\x7a\x78\x7d\xfe\xcc\x4c\xa1\x40\x11"
+        "\x20\xbe\x2a\xc1\xaf\x18\x53\x45\x6a\xb4\x2a\x0a\xc9\x01\x36"
+        "\x60\xf1\x61\x97\x73\xde\xac\x3e\x24\xff\x5b\x25\xdb\x93\x97";
+
+    static unsigned char d2[] =
+        "\x03\xf4\xef\x4a\x73\x47\xa8\x31\xd1\x63\x5b\xba\xa6\xe2\x7a"
+        "\xd8\xef\xea\x2f\x04\x76\x3c\x7a\x8d\x4e\xc1\x81\xc5\x39\x4f"
+        "\x09\xc4\xb1\xfb\x75\xd0\xae\x32\x2e\x44\xa3\xb6\xdc\x60\xc6"
+        "\x60\x1e\x40\x6f\x04\xc2\x7a\xd3\x0f\x8a\xa4\x23\x8f\x0e\x2e"
+        "\x2a\xcd\x65\x2a\x6e\x97\xa8\xe5\x01\x96\xd1\x41\x27\xa5\x16"
+        "\x2f\xb0\x15\x0a\x33\x06\x72\x40\xa5\xe4\x74\xbe\x4a\x87\x28"
+        "\x8a\x68\xea\x39\x42\x08\x47\xff\x9d\x9e\x06\x03\xfa\x4a\x6a"
+        "\xbb\xe5\x6f\x97\x05\x5f\xae\x47\xe6\xc4\xe0\x48\x62\x65\x9b"
+        "\x91\x50\xda\x84\xcf\xa3\xb2\x9d\x51\x84\x02\x4b\xe6\x12\xa2"
+        "\x87\x6e\x1f\x43\x2f\x90\x36\xb1\x15\xc6\xf6\xe0\xde\x52\x39"
+        "\x8e\x22\x39\x8c\x4f\x1c\x08\xac\x55\x5c\xa9\x69\x4e\x77\x8d"
+        "\x74\x6e\x0b\x06\xda\x61\xcd\xe2\xc8\xc6\x02\x54\x70\x05\xc1"
+        "\x50\x6d\x5e\x3e\x66\x7d\x41\x3c\x57\x68\x8a\x16\xb9\xd8\x29"
+        "\xfb\xeb\x05\x57\x87\xdc\x88\xc6\x91\x67\x3c\xcc\x19\x28\xa1"
+        "\x23\x54\xc3\x88\xc4\x28\x63\xca\xf7\xb2\xea\x34\xa1\x9e\xc1"
+        "\xca\x9b\x96\xe7\x4d\x82\x22\xf9\xcb\xc3\x2a\x3f\x19\xe3\x7c"
+        "\xce\x8c\x66\x45\xfe\xe6\x31\x31\x66\xd4\x1a\xb5\x47\x98\xea"
+        "\x80\x01";
+
+    static unsigned char p[] =
+        "\x03\xf5\x90\x21\xf3\xa6\x13\xdd\x33\x2a\x4c\x1f\x53\xd6\x9e"
+        "\x64\x1d\xfc\xed\xfb\xa1\xe6\xd0\x80\xd1\x6a\xcd\x20\x68\xea"
+        "\x75\x72\x59\x24\x8b\x1b\x28\x37\xbd\x8f\xc4\xc9\xb6\xda\xef"
+        "\x55\xb9\x0e\x26\x93\x8a\x8a\xec\x2f\x47\xe6\x4e\xa9\x42\xfb"
+        "\x02\x28\x5e\x37\xb7\x5a\x61\xfa\x39\xab\x63\x61\x1b\xbb";
+
+    static unsigned char q[] =
+        "\x01\xea\x64\x6e\x7d\xaa\xd7\x6a\xfa\x0c\x52\xfa\x2b\x00\x51"
+        "\x7d\x4d\xc3\x9f\x1d\x21\xb2\x62\x11\xd4\x7d\x0e\xc2\xe7\xdf"
+        "\xd0\x04\xd6\x30\x02\x54\xb2\xa5\xb7\x85\xd5\x96\xc7\x24\x83"
+        "\x8e\x3d\x60\xc3\x42\xa5\xa3\x76\xdd\x6e\x60\xa0\xbf\x85\x05"
+        "\xb6\x52\x32\xeb\x41\x6f\x08\xc8\x56\x43\xd8\x80\x06\xf7";
+
+    static unsigned char dmp1[] =
+        "\x03\xcc\x5c\xe7\x45\x91\x49\xb3\x47\x77\xc7\xa9\xb2\x4b\xce"
+        "\x8e\xab\xfa\x4f\xf1\xbd\x63\xeb\x19\xfa\x4e\x64\xd6\x37\xf0"
+        "\xde\x95\xc2\x11\x7d\xe6\xa2\xd1\xbe\xe9\x23\x58\x85\x35\x4a"
+        "\xb0\xc9\xa5\x5a\xba\xe7\x09\xda\x06\x8e\x0a\xd3\xe2\x2c\x61"
+        "\x14\xb3\xd7\x97\xca\x2e\x4a\x9a\xbd\x22\xc0\x67\x94\x2b";
+
+    static unsigned char dmq1[] =
+        "\x01\x66\x28\x8d\xce\x38\x8d\x76\xb3\x43\x77\x03\x01\x8f\x0c"
+        "\xf5\x40\x6b\x84\x75\x69\x5b\xf8\x66\x5f\x54\x2b\x08\xcd\x03"
+        "\x58\xd1\x7f\x81\xb6\xe2\x17\x4c\x13\x3a\xab\x21\xa1\x36\x98"
+        "\xe2\xb5\x0f\x4b\xed\x0c\x3e\xd4\x1c\xab\x75\xe5\x51\x9b\x9c"
+        "\xed\x69\x21\x89\x52\xd3\xfe\x8d\x1a\xfc\x18\x4e\x81\x47";
+
+    static unsigned char iqmp[] =
+        "\x02\x31\xad\xe8\xa5\xa9\x5d\x52\x70\x68\xc1\x6e\x6b\x4e\xb5"
+        "\x0b\xc2\xd9\x89\xe5\xbc\x46\xca\xac\xac\x04\xe2\x39\x7f\xc4"
+        "\xa0\xe4\x9e\x8a\xb8\x1e\x67\x66\x85\xb8\x3e\x42\x7c\xc7\x2c"
+        "\x02\x64\x7c\xd3\x40\xda\x5d\x9f\x38\xa7\x7c\x30\xcd\x6b\x7d"
+        "\x4d\xd0\x77\x2d\x9b\xd1\xc3\x55\x03\x69\x3d\xda\x48\xe2";
+
+    static char *primes[] = {
+        "\x01\xb2\xe2\xf7\x3b\x29\xdc\x90\xf9\xc4\x5a\x75\x09\x00\xbe"
+        "\xec\xa6\x97\xbc\x47\x89\x24\x71\x48\xa7\xc9\xc8\xed\x9c\x88"
+        "\xb9\x9f\xcd\x79\xc9\x2d\xb1\x78\xf7\x54\x2c\x28\x01\x37\x01"
+        "\xa0\xff\xf2\x69\x52\x93\xf0\x16\x08\xaa\x2f\xff\x35\x14\x2d"
+        "\x65\x8d\x21\x05\x30\x84\x9b\xcb\x58\x42\xc6\x9b\xa7\xb5",
+
+        "\x01\xb7\x66\xfe\xb5\x94\xf8\x46\xcb\x06\x2a\x7a\xd4\x35\xe4"
+        "\x68\x6d\xcf\x58\x0b\xb3\x12\xe6\x7b\x66\xee\x36\xf5\x1f\x79"
+        "\x8f\x82\x1e\xd9\x97\x33\x45\x37\xa3\x84\x54\xab\x4b\x12\x96"
+        "\x76\x9f\xf9\x98\x02\xf1\x5e\xcb\x97\xe8\x13\xde\x91\x0b\xd5"
+        "\xec\x7f\x2b\x27\x55\xc1\x69\x58\xad\x8b\xaa\xce\x68\xc5",
+
+        "\x01\xbe\xdf\xa5\x33\xfb\xa1\xfa\xf6\xd2\x43\xcd\x76\x3e\x23"
+        "\xa2\xf7\x29\xeb\x65\xe5\xae\xe8\xfc\xfd\xca\x55\x16\x01\x57"
+        "\xcd\xca\x9e\x83\xf9\x61\x6a\x17\xac\x61\xec\x04\x32\x9f\x69"
+        "\xb8\x6d\x66\x33\x9b\xef\xf4\x91\xf1\x99\x02\xc2\xea\x58\x6e"
+        "\xad\x3d\x0e\xa9\x87\x17\x7c\x9b\x72\xcc\xab\x1c\x93\x2b",
+
+        "\x03\x2f\x4a\x9c\x49\x66\x9d\xbc\xae\xec\x54\x7d\xe6\x07\x52"
+        "\xc2\x9a\x09\xf5\xa7\x56\xa6\x68\x45\x38\x75\x7d\xb0\x0e\xee"
+        "\xf3\x23\xec\x74\x1e\x3b\xc0\x58\x1d\x43\xd9\x35\x15\x7e\x2f"
+        "\x28\xff\x08\x7a\x79\x44\xfc\x24\x06\xc5\x3f\xaa\xe0\xfa\xb2"
+        "\x1f\xd9\x4e\xd8\xc8\xda\xed\x1f\xaa\x77\x64\xae\xb3\xe3",
+
+        "\x01\xea\xaa\x9d\x90\x67\x3b\x2f\x9a\xe3\x7b\x56\x5c\x35\x9f"
+        "\x65\x0b\x0c\x3b\xa6\x60\x5f\x98\x36\x2c\xb6\xaa\xdb\xb2\x86"
+        "\x8b\x20\xba\xa4\x85\x7b\xa8\x80\x41\xee\x22\x1c\x7a\x92\xf5"
+        "\x39\x4e\x4a\x0b\x29\x0b\xe7\xdd\x3c\xb6\x51\xec\xc3\x26\xbc"
+        "\x33\x11\xbc\x29\x7a\x10\x68\x32\x55\xb4\x15\xd9\x8e\xc1"
+    };
+
+    static int primes_len[] = { 74, 74, 74, 74, 74 };
+
+    static char *exponents[] = {
+        "\x01\xa4\x49\xb7\x57\xc5\x50\x36\x08\x3c\xdc\x93\x29\x1d\x40"
+        "\x67\x63\x65\x57\x7f\xe7\x29\x82\x16\x0e\x9a\x74\x06\x37\x76"
+        "\xe7\xb6\x6a\x15\x5d\xf9\x3c\x00\x45\x3f\x62\xe1\x52\xb3\x3f"
+        "\x6e\xc2\x8d\x1b\x7e\xc4\x1c\x8e\x9e\xd7\x23\x45\xc8\x9d\x74"
+        "\x76\x25\x5b\x99\x31\x57\xa7\x5d\x71\x32\x2f\xd1\x74\xd5",
+
+        "\x01\x3a\xa4\x6d\x05\xf7\xeb\xa5\x3d\xe2\x67\x6e\xd7\x20\xd4"
+        "\x33\x17\x56\xdf\x34\x59\x81\xd2\x3b\x51\x64\x89\x44\x13\xca"
+        "\xc7\x41\xa4\xf7\xa8\xf6\xd4\xbc\xd7\xc1\x7d\xa3\xbf\x39\x4b"
+        "\x37\x1c\xac\xec\xf6\x46\x82\xdc\x05\x25\xf1\x7c\x71\x9e\xe9"
+        "\x0b\xd5\xb0\x40\x15\x7f\x4f\x01\x6a\x1c\x56\x2e\x42\x05",
+
+        "\x00\x9b\xd7\x14\x9e\xcf\x47\x4a\xe5\x1e\xa8\xc4\x93\x52\xd2"
+        "\x4c\xb7\xd3\x67\xa3\x4e\x79\x34\x09\x5e\x5c\x5c\x55\xe3\x3c"
+        "\x02\xa9\x81\xa4\x56\xa8\xb1\x3d\xf6\x40\xe3\xf5\x06\xce\x6f"
+        "\x29\x01\x05\xde\x43\xa8\x67\xeb\x29\x8d\x09\xd8\x7d\xaf\x3f"
+        "\x51\xac\xf4\x5b\x0c\xa0\x95\x35\x04\xd0\xf9\x6f\x6a\xa7",
+
+        "\x02\xfd\x38\x42\x48\x82\x90\x3a\xb0\xd4\x10\xd9\xba\x35\xd5"
+        "\x6f\xe1\xb4\xc7\x65\x30\xe7\x2f\xa7\x08\xbe\xfe\x21\x69\x62"
+        "\xcd\xc3\x42\x04\x1a\xfc\x6a\x24\x4a\x13\x8c\xa3\x4e\x71\x09"
+        "\x42\xa9\x5d\x03\xd7\x1e\xf0\xa9\xbf\xd1\x13\x59\x07\xa1\x45"
+        "\xde\xae\xd0\x5a\x98\xeb\x22\xf5\x3d\xc2\xa2\x35\x77\x91",
+
+        "\x13\x1d\x2c\x60\x28\xb5\x54\x88\x6b\x1e\x2d\xe2\x0f\xb0\xb2"
+        "\xe5\xf8\x47\x06\x97\x30\x82\x24\x72\x1f\x77\x8e\x71\x68\xee"
+        "\x58\x8b\x0c\xc7\xaa\x66\x89\x00\x88\x7f\x49\xae\xb8\xb4\xd6"
+        "\xd3\xa6\xec\xc2\x5f\x95\x5b\xb7\xf6\xbe\x40\x43\xe5\xe9\x64"
+        "\xef\xe6\xed\x92\xb4\xba\xea\x63\x0e\x4d\xdf\x98\xc1"
+    };
+
+    static int exps_len[] = { 74, 74, 74, 74, 73 };
+
+    static char *coefficients[] = {
+        "\x18\x19\x50\xc2\x69\x6a\x63\x66\x40\x6a\x43\xa6\x7d\x0d\x12"
+        "\x0f\x04\x3a\xe7\xb2\x1c\xe3\xfc\x6f\xa7\x8b\x5e\x99\xe3\x43"
+        "\x97\x68\x10\xee\x68\x73\x01\xc6\xaf\x5e\x26\xaf\xcc\x1f\x39"
+        "\x9c\x8d\xa9\x06\x80\x21\x7a\xaa\x29\x8a\x4b\x71\x03\xb0\x9a"
+        "\x2f\xd6\x6b\xb0\x0b\x93\xc9\x4d\x0b\x9d\x3f\xe6\x21",
+
+        "\x00\xa4\x80\x6e\xef\x34\xba\x3f\xe7\x96\xec\x25\x16\x25\xe9"
+        "\x77\x5f\x61\xb1\x48\xdb\x03\xfa\x80\xf3\xbd\x20\xd1\x60\x9a"
+        "\x10\x9d\xf0\x1b\xff\xb8\x50\x14\x54\x75\x53\x2b\x89\x9f\x39"
+        "\x96\x63\x05\x89\xfb\xfb\x7f\x59\x93\xdc\x61\xe2\x8c\xfc\x5a"
+        "\x6f\x2c\x6a\xcf\xd4\xac\xa5\x81\xf2\xdd\x68\x75\xd4\x48",
+
+        "\x00\xf6\xec\xd6\x98\x10\x42\x38\x94\x30\x2c\xd4\xe7\xb1\x5f"
+        "\xa2\xfd\xc9\xc4\x92\x78\xf6\x31\x34\xb7\x26\xa1\x7f\x0b\xa3"
+        "\xc3\xf6\x4f\xd0\x05\x4e\x98\x1b\xa5\x98\xde\x26\xb8\xc2\x14"
+        "\x12\xa4\xae\x2f\xd8\x48\x39\x1b\x33\x1d\x0f\x72\xaf\xd3\x8d"
+        "\xd8\xb0\x9f\x52\x42\x5d\xae\xf6\x3c\xe1\xd2\x09\xd8\x53",
+
+        "\x00\xb3\xce\x4b\x87\x41\x21\x34\x7b\xe3\x64\x74\xef\x9f\x71"
+        "\xcc\x01\x19\x50\x69\xbb\x5f\x69\xc8\xbc\x62\x8b\x4d\xa9\x73"
+        "\x23\x7f\xc6\xce\xfa\xe7\x96\xa7\x22\x44\x33\x32\x47\x60\x23"
+        "\xb4\xd2\x5e\xa4\xa1\xbd\x31\x1f\x04\x1a\xdf\xdb\x05\xe9\x4c"
+        "\x44\xfb\x9b\x73\xfe\x25\x3d\x7a\x61\xc2\x22\x9a\xd6\x18",
+
+        "\x01\x8d\x43\x63\x89\x6d\x97\xf3\x4a\x3e\x10\xa0\x94\x46\x1a"
+        "\x1c\x34\x22\xb3\xe3\x21\xff\xad\xf2\x1b\x56\x74\x32\xdc\xd2"
+        "\x0e\xd7\x3a\x9c\xe9\x87\xcc\xf1\x9c\x56\xfe\xff\x2f\x3d\xec"
+        "\x70\xba\xfb\x5d\x37\xa8\x57\xd1\xc4\xa9\x1b\xc9\xdc\x76\x68"
+        "\xca\x7d\x39\x59\x97\x2d\x07\x03\x52\xf6\x8d\xb6\x0e\x24"
+    };
+
+    static int coeffs_len[] = { 73, 74, 74, 74, 74 };
+
+    BIGNUM **pris = NULL, **exps = NULL, **coeffs = NULL;
+    int i, rv = 512;
+    unsigned char *n, *d;
+    size_t len_n, len_d;
+
+    len_n = sizeof(n1) + sizeof(n2) - 2;
+    n = OPENSSL_zalloc(len_n);
+    if (n == NULL)
+        return 0;
+
+    memcpy(n, n1, sizeof(n1) - 1);
+    memcpy(n + sizeof(n1) - 1, n2, sizeof(n2) - 1);
+
+    len_d = sizeof(d1) + sizeof(d2) - 2;
+    d = OPENSSL_zalloc(len_d);
+    if (d == NULL)
+        goto err;
+
+    memcpy(d, d1, sizeof(d1) - 1);
+    memcpy(d + sizeof(d1) - 1, d2, sizeof(d2) - 1);
+
+    if (!TEST_int_eq(RSA_set0_key(key,
+                                  BN_bin2bn(n, len_n, NULL),
+                                  BN_bin2bn(e, sizeof(e) - 1, NULL),
+                                  BN_bin2bn(d, len_d, NULL)), 1))
+        goto err;
+
+    if (!TEST_int_eq(RSA_set0_factors(key,
+                                      BN_bin2bn(p, sizeof(p) - 1, NULL),
+                                      BN_bin2bn(q, sizeof(q) - 1, NULL)), 1))
+        goto err;
+
+    if (!TEST_int_eq(RSA_set0_crt_params(key,
+                                         BN_bin2bn(dmp1, sizeof(dmp1) - 1, NULL),
+                                         BN_bin2bn(dmq1, sizeof(dmq1) - 1, NULL),
+                                         BN_bin2bn(iqmp, sizeof(iqmp) - 1,
+                                                   NULL)), 1))
+        return 0;
+
+    pris = OPENSSL_zalloc(sizeof(BIGNUM *) * NUM_EXTRA_PRIMES);
+    exps = OPENSSL_zalloc(sizeof(BIGNUM *) * NUM_EXTRA_PRIMES);
+    coeffs = OPENSSL_zalloc(sizeof(BIGNUM *) * NUM_EXTRA_PRIMES);
+    if (!TEST_ptr(pris) || !TEST_ptr(exps) || !TEST_ptr(coeffs))
+        goto err;
+
+    for (i = 0; i < NUM_EXTRA_PRIMES; i++) {
+        pris[i] = BN_bin2bn((unsigned char *)primes[i], primes_len[i], NULL);
+        exps[i] = BN_bin2bn((unsigned char *)exponents[i], exps_len[i], NULL);
+        coeffs[i] = BN_bin2bn((unsigned char *)coefficients[i],
+                              coeffs_len[i], NULL);
+        if (!TEST_ptr(pris[i]) || !TEST_ptr(exps[i]) || !TEST_ptr(coeffs[i]))
+            goto err;
+    }
+
+    if (!TEST_true(RSA_set0_multi_prime_params(key, pris, exps,
+                                               coeffs, NUM_EXTRA_PRIMES)))
+        goto err;
+
+ ret:
+    OPENSSL_free(pris);
+    OPENSSL_free(exps);
+    OPENSSL_free(coeffs);
+    OPENSSL_free(n);
+    OPENSSL_free(d);
+    return rv;
+ err:
+    for (i = 0; i < 5; i++) {
+        if (pris != NULL)
+            BN_free(pris[i]);
+        if (exps != NULL)
+            BN_free(exps[i]);
+        if (coeffs != NULL)
+            BN_free(coeffs[i]);
+    }
+    rv = 0;
+    goto ret;
+}
+
+static int test_rsa_mp(void)
+{
+    int ret = 0;
+    RSA *key;
+    unsigned char ptext[512];
+    unsigned char ctext[512];
+    static unsigned char ptext_ex[] = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
+    int plen;
+    int clen = 0;
+    int num;
+
+    plen = sizeof(ptext_ex) - 1;
+    key = RSA_new();
+    if (!TEST_ptr(key))
+        goto err;
+    clen = key4096p7(key);
+    if (!TEST_int_eq(clen, 512))
+        goto err;
+
+    if (!TEST_true(RSA_check_key_ex(key, NULL)))
+        goto err;
+
+    num = RSA_public_encrypt(plen, ptext_ex, ctext, key,
+                             RSA_PKCS1_PADDING);
+    if (!TEST_int_eq(num, clen))
+        goto err;
+
+    num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_PADDING);
+    if (!TEST_mem_eq(ptext, num, ptext_ex, plen))
+        goto err;
+
+    ret = 1;
+err:
+    RSA_free(key);
+    return ret;
+}
+#endif
+
+int setup_tests(void)
+{
+#ifndef OPENSSL_NO_RSA
+    ADD_TEST(test_rsa_mp);
+#endif
+    return 1;
+}
index 8d9db31..10ffa2c 100644 (file)
@@ -4438,3 +4438,11 @@ EVP_PKEY_asn1_set_param_check           4382     1_1_1   EXIST::FUNCTION:
 DH_check_ex                             4383   1_1_1   EXIST::FUNCTION:DH
 DH_check_pub_key_ex                     4384   1_1_1   EXIST::FUNCTION:DH
 DH_check_params_ex                      4385   1_1_1   EXIST::FUNCTION:DH
 DH_check_ex                             4383   1_1_1   EXIST::FUNCTION:DH
 DH_check_pub_key_ex                     4384   1_1_1   EXIST::FUNCTION:DH
 DH_check_params_ex                      4385   1_1_1   EXIST::FUNCTION:DH
+RSA_generate_multi_prime_key            4386   1_1_1   EXIST::FUNCTION:RSA
+RSA_get_multi_prime_extra_count         4387   1_1_1   EXIST::FUNCTION:RSA
+RSA_get0_multi_prime_factors            4388   1_1_1   EXIST::FUNCTION:RSA
+RSA_get0_multi_prime_crt_params         4389   1_1_1   EXIST::FUNCTION:RSA
+RSA_set0_multi_prime_params             4390   1_1_1   EXIST::FUNCTION:RSA
+RSA_get_version                         4391   1_1_1   EXIST::FUNCTION:RSA
+RSA_meth_get_multi_prime_keygen         4392   1_1_1   EXIST::FUNCTION:RSA
+RSA_meth_set_multi_prime_keygen         4393   1_1_1   EXIST::FUNCTION:RSA