Skip to content

Commit

Permalink
Support multi-prime RSA (RFC 8017)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Reviewed-by: Bernd Edlinger <[email protected]>
(Merged from openssl#4241)
  • Loading branch information
InfoHunter committed Nov 21, 2017
1 parent b000470 commit 665d899
Show file tree
Hide file tree
Showing 29 changed files with 1,559 additions and 99 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

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 <[email protected]>,
Ronald Tse <[email protected]>,
Expand Down
17 changes: 12 additions & 5 deletions apps/genrsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ NON_EMPTY_TRANSLATION_UNIT
# 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,
OPT_OUT, OPT_PASSOUT, OPT_CIPHER,
OPT_OUT, OPT_PASSOUT, OPT_CIPHER, OPT_PRIMES,
OPT_R_ENUM
} OPTION_CHOICE;

Expand All @@ -49,6 +50,7 @@ const OPTIONS genrsa_options[] = {
# ifndef OPENSSL_NO_ENGINE
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
# endif
{"primes", OPT_PRIMES, 'p', "Specify number of primes"},
{NULL}
};

Expand All @@ -62,7 +64,7 @@ int genrsa_main(int argc, char **argv)
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;
Expand Down Expand Up @@ -108,6 +110,10 @@ int genrsa_main(int argc, char **argv)
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();
Expand All @@ -131,13 +137,14 @@ int genrsa_main(int argc, char **argv)
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;

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);
Expand Down
41 changes: 40 additions & 1 deletion apps/speed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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[] = {
Expand All @@ -366,6 +367,7 @@ const OPTIONS speed_options[] = {
#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},
};

Expand Down Expand Up @@ -1325,6 +1327,7 @@ int speed_main(int argc, char **argv)
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 };
Expand Down Expand Up @@ -1459,6 +1462,10 @@ int speed_main(int argc, char **argv)
if (!opt_rand(o))
goto end;
break;
case OPT_PRIMES:
if (!opt_int(opt_arg(), &primes))
goto end;
break;
}
}
argc = opt_num_rest();
Expand Down Expand Up @@ -1615,6 +1622,10 @@ int speed_main(int argc, char **argv)

#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;

Expand Down Expand Up @@ -2395,6 +2406,34 @@ int speed_main(int argc, char **argv)
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)
Expand Down
6 changes: 6 additions & 0 deletions crypto/err/openssl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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_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
Expand All @@ -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_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_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_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:\
Expand Down
2 changes: 1 addition & 1 deletion crypto/rsa/build.info
Original file line number Diff line number Diff line change
Expand Up @@ -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_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
41 changes: 39 additions & 2 deletions crypto/rsa/rsa_ameth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
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);
ex_primes = sk_RSA_PRIME_INFO_num(x->prime_infos);

if (!BIO_indent(bp, off, 128))
goto err;
Expand All @@ -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) {
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:";
Expand All @@ -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) {
int i;

if (!ASN1_bn_print(bp, "privateExponent:", x->d, NULL, off))
goto err;
if (!ASN1_bn_print(bp, "prime1:", x->p, NULL, off))
Expand All @@ -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;
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;
Expand Down
24 changes: 21 additions & 3 deletions crypto/rsa/rsa_asn1.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,7 +14,11 @@
#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)
{
Expand All @@ -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;
} 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;
}

/* 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),
Expand All @@ -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, iqmp, CBIGNUM)
ASN1_SIMPLE(RSA, iqmp, CBIGNUM),
ASN1_SEQUENCE_OF_OPT(RSA, prime_infos, RSA_PRIME_INFO)
} ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey)


Expand Down
Loading

0 comments on commit 665d899

Please sign in to comment.