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/21964)
This commit is contained in:
parent
54e60d2a05
commit
fffa78c2fd
@ -345,6 +345,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);
|
||||
@ -354,8 +356,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);
|
||||
}
|
||||
|
||||
@ -374,6 +374,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);
|
||||
@ -383,8 +385,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);
|
||||
}
|
||||
|
||||
@ -738,6 +738,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);
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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,39 +702,12 @@ 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
|
||||
*
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -198,6 +198,7 @@ my %params = (
|
||||
'RAND_PARAM_MAX_REQUEST' => "max_request",
|
||||
'RAND_PARAM_TEST_ENTROPY' => "test_entropy",
|
||||
'RAND_PARAM_TEST_NONCE' => "test_nonce",
|
||||
'RAND_PARAM_GENERATE' => "generate",
|
||||
|
||||
# RAND/DRBG names
|
||||
'DRBG_PARAM_RESEED_REQUESTS' => "reseed_requests",
|
||||
|
Loading…
x
Reference in New Issue
Block a user