Path: blob/main/crypto/openssl/providers/implementations/rands/fips_crng_test.c
48383 views
/*1* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* Implementation of SP 800-90B section 4.4 Approved Continuous Health Tests.11*/1213#include <string.h>14#include <openssl/evp.h>15#include <openssl/core_dispatch.h>16#include <openssl/params.h>17#include <openssl/self_test.h>18#include <openssl/proverr.h>19#include "prov/providercommon.h"20#include "prov/provider_ctx.h"21#include "prov/implementations.h"22#include "internal/cryptlib.h"23#include "crypto/rand_pool.h"24#include "drbg_local.h"25#include "prov/seeding.h"26#include "crypto/context.h"2728static OSSL_FUNC_rand_newctx_fn crng_test_new;29static OSSL_FUNC_rand_freectx_fn crng_test_free;30static OSSL_FUNC_rand_instantiate_fn crng_test_instantiate;31static OSSL_FUNC_rand_uninstantiate_fn crng_test_uninstantiate;32static OSSL_FUNC_rand_generate_fn crng_test_generate;33static OSSL_FUNC_rand_reseed_fn crng_test_reseed;34static OSSL_FUNC_rand_gettable_ctx_params_fn crng_test_gettable_ctx_params;35static OSSL_FUNC_rand_get_ctx_params_fn crng_test_get_ctx_params;36static OSSL_FUNC_rand_verify_zeroization_fn crng_test_verify_zeroization;37static OSSL_FUNC_rand_enable_locking_fn crng_test_enable_locking;38static OSSL_FUNC_rand_lock_fn crng_test_lock;39static OSSL_FUNC_rand_unlock_fn crng_test_unlock;40static OSSL_FUNC_rand_get_seed_fn crng_test_get_seed;41static OSSL_FUNC_rand_clear_seed_fn crng_test_clear_seed;4243#ifndef ENTROPY_H44# define ENTROPY_H 6 /* default to six bits per byte of entropy */45#endif46#ifndef ENTROPY_APT_W47# define ENTROPY_APT_W 51248#endif4950typedef struct crng_testal_st {51void *provctx;52CRYPTO_RWLOCK *lock;53int state;5455/* State for SP 800-90B 4.4.1 Repetition Count Test */56struct {57unsigned int b;58uint8_t a;59} rct;6061/* State for SP 800-90B 4.4.2 Adaptive Proportion Test */62struct {63unsigned int b;64unsigned int i;65uint8_t a;66} apt;6768/* Parent PROV_RAND and its dispatch table functions */69void *parent;70OSSL_FUNC_rand_enable_locking_fn *parent_enable_locking;71OSSL_FUNC_rand_lock_fn *parent_lock;72OSSL_FUNC_rand_unlock_fn *parent_unlock;73OSSL_FUNC_rand_get_ctx_params_fn *parent_get_ctx_params;74OSSL_FUNC_rand_gettable_ctx_params_fn *parent_gettable_ctx_params;75OSSL_FUNC_rand_get_seed_fn *parent_get_seed;76OSSL_FUNC_rand_clear_seed_fn *parent_clear_seed;77} CRNG_TEST;7879/*80* Some helper functions81*/82static int lock_parent(CRNG_TEST *crngt)83{84void *parent = crngt->parent;8586if (parent != NULL87&& crngt->parent_lock != NULL88&& !crngt->parent_lock(parent)) {89ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED);90return 0;91}92return 1;93}9495static void unlock_parent(CRNG_TEST *crngt)96{97void *parent = crngt->parent;9899if (parent != NULL && crngt->parent_unlock != NULL)100crngt->parent_unlock(parent);101}102103/*104* Implementation of SP 800-90B section 4.4.1: Repetition Count Test105*/106static int RCT_test(CRNG_TEST *crngt, uint8_t next)107{108/*109* Critical values for this test are computed using:110*111* C = 1 + \left\lceil\frac{-log_2 \alpha}H\right\rceil112*113* where alpha = 2^-20 and H is the expected entropy per sample.114*/115static const unsigned int rct_c[9] = {11641, /* H = 0.5 */11721, 11, 8, 6, 5, 5, 4, 4 /* H = 1, ..., 8 */118};119120if (ossl_likely(crngt->rct.b != 0)121&& ossl_unlikely(next == crngt->rct.a))122return ossl_likely(++crngt->rct.b < rct_c[ENTROPY_H]);123crngt->rct.a = next;124crngt->rct.b = 1;125return 1;126}127128/*129* Implementation of SP 800-90B section 4.4.2: Adaptive Proportion Test130*/131static int APT_test(CRNG_TEST *crngt, uint8_t next)132{133/*134* Critical values for this test are drawn from a binomial135* distribution with n = 512, p = 2^-H at a critical threshold of136* 2^-20. H being the expected entropy per sample. Refer SP 800-90B137* section 4.4.2, table 2.138*/139static const unsigned int apt_c[9] = {140410, /* H = 0.5 */141311, 177, 103, 62, 39, 25, 18, 13 /* H = 1, ..., 8 */142};143144if (ossl_likely(crngt->apt.b != 0)) {145if (ossl_unlikely(crngt->apt.a == next)146&& ossl_unlikely(++crngt->apt.b >= apt_c[ENTROPY_H])) {147crngt->apt.b = 0;148return 0;149}150if (ossl_unlikely(++crngt->apt.i >= ENTROPY_APT_W))151crngt->apt.b = 0;152return 1;153}154crngt->apt.a = next;155crngt->apt.b = 1;156crngt->apt.i = 1;157return 1;158}159160static int crng_test(CRNG_TEST *crngt, const unsigned char *buf, size_t n)161{162size_t i;163164for (i = 0; i < n; i++)165if (!RCT_test(crngt, buf[i]) || !APT_test(crngt, buf[i])) {166crngt->state = EVP_RAND_STATE_ERROR;167ERR_raise(ERR_LIB_PROV,168PROV_R_ENTROPY_SOURCE_FAILED_CONTINUOUS_TESTS);169return 0;170}171return 1;172}173174static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch,175int function)176{177if (dispatch != NULL)178while (dispatch->function_id != 0) {179if (dispatch->function_id == function)180return dispatch;181dispatch++;182}183return NULL;184}185186static void *crng_test_new(void *provctx, void *parent,187const OSSL_DISPATCH *p_dispatch)188{189CRNG_TEST *crngt = OPENSSL_zalloc(sizeof(*crngt));190const OSSL_DISPATCH *pfunc;191192if (crngt == NULL)193return NULL;194195crngt->provctx = provctx;196crngt->state = EVP_RAND_STATE_UNINITIALISED;197198/* Extract parent's functions */199if (parent != NULL) {200crngt->parent = parent;201if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING)) != NULL)202crngt->parent_enable_locking = OSSL_FUNC_rand_enable_locking(pfunc);203if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_LOCK)) != NULL)204crngt->parent_lock = OSSL_FUNC_rand_lock(pfunc);205if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_UNLOCK)) != NULL)206crngt->parent_unlock = OSSL_FUNC_rand_unlock(pfunc);207if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS)) != NULL)208crngt->parent_gettable_ctx_params = OSSL_FUNC_rand_gettable_ctx_params(pfunc);209if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS)) != NULL)210crngt->parent_get_ctx_params = OSSL_FUNC_rand_get_ctx_params(pfunc);211if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_SEED)) != NULL)212crngt->parent_get_seed = OSSL_FUNC_rand_get_seed(pfunc);213if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_CLEAR_SEED)) != NULL)214crngt->parent_clear_seed = OSSL_FUNC_rand_clear_seed(pfunc);215}216217return crngt;218}219220static void crng_test_free(void *vcrngt)221{222CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;223224if (crngt != NULL) {225CRYPTO_THREAD_lock_free(crngt->lock);226OPENSSL_free(crngt);227}228}229230static int crng_test_instantiate(void *vcrngt, unsigned int strength,231int prediction_resistance,232const unsigned char *pstr,233size_t pstr_len,234ossl_unused const OSSL_PARAM params[])235{236CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;237238/* Start up health tests should go here */239crngt->state = EVP_RAND_STATE_READY;240return 1;241}242243static int crng_test_uninstantiate(void *vcrngt)244{245CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;246247crngt->state = EVP_RAND_STATE_UNINITIALISED;248return 1;249}250251static int crng_test_generate(void *vcrngt, unsigned char *out, size_t outlen,252unsigned int strength, int prediction_resistance,253const unsigned char *adin, size_t adin_len)254{255unsigned char *p;256CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;257258if (!crng_test_get_seed(crngt, &p, 0, outlen, outlen, prediction_resistance,259adin, adin_len))260return 0;261memcpy(out, p, outlen);262crng_test_clear_seed(crngt, p, outlen);263return 1;264}265266static int crng_test_reseed(ossl_unused void *vcrngt,267ossl_unused int prediction_resistance,268ossl_unused const unsigned char *ent,269ossl_unused size_t ent_len,270ossl_unused const unsigned char *adin,271ossl_unused size_t adin_len)272{273return 1;274}275276static int crng_test_verify_zeroization(ossl_unused void *vcrngt)277{278return 1;279}280281static size_t crng_test_get_seed(void *vcrngt, unsigned char **pout,282int entropy, size_t min_len,283size_t max_len,284int prediction_resistance,285const unsigned char *adin,286size_t adin_len)287{288CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;289size_t n;290int r = 0;291292/* Without a parent, we rely on the up calls */293if (crngt->parent == NULL294|| crngt->parent_get_seed == NULL) {295n = ossl_prov_get_entropy(crngt->provctx, pout, entropy,296min_len, max_len);297if (n == 0)298return 0;299r = crng_test(crngt, *pout, n);300return r > 0 ? n : 0;301}302303/* Grab seed from our parent */304if (!lock_parent(crngt))305return 0;306307n = crngt->parent_get_seed(crngt->parent, pout, entropy,308min_len, max_len, prediction_resistance,309adin, adin_len);310if (n > 0 && crng_test(crngt, *pout, n) > 0)311r = n;312else if (crngt->parent_clear_seed != NULL)313crngt->parent_clear_seed(crngt->parent, *pout, n);314unlock_parent(crngt);315return r;316}317318static void crng_test_clear_seed(void *vcrngt,319unsigned char *out, size_t outlen)320{321CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;322323if (crngt->parent == NULL || crngt->parent_get_seed == NULL)324ossl_prov_cleanup_entropy(crngt->provctx, out, outlen);325else if (crngt->parent_clear_seed != NULL)326crngt->parent_clear_seed(crngt->parent, out, outlen);327}328329static int crng_test_enable_locking(void *vcrngt)330{331CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;332333if (crngt != NULL && crngt->lock == NULL) {334if (crngt->parent_enable_locking != NULL)335if (!crngt->parent_enable_locking(crngt->parent)) {336ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED);337return 0;338}339crngt->lock = CRYPTO_THREAD_lock_new();340if (crngt->lock == NULL) {341ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK);342return 0;343}344}345return 1;346}347348static int crng_test_lock(ossl_unused void *vcrngt)349{350CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;351352return crngt->lock == NULL || CRYPTO_THREAD_write_lock(crngt->lock);353}354355static void crng_test_unlock(ossl_unused void *vcrngt)356{357CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;358359if (crngt->lock != NULL)360CRYPTO_THREAD_unlock(crngt->lock);361}362363static int crng_test_get_ctx_params(void *vcrngt, OSSL_PARAM params[])364{365CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;366OSSL_PARAM *p;367368if (crngt->parent != NULL && crngt->parent_get_ctx_params != NULL)369return crngt->parent_get_ctx_params(crngt->parent, params);370371/* No parent means we are using call backs for entropy */372p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE);373if (p != NULL && !OSSL_PARAM_set_int(p, crngt->state))374return 0;375376p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH);377if (p != NULL && !OSSL_PARAM_set_int(p, 1024))378return 0;379380p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);381if (p != NULL && !OSSL_PARAM_set_size_t(p, 128))382return 0;383384p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_FIPS_APPROVED_INDICATOR);385if (p != NULL && !OSSL_PARAM_set_int(p, 0))386return 0;387return 1;388}389390static const OSSL_PARAM *crng_test_gettable_ctx_params(void *vcrngt,391void *provctx)392{393CRNG_TEST *crngt = (CRNG_TEST *)vcrngt;394static const OSSL_PARAM known_gettable_ctx_params[] = {395OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL),396OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL),397OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL),398OSSL_PARAM_int(OSSL_RAND_PARAM_FIPS_APPROVED_INDICATOR, NULL),399OSSL_PARAM_END400};401402if (crngt->parent != NULL && crngt->parent_gettable_ctx_params != NULL)403return crngt->parent_gettable_ctx_params(crngt->parent, provctx);404return known_gettable_ctx_params;405}406407const OSSL_DISPATCH ossl_crng_test_functions[] = {408{ OSSL_FUNC_RAND_NEWCTX, (void(*)(void))crng_test_new },409{ OSSL_FUNC_RAND_FREECTX, (void(*)(void))crng_test_free },410{ OSSL_FUNC_RAND_INSTANTIATE,411(void(*)(void))crng_test_instantiate },412{ OSSL_FUNC_RAND_UNINSTANTIATE,413(void(*)(void))crng_test_uninstantiate },414{ OSSL_FUNC_RAND_GENERATE, (void(*)(void))crng_test_generate },415{ OSSL_FUNC_RAND_RESEED, (void(*)(void))crng_test_reseed },416{ OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))crng_test_enable_locking },417{ OSSL_FUNC_RAND_LOCK, (void(*)(void))crng_test_lock },418{ OSSL_FUNC_RAND_UNLOCK, (void(*)(void))crng_test_unlock },419{ OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,420(void(*)(void))crng_test_gettable_ctx_params },421{ OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))crng_test_get_ctx_params },422{ OSSL_FUNC_RAND_VERIFY_ZEROIZATION,423(void(*)(void))crng_test_verify_zeroization },424{ OSSL_FUNC_RAND_GET_SEED, (void(*)(void))crng_test_get_seed },425{ OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))crng_test_clear_seed },426OSSL_DISPATCH_END427};428429430