Commit a2f27fd7 authored by Matt Caswell's avatar Matt Caswell
Browse files

Move the rand_nonce_lock code into drbg_lib.c



It was previously rand_lib but it makes more sense in drbg_lib.c since
all the functions that use this lock are only ever called from drbg_lib.c

We add some FIPS_MODE defines in preparation for later moving this code
into the FIPS module.

Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9039)
parent 4e297b74
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -852,5 +852,6 @@ void OPENSSL_fork_parent(void)
void OPENSSL_fork_child(void)
{
    rand_fork();
    /* TODO(3.0): Inform all providers about a fork event */
}
#endif
+154 −54
Original line number Diff line number Diff line
@@ -69,6 +69,11 @@ typedef struct drbg_global_st {
    CRYPTO_THREAD_LOCAL private_drbg;
} DRBG_GLOBAL;

typedef struct drbg_nonce_global_st {
    CRYPTO_RWLOCK *rand_nonce_lock;
    int rand_nonce_count;
} DRBG_NONCE_GLOBAL;

/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING;

@@ -142,6 +147,149 @@ static int is_digest(int type)
    }
}

/*
 * Initialize the OPENSSL_CTX global DRBGs on first use.
 * Returns the allocated global data on success or NULL on failure.
 */
static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
{
    DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));

    if (dgbl == NULL)
        return NULL;

    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:
    OPENSSL_free(dgbl);
    return NULL;
}

static void drbg_ossl_ctx_free(void *vdgbl)
{
    DRBG_GLOBAL *dgbl = vdgbl;

    RAND_DRBG_free(dgbl->master_drbg);
    CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
    CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);

    OPENSSL_free(dgbl);
}

static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
    drbg_ossl_ctx_new,
    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;

    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, 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_secure_clear_free(out, outlen);
}

/*
 * Set/initialize |drbg| to be of type |type|, with optional |flags|.
 *
@@ -989,62 +1137,10 @@ err:
    return NULL;
}

/*
 * Initialize the OPENSSL_CTX global DRBGs on first use.
 * Returns the allocated global data on success or NULL on failure.
 */
static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
{
    DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));

    if (dgbl == NULL)
        return NULL;

    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:
    OPENSSL_free(dgbl);
    return NULL;
}

static void drbg_ossl_ctx_free(void *vdgbl)
{
    DRBG_GLOBAL *dgbl = vdgbl;

    RAND_DRBG_free(dgbl->master_drbg);
    CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
    CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);

    OPENSSL_free(dgbl);
}

static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
    drbg_ossl_ctx_new,
    drbg_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);
}

void drbg_delete_thread_state(void)
{
    /* TODO(3.0): Other PRs will pass the ctx as a param to this function */
    OPENSSL_CTX *ctx = NULL;
    DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
    RAND_DRBG *drbg;

@@ -1287,5 +1383,9 @@ RAND_METHOD rand_meth = {

RAND_METHOD *RAND_OpenSSL(void)
{
#ifndef FIPS_MODE
    return &rand_meth;
#else
    return NULL;
#endif
}
+37 −88
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "rand_lcl.h"
#include "e_os.h"

#ifndef FIPS_MODE
# ifndef OPENSSL_NO_ENGINE
/* non-NULL if default_RAND_meth is ENGINE-provided */
static ENGINE *funct_ref;
@@ -26,12 +27,10 @@ static CRYPTO_RWLOCK *rand_meth_lock;
static const RAND_METHOD *default_RAND_meth;
static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;

int rand_fork_count;

static CRYPTO_RWLOCK *rand_nonce_lock;
static int rand_nonce_count;

static int rand_inited = 0;
#endif /* FIPS_MODE */

int rand_fork_count;

#ifdef OPENSSL_RAND_SEED_RDTSC
/*
@@ -208,56 +207,6 @@ void rand_drbg_cleanup_entropy(RAND_DRBG *drbg,
        OPENSSL_secure_clear_free(out, outlen);
}


/*
 * 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;

    struct {
        void * instance;
        int count;
    } data;

    memset(&data, 0, sizeof(data));
    pool = rand_pool_new(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(&rand_nonce_count, 1, &data.count, 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_secure_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
@@ -292,6 +241,7 @@ void rand_fork(void)
    rand_fork_count++;
}

#ifndef FIPS_MODE
DEFINE_RUN_ONCE_STATIC(do_rand_init)
{
# ifndef OPENSSL_NO_ENGINE
@@ -302,25 +252,17 @@ DEFINE_RUN_ONCE_STATIC(do_rand_init)

    rand_meth_lock = CRYPTO_THREAD_lock_new();
    if (rand_meth_lock == NULL)
        goto err1;

    rand_nonce_lock = CRYPTO_THREAD_lock_new();
    if (rand_nonce_lock == NULL)
        goto err2;
        goto err;

    if (!rand_pool_init())
        goto err3;
        goto err;

    rand_inited = 1;
    return 1;

err3:
    CRYPTO_THREAD_lock_free(rand_nonce_lock);
    rand_nonce_lock = NULL;
err2:
 err:
    CRYPTO_THREAD_lock_free(rand_meth_lock);
    rand_meth_lock = NULL;
err1:
# ifndef OPENSSL_NO_ENGINE
    CRYPTO_THREAD_lock_free(rand_engine_lock);
    rand_engine_lock = NULL;
@@ -345,11 +287,10 @@ void rand_cleanup_int(void)
# endif
    CRYPTO_THREAD_lock_free(rand_meth_lock);
    rand_meth_lock = NULL;
    CRYPTO_THREAD_lock_free(rand_nonce_lock);
    rand_nonce_lock = NULL;
    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 decriptors are
 * closed after use.
@@ -371,8 +312,6 @@ int RAND_poll(void)
{
    int ret = 0;

    RAND_POOL *pool = NULL;

    const RAND_METHOD *meth = RAND_get_rand_method();

    if (meth == RAND_OpenSSL()) {
@@ -389,6 +328,8 @@ int RAND_poll(void)
        return ret;

    } else {
        RAND_POOL *pool = NULL;

        /* fill random pool and seed the current legacy RNG */
        pool = rand_pool_new(RAND_DRBG_STRENGTH,
                             (RAND_DRBG_STRENGTH + 7) / 8,
@@ -406,12 +347,14 @@ int RAND_poll(void)
            goto err;

        ret = 1;
    }

     err:
        rand_pool_free(pool);
    }

    return ret;
}
#endif /* FIPS_MODE */

/*
 * Allocate memory and initialize a new random pool
@@ -708,6 +651,7 @@ int rand_pool_add_end(RAND_POOL *pool, size_t len, size_t entropy)
    return 1;
}

#ifndef FIPS_MODE
int RAND_set_rand_method(const RAND_METHOD *meth)
{
    if (!RUN_ONCE(&rand_init, do_rand_init))
@@ -722,9 +666,13 @@ int RAND_set_rand_method(const RAND_METHOD *meth)
    CRYPTO_THREAD_unlock(rand_meth_lock);
    return 1;
}
#endif

const RAND_METHOD *RAND_get_rand_method(void)
{
#ifdef FIPS_MODE
    return NULL;
#else
    const RAND_METHOD *tmp_meth = NULL;

    if (!RUN_ONCE(&rand_init, do_rand_init))
@@ -751,9 +699,10 @@ const RAND_METHOD *RAND_get_rand_method(void)
    tmp_meth = default_RAND_meth;
    CRYPTO_THREAD_unlock(rand_meth_lock);
    return tmp_meth;
#endif
}

#ifndef OPENSSL_NO_ENGINE
#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE)
int RAND_set_rand_engine(ENGINE *engine)
{
    const RAND_METHOD *tmp_meth = NULL;
@@ -802,9 +751,9 @@ void RAND_add(const void *buf, int num, double randomness)
 */
int RAND_priv_bytes(unsigned char *buf, int num)
{
    const RAND_METHOD *meth = RAND_get_rand_method();
    RAND_DRBG *drbg;
    int ret;
    const RAND_METHOD *meth = RAND_get_rand_method();

    if (meth != RAND_OpenSSL())
        return RAND_bytes(buf, num);
@@ -827,7 +776,7 @@ int RAND_bytes(unsigned char *buf, int num)
    return -1;
}

#if !OPENSSL_API_1_1_0
#if !OPENSSL_API_1_1_0 && !defined(FIPS_MODE)
int RAND_pseudo_bytes(unsigned char *buf, int num)
{
    const RAND_METHOD *meth = RAND_get_rand_method();
+3 −2
Original line number Diff line number Diff line
@@ -147,8 +147,9 @@ typedef struct ossl_ex_data_global_st {
# define OPENSSL_CTX_PROPERTY_STRING_INDEX          3
# define OPENSSL_CTX_NAMEMAP_INDEX                  4
# define OPENSSL_CTX_DRBG_INDEX                     5
# define OPENSSL_CTX_RAND_CRNGT_INDEX               6
# define OPENSSL_CTX_MAX_INDEXES                    7
# define OPENSSL_CTX_DRBG_NONCE_INDEX               6
# define OPENSSL_CTX_RAND_CRNGT_INDEX               7
# define OPENSSL_CTX_MAX_INDEXES                    8

typedef struct openssl_ctx_method {
    void *(*new_func)(OPENSSL_CTX *ctx);