From 44e9bc81eb4546aaa265ee190e782e2c92ccd502 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Sat, 7 May 2005 22:06:40 +0000 Subject: [PATCH] Add FIPS RNG tests. Submitted by: Steve Marquess --- fips/fips.c | 8 ++ fips/fips.h | 1 + fips/fips_err.h | 1 + fips/fips_test_suite.c | 13 +- fips/fipshashes.c | 9 +- fips/rand/Makefile | 20 ++- fips/rand/fips_rand.c | 10 +- fips/rand/fips_rand_selftest.c | 120 ++++++++++++++++++ fips/rand/fips_rngvs.c | 222 +++++++++++++++++++++++++++++++++ 9 files changed, 389 insertions(+), 15 deletions(-) create mode 100644 fips/rand/fips_rand_selftest.c create mode 100644 fips/rand/fips_rngvs.c diff --git a/fips/fips.c b/fips/fips.c index 8f19c0ecec..75fcfe13b2 100644 --- a/fips/fips.c +++ b/fips/fips.c @@ -239,6 +239,14 @@ int FIPS_mode_set(int onoff,const char *path) goto end; } + /* Perform RNG KAT before seeding */ + if (!FIPS_selftest_rng()) + { + fips_selftest_fail = 1; + ret = 0; + goto end; + } + /* automagically seed PRNG if not already seeded */ if(!FIPS_rand_seeded()) { diff --git a/fips/fips.h b/fips/fips.h index e8ebaf3679..451138a336 100644 --- a/fips/fips.h +++ b/fips/fips.h @@ -99,6 +99,7 @@ void ERR_load_FIPS_strings(void); #define FIPS_F_FIPS_SELFTEST_AES 104 #define FIPS_F_FIPS_SELFTEST_DES 107 #define FIPS_F_FIPS_SELFTEST_DSA 109 +#define FIPS_F_FIPS_SELFTEST_RNG 118 #define FIPS_F_FIPS_SELFTEST_RSA 108 #define FIPS_F_FIPS_SELFTEST_SHA1 103 #define FIPS_F_HASH_FINAL 100 diff --git a/fips/fips_err.h b/fips/fips_err.h index 4f79f79862..aa70f22fcb 100644 --- a/fips/fips_err.h +++ b/fips/fips_err.h @@ -82,6 +82,7 @@ static ERR_STRING_DATA FIPS_str_functs[]= {ERR_FUNC(FIPS_F_FIPS_SELFTEST_AES), "FIPS_selftest_aes"}, {ERR_FUNC(FIPS_F_FIPS_SELFTEST_DES), "FIPS_selftest_des"}, {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_SHA1), "FIPS_selftest_sha1"}, {ERR_FUNC(FIPS_F_HASH_FINAL), "HASH_FINAL"}, diff --git a/fips/fips_test_suite.c b/fips/fips_test_suite.c index 60ee8d856b..2532e51f42 100644 --- a/fips/fips_test_suite.c +++ b/fips/fips_test_suite.c @@ -228,19 +228,22 @@ int main(int argc,char **argv) /* Corrupted KAT tests */ if (!strcmp(argv[1], "aes")) { FIPS_corrupt_aes(); - printf("3. AES encryption/decryption with corrupted KAT...\n"); + printf("AES encryption/decryption with corrupted KAT...\n"); } else if (!strcmp(argv[1], "des")) { FIPS_corrupt_des(); - printf("5. DES-ECB encryption/decryption with corrupted KAT...\n"); + printf("DES-ECB encryption/decryption with corrupted KAT...\n"); } else if (!strcmp(argv[1], "dsa")) { FIPS_corrupt_dsa(); - printf("6. DSA key generation and signature validation with corrupted KAT...\n"); + printf("DSA key generation and signature validation with corrupted KAT...\n"); } else if (!strcmp(argv[1], "rsa")) { FIPS_corrupt_rsa(); - printf("4. RSA key generation and encryption/decryption with corrupted KAT...\n"); + printf("RSA key generation and encryption/decryption with corrupted KAT...\n"); } else if (!strcmp(argv[1], "sha1")) { FIPS_corrupt_sha1(); - printf("7. SHA-1 hash with corrupted KAT...\n"); + printf("SHA-1 hash with corrupted KAT...\n"); + } else if (!strcmp(argv[1], "rng")) { + FIPS_corrupt_rng(); + printf("RNG test with corrupted KAT...\n"); } else { printf("Bad argument \"%s\"\n", argv[1]); exit(1); diff --git a/fips/fipshashes.c b/fips/fipshashes.c index 9a0f075250..6090e9efa3 100644 --- a/fips/fipshashes.c +++ b/fips/fipshashes.c @@ -1,8 +1,8 @@ const char * const FIPS_source_hashes[] = { -"HMAC-SHA1(fips.c)= 2f46f538f12228814cfdc8c6b37261258686fc8c", +"HMAC-SHA1(fips.c)= 23f2470208ebbc7daeae50ad7b13e7cd7e269477", "HMAC-SHA1(fips_err_wrapper.c)= d3e2be316062510312269e98f964cb87e7577898", -"HMAC-SHA1(fips.h)= 564e34c12d6743a9be06d5da74608a71937c872a", -"HMAC-SHA1(fips_err.h)= 32ad0130f639b8f6ff417d3dfda553f5a1d7512d", +"HMAC-SHA1(fips.h)= 87423b80f7635f08fbea23897c64e999166360a2", +"HMAC-SHA1(fips_err.h)= d356c4436362dba2974f767e06c6be1c90dbfe9f", "HMAC-SHA1(aes/fips_aes_core.c)= b70bbbd675efe0613da0d57055310926a0104d55", "HMAC-SHA1(aes/asm/fips-ax86-elf.s)= 361df58c4838e55cf0b5fa1427c81c253e551388", "HMAC-SHA1(aes/fips_aes_selftest.c)= 98b01502221e7fe529fd981222f2cbb52eb4cbe0", @@ -18,8 +18,9 @@ const char * const FIPS_source_hashes[] = { "HMAC-SHA1(dsa/fips_dsa_ossl.c)= 8bb943c0fd1adf04f6a845f4d1727c5472697e93", "HMAC-SHA1(dsa/fips_dsa_gen.c)= 78c879484fd849312ca4828b957df3842b70efc0", "HMAC-SHA1(dsa/fips_dsa_selftest.c)= 7c2ba8d82feda2aadc8b769a3b6c4c25a6356e01", -"HMAC-SHA1(rand/fips_rand.c)= 29139e29f56f3ecd99f527af8742d5afb12f409a", +"HMAC-SHA1(rand/fips_rand.c)= 7e3964447a81cfe4e75df981827d14a5fe0c2923", "HMAC-SHA1(rand/fips_rand.h)= bf009ea8963e79b1e414442ede9ae7010a03160b", +"HMAC-SHA1(rand/fips_rand_selftest.c)= d9c8985e08feecefafe667ad0119d444b42f807c", "HMAC-SHA1(rsa/fips_rsa_eay.c)= 2596773a7af8f037427217b79f56858296961d66", "HMAC-SHA1(rsa/fips_rsa_gen.c)= 713d2e0d7a1a682b1794f1224b7afe01272ba755", "HMAC-SHA1(rsa/fips_rsa_selftest.c)= dcd0970a4de2d7f0d2333d6a3efb1ae350209b57", diff --git a/fips/rand/Makefile b/fips/rand/Makefile index e11a5b3154..71780b2147 100644 --- a/fips/rand/Makefile +++ b/fips/rand/Makefile @@ -22,8 +22,8 @@ TEST= fips_randtest.c APPS= LIB=$(TOP)/libcrypto.a -LIBSRC=fips_rand.c -LIBOBJ=fips_rand.o +LIBSRC=fips_rand.c fips_rand_selftest.c +LIBOBJ=fips_rand.o fips_rand_selftest.o SRC= $(LIBSRC) @@ -62,6 +62,22 @@ tags: tests: +top_fips_rngvs: + (cd $(TOP); $(MAKE) DIRS=fips FDIRS=$(DIR) TARGET=fips_rngvs sub_target) + +fips_rngvs: fips_rngvs.o $(TOP)/libcrypto.a + $(CC) $(CFLAGS) -o fips_rngvs fips_rngvs.o $(PEX_LIBS) $(TOP)/libcrypto.a $(EX_LIBS) + TOP=$(TOP) $(TOP)/fips/openssl_fips_fingerprint $(TOP)/libcrypto.a fips_rngvs + +Q=../testvectors/rng/req +A=../testvectors/rng/rsp + +fips_test: top_fips_rngvs + -rm -rf $A + mkdir $A + ./fips_rngvs mct < $Q/MCT.req > $A/MCT.rsp + ./fips_rngvs vst < $Q/VST.req > $A/VST.rsp + lint: lint -DLINT $(INCLUDES) $(SRC)>fluff diff --git a/fips/rand/fips_rand.c b/fips/rand/fips_rand.c index 45cf1c5706..7df2dc804e 100644 --- a/fips/rand/fips_rand.c +++ b/fips/rand/fips_rand.c @@ -90,6 +90,7 @@ static DES_cblock key1; static DES_cblock key2; static DES_key_schedule ks1,ks2; static int key_set; +static int key_init; static int test_mode; static unsigned char test_faketime[8]; @@ -153,7 +154,7 @@ static void fips_gettime(unsigned char buf[8]) if(test_mode) { - fprintf(OPENSSL_stderr(),"WARNING!!! PRNG IN TEST MODE!!!\n"); + /* fprintf(OPENSSL_stderr(),"WARNING!!! PRNG IN TEST MODE!!!\n"); */ memcpy(buf,test_faketime,sizeof test_faketime); return; } @@ -202,22 +203,23 @@ static void fips_rand_cleanup(void) { OPENSSL_cleanse(seed,sizeof seed); n_seed=0; + o_seed=0; + key_init=0; } void FIPS_rand_seed(const void *buf_, FIPS_RAND_SIZE_T num) { const char *buf=buf_; FIPS_RAND_SIZE_T n; - static int init; /* If the key hasn't been set, we can't seed! */ if(!key_set) return; CRYPTO_w_lock(CRYPTO_LOCK_RAND); - if(!init) + if(!key_init) { - init=1; + key_init=1; DES_set_key(&key1,&ks1); DES_set_key(&key2,&ks2); } diff --git a/fips/rand/fips_rand_selftest.c b/fips/rand/fips_rand_selftest.c new file mode 100644 index 0000000000..36346774d8 --- /dev/null +++ b/fips/rand/fips_rand_selftest.c @@ -0,0 +1,120 @@ +/* ==================================================================== + * Copyright (c) 2003 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 + * openssl-core@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. + * + */ + +#include +#include +#include +#include +#include + +#ifdef OPENSSL_FIPS +static struct + { + unsigned char key1[8]; + unsigned char key2[8]; + unsigned char seed[8]; + unsigned char dt[8]; + } init_iv[] = + { + { + { 0x75, 0xc7, 0x1a, 0xe5, 0xa1, 0x1a, 0x23, 0x2c }, + { 0x40, 0x25, 0x6d, 0xcd, 0x94, 0xf7, 0x67, 0xb0 }, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xc8, 0x9a, 0x1d, 0x88, 0x8e, 0xd1, 0x2f, 0x3c }, + }, + { + { 0x75, 0xc7, 0x1a, 0xe5, 0xa1, 0x1a, 0x23, 0x2c }, + { 0x40, 0x25, 0x6d, 0xcd, 0x94, 0xf7, 0x67, 0xb0 }, + { 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xc8, 0x9a, 0x1d, 0x88, 0x8e, 0xd1, 0x2f, 0x40 }, + }, + { + { 0x75, 0xc7, 0x1a, 0xe5, 0xa1, 0x1a, 0x23, 0x2c }, + { 0x40, 0x25, 0x6d, 0xcd, 0x94, 0xf7, 0x67, 0xb0 }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xc8, 0x9a, 0x1d, 0x88, 0x8e, 0xd1, 0x2f, 0x7b }, + }, + }; + +static const unsigned char expected_ret[][8]= + { + { 0x94, 0x4d, 0xc7, 0x21, 0x0d, 0x6d, 0x7f, 0xd7 }, + { 0x02, 0x43, 0x3c, 0x94, 0x17, 0xa3, 0x32, 0x6f }, + { 0xe7, 0xe2, 0xb2, 0x96, 0x4f, 0x36, 0xed, 0x41 }, + }; + +void FIPS_corrupt_rng() + { + init_iv[0].dt[0]++; + } + +int FIPS_selftest_rng() + { + int n; + + for(n=0 ; n < 3 ; ++n) + { + unsigned char actual_ret[8]; + + FIPS_rand_method()->cleanup(); + FIPS_set_prng_key(init_iv[n].key1,init_iv[n].key2); + FIPS_rand_seed(init_iv[n].seed,8); + FIPS_test_mode(1,init_iv[n].dt); + if ((FIPS_rand_method()->bytes(actual_ret, 8) <=0) || (memcmp(actual_ret,expected_ret[n],sizeof actual_ret))) + { + FIPS_test_mode(0,NULL); + FIPSerr(FIPS_F_FIPS_SELFTEST_RNG,FIPS_R_SELFTEST_FAILED); + return 0; + } + } + FIPS_test_mode(0,NULL); + return 1; + } + +#endif diff --git a/fips/rand/fips_rngvs.c b/fips/rand/fips_rngvs.c new file mode 100644 index 0000000000..e616664552 --- /dev/null +++ b/fips/rand/fips_rngvs.c @@ -0,0 +1,222 @@ +/* + * Crude test driver for processing the VST and MCT testvector files generated by the CMVP + * RNGVS product. + * + * Note the input files are assumed to have a _very_ specific format as described in the + * NIST document "The Random Number Generator Validation System (RNGVS)", May 25, 2004. + * +*/ + +#include +#include +#include +#include +#include +#include +#include + +int hex2bin(const char *in, unsigned char *out) + { + int n1, n2; + unsigned char ch; + + for (n1=0,n2=0 ; in[n1] && in[n1] != '\n' ; ) + { /* first byte */ + if ((in[n1] >= '0') && (in[n1] <= '9')) + ch = in[n1++] - '0'; + else if ((in[n1] >= 'A') && (in[n1] <= 'F')) + ch = in[n1++] - 'A' + 10; + else if ((in[n1] >= 'a') && (in[n1] <= 'f')) + ch = in[n1++] - 'a' + 10; + else + return -1; + if(!in[n1]) + { + out[n2++]=ch; + break; + } + out[n2] = ch << 4; + /* second byte */ + if ((in[n1] >= '0') && (in[n1] <= '9')) + ch = in[n1++] - '0'; + else if ((in[n1] >= 'A') && (in[n1] <= 'F')) + ch = in[n1++] - 'A' + 10; + else if ((in[n1] >= 'a') && (in[n1] <= 'f')) + ch = in[n1++] - 'a' + 10; + else + return -1; + out[n2++] |= ch; + } + return n2; + } + +int bin2hex(const unsigned char *in,int len,char *out) + { + int n1, n2; + unsigned char ch; + + for (n1=0,n2=0 ; n1 < len ; ++n1) + { + ch=in[n1] >> 4; + if (ch <= 0x09) + out[n2++]=ch+'0'; + else + out[n2++]=ch-10+'a'; + ch=in[n1] & 0x0f; + if(ch <= 0x09) + out[n2++]=ch+'0'; + else + out[n2++]=ch-10+'a'; + } + out[n2]='\0'; + return n2; + } + +void pv(const char *tag,const unsigned char *val,int len) + { + char obuf[2048]; + + bin2hex(val,len,obuf); + printf("%s = %s\n",tag,obuf); + } + +void vst() + { + unsigned char key1[8]; + unsigned char key2[8]; + unsigned char v[8]; + unsigned char dt[8]; + unsigned char ret[8]; + char buf[1024]; + int n; + + while(fgets(buf,sizeof buf,stdin) != NULL) + { + if(!strncmp(buf,"Key1 = ",7)) + { + n=hex2bin(buf+7,key1); + pv("Key1",key1,n); + } + else if(!strncmp(buf,"Key2 = ",7)) + { + n=hex2bin(buf+7,key2); + pv("Key1",key2,n); + } + else if(!strncmp(buf,"DT = ",5)) + { + n=hex2bin(buf+5,dt); + pv("DT",dt,n); + } + else if(!strncmp(buf,"V = ",4)) + { + n=hex2bin(buf+4,v); + pv("V",v,n); + + FIPS_rand_method()->cleanup(); + FIPS_set_prng_key(key1,key2); + FIPS_rand_seed(v,8); + FIPS_test_mode(1,dt); + if (FIPS_rand_method()->bytes(ret,8) <= 0) + { + FIPS_test_mode(0,NULL); + FIPSerr(FIPS_F_FIPS_SELFTEST_RNG,FIPS_R_SELFTEST_FAILED); + return; + } + + pv("R",ret,8); + putc('\n',stdout); + } + else + fputs(buf,stdout); + } + } + + +void mct() + { + unsigned char key1[8]; + unsigned char key2[8]; + unsigned char v[8]; + unsigned char dt[8]; + unsigned char ret[8]; + char buf[1024]; + int n; + + BIGNUM *bn; + BIGNUM *pbn; + bn = BN_new(); + + while(fgets(buf,sizeof buf,stdin) != NULL) + { + if(!strncmp(buf,"Key1 = ",7)) + { + n=hex2bin(buf+7,key1); + pv("Key1",key1,n); + } + else if(!strncmp(buf,"Key2 = ",7)) + { + n=hex2bin(buf+7,key2); + pv("Key1",key2,n); + } + else if(!strncmp(buf,"DT = ",5)) + { + n=hex2bin(buf+5,dt); + pv("DT",dt,n); + } + else if(!strncmp(buf,"V = ",4)) + { + int iter; + n=hex2bin(buf+4,v); + pv("V",v,n); + + FIPS_rand_method()->cleanup(); + FIPS_set_prng_key(key1,key2); + FIPS_rand_seed(v,8); + for (iter=0; iter < 10000; ++iter) + { + FIPS_test_mode(1,dt); + if (FIPS_rand_method()->bytes(ret,8) <= 0) + { + FIPS_test_mode(0,NULL); + FIPSerr(FIPS_F_FIPS_SELFTEST_RNG,FIPS_R_SELFTEST_FAILED); + return; + } + pbn = BN_bin2bn(dt,8,bn); + n = BN_add(bn,bn,BN_value_one()); + n = BN_bn2bin(bn,dt); + } + + pv("R",ret,8); + putc('\n',stdout); + } + else + fputs(buf,stdout); + } + BN_free(bn); + } + +int main(int argc,char **argv) + { + if(argc != 2) + { + fprintf(stderr,"%s [mct|vst]\n",argv[0]); + exit(1); + } + if(!FIPS_mode_set(1,argv[0])) + { + ERR_load_crypto_strings(); + ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE)); + exit(1); + } + if(!strcmp(argv[1],"mct")) + mct(); + else if(!strcmp(argv[1],"vst")) + vst(); + else + { + fprintf(stderr,"Don't know how to %s.\n",argv[1]); + exit(1); + } + + return 0; + } -- 2.25.1