| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159 | /* * Copyright 2011-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (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 <string.h>#include <openssl/crypto.h>#include <openssl/err.h>#include <openssl/rand.h>#include "rand_lcl.h"#include "internal/thread_once.h"#include "internal/rand_int.h"#include "internal/cryptlib_int.h"/* * Support framework for NIST SP 800-90A DRBG * * See manual page RAND_DRBG(7) for a general overview. * * The OpenSSL model is to have new and free functions, and that new * does all initialization.  That is not the NIST model, which has * instantiation and un-instantiate, and re-use within a new/free * lifecycle.  (No doubt this comes from the desire to support hardware * DRBG, where allocation of resources on something like an HSM is * a much bigger deal than just re-setting an allocated resource.) *//* * The three shared DRBG instances * * There are three shared DRBG instances: <master>, <public>, and <private>. *//* * The <master> DRBG * * Not used directly by the application, only for reseeding the two other * DRBGs. It reseeds itself by pulling either randomness from os entropy * sources or by consuming randomness which was added by RAND_add(). * * The <master> DRBG is a global instance which is accessed concurrently by * all threads. The necessary locking is managed automatically by its child * DRBG instances during reseeding. */static RAND_DRBG *master_drbg;/* * The <public> DRBG * * Used by default for generating random bytes using RAND_bytes(). * * The <public> DRBG is thread-local, i.e., there is one instance per thread. */static CRYPTO_THREAD_LOCAL public_drbg;/* * The <private> DRBG * * Used by default for generating private keys using RAND_priv_bytes() * * The <private> DRBG is thread-local, i.e., there is one instance per thread. */static CRYPTO_THREAD_LOCAL private_drbg;/* NIST SP 800-90A DRBG recommends the use of a personalization string. */static const char ossl_pers_string[] = "OpenSSL NIST SP 800-90A DRBG";static CRYPTO_ONCE rand_drbg_init = CRYPTO_ONCE_STATIC_INIT;static int rand_drbg_type = RAND_DRBG_TYPE;static unsigned int rand_drbg_flags = RAND_DRBG_FLAGS;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;/* A logical OR of all used DRBG flag bits (currently there is only one) */static const unsigned int rand_drbg_used_flags =    RAND_DRBG_FLAG_CTR_NO_DF;static RAND_DRBG *drbg_setup(RAND_DRBG *parent);static RAND_DRBG *rand_drbg_new(int secure,                                int type,                                unsigned int flags,                                RAND_DRBG *parent);/* * Set/initialize |drbg| to be of type |type|, with optional |flags|. * * If |type| and |flags| are zero, use the defaults * * Returns 1 on success, 0 on failure. */int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags){    int ret = 1;    if (type == 0 && flags == 0) {        type = rand_drbg_type;        flags = rand_drbg_flags;    }    /* If set is called multiple times - clear the old one */    if (drbg->type != 0 && (type != drbg->type || flags != drbg->flags)) {        drbg->meth->uninstantiate(drbg);        rand_pool_free(drbg->adin_pool);        drbg->adin_pool = NULL;    }    drbg->state = DRBG_UNINITIALISED;    drbg->flags = flags;    drbg->type = type;    switch (type) {    default:        drbg->type = 0;        drbg->flags = 0;        drbg->meth = NULL;        RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE);        return 0;    case 0:        /* Uninitialized; that's okay. */        drbg->meth = NULL;        return 1;    case NID_aes_128_ctr:    case NID_aes_192_ctr:    case NID_aes_256_ctr:        ret = drbg_ctr_init(drbg);        break;    }    if (ret == 0) {        drbg->state = DRBG_ERROR;        RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_ERROR_INITIALISING_DRBG);    }    return ret;}/* * Set/initialize default |type| and |flag| for new drbg instances. * * Returns 1 on success, 0 on failure. */int RAND_DRBG_set_defaults(int type, unsigned int flags){    int ret = 1;    switch (type) {    default:        RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_TYPE);        return 0;    case NID_aes_128_ctr:    case NID_aes_192_ctr:    case NID_aes_256_ctr:        break;    }    if ((flags & ~rand_drbg_used_flags) != 0) {        RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_FLAGS);        return 0;    }    rand_drbg_type  = type;    rand_drbg_flags = flags;    return ret;}/* * 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. * 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(int secure,                                int type,                                unsigned int flags,                                RAND_DRBG *parent){    RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg))                             : OPENSSL_zalloc(sizeof(*drbg));    if (drbg == NULL) {        RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);        return NULL;    }    drbg->secure = secure && CRYPTO_secure_allocated(drbg);    drbg->fork_count = rand_fork_count;    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_free(drbg);    return NULL;}RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent){    return rand_drbg_new(0, type, flags, parent);}RAND_DRBG *RAND_DRBG_secure_new(int type, unsigned int flags, RAND_DRBG *parent){    return rand_drbg_new(1, type, flags, parent);}/* * Uninstantiate |drbg| and free all memory. */void RAND_DRBG_free(RAND_DRBG *drbg){    if (drbg == NULL)        return;    if (drbg->meth != NULL)        drbg->meth->uninstantiate(drbg);    rand_pool_free(drbg->adin_pool);    CRYPTO_THREAD_lock_free(drbg->lock);    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data);    if (drbg->secure)        OPENSSL_secure_clear_free(drbg, sizeof(*drbg));    else        OPENSSL_clear_free(drbg, sizeof(*drbg));}/* * Instantiate |drbg|, after it has been initialized.  Use |pers| and * |perslen| as prediction-resistance input. * * Requires that drbg->lock is already locked for write, if non-null. * * Returns 1 on success, 0 on failure. */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 = drbg->strength;    size_t min_entropylen = drbg->min_entropylen;    size_t 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->meth == NULL) {        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,                RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);        goto end;    }    if (drbg->state != DRBG_UNINITIALISED) {        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,                drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE                                          : 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 accomadate 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;}/* * 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 RAND_DRBG_uninstantiate(RAND_DRBG *drbg){    if (drbg->meth == NULL) {        drbg->state = DRBG_ERROR;        RANDerr(RAND_F_RAND_DRBG_UNINSTANTIATE,                RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED);        return 0;    }    /* Clear the entire drbg->ctr struct, then reset some important     * members of the drbg->ctr struct (e.g. keysize, df_ks) to their     * initial values.     */    drbg->meth->uninstantiate(drbg);    return RAND_DRBG_set(drbg, drbg->type, drbg->flags);}/* * Reseed |drbg|, mixing in the specified data * * Requires that drbg->lock is already locked for write, if non-null. * * Returns 1 on success, 0 on failure. */int RAND_DRBG_reseed(RAND_DRBG *drbg,                     const unsigned char *adin, size_t adinlen,                     int prediction_resistance){    unsigned char *entropy = NULL;    size_t entropylen = 0;    if (drbg->state == DRBG_ERROR) {        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_IN_ERROR_STATE);        return 0;    }    if (drbg->state == DRBG_UNINITIALISED) {        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_NOT_INSTANTIATED);        return 0;    }    if (adin == NULL) {        adinlen = 0;    } else if (adinlen > drbg->max_adinlen) {        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG);        return 0;    }    drbg->state = DRBG_ERROR;    drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);    if (drbg->reseed_next_counter) {        drbg->reseed_next_counter++;        if(!drbg->reseed_next_counter)            drbg->reseed_next_counter = 1;    }    if (drbg->get_entropy != NULL)        entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,                                       drbg->min_entropylen,                                       drbg->max_entropylen,                                       prediction_resistance);    if (entropylen < drbg->min_entropylen            || entropylen > drbg->max_entropylen) {        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY);        goto end;    }    if (!drbg->meth->reseed(drbg, entropy, entropylen, adin, adinlen))        goto end;    drbg->state = DRBG_READY;    drbg->reseed_gen_counter = 1;    drbg->reseed_time = time(NULL);    tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); end:    if (entropy != NULL && drbg->cleanup_entropy != NULL)        drbg->cleanup_entropy(drbg, entropy, entropylen);    if (drbg->state == DRBG_READY)        return 1;    return 0;}/* * 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. */int rand_drbg_restart(RAND_DRBG *drbg,                      const unsigned char *buffer, size_t len, size_t entropy){    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 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;        }    }    /* 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);    }    /* 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);        }    }    rand_pool_free(drbg->seed_pool);    drbg->seed_pool = NULL;    return drbg->state == DRBG_READY;}/* * 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){    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;        }    }    if (outlen > drbg->max_request) {        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG);        return 0;    }    if (adinlen > drbg->max_adinlen) {        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG);        return 0;    }    if (drbg->fork_count != rand_fork_count) {        drbg->fork_count = rand_fork_count;        reseed_required = 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;    }    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->meth->generate(drbg, out, outlen, adin, adinlen)) {        drbg->state = DRBG_ERROR;        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_GENERATE_ERROR);        return 0;    }    drbg->reseed_gen_counter++;    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){    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, drbg->max_adinlen);        if (drbg->adin_pool == NULL)            goto err;    }    additional_len = rand_drbg_get_additional_data(drbg->adin_pool,                                                   &additional);    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; err:    if (additional != NULL)        rand_drbg_cleanup_additional_data(drbg->adin_pool, additional);    return ret;}/* * Set the RAND_DRBG callbacks for obtaining entropy and nonce. * * Setting the callbacks is allowed only if the drbg has not been * initialized yet. Otherwise, the operation will fail. * * Returns 1 on success, 0 on failure. */int RAND_DRBG_set_callbacks(RAND_DRBG *drbg,                            RAND_DRBG_get_entropy_fn get_entropy,                            RAND_DRBG_cleanup_entropy_fn cleanup_entropy,                            RAND_DRBG_get_nonce_fn get_nonce,                            RAND_DRBG_cleanup_nonce_fn cleanup_nonce){    if (drbg->state != DRBG_UNINITIALISED            || drbg->parent != NULL)        return 0;    drbg->get_entropy = get_entropy;    drbg->cleanup_entropy = cleanup_entropy;    drbg->get_nonce = get_nonce;    drbg->cleanup_nonce = cleanup_nonce;    return 1;}/* * Set the reseed interval. * * The drbg will reseed automatically whenever the number of generate * requests exceeds the given reseed interval. If the reseed interval * is 0, then this feature is disabled. * * Returns 1 on success, 0 on failure. */int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval){    if (interval > MAX_RESEED_INTERVAL)        return 0;    drbg->reseed_interval = interval;    return 1;}/* * Set the reseed time interval. * * The drbg will reseed automatically whenever the time elapsed since * the last reseeding exceeds the given reseed time interval. For safety, * a reseeding will also occur if the clock has been reset to a smaller * value. * * Returns 1 on success, 0 on failure. */int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval){    if (interval > MAX_RESEED_TIME_INTERVAL)        return 0;    drbg->reseed_time_interval = interval;    return 1;}/* * Set the default values for reseed (time) intervals of new DRBG instances * * The default values can be set independently for master DRBG instances * (without a parent) and slave DRBG instances (with parent). * * Returns 1 on success, 0 on failure. */int RAND_DRBG_set_reseed_defaults(                                  unsigned int _master_reseed_interval,                                  unsigned int _slave_reseed_interval,                                  time_t _master_reseed_time_interval,                                  time_t _slave_reseed_time_interval                                  ){    if (_master_reseed_interval > MAX_RESEED_INTERVAL        || _slave_reseed_interval > MAX_RESEED_INTERVAL)        return 0;    if (_master_reseed_time_interval > MAX_RESEED_TIME_INTERVAL        || _slave_reseed_time_interval > MAX_RESEED_TIME_INTERVAL)        return 0;    master_reseed_interval = _master_reseed_interval;    slave_reseed_interval = _slave_reseed_interval;    master_reseed_time_interval = _master_reseed_time_interval;    slave_reseed_time_interval = _slave_reseed_time_interval;    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;}/* * Get and set the EXDATA */int RAND_DRBG_set_ex_data(RAND_DRBG *drbg, int idx, void *arg){    return CRYPTO_set_ex_data(&drbg->ex_data, idx, arg);}void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx){    return CRYPTO_get_ex_data(&drbg->ex_data, idx);}/* * The following functions provide a RAND_METHOD that works on the * global DRBG.  They lock. *//* * Allocates a new global DRBG on the secure heap (if enabled) and * initializes it with default settings. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */static RAND_DRBG *drbg_setup(RAND_DRBG *parent){    RAND_DRBG *drbg;    drbg = RAND_DRBG_secure_new(rand_drbg_type, rand_drbg_flags, parent);    if (drbg == NULL)        return NULL;    /* Only the master DRBG needs to have a lock */    if (parent == NULL && rand_drbg_enable_locking(drbg) == 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);    return drbg;err:    RAND_DRBG_free(drbg);    return NULL;}/* * Initialize the global DRBGs on first use. * Returns 1 on success, 0 on failure. */DEFINE_RUN_ONCE_STATIC(do_rand_drbg_init){    /*     * ensure that libcrypto is initialized, otherwise the     * DRBG locks are not cleaned up properly     */    if (!OPENSSL_init_crypto(0, NULL))        return 0;    if (!CRYPTO_THREAD_init_local(&private_drbg, NULL))        return 0;    if (!CRYPTO_THREAD_init_local(&public_drbg, NULL))        goto err1;    master_drbg = drbg_setup(NULL);    if (master_drbg == NULL)        goto err2;    return 1;err2:    CRYPTO_THREAD_cleanup_local(&public_drbg);err1:    CRYPTO_THREAD_cleanup_local(&private_drbg);    return 0;}/* Clean up the global DRBGs before exit */void rand_drbg_cleanup_int(void){    if (master_drbg != NULL) {        RAND_DRBG_free(master_drbg);        master_drbg = NULL;        CRYPTO_THREAD_cleanup_local(&private_drbg);        CRYPTO_THREAD_cleanup_local(&public_drbg);    }}void drbg_delete_thread_state(void){    RAND_DRBG *drbg;    drbg = CRYPTO_THREAD_get_local(&public_drbg);    CRYPTO_THREAD_set_local(&public_drbg, NULL);    RAND_DRBG_free(drbg);    drbg = CRYPTO_THREAD_get_local(&private_drbg);    CRYPTO_THREAD_set_local(&private_drbg, NULL);    RAND_DRBG_free(drbg);}/* Implements the default OpenSSL RAND_bytes() method */static int drbg_bytes(unsigned char *out, int count){    int ret;    RAND_DRBG *drbg = RAND_DRBG_get0_public();    if (drbg == NULL)        return 0;    ret = RAND_DRBG_bytes(drbg, out, count);    return ret;}/* * Calculates the minimum length of a full entropy buffer * which is necessary to seed (i.e. instantiate) the DRBG * successfully. */size_t rand_drbg_seedlen(RAND_DRBG *drbg){    /*     * If no os entropy source is available then RAND_seed(buffer, bufsize)     * is expected to succeed if and only if the buffer length satisfies     * the following requirements, which follow from the calculations     * in RAND_DRBG_instantiate().     */    size_t min_entropy = drbg->strength;    size_t min_entropylen = drbg->min_entropylen;    /*     * Extra entropy for the random nonce in the absence of a     * get_nonce callback, see comment in RAND_DRBG_instantiate().     */    if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) {        min_entropy += drbg->strength / 2;        min_entropylen += drbg->min_noncelen;    }    /*     * Convert entropy requirement from bits to bytes     * (dividing by 8 without rounding upwards, because     * all entropy requirements are divisible by 8).     */    min_entropy >>= 3;    /* Return a value that satisfies both requirements */    return min_entropy > min_entropylen ? min_entropy : min_entropylen;}/* Implements the default OpenSSL RAND_add() method */static int drbg_add(const void *buf, int num, double randomness){    int ret = 0;    RAND_DRBG *drbg = RAND_DRBG_get0_master();    size_t buflen;    size_t seedlen;    if (drbg == NULL)        return 0;    if (num < 0 || randomness < 0.0)        return 0;    rand_drbg_lock(drbg);    seedlen = rand_drbg_seedlen(drbg);    buflen = (size_t)num;    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 avaible 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;}/* Implements the default OpenSSL RAND_seed() method */static int drbg_seed(const void *buf, int num){    return drbg_add(buf, num, num);}/* Implements the default OpenSSL RAND_status() method */static int drbg_status(void){    int ret;    RAND_DRBG *drbg = RAND_DRBG_get0_master();    if (drbg == NULL)        return 0;    rand_drbg_lock(drbg);    ret = drbg->state == DRBG_READY ? 1 : 0;    rand_drbg_unlock(drbg);    return ret;}/* * Get the master DRBG. * Returns pointer to the DRBG on success, NULL on failure. * */RAND_DRBG *RAND_DRBG_get0_master(void){    if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))        return NULL;    return master_drbg;}/* * Get the public DRBG. * Returns pointer to the DRBG on success, NULL on failure. */RAND_DRBG *RAND_DRBG_get0_public(void){    RAND_DRBG *drbg;    if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))        return NULL;    drbg = CRYPTO_THREAD_get_local(&public_drbg);    if (drbg == NULL) {        if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND))            return NULL;        drbg = drbg_setup(master_drbg);        CRYPTO_THREAD_set_local(&public_drbg, drbg);    }    return drbg;}/* * Get the private DRBG. * Returns pointer to the DRBG on success, NULL on failure. */RAND_DRBG *RAND_DRBG_get0_private(void){    RAND_DRBG *drbg;    if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init))        return NULL;    drbg = CRYPTO_THREAD_get_local(&private_drbg);    if (drbg == NULL) {        if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND))            return NULL;        drbg = drbg_setup(master_drbg);        CRYPTO_THREAD_set_local(&private_drbg, drbg);    }    return drbg;}RAND_METHOD rand_meth = {    drbg_seed,    drbg_bytes,    NULL,    drbg_add,    drbg_bytes,    drbg_status};RAND_METHOD *RAND_OpenSSL(void){    return &rand_meth;}
 |