diff options
author | Pauli <pauli@openssl.org> | 2023-09-05 10:16:49 +1000 |
---|---|---|
committer | Pauli <pauli@openssl.org> | 2023-10-03 18:54:03 +1100 |
commit | bc347a35d025b989abfeb8ef556f895cb1ee9381 (patch) | |
tree | bed1fe9df817b292be9d7f71de913c8eecb9f957 | |
parent | 3b804c513d8d586ba8df064ee7893c10f0a0759c (diff) |
fips selftest: avoid relying on a real RNG for self tests
Rather than instantiate the private and primary DRBGs during the
selftest, instead use a test RNG. This leaves the DRBG setup
pristine and permits later replacement of the seed source despite
the very early running power up self tests.
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22210)
-rw-r--r-- | crypto/rand/rand_lib.c | 20 | ||||
-rw-r--r-- | include/crypto/rand.h | 4 | ||||
-rw-r--r-- | include/openssl/core_names.h | 1 | ||||
-rw-r--r-- | providers/fips/self_test.c | 17 | ||||
-rw-r--r-- | providers/fips/self_test_kats.c | 136 | ||||
-rw-r--r-- | providers/implementations/rands/test_rng.c | 47 |
6 files changed, 154 insertions, 71 deletions
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index 7c1c89ab70..4d10ca8db9 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -338,6 +338,8 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, } #endif + if (num < 0) + return 0; rand = RAND_get0_private(ctx); if (rand != NULL) return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0); @@ -347,8 +349,6 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, int RAND_priv_bytes(unsigned char *buf, int num) { - if (num < 0) - return 0; return RAND_priv_bytes_ex(NULL, buf, (size_t)num, 0); } @@ -367,6 +367,8 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, } #endif + if (num < 0) + return 0; rand = RAND_get0_public(ctx); if (rand != NULL) return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0); @@ -376,8 +378,6 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, int RAND_bytes(unsigned char *buf, int num) { - if (num < 0) - return 0; return RAND_bytes_ex(NULL, buf, (size_t)num, 0); } @@ -727,6 +727,18 @@ EVP_RAND_CTX *RAND_get0_private(OSSL_LIB_CTX *ctx) return rand; } +#ifdef FIPS_MODULE +EVP_RAND_CTX *ossl_rand_get0_private_noncreating(OSSL_LIB_CTX *ctx) +{ + RAND_GLOBAL *dgbl = rand_get_global(ctx); + + if (dgbl == NULL) + return NULL; + + return CRYPTO_THREAD_get_local(&dgbl->private); +} +#endif + int RAND_set0_public(OSSL_LIB_CTX *ctx, EVP_RAND_CTX *rand) { RAND_GLOBAL *dgbl = rand_get_global(ctx); diff --git a/include/crypto/rand.h b/include/crypto/rand.h index 6a71a339c8..3b6ccecc06 100644 --- a/include/crypto/rand.h +++ b/include/crypto/rand.h @@ -125,4 +125,8 @@ void ossl_rand_cleanup_nonce(ossl_unused const OSSL_CORE_HANDLE *handle, size_t ossl_pool_acquire_entropy(RAND_POOL *pool); int ossl_pool_add_nonce_data(RAND_POOL *pool); +# ifdef FIPS_MODULE +EVP_RAND_CTX *ossl_rand_get0_private_noncreating(OSSL_LIB_CTX *ctx); +# endif + #endif diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 5e3c132f5b..0a6ec1bbba 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -248,6 +248,7 @@ extern "C" { #define OSSL_RAND_PARAM_MAX_REQUEST "max_request" #define OSSL_RAND_PARAM_TEST_ENTROPY "test_entropy" #define OSSL_RAND_PARAM_TEST_NONCE "test_nonce" +#define OSSL_RAND_PARAM_GENERATE "generate" /* RAND/DRBG names */ #define OSSL_DRBG_PARAM_RESEED_REQUESTS "reseed_requests" diff --git a/providers/fips/self_test.c b/providers/fips/self_test.c index 0be314692e..b8dc9817b2 100644 --- a/providers/fips/self_test.c +++ b/providers/fips/self_test.c @@ -19,6 +19,7 @@ #include "internal/e_os.h" #include "internal/tsan_assist.h" #include "prov/providercommon.h" +#include "crypto/rand.h" /* * We're cheating here. Normally we don't allow RUN_ONCE usage inside the FIPS @@ -406,14 +407,14 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) } /* Verify that the RNG has been restored properly */ - testrand = EVP_RAND_fetch(st->libctx, "TEST-RAND", NULL); - if (testrand == NULL - || (rng = RAND_get0_private(st->libctx)) == NULL - || strcmp(EVP_RAND_get0_name(EVP_RAND_CTX_get0_rand(rng)), - EVP_RAND_get0_name(testrand)) == 0) { - ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE); - goto end; - } + rng = ossl_rand_get0_private_noncreating(st->libctx); + if (rng != NULL) + if ((testrand = EVP_RAND_fetch(st->libctx, "TEST-RAND", NULL)) == NULL + || strcmp(EVP_RAND_get0_name(EVP_RAND_CTX_get0_rand(rng)), + EVP_RAND_get0_name(testrand)) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE); + goto end; + } ok = 1; end: diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c index 74ee25dcb6..b2060c500c 100644 --- a/providers/fips/self_test_kats.c +++ b/providers/fips/self_test_kats.c @@ -13,6 +13,7 @@ #include <openssl/core_names.h> #include <openssl/param_build.h> #include <openssl/rand.h> +#include "crypto/rand.h" #include "internal/cryptlib.h" #include "internal/nelem.h" #include "self_test.h" @@ -22,7 +23,7 @@ static int set_kat_drbg(OSSL_LIB_CTX *ctx, const unsigned char *entropy, size_t entropy_len, const unsigned char *nonce, size_t nonce_len, const unsigned char *persstr, size_t persstr_len); -static int reset_original_drbg(OSSL_LIB_CTX *ctx); +static int reset_main_drbg(OSSL_LIB_CTX *ctx); static int self_test_digest(const ST_KAT_DIGEST *t, OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) @@ -701,40 +702,13 @@ static int self_test_signatures(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) return 0; if (!self_test_sign(t, st, libctx)) ret = 0; - if (!reset_original_drbg(libctx)) + if (!reset_main_drbg(libctx)) ret = 0; } return ret; } /* - * Run the algorithm KAT's. - * Return 1 is successful, otherwise return 0. - * This runs all the tests regardless of if any fail. - */ -int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) -{ - int ret = 1; - - if (!self_test_digests(st, libctx)) - ret = 0; - if (!self_test_ciphers(st, libctx)) - ret = 0; - if (!self_test_signatures(st, libctx)) - ret = 0; - if (!self_test_kdfs(st, libctx)) - ret = 0; - if (!self_test_drbgs(st, libctx)) - ret = 0; - if (!self_test_kas(st, libctx)) - ret = 0; - if (!self_test_asym_ciphers(st, libctx)) - ret = 0; - - return ret; -} - -/* * Swap the library context DRBG for KAT testing * * In FIPS 140-3, the asymmetric POST must be a KAT, not a PCT. For DSA and ECDSA, @@ -745,13 +719,12 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) */ /* - * The default private DRBG of the library context, saved for the duration - * of KAT testing. + * Replacement "random" sources + * main_rand is used for most tests and it's set to generate mode. + * kat_rand is used for KATs where specific input is mandated. */ -static EVP_RAND_CTX *saved_rand = NULL; - -/* Replacement "random" source */ static EVP_RAND_CTX *kat_rand = NULL; +static EVP_RAND_CTX *main_rand = NULL; static int set_kat_drbg(OSSL_LIB_CTX *ctx, const unsigned char *entropy, size_t entropy_len, @@ -765,7 +738,7 @@ static int set_kat_drbg(OSSL_LIB_CTX *ctx, }; /* If not NULL, we didn't cleanup from last call: BAD */ - if (kat_rand != NULL || saved_rand != NULL) + if (kat_rand != NULL) return 0; rand = EVP_RAND_fetch(ctx, "TEST-RAND", NULL); @@ -777,7 +750,8 @@ static int set_kat_drbg(OSSL_LIB_CTX *ctx, if (parent_rand == NULL) goto err; - drbg_params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &strength); + drbg_params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, + &strength); if (!EVP_RAND_CTX_set_params(parent_rand, drbg_params)) goto err; @@ -810,37 +784,30 @@ static int set_kat_drbg(OSSL_LIB_CTX *ctx, if (!EVP_RAND_instantiate(kat_rand, strength, 0, persstr, persstr_len, NULL)) goto err; + /* When we set the new private generator this one is freed, so upref it */ + if (!EVP_RAND_CTX_up_ref(main_rand)) + goto err; + /* Update the library context DRBG */ - if ((saved_rand = RAND_get0_private(ctx)) != NULL) - /* Avoid freeing this since we replace it */ - if (!EVP_RAND_CTX_up_ref(saved_rand)) { - saved_rand = NULL; - goto err; - } if (RAND_set0_private(ctx, kat_rand) > 0) { /* Keeping a copy to verify zeroization */ if (EVP_RAND_CTX_up_ref(kat_rand)) return 1; - if (saved_rand != NULL) - RAND_set0_private(ctx, saved_rand); + RAND_set0_private(ctx, main_rand); } err: EVP_RAND_CTX_free(parent_rand); - EVP_RAND_CTX_free(saved_rand); EVP_RAND_CTX_free(kat_rand); - kat_rand = saved_rand = NULL; + kat_rand = NULL; return 0; } -static int reset_original_drbg(OSSL_LIB_CTX *ctx) { +static int reset_main_drbg(OSSL_LIB_CTX *ctx) { int ret = 1; - if (saved_rand != NULL) { - if (!RAND_set0_private(ctx, saved_rand)) - ret = 0; - saved_rand = NULL; - } + if (!RAND_set0_private(ctx, main_rand)) + ret = 0; if (kat_rand != NULL) { if (!EVP_RAND_uninstantiate(kat_rand) || !EVP_RAND_verify_zeroization(kat_rand)) @@ -851,3 +818,68 @@ static int reset_original_drbg(OSSL_LIB_CTX *ctx) { return ret; } +static int setup_main_random(OSSL_LIB_CTX *libctx) +{ + OSSL_PARAM drbg_params[3] = { + OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END + }; + unsigned int strength = 256, generate = 1; + EVP_RAND *rand; + + rand = EVP_RAND_fetch(libctx, "TEST-RAND", NULL); + if (rand == NULL) + return 0; + + main_rand = EVP_RAND_CTX_new(rand, NULL); + EVP_RAND_free(rand); + if (main_rand == NULL) + goto err; + + drbg_params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_GENERATE, + &generate); + drbg_params[1] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, + &strength); + + if (!EVP_RAND_instantiate(main_rand, strength, 0, NULL, 0, drbg_params)) + goto err; + return 1; + err: + EVP_RAND_CTX_free(main_rand); + return 0; +} + +/* + * Run the algorithm KAT's. + * Return 1 is successful, otherwise return 0. + * This runs all the tests regardless of if any fail. + */ +int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) +{ + EVP_RAND_CTX *saved_rand = ossl_rand_get0_private_noncreating(libctx); + int ret = 1; + + if (!setup_main_random(libctx) + || !RAND_set0_private(libctx, main_rand)) { + EVP_RAND_CTX_free(main_rand); + return 0; + } + + if (!self_test_digests(st, libctx)) + ret = 0; + if (!self_test_ciphers(st, libctx)) + ret = 0; + if (!self_test_signatures(st, libctx)) + ret = 0; + if (!self_test_kdfs(st, libctx)) + ret = 0; + if (!self_test_drbgs(st, libctx)) + ret = 0; + if (!self_test_kas(st, libctx)) + ret = 0; + if (!self_test_asym_ciphers(st, libctx)) + ret = 0; + + RAND_set0_private(libctx, saved_rand); + return ret; +} + diff --git a/providers/implementations/rands/test_rng.c b/providers/implementations/rands/test_rng.c index 4e7fed0fc7..5c05e34988 100644 --- a/providers/implementations/rands/test_rng.c +++ b/providers/implementations/rands/test_rng.c @@ -8,6 +8,7 @@ */ #include <string.h> +#include <stdlib.h> #include <openssl/core_dispatch.h> #include <openssl/e_os2.h> #include <openssl/params.h> @@ -39,6 +40,7 @@ static OSSL_FUNC_rand_get_seed_fn test_rng_get_seed; typedef struct { void *provctx; + unsigned int generate; int state; unsigned int strength; size_t max_request; @@ -99,16 +101,30 @@ static int test_rng_uninstantiate(void *vtest) return 1; } +static unsigned char gen_byte(PROV_TEST_RNG *t) +{ + return rand() & 0xff; +} + static int test_rng_generate(void *vtest, unsigned char *out, size_t outlen, unsigned int strength, int prediction_resistance, const unsigned char *adin, size_t adin_len) { PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + size_t i; - if (strength > t->strength || t->entropy_len - t->entropy_pos < outlen) + if (strength > t->strength) return 0; - memcpy(out, t->entropy + t->entropy_pos, outlen); - t->entropy_pos += outlen; + if (t->generate) { + for (i = 0; i < outlen; i++) + out[i] = gen_byte(t); + } else { + if (t->entropy_len - t->entropy_pos < outlen) + return 0; + + memcpy(out, t->entropy + t->entropy_pos, outlen); + t->entropy_pos += outlen; + } return 1; } @@ -123,15 +139,23 @@ static int test_rng_reseed(ossl_unused void *vtest, } static size_t test_rng_nonce(void *vtest, unsigned char *out, - unsigned int strength, - ossl_unused size_t min_noncelen, + unsigned int strength, size_t min_noncelen, ossl_unused size_t max_noncelen) { PROV_TEST_RNG *t = (PROV_TEST_RNG *)vtest; + size_t i; - if (t->nonce == NULL || strength > t->strength) + if (strength > t->strength) return 0; + if (t->generate) { + for (i = 0; i < min_noncelen; i++) + out[i] = gen_byte(t); + return min_noncelen; + } + + if (t->nonce == NULL) + return 0; if (out != NULL) memcpy(out, t->nonce, t->nonce_len); return t->nonce_len; @@ -153,6 +177,10 @@ static int test_rng_get_ctx_params(void *vtest, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); if (p != NULL && !OSSL_PARAM_set_size_t(p, t->max_request)) return 0; + + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_GENERATE); + if (p != NULL && OSSL_PARAM_set_uint(p, t->generate)) + return 0; return 1; } @@ -163,6 +191,7 @@ static const OSSL_PARAM *test_rng_gettable_ctx_params(ossl_unused void *vtest, OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL), OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_GENERATE, NULL), OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -203,9 +232,12 @@ static int test_rng_set_ctx_params(void *vtest, const OSSL_PARAM params[]) } p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_MAX_REQUEST); - if (p != NULL && !OSSL_PARAM_get_size_t(p, &t->max_request)) + if (p != NULL && !OSSL_PARAM_get_size_t(p, &t->max_request)) return 0; + p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_GENERATE); + if (p != NULL && !OSSL_PARAM_get_uint(p, &t->generate)) + return 0; return 1; } @@ -217,6 +249,7 @@ static const OSSL_PARAM *test_rng_settable_ctx_params(ossl_unused void *vtest, OSSL_PARAM_octet_string(OSSL_RAND_PARAM_TEST_NONCE, NULL, 0), OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), + OSSL_PARAM_uint(OSSL_RAND_PARAM_GENERATE, NULL), OSSL_PARAM_END }; return known_settable_ctx_params; |