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 <Matthias.St.Pierre@ncp-e.com>
(Merged from https://github.com/openssl/openssl/pull/11682)
$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 \
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;
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 */ ;
--- /dev/null
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/evp.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/core.h>
+#include <openssl/core_names.h>
+#include <openssl/crypto.h>
+#include "crypto/asn1.h"
+#include "crypto/evp.h"
+#include "internal/cryptlib.h"
+#include "internal/numbers.h"
+#include "internal/provider.h"
+#include "evp_local.h"
+
+static int evp_rand_up_ref(void *vrand)
+{
+ EVP_RAND *rand = (EVP_RAND *)vrand;
+ int ref = 0;
+
+ if (rand != NULL)
+ return CRYPTO_UP_REF(&rand->refcnt, &ref, rand->refcnt_lock);
+ return 1;
+}
+
+static void evp_rand_free(void *vrand){
+ EVP_RAND *rand = (EVP_RAND *)vrand;
+ int ref = 0;
+
+ if (rand != NULL) {
+ CRYPTO_DOWN_REF(&rand->refcnt, &ref, rand->refcnt_lock);
+ if (ref <= 0) {
+ ossl_provider_free(rand->prov);
+ CRYPTO_THREAD_lock_free(rand->refcnt_lock);
+ OPENSSL_free(rand);
+ }
+ }
+}
+
+static void *evp_rand_new(void)
+{
+ EVP_RAND *rand = OPENSSL_zalloc(sizeof(*rand));
+
+ if (rand == NULL
+ || (rand->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL) {
+ OPENSSL_free(rand);
+ return NULL;
+ }
+ rand->refcnt = 1;
+ return rand;
+}
+
+/* Enable locking of the underlying DRBG/RAND if available */
+int EVP_RAND_enable_locking(EVP_RAND_CTX *rand)
+{
+ 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->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->unlock != NULL)
+ rand->meth->unlock(rand->data);
+}
+
+static void *evp_rand_from_dispatch(int name_id,
+ const OSSL_DISPATCH *fns,
+ OSSL_PROVIDER *prov)
+{
+ EVP_RAND *rand = NULL;
+ int fnrandcnt = 0, fnctxcnt = 0, fnlockcnt = 0;
+#ifdef FIPS_MODULE
+ int fnzeroizecnt = 0;
+#endif
+
+ if ((rand = evp_rand_new()) == NULL) {
+ EVPerr(0, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ rand->name_id = name_id;
+ rand->dispatch = fns;
+ for (; fns->function_id != 0; fns++) {
+ switch (fns->function_id) {
+ case OSSL_FUNC_RAND_NEWCTX:
+ if (rand->newctx != NULL)
+ break;
+ rand->newctx = OSSL_get_OP_rand_newctx(fns);
+ fnctxcnt++;
+ break;
+ case OSSL_FUNC_RAND_FREECTX:
+ if (rand->freectx != NULL)
+ break;
+ rand->freectx = OSSL_get_OP_rand_freectx(fns);
+ fnctxcnt++;
+ break;
+ case OSSL_FUNC_RAND_INSTANTIATE:
+ if (rand->instantiate != NULL)
+ break;
+ rand->instantiate = OSSL_get_OP_rand_instantiate(fns);
+ fnrandcnt++;
+ break;
+ case OSSL_FUNC_RAND_UNINSTANTIATE:
+ if (rand->uninstantiate != NULL)
+ break;
+ rand->uninstantiate = OSSL_get_OP_rand_uninstantiate(fns);
+ fnrandcnt++;
+ break;
+ case OSSL_FUNC_RAND_GENERATE:
+ if (rand->generate != NULL)
+ break;
+ rand->generate = OSSL_get_OP_rand_generate(fns);
+ fnrandcnt++;
+ break;
+ case OSSL_FUNC_RAND_RESEED:
+ if (rand->reseed != NULL)
+ break;
+ rand->reseed = OSSL_get_OP_rand_reseed(fns);
+ break;
+ case OSSL_FUNC_RAND_NONCE:
+ if (rand->nonce != NULL)
+ break;
+ rand->nonce = OSSL_get_OP_rand_nonce(fns);
+ break;
+ case OSSL_FUNC_RAND_SET_CALLBACKS:
+ if (rand->set_callbacks != NULL)
+ break;
+ rand->set_callbacks = OSSL_get_OP_rand_set_callbacks(fns);
+ break;
+ case OSSL_FUNC_RAND_ENABLE_LOCKING:
+ if (rand->enable_locking != NULL)
+ break;
+ rand->enable_locking = OSSL_get_OP_rand_enable_locking(fns);
+ fnlockcnt++;
+ break;
+ case OSSL_FUNC_RAND_LOCK:
+ if (rand->lock != NULL)
+ break;
+ rand->lock = OSSL_get_OP_rand_lock(fns);
+ fnlockcnt++;
+ break;
+ case OSSL_FUNC_RAND_UNLOCK:
+ if (rand->unlock != NULL)
+ break;
+ rand->unlock = OSSL_get_OP_rand_unlock(fns);
+ fnlockcnt++;
+ break;
+ case OSSL_FUNC_RAND_GETTABLE_PARAMS:
+ if (rand->gettable_params != NULL)
+ break;
+ rand->gettable_params =
+ OSSL_get_OP_rand_gettable_params(fns);
+ break;
+ case OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS:
+ if (rand->gettable_ctx_params != NULL)
+ break;
+ rand->gettable_ctx_params =
+ OSSL_get_OP_rand_gettable_ctx_params(fns);
+ break;
+ case OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS:
+ if (rand->settable_ctx_params != NULL)
+ break;
+ rand->settable_ctx_params =
+ OSSL_get_OP_rand_settable_ctx_params(fns);
+ break;
+ case OSSL_FUNC_RAND_GET_PARAMS:
+ if (rand->get_params != NULL)
+ break;
+ rand->get_params = OSSL_get_OP_rand_get_params(fns);
+ break;
+ case OSSL_FUNC_RAND_GET_CTX_PARAMS:
+ if (rand->get_ctx_params != NULL)
+ break;
+ rand->get_ctx_params = OSSL_get_OP_rand_get_ctx_params(fns);
+ break;
+ case OSSL_FUNC_RAND_SET_CTX_PARAMS:
+ if (rand->set_ctx_params != NULL)
+ break;
+ rand->set_ctx_params = OSSL_get_OP_rand_set_ctx_params(fns);
+ break;
+ case OSSL_FUNC_RAND_VERIFY_ZEROIZATION:
+ if (rand->verify_zeroization != NULL)
+ break;
+ rand->verify_zeroization = OSSL_get_OP_rand_verify_zeroization(fns);
+#ifdef FIPS_MODULE
+ 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
+ || fnzeroizecnt != 1
+#endif
+ ) {
+ 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;
+
+ return rand;
+}
+
+EVP_RAND *EVP_RAND_fetch(OPENSSL_CTX *libctx, const char *algorithm,
+ const char *properties)
+{
+ return evp_generic_fetch(libctx, OSSL_OP_RAND, algorithm, properties,
+ evp_rand_from_dispatch, evp_rand_up_ref,
+ evp_rand_free);
+}
+
+int EVP_RAND_up_ref(EVP_RAND *rand)
+{
+ return evp_rand_up_ref(rand);
+}
+
+void EVP_RAND_free(EVP_RAND *rand)
+{
+ evp_rand_free(rand);
+}
+
+int EVP_RAND_number(const EVP_RAND *rand)
+{
+ return rand->name_id;
+}
+
+const char *EVP_RAND_name(const EVP_RAND *rand)
+{
+ return evp_first_name(rand->prov, rand->name_id);
+}
+
+int EVP_RAND_is_a(const EVP_RAND *rand, const char *name)
+{
+ return evp_is_a(rand->prov, rand->name_id, NULL, name);
+}
+
+const OSSL_PROVIDER *EVP_RAND_provider(const EVP_RAND *rand)
+{
+ return rand->prov;
+}
+
+int EVP_RAND_get_params(EVP_RAND *rand, OSSL_PARAM params[])
+{
+ if (rand->get_params != NULL)
+ return rand->get_params(params);
+ return 1;
+}
+
+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) {
+ EVPerr(0, EVP_R_INVALID_NULL_ALGORITHM);
+ return NULL;
+ }
+
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ EVPerr(0, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (parent != NULL) {
+ 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), parent_ctx,
+ parent_dispatch)) == NULL
+ || !EVP_RAND_up_ref(rand)) {
+ EVPerr(0, ERR_R_MALLOC_FAILURE);
+ rand->freectx(ctx->data);
+ OPENSSL_free(ctx);
+ return NULL;
+ }
+ ctx->meth = rand;
+ return ctx;
+}
+
+void EVP_RAND_CTX_free(EVP_RAND_CTX *ctx)
+{
+ if (ctx != NULL) {
+ ctx->meth->freectx(ctx->data);
+ ctx->data = NULL;
+ EVP_RAND_free(ctx->meth);
+ OPENSSL_free(ctx);
+ }
+}
+
+EVP_RAND *EVP_RAND_CTX_rand(EVP_RAND_CTX *ctx)
+{
+ return ctx->meth;
+}
+
+int EVP_RAND_get_ctx_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[])
+{
+ int res = 1;
+
+ if (ctx->meth->get_ctx_params != NULL) {
+ if (!evp_rand_lock(ctx))
+ return 0;
+ res = ctx->meth->get_ctx_params(ctx->data, params);
+ evp_rand_unlock(ctx);
+ }
+ return res;
+}
+
+int EVP_RAND_set_ctx_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[])
+{
+ int res = 1;
+
+ if (ctx->meth->set_ctx_params != NULL) {
+ if (!evp_rand_lock(ctx))
+ return 0;
+ res = ctx->meth->set_ctx_params(ctx->data, params);
+ evp_rand_unlock(ctx);
+ /* Clear out the cache state because the values can change on a set */
+ ctx->strength = 0;
+ ctx->max_request = 0;
+ }
+ return res;
+}
+
+const OSSL_PARAM *EVP_RAND_gettable_params(const EVP_RAND *rand)
+{
+ return rand->gettable_params == NULL ? NULL : rand->gettable_params();
+}
+
+const OSSL_PARAM *EVP_RAND_gettable_ctx_params(const EVP_RAND *rand)
+{
+ return rand->gettable_ctx_params == NULL ? NULL
+ : rand->gettable_ctx_params();
+}
+
+const OSSL_PARAM *EVP_RAND_settable_ctx_params(const EVP_RAND *rand)
+{
+ return rand->settable_ctx_params == NULL ? NULL
+ :rand->settable_ctx_params();
+}
+
+void EVP_RAND_do_all_provided(OPENSSL_CTX *libctx,
+ void (*fn)(EVP_RAND *rand, void *arg),
+ void *arg)
+{
+ evp_generic_do_all(libctx, OSSL_OP_RAND,
+ (void (*)(void *, void *))fn, arg,
+ evp_rand_from_dispatch, evp_rand_free);
+}
+
+void EVP_RAND_names_do_all(const EVP_RAND *rand,
+ void (*fn)(const char *name, void *data),
+ void *data)
+{
+ if (rand->prov != NULL)
+ evp_names_do_all(rand->prov, rand->name_id, fn, data);
+}
+
+int EVP_RAND_instantiate(EVP_RAND_CTX *ctx, unsigned int strength,
+ int prediction_resistance,
+ const unsigned char *pstr, size_t pstr_len)
+{
+ int res;
+
+ if (!evp_rand_lock(ctx))
+ return 0;
+ res = ctx->meth->instantiate(ctx->data, strength, prediction_resistance,
+ pstr, pstr_len);
+ evp_rand_unlock(ctx);
+ return res;
+}
+
+int EVP_RAND_uninstantiate(EVP_RAND_CTX *ctx)
+{
+ int res;
+
+ if (!evp_rand_lock(ctx))
+ return 0;
+ res = ctx->meth->uninstantiate(ctx->data);
+ evp_rand_unlock(ctx);
+ return res;
+}
+
+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];
+ int res = 0;
+
+ if (!evp_rand_lock(ctx))
+ return 0;
+ if (ctx->max_request == 0) {
+ params[0] = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_REQUEST,
+ &chunk);
+ params[1] = OSSL_PARAM_construct_end();
+ 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)) {
+ 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:
+ evp_rand_unlock(ctx);
+ return res;
+}
+
+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;
+
+ if (!evp_rand_lock(ctx))
+ return 0;
+ if (ctx->meth->reseed != NULL)
+ res = ctx->meth->reseed(ctx->data, prediction_resistance,
+ ent, ent_len, addin, addin_len);
+ evp_rand_unlock(ctx);
+ return res;
+}
+
+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, 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_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, &t);
+ params[1] = OSSL_PARAM_construct_end();
+ if (!evp_rand_lock(ctx))
+ return 0;
+ 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_state(EVP_RAND_CTX *ctx)
+{
+ OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+ int status, res;
+
+ params[0] = OSSL_PARAM_construct_int(OSSL_RAND_PARAM_STATE,
+ &status);
+ if (!evp_rand_lock(ctx))
+ return 0;
+ res = EVP_RAND_get_ctx_params(ctx, params);
+ evp_rand_unlock(ctx);
+ if (!res)
+ status = EVP_RAND_STATE_ERROR;
+ return status;
+}
+
+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;
+
+ if (ctx->meth->verify_zeroization != NULL) {
+ if (!evp_rand_lock(ctx))
+ return 0;
+ res = ctx->meth->verify_zeroization(ctx->data);
+ evp_rand_unlock(ctx);
+ }
+ return res;
+}
+++ /dev/null
-/*
- * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include <openssl/evp.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "internal/cryptlib.h"
-#include <openssl/engine.h>
-#include <openssl/evp.h>
-#include <openssl/x509v3.h>
-#include <openssl/rand.h>
-#include <openssl/core.h>
-#include <openssl/core_names.h>
-#include <openssl/crypto.h>
-#include "crypto/asn1.h"
-#include "crypto/evp.h"
-#include "internal/numbers.h"
-#include "internal/provider.h"
-#include "evp_local.h"
-
-static int evp_rand_up_ref(void *vrand)
-{
- EVP_RAND *rand = (EVP_RAND *)vrand;
- int ref = 0;
-
- if (rand != NULL)
- return CRYPTO_UP_REF(&rand->refcnt, &ref, rand->lock);
- return 1;
-}
-
-static void evp_rand_free(void *vrand){
- EVP_RAND *rand = (EVP_RAND *)vrand;
- int ref = 0;
-
- if (rand != NULL) {
- CRYPTO_DOWN_REF(&rand->refcnt, &ref, rand->lock);
- if (ref <= 0) {
- ossl_provider_free(rand->prov);
- CRYPTO_THREAD_lock_free(rand->lock);
- OPENSSL_free(rand);
- }
- }
-}
-
-static void *evp_rand_new(void)
-{
- EVP_RAND *rand = NULL;
-
- if ((rand = OPENSSL_zalloc(sizeof(*rand))) == NULL
- || (rand->lock = CRYPTO_THREAD_lock_new()) == NULL) {
- evp_rand_free(rand);
- return NULL;
- }
- rand->refcnt = 1;
- return rand;
-}
-
-/* Enable locking of the underlying DRBG/RAND if available */
-int EVP_RAND_CTX_enable_locking(EVP_RAND_CTX *rand)
-{
- if (rand->meth->enable_prov_locking != NULL)
- return rand->meth->enable_prov_locking(rand->data);
- return 1;
-}
-
-/* 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);
- 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);
-}
-
-static void *evp_rand_from_dispatch(int name_id,
- const OSSL_DISPATCH *fns,
- OSSL_PROVIDER *prov)
-{
- EVP_RAND *rand = NULL;
- int fnrandcnt = 0, fnctxcnt = 0;
-#ifdef FIPS_MODULE
- int fnfipscnt = 0;
-#endif
-
- if ((rand = evp_rand_new()) == NULL) {
- EVPerr(0, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- rand->name_id = name_id;
- rand->dispatch = fns;
- for (; fns->function_id != 0; fns++) {
- switch (fns->function_id) {
- case OSSL_FUNC_RAND_NEWCTX:
- if (rand->newctx != NULL)
- break;
- rand->newctx = OSSL_get_OP_rand_newctx(fns);
- fnctxcnt++;
- break;
- case OSSL_FUNC_RAND_FREECTX:
- if (rand->freectx != NULL)
- break;
- rand->freectx = OSSL_get_OP_rand_freectx(fns);
- fnctxcnt++;
- break;
- case OSSL_FUNC_RAND_INSTANTIATE:
- if (rand->instantiate != NULL)
- break;
- rand->instantiate = OSSL_get_OP_rand_instantiate(fns);
- fnrandcnt++;
- break;
- case OSSL_FUNC_RAND_UNINSTANTIATE:
- if (rand->uninstantiate != NULL)
- break;
- rand->uninstantiate = OSSL_get_OP_rand_uninstantiate(fns);
- fnrandcnt++;
- break;
- case OSSL_FUNC_RAND_GENERATE:
- if (rand->generate != NULL)
- break;
- rand->generate = OSSL_get_OP_rand_generate(fns);
- fnrandcnt++;
- break;
- case OSSL_FUNC_RAND_RESEED:
- if (rand->reseed != NULL)
- break;
- rand->reseed = OSSL_get_OP_rand_reseed(fns);
- break;
- case OSSL_FUNC_RAND_NONCE:
- if (rand->nonce != NULL)
- break;
- rand->nonce = OSSL_get_OP_rand_nonce(fns);
- break;
- case OSSL_FUNC_RAND_SET_CALLBACKS:
- if (rand->set_callbacks != NULL)
- break;
- rand->set_callbacks = OSSL_get_OP_rand_set_callbacks(fns);
- break;
- case OSSL_FUNC_RAND_ENABLE_LOCKING:
- if (rand->enable_prov_locking != NULL)
- break;
- rand->enable_prov_locking = OSSL_get_OP_rand_enable_locking(fns);
- break;
- case OSSL_FUNC_RAND_LOCK:
- if (rand->prov_lock != NULL)
- break;
- rand->prov_lock = OSSL_get_OP_rand_lock(fns);
- break;
- case OSSL_FUNC_RAND_UNLOCK:
- if (rand->prov_unlock != NULL)
- break;
- rand->prov_unlock = OSSL_get_OP_rand_unlock(fns);
- break;
- case OSSL_FUNC_RAND_GETTABLE_PARAMS:
- if (rand->gettable_params != NULL)
- break;
- rand->gettable_params =
- OSSL_get_OP_rand_gettable_params(fns);
- break;
- case OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS:
- if (rand->gettable_ctx_params != NULL)
- break;
- rand->gettable_ctx_params =
- OSSL_get_OP_rand_gettable_ctx_params(fns);
- break;
- case OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS:
- if (rand->settable_ctx_params != NULL)
- break;
- rand->settable_ctx_params =
- OSSL_get_OP_rand_settable_ctx_params(fns);
- break;
- case OSSL_FUNC_RAND_GET_PARAMS:
- if (rand->get_params != NULL)
- break;
- rand->get_params = OSSL_get_OP_rand_get_params(fns);
- break;
- case OSSL_FUNC_RAND_GET_CTX_PARAMS:
- if (rand->get_ctx_params != NULL)
- break;
- rand->get_ctx_params = OSSL_get_OP_rand_get_ctx_params(fns);
- break;
- case OSSL_FUNC_RAND_SET_CTX_PARAMS:
- if (rand->set_ctx_params != NULL)
- break;
- rand->set_ctx_params = OSSL_get_OP_rand_set_ctx_params(fns);
- break;
- case OSSL_FUNC_RAND_VERIFY_ZEROIZATION:
- if (rand->verify_zeroization != NULL)
- break;
- rand->verify_zeroization = OSSL_get_OP_rand_verify_zeroization(fns);
-#ifdef FIPS_MODULE
- fnfipscnt++;
-#endif
- break;
- }
- }
- if (fnrandcnt != 3
- || fnctxcnt != 2
-#ifdef FIPS_MODULE
- || fnfipscnt != 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;
- }
- 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)
-{
- return evp_generic_fetch(libctx, OSSL_OP_RAND, algorithm, properties,
- evp_rand_from_dispatch, evp_rand_up_ref,
- evp_rand_free);
-}
-
-int EVP_RAND_up_ref(EVP_RAND *rand)
-{
- return evp_rand_up_ref(rand);
-}
-
-void EVP_RAND_free(EVP_RAND *rand)
-{
- evp_rand_free(rand);
-}
-
-int EVP_RAND_number(const EVP_RAND *rand)
-{
- return rand->name_id;
-}
-
-const char *EVP_RAND_name(const EVP_RAND *rand)
-{
- return evp_first_name(rand->prov, rand->name_id);
-}
-
-int EVP_RAND_is_a(const EVP_RAND *rand, const char *name)
-{
- return evp_is_a(rand->prov, rand->name_id, NULL, name);
-}
-
-const OSSL_PROVIDER *EVP_RAND_provider(const EVP_RAND *rand)
-{
- return rand->prov;
-}
-
-int EVP_RAND_get_params(EVP_RAND *rand, OSSL_PARAM params[])
-{
- if (rand->get_params != NULL)
- return rand->get_params(params);
- return 1;
-}
-
-EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, int secure, EVP_RAND_CTX *parent)
-{
- EVP_RAND_CTX *ctx;
- void *parent_ctx = NULL;
- const OSSL_DISPATCH *parent_dispatch = NULL;
-
- if (rand == NULL)
- return NULL;
-
- ctx = OPENSSL_zalloc(sizeof(EVP_RAND_CTX));
- if (ctx == NULL)
- return NULL;
- if (parent != NULL) {
- EVP_RAND_CTX_enable_locking(parent);
- 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
- || !EVP_RAND_up_ref(rand)) {
- EVPerr(0, ERR_R_MALLOC_FAILURE);
- rand->freectx(ctx->data);
- OPENSSL_free(ctx);
- return NULL;
- }
- ctx->meth = rand;
- return ctx;
-}
-
-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);
- }
-}
-
-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 res = 1;
-
- if (ctx->meth->get_ctx_params != NULL) {
- if (!evp_rand_lock(ctx))
- return 0;
- res = ctx->meth->get_ctx_params(ctx->data, params);
- evp_rand_unlock(ctx);
- }
- return res;
-}
-
-int EVP_RAND_CTX_set_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[])
-{
- int res = 1;
-
- if (ctx->meth->set_ctx_params != NULL) {
- if (!evp_rand_lock(ctx))
- return 0;
- res = ctx->meth->set_ctx_params(ctx->data, params);
- evp_rand_unlock(ctx);
- /* Clear out the cache state because the values can change on a set */
- ctx->strength = 0;
- ctx->max_request = 0;
- }
- return res;
-}
-
-const OSSL_PARAM *EVP_RAND_gettable_params(const EVP_RAND *rand)
-{
- if (rand->gettable_params == NULL)
- return NULL;
- return 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();
-}
-
-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();
-}
-
-void EVP_RAND_do_all_provided(OPENSSL_CTX *libctx,
- void (*fn)(EVP_RAND *rand, void *arg),
- void *arg)
-{
- evp_generic_do_all(libctx, OSSL_OP_RAND,
- (void (*)(void *, void *))fn, arg,
- evp_rand_from_dispatch, evp_rand_free);
-}
-
-void EVP_RAND_names_do_all(const EVP_RAND *rand,
- void (*fn)(const char *name, void *data),
- void *data)
-{
- if (rand->prov != NULL)
- 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 res;
-
- if (!evp_rand_lock(ctx))
- return 0;
- res = ctx->meth->instantiate(ctx->data, strength, prediction_resistance,
- pstr, pstr_len);
- evp_rand_unlock(ctx);
- return res;
-}
-
-int EVP_RAND_CTX_uninstantiate(EVP_RAND_CTX *ctx)
-{
- int res;
-
- if (!evp_rand_lock(ctx))
- return 0;
- res = ctx->meth->uninstantiate(ctx->data);
- evp_rand_unlock(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)
-{
- size_t chunk;
- OSSL_PARAM params[2];
- int res = 0;
-
- if (!evp_rand_lock(ctx))
- return 0;
- if (ctx->max_request == 0) {
- params[0] = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_REQUEST,
- &ctx->max_request);
- params[1] = OSSL_PARAM_construct_end();
- if (!EVP_RAND_CTX_get_params(ctx, params)
- || ctx->max_request == 0)
- goto err;
- }
- 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))
- goto err;
- }
- res = 1;
-err:
- evp_rand_unlock(ctx);
- 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 res = 1;
-
- if (!evp_rand_lock(ctx))
- return 0;
- if (ctx->meth->reseed != NULL)
- res = ctx->meth->reseed(ctx->data, prediction_resistance,
- ent, ent_len, addin, addin_len);
- evp_rand_unlock(ctx);
- return res;
-}
-
-int EVP_RAND_CTX_nonce(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen)
-{
- int res = 1;
-
- 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);
- evp_rand_unlock(ctx);
- return res;
-}
-
-unsigned int EVP_RAND_CTX_strength(EVP_RAND_CTX *ctx)
-{
- OSSL_PARAM params[2];
- int res;
-
- if (ctx->strength == 0) {
- params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH,
- &ctx->strength);
- params[1] = OSSL_PARAM_construct_end();
- if (!evp_rand_lock(ctx))
- return 0;
- res = EVP_RAND_CTX_get_params(ctx, params);
- evp_rand_unlock(ctx);
- if (!res)
- return 0;
- }
- return ctx->strength;
-}
-
-int EVP_RAND_CTX_state(EVP_RAND_CTX *ctx)
-{
- OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
- int status, res;
-
- params[0] = OSSL_PARAM_construct_int(OSSL_RAND_PARAM_STATE,
- &status);
- if (!evp_rand_lock(ctx))
- return 0;
- res = EVP_RAND_CTX_get_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 res = 0;
-
- if (ctx->meth->verify_zeroization != NULL) {
- if (!evp_rand_lock(ctx))
- return 0;
- res = ctx->meth->verify_zeroization(ctx->data);
- evp_rand_unlock(ctx);
- }
- return res;
-}
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
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/core_names.h>
#include "rand_local.h"
#include "internal/thread_once.h"
#include "crypto/rand.h"
-#include "crypto/rand_pool.h"
#include "crypto/cryptlib.h"
/*
*
* There are three shared DRBG instances: <master>, <public>, and <private>.
*/
+ CRYPTO_RWLOCK *lock;
/*
* The <master> DRBG
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 )
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;
}
/*
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;
}
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);
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
*
*/
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;
*/
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.
*
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;
}
/*
- * 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);
}
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:
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)
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.
*/
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);
}
/*
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);
}
/*
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)
flags = drbg->flags;
type = drbg->type;
}
- return rand_drbg_set(drbg, type, flags);
+ return RAND_DRBG_set(drbg, type, flags);
}
/*
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;
}
/*
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;
}
*/
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);
}
/*
*/
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);
}
/*
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
*/
{
return CRYPTO_get_ex_data(&drbg->ex_data, idx);
}
-#endif
/*
* The following functions provide a RAND_METHOD that works on the
{
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:
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 */
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.
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;
}
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
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;
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
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;
#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;
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
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)
{
*/
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),
goto err;
ret = 1;
-
err:
rand_pool_free(pool);
}
-
return ret;
}
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))
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;
CRYPTO_THREAD_unlock(rand_engine_lock);
return 1;
}
-#endif
+# endif
void RAND_seed(const void *buf, int num)
{
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
{
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;
-}
# include <openssl/rand_drbg.h>
# include "internal/tsan_assist.h"
# include "crypto/rand.h"
-# include "crypto/rand_pool.h"
# include "internal/numbers.h"
# 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 */
/* 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
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,
void RAND_DRBG_free(RAND_DRBG *drbg);
+Deprecated since OpenSSL 3.0, can be hidden entirely by defining
+B<OPENSSL_API_COMPAT> with a suitable version value, see
+L<openssl_user_macros(7)>:
+
+ 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<type>, allocated from the heap resp.
-the secure heap, for the given OPENSSL_CTX <ctx>
-(using OPENSSL_zalloc() resp. OPENSSL_secure_zalloc()). The <ctx> 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<type> for the given OPENSSL_CTX <ctx>.
+The <ctx> 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<drbg> with the given B<type> and B<flags>.
+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<type> and B<flags> for new DRBG
instances.
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
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<OPENSSL_zalloc(3)>,
=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
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<get_nonce>() and B<cleanup_nonce>()
callbacks can be omitted by setting them to NULL.
#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 */
# 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,
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))
(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))
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);
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
DEPRECATEDIN_1_1_0(int RAND_event(UINT, WPARAM, LPARAM))
# endif
-
#ifdef __cplusplus
}
#endif
*/
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);
};
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 }
};
};
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 }
};
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
#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];
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/evp.h>
#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
* 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;
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;
}
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())
*
* 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))
* 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;
}
}
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) {
* 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) {
*pout = rand_pool_detach(pool);
}
+err:
if (drbg->seed_pool == NULL)
rand_pool_free(pool);
return ret;
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 {
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;
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
*
* 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;
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 */
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;
}
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
*
*/
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;
}
*
*/
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;
}
|| 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;
}
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;
}
}
*
* 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;
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) {
* 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;
}
}
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;
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;
}
{
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;
+}
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/aes.h>
+#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;
} 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;
/*
* 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;
/*
* 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;
* 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;
/*
* 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)
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);
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)
* 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;
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))
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;
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;
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;
} 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;
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;
}
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 }
+};
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <openssl/sha.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/core_numbers.h>
#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).
* 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] */
* (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))
}
/* 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)
{
* 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;
}
/* 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))
*
* 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;
*
* 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:
*
*
* 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))
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:
*
*
* 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;
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) */
&& 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 }
+};
* 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 <stdlib.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#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.
*
* 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));
}
/*
*
* 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))
*
* 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);
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:
*
*
* 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)
{
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:
*
*
* 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
* }
*/
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;
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 }
+};
# include <openssl/core_names.h>
# include <openssl/params.h>
# include "internal/tsan_assist.h"
-
+# include "internal/nelem.h"
# include "internal/numbers.h"
/* How many times to read the TSC as a randomness source. */
# 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
} 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 !=
* clarification.
*/
- int strength;
+ unsigned int strength;
size_t max_request;
size_t min_entropylen, max_entropylen;
size_t min_noncelen, max_noncelen;
* 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,
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
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;
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;
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)
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)
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 },