Preliminary support for X9.31 RSA key generation for FIPS.

Included prime derivation, random prime generation, test program and
new option to genrsa.
This commit is contained in:
Dr. Stephen Henson 2005-05-31 12:38:03 +00:00
parent bb1bbb3274
commit 485bcc9cab
13 changed files with 1070 additions and 20 deletions

View file

@ -88,6 +88,9 @@ int MAIN(int argc, char **argv)
RSA *rsa=NULL;
int i,num=DEFBITS;
long l;
#ifdef OPENSSL_FIPS
int use_x931 = 0;
#endif
const EVP_CIPHER *enc=NULL;
unsigned long f4=RSA_F4;
char *outfile=NULL;
@ -126,6 +129,10 @@ int MAIN(int argc, char **argv)
f4=3;
else if (strcmp(*argv,"-F4") == 0 || strcmp(*argv,"-f4") == 0)
f4=RSA_F4;
#ifdef OPENSSL_FIPS
else if (strcmp(*argv,"-x931") == 0)
use_x931 = 1;
#endif
#ifndef OPENSSL_NO_ENGINE
else if (strcmp(*argv,"-engine") == 0)
{
@ -233,11 +240,27 @@ bad:
BIO_printf(bio_err,"Generating RSA private key, %d bit long modulus\n",
num);
rsa=RSA_generate_key(num,f4,genrsa_cb,bio_err);
#ifdef OPENSSL_FIPS
if (use_x931)
{
BIGNUM *pubexp;
pubexp = BN_new();
BN_set_word(pubexp, f4);
rsa = RSA_X931_generate_key(num, pubexp, genrsa_cb, bio_err);
BN_free(pubexp);
}
else
#endif
rsa=RSA_generate_key(num,f4,genrsa_cb,bio_err);
app_RAND_write_file(NULL, bio_err);
if (rsa == NULL) goto err;
if (rsa == NULL)
{
BIO_printf(bio_err, "Key Generation error\n");
goto err;
}
/* We need to do the following for when the base number size is <
* long, esp windows 3.1 :-(. */

View file

@ -31,12 +31,12 @@ LIB=$(TOP)/libcrypto.a
LIBSRC= bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c bn_mod.c \
bn_print.c bn_rand.c bn_shift.c bn_word.c bn_blind.c \
bn_kron.c bn_sqrt.c bn_gcd.c bn_prime.c bn_err.c bn_sqr.c bn_asm.c \
bn_recp.c bn_mont.c bn_mpi.c bn_exp2.c
bn_recp.c bn_mont.c bn_mpi.c bn_exp2.c bn_x931p.c
LIBOBJ= bn_add.o bn_div.o bn_exp.o bn_lib.o bn_ctx.o bn_mul.o bn_mod.o \
bn_print.o bn_rand.o bn_shift.o bn_word.o bn_blind.o \
bn_kron.o bn_sqrt.o bn_gcd.o bn_prime.o bn_err.o bn_sqr.o $(BN_ASM) \
bn_recp.o bn_mont.o bn_mpi.o bn_exp2.o
bn_recp.o bn_mont.o bn_mpi.o bn_exp2.o bn_x931p.o
SRC= $(LIBSRC)

View file

@ -438,6 +438,19 @@ int BN_is_prime_fasttest(const BIGNUM *p,int nchecks,
void (*callback)(int,int,void *),BN_CTX *ctx,void *cb_arg,
int do_trial_division);
#ifdef OPENSSL_FIPS
int BN_X931_derive_prime(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
void (*cb)(int, int, void *), void *cb_arg,
const BIGNUM *Xp, const BIGNUM *Xp1, const BIGNUM *Xp2,
const BIGNUM *e, BN_CTX *ctx);
int BN_X931_generate_Xpq(BIGNUM *Xp, BIGNUM *Xq, int nbits, BN_CTX *ctx);
int BN_X931_generate_prime(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
BIGNUM *Xp1, BIGNUM *Xp2,
const BIGNUM *Xp,
const BIGNUM *e, BN_CTX *ctx,
void (*cb)(int, int, void *), void *cb_arg);
#endif
BN_MONT_CTX *BN_MONT_CTX_new(void );
void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
int BN_mod_mul_montgomery(BIGNUM *r,const BIGNUM *a,const BIGNUM *b,

279
crypto/bn/bn_x931p.c Normal file
View file

@ -0,0 +1,279 @@
/* bn_x931p.c */
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
* project 2005.
*/
/* ====================================================================
* Copyright (c) 2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#include <stdio.h>
#include <openssl/bn.h>
/* X9.31 routines for prime derivation */
/* X9.31 prime derivation. This is used to generate the primes pi
* (p1, p2, q1, q2) from a parameter Xpi by checking successive odd
* integers.
*/
static int bn_x931_derive_pi(BIGNUM *pi, const BIGNUM *Xpi, BN_CTX *ctx,
void (*cb)(int, int, void *), void *cb_arg)
{
int i = 0;
if (!BN_copy(pi, Xpi))
return 0;
if (!BN_is_odd(pi) && !BN_add_word(pi, 1))
return 0;
for(;;)
{
i++;
if (cb)
cb(0, i, cb_arg);
/* NB 27 MR is specificed in X9.31 */
if (BN_is_prime_fasttest(pi, 27, cb, ctx, cb_arg, 1))
break;
if (!BN_add_word(pi, 2))
return 0;
}
if (cb)
cb(2, i, cb_arg);
return 1;
}
/* This is the main X9.31 prime derivation function. From parameters
* Xp1, Xp2 and Xp derive the prime p. If the parameters p1 or p2 are
* not NULL they will be returned too: this is needed for testing.
*/
int BN_X931_derive_prime(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
void (*cb)(int, int, void *), void *cb_arg,
const BIGNUM *Xp, const BIGNUM *Xp1, const BIGNUM *Xp2,
const BIGNUM *e, BN_CTX *ctx)
{
int ret = 0;
BIGNUM *t, *p1p2, *pm1;
/* Only even e supported */
if (!BN_is_odd(e))
return 0;
BN_CTX_start(ctx);
if (!p1)
p1 = BN_CTX_get(ctx);
if (!p2)
p2 = BN_CTX_get(ctx);
t = BN_CTX_get(ctx);
p1p2 = BN_CTX_get(ctx);
pm1 = BN_CTX_get(ctx);
if (!bn_x931_derive_pi(p1, Xp1, ctx, cb, cb_arg))
goto err;
if (!bn_x931_derive_pi(p2, Xp2, ctx, cb, cb_arg))
goto err;
if (!BN_mul(p1p2, p1, p2, ctx))
goto err;
/* First set p to value of Rp */
if (!BN_mod_inverse(p, p2, p1, ctx))
goto err;
if (!BN_mul(p, p, p2, ctx))
goto err;
if (!BN_mod_inverse(t, p1, p2, ctx))
goto err;
if (!BN_mul(t, t, p1, ctx))
goto err;
if (!BN_sub(p, p, t))
goto err;
if (p->neg && !BN_add(p, p, p1p2))
goto err;
/* p now equals Rp */
if (!BN_mod_sub(p, p, Xp, p1p2, ctx))
goto err;
if (!BN_add(p, p, Xp))
goto err;
/* p now equals Yp0 */
for (;;)
{
int i = 1;
if (cb)
cb(0, i++, cb_arg);
if (!BN_copy(pm1, p))
goto err;
if (!BN_sub_word(pm1, 1))
goto err;
if (!BN_gcd(t, pm1, e, ctx))
goto err;
if (BN_is_one(t)
/* X9.31 specifies 8 MR and 1 Lucas test or any prime test
* offering similar or better guarantees 50 MR is considerably
* better.
*/
&& BN_is_prime_fasttest(p, 50, cb, ctx, cb_arg, 1))
break;
if (!BN_add(p, p, p1p2))
goto err;
}
if (cb)
cb(3, 0, cb_arg);
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
/* Generate pair of paramters Xp, Xq for X9.31 prime generation.
* Note: nbits paramter is sum of number of bits in both.
*/
int BN_X931_generate_Xpq(BIGNUM *Xp, BIGNUM *Xq, int nbits, BN_CTX *ctx)
{
BIGNUM *t;
int i;
/* Number of bits for each prime is of the form
* 512+128s for s = 0, 1, ...
*/
if ((nbits < 1024) || (nbits & 0xff))
return 0;
nbits >>= 1;
/* The random value Xp must be between sqrt(2) * 2^(nbits-1) and
* 2^nbits - 1. By setting the top two bits we ensure that the lower
* bound is exceeded.
*/
if (!BN_rand(Xp, nbits, 1, 0))
return 0;
BN_CTX_start(ctx);
t = BN_CTX_get(ctx);
for (i = 0; i < 1000; i++)
{
if (!BN_rand(Xq, nbits, 1, 0))
return 0;
/* Check that |Xp - Xq| > 2^(nbits - 100) */
BN_sub(t, Xp, Xq);
if (BN_num_bits(t) > (nbits - 100))
break;
}
BN_CTX_end(ctx);
if (i < 1000)
return 1;
return 0;
}
/* Generate primes using X9.31 algorithm. Of the values p, p1, p2, Xp1
* and Xp2 only 'p' needs to be non-NULL. If any of the others are not NULL
* the relevant parameter will be stored in it.
*
* Due to the fact that |Xp - Xq| > 2^(nbits - 100) must be satisfied Xp and Xq
* are generated using the previous function and supplied as input.
*/
int BN_X931_generate_prime(BIGNUM *p, BIGNUM *p1, BIGNUM *p2,
BIGNUM *Xp1, BIGNUM *Xp2,
const BIGNUM *Xp,
const BIGNUM *e, BN_CTX *ctx,
void (*cb)(int, int, void *), void *cb_arg)
{
int ret = 0;
BN_CTX_start(ctx);
if (!Xp1)
Xp1 = BN_CTX_get(ctx);
if (!Xp2)
Xp2 = BN_CTX_get(ctx);
if (!BN_rand(Xp1, 101, 0, 0))
goto error;
if (!BN_rand(Xp2, 101, 0, 0))
goto error;
if (!BN_X931_derive_prime(p, p1, p2, cb, cb_arg,
Xp, Xp1, Xp2, e, ctx))
goto error;
ret = 1;
error:
BN_CTX_end(ctx);
return ret;
}

View file

@ -204,6 +204,15 @@ int RSA_size(const RSA *);
RSA * RSA_generate_key(int bits, unsigned long e,void
(*callback)(int,int,void *),void *cb_arg);
int RSA_check_key(const RSA *);
#ifndef FIPS
int RSA_X931_derive(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1, BIGNUM *q2,
void (*cb)(int, int, void *), void *cb_arg,
const BIGNUM *Xp1, const BIGNUM *Xp2, const BIGNUM *Xp,
const BIGNUM *Xq1, const BIGNUM *Xq2, const BIGNUM *Xq,
const BIGNUM *e);
RSA *RSA_X931_generate_key(int bits, const BIGNUM *e,
void (*cb)(int,int,void *), void *cb_arg);
#endif
/* next 4 return -1 on error */
int RSA_public_encrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa,int padding);

View file

@ -108,6 +108,7 @@ void ERR_load_FIPS_strings(void);
#define FIPS_F_HASH_FINAL 100
#define FIPS_F_RSA_EAY_PUBLIC_ENCRYPT 114
#define FIPS_F_RSA_GENERATE_KEY 113
#define FIPS_F_RSA_X931_GENERATE_KEY 119
#define FIPS_F_SSLEAY_RAND_BYTES 101
/* Reason codes. */
@ -116,10 +117,11 @@ void ERR_load_FIPS_strings(void);
#define FIPS_R_EXE_DIGEST_DOES_NOT_MATCH 105
#define FIPS_R_FIPS_MODE_ALREADY_SET 102
#define FIPS_R_FIPS_SELFTEST_FAILED 106
#define FIPS_R_INVALID_KEY_LENGTH 109
#define FIPS_R_KEY_TOO_SHORT 108
#define FIPS_R_NON_FIPS_METHOD 100
#define FIPS_R_PAIRWISE_TEST_FAILED 107
#define FIPS_R_SELFTEST_FAILED 101
#define FIPS_R_KEY_TOO_SHORT 108
#ifdef __cplusplus
}

View file

@ -84,10 +84,11 @@ static ERR_STRING_DATA FIPS_str_functs[]=
{ERR_FUNC(FIPS_F_FIPS_SELFTEST_DSA), "FIPS_selftest_dsa"},
{ERR_FUNC(FIPS_F_FIPS_SELFTEST_RNG), "FIPS_selftest_rng"},
{ERR_FUNC(FIPS_F_FIPS_SELFTEST_RSA), "FIPS_selftest_rsa"},
{ERR_FUNC(FIPS_F_FIPS_SELFTEST_SHA), "FIPS_selftest_sha"},
{ERR_FUNC(FIPS_F_FIPS_SELFTEST_SHA), "FIPS_SELFTEST_SHA"},
{ERR_FUNC(FIPS_F_HASH_FINAL), "HASH_FINAL"},
{ERR_FUNC(FIPS_F_RSA_EAY_PUBLIC_ENCRYPT), "RSA_EAY_PUBLIC_ENCRYPT"},
{ERR_FUNC(FIPS_F_RSA_GENERATE_KEY), "RSA_generate_key"},
{ERR_FUNC(FIPS_F_RSA_X931_GENERATE_KEY), "RSA_X931_generate_key"},
{ERR_FUNC(FIPS_F_SSLEAY_RAND_BYTES), "SSLEAY_RAND_BYTES"},
{0,NULL}
};
@ -99,6 +100,8 @@ static ERR_STRING_DATA FIPS_str_reasons[]=
{ERR_REASON(FIPS_R_EXE_DIGEST_DOES_NOT_MATCH),"exe digest does not match"},
{ERR_REASON(FIPS_R_FIPS_MODE_ALREADY_SET),"fips mode already set"},
{ERR_REASON(FIPS_R_FIPS_SELFTEST_FAILED) ,"fips selftest failed"},
{ERR_REASON(FIPS_R_INVALID_KEY_LENGTH) ,"invalid key length"},
{ERR_REASON(FIPS_R_KEY_TOO_SHORT) ,"key too short"},
{ERR_REASON(FIPS_R_NON_FIPS_METHOD) ,"non fips method"},
{ERR_REASON(FIPS_R_PAIRWISE_TEST_FAILED) ,"pairwise test failed"},
{ERR_REASON(FIPS_R_SELFTEST_FAILED) ,"selftest failed"},
@ -109,11 +112,11 @@ static ERR_STRING_DATA FIPS_str_reasons[]=
void ERR_load_FIPS_strings(void)
{
static int init;
static int init=1;
if (!init)
if (init)
{
init=1;
init=0;
#ifndef OPENSSL_NO_ERR
ERR_load_strings(0,FIPS_str_functs);
ERR_load_strings(0,FIPS_str_reasons);

View file

@ -1,8 +1,8 @@
const char * const FIPS_source_hashes[] = {
"HMAC-SHA1(fips.c)= 7cbbda3b9e8aec46ee31797179cb72faeef80712",
"HMAC-SHA1(fips_err_wrapper.c)= d3e2be316062510312269e98f964cb87e7577898",
"HMAC-SHA1(fips.h)= e85fdc2fe6ad2dbf0662691e87af4b6b240da62e",
"HMAC-SHA1(fips_err.h)= 0b2bd6999ee5792fec3739689cde5f352789e63a",
"HMAC-SHA1(fips.h)= 9e8d77f438eabc36273e2046aa209e6e78515103",
"HMAC-SHA1(fips_err.h)= fec567f1abe0f8d53a208b7f24b992dda2db3e4d",
"HMAC-SHA1(aes/fips_aes_core.c)= b70bbbd675efe0613da0d57055310926a0104d55",
"HMAC-SHA1(aes/asm/fips-ax86-elf.s)= f797b524a79196e7f59458a5b223432fcfd4a868",
"HMAC-SHA1(aes/fips_aes_selftest.c)= 98b01502221e7fe529fd981222f2cbb52eb4cbe0",
@ -22,8 +22,9 @@ const char * const FIPS_source_hashes[] = {
"HMAC-SHA1(rand/fips_rand.h)= bf009ea8963e79b1e414442ede9ae7010a03160b",
"HMAC-SHA1(rand/fips_rand_selftest.c)= d9c8985e08feecefafe667ad0119d444b42f807c",
"HMAC-SHA1(rsa/fips_rsa_eay.c)= 2512f849a220daa083f346b10effdb2ee96d4395",
"HMAC-SHA1(rsa/fips_rsa_gen.c)= af83b857d2be13d59e7f1516e6b1a25edd6369c3",
"HMAC-SHA1(rsa/fips_rsa_gen.c)= 577466931c054d99caf4ac2aefff0e35efd94024",
"HMAC-SHA1(rsa/fips_rsa_selftest.c)= a9dc47bd1001f795d1565111d26433c300101e06",
"HMAC-SHA1(rsa/fips_rsa_x931g.c)= 62ecb2622cf61010561d5800ba2c74f54a3d2526",
"HMAC-SHA1(sha/fips_sha1dgst.c)= 26e529d630b5e754b4a29bd1bb697e991e7fdc04",
"HMAC-SHA1(sha/fips_standalone_sha1.c)= faae95bc36cc80f5be6a0cde02ebab0f63d4fd97",
"HMAC-SHA1(sha/fips_sha1_selftest.c)= a08f9c1e2c0f63b9aa96b927c0333a03b020749f",

View file

@ -18,12 +18,12 @@ AR= ar r
CFLAGS= $(INCLUDES) $(CFLAG)
GENERAL=Makefile
TEST= fips_rsavtest.c fips_rsastest.c
TEST= fips_rsavtest.c fips_rsastest.c fips_rsagtest.c
APPS=
LIB=$(TOP)/libcrypto.a
LIBSRC=fips_rsa_eay.c fips_rsa_gen.c fips_rsa_selftest.c
LIBOBJ=fips_rsa_eay.o fips_rsa_gen.o fips_rsa_selftest.o
LIBSRC=fips_rsa_eay.c fips_rsa_gen.c fips_rsa_selftest.c fips_rsa_x931g.c
LIBOBJ=fips_rsa_eay.o fips_rsa_gen.o fips_rsa_selftest.o fips_rsa_x931g.o
SRC= $(LIBSRC)
@ -68,6 +68,9 @@ top_fips_rsastest:
top_fips_rsavtest:
(cd $(TOP); $(MAKE) DIRS=fips FDIRS=$(DIR) TARGET=fips_rsavtest sub_target)
top_fips_rsagtest:
(cd $(TOP); $(MAKE) DIRS=fips FDIRS=$(DIR) TARGET=fips_rsagtest sub_target)
fips_rsastest: fips_rsastest.o $(TOP)/libcrypto.a
$(CC) $(CFLAGS) -o fips_rsastest fips_rsastest.o $(PEX_LIBS) $(TOP)/libcrypto.a $(EX_LIBS)
TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a fips_rsastest
@ -76,10 +79,14 @@ fips_rsavtest: fips_rsavtest.o $(TOP)/libcrypto.a
$(CC) $(CFLAGS) -o fips_rsavtest fips_rsavtest.o $(PEX_LIBS) $(TOP)/libcrypto.a $(EX_LIBS)
TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a fips_rsavtest
fips_rsagtest: fips_rsagtest.o $(TOP)/libcrypto.a
$(CC) $(CFLAGS) -o fips_rsagtest fips_rsagtest.o $(PEX_LIBS) $(TOP)/libcrypto.a $(EX_LIBS)
TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a fips_rsagtest
Q=../testvectors/rsa/req
A=../testvectors/rsa/rsp
fips_test: top top_fips_rsastest top_fips_rsavtest
fips_test: top top_fips_rsastest top_fips_rsavtest top_fips_rsagtest
-rm -rf $(A)
mkdir $(A)
./fips_rsastest < $(Q)/SigGen15.req > $(A)/SigGen15.rsp

View file

@ -68,7 +68,7 @@ void *OPENSSL_stderr(void);
#ifdef OPENSSL_FIPS
static int fips_check_rsa(RSA *rsa)
int fips_check_rsa(RSA *rsa)
{
int n, ret = 0;
unsigned char tctext[256], *ctext = tctext;

286
fips/rsa/fips_rsa_x931g.c Normal file
View file

@ -0,0 +1,286 @@
/* crypto/rsa/rsa_gen.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/fips.h>
extern int fips_check_rsa(RSA *rsa);
/* X9.31 RSA key derivation and generation */
int RSA_X931_derive(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1, BIGNUM *q2,
void (*cb)(int, int, void *), void *cb_arg,
const BIGNUM *Xp1, const BIGNUM *Xp2, const BIGNUM *Xp,
const BIGNUM *Xq1, const BIGNUM *Xq2, const BIGNUM *Xq,
const BIGNUM *e)
{
BIGNUM *r0=NULL,*r1=NULL,*r2=NULL,*r3=NULL;
BN_CTX *ctx=NULL,*ctx2=NULL;
if (!rsa)
goto err;
ctx = BN_CTX_new();
BN_CTX_start(ctx);
if (!ctx)
goto err;
r0 = BN_CTX_get(ctx);
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
r3 = BN_CTX_get(ctx);
if (r3 == NULL)
goto err;
if (!rsa->e)
{
rsa->e = BN_dup(e);
if (!rsa->e)
goto err;
}
else
e = rsa->e;
/* If not all parameters present only calculate what we can.
* This allows test programs to output selective parameters.
*/
if (Xp && !rsa->p)
{
rsa->p = BN_new();
if (!rsa->p)
goto err;
if (!BN_X931_derive_prime(rsa->p, p1, p2, cb, cb_arg,
Xp, Xp1, Xp2, e, ctx))
goto err;
}
if (Xq && !rsa->q)
{
rsa->q = BN_new();
if (!rsa->q)
goto err;
if (!BN_X931_derive_prime(rsa->q, q1, q2, cb, cb_arg,
Xq, Xq1, Xq2, e, ctx))
goto err;
}
if (!rsa->p || !rsa->q)
{
BN_CTX_end(ctx);
BN_CTX_free(ctx);
return 2;
}
/* Since both primes are set we can now calculate all remaining
* components.
*/
/* calculate n */
rsa->n=BN_new();
if (rsa->n == NULL)
goto err;
if (!BN_mul(rsa->n,rsa->p,rsa->q,ctx))
goto err;
/* calculate d */
if (!BN_sub(r1,rsa->p,BN_value_one()))
goto err; /* p-1 */
if (!BN_sub(r2,rsa->q,BN_value_one()))
goto err; /* q-1 */
if (!BN_mul(r0,r1,r2,ctx))
goto err; /* (p-1)(q-1) */
if (!BN_gcd(r3, r1, r2, ctx))
goto err;
if (!BN_div(r0, NULL, r0, r3, ctx))
goto err; /* LCM((p-1)(q-1)) */
ctx2 = BN_CTX_new();
if (!ctx2)
goto err;
rsa->d=BN_mod_inverse(NULL,rsa->e,r0,ctx2); /* d */
if (rsa->d == NULL)
goto err;
/* calculate d mod (p-1) */
rsa->dmp1=BN_new();
if (rsa->dmp1 == NULL)
goto err;
if (!BN_mod(rsa->dmp1,rsa->d,r1,ctx))
goto err;
/* calculate d mod (q-1) */
rsa->dmq1=BN_new();
if (rsa->dmq1 == NULL)
goto err;
if (!BN_mod(rsa->dmq1,rsa->d,r2,ctx))
goto err;
/* calculate inverse of q mod p */
rsa->iqmp=BN_mod_inverse(NULL,rsa->q,rsa->p,ctx2);
err:
if (ctx)
{
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if (ctx2)
BN_CTX_free(ctx2);
/* If this is set all calls successful */
if (rsa->iqmp != NULL)
return 1;
return 0;
}
RSA *RSA_X931_generate_key(FIPS_RSA_SIZE_T bits, const BIGNUM *e,
void (*cb)(int,int,void *), void *cb_arg)
{
RSA *rsa = NULL;
int ok = 0;
BIGNUM *Xp = NULL, *Xq = NULL;
BN_CTX *ctx = NULL;
if (bits < 1024)
{
FIPSerr(FIPS_F_RSA_X931_GENERATE_KEY,FIPS_R_KEY_TOO_SHORT);
return NULL;
}
if (bits & 0xff)
{
FIPSerr(FIPS_F_RSA_X931_GENERATE_KEY,FIPS_R_INVALID_KEY_LENGTH);
return NULL;
}
if(FIPS_selftest_failed())
{
FIPSerr(FIPS_F_RSA_X931_GENERATE_KEY,FIPS_R_FIPS_SELFTEST_FAILED);
return NULL;
}
ctx = BN_CTX_new();
if (!ctx)
goto error;
BN_CTX_start(ctx);
Xp = BN_CTX_get(ctx);
Xq = BN_CTX_get(ctx);
if (!BN_X931_generate_Xpq(Xp, Xq, bits, ctx))
goto error;
rsa = RSA_new();
if (!rsa)
goto error;
rsa->p = BN_new();
rsa->q = BN_new();
if (!rsa->p || !rsa->q)
goto error;
/* Generate two primes from Xp, Xq */
if (!BN_X931_generate_prime(rsa->p, NULL, NULL, NULL, NULL, Xp,
e, ctx, cb, cb_arg))
goto error;
if (!BN_X931_generate_prime(rsa->q, NULL, NULL, NULL, NULL, Xq,
e, ctx, cb, cb_arg))
goto error;
/* Since rsa->p and rsa->q are valid this call will just derive
* remaining RSA components.
*/
if (!RSA_X931_derive(rsa, NULL, NULL, NULL, NULL, cb, cb_arg,
NULL, NULL, NULL, NULL, NULL, NULL, e))
goto error;
if(!fips_check_rsa(rsa))
goto error;
ok = 1;
error:
if (ctx)
{
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if (ok)
return rsa;
if (rsa)
RSA_free(rsa);
return NULL;
}

420
fips/rsa/fips_rsagtest.c Normal file
View file

@ -0,0 +1,420 @@
/* fips_rsagtest.c */
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
* project 2005.
*/
/* ====================================================================
* Copyright (c) 2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_FIPS
int main(int argc, char *argv[])
{
printf("No FIPS RSA support\n");
return(0);
}
#else
extern int RSA_X931_derive(RSA *rsa, BIGNUM *p1, BIGNUM *p2, BIGNUM *q1, BIGNUM *q2,
void (*cb)(int, int, void *), void *cb_arg,
const BIGNUM *Xp1, const BIGNUM *Xp2, const BIGNUM *Xp,
const BIGNUM *Xq1, const BIGNUM *Xq2, const BIGNUM *Xq,
const BIGNUM *e);
int rsa_test(BIO *err, BIO *out, BIO *in);
static int rsa_printkey1(BIO *err, BIO *out, RSA *rsa,
BIGNUM *Xp1, BIGNUM *Xp2, BIGNUM *Xp,
BIGNUM *e);
static int rsa_printkey2(BIO *err, BIO *out, RSA *rsa,
BIGNUM *Xq1, BIGNUM *Xq2, BIGNUM *Xq);
int main(int argc, char **argv)
{
BIO *in = NULL, *out = NULL, *err = NULL;
int ret = 1;
ERR_load_crypto_strings();
err = BIO_new_fp(stderr, BIO_NOCLOSE);
if (!err)
{
fprintf(stderr, "FATAL stderr initialization error\n");
goto end;
}
if(!FIPS_mode_set(1,argv[0]))
{
ERR_print_errors(err);
goto end;
}
if (argc == 1)
in = BIO_new_fp(stdin, BIO_NOCLOSE);
else
in = BIO_new_file(argv[1], "r");
if (argc < 2)
out = BIO_new_fp(stdout, BIO_NOCLOSE);
else
out = BIO_new_file(argv[2], "w");
if (!in)
{
BIO_printf(err, "FATAL input initialization error\n");
goto end;
}
if (!out)
{
fprintf(stderr, "FATAL output initialization error\n");
goto end;
}
if (!rsa_test(err, out, in))
{
fprintf(stderr, "FATAL RSAVTEST file processing error\n");
goto end;
}
else
ret = 0;
end:
if (ret && err)
ERR_print_errors(err);
if (in)
BIO_free(in);
if (out)
BIO_free(out);
if (err)
BIO_free(err);
return ret;
}
static void do_bn_print(BIO *out, const char *name, BIGNUM *b)
{
char *htmp, *p;
/* Can't use BN_print_fp because it uses upper case so
* use BN_bn2hex() and convert.
*/
htmp = BN_bn2hex(b);
for(p = htmp; *p; p++)
{
if (isupper(*p))
*p = tolower(*p);
}
BIO_printf(out, "%s = %s\n", name, htmp);
OPENSSL_free(htmp);
}
#define RSA_TEST_MAXLINELEN 10240
int rsa_test(BIO *err, BIO *out, BIO *in)
{
char *linebuf, *olinebuf, *p, *q;
char *keyword, *value;
RSA *rsa = NULL;
BIGNUM *Xp1 = NULL, *Xp2 = NULL, *Xp = NULL;
BIGNUM *Xq1 = NULL, *Xq2 = NULL, *Xq = NULL;
BIGNUM *e = NULL;
int ret = 0;
int lnum = 0;
olinebuf = OPENSSL_malloc(RSA_TEST_MAXLINELEN);
linebuf = OPENSSL_malloc(RSA_TEST_MAXLINELEN);
if (!linebuf || !olinebuf)
goto error;
while (BIO_gets(in, olinebuf, RSA_TEST_MAXLINELEN) > 0)
{
lnum++;
strcpy(linebuf, olinebuf);
keyword = linebuf;
/* Skip leading space */
while (isspace((unsigned char)*keyword))
keyword++;
/* Look for = sign */
p = strchr(linebuf, '=');
/* If no = or starts with [ (for [foo = bar] line) just copy */
if (!p || *keyword=='[')
{
if (!BIO_puts(out, olinebuf))
goto error;
continue;
}
q = p - 1;
/* Remove trailing space */
while (isspace((unsigned char)*q))
*q-- = 0;
value = p + 1;
/* Remove leading space from value */
while (isspace((unsigned char)*value))
value++;
/* Remove trailing space from value */
p = value + strlen(value) - 1;
while (*p == '\n' || isspace((unsigned char)*p))
*p-- = 0;
if (!strcmp(keyword, "xp1"))
{
if (Xp1 || !BN_hex2bn(&Xp1,value))
goto parse_error;
}
else if (!strcmp(keyword, "xp2"))
{
if (Xp2 || !BN_hex2bn(&Xp2,value))
goto parse_error;
}
else if (!strcmp(keyword, "Xp"))
{
if (Xp || !BN_hex2bn(&Xp,value))
goto parse_error;
}
else if (!strcmp(keyword, "xq1"))
{
if (Xq1 || !BN_hex2bn(&Xq1,value))
goto parse_error;
}
else if (!strcmp(keyword, "xq2"))
{
if (Xq2 || !BN_hex2bn(&Xq2,value))
goto parse_error;
}
else if (!strcmp(keyword, "Xq"))
{
if (Xq || !BN_hex2bn(&Xq,value))
goto parse_error;
}
else if (!strcmp(keyword, "e"))
{
if (e || !BN_hex2bn(&e,value))
goto parse_error;
}
else if (!strcmp(keyword, "p1"))
continue;
else if (!strcmp(keyword, "p2"))
continue;
else if (!strcmp(keyword, "p"))
continue;
else if (!strcmp(keyword, "q1"))
continue;
else if (!strcmp(keyword, "q2"))
continue;
else if (!strcmp(keyword, "q"))
continue;
else if (!strcmp(keyword, "n"))
continue;
else if (!strcmp(keyword, "d"))
continue;
else
goto parse_error;
BIO_puts(out, olinebuf);
if (e && Xp1 && Xp2 && Xp)
{
rsa = RSA_new();
if (!rsa)
goto error;
if (!rsa_printkey1(err, out, rsa, Xp1, Xp2, Xp, e))
goto error;
BN_free(Xp1);
Xp1 = NULL;
BN_free(Xp2);
Xp2 = NULL;
BN_free(Xp);
Xp = NULL;
BN_free(e);
e = NULL;
}
if (rsa && Xq1 && Xq2 && Xq)
{
if (!rsa_printkey2(err, out, rsa, Xq1, Xq2, Xq))
goto error;
BN_free(Xq1);
Xq1 = NULL;
BN_free(Xq2);
Xq2 = NULL;
BN_free(Xq);
Xq = NULL;
RSA_free(rsa);
rsa = NULL;
}
}
ret = 1;
error:
if (olinebuf)
OPENSSL_free(olinebuf);
if (linebuf)
OPENSSL_free(linebuf);
if (Xp1)
BN_free(Xp1);
if (Xp2)
BN_free(Xp2);
if (Xp)
BN_free(Xp);
if (Xq1)
BN_free(Xq1);
if (Xq1)
BN_free(Xq1);
if (Xq2)
BN_free(Xq2);
if (Xq)
BN_free(Xq);
if (e)
BN_free(e);
if (rsa)
RSA_free(rsa);
return ret;
parse_error:
BIO_printf(err, "FATAL parse error processing line %d\n", lnum);
goto error;
}
static int rsa_printkey1(BIO *err, BIO *out, RSA *rsa,
BIGNUM *Xp1, BIGNUM *Xp2, BIGNUM *Xp,
BIGNUM *e)
{
int ret = 0;
BIGNUM *p1 = NULL, *p2 = NULL;
p1 = BN_new();
p2 = BN_new();
if (!p1 || !p2)
goto error;
if (!RSA_X931_derive(rsa, p1, p2, NULL, NULL, 0, NULL, Xp1, Xp2, Xp,
NULL, NULL, NULL, e))
goto error;
do_bn_print(out, "p1", p1);
do_bn_print(out, "p2", p2);
do_bn_print(out, "p", rsa->p);
ret = 1;
error:
if (p1)
BN_free(p1);
if (p2)
BN_free(p2);
return ret;
}
static int rsa_printkey2(BIO *err, BIO *out, RSA *rsa,
BIGNUM *Xq1, BIGNUM *Xq2, BIGNUM *Xq)
{
int ret = 0;
BIGNUM *q1 = NULL, *q2 = NULL;
q1 = BN_new();
q2 = BN_new();
if (!q1 || !q2)
goto error;
if (!RSA_X931_derive(rsa, NULL, NULL, q1, q2, 0, NULL, NULL, NULL, NULL,
Xq1, Xq2, Xq, NULL))
goto error;
do_bn_print(out, "q1", q1);
do_bn_print(out, "q2", q2);
do_bn_print(out, "q", rsa->q);
do_bn_print(out, "n", rsa->n);
do_bn_print(out, "d", rsa->d);
ret = 1;
error:
if (q1)
BN_free(q1);
if (q2)
BN_free(q2);
return ret;
}
#endif

View file

@ -67,6 +67,7 @@ FIPS_AESTEST= fips_aesavs
FIPS_HMACTEST= fips_hmactest
FIPS_RSAVTEST= fips_rsavtest
FIPS_RSASTEST= fips_rsastest
FIPS_RSAGTEST= fips_rsagtest
TESTS= alltests
@ -77,7 +78,7 @@ EXE= $(BNTEST)$(EXE_EXT) $(ECTEST)$(EXE_EXT) $(IDEATEST)$(EXE_EXT) $(MD2TEST)$(E
$(BFTEST)$(EXE_EXT) $(CASTTEST)$(EXE_EXT) $(SSLTEST)$(EXE_EXT) $(EXPTEST)$(EXE_EXT) $(DSATEST)$(EXE_EXT) $(FIPS_DSATEST)$(EXE_EXT) $(RSATEST)$(EXE_EXT) \
$(EVPTEST)$(EXE_EXT) $(FIPS_AESTEST)$(EXE_EXT) \
$(FIPS_HMACTEST)$(EXE_EXT) $(FIPS_RSAVTEST)$(EXE_EXT) \
$(FIPS_RSASTEST)$(EXE_EXT)
$(FIPS_RSASTEST)$(EXE_EXT) $(FIPS_RSAGTEST)$(EXE_EXT)
# $(METHTEST)$(EXE_EXT)
@ -88,7 +89,7 @@ OBJ= $(BNTEST).o $(ECTEST).o $(IDEATEST).o $(MD2TEST).o $(MD4TEST).o $(MD5TEST).
$(RANDTEST).o $(FIPS_RANDTEST).o $(DHTEST).o $(ENGINETEST).o $(CASTTEST).o \
$(BFTEST).o $(SSLTEST).o $(DSATEST).o $(FIPS_DSATEST).o $(EXPTEST).o $(RSATEST).o \
$(EVPTEST).o $(FIPS_AESTEST).o $(FIPS_HMACTEST).o $(FIPS_RSAVTEST).o \
$(FIPS_RSASTEST).o
$(FIPS_RSASTEST).o $(FIPS_RSAGTEST).o
SRC= $(BNTEST).c $(ECTEST).c $(IDEATEST).c $(MD2TEST).c $(MD4TEST).c $(MD5TEST).c \
$(HMACTEST).c \
$(RC2TEST).c $(RC4TEST).c $(RC5TEST).c \
@ -96,7 +97,7 @@ SRC= $(BNTEST).c $(ECTEST).c $(IDEATEST).c $(MD2TEST).c $(MD4TEST).c $(MD5TEST)
$(RANDTEST).c $(FIPS_RANDTEST).c $(DHTEST).c $(ENGINETEST).c $(CASTTEST).c \
$(BFTEST).c $(SSLTEST).c $(DSATEST).c $(FIPS_DSATEST).c $(EXPTEST).c $(RSATEST).c \
$(EVPTEST).c $(FIPS_AESTEST).c $(FIPS_HMACTEST).c $(FIPS_RSAVTEST).c \
$(FIPS_RSASTEST).c
$(FIPS_RSASTEST).c $(FIPS_RSAGTEST).c
EXHEADER=
HEADER= $(EXHEADER)
@ -351,6 +352,12 @@ $(FIPS_RSASTEST)$(EXE_EXT): $(FIPS_RSASTEST).o $(DLIBCRYPTO)
TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a $(FIPS_RSASTEST); \
fi
$(FIPS_RSAGTEST)$(EXE_EXT): $(FIPS_RSAGTEST).o $(DLIBCRYPTO)
@target=$(FIPS_RSAGTEST); $(BUILD_CMD)
if egrep 'define OPENSSL_FIPS' $(TOP)/include/openssl/opensslconf.h > /dev/null; then \
TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a $(FIPS_RSAGTEST); \
fi
$(RSATEST)$(EXE_EXT): $(RSATEST).o $(DLIBCRYPTO)
@target=$(RSATEST); $(BUILD_CMD)