Commit 3ce1c27b authored by Dr. Matthias St. Pierre's avatar Dr. Matthias St. Pierre
Browse files

DRBG: add locking api



This commit adds three new accessors to the internal DRBG lock

   int RAND_DRBG_lock(RAND_DRBG *drbg)
   int RAND_DRBG_unlock(RAND_DRBG *drbg)
   int RAND_DRBG_enable_locking(RAND_DRBG *drbg)

The three shared DRBGs are intended to be used concurrently, so they
have locking enabled by default. It is the callers responsibility to
guard access to the shared DRBGs by calls to RAND_DRBG_lock() and
RAND_DRBG_unlock().

All other DRBG instances don't have locking enabled by default, because
they are intendended to be used by a single thread. If it is desired,
locking can be enabled by using RAND_DRBG_enable_locking().

Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5294)
parent fcd21502
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -890,6 +890,7 @@ RAND_F_DRBG_GET_ENTROPY:105:drbg_get_entropy
RAND_F_DRBG_SETUP:117:drbg_setup
RAND_F_GET_ENTROPY:106:get_entropy
RAND_F_RAND_BYTES:100:RAND_bytes
RAND_F_RAND_DRBG_ENABLE_LOCKING:119:RAND_DRBG_enable_locking
RAND_F_RAND_DRBG_GENERATE:107:RAND_DRBG_generate
RAND_F_RAND_DRBG_INSTANTIATE:108:RAND_DRBG_instantiate
RAND_F_RAND_DRBG_NEW:109:RAND_DRBG_new
@@ -2256,6 +2257,7 @@ RAND_R_ADDITIONAL_INPUT_TOO_LONG:102:additional input too long
RAND_R_ALREADY_INSTANTIATED:103:already instantiated
RAND_R_ARGUMENT_OUT_OF_RANGE:105:argument out of range
RAND_R_CANNOT_OPEN_FILE:121:Cannot open file
RAND_R_DRBG_ALREADY_INITIALIZED:129:drbg already initialized
RAND_R_DRBG_NOT_INITIALISED:104:drbg not initialised
RAND_R_ENTROPY_INPUT_TOO_LONG:106:entropy input too long
RAND_R_ENTROPY_OUT_OF_RANGE:124:entropy out of range
@@ -2274,6 +2276,7 @@ RAND_R_IN_ERROR_STATE:114:in error state
RAND_R_NOT_A_REGULAR_FILE:122:Not a regular file
RAND_R_NOT_INSTANTIATED:115:not instantiated
RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED:128:no drbg implementation selected
RAND_R_PARENT_LOCKING_NOT_ENABLED:130:parent locking not enabled
RAND_R_PERSONALISATION_STRING_TOO_LONG:116:personalisation string too long
RAND_R_PRNG_NOT_SEEDED:100:PRNG not seeded
RAND_R_RANDOM_POOL_OVERFLOW:125:random pool overflow
+84 −6
Original line number Diff line number Diff line
@@ -90,6 +90,21 @@ static RAND_DRBG *drbg_private;
 * |randomness| argument). This will immediately reseed the <master> DRBG.
 * The <public> and <private> DRBG will detect this on their next generate
 * call and reseed, pulling randomness from <master>.
 *
 * LOCKING
 *
 * The three shared DRBGs are intended to be used concurrently, so they
 * support locking by default. It is the callers responsibility to wrap
 * calls to functions like RAND_DRBG_generate() which modify the DRBGs
 * internal state with calls to RAND_DRBG_lock() and RAND_DRBG_unlock().
 * The functions RAND_bytes() and RAND_priv_bytes() take the locks
 * automatically, so using the RAND api is thread safe as before.
 *
 * All other DRBG instances don't have locking enabled by default, because
 * they are intendended to be used by a single thread. If it is desired,
 * locking can be enabled using RAND_DRBG_enable_locking(). However, instead
 * of accessing a single DRBG instance concurrently from different threads,
 * it is recommended to instantiate a separate DRBG instance per thread.
 */


@@ -656,6 +671,69 @@ int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t 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->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
 */
@@ -782,9 +860,9 @@ static int drbg_bytes(unsigned char *out, int count)
    if (drbg == NULL)
        return 0;

    CRYPTO_THREAD_write_lock(drbg->lock);
    RAND_DRBG_lock(drbg);
    ret = RAND_DRBG_bytes(drbg, out, count);
    CRYPTO_THREAD_unlock(drbg->lock);
    RAND_DRBG_unlock(drbg);

    return ret;
}
@@ -811,11 +889,11 @@ static int drbg_add(const void *buf, int num, double randomness)
        return 0;
    }

    CRYPTO_THREAD_write_lock(drbg->lock);
    RAND_DRBG_lock(drbg);
    ret = rand_drbg_restart(drbg, buf,
                            (size_t)(unsigned int)num,
                            (size_t)(8*randomness));
    CRYPTO_THREAD_unlock(drbg->lock);
    RAND_DRBG_unlock(drbg);

    return ret;
}
@@ -835,9 +913,9 @@ static int drbg_status(void)
    if (drbg == NULL)
        return 0;

    CRYPTO_THREAD_write_lock(drbg->lock);
    RAND_DRBG_lock(drbg);
    ret = drbg->state == DRBG_READY ? 1 : 0;
    CRYPTO_THREAD_unlock(drbg->lock);
    RAND_DRBG_unlock(drbg);
    return ret;
}

+6 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ static const ERR_STRING_DATA RAND_str_functs[] = {
    {ERR_PACK(ERR_LIB_RAND, RAND_F_DRBG_SETUP, 0), "drbg_setup"},
    {ERR_PACK(ERR_LIB_RAND, RAND_F_GET_ENTROPY, 0), "get_entropy"},
    {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_BYTES, 0), "RAND_bytes"},
    {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_ENABLE_LOCKING, 0),
     "RAND_DRBG_enable_locking"},
    {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_GENERATE, 0),
     "RAND_DRBG_generate"},
    {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_INSTANTIATE, 0),
@@ -49,6 +51,8 @@ static const ERR_STRING_DATA RAND_str_reasons[] = {
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ARGUMENT_OUT_OF_RANGE),
    "argument out of range"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_CANNOT_OPEN_FILE), "Cannot open file"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_DRBG_ALREADY_INITIALIZED),
    "drbg already initialized"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_DRBG_NOT_INITIALISED),
    "drbg not initialised"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ENTROPY_INPUT_TOO_LONG),
@@ -80,6 +84,8 @@ static const ERR_STRING_DATA RAND_str_reasons[] = {
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_NOT_INSTANTIATED), "not instantiated"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED),
    "no drbg implementation selected"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PARENT_LOCKING_NOT_ENABLED),
    "parent locking not enabled"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PERSONALISATION_STRING_TOO_LONG),
    "personalisation string too long"},
    {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"},
+8 −9
Original line number Diff line number Diff line
@@ -200,17 +200,16 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg,
            /*
             * Get random from parent, include our state as additional input.
             * Our lock is already held, but we need to lock our parent before
             * generating bits from it.
             * generating bits from it. (Note: taking the lock will be a no-op
             * if locking if drbg->parent->lock == NULL.)
             */
            if (drbg->parent->lock)
                CRYPTO_THREAD_write_lock(drbg->parent->lock);
            RAND_DRBG_lock(drbg->parent);
            if (RAND_DRBG_generate(drbg->parent,
                                   buffer, bytes_needed,
                                   0,
                                   (unsigned char *)drbg, sizeof(*drbg)) != 0)
                bytes = bytes_needed;
            if (drbg->parent->lock)
                CRYPTO_THREAD_unlock(drbg->parent->lock);
            RAND_DRBG_unlock(drbg->parent);

            entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
        }
@@ -406,9 +405,9 @@ int RAND_poll(void)
        if (drbg == NULL)
            return 0;

        CRYPTO_THREAD_write_lock(drbg->lock);
        RAND_DRBG_lock(drbg);
        ret = rand_drbg_restart(drbg, NULL, 0, 0);
        CRYPTO_THREAD_unlock(drbg->lock);
        RAND_DRBG_unlock(drbg);

        return ret;

@@ -798,9 +797,9 @@ int RAND_priv_bytes(unsigned char *buf, int num)
        return 0;

    /* We have to lock the DRBG before generating bits from it. */
    CRYPTO_THREAD_write_lock(drbg->lock);
    RAND_DRBG_lock(drbg);
    ret = RAND_DRBG_bytes(drbg, buf, num);
    CRYPTO_THREAD_unlock(drbg->lock);
    RAND_DRBG_unlock(drbg);
    return ret;
}

+4 −0
Original line number Diff line number Diff line
@@ -47,6 +47,10 @@ int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen);
int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval);
int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval);

int RAND_DRBG_lock(RAND_DRBG *drbg);
int RAND_DRBG_unlock(RAND_DRBG *drbg);
int RAND_DRBG_enable_locking(RAND_DRBG *drbg);

RAND_DRBG *RAND_DRBG_get0_master(void);
RAND_DRBG *RAND_DRBG_get0_public(void);
RAND_DRBG *RAND_DRBG_get0_private(void);
Loading