From ded1999702eb684f2057628b261bdd951fa73bc3 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 4 Apr 2011 14:47:31 +0000 Subject: [PATCH] Change RNG test to block oriented instead of request oriented, add option to test a "stuck" DRBG. --- crypto/fips_err.h | 2 + fips/fips.h | 3 ++ fips/fips_test_suite.c | 7 +++ fips/rand/fips_drbg_ctr.c | 10 ++++ fips/rand/fips_drbg_hash.c | 10 ++++ fips/rand/fips_drbg_lib.c | 102 +++++++++++++------------------------ fips/rand/fips_drbg_rand.c | 9 +++- fips/rand/fips_rand_lcl.h | 7 ++- 8 files changed, 82 insertions(+), 68 deletions(-) diff --git a/crypto/fips_err.h b/crypto/fips_err.h index c808c88864..97a73f1dc2 100644 --- a/crypto/fips_err.h +++ b/crypto/fips_err.h @@ -71,6 +71,7 @@ static ERR_STRING_DATA FIPS_str_functs[]= { {ERR_FUNC(FIPS_F_DH_BUILTIN_GENPARAMS), "DH_BUILTIN_GENPARAMS"}, +{ERR_FUNC(FIPS_F_DRBG_CPRNG_TEST), "DRBG_CPRNG_TEST"}, {ERR_FUNC(FIPS_F_DSA_BUILTIN_PARAMGEN), "DSA_BUILTIN_PARAMGEN"}, {ERR_FUNC(FIPS_F_DSA_BUILTIN_PARAMGEN2), "DSA_BUILTIN_PARAMGEN2"}, {ERR_FUNC(FIPS_F_DSA_DO_SIGN), "DSA_do_sign"}, @@ -139,6 +140,7 @@ static ERR_STRING_DATA FIPS_str_reasons[]= {ERR_REASON(FIPS_R_GENERATE_ERROR_UNDETECTED),"generate error undetected"}, {ERR_REASON(FIPS_R_INSTANTIATE_ERROR) ,"instantiate error"}, {ERR_REASON(FIPS_R_INSUFFICIENT_SECURITY_STRENGTH),"insufficient security strength"}, +{ERR_REASON(FIPS_R_INTERNAL_ERROR) ,"internal error"}, {ERR_REASON(FIPS_R_INVALID_KEY_LENGTH) ,"invalid key length"}, {ERR_REASON(FIPS_R_IN_ERROR_STATE) ,"in error state"}, {ERR_REASON(FIPS_R_KEY_TOO_SHORT) ,"key too short"}, diff --git a/fips/fips.h b/fips/fips.h index 921591ba98..79160bbaac 100644 --- a/fips/fips.h +++ b/fips/fips.h @@ -92,6 +92,7 @@ void FIPS_corrupt_ec_keygen(void); void FIPS_corrupt_rng(void); void FIPS_corrupt_drbg(void); void FIPS_rng_stick(void); +void FIPS_drbg_stick(void); int FIPS_selftest_rng(void); int FIPS_selftest_hmac(void); int FIPS_selftest_drbg(void); @@ -188,6 +189,7 @@ void ERR_load_FIPS_strings(void); /* Function codes. */ #define FIPS_F_DH_BUILTIN_GENPARAMS 100 +#define FIPS_F_DRBG_CPRNG_TEST 141 #define FIPS_F_DSA_BUILTIN_PARAMGEN 101 #define FIPS_F_DSA_BUILTIN_PARAMGEN2 126 #define FIPS_F_DSA_DO_SIGN 102 @@ -253,6 +255,7 @@ void ERR_load_FIPS_strings(void); #define FIPS_R_GENERATE_ERROR_UNDETECTED 136 #define FIPS_R_INSTANTIATE_ERROR 125 #define FIPS_R_INSUFFICIENT_SECURITY_STRENGTH 132 +#define FIPS_R_INTERNAL_ERROR 143 #define FIPS_R_INVALID_KEY_LENGTH 109 #define FIPS_R_IN_ERROR_STATE 126 #define FIPS_R_KEY_TOO_SHORT 108 diff --git a/fips/fips_test_suite.c b/fips/fips_test_suite.c index 6addef6386..aa7fbf814f 100644 --- a/fips/fips_test_suite.c +++ b/fips/fips_test_suite.c @@ -671,6 +671,7 @@ int main(int argc,char **argv) int do_corrupt_rsa_keygen = 0, do_corrupt_dsa_keygen = 0; int bad_rsa = 0, bad_dsa = 0; int do_rng_stick = 0; + int do_drbg_stick = 0; int no_exit = 0; fips_algtest_init_nofips(); @@ -727,6 +728,10 @@ int main(int argc,char **argv) do_rng_stick = 1; no_exit = 1; printf("RNG test with stuck continuous test...\n"); + } else if (!strcmp(argv[1], "drbgstick")) { + do_drbg_stick = 1; + no_exit = 1; + printf("DRBG test with stuck continuous test...\n"); } else { printf("Bad argument \"%s\"\n", argv[1]); exit(1); @@ -756,6 +761,8 @@ int main(int argc,char **argv) FIPS_corrupt_dsa_keygen(); if (do_corrupt_rsa_keygen) FIPS_corrupt_rsa_keygen(); + if (do_drbg_stick) + FIPS_drbg_stick(); if (do_rng_stick) FIPS_rng_stick(); diff --git a/fips/rand/fips_drbg_ctr.c b/fips/rand/fips_drbg_ctr.c index 0a5270dcef..2a3c321618 100644 --- a/fips/rand/fips_drbg_ctr.c +++ b/fips/rand/fips_drbg_ctr.c @@ -330,14 +330,24 @@ static int drbg_ctr_generate(DRBG_CTX *dctx, for (;;) { inc_128(cctx); + if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid) + { + AES_encrypt(cctx->V, dctx->lb, &cctx->ks); + dctx->lb_valid = 1; + continue; + } if (outlen < 16) { /* Use K as temp space as it will be updated */ AES_encrypt(cctx->V, cctx->K, &cctx->ks); + if (!drbg_cprng_test(dctx, cctx->K)) + return 0; memcpy(out, cctx->K, outlen); break; } AES_encrypt(cctx->V, out, &cctx->ks); + if (!drbg_cprng_test(dctx, out)) + return 0; out += 16; outlen -= 16; if (outlen == 0) diff --git a/fips/rand/fips_drbg_hash.c b/fips/rand/fips_drbg_hash.c index b20d072646..8b49f33a63 100644 --- a/fips/rand/fips_drbg_hash.c +++ b/fips/rand/fips_drbg_hash.c @@ -195,13 +195,23 @@ static int hash_gen(DRBG_CTX *dctx, unsigned char *out, size_t outlen) { FIPS_digestinit(&hctx->mctx, hctx->md); FIPS_digestupdate(&hctx->mctx, hctx->vtmp, dctx->seedlen); + if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid) + { + FIPS_digestfinal(&hctx->mctx, dctx->lb, NULL); + dctx->lb_valid = 1; + continue; + } if (outlen < dctx->blocklength) { FIPS_digestfinal(&hctx->mctx, hctx->vtmp, NULL); + if (!drbg_cprng_test(dctx, hctx->vtmp)) + return 0; memcpy(out, hctx->vtmp, outlen); return 1; } FIPS_digestfinal(&hctx->mctx, out, NULL); + if (!drbg_cprng_test(dctx, out)) + return 0; outlen -= dctx->blocklength; if (outlen == 0) return 1; diff --git a/fips/rand/fips_drbg_lib.c b/fips/rand/fips_drbg_lib.c index 5564538540..920a61a97a 100644 --- a/fips/rand/fips_drbg_lib.c +++ b/fips/rand/fips_drbg_lib.c @@ -268,8 +268,7 @@ int FIPS_drbg_reseed(DRBG_CTX *dctx, } -static int fips_drbg_generate_internal(DRBG_CTX *dctx, - unsigned char *out, size_t outlen, +int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen, int strength, int prediction_resistance, const unsigned char *adin, size_t adinlen) { @@ -323,76 +322,13 @@ static int fips_drbg_generate_internal(DRBG_CTX *dctx, if (r) { if (!(dctx->flags & DRBG_FLAG_NOERR)) - FIPSerr(FIPS_F_FIPS_DRBG_GENERATE_INTERNAL, r); + FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, r); return 0; } return 1; } -/* external generate function: incorporates continuous RNG test if not - * in test mode. - */ - -int FIPS_drbg_generate(DRBG_CTX *dctx, - unsigned char *out, size_t outlen, - int strength, int prediction_resistance, - const unsigned char *adin, size_t adinlen) - { - unsigned char tmp[16], *pout; - size_t poutlen; - /* If test mode don't run continuous RNG test */ - if (dctx->flags & DRBG_FLAG_TEST) - { - return fips_drbg_generate_internal(dctx, out, outlen, - strength, - prediction_resistance, - adin, adinlen); - } - /* If this is the first call generate block and save buffer */ - if (!dctx->lb_valid) - { - if (!fips_drbg_generate_internal(dctx, dctx->lb, 16, - strength, prediction_resistance, - adin, adinlen)) - return 0; - dctx->lb_valid = 1; - } - - /* If request less that 16 bytes request 16 in temp buffer */ - - if (outlen < 16) - { - pout = tmp; - poutlen = 16; - } - else - { - pout = out; - poutlen = outlen; - } - - /* Generate data */ - if (!fips_drbg_generate_internal(dctx, pout, poutlen, - strength, prediction_resistance, - adin, adinlen)) - return 0; - /* Compare to last block for continuous PRNG test */ - if (!memcmp(pout, dctx->lb, 16)) - { - FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, FIPS_R_DRBG_STUCK); - return 0; - } - /* Update last block */ - memcpy(dctx->lb, pout, 16); - /* Copy to output buffer if needed */ - if (outlen < 16) - memcpy(out, pout, outlen); - - return 1; - - } - int FIPS_drbg_uninstantiate(DRBG_CTX *dctx) { int rv; @@ -461,3 +397,37 @@ int FIPS_drbg_get_strength(DRBG_CTX *dctx) { return dctx->strength; } + +static int drbg_stick = 0; + +void FIPS_drbg_stick(void) + { + drbg_stick = 1; + } + +/* Continuous DRBG utility function */ +int drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out) + { + /* No CPRNG in test mode */ + if (dctx->flags & DRBG_FLAG_TEST) + return 1; + /* Check block is valid: should never happen */ + if (dctx->lb_valid == 0) + { + FIPSerr(FIPS_F_DRBG_CPRNG_TEST, FIPS_R_INTERNAL_ERROR); + fips_set_selftest_fail(); + return 0; + } + if (drbg_stick) + memcpy(dctx->lb, out, dctx->blocklength); + /* Check against last block: fail if match */ + if (!memcmp(dctx->lb, out, dctx->blocklength)) + { + FIPSerr(FIPS_F_DRBG_CPRNG_TEST, FIPS_R_DRBG_STUCK); + fips_set_selftest_fail(); + return 0; + } + /* Save last block for next comparison */ + memcpy(dctx->lb, out, dctx->blocklength); + return 1; + } diff --git a/fips/rand/fips_drbg_rand.c b/fips/rand/fips_drbg_rand.c index f179bd82a9..4e02fd9408 100644 --- a/fips/rand/fips_drbg_rand.c +++ b/fips/rand/fips_drbg_rand.c @@ -117,6 +117,13 @@ static int fips_drbg_bytes(unsigned char *out, int count) return rv; } +static int fips_drbg_pseudo(unsigned char *out, int count) + { + if (fips_drbg_bytes(out, count) <= 0) + return -1; + return 1; + } + static int fips_drbg_status(void) { DRBG_CTX *dctx = &ossl_dctx; @@ -168,7 +175,7 @@ static const RAND_METHOD rand_drbg_meth = fips_drbg_bytes, fips_drbg_cleanup, fips_drbg_add, - fips_drbg_bytes, + fips_drbg_pseudo, fips_drbg_status }; diff --git a/fips/rand/fips_rand_lcl.h b/fips/rand/fips_rand_lcl.h index e3859163a3..2d63409537 100644 --- a/fips/rand/fips_rand_lcl.h +++ b/fips/rand/fips_rand_lcl.h @@ -100,6 +100,10 @@ struct drbg_ctr_ctx_st /* A default maximum length: larger than any reasonable value used in pratice */ #define DRBG_MAX_LENGTH 0x7ffffff0 +/* Maximum DRBG block length: all md sizes are bigger than cipher blocks sizes + * so use max digest length. + */ +#define DRBG_MAX_BLOCK EVP_MAX_MD_SIZE /* DRBG context structure */ @@ -163,7 +167,7 @@ struct drbg_ctx_st /* Continuous random number test temporary area */ /* Last block */ - unsigned char lb[16]; + unsigned char lb[EVP_MAX_MD_SIZE]; /* set if lb is valid */ int lb_valid; @@ -181,3 +185,4 @@ struct drbg_ctx_st int fips_drbg_ctr_init(DRBG_CTX *dctx); int fips_drbg_hash_init(DRBG_CTX *dctx); int fips_drbg_kat(DRBG_CTX *dctx, int nid, unsigned int flags); +int drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out); -- 2.25.1