X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=fips%2Frand%2Ffips_drbg_lib.c;h=46f059d05806da31fbc69c2805ac14da100e00c8;hp=7a0a1070e2b21dd740125a1e3256a1ee4bed2ff6;hb=fdb65c836cfc0c36f0a491a8fe4255cd18a7bc3f;hpb=42bd0a6b3c73c71b69967503c0ee0a3598b52655 diff --git a/fips/rand/fips_drbg_lib.c b/fips/rand/fips_drbg_lib.c index 7a0a1070e2..46f059d058 100644 --- a/fips/rand/fips_drbg_lib.c +++ b/fips/rand/fips_drbg_lib.c @@ -71,6 +71,10 @@ int FIPS_drbg_init(DRBG_CTX *dctx, int type, unsigned int flags) dctx->flags = flags; dctx->type = type; + dctx->entropy_blocklen = 0; + dctx->health_check_cnt = 0; + dctx->health_check_interval = DRBG_HEALTH_INTERVAL; + rv = fips_drbg_hash_init(dctx); if (rv == -2) @@ -84,12 +88,23 @@ int FIPS_drbg_init(DRBG_CTX *dctx, int type, unsigned int flags) FIPSerr(FIPS_F_FIPS_DRBG_INIT, FIPS_R_ERROR_INITIALISING_DRBG); } + /* If not in test mode run selftests on DRBG of the same type */ + + if (!(dctx->flags & DRBG_FLAG_TEST)) + { + DRBG_CTX tctx; + if (!fips_drbg_kat(&tctx, type, flags | DRBG_FLAG_TEST)) + { + FIPSerr(FIPS_F_FIPS_DRBG_INIT, FIPS_R_SELFTEST_FAILURE); + return 0; + } + } + return rv; } DRBG_CTX *FIPS_drbg_new(int type, unsigned int flags) { - int rv; DRBG_CTX *dctx; dctx = OPENSSL_malloc(sizeof(DRBG_CTX)); if (!dctx) @@ -99,7 +114,6 @@ DRBG_CTX *FIPS_drbg_new(int type, unsigned int flags) } if (type == 0) return dctx; - rv = FIPS_drbg_init(dctx, type, flags); if (FIPS_drbg_init(dctx, type, flags) <= 0) { @@ -118,6 +132,46 @@ void FIPS_drbg_free(DRBG_CTX *dctx) OPENSSL_free(dctx); } +static size_t fips_get_entropy(DRBG_CTX *dctx, unsigned char **pout, + int entropy, size_t min_len, size_t max_len) + { + unsigned char *tout, *p; + size_t bl = dctx->entropy_blocklen, rv; + if (dctx->flags & DRBG_FLAG_TEST || !bl) + return dctx->get_entropy(dctx, pout, entropy, min_len, max_len); + rv = dctx->get_entropy(dctx, &tout, entropy + bl, + min_len + bl, max_len + bl); + *pout = tout + bl; + if (rv < (min_len + bl) || (rv % bl)) + return 0; + /* Compare consecutive blocks for continuous PRNG test */ + for (p = tout; p < tout + rv - bl; p += bl) + { + if (!memcmp(p, p + bl, bl)) + { + FIPSerr(FIPS_F_FIPS_GET_ENTROPY, FIPS_R_ENTROPY_SOURCE_STUCK); + return 0; + } + } + rv -= bl; + if (rv > max_len) + return max_len; + return rv; + } + +static void fips_cleanup_entropy(DRBG_CTX *dctx, + unsigned char *out, size_t olen) + { + size_t bl; + if (dctx->flags & DRBG_FLAG_TEST) + bl = 0; + else + bl = dctx->entropy_blocklen; + /* Call cleanup with original arguments */ + dctx->cleanup_entropy(dctx, out - bl, olen + bl); + } + + int FIPS_drbg_instantiate(DRBG_CTX *dctx, const unsigned char *pers, size_t perslen) { @@ -154,7 +208,7 @@ int FIPS_drbg_instantiate(DRBG_CTX *dctx, dctx->status = DRBG_STATUS_ERROR; - entlen = dctx->get_entropy(dctx, &entropy, dctx->strength, + entlen = fips_get_entropy(dctx, &entropy, dctx->strength, dctx->min_entropy, dctx->max_entropy); if (entlen < dctx->min_entropy || entlen > dctx->max_entropy) @@ -193,7 +247,7 @@ int FIPS_drbg_instantiate(DRBG_CTX *dctx, end: if (entropy && dctx->cleanup_entropy) - dctx->cleanup_entropy(dctx, entropy, entlen); + fips_cleanup_entropy(dctx, entropy, entlen); if (nonce && dctx->cleanup_nonce) dctx->cleanup_nonce(dctx, nonce, noncelen); @@ -239,7 +293,7 @@ int FIPS_drbg_reseed(DRBG_CTX *dctx, dctx->status = DRBG_STATUS_ERROR; - entlen = dctx->get_entropy(dctx, &entropy, dctx->strength, + entlen = fips_get_entropy(dctx, &entropy, dctx->strength, dctx->min_entropy, dctx->max_entropy); if (entlen < dctx->min_entropy || entlen > dctx->max_entropy) @@ -256,7 +310,7 @@ int FIPS_drbg_reseed(DRBG_CTX *dctx, end: if (entropy && dctx->cleanup_entropy) - dctx->cleanup_entropy(dctx, entropy, entlen); + fips_cleanup_entropy(dctx, entropy, entlen); if (dctx->status == DRBG_STATUS_READY) return 1; @@ -267,6 +321,24 @@ int FIPS_drbg_reseed(DRBG_CTX *dctx, return 0; } +static int fips_drbg_check(DRBG_CTX *dctx) + { + if (dctx->flags & DRBG_FLAG_TEST) + return 1; + dctx->health_check_cnt++; + if (dctx->health_check_cnt >= dctx->health_check_interval) + { + DRBG_CTX tctx; + if (!fips_drbg_kat(&tctx, dctx->type, + dctx->flags | DRBG_FLAG_TEST)) + { + FIPSerr(FIPS_F_FIPS_DRBG_CHECK, FIPS_R_SELFTEST_FAILURE); + return 0; + } + dctx->health_check_cnt = 0; + } + return 1; + } int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen, int strength, int prediction_resistance, @@ -274,6 +346,9 @@ int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen, { int r = 0; + if (!fips_drbg_check(dctx)) + return 0; + if (dctx->status != DRBG_STATUS_READY && dctx->status != DRBG_STATUS_RESEED) { @@ -349,12 +424,14 @@ int FIPS_drbg_set_callbacks(DRBG_CTX *dctx, size_t (*get_entropy)(DRBG_CTX *ctx, unsigned char **pout, int entropy, size_t min_len, size_t max_len), void (*cleanup_entropy)(DRBG_CTX *ctx, unsigned char *out, size_t olen), + size_t entropy_blocklen, size_t (*get_nonce)(DRBG_CTX *ctx, unsigned char **pout, int entropy, size_t min_len, size_t max_len), void (*cleanup_nonce)(DRBG_CTX *ctx, unsigned char *out, size_t olen)) { if (dctx->status != DRBG_STATUS_UNINITIALISED) return 0; + dctx->entropy_blocklen = entropy_blocklen; dctx->get_entropy = get_entropy; dctx->cleanup_entropy = cleanup_entropy; dctx->get_nonce = get_nonce; @@ -398,6 +475,11 @@ int FIPS_drbg_get_strength(DRBG_CTX *dctx) return dctx->strength; } +void FIPS_drbg_set_check_interval(DRBG_CTX *dctx, int interval) + { + dctx->health_check_interval = interval; + } + static int drbg_stick = 0; void FIPS_drbg_stick(void) @@ -414,7 +496,7 @@ int fips_drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out) /* Check block is valid: should never happen */ if (dctx->lb_valid == 0) { - FIPSerr(FIPS_F_DRBG_CPRNG_TEST, FIPS_R_INTERNAL_ERROR); + FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_INTERNAL_ERROR); fips_set_selftest_fail(); return 0; } @@ -423,7 +505,7 @@ int fips_drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out) /* Check against last block: fail if match */ if (!memcmp(dctx->lb, out, dctx->blocklength)) { - FIPSerr(FIPS_F_DRBG_CPRNG_TEST, FIPS_R_DRBG_STUCK); + FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_DRBG_STUCK); fips_set_selftest_fail(); return 0; }