From f000e82898af251442ca52e81fc1ee45996090dc Mon Sep 17 00:00:00 2001 From: Pauli Date: Fri, 8 May 2020 10:25:19 +1000 Subject: [PATCH] CTR, HASH and HMAC DRBGs in provider Move the three different DRBGs to the provider. As part of the move, the DRBG specific data was pulled out of a common structure and into their own structures. Only these smaller structures are securely allocated. This saves quite a bit of secure memory: +-------------------------------+ | DRBG | Bytes | Secure | +--------------+-------+--------+ | HASH | 376 | 512 | | HMAC | 168 | 256 | | CTR | 176 | 256 | | Common (new) | 320 | 0 | | Common (old) | 592 | 1024 | +--------------+-------+--------+ Bytes is the structure size on the X86/64. Secure is the number of bytes of secure memory used (power of two allocator). Reviewed-by: Matthias St. Pierre (Merged from https://github.com/openssl/openssl/pull/11682) --- crypto/evp/build.info | 2 +- crypto/evp/evp_local.h | 18 +- crypto/evp/{rand_meth.c => evp_rand.c} | 197 ++-- crypto/rand/build.info | 12 +- crypto/rand/drbg_lib.c | 1056 +++++------------- crypto/rand/rand_lib.c | 309 +---- crypto/rand/rand_local.h | 72 +- doc/man3/RAND_DRBG_new.pod | 35 +- doc/man3/RAND_DRBG_set_callbacks.pod | 11 +- include/openssl/core_names.h | 44 +- include/openssl/core_numbers.h | 13 +- include/openssl/evp.h | 46 +- include/openssl/rand.h | 1 - include/openssl/rand_drbg.h | 6 +- providers/defltprov.c | 7 +- providers/fips/fipsprov.c | 11 +- providers/implementations/rands/build.info | 8 +- providers/implementations/rands/crngt.c | 2 +- providers/implementations/rands/drbg.c | 720 +++++++----- providers/implementations/rands/drbg_ctr.c | 470 ++++++-- providers/implementations/rands/drbg_hash.c | 302 +++-- providers/implementations/rands/drbg_hmac.c | 319 ++++-- providers/implementations/rands/drbg_local.h | 196 ++-- providers/implementations/rands/test_rng.c | 30 +- 24 files changed, 1930 insertions(+), 1957 deletions(-) rename crypto/evp/{rand_meth.c => evp_rand.c} (69%) diff --git a/crypto/evp/build.info b/crypto/evp/build.info index edef4930cb..ccd8357453 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -2,7 +2,7 @@ LIBS=../../libcrypto $COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c evp_utils.c \ mac_lib.c mac_meth.c keymgmt_meth.c keymgmt_lib.c kdf_lib.c kdf_meth.c \ m_sigver.c pmeth_lib.c signature.c p_lib.c pmeth_gn.c exchange.c \ - pmeth_check.c rand_meth.c + pmeth_check.c evp_rand.c SOURCE[../../libcrypto]=$COMMON\ encode.c evp_key.c evp_cnf.c \ diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index 03a1f36e1b..132534464f 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -69,16 +69,18 @@ struct evp_kdf_ctx_st { struct evp_rand_ctx_st { EVP_RAND *meth; /* Method structure */ void *data; /* Algorithm-specific data */ - EVP_RAND_CTX *parent; /* Parent seed source */ - size_t max_request; /* Cached: maximum number of bytes generated */ - unsigned int strength; /* Cache: bit strenght of generator */ + size_t max_request; /* + * Cached: maximum number of bytes generated + * in a single call to the generate function + */ + unsigned int strength; /* Cached: bit strength of generator */ } /* EVP_RAND_CTX */ ; struct evp_rand_st { OSSL_PROVIDER *prov; int name_id; CRYPTO_REF_COUNT refcnt; - CRYPTO_RWLOCK *lock; + CRYPTO_RWLOCK *refcnt_lock; const OSSL_DISPATCH *dispatch; OSSL_OP_rand_newctx_fn *newctx; @@ -88,16 +90,16 @@ struct evp_rand_st { OSSL_OP_rand_generate_fn *generate; OSSL_OP_rand_reseed_fn *reseed; OSSL_OP_rand_nonce_fn *nonce; - OSSL_OP_rand_set_callbacks_fn *set_callbacks; - OSSL_OP_rand_enable_locking_fn *enable_prov_locking; - OSSL_OP_rand_lock_fn *prov_lock; - OSSL_OP_rand_unlock_fn *prov_unlock; + OSSL_OP_rand_enable_locking_fn *enable_locking; + OSSL_OP_rand_lock_fn *lock; + OSSL_OP_rand_unlock_fn *unlock; OSSL_OP_rand_gettable_params_fn *gettable_params; OSSL_OP_rand_gettable_ctx_params_fn *gettable_ctx_params; OSSL_OP_rand_settable_ctx_params_fn *settable_ctx_params; OSSL_OP_rand_get_params_fn *get_params; OSSL_OP_rand_get_ctx_params_fn *get_ctx_params; OSSL_OP_rand_set_ctx_params_fn *set_ctx_params; + OSSL_OP_rand_set_callbacks_fn *set_callbacks; OSSL_OP_rand_verify_zeroization_fn *verify_zeroization; } /* EVP_RAND */ ; diff --git a/crypto/evp/rand_meth.c b/crypto/evp/evp_rand.c similarity index 69% rename from crypto/evp/rand_meth.c rename to crypto/evp/evp_rand.c index 0f1745411d..f7bc321f29 100644 --- a/crypto/evp/rand_meth.c +++ b/crypto/evp/evp_rand.c @@ -11,7 +11,6 @@ #include #include -#include "internal/cryptlib.h" #include #include #include @@ -21,6 +20,7 @@ #include #include "crypto/asn1.h" #include "crypto/evp.h" +#include "internal/cryptlib.h" #include "internal/numbers.h" #include "internal/provider.h" #include "evp_local.h" @@ -31,7 +31,7 @@ static int evp_rand_up_ref(void *vrand) int ref = 0; if (rand != NULL) - return CRYPTO_UP_REF(&rand->refcnt, &ref, rand->lock); + return CRYPTO_UP_REF(&rand->refcnt, &ref, rand->refcnt_lock); return 1; } @@ -40,10 +40,10 @@ static void evp_rand_free(void *vrand){ int ref = 0; if (rand != NULL) { - CRYPTO_DOWN_REF(&rand->refcnt, &ref, rand->lock); + CRYPTO_DOWN_REF(&rand->refcnt, &ref, rand->refcnt_lock); if (ref <= 0) { ossl_provider_free(rand->prov); - CRYPTO_THREAD_lock_free(rand->lock); + CRYPTO_THREAD_lock_free(rand->refcnt_lock); OPENSSL_free(rand); } } @@ -51,11 +51,11 @@ static void evp_rand_free(void *vrand){ static void *evp_rand_new(void) { - EVP_RAND *rand = NULL; + EVP_RAND *rand = OPENSSL_zalloc(sizeof(*rand)); - if ((rand = OPENSSL_zalloc(sizeof(*rand))) == NULL - || (rand->lock = CRYPTO_THREAD_lock_new()) == NULL) { - evp_rand_free(rand); + if (rand == NULL + || (rand->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL) { + OPENSSL_free(rand); return NULL; } rand->refcnt = 1; @@ -63,26 +63,27 @@ static void *evp_rand_new(void) } /* Enable locking of the underlying DRBG/RAND if available */ -int EVP_RAND_CTX_enable_locking(EVP_RAND_CTX *rand) +int EVP_RAND_enable_locking(EVP_RAND_CTX *rand) { - if (rand->meth->enable_prov_locking != NULL) - return rand->meth->enable_prov_locking(rand->data); - return 1; + if (rand->meth->enable_locking != NULL) + return rand->meth->enable_locking(rand->data); + EVPerr(0, EVP_R_LOCKING_NOT_SUPPORTED); + return 0; } /* Lock the underlying DRBG/RAND if available */ static int evp_rand_lock(EVP_RAND_CTX *rand) { - if (rand->meth->prov_lock != NULL) - return rand->meth->prov_lock(rand->data); + if (rand->meth->lock != NULL) + return rand->meth->lock(rand->data); return 1; } /* Unlock the underlying DRBG/RAND if available */ static void evp_rand_unlock(EVP_RAND_CTX *rand) { - if (rand->meth->prov_unlock != NULL) - rand->meth->prov_unlock(rand->data); + if (rand->meth->unlock != NULL) + rand->meth->unlock(rand->data); } static void *evp_rand_from_dispatch(int name_id, @@ -90,9 +91,9 @@ static void *evp_rand_from_dispatch(int name_id, OSSL_PROVIDER *prov) { EVP_RAND *rand = NULL; - int fnrandcnt = 0, fnctxcnt = 0; + int fnrandcnt = 0, fnctxcnt = 0, fnlockcnt = 0; #ifdef FIPS_MODULE - int fnfipscnt = 0; + int fnzeroizecnt = 0; #endif if ((rand = evp_rand_new()) == NULL) { @@ -149,19 +150,22 @@ static void *evp_rand_from_dispatch(int name_id, rand->set_callbacks = OSSL_get_OP_rand_set_callbacks(fns); break; case OSSL_FUNC_RAND_ENABLE_LOCKING: - if (rand->enable_prov_locking != NULL) + if (rand->enable_locking != NULL) break; - rand->enable_prov_locking = OSSL_get_OP_rand_enable_locking(fns); + rand->enable_locking = OSSL_get_OP_rand_enable_locking(fns); + fnlockcnt++; break; case OSSL_FUNC_RAND_LOCK: - if (rand->prov_lock != NULL) + if (rand->lock != NULL) break; - rand->prov_lock = OSSL_get_OP_rand_lock(fns); + rand->lock = OSSL_get_OP_rand_lock(fns); + fnlockcnt++; break; case OSSL_FUNC_RAND_UNLOCK: - if (rand->prov_unlock != NULL) + if (rand->unlock != NULL) break; - rand->prov_unlock = OSSL_get_OP_rand_unlock(fns); + rand->unlock = OSSL_get_OP_rand_unlock(fns); + fnlockcnt++; break; case OSSL_FUNC_RAND_GETTABLE_PARAMS: if (rand->gettable_params != NULL) @@ -201,36 +205,44 @@ static void *evp_rand_from_dispatch(int name_id, break; rand->verify_zeroization = OSSL_get_OP_rand_verify_zeroization(fns); #ifdef FIPS_MODULE - fnfipscnt++; + fnzeroizecnt++; #endif break; } } + /* + * In order to be a consistent set of functions we must have at least + * a complete set of "rand" functions and a complete set of context + * management functions. In FIPS mode, we also require the zeroization + * verification function. + * + * In addition, if locking can be enabled, we need a complete set of + * locking functions. + */ if (fnrandcnt != 3 || fnctxcnt != 2 + || (fnlockcnt != 0 && fnlockcnt != 3) #ifdef FIPS_MODULE - || fnfipscnt != 1 + || fnzeroizecnt != 1 #endif ) { - /* - * In order to be a consistent set of functions we must have at least - * a complete set of "rand" functions and a complete set of context - * management functions. In FIPS mode, we also require the zeroization - * verification function. - */ evp_rand_free(rand); ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); return NULL; } + + if (prov != NULL && !ossl_provider_up_ref(prov)) { + evp_rand_free(rand); + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return NULL; + } rand->prov = prov; - if (prov != NULL) - ossl_provider_up_ref(prov); return rand; } EVP_RAND *EVP_RAND_fetch(OPENSSL_CTX *libctx, const char *algorithm, - const char *properties) + const char *properties) { return evp_generic_fetch(libctx, OSSL_OP_RAND, algorithm, properties, evp_rand_from_dispatch, evp_rand_up_ref, @@ -274,25 +286,33 @@ int EVP_RAND_get_params(EVP_RAND *rand, OSSL_PARAM params[]) return 1; } -EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, int secure, EVP_RAND_CTX *parent) +EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, EVP_RAND_CTX *parent) { EVP_RAND_CTX *ctx; void *parent_ctx = NULL; const OSSL_DISPATCH *parent_dispatch = NULL; - if (rand == NULL) + if (rand == NULL) { + EVPerr(0, EVP_R_INVALID_NULL_ALGORITHM); return NULL; + } - ctx = OPENSSL_zalloc(sizeof(EVP_RAND_CTX)); - if (ctx == NULL) + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + EVPerr(0, ERR_R_MALLOC_FAILURE); return NULL; + } if (parent != NULL) { - EVP_RAND_CTX_enable_locking(parent); + if (!EVP_RAND_enable_locking(parent)) { + EVPerr(0, EVP_R_UNABLE_TO_ENABLE_PARENT_LOCKING); + OPENSSL_free(ctx); + return NULL; + } parent_ctx = parent->data; parent_dispatch = parent->meth->dispatch; } - if ((ctx->data = rand->newctx(ossl_provider_ctx(rand->prov), secure, - parent_ctx, parent_dispatch)) == NULL + if ((ctx->data = rand->newctx(ossl_provider_ctx(rand->prov), parent_ctx, + parent_dispatch)) == NULL || !EVP_RAND_up_ref(rand)) { EVPerr(0, ERR_R_MALLOC_FAILURE); rand->freectx(ctx->data); @@ -308,7 +328,6 @@ void EVP_RAND_CTX_free(EVP_RAND_CTX *ctx) if (ctx != NULL) { ctx->meth->freectx(ctx->data); ctx->data = NULL; - EVP_RAND_CTX_free(ctx->parent); EVP_RAND_free(ctx->meth); OPENSSL_free(ctx); } @@ -319,7 +338,7 @@ EVP_RAND *EVP_RAND_CTX_rand(EVP_RAND_CTX *ctx) return ctx->meth; } -int EVP_RAND_CTX_get_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[]) +int EVP_RAND_get_ctx_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[]) { int res = 1; @@ -332,7 +351,7 @@ int EVP_RAND_CTX_get_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[]) return res; } -int EVP_RAND_CTX_set_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[]) +int EVP_RAND_set_ctx_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[]) { int res = 1; @@ -350,23 +369,19 @@ int EVP_RAND_CTX_set_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[]) const OSSL_PARAM *EVP_RAND_gettable_params(const EVP_RAND *rand) { - if (rand->gettable_params == NULL) - return NULL; - return rand->gettable_params(); + return rand->gettable_params == NULL ? NULL : rand->gettable_params(); } const OSSL_PARAM *EVP_RAND_gettable_ctx_params(const EVP_RAND *rand) { - if (rand->gettable_ctx_params == NULL) - return NULL; - return rand->gettable_ctx_params(); + return rand->gettable_ctx_params == NULL ? NULL + : rand->gettable_ctx_params(); } const OSSL_PARAM *EVP_RAND_settable_ctx_params(const EVP_RAND *rand) { - if (rand->settable_ctx_params == NULL) - return NULL; - return rand->settable_ctx_params(); + return rand->settable_ctx_params == NULL ? NULL + :rand->settable_ctx_params(); } void EVP_RAND_do_all_provided(OPENSSL_CTX *libctx, @@ -386,9 +401,9 @@ void EVP_RAND_names_do_all(const EVP_RAND *rand, evp_names_do_all(rand->prov, rand->name_id, fn, data); } -int EVP_RAND_CTX_instantiate(EVP_RAND_CTX *ctx, unsigned int strength, - int prediction_resistance, - const unsigned char *pstr, size_t pstr_len) +int EVP_RAND_instantiate(EVP_RAND_CTX *ctx, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, size_t pstr_len) { int res; @@ -400,7 +415,7 @@ int EVP_RAND_CTX_instantiate(EVP_RAND_CTX *ctx, unsigned int strength, return res; } -int EVP_RAND_CTX_uninstantiate(EVP_RAND_CTX *ctx) +int EVP_RAND_uninstantiate(EVP_RAND_CTX *ctx) { int res; @@ -411,9 +426,9 @@ int EVP_RAND_CTX_uninstantiate(EVP_RAND_CTX *ctx) return res; } -int EVP_RAND_CTX_generate(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen, - unsigned int strength, int prediction_resistance, - const unsigned char *addin, size_t addin_len) +int EVP_RAND_generate(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen, + unsigned int strength, int prediction_resistance, + const unsigned char *addin, size_t addin_len) { size_t chunk; OSSL_PARAM params[2]; @@ -423,17 +438,26 @@ int EVP_RAND_CTX_generate(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen, return 0; if (ctx->max_request == 0) { params[0] = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_REQUEST, - &ctx->max_request); + &chunk); params[1] = OSSL_PARAM_construct_end(); - if (!EVP_RAND_CTX_get_params(ctx, params) - || ctx->max_request == 0) + if (!EVP_RAND_get_ctx_params(ctx, params) || chunk == 0) { + EVPerr(0, EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE); goto err; + } + ctx->max_request = chunk; } for (; outlen > 0; outlen -= chunk, out += chunk) { chunk = outlen > ctx->max_request ? ctx->max_request : outlen; if (!ctx->meth->generate(ctx->data, out, chunk, strength, - prediction_resistance, addin, addin_len)) + prediction_resistance, addin, addin_len)) { + EVPerr(0, EVP_R_GENERATE_ERROR); goto err; + } + /* + * Prediction resistance is only relevant the first time around, + * subsequently, the DRBG has already been properly reseeded. + */ + prediction_resistance = 0; } res = 1; err: @@ -441,9 +465,9 @@ err: return res; } -int EVP_RAND_CTX_reseed(EVP_RAND_CTX *ctx, int prediction_resistance, - const unsigned char *ent, size_t ent_len, - const unsigned char *addin, size_t addin_len) +int EVP_RAND_reseed(EVP_RAND_CTX *ctx, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *addin, size_t addin_len) { int res = 1; @@ -456,39 +480,41 @@ int EVP_RAND_CTX_reseed(EVP_RAND_CTX *ctx, int prediction_resistance, return res; } -int EVP_RAND_CTX_nonce(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen) +int EVP_RAND_nonce(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen) { int res = 1; + unsigned int str = EVP_RAND_strength(ctx); if (!evp_rand_lock(ctx)) return 0; if (ctx->meth->nonce == NULL - || !ctx->meth->nonce(ctx->data, out, 0, outlen, outlen)) - res = ctx->meth->generate(ctx->data, out, outlen, 0, 0, NULL, 0); + || !ctx->meth->nonce(ctx->data, out, str, outlen, outlen)) + res = ctx->meth->generate(ctx->data, out, outlen, str, 0, NULL, 0); evp_rand_unlock(ctx); return res; } -unsigned int EVP_RAND_CTX_strength(EVP_RAND_CTX *ctx) +unsigned int EVP_RAND_strength(EVP_RAND_CTX *ctx) { OSSL_PARAM params[2]; + unsigned int t; int res; if (ctx->strength == 0) { - params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, - &ctx->strength); + params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &t); params[1] = OSSL_PARAM_construct_end(); if (!evp_rand_lock(ctx)) return 0; - res = EVP_RAND_CTX_get_params(ctx, params); + res = EVP_RAND_get_ctx_params(ctx, params); evp_rand_unlock(ctx); if (!res) return 0; + ctx->strength = t; } return ctx->strength; } -int EVP_RAND_CTX_state(EVP_RAND_CTX *ctx) +int EVP_RAND_state(EVP_RAND_CTX *ctx) { OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; int status, res; @@ -497,14 +523,29 @@ int EVP_RAND_CTX_state(EVP_RAND_CTX *ctx) &status); if (!evp_rand_lock(ctx)) return 0; - res = EVP_RAND_CTX_get_params(ctx, params); + res = EVP_RAND_get_ctx_params(ctx, params); evp_rand_unlock(ctx); if (!res) status = EVP_RAND_STATE_ERROR; return status; } -int EVP_RAND_CTX_verify_zeroization(EVP_RAND_CTX *ctx) +int EVP_RAND_set_callbacks(EVP_RAND_CTX *ctx, + OSSL_INOUT_CALLBACK *get_entropy, + OSSL_CALLBACK *cleanup_entropy, + OSSL_INOUT_CALLBACK *get_nonce, + OSSL_CALLBACK *cleanup_nonce, void *arg) +{ + if (ctx->meth->set_callbacks == NULL) { + EVPerr(0, EVP_R_UNABLE_TO_SET_CALLBACKS); + return 0; + } + ctx->meth->set_callbacks(ctx->data, get_entropy, cleanup_entropy, + get_nonce, cleanup_nonce, arg); + return 1; +} + +int EVP_RAND_verify_zeroization(EVP_RAND_CTX *ctx) { int res = 0; diff --git a/crypto/rand/build.info b/crypto/rand/build.info index 7840428045..b7a4d598f1 100644 --- a/crypto/rand/build.info +++ b/crypto/rand/build.info @@ -1,16 +1,10 @@ LIBS=../../libcrypto -$COMMON=rand_pool.c rand_lib.c drbg_lib.c drbg_ctr.c drbg_hash.c drbg_hmac.c -$CRYPTO=rand_unix.c rand_win.c randfile.c rand_err.c +$COMMON=drbg_lib.c rand_lib.c +$CRYPTO=randfile.c rand_err.c IF[{- !$disabled{'egd'} -}] - $CYPTO=$CYPTO rand_egd.c -ENDIF -IF[{- $config{target} =~ /vxworks/i -}] - $CYPTO=$CYPTO rand_vxworks.c -ENDIF -IF[{- $config{target} =~ /vms/i -}] - $CYPTO=$CYPTO rand_vms.c + $CRYPTO=$CRYPTO rand_egd.c ENDIF diff --git a/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c index 94a4e98d73..80759cbfaf 100644 --- a/crypto/rand/drbg_lib.c +++ b/crypto/rand/drbg_lib.c @@ -11,10 +11,10 @@ #include #include #include +#include #include "rand_local.h" #include "internal/thread_once.h" #include "crypto/rand.h" -#include "crypto/rand_pool.h" #include "crypto/cryptlib.h" /* @@ -37,6 +37,7 @@ typedef struct drbg_global_st { * * There are three shared DRBG instances: , , and . */ + CRYPTO_RWLOCK *lock; /* * The DRBG @@ -70,14 +71,6 @@ typedef struct drbg_global_st { CRYPTO_THREAD_LOCAL private_drbg; } DRBG_GLOBAL; -typedef struct drbg_nonce_global_st { - CRYPTO_RWLOCK *rand_nonce_lock; - int rand_nonce_count; -} DRBG_NONCE_GLOBAL; - -/* NIST SP 800-90A DRBG recommends the use of a personalization string. */ -static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING; - #define RAND_DRBG_TYPE_FLAGS ( \ RAND_DRBG_FLAG_MASTER | RAND_DRBG_FLAG_PUBLIC | RAND_DRBG_FLAG_PRIVATE ) @@ -110,45 +103,76 @@ static const unsigned int rand_drbg_used_flags = static RAND_DRBG *drbg_setup(OPENSSL_CTX *ctx, RAND_DRBG *parent, int drbg_type); -static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx, - int secure, - int type, - unsigned int flags, - RAND_DRBG *parent); - -static int rand_drbg_set(RAND_DRBG *drbg, int type, unsigned int flags); -static int rand_drbg_init_method(RAND_DRBG *drbg); - -static int is_ctr(int type) +static int get_drbg_params(int type, unsigned int flags, const char **name, + OSSL_PARAM params[3]) { + OSSL_PARAM *p = params; + switch (type) { - case NID_aes_128_ctr: - case NID_aes_192_ctr: - case NID_aes_256_ctr: + case 0: return 1; default: return 0; + +#define CTR(v) \ + *name = "CTR-DRBG"; \ + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, v, 0) + + case NID_aes_128_ctr: + CTR(SN_aes_128_ctr); + break; + case NID_aes_192_ctr: + CTR(SN_aes_192_ctr); + break; + case NID_aes_256_ctr: + CTR(SN_aes_256_ctr); + break; + +#define DGST(v) \ + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, v, 0); \ + if ((flags & RAND_DRBG_FLAG_HMAC) == 0) { \ + *name = "HASH-DRBG"; \ + } else { \ + *name = "HMAC-DRBG"; \ + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_MAC, \ + SN_hmac, 0); \ } -} -static int is_digest(int type) -{ - switch (type) { case NID_sha1: + DGST(SN_sha1); + break; case NID_sha224: + DGST(SN_sha224); + break; case NID_sha256: + DGST(SN_sha256); + break; case NID_sha384: + DGST(SN_sha384); + break; case NID_sha512: + DGST(SN_sha512); + break; case NID_sha512_224: + DGST(SN_sha512_224); + break; case NID_sha512_256: + DGST(SN_sha512_256); + break; case NID_sha3_224: + DGST(SN_sha3_224); + break; case NID_sha3_256: + DGST(SN_sha3_256); + break; case NID_sha3_384: + DGST(SN_sha3_384); + break; case NID_sha3_512: - return 1; - default: - return 0; + DGST(SN_sha3_512); } + *p = OSSL_PARAM_construct_end(); + return 1; } /* @@ -170,23 +194,23 @@ static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx) OPENSSL_init_crypto(0, NULL); #endif + dgbl->lock = CRYPTO_THREAD_lock_new(); + if (dgbl->lock == NULL) + goto err0; + if (!CRYPTO_THREAD_init_local(&dgbl->private_drbg, NULL)) goto err1; if (!CRYPTO_THREAD_init_local(&dgbl->public_drbg, NULL)) goto err2; - dgbl->master_drbg = drbg_setup(libctx, NULL, RAND_DRBG_TYPE_MASTER); - if (dgbl->master_drbg == NULL) - goto err3; - return dgbl; - err3: - CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg); err2: CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg); err1: + CRYPTO_THREAD_lock_free(dgbl->lock); + err0: OPENSSL_free(dgbl); return NULL; } @@ -198,6 +222,7 @@ static void drbg_ossl_ctx_free(void *vdgbl) if (dgbl == NULL) return; + CRYPTO_THREAD_lock_free(dgbl->lock); RAND_DRBG_free(dgbl->master_drbg); CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg); CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg); @@ -210,104 +235,12 @@ static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = { drbg_ossl_ctx_free, }; -/* - * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce() - * which needs to get the rand_nonce_lock out of the OPENSSL_CTX...but since - * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock - * to be in a different global data object. Otherwise we will go into an - * infinite recursion loop. - */ -static void *drbg_nonce_ossl_ctx_new(OPENSSL_CTX *libctx) -{ - DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl)); - - if (dngbl == NULL) - return NULL; - - dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new(); - if (dngbl->rand_nonce_lock == NULL) { - OPENSSL_free(dngbl); - return NULL; - } - - return dngbl; -} - -static void drbg_nonce_ossl_ctx_free(void *vdngbl) -{ - DRBG_NONCE_GLOBAL *dngbl = vdngbl; - - if (dngbl == NULL) - return; - - CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock); - - OPENSSL_free(dngbl); -} - -static const OPENSSL_CTX_METHOD drbg_nonce_ossl_ctx_method = { - drbg_nonce_ossl_ctx_new, - drbg_nonce_ossl_ctx_free, -}; - static DRBG_GLOBAL *drbg_get_global(OPENSSL_CTX *libctx) { return openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_INDEX, &drbg_ossl_ctx_method); } -/* Implements the get_nonce() callback (see RAND_DRBG_set_callbacks()) */ -size_t rand_drbg_get_nonce(RAND_DRBG *drbg, - unsigned char **pout, - int entropy, size_t min_len, size_t max_len) -{ - size_t ret = 0; - RAND_POOL *pool; - DRBG_NONCE_GLOBAL *dngbl - = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX, - &drbg_nonce_ossl_ctx_method); - struct { - void *instance; - int count; - } data; - - if (dngbl == NULL) - return 0; - - memset(&data, 0, sizeof(data)); - pool = rand_pool_new(0, 0, min_len, max_len); - if (pool == NULL) - return 0; - - if (rand_pool_add_nonce_data(pool) == 0) - goto err; - - data.instance = drbg; - CRYPTO_atomic_add(&dngbl->rand_nonce_count, 1, &data.count, - dngbl->rand_nonce_lock); - - if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0) - goto err; - - ret = rand_pool_length(pool); - *pout = rand_pool_detach(pool); - - err: - rand_pool_free(pool); - - return ret; -} - -/* - * Implements the cleanup_nonce() callback (see RAND_DRBG_set_callbacks()) - * - */ -void rand_drbg_cleanup_nonce(RAND_DRBG *drbg, - unsigned char *out, size_t outlen) -{ - OPENSSL_clear_free(out, outlen); -} - /* * Set the |drbg|'s callback data pointer for the entropy and nonce callbacks * @@ -322,8 +255,8 @@ void rand_drbg_cleanup_nonce(RAND_DRBG *drbg, */ int RAND_DRBG_set_callback_data(RAND_DRBG *drbg, void *data) { - if (drbg->state != DRBG_UNINITIALISED - || drbg->parent != NULL) + if (EVP_RAND_state(drbg->rand) != EVP_RAND_STATE_UNINITIALISED + || drbg->parent != NULL) return 0; drbg->callback_data = data; @@ -345,68 +278,71 @@ void *RAND_DRBG_get_callback_data(RAND_DRBG *drbg) */ int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags) { - return rand_drbg_set(drbg, type, flags) && rand_drbg_init_method(drbg); -} + OSSL_PARAM params[6], *p = params; + unsigned int reseed_interval; + time_t reseed_time_interval; + const char *name = NULL; + EVP_RAND *rand; + EVP_RAND_CTX *pctx; + int use_df; -static int rand_drbg_set(RAND_DRBG *drbg, int type, unsigned int flags) -{ if (type == 0 && flags == 0) { type = rand_drbg_type[RAND_DRBG_TYPE_MASTER]; flags = rand_drbg_flags[RAND_DRBG_TYPE_MASTER]; } - /* If set is called multiple times - clear the old one */ - if (drbg->type != 0 && (type != drbg->type || flags != drbg->flags)) { - if (drbg->meth != NULL) - drbg->meth->uninstantiate(drbg); - rand_pool_free(drbg->adin_pool); - drbg->adin_pool = NULL; + if (drbg->parent == NULL) { + reseed_interval = master_reseed_interval; + reseed_time_interval = master_reseed_time_interval; + } else { + reseed_interval = slave_reseed_interval; + reseed_time_interval = slave_reseed_time_interval; + } + *p++ = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS, + &reseed_interval); + *p++ = OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, + &reseed_time_interval); + use_df = (flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0; + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_USE_DF, &use_df); + + if (!get_drbg_params(type, flags, &name, p)) { + RANDerr(0, RAND_R_UNSUPPORTED_DRBG_TYPE); + return 0; } - drbg->state = DRBG_UNINITIALISED; + rand = EVP_RAND_fetch(drbg->libctx, name, NULL); + if (rand == NULL) { + RANDerr(0, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); + return 0; + } + + EVP_RAND_CTX_free(drbg->rand); + drbg->rand = NULL; + drbg->flags = flags; drbg->type = type; - drbg->meth = NULL; - if (type == 0 || is_ctr(type) || is_digest(type)) - return 1; + pctx = drbg->parent != NULL ? drbg->parent->rand : NULL; + drbg->rand = EVP_RAND_CTX_new(rand, pctx); + EVP_RAND_free(rand); + if (drbg->rand == NULL) { + RANDerr(0, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); + goto err; + } + if (!EVP_RAND_set_ctx_params(drbg->rand, params)) { + RANDerr(0, RAND_R_ERROR_INITIALISING_DRBG); + goto err; + } + return 1; +err: + EVP_RAND_CTX_free(drbg->rand); + drbg->rand = NULL; drbg->type = 0; drbg->flags = 0; - RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE); - return 0; } -static int rand_drbg_init_method(RAND_DRBG *drbg) -{ - int ret; - - if (drbg->meth != NULL) - return 1; - - if (is_ctr(drbg->type)) { - ret = drbg_ctr_init(drbg); - } else if (is_digest(drbg->type)) { - if (drbg->flags & RAND_DRBG_FLAG_HMAC) - ret = drbg_hmac_init(drbg); - else - ret = drbg_hash_init(drbg); - } else { - /* other cases should already be excluded */ - RANDerr(RAND_F_RAND_DRBG_INIT_METHOD, ERR_R_INTERNAL_ERROR); - drbg->type = 0; - drbg->flags = 0; - return 0; - } - - if (ret == 0) { - drbg->state = DRBG_ERROR; - RANDerr(RAND_F_RAND_DRBG_INIT_METHOD, RAND_R_ERROR_INITIALISING_DRBG); - } - return ret; -} - /* * Set/initialize default |type| and |flag| for new drbg instances. * @@ -415,7 +351,10 @@ static int rand_drbg_init_method(RAND_DRBG *drbg) int RAND_DRBG_set_defaults(int type, unsigned int flags) { int all; - if (!(is_digest(type) || is_ctr(type))) { + const char *name; + OSSL_PARAM params[3]; + + if (!get_drbg_params(type, flags, &name, params)) { RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_TYPE); return 0; } @@ -443,20 +382,17 @@ int RAND_DRBG_set_defaults(int type, unsigned int flags) /* - * Allocate memory and initialize a new DRBG. The DRBG is allocated on - * the secure heap if |secure| is nonzero and the secure heap is enabled. + * Allocate memory and initialize a new DRBG. * The |parent|, if not NULL, will be used as random source for reseeding. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx, - int secure, int type, unsigned int flags, RAND_DRBG *parent) { - RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg)) - : OPENSSL_zalloc(sizeof(*drbg)); + RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg)); if (drbg == NULL) { RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); @@ -464,49 +400,11 @@ static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx, } drbg->libctx = ctx; - drbg->secure = secure && CRYPTO_secure_allocated(drbg); - drbg->fork_id = openssl_get_fork_id(); drbg->parent = parent; - if (parent == NULL) { - drbg->get_entropy = rand_drbg_get_entropy; - drbg->cleanup_entropy = rand_drbg_cleanup_entropy; -#ifndef RAND_DRBG_GET_RANDOM_NONCE - drbg->get_nonce = rand_drbg_get_nonce; - drbg->cleanup_nonce = rand_drbg_cleanup_nonce; -#endif - - drbg->reseed_interval = master_reseed_interval; - drbg->reseed_time_interval = master_reseed_time_interval; - } else { - drbg->get_entropy = rand_drbg_get_entropy; - drbg->cleanup_entropy = rand_drbg_cleanup_entropy; - /* - * Do not provide nonce callbacks, the child DRBGs will - * obtain their nonce using random bits from the parent. - */ - - drbg->reseed_interval = slave_reseed_interval; - drbg->reseed_time_interval = slave_reseed_time_interval; - } - if (RAND_DRBG_set(drbg, type, flags) == 0) goto err; - if (parent != NULL) { - rand_drbg_lock(parent); - if (drbg->strength > parent->strength) { - /* - * We currently don't support the algorithm from NIST SP 800-90C - * 10.1.2 to use a weaker DRBG as source - */ - rand_drbg_unlock(parent); - RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); - goto err; - } - rand_drbg_unlock(parent); - } - return drbg; err: @@ -518,7 +416,7 @@ static RAND_DRBG *rand_drbg_new(OPENSSL_CTX *ctx, RAND_DRBG *RAND_DRBG_new_ex(OPENSSL_CTX *ctx, int type, unsigned int flags, RAND_DRBG *parent) { - return rand_drbg_new(ctx, 0, type, flags, parent); + return rand_drbg_new(ctx, type, flags, parent); } RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent) @@ -526,16 +424,6 @@ RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent) return RAND_DRBG_new_ex(NULL, type, flags, parent); } -RAND_DRBG *RAND_DRBG_secure_new_ex(OPENSSL_CTX *ctx, int type, - unsigned int flags, RAND_DRBG *parent) -{ - return rand_drbg_new(ctx, 1, type, flags, parent); -} - -RAND_DRBG *RAND_DRBG_secure_new(int type, unsigned int flags, RAND_DRBG *parent) -{ - return RAND_DRBG_secure_new_ex(NULL, type, flags, parent); -} /* * Uninstantiate |drbg| and free all memory. */ @@ -544,18 +432,8 @@ void RAND_DRBG_free(RAND_DRBG *drbg) if (drbg == NULL) return; - if (drbg->meth != NULL) - drbg->meth->uninstantiate(drbg); - rand_pool_free(drbg->adin_pool); - CRYPTO_THREAD_lock_free(drbg->lock); -#ifndef FIPS_MODULE CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RAND_DRBG, drbg, &drbg->ex_data); -#endif - - if (drbg->secure) - OPENSSL_secure_clear_free(drbg, sizeof(*drbg)); - else - OPENSSL_clear_free(drbg, sizeof(*drbg)); + OPENSSL_free(drbg); } /* @@ -569,92 +447,8 @@ void RAND_DRBG_free(RAND_DRBG *drbg) int RAND_DRBG_instantiate(RAND_DRBG *drbg, const unsigned char *pers, size_t perslen) { - unsigned char *nonce = NULL, *entropy = NULL; - size_t noncelen = 0, entropylen = 0; - size_t min_entropy, min_entropylen, max_entropylen; - - if (drbg->meth == NULL && !rand_drbg_init_method(drbg)) { - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, - RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); - goto end; - } - - min_entropy = drbg->strength; - min_entropylen = drbg->min_entropylen; - max_entropylen = drbg->max_entropylen; - - if (perslen > drbg->max_perslen) { - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, - RAND_R_PERSONALISATION_STRING_TOO_LONG); - goto end; - } - - if (drbg->state != DRBG_UNINITIALISED) { - if (drbg->state == DRBG_ERROR) - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_IN_ERROR_STATE); - else - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ALREADY_INSTANTIATED); - goto end; - } - - drbg->state = DRBG_ERROR; - - /* - * NIST SP800-90Ar1 section 9.1 says you can combine getting the entropy - * and nonce in 1 call by increasing the entropy with 50% and increasing - * the minimum length to accommodate the length of the nonce. - * We do this in case a nonce is require and get_nonce is NULL. - */ - if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) { - min_entropy += drbg->strength / 2; - min_entropylen += drbg->min_noncelen; - max_entropylen += drbg->max_noncelen; - } - - drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); - if (drbg->reseed_next_counter) { - drbg->reseed_next_counter++; - if(!drbg->reseed_next_counter) - drbg->reseed_next_counter = 1; - } - - if (drbg->get_entropy != NULL) - entropylen = drbg->get_entropy(drbg, &entropy, min_entropy, - min_entropylen, max_entropylen, 0); - if (entropylen < min_entropylen - || entropylen > max_entropylen) { - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); - goto end; - } - - if (drbg->min_noncelen > 0 && drbg->get_nonce != NULL) { - noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, - drbg->min_noncelen, drbg->max_noncelen); - if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); - goto end; - } - } - - if (!drbg->meth->instantiate(drbg, entropy, entropylen, - nonce, noncelen, pers, perslen)) { - RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG); - goto end; - } - - drbg->state = DRBG_READY; - drbg->reseed_gen_counter = 1; - drbg->reseed_time = time(NULL); - tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); - - end: - if (entropy != NULL && drbg->cleanup_entropy != NULL) - drbg->cleanup_entropy(drbg, entropy, entropylen); - if (nonce != NULL && drbg->cleanup_nonce != NULL) - drbg->cleanup_nonce(drbg, nonce, noncelen); - if (drbg->state == DRBG_READY) - return 1; - return 0; + return EVP_RAND_instantiate(drbg->rand, EVP_RAND_strength(drbg->rand), 0, + pers, perslen); } /* @@ -667,10 +461,9 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg, int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) { int index = -1, type, flags; - if (drbg->meth != NULL) { - drbg->meth->uninstantiate(drbg); - drbg->meth = NULL; - } + + if (!EVP_RAND_uninstantiate(drbg->rand)) + return 0; /* The reset uses the default values for type and flags */ if (drbg->flags & RAND_DRBG_FLAG_MASTER) @@ -687,7 +480,7 @@ int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) flags = drbg->flags; type = drbg->type; } - return rand_drbg_set(drbg, type, flags); + return RAND_DRBG_set(drbg, type, flags); } /* @@ -701,288 +494,152 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg, const unsigned char *adin, size_t adinlen, int prediction_resistance) { - unsigned char *entropy = NULL; - size_t entropylen = 0; - - if (drbg->state == DRBG_ERROR) { - RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_IN_ERROR_STATE); - return 0; - } - if (drbg->state == DRBG_UNINITIALISED) { - RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_NOT_INSTANTIATED); - return 0; - } - - if (adin == NULL) { - adinlen = 0; - } else if (adinlen > drbg->max_adinlen) { - RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG); - return 0; - } - - drbg->state = DRBG_ERROR; - - drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); - if (drbg->reseed_next_counter) { - drbg->reseed_next_counter++; - if(!drbg->reseed_next_counter) - drbg->reseed_next_counter = 1; - } - - if (drbg->get_entropy != NULL) - entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, - drbg->min_entropylen, - drbg->max_entropylen, - prediction_resistance); - if (entropylen < drbg->min_entropylen - || entropylen > drbg->max_entropylen) { - RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY); - goto end; - } - - if (!drbg->meth->reseed(drbg, entropy, entropylen, adin, adinlen)) - goto end; - - drbg->state = DRBG_READY; - drbg->reseed_gen_counter = 1; - drbg->reseed_time = time(NULL); - tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); - - end: - if (entropy != NULL && drbg->cleanup_entropy != NULL) - drbg->cleanup_entropy(drbg, entropy, entropylen); - if (drbg->state == DRBG_READY) - return 1; - return 0; + return EVP_RAND_reseed(drbg->rand, prediction_resistance, NULL, 0, + adin, adinlen); } /* - * Restart |drbg|, using the specified entropy or additional input - * - * Tries its best to get the drbg instantiated by all means, - * regardless of its current state. + * Generate |outlen| bytes into the buffer at |out|. Reseed if we need + * to or if |prediction_resistance| is set. Additional input can be + * sent in |adin| and |adinlen|. * - * Optionally, a |buffer| of |len| random bytes can be passed, - * which is assumed to contain at least |entropy| bits of entropy. + * Requires that drbg->lock is already locked for write, if non-null. * - * If |entropy| > 0, the buffer content is used as entropy input. + * Returns 1 on success, 0 on failure. * - * If |entropy| == 0, the buffer content is used as additional input + */ +int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, + int prediction_resistance, + const unsigned char *adin, size_t adinlen) +{ + return EVP_RAND_generate(drbg->rand, out, outlen, 0, + prediction_resistance, adin, adinlen); +} + +/* + * Generates |outlen| random bytes and stores them in |out|. It will + * using the given |drbg| to generate the bytes. * - * Returns 1 on success, 0 on failure. + * Requires that drbg->lock is already locked for write, if non-null. * - * This function is used internally only. + * Returns 1 on success 0 on failure. */ -int rand_drbg_restart(RAND_DRBG *drbg, - const unsigned char *buffer, size_t len, size_t entropy) +int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen) { - int reseeded = 0; - const unsigned char *adin = NULL; - size_t adinlen = 0; - - if (drbg->seed_pool != NULL) { - RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); - drbg->state = DRBG_ERROR; - rand_pool_free(drbg->seed_pool); - drbg->seed_pool = NULL; + return EVP_RAND_generate(drbg->rand, out, outlen, 0, 0, NULL, 0); +} + +/* DRBG call back shims */ +static int rand_drbg_get_entroy_cb(const OSSL_PARAM *params, OSSL_PARAM *out, + void *vdrbg) +{ + RAND_DRBG *drbg = (RAND_DRBG *)vdrbg; + int entropy = 0, prediction_resistance = 0; + size_t min_len = 0, max_len = 2048; + const OSSL_PARAM *p; + OSSL_PARAM *q; + + if (drbg->get_entropy == NULL) return 0; - } - if (buffer != NULL) { - if (entropy > 0) { - if (drbg->max_entropylen < len) { - RANDerr(RAND_F_RAND_DRBG_RESTART, - RAND_R_ENTROPY_INPUT_TOO_LONG); - drbg->state = DRBG_ERROR; - return 0; - } - - if (entropy > 8 * len) { - RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE); - drbg->state = DRBG_ERROR; - return 0; - } - - /* will be picked up by the rand_drbg_get_entropy() callback */ - drbg->seed_pool = rand_pool_attach(buffer, len, entropy); - if (drbg->seed_pool == NULL) - return 0; - } else { - if (drbg->max_adinlen < len) { - RANDerr(RAND_F_RAND_DRBG_RESTART, - RAND_R_ADDITIONAL_INPUT_TOO_LONG); - drbg->state = DRBG_ERROR; - return 0; - } - adin = buffer; - adinlen = len; - } - } + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_ENTROPY_REQUIRED); + if (p == NULL || !OSSL_PARAM_get_int(p, &entropy)) + return 0; - /* repair error state */ - if (drbg->state == DRBG_ERROR) - RAND_DRBG_uninstantiate(drbg); - - /* repair uninitialized state */ - if (drbg->state == DRBG_UNINITIALISED) { - /* reinstantiate drbg */ - RAND_DRBG_instantiate(drbg, - (const unsigned char *) ossl_pers_string, - sizeof(ossl_pers_string) - 1); - /* already reseeded. prevent second reseeding below */ - reseeded = (drbg->state == DRBG_READY); - } + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_PREDICTION_RESISTANCE); + if (p == NULL || !OSSL_PARAM_get_int(p, &prediction_resistance)) + return 0; - /* refresh current state if entropy or additional input has been provided */ - if (drbg->state == DRBG_READY) { - if (adin != NULL) { - /* - * mix in additional input without reseeding - * - * Similar to RAND_DRBG_reseed(), but the provided additional - * data |adin| is mixed into the current state without pulling - * entropy from the trusted entropy source using get_entropy(). - * This is not a reseeding in the strict sense of NIST SP 800-90A. - */ - drbg->meth->reseed(drbg, adin, adinlen, NULL, 0); - } else if (reseeded == 0) { - /* do a full reseeding if it has not been done yet above */ - RAND_DRBG_reseed(drbg, NULL, 0, 0); - } - } + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MAX_LENGTH); + if (p == NULL || !OSSL_PARAM_get_size_t(p, &max_len)) + return 0; - rand_pool_free(drbg->seed_pool); - drbg->seed_pool = NULL; + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MIN_LENGTH); + if (p == NULL || !OSSL_PARAM_get_size_t(p, &min_len)) + return 0; + + q = OSSL_PARAM_locate(out, OSSL_DRBG_PARAM_RANDOM_DATA); + if (q == NULL || q->data_type != OSSL_PARAM_OCTET_PTR || q->data == NULL) + return 0; - return drbg->state == DRBG_READY; + q->return_size = drbg->get_entropy(drbg, (unsigned char **)q->data, entropy, + min_len, max_len, prediction_resistance); + return 1; } -/* - * Generate |outlen| bytes into the buffer at |out|. Reseed if we need - * to or if |prediction_resistance| is set. Additional input can be - * sent in |adin| and |adinlen|. - * - * Requires that drbg->lock is already locked for write, if non-null. - * - * Returns 1 on success, 0 on failure. - * - */ -int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, - int prediction_resistance, - const unsigned char *adin, size_t adinlen) +static int rand_drbg_cleanup_entropy_cb(const OSSL_PARAM *params, void *vdrbg) { - int fork_id; - int reseed_required = 0; - - if (drbg->state != DRBG_READY) { - /* try to recover from previous errors */ - rand_drbg_restart(drbg, NULL, 0, 0); - - if (drbg->state == DRBG_ERROR) { - RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE); - return 0; - } - if (drbg->state == DRBG_UNINITIALISED) { - RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED); - return 0; - } - } + RAND_DRBG *drbg = (RAND_DRBG *)vdrbg; + const OSSL_PARAM *p; + size_t sz; - if (outlen > drbg->max_request) { - RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG); + if (drbg->cleanup_entropy == NULL) return 0; - } - if (adinlen > drbg->max_adinlen) { - RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_SIZE); + if (p == NULL || !OSSL_PARAM_get_size_t(p, &sz)) return 0; - } - fork_id = openssl_get_fork_id(); + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RANDOM_DATA); + if (p == NULL || p->data_type != OSSL_PARAM_OCTET_PTR) + return 0; - if (drbg->fork_id != fork_id) { - drbg->fork_id = fork_id; - reseed_required = 1; - } + drbg->cleanup_entropy(drbg, p->data, sz); + return 1; +} - if (drbg->reseed_interval > 0) { - if (drbg->reseed_gen_counter > drbg->reseed_interval) - reseed_required = 1; - } - if (drbg->reseed_time_interval > 0) { - time_t now = time(NULL); - if (now < drbg->reseed_time - || now - drbg->reseed_time >= drbg->reseed_time_interval) - reseed_required = 1; - } - if (drbg->parent != NULL) { - unsigned int reseed_counter = tsan_load(&drbg->reseed_prop_counter); - if (reseed_counter > 0 - && tsan_load(&drbg->parent->reseed_prop_counter) - != reseed_counter) - reseed_required = 1; - } +static int rand_drbg_get_nonce_cb(const OSSL_PARAM *params, OSSL_PARAM *out, + void *vdrbg) +{ + RAND_DRBG *drbg = (RAND_DRBG *)vdrbg; + int entropy = 0; + size_t min_len = 0, max_len = 10240; + const OSSL_PARAM *p; + OSSL_PARAM *q; - if (reseed_required || prediction_resistance) { - if (!RAND_DRBG_reseed(drbg, adin, adinlen, prediction_resistance)) { - RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR); - return 0; - } - adin = NULL; - adinlen = 0; - } + if (drbg->get_nonce == NULL) + return 0; - if (!drbg->meth->generate(drbg, out, outlen, adin, adinlen)) { - drbg->state = DRBG_ERROR; - RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_GENERATE_ERROR); + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_ENTROPY_REQUIRED); + if (p == NULL || !OSSL_PARAM_get_int(p, &entropy)) return 0; - } - drbg->reseed_gen_counter++; + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MAX_LENGTH); + if (p == NULL || !OSSL_PARAM_get_size_t(p, &max_len)) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_MIN_LENGTH); + if (p == NULL || !OSSL_PARAM_get_size_t(p, &min_len)) + return 0; + + q = OSSL_PARAM_locate(out, OSSL_DRBG_PARAM_RANDOM_DATA); + if (q == NULL || q->data_type != OSSL_PARAM_OCTET_PTR || q->data == NULL) + return 0; + q->return_size = drbg->get_nonce(drbg, (unsigned char **)q->data, entropy, + min_len, max_len); return 1; } -/* - * Generates |outlen| random bytes and stores them in |out|. It will - * using the given |drbg| to generate the bytes. - * - * Requires that drbg->lock is already locked for write, if non-null. - * - * Returns 1 on success 0 on failure. - */ -int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen) +static int rand_drbg_cleanup_nonce_cb(const OSSL_PARAM *params, void *vdrbg) { - unsigned char *additional = NULL; - size_t additional_len; - size_t chunk; - size_t ret = 0; - - if (drbg->adin_pool == NULL) { - if (drbg->type == 0) - goto err; - drbg->adin_pool = rand_pool_new(0, 0, 0, drbg->max_adinlen); - if (drbg->adin_pool == NULL) - goto err; - } + RAND_DRBG *drbg = (RAND_DRBG *)vdrbg; + const OSSL_PARAM *p; + size_t sz; - additional_len = rand_drbg_get_additional_data(drbg->adin_pool, - &additional); + if (drbg->cleanup_nonce == NULL) + return 0; - for ( ; outlen > 0; outlen -= chunk, out += chunk) { - chunk = outlen; - if (chunk > drbg->max_request) - chunk = drbg->max_request; - ret = RAND_DRBG_generate(drbg, out, chunk, 0, additional, additional_len); - if (!ret) - goto err; - } - ret = 1; + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_SIZE); + if (p == NULL || !OSSL_PARAM_get_size_t(p, &sz)) + return 0; - err: - if (additional != NULL) - rand_drbg_cleanup_additional_data(drbg->adin_pool, additional); + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RANDOM_DATA); + if (p == NULL || p->data_type != OSSL_PARAM_OCTET_PTR) + return 0; - return ret; + drbg->cleanup_nonce(drbg, p->data, sz); + return 1; } /* @@ -999,13 +656,25 @@ int RAND_DRBG_set_callbacks(RAND_DRBG *drbg, RAND_DRBG_get_nonce_fn get_nonce, RAND_DRBG_cleanup_nonce_fn cleanup_nonce) { - if (drbg->state != DRBG_UNINITIALISED - || drbg->parent != NULL) + EVP_RAND_CTX *rand = drbg->rand; + OSSL_INOUT_CALLBACK *g_ent = NULL, *g_nonce = NULL; + OSSL_CALLBACK *c_ent = NULL, *c_nonce = NULL; + + if (get_entropy != NULL) { + g_ent = &rand_drbg_get_entroy_cb; + c_ent = &rand_drbg_cleanup_entropy_cb; + } + if (get_nonce != NULL) { + g_nonce = rand_drbg_get_nonce_cb; + c_nonce = rand_drbg_cleanup_nonce_cb; + } + if (!EVP_RAND_set_callbacks(rand, g_ent, c_ent, g_nonce, c_nonce, drbg)) return 0; - drbg->get_entropy = get_entropy; - drbg->cleanup_entropy = cleanup_entropy; - drbg->get_nonce = get_nonce; - drbg->cleanup_nonce = cleanup_nonce; + + drbg->get_entropy = g_ent != NULL ? get_entropy : NULL; + drbg->cleanup_entropy = c_ent != NULL ? cleanup_entropy : NULL; + drbg->get_nonce = g_nonce != NULL ? get_nonce : NULL; + drbg->cleanup_nonce = c_nonce != NULL ? cleanup_nonce : NULL; return 1; } @@ -1020,10 +689,13 @@ int RAND_DRBG_set_callbacks(RAND_DRBG *drbg, */ int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + if (interval > MAX_RESEED_INTERVAL) return 0; - drbg->reseed_interval = interval; - return 1; + params[0] = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS, + &interval); + return EVP_RAND_set_ctx_params(drbg->rand, params); } /* @@ -1038,10 +710,14 @@ int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval) */ int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval) { + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + if (interval > MAX_RESEED_TIME_INTERVAL) return 0; - drbg->reseed_time_interval = interval; - return 1; + params[0] = + OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, + &interval); + return EVP_RAND_set_ctx_params(drbg->rand, params); } /* @@ -1077,69 +753,6 @@ int RAND_DRBG_set_reseed_defaults( return 1; } -/* - * Locks the given drbg. Locking a drbg which does not have locking - * enabled is considered a successful no-op. - * - * Returns 1 on success, 0 on failure. - */ -int rand_drbg_lock(RAND_DRBG *drbg) -{ - if (drbg->lock != NULL) - return CRYPTO_THREAD_write_lock(drbg->lock); - - return 1; -} - -/* - * Unlocks the given drbg. Unlocking a drbg which does not have locking - * enabled is considered a successful no-op. - * - * Returns 1 on success, 0 on failure. - */ -int rand_drbg_unlock(RAND_DRBG *drbg) -{ - if (drbg->lock != NULL) - return CRYPTO_THREAD_unlock(drbg->lock); - - return 1; -} - -/* - * Enables locking for the given drbg - * - * Locking can only be enabled if the random generator - * is in the uninitialized state. - * - * Returns 1 on success, 0 on failure. - */ -int rand_drbg_enable_locking(RAND_DRBG *drbg) -{ - if (drbg->state != DRBG_UNINITIALISED) { - RANDerr(RAND_F_RAND_DRBG_ENABLE_LOCKING, - RAND_R_DRBG_ALREADY_INITIALIZED); - return 0; - } - - if (drbg->lock == NULL) { - if (drbg->parent != NULL && drbg->parent->lock == NULL) { - RANDerr(RAND_F_RAND_DRBG_ENABLE_LOCKING, - RAND_R_PARENT_LOCKING_NOT_ENABLED); - return 0; - } - - drbg->lock = CRYPTO_THREAD_lock_new(); - if (drbg->lock == NULL) { - RANDerr(RAND_F_RAND_DRBG_ENABLE_LOCKING, - RAND_R_FAILED_TO_CREATE_LOCK); - return 0; - } - } - - return 1; -} - -#ifndef FIPS_MODULE /* * Get and set the EXDATA */ @@ -1152,7 +765,6 @@ void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx) { return CRYPTO_get_ex_data(&drbg->ex_data, idx); } -#endif /* * The following functions provide a RAND_METHOD that works on the @@ -1169,27 +781,22 @@ static RAND_DRBG *drbg_setup(OPENSSL_CTX *ctx, RAND_DRBG *parent, int drbg_type) { RAND_DRBG *drbg; - drbg = RAND_DRBG_secure_new_ex(ctx, rand_drbg_type[drbg_type], - rand_drbg_flags[drbg_type], parent); + drbg = RAND_DRBG_new_ex(ctx, rand_drbg_type[drbg_type], + rand_drbg_flags[drbg_type], parent); if (drbg == NULL) return NULL; /* Only the master DRBG needs to have a lock */ - if (parent == NULL && rand_drbg_enable_locking(drbg) == 0) + if (parent == NULL && EVP_RAND_enable_locking(drbg->rand) == 0) goto err; - /* enable seed propagation */ - tsan_store(&drbg->reseed_prop_counter, 1); - /* * Ignore instantiation error to support just-in-time instantiation. * * The state of the drbg will be checked in RAND_DRBG_generate() and * an automatic recovery is attempted. */ - (void)RAND_DRBG_instantiate(drbg, - (const unsigned char *) ossl_pers_string, - sizeof(ossl_pers_string) - 1); + (void)RAND_DRBG_instantiate(drbg, NULL, 0); return drbg; err: @@ -1228,112 +835,15 @@ static int drbg_bytes(unsigned char *out, int count) return ret; } -/* - * Calculates the minimum length of a full entropy buffer - * which is necessary to seed (i.e. instantiate) the DRBG - * successfully. - */ -size_t rand_drbg_seedlen(RAND_DRBG *drbg) -{ - /* - * If no os entropy source is available then RAND_seed(buffer, bufsize) - * is expected to succeed if and only if the buffer length satisfies - * the following requirements, which follow from the calculations - * in RAND_DRBG_instantiate(). - */ - size_t min_entropy = drbg->strength; - size_t min_entropylen = drbg->min_entropylen; - - /* - * Extra entropy for the random nonce in the absence of a - * get_nonce callback, see comment in RAND_DRBG_instantiate(). - */ - if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) { - min_entropy += drbg->strength / 2; - min_entropylen += drbg->min_noncelen; - } - - /* - * Convert entropy requirement from bits to bytes - * (dividing by 8 without rounding upwards, because - * all entropy requirements are divisible by 8). - */ - min_entropy >>= 3; - - /* Return a value that satisfies both requirements */ - return min_entropy > min_entropylen ? min_entropy : min_entropylen; -} - /* Implements the default OpenSSL RAND_add() method */ static int drbg_add(const void *buf, int num, double randomness) { - int ret = 0; RAND_DRBG *drbg = RAND_DRBG_get0_master(); - size_t buflen; - size_t seedlen; - if (drbg == NULL) + if (drbg == NULL || num <= 0) return 0; - if (num < 0 || randomness < 0.0) - return 0; - - rand_drbg_lock(drbg); - seedlen = rand_drbg_seedlen(drbg); - - buflen = (size_t)num; - -#ifdef FIPS_MODULE - /* - * NIST SP-800-90A mandates that entropy *shall not* be provided - * by the consuming application. By setting the randomness to zero, - * we ensure that the buffer contents will be added to the internal - * state of the DRBG only as additional data. - * - * (NIST SP-800-90Ar1, Sections 9.1 and 9.2) - */ - randomness = 0.0; -#endif - if (buflen < seedlen || randomness < (double) seedlen) { -#if defined(OPENSSL_RAND_SEED_NONE) - /* - * If no os entropy source is available, a reseeding will fail - * inevitably. So we use a trick to mix the buffer contents into - * the DRBG state without forcing a reseeding: we generate a - * dummy random byte, using the buffer content as additional data. - * Note: This won't work with RAND_DRBG_FLAG_CTR_NO_DF. - */ - unsigned char dummy[1]; - - ret = RAND_DRBG_generate(drbg, dummy, sizeof(dummy), 0, buf, buflen); - rand_drbg_unlock(drbg); - return ret; -#else - /* - * If an os entropy source is available then we declare the buffer content - * as additional data by setting randomness to zero and trigger a regular - * reseeding. - */ - randomness = 0.0; -#endif - } - - if (randomness > (double)seedlen) { - /* - * The purpose of this check is to bound |randomness| by a - * relatively small value in order to prevent an integer - * overflow when multiplying by 8 in the rand_drbg_restart() - * call below. Note that randomness is measured in bytes, - * not bits, so this value corresponds to eight times the - * security strength. - */ - randomness = (double)seedlen; - } - - ret = rand_drbg_restart(drbg, buf, buflen, (size_t)(8 * randomness)); - rand_drbg_unlock(drbg); - - return ret; + return EVP_RAND_reseed(drbg->rand, 0, NULL, 0, buf, num); } /* Implements the default OpenSSL RAND_seed() method */ @@ -1351,12 +861,15 @@ static int drbg_status(void) if (drbg == NULL) return 0; - rand_drbg_lock(drbg); - ret = drbg->state == DRBG_READY ? 1 : 0; - rand_drbg_unlock(drbg); + ret = EVP_RAND_state(drbg->rand) == EVP_RAND_STATE_READY ? 1 : 0; return ret; } +int RAND_DRBG_verify_zeroization(RAND_DRBG *drbg) +{ + return EVP_RAND_verify_zeroization(drbg->rand); +} + /* * Get the master DRBG. * Returns pointer to the DRBG on success, NULL on failure. @@ -1369,6 +882,13 @@ RAND_DRBG *OPENSSL_CTX_get0_master_drbg(OPENSSL_CTX *ctx) if (dgbl == NULL) return NULL; + if (dgbl->master_drbg == NULL) { + if (!CRYPTO_THREAD_write_lock(dgbl->lock)) + return NULL; + if (dgbl->master_drbg == NULL) + dgbl->master_drbg = drbg_setup(ctx, NULL, RAND_DRBG_TYPE_MASTER); + CRYPTO_THREAD_unlock(dgbl->lock); + } return dgbl->master_drbg; } @@ -1384,13 +904,17 @@ RAND_DRBG *RAND_DRBG_get0_master(void) RAND_DRBG *OPENSSL_CTX_get0_public_drbg(OPENSSL_CTX *ctx) { DRBG_GLOBAL *dgbl = drbg_get_global(ctx); - RAND_DRBG *drbg; + RAND_DRBG *drbg, *master; if (dgbl == NULL) return NULL; drbg = CRYPTO_THREAD_get_local(&dgbl->public_drbg); if (drbg == NULL) { + master = OPENSSL_CTX_get0_master_drbg(ctx); + if (master == NULL) + return NULL; + ctx = openssl_ctx_get_concrete(ctx); /* * If the private_drbg is also NULL then this is the first time we've @@ -1399,7 +923,7 @@ RAND_DRBG *OPENSSL_CTX_get0_public_drbg(OPENSSL_CTX *ctx) if (CRYPTO_THREAD_get_local(&dgbl->private_drbg) == NULL && !ossl_init_thread_start(NULL, ctx, drbg_delete_thread_state)) return NULL; - drbg = drbg_setup(ctx, dgbl->master_drbg, RAND_DRBG_TYPE_PUBLIC); + drbg = drbg_setup(ctx, master, RAND_DRBG_TYPE_PUBLIC); CRYPTO_THREAD_set_local(&dgbl->public_drbg, drbg); } return drbg; @@ -1417,13 +941,17 @@ RAND_DRBG *RAND_DRBG_get0_public(void) RAND_DRBG *OPENSSL_CTX_get0_private_drbg(OPENSSL_CTX *ctx) { DRBG_GLOBAL *dgbl = drbg_get_global(ctx); - RAND_DRBG *drbg; + RAND_DRBG *drbg, *master; if (dgbl == NULL) return NULL; drbg = CRYPTO_THREAD_get_local(&dgbl->private_drbg); if (drbg == NULL) { + master = OPENSSL_CTX_get0_master_drbg(ctx); + if (master == NULL) + return NULL; + ctx = openssl_ctx_get_concrete(ctx); /* * If the public_drbg is also NULL then this is the first time we've @@ -1432,7 +960,7 @@ RAND_DRBG *OPENSSL_CTX_get0_private_drbg(OPENSSL_CTX *ctx) if (CRYPTO_THREAD_get_local(&dgbl->public_drbg) == NULL && !ossl_init_thread_start(NULL, ctx, drbg_delete_thread_state)) return NULL; - drbg = drbg_setup(ctx, dgbl->master_drbg, RAND_DRBG_TYPE_PRIVATE); + drbg = drbg_setup(ctx, master, RAND_DRBG_TYPE_PRIVATE); CRYPTO_THREAD_set_local(&dgbl->private_drbg, drbg); } return drbg; diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index a4c9e69472..e7dfb07de2 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -18,6 +18,9 @@ #include "e_os.h" #ifndef FIPS_MODULE +# include "prov/rand_pool.h" +# include "prov/seeding.h" + # ifndef OPENSSL_NO_ENGINE /* non-NULL if default_RAND_meth is ENGINE-provided */ static ENGINE *funct_ref; @@ -28,218 +31,7 @@ static const RAND_METHOD *default_RAND_meth; static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT; static int rand_inited = 0; -#endif /* FIPS_MODULE */ - -#ifdef OPENSSL_RAND_SEED_RDTSC -/* - * IMPORTANT NOTE: It is not currently possible to use this code - * because we are not sure about the amount of randomness it provides. - * Some SP900 tests have been run, but there is internal skepticism. - * So for now this code is not used. - */ -# error "RDTSC enabled? Should not be possible!" - -/* - * Acquire entropy from high-speed clock - * - * Since we get some randomness from the low-order bits of the - * high-speed clock, it can help. - * - * Returns the total entropy count, if it exceeds the requested - * entropy count. Otherwise, returns an entropy count of 0. - */ -size_t rand_acquire_entropy_from_tsc(RAND_POOL *pool) -{ - unsigned char c; - int i; - - if ((OPENSSL_ia32cap_P[0] & (1 << 4)) != 0) { - for (i = 0; i < TSC_READ_COUNT; i++) { - c = (unsigned char)(OPENSSL_rdtsc() & 0xFF); - rand_pool_add(pool, &c, 1, 4); - } - } - return rand_pool_entropy_available(pool); -} -#endif - -#ifdef OPENSSL_RAND_SEED_RDCPU -size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len); -size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len); - -/* - * Acquire entropy using Intel-specific cpu instructions - * - * Uses the RDSEED instruction if available, otherwise uses - * RDRAND if available. - * - * For the differences between RDSEED and RDRAND, and why RDSEED - * is the preferred choice, see https://goo.gl/oK3KcN - * - * Returns the total entropy count, if it exceeds the requested - * entropy count. Otherwise, returns an entropy count of 0. - */ -size_t rand_acquire_entropy_from_cpu(RAND_POOL *pool) -{ - size_t bytes_needed; - unsigned char *buffer; - - bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); - if (bytes_needed > 0) { - buffer = rand_pool_add_begin(pool, bytes_needed); - - if (buffer != NULL) { - /* Whichever comes first, use RDSEED, RDRAND or nothing */ - if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) { - if (OPENSSL_ia32_rdseed_bytes(buffer, bytes_needed) - == bytes_needed) { - rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); - } - } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) { - if (OPENSSL_ia32_rdrand_bytes(buffer, bytes_needed) - == bytes_needed) { - rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); - } - } else { - rand_pool_add_end(pool, 0, 0); - } - } - } - - return rand_pool_entropy_available(pool); -} -#endif - -#if 0 -/* - * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) - * - * If the DRBG has a parent, then the required amount of entropy input - * is fetched using the parent's RAND_DRBG_generate(). - * - * Otherwise, the entropy is polled from the system entropy sources - * using rand_pool_acquire_entropy(). - * - * If a random pool has been added to the DRBG using RAND_add(), then - * its entropy will be used up first. - */ -size_t rand_drbg_get_entropy(RAND_DRBG *drbg, - unsigned char **pout, - int entropy, size_t min_len, size_t max_len, - int prediction_resistance) -{ - size_t ret = 0; - size_t entropy_available = 0; - RAND_POOL *pool; - - if (drbg->parent != NULL && drbg->strength > drbg->parent->strength) { - /* - * We currently don't support the algorithm from NIST SP 800-90C - * 10.1.2 to use a weaker DRBG as source - */ - RANDerr(RAND_F_RAND_DRBG_GET_ENTROPY, RAND_R_PARENT_STRENGTH_TOO_WEAK); - return 0; - } - - if (drbg->seed_pool != NULL) { - pool = drbg->seed_pool; - pool->entropy_requested = entropy; - } else { - pool = rand_pool_new(entropy, drbg->secure, min_len, max_len); - if (pool == NULL) - return 0; - } - - if (drbg->parent != NULL) { - size_t bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); - unsigned char *buffer = rand_pool_add_begin(pool, bytes_needed); - - if (buffer != NULL) { - size_t bytes = 0; - - /* - * Get random data from parent. Include our address as additional input, - * in order to provide some additional distinction between different - * DRBG child instances. - * Our lock is already held, but we need to lock our parent before - * generating bits from it. (Note: taking the lock will be a no-op - * if locking if drbg->parent->lock == NULL.) - */ - rand_drbg_lock(drbg->parent); - if (RAND_DRBG_generate(drbg->parent, - buffer, bytes_needed, - prediction_resistance, - (unsigned char *)&drbg, sizeof(drbg)) != 0) - bytes = bytes_needed; - drbg->reseed_next_counter - = tsan_load(&drbg->parent->reseed_prop_counter); - rand_drbg_unlock(drbg->parent); - - rand_pool_add_end(pool, bytes, 8 * bytes); - entropy_available = rand_pool_entropy_available(pool); - } - - } else { - /* Get entropy by polling system entropy sources. */ - entropy_available = rand_pool_acquire_entropy(pool); - } - - if (entropy_available > 0) { - ret = rand_pool_length(pool); - *pout = rand_pool_detach(pool); - } - - if (drbg->seed_pool == NULL) - rand_pool_free(pool); - return ret; -} - -/* - * Implements the cleanup_entropy() callback (see RAND_DRBG_set_callbacks()) - * - */ -void rand_drbg_cleanup_entropy(RAND_DRBG *drbg, - unsigned char *out, size_t outlen) -{ - if (drbg->seed_pool == NULL) { - if (drbg->secure) - OPENSSL_secure_clear_free(out, outlen); - else - OPENSSL_clear_free(out, outlen); - } -} - -/* - * Generate additional data that can be used for the drbg. The data does - * not need to contain entropy, but it's useful if it contains at least - * some bits that are unpredictable. - * - * Returns 0 on failure. - * - * On success it allocates a buffer at |*pout| and returns the length of - * the data. The buffer should get freed using OPENSSL_secure_clear_free(). - */ -size_t rand_drbg_get_additional_data(RAND_POOL *pool, unsigned char **pout) -{ - size_t ret = 0; - - if (rand_pool_add_additional_data(pool) == 0) - goto err; - - ret = rand_pool_length(pool); - *pout = rand_pool_detach(pool); - - err: - return ret; -} - -void rand_drbg_cleanup_additional_data(RAND_POOL *pool, unsigned char *out) -{ - rand_pool_reattach(pool, out); -} -#endif -#ifndef FIPS_MODULE DEFINE_RUN_ONCE_STATIC(do_rand_init) { # ifndef OPENSSL_NO_ENGINE @@ -288,10 +80,10 @@ void rand_cleanup_int(void) rand_inited = 0; } -/* TODO(3.0): Do we need to handle this somehow in the FIPS module? */ /* * RAND_close_seed_files() ensures that any seed file descriptors are - * closed after use. + * closed after use. This only applies to libcrypto/default provider, + * it does not apply to other providers. */ void RAND_keep_random_devices_open(int keep) { @@ -308,39 +100,24 @@ void RAND_keep_random_devices_open(int keep) */ int RAND_poll(void) { - int ret = 0; - const RAND_METHOD *meth = RAND_get_rand_method(); + int ret = meth == RAND_OpenSSL(); + RAND_POOL *pool; if (meth == NULL) return 0; - if (meth == RAND_OpenSSL()) { - /* fill random pool and seed the master DRBG */ - RAND_DRBG *drbg = RAND_DRBG_get0_master(); - - if (drbg == NULL) - return 0; - -#if 0 - ret = rand_drbg_restart(drbg, NULL, 0, 0); -#endif - - return ret; - - } else { - RAND_POOL *pool = NULL; - + if (!ret) { /* fill random pool and seed the current legacy RNG */ pool = rand_pool_new(RAND_DRBG_STRENGTH, 1, (RAND_DRBG_STRENGTH + 7) / 8, RAND_POOL_MAX_LENGTH); if (pool == NULL) return 0; -#if 0 - if (rand_pool_acquire_entropy(pool) == 0) + + if (prov_pool_acquire_entropy(pool) == 0) goto err; -#endif + if (meth->add == NULL || meth->add(rand_pool_buffer(pool), rand_pool_length(pool), @@ -348,11 +125,9 @@ int RAND_poll(void) goto err; ret = 1; - err: rand_pool_free(pool); } - return ret; } @@ -370,13 +145,9 @@ int RAND_set_rand_method(const RAND_METHOD *meth) CRYPTO_THREAD_unlock(rand_meth_lock); return 1; } -#endif /* FIPS_MODULE */ const RAND_METHOD *RAND_get_rand_method(void) { -#ifdef FIPS_MODULE - return NULL; -#else const RAND_METHOD *tmp_meth = NULL; if (!RUN_ONCE(&rand_init, do_rand_init)) @@ -403,10 +174,9 @@ const RAND_METHOD *RAND_get_rand_method(void) tmp_meth = default_RAND_meth; CRYPTO_THREAD_unlock(rand_meth_lock); return tmp_meth; -#endif } -#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) +# if !defined(OPENSSL_NO_ENGINE) int RAND_set_rand_engine(ENGINE *engine) { const RAND_METHOD *tmp_meth = NULL; @@ -430,7 +200,7 @@ int RAND_set_rand_engine(ENGINE *engine) CRYPTO_THREAD_unlock(rand_engine_lock); return 1; } -#endif +# endif void RAND_seed(const void *buf, int num) { @@ -448,6 +218,38 @@ void RAND_add(const void *buf, int num, double randomness) meth->add(buf, num, randomness); } +# if !defined(OPENSSL_NO_DEPRECATED_1_1_0) +int RAND_pseudo_bytes(unsigned char *buf, int num) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth->pseudorand != NULL) + return meth->pseudorand(buf, num); + RANDerr(RAND_F_RAND_PSEUDO_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED); + return -1; +} +# endif + +int RAND_status(void) +{ + RAND_DRBG *drbg; + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth != RAND_OpenSSL()) + return meth->status != NULL ? meth->status() : 0; + + if ((drbg = RAND_DRBG_get0_master()) == NULL || drbg->rand == NULL) + return EVP_RAND_STATE_UNINITIALISED; + return EVP_RAND_state(drbg->rand) == EVP_RAND_STATE_READY; +} +#else /* !FIPS_MODULE */ + +const RAND_METHOD *RAND_get_rand_method(void) +{ + return NULL; +} +#endif /* !FIPS_MODULE */ + /* * This function is not part of RAND_METHOD, so if we're not using * the default method, then just call RAND_bytes(). Otherwise make @@ -500,24 +302,3 @@ int RAND_bytes(unsigned char *buf, int num) { return RAND_bytes_ex(NULL, buf, num); } - -#if !defined(OPENSSL_NO_DEPRECATED_1_1_0) && !defined(FIPS_MODULE) -int RAND_pseudo_bytes(unsigned char *buf, int num) -{ - const RAND_METHOD *meth = RAND_get_rand_method(); - - if (meth != NULL && meth->pseudorand != NULL) - return meth->pseudorand(buf, num); - RANDerr(RAND_F_RAND_PSEUDO_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED); - return -1; -} -#endif - -int RAND_status(void) -{ - const RAND_METHOD *meth = RAND_get_rand_method(); - - if (meth != NULL && meth->status != NULL) - return meth->status(); - return 0; -} diff --git a/crypto/rand/rand_local.h b/crypto/rand/rand_local.h index 85158df76f..e46248cf9b 100644 --- a/crypto/rand/rand_local.h +++ b/crypto/rand/rand_local.h @@ -18,7 +18,6 @@ # include # include "internal/tsan_assist.h" # include "crypto/rand.h" -# include "crypto/rand_pool.h" # include "internal/numbers.h" @@ -31,67 +30,14 @@ # define SLAVE_RESEED_INTERVAL (1 << 16) # define MASTER_RESEED_TIME_INTERVAL (60 * 60) /* 1 hour */ # define SLAVE_RESEED_TIME_INTERVAL (7 * 60) /* 7 minutes */ - /* - * The number of bytes that constitutes an atomic lump of entropy with respect - * to the FIPS 140-2 section 4.9.2 Conditional Tests. The size is somewhat - * arbitrary, the smaller the value, the less entropy is consumed on first - * read but the higher the probability of the test failing by accident. - * - * The value is in bytes. - */ -#define CRNGT_BUFSIZ 16 - -/* - * Maximum input size for the DRBG (entropy, nonce, personalization string) - * - * NIST SP800 90Ar1 allows a maximum of (1 << 35) bits i.e., (1 << 32) bytes. - * - * We lower it to 'only' INT32_MAX bytes, which is equivalent to 2 gigabytes. - */ -# define DRBG_MAX_LENGTH INT32_MAX - -/* DRBG status values */ -typedef enum drbg_status_e { - DRBG_UNINITIALISED, - DRBG_READY, - DRBG_ERROR -} DRBG_STATUS; - -/* instantiate */ -typedef int (*RAND_DRBG_instantiate_fn)(RAND_DRBG *ctx, - const unsigned char *ent, - size_t entlen, - const unsigned char *nonce, - size_t noncelen, - const unsigned char *pers, - size_t perslen); -/* reseed */ -typedef int (*RAND_DRBG_reseed_fn)(RAND_DRBG *ctx, - const unsigned char *ent, - size_t entlen, - const unsigned char *adin, - size_t adinlen); -/* generate output */ -typedef int (*RAND_DRBG_generate_fn)(RAND_DRBG *ctx, - unsigned char *out, - size_t outlen, - const unsigned char *adin, - size_t adinlen); -/* uninstantiate */ -typedef int (*RAND_DRBG_uninstantiate_fn)(RAND_DRBG *ctx); - - -/* - * The state of all types of DRBGs, even though we only have CTR mode - * right now. + * The state of all types of DRBGs. */ struct rand_drbg_st { CRYPTO_RWLOCK *lock; /* The library context this DRBG is associated with, if any */ OPENSSL_CTX *libctx; RAND_DRBG *parent; - int secure; /* 1: allocated on the secure heap, 0: otherwise */ int type; /* the nid of the underlying algorithm */ unsigned short flags; /* various external flags */ @@ -113,20 +59,4 @@ struct rand_drbg_st { /* The global RAND method, and the global buffer and DRBG instance. */ extern RAND_METHOD rand_meth; -/* DRBG helpers */ -int rand_drbg_restart(RAND_DRBG *drbg, - const unsigned char *buffer, size_t len, size_t entropy); -size_t rand_drbg_seedlen(RAND_DRBG *drbg); - -/* - * Entropy call back for the FIPS 140-2 section 4.9.2 Conditional Tests. - * These need to be exposed for the unit tests. - */ -int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx, RAND_POOL *pool, - unsigned char *buf, unsigned char *md, - unsigned int *md_size); -extern int (*crngt_get_entropy)(OPENSSL_CTX *ctx, RAND_POOL *pool, - unsigned char *buf, unsigned char *md, - unsigned int *md_size); - #endif diff --git a/doc/man3/RAND_DRBG_new.pod b/doc/man3/RAND_DRBG_new.pod index 3ff98ae052..cd770fd673 100644 --- a/doc/man3/RAND_DRBG_new.pod +++ b/doc/man3/RAND_DRBG_new.pod @@ -35,9 +35,6 @@ RAND_DRBG_free unsigned int flags, RAND_DRBG *parent); - int RAND_DRBG_set(RAND_DRBG *drbg, - int type, unsigned int flags); - int RAND_DRBG_set_defaults(int type, unsigned int flags); int RAND_DRBG_instantiate(RAND_DRBG *drbg, @@ -47,18 +44,27 @@ RAND_DRBG_free void RAND_DRBG_free(RAND_DRBG *drbg); +Deprecated since OpenSSL 3.0, can be hidden entirely by defining +B with a suitable version value, see +L: + + int RAND_DRBG_set(RAND_DRBG *drbg, + int type, unsigned int flags); =head1 DESCRIPTION -RAND_DRBG_new_ex() and RAND_DRBG_secure_new_ex() -create a new DRBG instance of the given B, allocated from the heap resp. -the secure heap, for the given OPENSSL_CTX -(using OPENSSL_zalloc() resp. OPENSSL_secure_zalloc()). The parameter can -be NULL in which case the default OPENSSL_CTX is used. RAND_DRBG_new() and -RAND_DRBG_secure_new() are the same as RAND_DRBG_new_ex() and -RAND_DRBG_secure_new_ex() except that the default OPENSSL_CTX is always used. +RAND_DRBG_new_ex() and RAND_DRBG_secure_new_ex() create a new DRBG instance +of the given B for the given OPENSSL_CTX . +The parameter can be NULL in which case the default OPENSSL_CTX is used. +RAND_DRBG_new() and RAND_DRBG_secure_new() are the same as RAND_DRBG_new_ex() +and RAND_DRBG_secure_new_ex() except that the default OPENSSL_CTX is always +used. +As of OpenSSL 3.0, there is no different between the new and secure_new +functions. RAND_DRBG_set() initializes the B with the given B and B. +This function is deprecated. Applications should instead use +RAND_DRBG_new_ex() to create a new DRBG. RAND_DRBG_set_defaults() sets the default B and B for new DRBG instances. @@ -124,7 +130,7 @@ uninstantiated state. RAND_DRBG_new_ex(), RAND_DRBG_new(), RAND_DRBG_secure_new_ex() and RAND_DRBG_secure_new() return a pointer to a DRBG instance allocated on the -heap, resp. secure heap. +heap. RAND_DRBG_set(), RAND_DRBG_instantiate(), and @@ -149,6 +155,11 @@ To ensure that they are applied to the global and thread-local DRBG instances RAND_DRBG_set_defaults() before creating any thread and before calling any cryptographic routines that obtain random data directly or indirectly. +As of OpenSSL 3.0, RAND_DRBG_new() and RAND_DRBG_secure_new() are +functionally identical. The DRBG is allocated on the normal heap and its +sensitive state is allocated on the secure heap. Likewise for, +RAND_DRBG_new_ex() and RAND_DRBG_secure_new_ex(). + =head1 SEE ALSO L, @@ -158,6 +169,8 @@ L =head1 HISTORY +The RAND_DRBG_set() function was deprecated in OpenSSL 3.0. + The RAND_DRBG functions were added in OpenSSL 1.1.1. =head1 COPYRIGHT diff --git a/doc/man3/RAND_DRBG_set_callbacks.pod b/doc/man3/RAND_DRBG_set_callbacks.pod index d00397da62..0ae3028a5a 100644 --- a/doc/man3/RAND_DRBG_set_callbacks.pod +++ b/doc/man3/RAND_DRBG_set_callbacks.pod @@ -127,11 +127,12 @@ entropy from a live entropy source (section 5.5.2 of [NIST SP 800-90C]). It is up to the user to ensure that a live entropy source is configured and is being used. -The derivation function is disabled during initialization by calling the -RAND_DRBG_set() function with the RAND_DRBG_FLAG_CTR_NO_DF flag. -For more information on the derivation function and when it can be omitted, -see [NIST SP 800-90A Rev. 1]. Roughly speaking it can be omitted if the random -source has "full entropy", i.e., contains 8 bits of entropy per byte. +The derivation function is disabled by calling the RAND_DRBG_new_ex() +function with the RAND_DRBG_FLAG_CTR_NO_DF flag. For more information on +the derivation function and when it can be omitted, see [NIST SP 800-90A +Rev. 1]. Roughly speaking it can be omitted if the random source has "full +entropy", i.e., contains 8 bits of entropy per byte. In a FIPS context, +the derivation function can never be omitted. Even if a nonce is required, the B() and B() callbacks can be omitted by setting them to NULL. diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index e7b522a810..fe126ccd7a 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -180,26 +180,38 @@ extern "C" { #define OSSL_KDF_NAME_KBKDF "KBKDF" #define OSSL_KDF_NAME_KRB5KDF "KRB5KDF" -/* Know RAND names */ -#define OSSL_RAND_PARAM_STATUS "status" +/* Known RAND names */ +#define OSSL_RAND_PARAM_STATE "state" #define OSSL_RAND_PARAM_STRENGTH "strength" -#define OSSL_RAND_PARAM_RESEED_REQUESTS "reseed_requests" -#define OSSL_RAND_PARAM_RESEED_TIME_INTERVAL "reseed_time_interval" -#define OSSL_RAND_PARAM_MAX_REQUEST "max_request" -#define OSSL_RAND_PARAM_MIN_ENTROPYLEN "min_entropylen" -#define OSSL_RAND_PARAM_MAX_ENTROPYLEN "max_entropylen" -#define OSSL_RAND_PARAM_MIN_NONCELEN "min_noncelen" -#define OSSL_RAND_PARAM_MAX_NONCELEN "max_noncelen" -#define OSSL_RAND_PARAM_MAX_PERSLEN "max_perslen" -#define OSSL_RAND_PARAM_MAX_ADINLEN "max_adinlen" -#define OSSL_RAND_PARAM_RESEED_CTR "reseed_counter" -#define OSSL_RAND_PARAM_RESEED_PROP_CTR "reseed_prop_counter" -#define OSSL_RAND_PARAM_PROPERTIES OSSL_ALG_PARAM_PROPERTIES -#define OSSL_RAND_PARAM_DIGEST OSSL_ALG_PARAM_DIGEST -#define OSSL_RAND_PARAM_CIPHER OSSL_ALG_PARAM_CIPHER #define OSSL_RAND_PARAM_TEST_ENTROPY "test_entropy" #define OSSL_RAND_PARAM_TEST_NONCE "test_nonce" +/* RAND/DRBG names */ +#define OSSL_DRBG_PARAM_RESEED_REQUESTS "reseed_requests" +#define OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL "reseed_time_interval" +#define OSSL_DRBG_PARAM_MAX_REQUEST "max_request" +#define OSSL_DRBG_PARAM_MIN_ENTROPYLEN "min_entropylen" +#define OSSL_DRBG_PARAM_MAX_ENTROPYLEN "max_entropylen" +#define OSSL_DRBG_PARAM_MIN_NONCELEN "min_noncelen" +#define OSSL_DRBG_PARAM_MAX_NONCELEN "max_noncelen" +#define OSSL_DRBG_PARAM_MAX_PERSLEN "max_perslen" +#define OSSL_DRBG_PARAM_MAX_ADINLEN "max_adinlen" +#define OSSL_DRBG_PARAM_RESEED_CTR "reseed_counter" +#define OSSL_DRBG_PARAM_RESEED_TIME "reseed_time" +#define OSSL_DRBG_PARAM_PROPERTIES OSSL_ALG_PARAM_PROPERTIES +#define OSSL_DRBG_PARAM_DIGEST OSSL_ALG_PARAM_DIGEST +#define OSSL_DRBG_PARAM_CIPHER OSSL_ALG_PARAM_CIPHER +#define OSSL_DRBG_PARAM_MAC OSSL_ALG_PARAM_MAC +#define OSSL_DRBG_PARAM_USE_DF "use_derivation_function" + +/* DRBG call back parameters */ +#define OSSL_DRBG_PARAM_ENTROPY_REQUIRED "entropy_required" +#define OSSL_DRBG_PARAM_PREDICTION_RESISTANCE "prediction_resistance" +#define OSSL_DRBG_PARAM_MIN_LENGTH "minium_length" +#define OSSL_DRBG_PARAM_MAX_LENGTH "maxium_length" +#define OSSL_DRBG_PARAM_RANDOM_DATA "random_data" +#define OSSL_DRBG_PARAM_SIZE "size" + /* PKEY parameters */ /* Common PKEY parameters */ #define OSSL_PKEY_PARAM_BITS "bits" /* integer */ diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index acc758e462..af2a35efc0 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -362,7 +362,7 @@ OSSL_CORE_MAKE_FUNC(int, OP_kdf_set_ctx_params, # define OSSL_FUNC_RAND_VERIFY_ZEROIZATION 18 OSSL_CORE_MAKE_FUNC(void *, OP_rand_newctx, - (void *provctx, int secure, void *parent, + (void *provctx, void *parent, const OSSL_DISPATCH *parent_calls)) OSSL_CORE_MAKE_FUNC(void, OP_rand_freectx, (void *vctx)) OSSL_CORE_MAKE_FUNC(int, OP_rand_instantiate, @@ -379,12 +379,8 @@ OSSL_CORE_MAKE_FUNC(int, OP_rand_reseed, const unsigned char *ent, size_t ent_len, const unsigned char *addin, size_t addin_len)) OSSL_CORE_MAKE_FUNC(size_t, OP_rand_nonce, - (void *vctx, unsigned char *out, int strength, + (void *vctx, unsigned char *out, unsigned int strength, size_t min_noncelen, size_t max_noncelen)) -OSSL_CORE_MAKE_FUNC(int, OP_rand_set_callbacks, - (void *vctx, - OSSL_CALLBACK *get_entropy, OSSL_CALLBACK *cleanup_entropy, - OSSL_CALLBACK *get_nonce, OSSL_CALLBACK *cleanup_nonce)) OSSL_CORE_MAKE_FUNC(int, OP_rand_enable_locking, (void *vctx)) OSSL_CORE_MAKE_FUNC(int, OP_rand_lock, (void *vctx)) OSSL_CORE_MAKE_FUNC(void, OP_rand_unlock, (void *vctx)) @@ -396,6 +392,11 @@ OSSL_CORE_MAKE_FUNC(int, OP_rand_get_ctx_params, (void *vctx, OSSL_PARAM params[])) OSSL_CORE_MAKE_FUNC(int, OP_rand_set_ctx_params, (void *vctx, const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(void, OP_rand_set_callbacks, + (void *vctx, OSSL_INOUT_CALLBACK *get_entropy, + OSSL_CALLBACK *cleanup_entropy, + OSSL_INOUT_CALLBACK *get_nonce, + OSSL_CALLBACK *cleanup_nonce, void *arg)) OSSL_CORE_MAKE_FUNC(int, OP_rand_verify_zeroization, (void *vctx)) diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 2e6f855031..644a214a6e 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1082,12 +1082,11 @@ int EVP_RAND_is_a(const EVP_RAND *rand, const char *name); const OSSL_PROVIDER *EVP_RAND_provider(const EVP_RAND *rand); int EVP_RAND_get_params(EVP_RAND *rand, OSSL_PARAM params[]); -EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, int secure, - EVP_RAND_CTX *parent); +EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, EVP_RAND_CTX *parent); void EVP_RAND_CTX_free(EVP_RAND_CTX *ctx); EVP_RAND *EVP_RAND_CTX_rand(EVP_RAND_CTX *ctx); -int EVP_RAND_CTX_get_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[]); -int EVP_RAND_CTX_set_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[]); +int EVP_RAND_get_ctx_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[]); +int EVP_RAND_set_ctx_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[]); const OSSL_PARAM *EVP_RAND_gettable_params(const EVP_RAND *rand); const OSSL_PARAM *EVP_RAND_gettable_ctx_params(const EVP_RAND *rand); const OSSL_PARAM *EVP_RAND_settable_ctx_params(const EVP_RAND *rand); @@ -1099,26 +1098,27 @@ void EVP_RAND_names_do_all(const EVP_RAND *rand, void (*fn)(const char *name, void *data), void *data); -int EVP_RAND_CTX_instantiate(EVP_RAND_CTX *ctx, unsigned int strength, +__owur int EVP_RAND_instantiate(EVP_RAND_CTX *ctx, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, size_t pstr_len); +int EVP_RAND_uninstantiate(EVP_RAND_CTX *ctx); +__owur int EVP_RAND_generate(EVP_RAND_CTX *ctx, unsigned char *out, + size_t outlen, unsigned int strength, int prediction_resistance, - const unsigned char *pstr, size_t pstr_len); -int EVP_RAND_CTX_uninstantiate(EVP_RAND_CTX *ctx); -int EVP_RAND_CTX_generate(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen, - unsigned int strength, int prediction_resistance, - const unsigned char *addin, size_t addin_len); -int EVP_RAND_CTX_reseed(EVP_RAND_CTX *ctx, int prediction_resistance, - const unsigned char *ent, size_t ent_len, - const unsigned char *addin, size_t addin_len); -int EVP_RAND_CTX_nonce(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen); -int EVP_RAND_CTX_set_callbacks(const EVP_RAND_CTX *rand, - OSSL_CALLBACK *get_entropy, - OSSL_CALLBACK *cleanup_entropy, - OSSL_CALLBACK *get_nonce, - OSSL_CALLBACK *cleanup_nonce); -int EVP_RAND_CTX_enable_locking(EVP_RAND_CTX *ctx); -int EVP_RAND_CTX_verify_zeroization(EVP_RAND_CTX *ctx); -unsigned int EVP_RAND_CTX_strength(EVP_RAND_CTX *ctx); -int EVP_RAND_CTX_state(EVP_RAND_CTX *ctx); + const unsigned char *addin, size_t addin_len); +int EVP_RAND_reseed(EVP_RAND_CTX *ctx, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *addin, size_t addin_len); +__owur int EVP_RAND_nonce(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen); +__owur int EVP_RAND_enable_locking(EVP_RAND_CTX *ctx); +int EVP_RAND_set_callbacks(EVP_RAND_CTX *ctx, + OSSL_INOUT_CALLBACK *get_entropy, + OSSL_CALLBACK *cleanup_entropy, + OSSL_INOUT_CALLBACK *get_nonce, + OSSL_CALLBACK *cleanup_nonce, void *arg); +int EVP_RAND_verify_zeroization(EVP_RAND_CTX *ctx); +unsigned int EVP_RAND_strength(EVP_RAND_CTX *ctx); +int EVP_RAND_state(EVP_RAND_CTX *ctx); #define EVP_RAND_STATE_UNINITIALISED 0 #define EVP_RAND_STATE_READY 1 diff --git a/include/openssl/rand.h b/include/openssl/rand.h index a95e9d4103..d2db26a8ae 100644 --- a/include/openssl/rand.h +++ b/include/openssl/rand.h @@ -82,7 +82,6 @@ DEPRECATEDIN_1_1_0(void RAND_screen(void)) DEPRECATEDIN_1_1_0(int RAND_event(UINT, WPARAM, LPARAM)) # endif - #ifdef __cplusplus } #endif diff --git a/include/openssl/rand_drbg.h b/include/openssl/rand_drbg.h index c37df348d2..fd708d397c 100644 --- a/include/openssl/rand_drbg.h +++ b/include/openssl/rand_drbg.h @@ -80,11 +80,9 @@ extern "C" { */ RAND_DRBG *RAND_DRBG_new_ex(OPENSSL_CTX *ctx, int type, unsigned int flags, RAND_DRBG *parent); -RAND_DRBG *RAND_DRBG_secure_new_ex(OPENSSL_CTX *ctx, int type, - unsigned int flags, RAND_DRBG *parent); RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent); -RAND_DRBG *RAND_DRBG_secure_new(int type, unsigned int flags, RAND_DRBG *parent); -int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags); +DEPRECATEDIN_3_0(int RAND_DRBG_set(RAND_DRBG *drbg, int type, + unsigned int flags)) int RAND_DRBG_set_defaults(int type, unsigned int flags); int RAND_DRBG_instantiate(RAND_DRBG *drbg, const unsigned char *pers, size_t perslen); diff --git a/providers/defltprov.c b/providers/defltprov.c index c68e34770e..7c1ffc7763 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -338,13 +338,10 @@ static const OSSL_ALGORITHM deflt_keyexch[] = { }; static const OSSL_ALGORITHM deflt_rands[] = { - { "TEST-RAND", "provider=default", test_rng_functions }, + { "CTR-DRBG", "provider=default", drbg_ctr_functions }, { "HASH-DRBG", "provider=default", drbg_hash_functions }, -/* { "HMAC-DRBG", "provider=default", drbg_hmac_functions }, - { "CTR-DRBG", "provider=default", drbg_ctr_functions }, -*/ - { "CRNGT:continuous-rng-test", "provider=default", crngt_functions }, + { "TEST-RAND", "provider=default", test_rng_functions }, { NULL, NULL, NULL } }; diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 5927c9fedc..6a1b56eeae 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -470,17 +470,10 @@ static const OSSL_ALGORITHM fips_kdfs[] = { }; static const OSSL_ALGORITHM fips_rands[] = { - /* - * The TEST RNG must be first, so it can be suppressed after the power up - * tests are completed. - */ - { "TEST-RAND", "provider=fips", test_rng_functions }, + { "CTR-DRBG", "provider=fips", drbg_ctr_functions }, { "HASH-DRBG", "provider=fips", drbg_hash_functions }, -/* { "HMAC-DRBG", "provider=fips", drbg_hmac_functions }, - { "CTR-DRBG", "provider=fips", drbg_ctr_functions }, -*/ - { "CRNGT:continuous-rng-test", "provider=fips", crngt_functions }, + { "TEST-RAND", "provider=fips", test_rng_functions }, { NULL, NULL, NULL } }; diff --git a/providers/implementations/rands/build.info b/providers/implementations/rands/build.info index 5d55c27fe4..1e710bb510 100644 --- a/providers/implementations/rands/build.info +++ b/providers/implementations/rands/build.info @@ -1,8 +1,6 @@ SUBDIRS=seeding -# Missing: drbg_ctr.c -SOURCE[../../libfips.a]=drbg.c -SOURCE[../../libnonfips.a]=drbg.c +$COMMON=drbg.c test_rng.c drbg_ctr.c drbg_hash.c drbg_hmac.c crngt.c rand_pool.c -# Missing: drbg_hmac.c -SOURCE[../../libimplementations.a]=test_rng.c drbg_hash.c crngt.c +SOURCE[../../libfips.a]=$COMMON +SOURCE[../../libnonfips.a]=$COMMON diff --git a/providers/implementations/rands/crngt.c b/providers/implementations/rands/crngt.c index 2680f7b644..1777b33489 100644 --- a/providers/implementations/rands/crngt.c +++ b/providers/implementations/rands/crngt.c @@ -21,7 +21,7 @@ #include "internal/cryptlib.h" #include "prov/rand_pool.h" #include "drbg_local.h" -#include "seeding/seeding.h" +#include "prov/seeding.h" typedef struct crng_test_global_st { unsigned char crngt_prev[EVP_MAX_MD_SIZE]; diff --git a/providers/implementations/rands/drbg.c b/providers/implementations/rands/drbg.c index c9e4cd4b60..db8fce877a 100644 --- a/providers/implementations/rands/drbg.c +++ b/providers/implementations/rands/drbg.c @@ -11,12 +11,15 @@ #include #include #include +#include #include "crypto/rand.h" #include "drbg_local.h" #include "internal/thread_once.h" #include "crypto/cryptlib.h" -#include "seeding/seeding.h" -#include "crypto/rand_pool.h" +#include "prov/seeding.h" +#include "prov/rand_pool.h" +#include "prov/provider_ctx.h" +#include "prov/providercommonerr.h" /* * Support framework for NIST SP 800-90A DRBG @@ -31,26 +34,14 @@ * a much bigger deal than just re-setting an allocated resource.) */ -#ifdef FIPS_MODULE -# define get_entropy prov_crngt_get_entropy -# define cleanup_entropy prov_crngt_cleanup_entropy -#else -# define get_entropy prov_drbg_get_entropy -# define cleanup_entropy prov_drbg_cleanup_entropy -#endif - /* NIST SP 800-90A DRBG recommends the use of a personalization string. */ static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING; -static unsigned int master_reseed_interval = MASTER_RESEED_INTERVAL; -static unsigned int slave_reseed_interval = SLAVE_RESEED_INTERVAL; - -static time_t master_reseed_time_interval = MASTER_RESEED_TIME_INTERVAL; -static time_t slave_reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL; - static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, int function); +static int rand_drbg_restart(PROV_DRBG *drbg); + int drbg_lock(void *vctx) { PROV_DRBG *drbg = vctx; @@ -71,14 +62,12 @@ void drbg_unlock(void *vctx) static int drbg_lock_parent(PROV_DRBG *drbg) { void *parent = drbg->parent; - const OSSL_DISPATCH *pfunc; - if (parent != NULL) { - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_LOCK); - if (pfunc != NULL && !OSSL_get_OP_rand_lock(pfunc)(parent)) { - ERR_raise(ERR_LIB_PROV, RAND_R_PARENT_LOCKING_NOT_ENABLED); - return 0; - } + if (parent != NULL + && drbg->parent_lock != NULL + && !drbg->parent_lock(parent)) { + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); + return 0; } return 1; } @@ -86,74 +75,62 @@ static int drbg_lock_parent(PROV_DRBG *drbg) static void drbg_unlock_parent(PROV_DRBG *drbg) { void *parent = drbg->parent; - const OSSL_DISPATCH *pfunc; - if (parent != NULL) { - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_UNLOCK); - if (pfunc != NULL) - OSSL_get_OP_rand_unlock(pfunc)(parent); - } + if (parent != NULL && drbg->parent_unlock != NULL) + drbg->parent_unlock(parent); } -static int get_parent_strength(PROV_DRBG *drbg, int *str) +static int get_parent_strength(PROV_DRBG *drbg, unsigned int *str) { OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; - const OSSL_DISPATCH *pfunc; void *parent = drbg->parent; + int res; - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS); - if (pfunc == NULL) { - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH); + if (drbg->parent_get_ctx_params == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); return 0; } - *params = OSSL_PARAM_construct_int(OSSL_RAND_PARAM_STRENGTH, str); + + *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, str); if (!drbg_lock_parent(drbg)) { - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_LOCK_PARENT); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); return 0; } - if (!OSSL_get_OP_rand_get_ctx_params(pfunc)(parent, params)) { - drbg_unlock_parent(drbg); - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH); + res = drbg->parent_get_ctx_params(parent, params); + drbg_unlock_parent(drbg); + if (!res) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); return 0; } - drbg_unlock_parent(drbg); return 1; } static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) { OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; - const OSSL_DISPATCH *pfunc; void *parent = drbg->parent; unsigned int r; - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS); - if (pfunc == NULL) { - ERR_raise(ERR_LIB_PROV, - RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER); - goto err; - } - *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_RESEED_PROP_CTR, &r); + *params = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_CTR, &r); if (!drbg_lock_parent(drbg)) { - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_LOCK_PARENT); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); goto err; } - if (!OSSL_get_OP_rand_get_ctx_params(pfunc)(parent, params)) { + if (!drbg->parent_get_ctx_params(parent, params)) { drbg_unlock_parent(drbg); - ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_RESEED_PROP_CTR); + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_RESEED_PROP_CTR); goto err; } drbg_unlock_parent(drbg); return r; err: - r = tsan_load(&drbg->reseed_prop_counter) - 2; + r = tsan_load(&drbg->reseed_counter) - 2; if (r == 0) r = UINT_MAX; return r; } -#ifndef FIPS_MODULE /* * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) * @@ -161,20 +138,19 @@ static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) * is fetched using the parent's RAND_DRBG_generate(). * * Otherwise, the entropy is polled from the system entropy sources - * using rand_pool_acquire_entropy(). + * using prov_pool_acquire_entropy(). * * If a random pool has been added to the DRBG using RAND_add(), then * its entropy will be used up first. */ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, - int entropy, size_t min_len, size_t max_len, - int prediction_resistance) + int entropy, size_t min_len, + size_t max_len, int prediction_resistance) { size_t ret = 0; size_t entropy_available = 0; RAND_POOL *pool; - int p_str; - const OSSL_DISPATCH *pfunc; + unsigned int p_str; if (drbg->parent != NULL) { if (!get_parent_strength(drbg, &p_str)) @@ -184,7 +160,7 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, * We currently don't support the algorithm from NIST SP 800-90C * 10.1.2 to use a weaker DRBG as source */ - RANDerr(0, RAND_R_PARENT_STRENGTH_TOO_WEAK); + RANDerr(0, PROV_R_PARENT_STRENGTH_TOO_WEAK); return 0; } } @@ -193,9 +169,11 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, pool = drbg->seed_pool; pool->entropy_requested = entropy; } else { - pool = rand_pool_new(entropy, drbg->secure, min_len, max_len); - if (pool == NULL) + pool = rand_pool_new(entropy, 1, min_len, max_len); + if (pool == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; + } } if (drbg->parent != NULL) { @@ -213,25 +191,23 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, * generating bits from it. (Note: taking the lock will be a no-op * if locking if drbg->parent->lock == NULL.) */ - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GENERATE); - if (pfunc == NULL) - return 0; + if (drbg->parent_generate == NULL) + goto err; drbg_lock_parent(drbg); - if (OSSL_get_OP_rand_generate(pfunc)(drbg->parent, buffer, bytes_needed, - drbg->strength, - prediction_resistance, - (unsigned char *)&drbg, - sizeof(drbg)) != 0) + if (drbg->parent_generate(drbg->parent, buffer, bytes_needed, + drbg->strength, prediction_resistance, + (unsigned char *)&drbg, + sizeof(drbg)) != 0) bytes = bytes_needed; - drbg->reseed_next_counter = get_parent_reseed_count(drbg); drbg_unlock_parent(drbg); + drbg->parent_reseed_counter = get_parent_reseed_count(drbg); rand_pool_add_end(pool, bytes, 8 * bytes); entropy_available = rand_pool_entropy_available(pool); } } else { /* Get entropy by polling system entropy sources. */ - entropy_available = rand_pool_acquire_entropy(pool); + entropy_available = prov_pool_acquire_entropy(pool); } if (entropy_available > 0) { @@ -239,6 +215,7 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, *pout = rand_pool_detach(pool); } +err: if (drbg->seed_pool == NULL) rand_pool_free(pool); return ret; @@ -251,14 +228,68 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, static void prov_drbg_cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) { - if (drbg->seed_pool == NULL) { - if (drbg->secure) - OPENSSL_secure_clear_free(out, outlen); - else - OPENSSL_clear_free(out, outlen); + OSSL_PARAM params[3], *p = params; + + if (drbg->get_entropy_fn != NULL) { + if (drbg->cleanup_entropy_fn != NULL) { + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE, + &outlen); + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)&out, 0); + *p = OSSL_PARAM_construct_end(); + + drbg->cleanup_entropy_fn(params, drbg->callback_arg); + } + } else if (drbg->seed_pool == NULL) { + OPENSSL_secure_clear_free(out, outlen); } } + +static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, + size_t min_len, size_t max_len, + int prediction_resistance) +{ + if (drbg->get_entropy_fn != NULL) { + OSSL_PARAM params[6], *p = params; + OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED, + &entropy); + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_PREDICTION_RESISTANCE, + &prediction_resistance); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH, + &min_len); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH, + &max_len); + *p = OSSL_PARAM_construct_end(); + *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)pout, 0); + + if (drbg->get_entropy_fn(params, out, drbg->callback_arg)) + return out->return_size; + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_ENTROPY); + return 0; + } + +#ifdef FIPS_MODULE + if (drbg->parent == NULL) + return prov_crngt_get_entropy(drbg, pout, entropy, min_len, max_len, + prediction_resistance); +#endif + + return prov_drbg_get_entropy(drbg, pout, entropy, min_len, max_len, + prediction_resistance); +} + +static void cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) +{ +#ifdef FIPS_MODULE + if (drbg->parent == NULL) + prov_crngt_cleanup_entropy(drbg, out, outlen); + else #endif + prov_drbg_cleanup_entropy(drbg, out, outlen); +} #ifndef PROV_RAND_GET_RANDOM_NONCE typedef struct prov_drbg_nonce_global_st { @@ -311,26 +342,63 @@ static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { - size_t ret = 0; + size_t ret = 0, n; RAND_POOL *pool; + unsigned char *buf = NULL; + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(drbg->provctx); PROV_DRBG_NONCE_GLOBAL *dngbl - = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX, + = openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_NONCE_INDEX, &drbg_nonce_ossl_ctx_method); + OSSL_PARAM params[5], *p = params; + OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; struct { void *instance; int count; } data; - if (dngbl == NULL) return 0; + if (drbg->get_nonce_fn != NULL) { + *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED, + &entropy); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH, + &min_len); + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH, + &max_len); + *p = OSSL_PARAM_construct_end(); + *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)pout, 0); + + if (drbg->get_nonce_fn(params, out, drbg->callback_arg)) + return out->return_size; + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_NONCE); + return 0; + } + if (drbg->parent != NULL) { + if (drbg->parent_nonce != NULL) { + n = drbg->parent_nonce(drbg->parent, NULL, 0, drbg->min_noncelen, + drbg->max_noncelen); + if (n > 0 && (buf = OPENSSL_malloc(n)) != NULL) { + ret = drbg->parent_nonce(drbg->parent, buf, 0, + drbg->min_noncelen, + drbg->max_noncelen); + if (ret == n) { + *pout = buf; + return ret; + } + OPENSSL_free(buf); + } + } + } + + /* Use the built in nonce source */ memset(&data, 0, sizeof(data)); pool = rand_pool_new(0, 0, min_len, max_len); if (pool == NULL) return 0; - if (rand_pool_add_nonce_data(pool) == 0) + if (prov_pool_add_nonce_data(pool) == 0) goto err; data.instance = drbg; @@ -348,17 +416,30 @@ static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, return ret; } -#endif -/* - * Implements the cleanup_nonce() callback (see PROV_DRBG_set_callbacks()) - * - */ -static void prov_drbg_cleanup_nonce(PROV_DRBG *drbg, - unsigned char *out, size_t outlen) +static void prov_drbg_clear_nonce(PROV_DRBG *drbg, unsigned char *nonce, + size_t noncelen) { - OPENSSL_clear_free(out, outlen); + OSSL_PARAM params[3], *p = params; + + if (drbg->get_nonce_fn != NULL) { + if (drbg->cleanup_nonce_fn != NULL) { + *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE, + &noncelen); + *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, + (void **)&nonce, 0); + *p = OSSL_PARAM_construct_end(); + + drbg->cleanup_nonce_fn(params, drbg->callback_arg); + } + } else { + OPENSSL_clear_free(nonce, noncelen); + } } +#else +# define prov_drbg_clear_nonce(drbg, nonce, len) \ + OPENSSL_clear_free((nonce), (len)) +#endif /* PROV_RAND_GET_RANDOM_NONCE */ /* * Instantiate |drbg|, after it has been initialized. Use |pers| and @@ -368,23 +449,16 @@ static void prov_drbg_cleanup_nonce(PROV_DRBG *drbg, * * Returns 1 on success, 0 on failure. */ -int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, +int PROV_DRBG_instantiate(PROV_DRBG *drbg, unsigned int strength, int prediction_resistance, - const unsigned char *pers, size_t perslen, - int (*ifnc)(PROV_DRBG *drbg, - const unsigned char *ent, size_t ent_len, - const unsigned char *nonce, - size_t nonce_len, - const unsigned char *pstr, - size_t pstr_len)) + const unsigned char *pers, size_t perslen) { unsigned char *nonce = NULL, *entropy = NULL; size_t noncelen = 0, entropylen = 0; size_t min_entropy, min_entropylen, max_entropylen; - const OSSL_DISPATCH *pnonce; if (strength > drbg->strength) { - PROVerr(0, RAND_R_INSUFFICIENT_DRBG_STRENGTH); + PROVerr(0, PROV_R_INSUFFICIENT_DRBG_STRENGTH); goto end; } min_entropy = drbg->strength; @@ -396,50 +470,54 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, perslen = sizeof(ossl_pers_string); } if (perslen > drbg->max_perslen) { - PROVerr(0, RAND_R_PERSONALISATION_STRING_TOO_LONG); + PROVerr(0, PROV_R_PERSONALISATION_STRING_TOO_LONG); goto end; } - if (drbg->state != DRBG_UNINITIALISED) { - if (drbg->state == DRBG_ERROR) - PROVerr(0, RAND_R_IN_ERROR_STATE); + if (drbg->state != EVP_RAND_STATE_UNINITIALISED) { + if (drbg->state == EVP_RAND_STATE_ERROR) + PROVerr(0, PROV_R_IN_ERROR_STATE); else - PROVerr(0, RAND_R_ALREADY_INSTANTIATED); + PROVerr(0, PROV_R_ALREADY_INSTANTIATED); goto end; } - drbg->state = DRBG_ERROR; + drbg->state = EVP_RAND_STATE_ERROR; if (drbg->min_noncelen > 0) { + if (drbg->parent_nonce != NULL) { + noncelen = drbg->parent_nonce(drbg->parent, NULL, drbg->strength, + drbg->min_noncelen, + drbg->max_noncelen); + if (noncelen == 0) { + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + nonce = OPENSSL_malloc(noncelen); + if (nonce == NULL) { + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); + goto end; + } + if (noncelen != drbg->parent_nonce(drbg->parent, nonce, + drbg->strength, + drbg->min_noncelen, + drbg->max_noncelen)) { + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); + OPENSSL_free(nonce); + } #ifndef PROV_RAND_GET_RANDOM_NONCE - if (drbg->parent != NULL) + } else if (drbg->parent != NULL) { #endif - { - pnonce = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_NONCE); - if (pnonce == NULL) { - /* - * NIST SP800-90Ar1 section 9.1 says you can combine getting - * the entropy and nonce in 1 call by increasing the entropy - * with 50% and increasing the minimum length to accommodate - * the length of the nonce. We do this in case a nonce is - * required and there is no parental nonce capability. - */ - min_entropy += drbg->strength / 2; - min_entropylen += drbg->min_noncelen; - max_entropylen += drbg->max_noncelen; - } else { - drbg_lock_parent(drbg); - noncelen = OSSL_get_OP_rand_nonce(pnonce)(drbg->parent, &nonce, - drbg->strength / 2, - drbg->min_noncelen, - drbg->max_noncelen); - drbg_unlock_parent(drbg); - if (noncelen < drbg->min_noncelen - || noncelen > drbg->max_noncelen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_NONCE); - goto end; - } - } + /* + * NIST SP800-90Ar1 section 9.1 says you can combine getting + * the entropy and nonce in 1 call by increasing the entropy + * with 50% and increasing the minimum length to accommodate + * the length of the nonce. We do this in case a nonce is + * required and there is no parental nonce capability. + */ + min_entropy += drbg->strength / 2; + min_entropylen += drbg->min_noncelen; + max_entropylen += drbg->max_noncelen; } #ifndef PROV_RAND_GET_RANDOM_NONCE else { /* parent == NULL */ @@ -448,17 +526,17 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, drbg->max_noncelen); if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_NONCE); + PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); goto end; } } #endif } - drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); + drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); if (drbg->reseed_next_counter) { drbg->reseed_next_counter++; - if(!drbg->reseed_next_counter) + if (!drbg->reseed_next_counter) drbg->reseed_next_counter = 1; } @@ -467,30 +545,43 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, prediction_resistance); if (entropylen < min_entropylen || entropylen > max_entropylen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_ENTROPY); + PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY); goto end; } - if (!ifnc(drbg, entropy, entropylen, nonce, noncelen, pers, perslen)) { - PROVerr(0, RAND_R_ERROR_INSTANTIATING_DRBG); + if (!drbg->instantiate(drbg, entropy, entropylen, nonce, noncelen, + pers, perslen)) { + PROVerr(0, PROV_R_ERROR_INSTANTIATING_DRBG); goto end; } - drbg->state = DRBG_READY; + drbg->state = EVP_RAND_STATE_READY; drbg->reseed_gen_counter = 1; drbg->reseed_time = time(NULL); - tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); + tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); end: if (entropy != NULL) cleanup_entropy(drbg, entropy, entropylen); - if (nonce != NULL) - prov_drbg_cleanup_nonce(drbg, nonce, noncelen); - if (drbg->state == DRBG_READY) + prov_drbg_clear_nonce(drbg, nonce, noncelen); + if (drbg->state == EVP_RAND_STATE_READY) return 1; return 0; } +/* + * Uninstantiate |drbg|. Must be instantiated before it can be used. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int PROV_DRBG_uninstantiate(PROV_DRBG *drbg) +{ + drbg->state = EVP_RAND_STATE_UNINITIALISED; + return 1; +} + /* * Reseed |drbg|, mixing in the specified data * @@ -500,60 +591,101 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, */ int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance, const unsigned char *ent, size_t ent_len, - const unsigned char *adin, size_t adinlen, - int (*reseed)(PROV_DRBG *drbg, - const unsigned char *ent, size_t ent_len, - const unsigned char *adin, size_t adin_len)) + const unsigned char *adin, size_t adinlen) { unsigned char *entropy = NULL; size_t entropylen = 0; - if (drbg->state == DRBG_ERROR) { - PROVerr(0, RAND_R_IN_ERROR_STATE); - return 0; + if (drbg->state != EVP_RAND_STATE_READY) { + /* try to recover from previous errors */ + rand_drbg_restart(drbg); + + if (drbg->state == EVP_RAND_STATE_ERROR) { + PROVerr(0, PROV_R_IN_ERROR_STATE); + return 0; + } + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { + PROVerr(0, PROV_R_NOT_INSTANTIATED); + return 0; + } } - if (drbg->state == DRBG_UNINITIALISED) { - PROVerr(0, RAND_R_NOT_INSTANTIATED); - return 0; + + if (ent != NULL) { + if (ent_len < drbg->min_entropylen) { + RANDerr(0, RAND_R_ENTROPY_OUT_OF_RANGE); + drbg->state = EVP_RAND_STATE_ERROR; + return 0; + } + if (ent_len > drbg->max_entropylen) { + RANDerr(0, RAND_R_ENTROPY_INPUT_TOO_LONG); + drbg->state = EVP_RAND_STATE_ERROR; + return 0; + } } if (adin == NULL) { adinlen = 0; } else if (adinlen > drbg->max_adinlen) { - PROVerr(0, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + PROVerr(0, PROV_R_ADDITIONAL_INPUT_TOO_LONG); return 0; } - drbg->state = DRBG_ERROR; + drbg->state = EVP_RAND_STATE_ERROR; - drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); + drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); if (drbg->reseed_next_counter) { drbg->reseed_next_counter++; - if(!drbg->reseed_next_counter) + if (!drbg->reseed_next_counter) drbg->reseed_next_counter = 1; } + if (ent != NULL) { +#ifdef FIP_MODULE + /* + * NIST SP-800-90A mandates that entropy *shall not* be provided + * by the consuming application. Instead the data is added as additional + * input. + * + * (NIST SP-800-90Ar1, Sections 9.1 and 9.2) + */ + if (!drbg->reseed(drbg, NULL, 0, ent, ent_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); + return 0; + } +#else + if (!drbg->reseed(drbg, ent, ent_len, adin, adinlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); + return 0; + } + /* There isn't much point adding the same additional input twice */ + adin = NULL; + adinlen = 0; +#endif + } + + /* Reseed using our sources in addition */ entropylen = get_entropy(drbg, &entropy, drbg->strength, drbg->min_entropylen, drbg->max_entropylen, prediction_resistance); if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) { - PROVerr(0, RAND_R_ERROR_RETRIEVING_ENTROPY); + PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY); goto end; } - if (!reseed(drbg, entropy, entropylen, adin, adinlen)) + if (!drbg->reseed(drbg, entropy, entropylen, adin, adinlen)) goto end; - drbg->state = DRBG_READY; + drbg->state = EVP_RAND_STATE_READY; drbg->reseed_gen_counter = 1; drbg->reseed_time = time(NULL); - tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); + tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); + if (drbg->parent != NULL) + drbg->parent_reseed_counter = get_parent_reseed_count(drbg); end: - if (entropy != NULL) - OPENSSL_cleanse(entropy, entropylen); - if (drbg->state == DRBG_READY) + cleanup_entropy(drbg, entropy, entropylen); + if (drbg->state == EVP_RAND_STATE_READY) return 1; return 0; } @@ -569,35 +701,36 @@ int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance, * */ int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, - int strength, int prediction_resistance, - const unsigned char *adin, size_t adinlen, - int (*generate)(PROV_DRBG *, unsigned char *out, - size_t outlen, const unsigned char *adin, - size_t adin_len), - int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, - size_t ent_len, const unsigned char *adin, - size_t adin_len)) + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adinlen) { int fork_id; int reseed_required = 0; - if (drbg->state != DRBG_READY) { - if (drbg->state == DRBG_ERROR) { - PROVerr(0, RAND_R_IN_ERROR_STATE); + if (drbg->state != EVP_RAND_STATE_READY) { + /* try to recover from previous errors */ + rand_drbg_restart(drbg); + + if (drbg->state == EVP_RAND_STATE_ERROR) { + PROVerr(0, PROV_R_IN_ERROR_STATE); return 0; } - if (drbg->state == DRBG_UNINITIALISED) { - PROVerr(0, RAND_R_NOT_INSTANTIATED); + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { + PROVerr(0, PROV_R_NOT_INSTANTIATED); return 0; } } + if (strength > drbg->strength) { + PROVerr(0, PROV_R_INSUFFICIENT_DRBG_STRENGTH); + return 0; + } if (outlen > drbg->max_request) { - PROVerr(0, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG); + PROVerr(0, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG); return 0; } if (adinlen > drbg->max_adinlen) { - PROVerr(0, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + PROVerr(0, PROV_R_ADDITIONAL_INPUT_TOO_LONG); return 0; } @@ -618,28 +751,23 @@ int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, || now - drbg->reseed_time >= drbg->reseed_time_interval) reseed_required = 1; } - if (drbg->parent != NULL) { - unsigned int reseed_counter = 0; - - if (reseed_counter > 0 - && get_parent_reseed_count(drbg) != - tsan_load(&drbg->reseed_prop_counter)) - reseed_required = 1; - } + if (drbg->parent != NULL + && get_parent_reseed_count(drbg) != drbg->parent_reseed_counter) + reseed_required = 1; if (reseed_required || prediction_resistance) { if (!PROV_DRBG_reseed(drbg, prediction_resistance, NULL, 0, - adin, adinlen, reseed)) { - PROVerr(0, RAND_R_RESEED_ERROR); + adin, adinlen)) { + PROVerr(0, PROV_R_RESEED_ERROR); return 0; } adin = NULL; adinlen = 0; } - if (!generate(drbg, out, outlen, adin, adinlen)) { - drbg->state = DRBG_ERROR; - PROVerr(0, RAND_R_GENERATE_ERROR); + if (!drbg->generate(drbg, out, outlen, adin, adinlen)) { + drbg->state = EVP_RAND_STATE_ERROR; + PROVerr(0, PROV_R_GENERATE_ERROR); return 0; } @@ -648,83 +776,73 @@ int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, return 1; } -#if 0 /* - * Calculates the minimum length of a full entropy buffer - * which is necessary to seed (i.e. instantiate) the DRBG - * successfully. + * Restart |drbg|, using the specified entropy or additional input + * + * Tries its best to get the drbg instantiated by all means, + * regardless of its current state. + * + * Optionally, a |buffer| of |len| random bytes can be passed, + * which is assumed to contain at least |entropy| bits of entropy. + * + * If |entropy| > 0, the buffer content is used as entropy input. + * + * If |entropy| == 0, the buffer content is used as additional input + * + * Returns 1 on success, 0 on failure. + * + * This function is used internally only. */ -size_t prov_drbg_seedlen(PROV_DRBG *drbg) +static int rand_drbg_restart(PROV_DRBG *drbg) { - /* - * If no os entropy source is available then PROV_seed(buffer, bufsize) - * is expected to succeed if and only if the buffer length satisfies - * the following requirements, which follow from the calculations - * in PROV_DRBG_instantiate(). - */ - size_t min_entropy = drbg->strength; - size_t min_entropylen = drbg->min_entropylen; - - /* - * Extra entropy for the random nonce in the absence of a - * get_nonce callback, see comment in PROV_DRBG_instantiate(). - */ - if (drbg->min_noncelen > 0) { -#ifndef PROV_RAND_GET_RANDOM_NONCE - if (drbg->parent != NULL) -#endif - if (find_call(drbg->parent_dispatch, - OSSL_FUNC_RAND_NONCE) == NULL) { - min_entropy += drbg->strength / 2; - min_entropylen += drbg->min_noncelen; - } + if (drbg->seed_pool != NULL) { + drbg->state = EVP_RAND_STATE_ERROR; + rand_pool_free(drbg->seed_pool); + drbg->seed_pool = NULL; + RANDerr(0, ERR_R_INTERNAL_ERROR); + return 0; } - /* - * Convert entropy requirement from bits to bytes - * (dividing by 8 without rounding upwards, because - * all entropy requirements are divisible by 8). - */ - min_entropy >>= 3; + /* repair error state */ + if (drbg->state == EVP_RAND_STATE_ERROR) + drbg->uninstantiate(drbg); + + /* repair uninitialized state */ + if (drbg->state == EVP_RAND_STATE_UNINITIALISED) + /* reinstantiate drbg */ + PROV_DRBG_instantiate(drbg, drbg->strength, 0, NULL, 0); - /* Return a value that satisfies both requirements */ - return min_entropy > min_entropylen ? min_entropy : min_entropylen; + rand_pool_free(drbg->seed_pool); + drbg->seed_pool = NULL; + return drbg->state == EVP_RAND_STATE_READY; } -#endif /* Provider support from here down */ static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, int function) { if (dispatch != NULL) - while (dispatch->function_id != 0) + while (dispatch->function_id != 0) { if (dispatch->function_id == function) return dispatch; + dispatch++; + } return NULL; } int drbg_enable_locking(void *vctx) { PROV_DRBG *drbg = vctx; - const OSSL_DISPATCH *pfunc; - if (drbg == NULL) - return 1; - if (drbg->lock == NULL) { - if (drbg->state != DRBG_UNINITIALISED) { - ERR_raise(ERR_LIB_PROV, RAND_R_DRBG_ALREADY_INITIALIZED); - return 0; - } - - pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING); - if (pfunc != NULL) - if (!OSSL_get_OP_rand_enable_locking(pfunc)(drbg->parent)) { - ERR_raise(ERR_LIB_PROV, RAND_R_PARENT_LOCKING_NOT_ENABLED); + if (drbg != NULL && drbg->lock == NULL) { + if (drbg->parent_enable_locking != NULL) + if (!drbg->parent_enable_locking(drbg->parent)) { + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); return 0; } drbg->lock = CRYPTO_THREAD_lock_new(); if (drbg->lock == NULL) { - ERR_raise(ERR_LIB_PROV, RAND_R_FAILED_TO_CREATE_LOCK); + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); return 0; } } @@ -739,22 +857,49 @@ int drbg_enable_locking(void *vctx) * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ -PROV_DRBG *prov_rand_drbg_new(void *provctx, int secure, void *parent, - const OSSL_DISPATCH *parent_dispatch, - int (*dnew)(PROV_DRBG *ctx, int secure)) +PROV_DRBG *prov_rand_drbg_new + (void *provctx, void *parent, const OSSL_DISPATCH *p_dispatch, + int (*dnew)(PROV_DRBG *ctx), + int (*instantiate)(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen), + int (*uninstantiate)(PROV_DRBG *ctx), + int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len), + int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len)) { PROV_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg)); - int p_str; + unsigned int p_str; + const OSSL_DISPATCH *pfunc; if (drbg == NULL) { ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return NULL; } - drbg->libctx = provctx; - drbg->secure = secure; + drbg->provctx = provctx; + drbg->instantiate = instantiate; + drbg->uninstantiate = uninstantiate; + drbg->reseed = reseed; + drbg->generate = generate; + drbg->fork_id = openssl_get_fork_id(); + + /* Extract parent's functions */ drbg->parent = parent; - drbg->parent_dispatch = parent_dispatch; + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING)) != NULL) + drbg->parent_enable_locking = OSSL_get_OP_rand_enable_locking(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_LOCK)) != NULL) + drbg->parent_lock = OSSL_get_OP_rand_lock(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_UNLOCK)) != NULL) + drbg->parent_unlock = OSSL_get_OP_rand_unlock(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS)) != NULL) + drbg->parent_get_ctx_params = OSSL_get_OP_rand_get_ctx_params(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GENERATE)) != NULL) + drbg->parent_generate = OSSL_get_OP_rand_generate(pfunc); + if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_NONCE)) != NULL) + drbg->parent_nonce = OSSL_get_OP_rand_nonce(pfunc); /* Set some default maximums up */ drbg->max_entropylen = DRBG_MAX_LENGTH; @@ -762,21 +907,11 @@ PROV_DRBG *prov_rand_drbg_new(void *provctx, int secure, void *parent, drbg->max_perslen = DRBG_MAX_LENGTH; drbg->max_adinlen = DRBG_MAX_LENGTH; drbg->reseed_gen_counter = 1; + drbg->reseed_counter = 1; + drbg->reseed_interval = RESEED_INTERVAL; + drbg->reseed_time_interval = TIME_INTERVAL; - /* TODO(3.0) clean this up */ - if (parent == NULL) { - drbg->reseed_interval = master_reseed_interval; - drbg->reseed_time_interval = master_reseed_time_interval; - } else { - /* - * Do not provide nonce callbacks, the child DRBGs will - * obtain their nonce using random bits from the parent. - */ - drbg->reseed_interval = slave_reseed_interval; - drbg->reseed_time_interval = slave_reseed_time_interval; - } - - if (!dnew(drbg, secure)) + if (!dnew(drbg)) goto err; if (parent != NULL) { @@ -787,7 +922,7 @@ PROV_DRBG *prov_rand_drbg_new(void *provctx, int secure, void *parent, * We currently don't support the algorithm from NIST SP 800-90C * 10.1.2 to use a weaker DRBG as source */ - ERR_raise(ERR_LIB_PROV, RAND_R_PARENT_STRENGTH_TOO_WEAK); + ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK); goto err; } } @@ -805,16 +940,14 @@ void prov_rand_drbg_free(PROV_DRBG *drbg) rand_pool_free(drbg->adin_pool); CRYPTO_THREAD_lock_free(drbg->lock); -#ifndef FIPS_MODULE - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RAND_DRBG, drbg, &drbg->ex_data); -#endif + OPENSSL_free(drbg); } int drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]) { OSSL_PARAM *p; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATUS); + p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); if (p != NULL && !OSSL_PARAM_set_int(p, drbg->state)) return 0; @@ -822,49 +955,49 @@ int drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]) if (p != NULL && !OSSL_PARAM_set_int(p, drbg->strength)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_REQUEST); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_request)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MIN_ENTROPYLEN); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_ENTROPYLEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_entropylen)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_ENTROPYLEN); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ENTROPYLEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_entropylen)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MIN_NONCELEN); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_NONCELEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_noncelen)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_NONCELEN); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_NONCELEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_noncelen)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_PERSLEN); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_PERSLEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_perslen)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_ADINLEN); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ADINLEN); if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_adinlen)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_RESEED_CTR); - if (p != NULL && !OSSL_PARAM_set_uint(p, drbg->reseed_gen_counter)) + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); + if (p != NULL && !OSSL_PARAM_set_uint(p, drbg->reseed_interval)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_RESEED_REQUESTS); - if (p != NULL && !OSSL_PARAM_set_uint(p, drbg->reseed_interval)) + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME); + if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_RESEED_TIME_INTERVAL); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time_interval)) return 0; - p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_RESEED_PROP_CTR); + p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_CTR); if (p != NULL - && !OSSL_PARAM_set_uint(p, tsan_load(&drbg->reseed_prop_counter))) + && !OSSL_PARAM_set_uint(p, tsan_load(&drbg->reseed_counter))) return 0; return 1; } @@ -873,12 +1006,31 @@ int drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]) { const OSSL_PARAM *p; - p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_RESEED_REQUESTS); + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); if (p != NULL && !OSSL_PARAM_get_uint(p, &drbg->reseed_interval)) return 0; - p = OSSL_PARAM_locate_const(params, OSSL_RAND_PARAM_RESEED_TIME_INTERVAL); + p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); if (p != NULL && !OSSL_PARAM_get_time_t(p, &drbg->reseed_time_interval)) return 0; return 1; } + +int drbg_set_callbacks(void *vctx, OSSL_INOUT_CALLBACK *get_entropy_fn, + OSSL_CALLBACK *cleanup_entropy_fn, + OSSL_INOUT_CALLBACK *get_nonce_fn, + OSSL_CALLBACK *cleanup_nonce_fn, void *arg) +{ + PROV_DRBG *drbg = vctx; + + if (drbg->state != EVP_RAND_STATE_UNINITIALISED + || drbg->parent != NULL) + return 0; + + drbg->get_entropy_fn = get_entropy_fn; + drbg->cleanup_entropy_fn = cleanup_entropy_fn; + drbg->get_nonce_fn = get_nonce_fn; + drbg->cleanup_nonce_fn = cleanup_nonce_fn; + drbg->callback_arg = arg; + return 1; +} diff --git a/providers/implementations/rands/drbg_ctr.c b/providers/implementations/rands/drbg_ctr.c index 33e1b324c6..14f8b9fbc8 100644 --- a/providers/implementations/rands/drbg_ctr.c +++ b/providers/implementations/rands/drbg_ctr.c @@ -12,14 +12,50 @@ #include #include #include +#include +#include "e_os.h" /* strcasecmp */ #include "crypto/modes.h" #include "internal/thread_once.h" -#include "rand_local.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/providercommonerr.h" +#include "drbg_local.h" + +static OSSL_OP_rand_newctx_fn drbg_ctr_new_wrapper; +static OSSL_OP_rand_freectx_fn drbg_ctr_free; +static OSSL_OP_rand_instantiate_fn drbg_ctr_instantiate_wrapper; +static OSSL_OP_rand_uninstantiate_fn drbg_ctr_uninstantiate_wrapper; +static OSSL_OP_rand_generate_fn drbg_ctr_generate_wrapper; +static OSSL_OP_rand_reseed_fn drbg_ctr_reseed_wrapper; +static OSSL_OP_rand_settable_ctx_params_fn drbg_ctr_settable_ctx_params; +static OSSL_OP_rand_set_ctx_params_fn drbg_ctr_set_ctx_params; +static OSSL_OP_rand_gettable_ctx_params_fn drbg_ctr_gettable_ctx_params; +static OSSL_OP_rand_get_ctx_params_fn drbg_ctr_get_ctx_params; +static OSSL_OP_rand_verify_zeroization_fn drbg_ctr_verify_zeroization; + +/* + * The state of a DRBG AES-CTR. + */ +typedef struct rand_drbg_ctr_st { + EVP_CIPHER_CTX *ctx_ecb; + EVP_CIPHER_CTX *ctx_ctr; + EVP_CIPHER_CTX *ctx_df; + EVP_CIPHER *cipher_ecb; + EVP_CIPHER *cipher_ctr; + size_t keylen; + int use_df; + unsigned char K[32]; + unsigned char V[16]; + /* Temporary block storage used by ctr_df */ + unsigned char bltmp[16]; + size_t bltmp_pos; + unsigned char KX[48]; +} PROV_DRBG_CTR; /* * Implementation of NIST SP 800-90A CTR DRBG. */ -static void inc_128(RAND_DRBG_CTR *ctr) +static void inc_128(PROV_DRBG_CTR *ctr) { unsigned char *p = &ctr->V[0]; u32 n = 16, c = 1; @@ -32,7 +68,7 @@ static void inc_128(RAND_DRBG_CTR *ctr) } while (n); } -static void ctr_XOR(RAND_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) +static void ctr_XOR(PROV_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) { size_t i, n; @@ -61,7 +97,7 @@ static void ctr_XOR(RAND_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) /* * Process a complete block using BCC algorithm of SP 800-90A 10.3.3 */ -__owur static int ctr_BCC_block(RAND_DRBG_CTR *ctr, unsigned char *out, +__owur static int ctr_BCC_block(PROV_DRBG_CTR *ctr, unsigned char *out, const unsigned char *in, int len) { int i, outlen = AES_BLOCK_SIZE; @@ -79,7 +115,7 @@ __owur static int ctr_BCC_block(RAND_DRBG_CTR *ctr, unsigned char *out, /* * Handle several BCC operations for as much data as we need for K and X */ -__owur static int ctr_BCC_blocks(RAND_DRBG_CTR *ctr, const unsigned char *in) +__owur static int ctr_BCC_blocks(PROV_DRBG_CTR *ctr, const unsigned char *in) { unsigned char in_tmp[48]; unsigned char num_of_blk = 2; @@ -97,7 +133,7 @@ __owur static int ctr_BCC_blocks(RAND_DRBG_CTR *ctr, const unsigned char *in) * Initialise BCC blocks: these have the value 0,1,2 in leftmost positions: * see 10.3.1 stage 7. */ -__owur static int ctr_BCC_init(RAND_DRBG_CTR *ctr) +__owur static int ctr_BCC_init(PROV_DRBG_CTR *ctr) { unsigned char bltmp[48] = {0}; unsigned char num_of_blk; @@ -112,7 +148,7 @@ __owur static int ctr_BCC_init(RAND_DRBG_CTR *ctr) /* * Process several blocks into BCC algorithm, some possibly partial */ -__owur static int ctr_BCC_update(RAND_DRBG_CTR *ctr, +__owur static int ctr_BCC_update(PROV_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) { if (in == NULL || inlen == 0) @@ -147,7 +183,7 @@ __owur static int ctr_BCC_update(RAND_DRBG_CTR *ctr, return 1; } -__owur static int ctr_BCC_final(RAND_DRBG_CTR *ctr) +__owur static int ctr_BCC_final(PROV_DRBG_CTR *ctr) { if (ctr->bltmp_pos) { memset(ctr->bltmp + ctr->bltmp_pos, 0, 16 - ctr->bltmp_pos); @@ -157,7 +193,7 @@ __owur static int ctr_BCC_final(RAND_DRBG_CTR *ctr) return 1; } -__owur static int ctr_df(RAND_DRBG_CTR *ctr, +__owur static int ctr_df(PROV_DRBG_CTR *ctr, const unsigned char *in1, size_t in1len, const unsigned char *in2, size_t in2len, const unsigned char *in3, size_t in3len) @@ -220,12 +256,12 @@ __owur static int ctr_df(RAND_DRBG_CTR *ctr, * zeroes if necessary and have up to two parameters XORed together, * so we handle both cases in this function instead. */ -__owur static int ctr_update(RAND_DRBG *drbg, +__owur static int ctr_update(PROV_DRBG *drbg, const unsigned char *in1, size_t in1len, const unsigned char *in2, size_t in2len, const unsigned char *nonce, size_t noncelen) { - RAND_DRBG_CTR *ctr = &drbg->data.ctr; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; int outlen = AES_BLOCK_SIZE; unsigned char V_tmp[48], out[48]; unsigned char len; @@ -247,7 +283,7 @@ __owur static int ctr_update(RAND_DRBG *drbg, memcpy(ctr->K, out, ctr->keylen); memcpy(ctr->V, out + ctr->keylen, 16); - if ((drbg->flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0) { + if (ctr->use_df) { /* If no input reuse existing derived value */ if (in1 != NULL || nonce != NULL || in2 != NULL) if (!ctr_df(ctr, in1, in1len, nonce, noncelen, in2, in2len)) @@ -266,12 +302,12 @@ __owur static int ctr_update(RAND_DRBG *drbg, return 1; } -__owur static int drbg_ctr_instantiate(RAND_DRBG *drbg, - const unsigned char *entropy, size_t entropylen, - const unsigned char *nonce, size_t noncelen, - const unsigned char *pers, size_t perslen) +static int drbg_ctr_instantiate(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen) { - RAND_DRBG_CTR *ctr = &drbg->data.ctr; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; if (entropy == NULL) return 0; @@ -287,11 +323,22 @@ __owur static int drbg_ctr_instantiate(RAND_DRBG *drbg, return 1; } -__owur static int drbg_ctr_reseed(RAND_DRBG *drbg, - const unsigned char *entropy, size_t entropylen, - const unsigned char *adin, size_t adinlen) +static int drbg_ctr_instantiate_wrapper(void *vdrbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, + size_t pstr_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_instantiate(drbg, strength, prediction_resistance, + pstr, pstr_len); +} + +static int drbg_ctr_reseed(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *adin, size_t adinlen) { - RAND_DRBG_CTR *ctr = &drbg->data.ctr; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; if (entropy == NULL) return 0; @@ -302,6 +349,16 @@ __owur static int drbg_ctr_reseed(RAND_DRBG *drbg, return 1; } +static int drbg_ctr_reseed_wrapper(void *vdrbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_reseed(drbg, prediction_resistance, ent, ent_len, + adin, adin_len); +} + static void ctr96_inc(unsigned char *counter) { u32 n = 12, c = 1; @@ -314,11 +371,11 @@ static void ctr96_inc(unsigned char *counter) } while (n); } -__owur static int drbg_ctr_generate(RAND_DRBG *drbg, - unsigned char *out, size_t outlen, - const unsigned char *adin, size_t adinlen) +static int drbg_ctr_generate(PROV_DRBG *drbg, + unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adinlen) { - RAND_DRBG_CTR *ctr = &drbg->data.ctr; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; unsigned int ctr32, blocks; int outl, buflen; @@ -328,7 +385,7 @@ __owur static int drbg_ctr_generate(RAND_DRBG *drbg, if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0)) return 0; /* This means we reuse derived value */ - if ((drbg->flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0) { + if (ctr->use_df) { adin = NULL; adinlen = 1; } @@ -388,116 +445,299 @@ __owur static int drbg_ctr_generate(RAND_DRBG *drbg, return 1; } -static int drbg_ctr_uninstantiate(RAND_DRBG *drbg) +static int drbg_ctr_generate_wrapper + (void *vdrbg, unsigned char *out, size_t outlen, + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adin_len) { - EVP_CIPHER_CTX_free(drbg->data.ctr.ctx_ecb); - EVP_CIPHER_CTX_free(drbg->data.ctr.ctx_ctr); - EVP_CIPHER_CTX_free(drbg->data.ctr.ctx_df); - EVP_CIPHER_free(drbg->data.ctr.cipher_ecb); - EVP_CIPHER_free(drbg->data.ctr.cipher_ctr); - OPENSSL_cleanse(&drbg->data.ctr, sizeof(drbg->data.ctr)); - return 1; + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_generate(drbg, out, outlen, strength, + prediction_resistance, adin, adin_len); } -static RAND_DRBG_METHOD drbg_ctr_meth = { - drbg_ctr_instantiate, - drbg_ctr_reseed, - drbg_ctr_generate, - drbg_ctr_uninstantiate -}; +static int drbg_ctr_uninstantiate(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + + OPENSSL_cleanse(ctr->K, sizeof(ctr->K)); + OPENSSL_cleanse(ctr->V, sizeof(ctr->V)); + OPENSSL_cleanse(ctr->bltmp, sizeof(ctr->bltmp)); + OPENSSL_cleanse(ctr->KX, sizeof(ctr->KX)); + ctr->bltmp_pos = 0; + return PROV_DRBG_uninstantiate(drbg); +} -int drbg_ctr_init(RAND_DRBG *drbg) +static int drbg_ctr_uninstantiate_wrapper(void *vdrbg) { - RAND_DRBG_CTR *ctr = &drbg->data.ctr; - size_t keylen; - EVP_CIPHER *cipher_ecb = NULL; - EVP_CIPHER *cipher_ctr = NULL; + return drbg_ctr_uninstantiate((PROV_DRBG *)vdrbg); +} - switch (drbg->type) { - default: - /* This can't happen, but silence the compiler warning. */ +static int drbg_ctr_verify_zeroization(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->K); + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->V); + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->bltmp); + PROV_DRBG_VERYIFY_ZEROIZATION(ctr->KX); + if (ctr->bltmp_pos != 0) return 0; - case NID_aes_128_ctr: - keylen = 16; - cipher_ecb = EVP_CIPHER_fetch(drbg->libctx, "AES-128-ECB", ""); - cipher_ctr = EVP_CIPHER_fetch(drbg->libctx, "AES-128-CTR", ""); - break; - case NID_aes_192_ctr: - keylen = 24; - cipher_ecb = EVP_CIPHER_fetch(drbg->libctx, "AES-192-ECB", ""); - cipher_ctr = EVP_CIPHER_fetch(drbg->libctx, "AES-192-CTR", ""); - break; - case NID_aes_256_ctr: - keylen = 32; - cipher_ecb = EVP_CIPHER_fetch(drbg->libctx, "AES-256-ECB", ""); - cipher_ctr = EVP_CIPHER_fetch(drbg->libctx, "AES-256-CTR", ""); - break; + return 1; +} + +static int drbg_ctr_init_lengths(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + int res = 1; + +#ifdef FIPS_MODULE + if (!ctr->use_df) { + PROVerr(0, RAND_R_DERIVATION_FUNCTION_MANDATORY_FOR_FIPS); + ctr->use_df = 1; + res = 0; } - if (cipher_ecb == NULL || cipher_ctr == NULL) - return 0; +#endif + /* Maximum number of bits per request = 2^19 = 2^16 bytes */ + drbg->max_request = 1 << 16; + if (ctr->use_df) { + drbg->min_entropylen = 0; + drbg->max_entropylen = DRBG_MAX_LENGTH; + drbg->min_noncelen = 0; + drbg->max_noncelen = DRBG_MAX_LENGTH; + drbg->max_perslen = DRBG_MAX_LENGTH; + drbg->max_adinlen = DRBG_MAX_LENGTH; - EVP_CIPHER_free(ctr->cipher_ecb); - ctr->cipher_ecb = cipher_ecb; - EVP_CIPHER_free(ctr->cipher_ctr); - ctr->cipher_ctr = cipher_ctr; + if (ctr->keylen > 0) { + drbg->min_entropylen = ctr->keylen; + drbg->min_noncelen = drbg->min_entropylen / 2; + } + } else { + const size_t len = ctr->keylen > 0 ? drbg->seedlen : DRBG_MAX_LENGTH; + + drbg->min_entropylen = len; + drbg->max_entropylen = len; + /* Nonce not used */ + drbg->min_noncelen = 0; + drbg->max_noncelen = 0; + drbg->max_perslen = len; + drbg->max_adinlen = len; + } + return res; +} + +static int drbg_ctr_init(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data; + const size_t keylen = EVP_CIPHER_key_length(ctr->cipher_ctr); ctr->keylen = keylen; if (ctr->ctx_ecb == NULL) ctr->ctx_ecb = EVP_CIPHER_CTX_new(); if (ctr->ctx_ctr == NULL) ctr->ctx_ctr = EVP_CIPHER_CTX_new(); - if (ctr->ctx_ecb == NULL || ctr->ctx_ctr == NULL - || !EVP_CipherInit_ex(ctr->ctx_ecb, - ctr->cipher_ecb, NULL, NULL, NULL, 1) - || !EVP_CipherInit_ex(ctr->ctx_ctr, - ctr->cipher_ctr, NULL, NULL, NULL, 1)) + if (ctr->ctx_ecb == NULL || ctr->ctx_ctr == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (ctr->cipher_ctr != NULL) { + if (!EVP_CipherInit_ex(ctr->ctx_ecb, + ctr->cipher_ecb, NULL, NULL, NULL, 1) + || !EVP_CipherInit_ex(ctr->ctx_ctr, + ctr->cipher_ctr, NULL, NULL, NULL, 1)) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_INITIALISE_CIPHERS); + goto err; + } + + drbg->strength = keylen * 8; + drbg->seedlen = keylen + 16; + + if (ctr->use_df) { + /* df initialisation */ + static const unsigned char df_key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + + if (ctr->ctx_df == NULL) + ctr->ctx_df = EVP_CIPHER_CTX_new(); + if (ctr->ctx_df == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto err; + } + /* Set key schedule for df_key */ + if (!EVP_CipherInit_ex(ctr->ctx_df, + ctr->cipher_ecb, NULL, df_key, NULL, 1)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED); + goto err; + } + } + } + return drbg_ctr_init_lengths(drbg); + +err: + EVP_CIPHER_CTX_free(ctr->ctx_ecb); + EVP_CIPHER_CTX_free(ctr->ctx_ctr); + ctr->ctx_ecb = ctr->ctx_ctr = NULL; + return 0; +} + +static int drbg_ctr_new(PROV_DRBG *drbg) +{ + PROV_DRBG_CTR *ctr; + + ctr = OPENSSL_secure_zalloc(sizeof(*ctr)); + if (ctr == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; + } + + ctr->use_df = 1; + drbg->data = ctr; + return drbg_ctr_init_lengths(drbg); +} + +static void *drbg_ctr_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return prov_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_ctr_new, + &drbg_ctr_instantiate, &drbg_ctr_uninstantiate, + &drbg_ctr_reseed, &drbg_ctr_generate); +} + +static void drbg_ctr_free(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_CTR *ctr; + + if (drbg != NULL && (ctr = (PROV_DRBG_CTR *)drbg->data) != NULL) { + EVP_CIPHER_CTX_free(ctr->ctx_ecb); + EVP_CIPHER_CTX_free(ctr->ctx_ctr); + EVP_CIPHER_CTX_free(ctr->ctx_df); + EVP_CIPHER_free(ctr->cipher_ecb); + EVP_CIPHER_free(ctr->cipher_ctr); + + OPENSSL_secure_clear_free(ctr, sizeof(*ctr)); + } + prov_rand_drbg_free(drbg); +} + +static int drbg_ctr_get_ctx_params(void *vdrbg, OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return drbg_get_ctx_params(drbg, params); +} + +static const OSSL_PARAM *drbg_ctr_gettable_ctx_params(void) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_DRBG_GETABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_DRBG *ctx = (PROV_DRBG *)vctx; + PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data; + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); + const OSSL_PARAM *p; + char *ecb; + const char *propquery = NULL; + int i, cipher_init = 0; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_USE_DF)) != NULL + && OSSL_PARAM_get_int(p, &i)) { + /* FIPS errors out in the drbg_ctr_init() call later */ + ctr->use_df = i != 0; + cipher_init = 1; + } + + if ((p = OSSL_PARAM_locate_const(params, + OSSL_DRBG_PARAM_PROPERTIES)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + propquery = (const char *)p->data; + } + + if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_CIPHER)) != NULL) { + const char *base = (const char *)p->data; - drbg->meth = &drbg_ctr_meth; - drbg->strength = keylen * 8; - drbg->seedlen = keylen + 16; - - if ((drbg->flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0) { - /* df initialisation */ - static const unsigned char df_key[32] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f - }; - - if (ctr->ctx_df == NULL) - ctr->ctx_df = EVP_CIPHER_CTX_new(); - if (ctr->ctx_df == NULL) + if (p->data_type != OSSL_PARAM_UTF8_STRING + || p->data_size < 3) return 0; - /* Set key schedule for df_key */ - if (!EVP_CipherInit_ex(ctr->ctx_df, - ctr->cipher_ecb, NULL, df_key, NULL, 1)) + if (strcasecmp("CTR", base + p->data_size - sizeof("CTR")) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER); + return 0; + } + if ((ecb = OPENSSL_strdup(base)) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; + } + strcpy(ecb + p->data_size - sizeof("ECB"), "ECB"); + EVP_CIPHER_free(ctr->cipher_ecb); + EVP_CIPHER_free(ctr->cipher_ctr); + ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); + ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); + OPENSSL_free(ecb); + if (ctr->cipher_ctr == NULL || ctr->cipher_ecb == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS); + return 0; + } + cipher_init = 1; + } - drbg->min_entropylen = ctr->keylen; - drbg->max_entropylen = DRBG_MAX_LENGTH; - drbg->min_noncelen = drbg->min_entropylen / 2; - drbg->max_noncelen = DRBG_MAX_LENGTH; - drbg->max_perslen = DRBG_MAX_LENGTH; - drbg->max_adinlen = DRBG_MAX_LENGTH; - } else { -#ifdef FIPS_MODULE - RANDerr(RAND_F_DRBG_CTR_INIT, - RAND_R_DERIVATION_FUNCTION_MANDATORY_FOR_FIPS); + if (cipher_init && !drbg_ctr_init(ctx)) return 0; -#else - drbg->min_entropylen = drbg->seedlen; - drbg->max_entropylen = drbg->seedlen; - /* Nonce not used */ - drbg->min_noncelen = 0; - drbg->max_noncelen = 0; - drbg->max_perslen = drbg->seedlen; - drbg->max_adinlen = drbg->seedlen; -#endif - } - drbg->max_request = 1 << 16; + return drbg_set_ctx_params(ctx, params); +} - return 1; +static const OSSL_PARAM *drbg_ctr_settable_ctx_params(void) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_CIPHER, NULL, 0), +#ifndef FIPS_MODULE + /* + * Don't advertise this for FIPS, it isn't allowed to change. + * The parameter can still be passed and will be processed but errors + * out. + */ + OSSL_PARAM_int(OSSL_DRBG_PARAM_USE_DF, NULL), +#endif + OSSL_PARAM_DRBG_SETABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_settable_ctx_params; } + +const OSSL_DISPATCH drbg_ctr_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_ctr_new_wrapper }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_ctr_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))drbg_ctr_instantiate_wrapper }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))drbg_ctr_uninstantiate_wrapper }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_ctr_generate_wrapper }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_ctr_reseed_wrapper }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))drbg_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))drbg_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))drbg_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))drbg_ctr_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_ctr_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))drbg_ctr_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_ctr_get_ctx_params }, + { OSSL_FUNC_RAND_SET_CALLBACKS, (void(*)(void))drbg_set_callbacks }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))drbg_ctr_verify_zeroization }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/drbg_hash.c b/providers/implementations/rands/drbg_hash.c index f087d88965..62a976827a 100644 --- a/providers/implementations/rands/drbg_hash.c +++ b/providers/implementations/rands/drbg_hash.c @@ -10,19 +10,50 @@ #include #include #include +#include #include #include #include +#include #include "internal/thread_once.h" #include "prov/providercommon.h" -#include "rand_local.h" +#include "prov/provider_ctx.h" +#include "prov/provider_util.h" +#include "prov/implementations.h" +#include "prov/providercommonerr.h" +#include "drbg_local.h" + +static OSSL_OP_rand_newctx_fn drbg_hash_new_wrapper; +static OSSL_OP_rand_freectx_fn drbg_hash_free; +static OSSL_OP_rand_instantiate_fn drbg_hash_instantiate_wrapper; +static OSSL_OP_rand_uninstantiate_fn drbg_hash_uninstantiate_wrapper; +static OSSL_OP_rand_generate_fn drbg_hash_generate_wrapper; +static OSSL_OP_rand_reseed_fn drbg_hash_reseed_wrapper; +static OSSL_OP_rand_settable_ctx_params_fn drbg_hash_settable_ctx_params; +static OSSL_OP_rand_set_ctx_params_fn drbg_hash_set_ctx_params; +static OSSL_OP_rand_gettable_ctx_params_fn drbg_hash_gettable_ctx_params; +static OSSL_OP_rand_get_ctx_params_fn drbg_hash_get_ctx_params; +static OSSL_OP_rand_verify_zeroization_fn drbg_hash_verify_zeroization; + +/* 888 bits from SP800-90Ar1 10.1 table 2 */ +#define HASH_PRNG_MAX_SEEDLEN (888/8) /* 440 bits from SP800-90Ar1 10.1 table 2 */ #define HASH_PRNG_SMALL_SEEDLEN (440/8) + /* Determine what seedlen to use based on the block length */ #define MAX_BLOCKLEN_USING_SMALL_SEEDLEN (256/8) #define INBYTE_IGNORE ((unsigned char)0xFF) +typedef struct rand_drbg_hash_st { + PROV_DIGEST digest; + EVP_MD_CTX *ctx; + size_t blocklen; + unsigned char V[HASH_PRNG_MAX_SEEDLEN]; + unsigned char C[HASH_PRNG_MAX_SEEDLEN]; + /* Temporary value storage: should always exceed max digest length */ + unsigned char vtmp[HASH_PRNG_MAX_SEEDLEN]; +} PROV_DRBG_HASH; /* * SP800-90Ar1 10.3.1 Derivation function using a Hash Function (Hash_df). @@ -33,13 +64,13 @@ * in3 - optional input string (Can be NULL). * These are concatenated as part of the DigestUpdate process. */ -static int hash_df(RAND_DRBG *drbg, unsigned char *out, +static int hash_df(PROV_DRBG *drbg, unsigned char *out, const unsigned char inbyte, const unsigned char *in, size_t inlen, const unsigned char *in2, size_t in2len, const unsigned char *in3, size_t in3len) { - RAND_DRBG_HASH *hash = &drbg->data.hash; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; EVP_MD_CTX *ctx = hash->ctx; unsigned char *vtmp = hash->vtmp; /* tmp = counter || num_bits_returned || [inbyte] */ @@ -69,7 +100,7 @@ static int hash_df(RAND_DRBG *drbg, unsigned char *out, * (Step 4.1) out = out || Hash(tmp || in || [in2] || [in3]) * (where tmp = counter || num_bits_returned || [inbyte]) */ - if (!(EVP_DigestInit_ex(ctx, hash->md, NULL) + if (!(EVP_DigestInit_ex(ctx, ossl_prov_digest_md(&hash->digest), NULL) && EVP_DigestUpdate(ctx, tmp, tmp_sz) && EVP_DigestUpdate(ctx, in, inlen) && (in2 == NULL || EVP_DigestUpdate(ctx, in2, in2len)) @@ -97,7 +128,7 @@ static int hash_df(RAND_DRBG *drbg, unsigned char *out, } /* Helper function that just passes 2 input parameters to hash_df() */ -static int hash_df1(RAND_DRBG *drbg, unsigned char *out, +static int hash_df1(PROV_DRBG *drbg, unsigned char *out, const unsigned char in_byte, const unsigned char *in1, size_t in1len) { @@ -110,7 +141,7 @@ static int hash_df1(RAND_DRBG *drbg, unsigned char *out, * The final carry is ignored i.e: dst = (dst + in) mod (2^seedlen_bits). * where dst size is drbg->seedlen, and inlen <= drbg->seedlen. */ -static int add_bytes(RAND_DRBG *drbg, unsigned char *dst, +static int add_bytes(PROV_DRBG *drbg, unsigned char *dst, unsigned char *in, size_t inlen) { size_t i; @@ -141,13 +172,13 @@ static int add_bytes(RAND_DRBG *drbg, unsigned char *dst, } /* V = (V + Hash(inbyte || V || [additional_input]) mod (2^seedlen) */ -static int add_hash_to_v(RAND_DRBG *drbg, unsigned char inbyte, +static int add_hash_to_v(PROV_DRBG *drbg, unsigned char inbyte, const unsigned char *adin, size_t adinlen) { - RAND_DRBG_HASH *hash = &drbg->data.hash; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; EVP_MD_CTX *ctx = hash->ctx; - return EVP_DigestInit_ex(ctx, hash->md, NULL) + return EVP_DigestInit_ex(ctx, ossl_prov_digest_md(&hash->digest), NULL) && EVP_DigestUpdate(ctx, &inbyte, 1) && EVP_DigestUpdate(ctx, hash->V, drbg->seedlen) && (adin == NULL || EVP_DigestUpdate(ctx, adin, adinlen)) @@ -173,16 +204,17 @@ static int add_hash_to_v(RAND_DRBG *drbg, unsigned char inbyte, * * Returns zero if an error occurs otherwise it returns 1. */ -static int hash_gen(RAND_DRBG *drbg, unsigned char *out, size_t outlen) +static int hash_gen(PROV_DRBG *drbg, unsigned char *out, size_t outlen) { - RAND_DRBG_HASH *hash = &drbg->data.hash; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; unsigned char one = 1; if (outlen == 0) return 1; memcpy(hash->vtmp, hash->V, drbg->seedlen); for(;;) { - if (!EVP_DigestInit_ex(hash->ctx, hash->md, NULL) + if (!EVP_DigestInit_ex(hash->ctx, ossl_prov_digest_md(&hash->digest), + NULL) || !EVP_DigestUpdate(hash->ctx, hash->vtmp, drbg->seedlen)) return 0; @@ -213,20 +245,35 @@ static int hash_gen(RAND_DRBG *drbg, unsigned char *out, size_t outlen) * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hash_instantiate(RAND_DRBG *drbg, +static int drbg_hash_instantiate(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, const unsigned char *nonce, size_t nonce_len, const unsigned char *pstr, size_t pstr_len) { - RAND_DRBG_HASH *hash = &drbg->data.hash; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; + + EVP_MD_CTX_free(hash->ctx); + hash->ctx = EVP_MD_CTX_new(); /* (Step 1-3) V = Hash_df(entropy||nonce||pers, seedlen) */ - return hash_df(drbg, hash->V, INBYTE_IGNORE, - ent, ent_len, nonce, nonce_len, pstr, pstr_len) + return hash->ctx != NULL + && hash_df(drbg, hash->V, INBYTE_IGNORE, + ent, ent_len, nonce, nonce_len, pstr, pstr_len) /* (Step 4) C = Hash_df(0x00||V, seedlen) */ && hash_df1(drbg, hash->C, 0x00, hash->V, drbg->seedlen); } +static int drbg_hash_instantiate_wrapper(void *vdrbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, + size_t pstr_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_instantiate(drbg, strength, prediction_resistance, + pstr, pstr_len); +} + /* * SP800-90Ar1 10.1.1.3 Hash_DRBG_Reseed_Process: * @@ -235,13 +282,13 @@ static int drbg_hash_instantiate(RAND_DRBG *drbg, * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hash_reseed(RAND_DRBG *drbg, +static int drbg_hash_reseed(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, const unsigned char *adin, size_t adin_len) { - RAND_DRBG_HASH *hash = &drbg->data.hash; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; - /* (Step 1-2) V = Hash_df(0x01 || V || entropy_input || additional_input)*/ + /* (Step 1-2) V = Hash_df(0x01 || V || entropy_input || additional_input) */ /* V about to be updated so use C as output instead */ if (!hash_df(drbg, hash->C, 0x01, hash->V, drbg->seedlen, ent, ent_len, adin, adin_len)) @@ -251,6 +298,16 @@ static int drbg_hash_reseed(RAND_DRBG *drbg, return hash_df1(drbg, hash->C, 0x00, hash->V, drbg->seedlen); } +static int drbg_hash_reseed_wrapper(void *vdrbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_reseed(drbg, prediction_resistance, ent, ent_len, + adin, adin_len); +} + /* * SP800-90Ar1 10.1.1.4 Hash_DRBG_Generate_Process: * @@ -260,11 +317,11 @@ static int drbg_hash_reseed(RAND_DRBG *drbg, * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hash_generate(RAND_DRBG *drbg, +static int drbg_hash_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, const unsigned char *adin, size_t adin_len) { - RAND_DRBG_HASH *hash = &drbg->data.hash; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; unsigned char counter[4]; int reseed_counter = drbg->reseed_gen_counter; @@ -273,10 +330,11 @@ static int drbg_hash_generate(RAND_DRBG *drbg, counter[2] = (unsigned char)((reseed_counter >> 8) & 0xff); counter[3] = (unsigned char)(reseed_counter & 0xff); - return (adin == NULL + return hash->ctx != NULL + && (adin == NULL /* (Step 2) if adin != NULL then V = V + Hash(0x02||V||adin) */ - || adin_len == 0 - || add_hash_to_v(drbg, 0x02, adin, adin_len)) + || adin_len == 0 + || add_hash_to_v(drbg, 0x02, adin, adin_len)) /* (Step 3) Hashgen(outlen, V) */ && hash_gen(drbg, out, outlen) /* (Step 4/5) H = V = (V + Hash(0x03||V) mod (2^seedlen_bits) */ @@ -288,73 +346,167 @@ static int drbg_hash_generate(RAND_DRBG *drbg, && add_bytes(drbg, hash->V, counter, 4); } -static int drbg_hash_uninstantiate(RAND_DRBG *drbg) +static int drbg_hash_generate_wrapper + (void *vdrbg, unsigned char *out, size_t outlen, unsigned int strength, + int prediction_resistance, const unsigned char *adin, size_t adin_len) { - EVP_MD_free(drbg->data.hash.md); - EVP_MD_CTX_free(drbg->data.hash.ctx); - OPENSSL_cleanse(&drbg->data.hash, sizeof(drbg->data.hash)); - return 1; + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_generate(drbg, out, outlen, strength, + prediction_resistance, adin, adin_len); } -static RAND_DRBG_METHOD drbg_hash_meth = { - drbg_hash_instantiate, - drbg_hash_reseed, - drbg_hash_generate, - drbg_hash_uninstantiate -}; +static int drbg_hash_uninstantiate(PROV_DRBG *drbg) +{ + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; -int drbg_hash_init(RAND_DRBG *drbg) + OPENSSL_cleanse(hash->V, sizeof(hash->V)); + OPENSSL_cleanse(hash->C, sizeof(hash->C)); + OPENSSL_cleanse(hash->vtmp, sizeof(hash->vtmp)); + return PROV_DRBG_uninstantiate(drbg); +} + +static int drbg_hash_uninstantiate_wrapper(void *vdrbg) { - EVP_MD *md; - RAND_DRBG_HASH *hash = &drbg->data.hash; + return drbg_hash_uninstantiate((PROV_DRBG *)vdrbg); +} - /* - * Confirm digest is allowed. We allow all digests that are not XOF - * (such as SHAKE). In FIPS mode, the fetch will fail for non-approved - * digests. - */ - md = EVP_MD_fetch(drbg->libctx, ossl_prov_util_nid_to_name(drbg->type), ""); - if (md == NULL) - return 0; +static int drbg_hash_verify_zeroization(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data; - if ((EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0) + PROV_DRBG_VERYIFY_ZEROIZATION(hash->V); + PROV_DRBG_VERYIFY_ZEROIZATION(hash->C); + PROV_DRBG_VERYIFY_ZEROIZATION(hash->vtmp); + return 1; +} + +static int drbg_hash_new(PROV_DRBG *ctx) +{ + PROV_DRBG_HASH *hash; + + hash = OPENSSL_secure_zalloc(sizeof(*hash)); + if (hash == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); return 0; + } - drbg->meth = &drbg_hash_meth; + ctx->data = hash; + ctx->seedlen = HASH_PRNG_MAX_SEEDLEN; + ctx->max_entropylen = DRBG_MAX_LENGTH; + ctx->max_noncelen = DRBG_MAX_LENGTH; + ctx->max_perslen = DRBG_MAX_LENGTH; + ctx->max_adinlen = DRBG_MAX_LENGTH; - if (hash->ctx == NULL) { - hash->ctx = EVP_MD_CTX_new(); - if (hash->ctx == NULL) { - EVP_MD_free(md); - return 0; - } + /* Maximum number of bits per request = 2^19 = 2^16 bytes */ + ctx->max_request = 1 << 16; + return 1; +} + +static void *drbg_hash_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return prov_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_hash_new, + &drbg_hash_instantiate, &drbg_hash_uninstantiate, + &drbg_hash_reseed, &drbg_hash_generate); +} + +static void drbg_hash_free(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HASH *hash; + + if (drbg != NULL && (hash = (PROV_DRBG_HASH *)drbg->data) != NULL) { + EVP_MD_CTX_free(hash->ctx); + ossl_prov_digest_reset(&hash->digest); + OPENSSL_secure_clear_free(hash, sizeof(*hash)); } + prov_rand_drbg_free(drbg); +} + +static int drbg_hash_get_ctx_params(void *vdrbg, OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return drbg_get_ctx_params(drbg, params); +} - EVP_MD_free(hash->md); - hash->md = md; +static const OSSL_PARAM *drbg_hash_gettable_ctx_params(void) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_DRBG_GETABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} - /* These are taken from SP 800-90 10.1 Table 2 */ - hash->blocklen = EVP_MD_size(md); - /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ - drbg->strength = 64 * (hash->blocklen >> 3); - if (drbg->strength > 256) - drbg->strength = 256; - if (hash->blocklen > MAX_BLOCKLEN_USING_SMALL_SEEDLEN) - drbg->seedlen = HASH_PRNG_MAX_SEEDLEN; - else - drbg->seedlen = HASH_PRNG_SMALL_SEEDLEN; +static int drbg_hash_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_DRBG *ctx = (PROV_DRBG *)vctx; + PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)ctx->data; + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); + const EVP_MD *md; - drbg->min_entropylen = drbg->strength / 8; - drbg->max_entropylen = DRBG_MAX_LENGTH; + if (!ossl_prov_digest_load_from_params(&hash->digest, params, libctx)) + return 0; - drbg->min_noncelen = drbg->min_entropylen / 2; - drbg->max_noncelen = DRBG_MAX_LENGTH; + md = ossl_prov_digest_md(&hash->digest); + if (md != NULL) { + if ((EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); + return 0; + } - drbg->max_perslen = DRBG_MAX_LENGTH; - drbg->max_adinlen = DRBG_MAX_LENGTH; + /* These are taken from SP 800-90 10.1 Table 2 */ + hash->blocklen = EVP_MD_size(md); + /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ + ctx->strength = 64 * (hash->blocklen >> 3); + if (ctx->strength > 256) + ctx->strength = 256; + if (hash->blocklen > MAX_BLOCKLEN_USING_SMALL_SEEDLEN) + ctx->seedlen = HASH_PRNG_MAX_SEEDLEN; + else + ctx->seedlen = HASH_PRNG_SMALL_SEEDLEN; + + ctx->min_entropylen = ctx->strength / 8; + ctx->min_noncelen = ctx->min_entropylen / 2; + } - /* Maximum number of bits per request = 2^19 = 2^16 bytes */ - drbg->max_request = 1 << 16; + return drbg_set_ctx_params(ctx, params); +} - return 1; +static const OSSL_PARAM *drbg_hash_settable_ctx_params(void) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_DRBG_SETABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_settable_ctx_params; } + +const OSSL_DISPATCH drbg_hash_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_hash_new_wrapper }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_hash_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))drbg_hash_instantiate_wrapper }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))drbg_hash_uninstantiate_wrapper }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_hash_generate_wrapper }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_hash_reseed_wrapper }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))drbg_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))drbg_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))drbg_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hash_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_hash_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hash_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_hash_get_ctx_params }, + { OSSL_FUNC_RAND_SET_CALLBACKS, (void(*)(void))drbg_set_callbacks }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))drbg_hash_verify_zeroization }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/drbg_hmac.c b/providers/implementations/rands/drbg_hmac.c index ea55279ea3..dc19952439 100644 --- a/providers/implementations/rands/drbg_hmac.c +++ b/providers/implementations/rands/drbg_hmac.c @@ -7,20 +7,38 @@ * https://www.openssl.org/source/license.html */ -/* - * HMAC low level APIs are deprecated for public use, but still ok for internal - * use. - */ -#include "internal/deprecated.h" - #include #include #include #include #include +#include "prov/provider_util.h" #include "internal/thread_once.h" #include "prov/providercommon.h" -#include "rand_local.h" +#include "prov/providercommonerr.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "drbg_local.h" + +static OSSL_OP_rand_newctx_fn drbg_hmac_new_wrapper; +static OSSL_OP_rand_freectx_fn drbg_hmac_free; +static OSSL_OP_rand_instantiate_fn drbg_hmac_instantiate_wrapper; +static OSSL_OP_rand_uninstantiate_fn drbg_hmac_uninstantiate_wrapper; +static OSSL_OP_rand_generate_fn drbg_hmac_generate_wrapper; +static OSSL_OP_rand_reseed_fn drbg_hmac_reseed_wrapper; +static OSSL_OP_rand_settable_ctx_params_fn drbg_hmac_settable_ctx_params; +static OSSL_OP_rand_set_ctx_params_fn drbg_hmac_set_ctx_params; +static OSSL_OP_rand_gettable_ctx_params_fn drbg_hmac_gettable_ctx_params; +static OSSL_OP_rand_get_ctx_params_fn drbg_hmac_get_ctx_params; +static OSSL_OP_rand_verify_zeroization_fn drbg_hmac_verify_zeroization; + +typedef struct rand_drbg_hmac_st { + EVP_MAC_CTX *ctx; /* H(x) = HMAC_hash OR H(x) = KMAC */ + PROV_DIGEST digest; /* H(x) = hash(x) */ + size_t blocklen; + unsigned char K[EVP_MAX_MD_SIZE]; + unsigned char V[EVP_MAX_MD_SIZE]; +} PROV_DRBG_HMAC; /* * Called twice by SP800-90Ar1 10.1.2.2 HMAC_DRBG_Update_Process. @@ -36,25 +54,34 @@ * * Returns zero if an error occurs otherwise it returns 1. */ -static int do_hmac(RAND_DRBG_HMAC *hmac, unsigned char inbyte, +static int do_hmac(PROV_DRBG_HMAC *hmac, unsigned char inbyte, const unsigned char *in1, size_t in1len, const unsigned char *in2, size_t in2len, const unsigned char *in3, size_t in3len) { - HMAC_CTX *ctx = hmac->ctx; - - return HMAC_Init_ex(ctx, hmac->K, hmac->blocklen, hmac->md, NULL) - /* K = HMAC(K, V || inbyte || [in1] || [in2] || [in3]) */ - && HMAC_Update(ctx, hmac->V, hmac->blocklen) - && HMAC_Update(ctx, &inbyte, 1) - && (in1 == NULL || in1len == 0 || HMAC_Update(ctx, in1, in1len)) - && (in2 == NULL || in2len == 0 || HMAC_Update(ctx, in2, in2len)) - && (in3 == NULL || in3len == 0 || HMAC_Update(ctx, in3, in3len)) - && HMAC_Final(ctx, hmac->K, NULL) - /* V = HMAC(K, V) */ - && HMAC_Init_ex(ctx, hmac->K, hmac->blocklen, hmac->md, NULL) - && HMAC_Update(ctx, hmac->V, hmac->blocklen) - && HMAC_Final(ctx, hmac->V, NULL); + EVP_MAC_CTX *ctx = hmac->ctx; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + *params = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, hmac->K, + hmac->blocklen); + if (!EVP_MAC_set_ctx_params(ctx, params) + || !EVP_MAC_init(ctx) + /* K = HMAC(K, V || inbyte || [in1] || [in2] || [in3]) */ + || !EVP_MAC_update(ctx, hmac->V, hmac->blocklen) + || !EVP_MAC_update(ctx, &inbyte, 1) + || !(in1 == NULL || in1len == 0 || EVP_MAC_update(ctx, in1, in1len)) + || !(in2 == NULL || in2len == 0 || EVP_MAC_update(ctx, in2, in2len)) + || !(in3 == NULL || in3len == 0 || EVP_MAC_update(ctx, in3, in3len)) + || !EVP_MAC_final(ctx, hmac->K, NULL, sizeof(hmac->K))) + return 0; + + /* V = HMAC(K, V) */ + *params = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, hmac->K, + hmac->blocklen); + return EVP_MAC_set_ctx_params(ctx, params) + && EVP_MAC_init(ctx) + && EVP_MAC_update(ctx, hmac->V, hmac->blocklen) + && EVP_MAC_final(ctx, hmac->V, NULL, sizeof(hmac->V)); } /* @@ -71,12 +98,12 @@ static int do_hmac(RAND_DRBG_HMAC *hmac, unsigned char inbyte, * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hmac_update(RAND_DRBG *drbg, +static int drbg_hmac_update(PROV_DRBG *drbg, const unsigned char *in1, size_t in1len, const unsigned char *in2, size_t in2len, const unsigned char *in3, size_t in3len) { - RAND_DRBG_HMAC *hmac = &drbg->data.hmac; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; /* (Steps 1-2) K = HMAC(K, V||0x00||provided_data). V = HMAC(K,V) */ if (!do_hmac(hmac, 0x00, in1, in1len, in2, in2len, in3, in3len)) @@ -99,12 +126,17 @@ static int drbg_hmac_update(RAND_DRBG *drbg, * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hmac_instantiate(RAND_DRBG *drbg, +static int drbg_hmac_instantiate(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, const unsigned char *nonce, size_t nonce_len, const unsigned char *pstr, size_t pstr_len) { - RAND_DRBG_HMAC *hmac = &drbg->data.hmac; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + + if (hmac->ctx == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC); + return 0; + } /* (Step 2) Key = 0x00 00...00 */ memset(hmac->K, 0x00, hmac->blocklen); @@ -115,6 +147,17 @@ static int drbg_hmac_instantiate(RAND_DRBG *drbg, pstr_len); } +static int drbg_hmac_instantiate_wrapper(void *vdrbg, unsigned int strength, + int prediction_resistance, + const unsigned char *pstr, + size_t pstr_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_instantiate(drbg, strength, prediction_resistance, + pstr, pstr_len); +} + /* * SP800-90Ar1 10.1.2.4 HMAC_DRBG_Reseed_Process: * @@ -125,7 +168,7 @@ static int drbg_hmac_instantiate(RAND_DRBG *drbg, * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hmac_reseed(RAND_DRBG *drbg, +static int drbg_hmac_reseed(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, const unsigned char *adin, size_t adin_len) { @@ -133,6 +176,16 @@ static int drbg_hmac_reseed(RAND_DRBG *drbg, return drbg_hmac_update(drbg, ent, ent_len, adin, adin_len, NULL, 0); } +static int drbg_hmac_reseed_wrapper(void *vdrbg, int prediction_resistance, + const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_reseed(drbg, prediction_resistance, ent, ent_len, + adin, adin_len); +} + /* * SP800-90Ar1 10.1.2.5 HMAC_DRBG_Generate_Process: * @@ -142,13 +195,14 @@ static int drbg_hmac_reseed(RAND_DRBG *drbg, * * Returns zero if an error occurs otherwise it returns 1. */ -static int drbg_hmac_generate(RAND_DRBG *drbg, +static int drbg_hmac_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, const unsigned char *adin, size_t adin_len) { - RAND_DRBG_HMAC *hmac = &drbg->data.hmac; - HMAC_CTX *ctx = hmac->ctx; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; + EVP_MAC_CTX *ctx = hmac->ctx; const unsigned char *temp = hmac->V; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; /* (Step 2) if adin != NULL then (K,V) = HMAC_DRBG_Update(adin, K, V) */ if (adin != NULL @@ -164,16 +218,19 @@ static int drbg_hmac_generate(RAND_DRBG *drbg, * } */ for (;;) { - if (!HMAC_Init_ex(ctx, hmac->K, hmac->blocklen, hmac->md, NULL) - || !HMAC_Update(ctx, temp, hmac->blocklen)) + *params = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + hmac->K, hmac->blocklen); + if (!EVP_MAC_set_ctx_params(ctx, params) + || !EVP_MAC_init(ctx) + || !EVP_MAC_update(ctx, temp, hmac->blocklen)) return 0; if (outlen > hmac->blocklen) { - if (!HMAC_Final(ctx, out, NULL)) + if (!EVP_MAC_final(ctx, out, NULL, outlen)) return 0; temp = out; } else { - if (!HMAC_Final(ctx, hmac->V, NULL)) + if (!EVP_MAC_final(ctx, hmac->V, NULL, sizeof(hmac->V))) return 0; memcpy(out, hmac->V, outlen); break; @@ -188,69 +245,171 @@ static int drbg_hmac_generate(RAND_DRBG *drbg, return 1; } -static int drbg_hmac_uninstantiate(RAND_DRBG *drbg) +static int drbg_hmac_generate_wrapper + (void *vdrbg, unsigned char *out, size_t outlen, unsigned int strength, + int prediction_resistance, const unsigned char *adin, size_t adin_len) { - EVP_MD_free(drbg->data.hmac.md); - HMAC_CTX_free(drbg->data.hmac.ctx); - OPENSSL_cleanse(&drbg->data.hmac, sizeof(drbg->data.hmac)); - return 1; + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return PROV_DRBG_generate(drbg, out, outlen, strength, + prediction_resistance, adin, adin_len); } -static RAND_DRBG_METHOD drbg_hmac_meth = { - drbg_hmac_instantiate, - drbg_hmac_reseed, - drbg_hmac_generate, - drbg_hmac_uninstantiate -}; +static int drbg_hmac_uninstantiate(PROV_DRBG *drbg) +{ + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; -int drbg_hmac_init(RAND_DRBG *drbg) + OPENSSL_cleanse(hmac->K, sizeof(hmac->K)); + OPENSSL_cleanse(hmac->V, sizeof(hmac->V)); + return PROV_DRBG_uninstantiate(drbg); +} + +static int drbg_hmac_uninstantiate_wrapper(void *vdrbg) { - EVP_MD *md = NULL; - RAND_DRBG_HMAC *hmac = &drbg->data.hmac; + return drbg_hmac_uninstantiate((PROV_DRBG *)vdrbg); +} - /* - * Confirm digest is allowed. We allow all digests that are not XOF - * (such as SHAKE). In FIPS mode, the fetch will fail for non-approved - * digests. - */ - md = EVP_MD_fetch(drbg->libctx, ossl_prov_util_nid_to_name(drbg->type), ""); - if (md == NULL) - return 0; +static int drbg_hmac_verify_zeroization(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data; - if ((EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0) - return 0; + PROV_DRBG_VERYIFY_ZEROIZATION(hmac->K); + PROV_DRBG_VERYIFY_ZEROIZATION(hmac->V); + return 1; +} - drbg->meth = &drbg_hmac_meth; +static int drbg_hmac_new(PROV_DRBG *drbg) +{ + PROV_DRBG_HMAC *hmac; - if (hmac->ctx == NULL) { - hmac->ctx = HMAC_CTX_new(); - if (hmac->ctx == NULL) { - EVP_MD_free(md); - return 0; - } + hmac = OPENSSL_secure_zalloc(sizeof(*hmac)); + if (hmac == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return 0; } - /* These are taken from SP 800-90 10.1 Table 2 */ - EVP_MD_free(hmac->md); - hmac->md = md; - hmac->blocklen = EVP_MD_size(md); + drbg->data = hmac; /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ - drbg->strength = 64 * (int)(hmac->blocklen >> 3); - if (drbg->strength > 256) - drbg->strength = 256; - drbg->seedlen = hmac->blocklen; - - drbg->min_entropylen = drbg->strength / 8; drbg->max_entropylen = DRBG_MAX_LENGTH; - - drbg->min_noncelen = drbg->min_entropylen / 2; drbg->max_noncelen = DRBG_MAX_LENGTH; - drbg->max_perslen = DRBG_MAX_LENGTH; drbg->max_adinlen = DRBG_MAX_LENGTH; - /* Maximum number of bits per request = 2^19 = 2^16 bytes*/ + /* Maximum number of bits per request = 2^19 = 2^16 bytes */ drbg->max_request = 1 << 16; - return 1; } + +static void *drbg_hmac_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return prov_rand_drbg_new(provctx, parent, parent_dispatch, &drbg_hmac_new, + &drbg_hmac_instantiate, &drbg_hmac_uninstantiate, + &drbg_hmac_reseed, &drbg_hmac_generate); +} + +static void drbg_hmac_free(void *vdrbg) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + PROV_DRBG_HMAC *hmac; + + if (drbg != NULL && (hmac = (PROV_DRBG_HMAC *)drbg->data) != NULL) { + EVP_MAC_free_ctx(hmac->ctx); + ossl_prov_digest_reset(&hmac->digest); + OPENSSL_secure_clear_free(hmac, sizeof(*hmac)); + } + prov_rand_drbg_free(drbg); +} + +static int drbg_hmac_get_ctx_params(void *vdrbg, OSSL_PARAM params[]) +{ + PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; + + return drbg_get_ctx_params(drbg, params); +} + +static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(void) +{ + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_DRBG_GETABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_gettable_ctx_params; +} + +static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_DRBG *ctx = (PROV_DRBG *)vctx; + PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)ctx->data; + OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx); + const EVP_MD *md; + + if (!ossl_prov_digest_load_from_params(&hmac->digest, params, libctx)) + return 0; + + /* + * Confirm digest is allowed. We allow all digests that are not XOF + * (such as SHAKE). In FIPS mode, the fetch will fail for non-approved + * digests. + */ + md = ossl_prov_digest_md(&hmac->digest); + if (md != NULL && (EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); + return 0; + } + + if (!ossl_prov_macctx_load_from_params(&hmac->ctx, params, + NULL, NULL, NULL, libctx)) + return 0; + + if (hmac->ctx != NULL) { + /* These are taken from SP 800-90 10.1 Table 2 */ + hmac->blocklen = EVP_MD_size(md); + /* See SP800-57 Part1 Rev4 5.6.1 Table 3 */ + ctx->strength = 64 * (int)(hmac->blocklen >> 3); + if (ctx->strength > 256) + ctx->strength = 256; + ctx->seedlen = hmac->blocklen; + ctx->min_entropylen = ctx->strength / 8; + ctx->min_noncelen = ctx->min_entropylen / 2; + } + + return drbg_set_ctx_params(ctx, params); +} + +static const OSSL_PARAM *drbg_hmac_settable_ctx_params(void) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_DRBG_PARAM_MAC, NULL, 0), + OSSL_PARAM_DRBG_SETABLE_CTX_COMMON, + OSSL_PARAM_END + }; + return known_settable_ctx_params; +} + +const OSSL_DISPATCH drbg_hmac_functions[] = { + { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))drbg_hmac_new_wrapper }, + { OSSL_FUNC_RAND_FREECTX, (void(*)(void))drbg_hmac_free }, + { OSSL_FUNC_RAND_INSTANTIATE, + (void(*)(void))drbg_hmac_instantiate_wrapper }, + { OSSL_FUNC_RAND_UNINSTANTIATE, + (void(*)(void))drbg_hmac_uninstantiate_wrapper }, + { OSSL_FUNC_RAND_GENERATE, (void(*)(void))drbg_hmac_generate_wrapper }, + { OSSL_FUNC_RAND_RESEED, (void(*)(void))drbg_hmac_reseed_wrapper }, + { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))drbg_enable_locking }, + { OSSL_FUNC_RAND_LOCK, (void(*)(void))drbg_lock }, + { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))drbg_unlock }, + { OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hmac_settable_ctx_params }, + { OSSL_FUNC_RAND_SET_CTX_PARAMS, (void(*)(void))drbg_hmac_set_ctx_params }, + { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, + (void(*)(void))drbg_hmac_gettable_ctx_params }, + { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))drbg_hmac_get_ctx_params }, + { OSSL_FUNC_RAND_SET_CALLBACKS, (void(*)(void))drbg_set_callbacks }, + { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, + (void(*)(void))drbg_hmac_verify_zeroization }, + { 0, NULL } +}; diff --git a/providers/implementations/rands/drbg_local.h b/providers/implementations/rands/drbg_local.h index a605186947..d9a06c7fb8 100644 --- a/providers/implementations/rands/drbg_local.h +++ b/providers/implementations/rands/drbg_local.h @@ -15,7 +15,7 @@ # include # include # include "internal/tsan_assist.h" - +# include "internal/nelem.h" # include "internal/numbers.h" /* How many times to read the TSC as a randomness source. */ @@ -26,10 +26,8 @@ # define MAX_RESEED_TIME_INTERVAL (1 << 20) /* approx. 12 days */ /* Default reseed intervals */ -# define MASTER_RESEED_INTERVAL (1 << 8) -# define SLAVE_RESEED_INTERVAL (1 << 16) -# define MASTER_RESEED_TIME_INTERVAL (60*60) /* 1 hour */ -# define SLAVE_RESEED_TIME_INTERVAL (7*60) /* 7 minutes */ +# define RESEED_INTERVAL (1 << 8) +# define TIME_INTERVAL (60*60) /* 1 hour */ /* * The number of bytes that constitutes an atomic lump of entropy with respect @@ -69,47 +67,34 @@ typedef enum drbg_status_e { } DRBG_STATUS; /* - * The DRBG methods - */ - -typedef struct rand_drbg_hmac_st { - EVP_MD *md; - HMAC_CTX *ctx; - size_t blocklen; - unsigned char K[EVP_MAX_MD_SIZE]; - unsigned char V[EVP_MAX_MD_SIZE]; -} PROV_DRBG_HMAC; - -/* - * The state of a DRBG AES-CTR. - */ -typedef struct rand_drbg_ctr_st { - EVP_CIPHER_CTX *ctx_ecb; - EVP_CIPHER_CTX *ctx_ctr; - EVP_CIPHER_CTX *ctx_df; - EVP_CIPHER *cipher_ecb; - EVP_CIPHER *cipher_ctr; - size_t keylen; - unsigned char K[32]; - unsigned char V[16]; - /* Temporary block storage used by ctr_df */ - unsigned char bltmp[16]; - size_t bltmp_pos; - unsigned char KX[48]; -} PROV_DRBG_CTR; - - -/* - * The state of all types of DRBGs, even though we only have CTR mode - * right now. + * The state of all types of DRBGs. */ struct prov_drbg_st { CRYPTO_RWLOCK *lock; - /* The library context this DRBG is associated with, if any */ - OPENSSL_CTX *libctx; + void *provctx; + + /* Virtual functions are cache here */ + int (*instantiate)(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen); + int (*uninstantiate)(PROV_DRBG *ctx); + int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len); + int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len); + + /* Parent PROV_RAND and its dispatch table functions */ void *parent; + OSSL_OP_rand_enable_locking_fn *parent_enable_locking; + OSSL_OP_rand_lock_fn *parent_lock; + OSSL_OP_rand_unlock_fn *parent_unlock; + OSSL_OP_rand_get_ctx_params_fn *parent_get_ctx_params; + OSSL_OP_rand_generate_fn *parent_generate; + OSSL_OP_rand_nonce_fn *parent_nonce; + const OSSL_DISPATCH *parent_dispatch; - int secure; /* 1: allocated on the secure heap, 0: otherwise */ + /* * Stores the return value of openssl_get_fork_id() as of when we last * reseeded. The DRBG reseeds automatically whenever drbg->fork_id != @@ -154,7 +139,7 @@ struct prov_drbg_st { * clarification. */ - int strength; + unsigned int strength; size_t max_request; size_t min_entropylen, max_entropylen; size_t min_noncelen, max_noncelen; @@ -188,83 +173,100 @@ struct prov_drbg_st { * is added by PROV_add() or PROV_seed() will have an immediate effect on * the output of PROV_bytes() resp. PROV_priv_bytes(). */ - TSAN_QUALIFIER unsigned int reseed_prop_counter; + TSAN_QUALIFIER unsigned int reseed_counter; unsigned int reseed_next_counter; + unsigned int parent_reseed_counter; size_t seedlen; DRBG_STATUS state; + /* DRBG specific data */ void *data; -#ifndef FIPS_MODULE - /* Application data, mainly used in the KATs. */ - CRYPTO_EX_DATA ex_data; -#endif + /* Entropy and nonce gathering callbacks */ + void *callback_arg; + OSSL_INOUT_CALLBACK *get_entropy_fn; + OSSL_CALLBACK *cleanup_entropy_fn; + OSSL_INOUT_CALLBACK *get_nonce_fn; + OSSL_CALLBACK *cleanup_nonce_fn; }; -/* DRBG helpers */ -int rand_drbg_restart(PROV_DRBG *drbg, - const unsigned char *buffer, size_t len, size_t entropy); -size_t rand_drbg_seedlen(PROV_DRBG *drbg); - -PROV_DRBG *prov_rand_drbg_new(void *provctx, int secure, void *parent, - const OSSL_DISPATCH *parent_dispatch, - int (*dnew)(PROV_DRBG *ctx, int secure)); -void prov_rand_free(PROV_DRBG *drbg); - -int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength, +PROV_DRBG *prov_rand_drbg_new + (void *provctx, void *parent, const OSSL_DISPATCH *parent_dispatch, + int (*dnew)(PROV_DRBG *ctx), + int (*instantiate)(PROV_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen), + int (*uninstantiate)(PROV_DRBG *ctx), + int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, + const unsigned char *adin, size_t adin_len), + int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adin_len)); +void prov_rand_drbg_free(PROV_DRBG *drbg); + +int PROV_DRBG_instantiate(PROV_DRBG *drbg, unsigned int strength, int prediction_resistance, - const unsigned char *pers, size_t perslen, - int (*ifnc)(PROV_DRBG *drbg, - const unsigned char *ent, size_t ent_len, - const unsigned char *nonce, - size_t nonce_len, - const unsigned char *pstr, - size_t pstr_len)); + const unsigned char *pers, size_t perslen); + +int PROV_DRBG_uninstantiate(PROV_DRBG *drbg); int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance, const unsigned char *ent, size_t ent_len, - const unsigned char *adin, size_t adinlen, - int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, - size_t ent_len, const unsigned char *adin, - size_t adin_len)); + const unsigned char *adin, size_t adinlen); int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, - int strength, int prediction_resistance, - const unsigned char *adin, size_t adinlen, - int (*generate)(PROV_DRBG *, unsigned char *out, - size_t outlen, const unsigned char *adin, - size_t adin_len), - int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, - size_t ent_len, const unsigned char *adin, - size_t adin_len)); + unsigned int strength, int prediction_resistance, + const unsigned char *adin, size_t adinlen); + +/* + * Entropy call back for the FIPS 140-2 section 4.9.2 Conditional Tests. + * These need to be exposed for the unit tests. + */ +int drbg_set_callbacks(void *vctx, OSSL_INOUT_CALLBACK *get_entropy_fn, + OSSL_CALLBACK *cleanup_entropy_fn, + OSSL_INOUT_CALLBACK *get_nonce_fn, + OSSL_CALLBACK *cleanup_nonce_fn, void *arg); + +/* Verify that an array of numeric values is all zero */ +#define PROV_DRBG_VERYIFY_ZEROIZATION(v) \ + { \ + size_t i; \ + \ + for (i = 0; i < OSSL_NELEM(v); i++) \ + if ((v)[i] != 0) \ + return 0; \ + } /* locking api */ OSSL_OP_rand_enable_locking_fn drbg_enable_locking; OSSL_OP_rand_lock_fn drbg_lock; OSSL_OP_rand_unlock_fn drbg_unlock; +/* Common parameters for all of our DRBGs */ int drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]); int drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]); #define OSSL_PARAM_DRBG_SETABLE_CTX_COMMON \ - OSSL_PARAM_uint(OSSL_RAND_PARAM_RESEED_REQUESTS, NULL), \ - OSSL_PARAM_uint64(OSSL_RAND_PARAM_RESEED_TIME_INTERVAL, NULL) + OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS, NULL), \ + OSSL_PARAM_uint64(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, NULL) #define OSSL_PARAM_DRBG_GETABLE_CTX_COMMON \ - OSSL_PARAM_int(OSSL_RAND_PARAM_STATUS, NULL), \ + 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_size_t(OSSL_RAND_PARAM_MIN_ENTROPYLEN, NULL), \ - OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_ENTROPYLEN, NULL), \ - OSSL_PARAM_size_t(OSSL_RAND_PARAM_MIN_NONCELEN, NULL), \ - OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_NONCELEN, NULL), \ - OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_PERSLEN, NULL), \ - OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_ADINLEN, NULL), \ - OSSL_PARAM_uint(OSSL_RAND_PARAM_RESEED_CTR, NULL), \ - OSSL_PARAM_uint(OSSL_RAND_PARAM_RESEED_REQUESTS, NULL), \ - OSSL_PARAM_uint64(OSSL_RAND_PARAM_RESEED_TIME_INTERVAL, NULL) - + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_REQUEST, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MIN_ENTROPYLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_ENTROPYLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MIN_NONCELEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_NONCELEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_PERSLEN, NULL), \ + OSSL_PARAM_size_t(OSSL_DRBG_PARAM_MAX_ADINLEN, NULL), \ + OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_CTR, NULL), \ + OSSL_PARAM_time_t(OSSL_DRBG_PARAM_RESEED_TIME, NULL), \ + OSSL_PARAM_uint(OSSL_DRBG_PARAM_RESEED_REQUESTS, NULL), \ + OSSL_PARAM_uint64(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, NULL) + +/* Continuous test "entropy" calls */ size_t prov_crngt_get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, size_t min_len, size_t max_len, @@ -272,16 +274,4 @@ size_t prov_crngt_get_entropy(PROV_DRBG *drbg, void prov_crngt_cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen); -/* - * Entropy call back for the FIPS 140-2 section 4.9.2 Conditional Tests. - * These need to be exposed for the unit tests. - */ -#if 0 -int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx, PROV_POOL *pool, - unsigned char *buf, unsigned char *md, - unsigned int *md_size); -extern int (*crngt_get_entropy)(OPENSSL_CTX *ctx, PROV_POOL *pool, - unsigned char *buf, unsigned char *md, - unsigned int *md_size); -#endif #endif diff --git a/providers/implementations/rands/test_rng.c b/providers/implementations/rands/test_rng.c index 41e83ab485..86fb979936 100644 --- a/providers/implementations/rands/test_rng.c +++ b/providers/implementations/rands/test_rng.c @@ -36,7 +36,7 @@ typedef struct { unsigned int strength; } PROV_TEST_RNG; -static int test_rng_new(PROV_DRBG *ctx, int secure) +static int test_rng_new(PROV_DRBG *ctx) { PROV_TEST_RNG *t; @@ -50,17 +50,9 @@ static int test_rng_new(PROV_DRBG *ctx, int secure) ctx->max_perslen = INT_MAX; ctx->max_adinlen = INT_MAX; ctx->max_request = INT_MAX; - ctx->strength = 1024; return 1; } -static void *test_rng_new_wrapper(void *provctx, int secure, void *parent, - const OSSL_DISPATCH *parent_dispatch) -{ - return prov_rand_drbg_new(provctx, secure, parent, parent_dispatch, - &test_rng_new); -} - static void test_rng_free(void *vdrbg) { PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; @@ -111,7 +103,7 @@ static int test_rng_uninstantiate(PROV_DRBG *drbg) PROV_TEST_RNG *t = (PROV_TEST_RNG *)drbg->data; t->entropy_pos = 0; - return 1; + return PROV_DRBG_uninstantiate(drbg); } static int test_rng_uninstantiate_wrapper(void *vdrbg) @@ -169,15 +161,6 @@ static int test_rng_reseed_wrapper(void *vdrbg, int prediction_resistance, return test_rng_reseed((PROV_DRBG *)vdrbg, ent, ent_len, adin, adin_len); } -static void *test_rng_new_wrapper(void *provctx, void *parent, - const OSSL_DISPATCH *parent_dispatch) -{ - return prov_rand_drbg_new(provctx, parent, parent_dispatch, - &test_rng_new, &test_rng_instantiate, - &test_rng_uninstantiate, &test_rng_reseed, - &test_rng_generate); -} - static size_t test_rng_nonce(void *vdrbg, unsigned char *out, unsigned int strength, size_t min_noncelen, size_t max_noncelen) @@ -307,6 +290,15 @@ static int test_rng_verify_zeroization(void *vdrbg) return 1; } +static void *test_rng_new_wrapper(void *provctx, void *parent, + const OSSL_DISPATCH *parent_dispatch) +{ + return prov_rand_drbg_new(provctx, parent, parent_dispatch, + &test_rng_new, &test_rng_instantiate, + &test_rng_uninstantiate, &test_rng_reseed, + &test_rng_generate); +} + const OSSL_DISPATCH test_rng_functions[] = { { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))test_rng_new_wrapper }, { OSSL_FUNC_RAND_FREECTX, (void(*)(void))test_rng_free }, -- 2.25.1