Commit 4e297b74 authored by Matt Caswell's avatar Matt Caswell
Browse files

Make the rand_crng code OPENSSL_CTX aware



This is in preparation for moving this code inside the FIPS module.

Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9039)
parent da0d114c
Loading
Loading
Loading
Loading
+61 −44
Original line number Diff line number Diff line
@@ -16,64 +16,78 @@
#include <openssl/evp.h>
#include "internal/rand_int.h"
#include "internal/thread_once.h"
#include "internal/cryptlib.h"
#include "rand_lcl.h"

static RAND_POOL *crngt_pool;
static unsigned char crngt_prev[EVP_MAX_MD_SIZE];
typedef struct crng_test_global_st {
    unsigned char crngt_prev[EVP_MAX_MD_SIZE];
    RAND_POOL *crngt_pool;
} CRNG_TEST_GLOBAL;

int (*crngt_get_entropy)(unsigned char *, unsigned char *, unsigned int *)
int (*crngt_get_entropy)(OPENSSL_CTX *, unsigned char *, unsigned char *,
                         unsigned int *)
    = &rand_crngt_get_entropy_cb;

int rand_crngt_get_entropy_cb(unsigned char *buf, unsigned char *md,
                              unsigned int *md_size)
static void rand_crng_ossl_ctx_free(void *vcrngt_glob)
{
    int r;
    size_t n;
    unsigned char *p;
    CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob;

    n = rand_pool_acquire_entropy(crngt_pool);
    if (n >= CRNGT_BUFSIZ) {
        p = rand_pool_detach(crngt_pool);
        r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, EVP_sha256(), NULL);
        if (r != 0)
            memcpy(buf, p, CRNGT_BUFSIZ);
        rand_pool_reattach(crngt_pool, p);
        return r;
    }
    return 0;
}

void rand_crngt_cleanup(void)
{
    rand_pool_free(crngt_pool);
    crngt_pool = NULL;
    rand_pool_free(crngt_glob->crngt_pool);
    OPENSSL_free(crngt_glob);
}

int rand_crngt_init(void)
static void *rand_crng_ossl_ctx_new(OPENSSL_CTX *ctx)
{
    unsigned char buf[CRNGT_BUFSIZ];
    CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob));

    if ((crngt_pool = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL)
        return 0;
    if (crngt_get_entropy(buf, crngt_prev, NULL)) {
    if (crngt_glob == NULL)
        return NULL;

    if ((crngt_glob->crngt_pool
         = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) {
        OPENSSL_free(crngt_glob);
        return NULL;
    }
    if (crngt_get_entropy(ctx, buf, crngt_glob->crngt_prev, NULL)) {
        OPENSSL_cleanse(buf, sizeof(buf));
        return 1;
        return crngt_glob;
    }
    rand_crngt_cleanup();
    return 0;
    rand_pool_free(crngt_glob->crngt_pool);
    OPENSSL_free(crngt_glob);
    return NULL;
}

static CRYPTO_ONCE rand_crngt_init_flag = CRYPTO_ONCE_STATIC_INIT;
DEFINE_RUN_ONCE_STATIC(do_rand_crngt_init)
{
    return OPENSSL_init_crypto(0, NULL)
        && rand_crngt_init()
        && OPENSSL_atexit(&rand_crngt_cleanup);
}
static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = {
    rand_crng_ossl_ctx_new,
    rand_crng_ossl_ctx_free,
};

int rand_crngt_single_init(void)
int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx,
                              unsigned char *buf,
                              unsigned char *md,
                              unsigned int *md_size)
{
    return RUN_ONCE(&rand_crngt_init_flag, do_rand_crngt_init);
    int r;
    size_t n;
    unsigned char *p;
    CRNG_TEST_GLOBAL *crngt_glob
        = openssl_ctx_get_data(ctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
                               &rand_crng_ossl_ctx_method);

    if (crngt_glob == NULL)
        return 0;

    n = rand_pool_acquire_entropy(crngt_glob->crngt_pool);
    if (n >= CRNGT_BUFSIZ) {
        p = rand_pool_detach(crngt_glob->crngt_pool);
        r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, EVP_sha256(), NULL);
        if (r != 0)
            memcpy(buf, p, CRNGT_BUFSIZ);
        rand_pool_reattach(crngt_glob->crngt_pool, p);
        return r;
    }
    return 0;
}

size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
@@ -86,8 +100,11 @@ size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
    RAND_POOL *pool;
    size_t q, r = 0, s, t = 0;
    int attempts = 3;
    CRNG_TEST_GLOBAL *crngt_glob
        = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
                               &rand_crng_ossl_ctx_method);

    if (!RUN_ONCE(&rand_crngt_init_flag, do_rand_crngt_init))
    if (crngt_glob == NULL)
        return 0;

    if ((pool = rand_pool_new(entropy, min_len, max_len)) == NULL)
@@ -95,11 +112,11 @@ size_t rand_crngt_get_entropy(RAND_DRBG *drbg,

    while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) {
        s = q > sizeof(buf) ? sizeof(buf) : q;
        if (!crngt_get_entropy(buf, md, &sz)
            || memcmp(crngt_prev, md, sz) == 0
        if (!crngt_get_entropy(drbg->libctx, buf, md, &sz)
            || memcmp(crngt_glob->crngt_prev, md, sz) == 0
            || !rand_pool_add(pool, buf, s, s * 8))
            goto err;
        memcpy(crngt_prev, md, sz);
        memcpy(crngt_glob->crngt_prev, md, sz);
        t += s;
        attempts++;
    }
+4 −12
Original line number Diff line number Diff line
@@ -336,18 +336,10 @@ int drbg_hmac_init(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(unsigned char *buf, unsigned char *md,
int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx, unsigned char *buf,
                              unsigned char *md, unsigned int *md_size);
extern int (*crngt_get_entropy)(OPENSSL_CTX *ctx, unsigned char *buf,
                                unsigned char *md,
                                unsigned int *md_size);
extern int (*crngt_get_entropy)(unsigned char *buf, unsigned char *md,
                                unsigned int *md_size);
int rand_crngt_init(void);
void rand_crngt_cleanup(void);

/*
 * Expose the run once initialisation function for the unit tests because.
 * they need to restart from scratch to validate the first block is skipped
 * properly.
 */
int rand_crngt_single_init(void);

#endif
+2 −1
Original line number Diff line number Diff line
@@ -147,7 +147,8 @@ 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_MAX_INDEXES                    6
# define OPENSSL_CTX_RAND_CRNGT_INDEX               6
# define OPENSSL_CTX_MAX_INDEXES                    7

typedef struct openssl_ctx_method {
    void *(*new_func)(OPENSSL_CTX *ctx);
+7 −8
Original line number Diff line number Diff line
@@ -1264,7 +1264,8 @@ static const size_t crngt_num_cases = 6;

static size_t crngt_case, crngt_idx;

static int crngt_entropy_cb(unsigned char *buf, unsigned char *md,
static int crngt_entropy_cb(OPENSSL_CTX *ctx, unsigned char *buf,
                            unsigned char *md,
                            unsigned int *md_size)
{
    size_t i, z;
@@ -1288,19 +1289,16 @@ static int test_crngt(int n)
    size_t ent;
    int res = 0;
    int expect;
    OPENSSL_CTX *ctx = OPENSSL_CTX_new();

    if (!TEST_true(rand_crngt_single_init()))
        return 0;
    rand_crngt_cleanup();

    if (!TEST_ptr(drbg = RAND_DRBG_new(dt->nid, dt->flags, NULL)))
    if (!TEST_ptr(ctx))
        return 0;
    if (!TEST_ptr(drbg = RAND_DRBG_new_ex(ctx, dt->nid, dt->flags, NULL)))
        goto err;
    ent = (drbg->min_entropylen + CRNGT_BUFSIZ - 1) / CRNGT_BUFSIZ;
    crngt_case = n % crngt_num_cases;
    crngt_idx = 0;
    crngt_get_entropy = &crngt_entropy_cb;
    if (!TEST_true(rand_crngt_init()))
        goto err;
#ifndef FIPS_MODE
    if (!TEST_true(RAND_DRBG_set_callbacks(drbg, &rand_crngt_get_entropy,
                                           &rand_crngt_cleanup_entropy,
@@ -1333,6 +1331,7 @@ err:
    uninstantiate(drbg);
    RAND_DRBG_free(drbg);
    crngt_get_entropy = &rand_crngt_get_entropy_cb;
    OPENSSL_CTX_free(ctx);
    return res;
}