Commit d69226a3 authored by Pauli's avatar Pauli
Browse files

Add the FIPS related continuous random number generator (CRNG) testing.


Refer to FIPS 140-2 section 4.9.2 Conditional Tests for details.

The check is fairly simplistic, being for the entropy sources to not feed
the DRBG the same block of seed material twice in a row.  Only the first
DRBG in a chain is subject to this check, latter DRBGs are assumed to be
safely seeded via the earlier DRBGs.

Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/8599)
parent cd353c77
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -49,6 +49,14 @@ size_t rand_drbg_get_additional_data(RAND_POOL *pool, unsigned char **pout);

void rand_drbg_cleanup_additional_data(RAND_POOL *pool, unsigned char *out);

/* CRNG test entropy filter callbacks. */
size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
                              unsigned char **pout,
                              int entropy, size_t min_len, size_t max_len,
                              int prediction_resistance);
void rand_crngt_cleanup_entropy(RAND_DRBG *drbg,
                                unsigned char *out, size_t outlen);

/*
 * RAND_POOL functions
 */
+1 −1
Original line number Diff line number Diff line
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
        randfile.c rand_lib.c rand_err.c rand_egd.c \
        randfile.c rand_lib.c rand_err.c rand_crng_test.c rand_egd.c \
        rand_win.c rand_unix.c rand_vms.c drbg_lib.c drbg_ctr.c \
        drbg_hash.c drbg_hmac.c
+6 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ 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 const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING;

static CRYPTO_ONCE rand_drbg_init = CRYPTO_ONCE_STATIC_INIT;

@@ -254,8 +254,13 @@ static RAND_DRBG *rand_drbg_new(int secure,
    drbg->parent = parent;

    if (parent == NULL) {
#ifdef FIPS_MODE
        drbg->get_entropy = rand_crngt_get_entropy;
        drbg->cleanup_entropy = rand_crngt_cleanup_entropy;
#else
        drbg->get_entropy = rand_drbg_get_entropy;
        drbg->cleanup_entropy = rand_drbg_cleanup_entropy;
#endif
#ifndef RAND_DRBG_GET_RANDOM_NONCE
        drbg->get_nonce = rand_drbg_get_nonce;
        drbg->cleanup_nonce = rand_drbg_cleanup_nonce;
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright (c) 2019, Oracle and/or its affiliates.  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
 */

/*
 * Implementation of the FIPS 140-2 section 4.9.2 Conditional Tests.
 */

#include <string.h>
#include "internal/rand_int.h"
#include "internal/thread_once.h"
#include "rand_lcl.h"

static RAND_POOL *crngt_pool;
static unsigned char *crngt_prev;

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

int rand_crngt_get_entropy_cb(unsigned char *buf)
{
    size_t n;
    unsigned char *p;

    while ((n = rand_pool_acquire_entropy(crngt_pool)) != 0)
        if (n >= CRNGT_BUFSIZ) {
            p = rand_pool_detach(crngt_pool);
            memcpy(crngt_prev, p, CRNGT_BUFSIZ);
            rand_pool_reattach(crngt_pool, p);
            return 1;
        }
    return 0;

}
void rand_crngt_cleanup(void)
{
    rand_pool_free(crngt_pool);
    OPENSSL_secure_free(crngt_prev);
    crngt_pool = NULL;
    crngt_prev = NULL;
}

int rand_crngt_init(void)
{
    if ((crngt_pool = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL)
        return 0;
    if ((crngt_prev = OPENSSL_secure_malloc(CRNGT_BUFSIZ)) != NULL
        && crngt_get_entropy(crngt_prev))
        return 1;
    rand_crngt_cleanup();
    return 0;
}

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);
}

int rand_crngt_single_init(void)
{
    return RUN_ONCE(&rand_crngt_init_flag, do_rand_crngt_init);
}

size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
                              unsigned char **pout,
                              int entropy, size_t min_len, size_t max_len,
                              int prediction_resistance)
{
    unsigned char buf[CRNGT_BUFSIZ];
    RAND_POOL *pool;
    size_t q, r = 0, s, t = 0;
    int attempts = 3;

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

    if ((pool = rand_pool_new(entropy, min_len, max_len)) == NULL)
        return 0;

    while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) {
        s = q > sizeof(buf) ? sizeof(buf) : q;
        if (!crngt_get_entropy(buf)
            || memcmp(crngt_prev, buf, CRNGT_BUFSIZ) == 0
            || !rand_pool_add(pool, buf, s, s * 8))
            goto err;
        memcpy(crngt_prev, buf, CRNGT_BUFSIZ);
        t += s;
        attempts++;
    }
    r = t;
    *pout = rand_pool_detach(pool);
err:
    rand_pool_free(pool);
    return r;
}

void rand_crngt_cleanup_entropy(RAND_DRBG *drbg,
                                unsigned char *out, size_t outlen)
{
    OPENSSL_secure_clear_free(out, outlen);
}
+27 −2
Original line number Diff line number Diff line
@@ -33,7 +33,15 @@
# 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)
@@ -44,7 +52,8 @@
 */
# define DRBG_MAX_LENGTH                         INT32_MAX


/* The default nonce */
# define DRBG_DEFAULT_PERS_STRING                "OpenSSL NIST SP 800-90A DRBG"

/*
 * Maximum allocation size for RANDOM_POOL buffers
@@ -321,4 +330,20 @@ int drbg_ctr_init(RAND_DRBG *drbg);
int drbg_hash_init(RAND_DRBG *drbg);
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);
extern int (*crngt_get_entropy)(unsigned char *);
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
Loading