rand_lib.c 9.9 KB
Newer Older
R
Rich Salz 已提交
1 2
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * 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
8 9 10 11
 */

#include <stdio.h>
#include <time.h>
12
#include "internal/cryptlib.h"
13
#include <openssl/opensslconf.h>
R
Rich Salz 已提交
14
#include "internal/rand_int.h"
R
Rich Salz 已提交
15
#include <openssl/engine.h>
16
#include "internal/thread_once.h"
R
Rich Salz 已提交
17
#include "rand_lcl.h"
18

19
#ifndef OPENSSL_NO_ENGINE
20
/* non-NULL if default_RAND_meth is ENGINE-provided */
R
Rich Salz 已提交
21 22
static ENGINE *funct_ref;
static CRYPTO_RWLOCK *rand_engine_lock;
23
#endif
R
Rich Salz 已提交
24 25 26
static CRYPTO_RWLOCK *rand_meth_lock;
static const RAND_METHOD *default_RAND_meth;
static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
R
Rich Salz 已提交
27
RAND_BYTES_BUFFER rand_bytes;
28

R
Rich Salz 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#ifdef OPENSSL_RAND_SEED_RDTSC
/*
 * IMPORTANT NOTE:  It is not currently possible to use this code
 * because we are not sure about the amount of randomness.  Some
 * SP900 tests have been run, but there is internal skepticism.
 * So for now this code is not used.
 */
# error "RDTSC enabled?  Should not be possible!"

/*
 * Since we get some randomness from the low-order bits of the
 * high-speec clock, it can help.  But don't return a status since
 * it's not sufficient to indicate whether or not the seeding was
 * done.
 */
R
Rich Salz 已提交
44
void rand_read_tsc(RAND_poll_fn cb, void *arg)
R
Rich Salz 已提交
45 46 47 48 49 50
{
    unsigned char c;
    int i;

    for (i = 0; i < 10; i++) {
        c = (unsigned char)(OPENSSL_rdtsc() & 0xFF);
R
Rich Salz 已提交
51
        cb(arg, &c, 1, 0.5);
R
Rich Salz 已提交
52 53 54 55 56 57 58 59 60 61
    }
}
#endif

#ifdef OPENSSL_RAND_SEED_RDCPU
size_t OPENSSL_ia32_rdseed(void);
size_t OPENSSL_ia32_rdrand(void);

extern unsigned int OPENSSL_ia32cap_P[];

R
Rich Salz 已提交
62
int rand_read_cpu(RAND_poll_fn cb, void *arg)
R
Rich Salz 已提交
63 64 65 66 67 68 69 70 71
{
    size_t i, s;

    /* If RDSEED is available, use that. */
    if ((OPENSSL_ia32cap_P[1] & (1 << 18)) != 0) {
        for (i = 0; i < RANDOMNESS_NEEDED; i += sizeof(s)) {
            s = OPENSSL_ia32_rdseed();
            if (s == 0)
                break;
R
Rich Salz 已提交
72
            cb(arg, &s, (int)sizeof(s), sizeof(s));
R
Rich Salz 已提交
73 74 75 76 77 78 79 80 81 82 83
        }
        if (i >= RANDOMNESS_NEEDED)
            return 1;
    }

    /* Second choice is RDRAND. */
    if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
        for (i = 0; i < RANDOMNESS_NEEDED; i += sizeof(s)) {
            s = OPENSSL_ia32_rdrand();
            if (s == 0)
                break;
R
Rich Salz 已提交
84
            cb(arg, &s, (int)sizeof(s), sizeof(s));
R
Rich Salz 已提交
85 86 87 88 89 90 91 92
        }
        if (i >= RANDOMNESS_NEEDED)
            return 1;
    }

    return 0;
}
#endif
R
Rich Salz 已提交
93

R
Rich Salz 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

/*
 * DRBG has two sets of callbacks; we only discuss the "entropy" one
 * here.  When the DRBG needs additional randomness bits (called entropy
 * in the NIST document), it calls the get_entropy callback which fills in
 * a pointer and returns the number of bytes. When the DRBG is finished with
 * the buffer, it calls the cleanup_entropy callback, with the value of
 * the buffer that the get_entropy callback filled in.
 *
 * Get entropy from the system, via RAND_poll if needed.  The |entropy|
 * is the bits of randomness required, and is expected to fit into a buffer
 * of |min_len|..|max__len| size.  We assume we're getting high-quality
 * randomness from the system, and that |min_len| bytes will do.
 */
size_t drbg_entropy_from_system(RAND_DRBG *drbg,
                                unsigned char **pout,
                                int entropy, size_t min_len, size_t max_len)
{
    int i;


    if (min_len > (size_t)drbg->size) {
        /* Should not happen.  See comment near RANDOMNESS_NEEDED. */
        min_len = drbg->size;
    }

    if (rand_drbg.filled) {
        /* Re-use what we have. */
        *pout = drbg->randomness;
        return drbg->size;
    }

    /* If we don't have enough, try to get more. */
    CRYPTO_THREAD_write_lock(rand_bytes.lock);
    for (i = RAND_POLL_RETRIES; rand_bytes.curr < min_len && --i >= 0; ) {
        CRYPTO_THREAD_unlock(rand_bytes.lock);
        RAND_poll();
        CRYPTO_THREAD_write_lock(rand_bytes.lock);
    }

    /* Get desired amount, but no more than we have. */
    if (min_len > rand_bytes.curr)
        min_len = rand_bytes.curr;
    if (min_len != 0) {
        memcpy(drbg->randomness, rand_bytes.buff, min_len);
        rand_drbg.filled = 1;
        /* Update amount left and shift it down. */
        rand_bytes.curr -= min_len;
        if (rand_bytes.curr != 0)
            memmove(rand_bytes.buff, &rand_bytes.buff[min_len], rand_bytes.curr);
    }
    CRYPTO_THREAD_unlock(rand_bytes.lock);
    return min_len;
}

size_t drbg_entropy_from_parent(RAND_DRBG *drbg,
                                unsigned char **pout,
                                int entropy, size_t min_len, size_t max_len)
{
    int st;

    if (min_len > (size_t)drbg->size) {
        /* Should not happen.  See comment near RANDOMNESS_NEEDED. */
        min_len = drbg->size;
    }

    /* Get random from parent, include our state as additional input. */
    st = RAND_DRBG_generate(drbg->parent, drbg->randomness, min_len, 0,
                            (unsigned char *)drbg, sizeof(*drbg));
    if (st == 0)
        return 0;
    drbg->filled = 1;
    return min_len;
}

void drbg_release_entropy(RAND_DRBG *drbg, unsigned char *out)
{
    drbg->filled = 0;
    OPENSSL_cleanse(drbg->randomness, sizeof(drbg->randomness));
}

R
Rich Salz 已提交
175
DEFINE_RUN_ONCE_STATIC(do_rand_init)
176
{
177
    int ret = 1;
R
Rich Salz 已提交
178

179 180
#ifndef OPENSSL_NO_ENGINE
    rand_engine_lock = CRYPTO_THREAD_lock_new();
181
    ret &= rand_engine_lock != NULL;
182 183
#endif
    rand_meth_lock = CRYPTO_THREAD_lock_new();
184
    ret &= rand_meth_lock != NULL;
R
Rich Salz 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

    rand_bytes.lock = CRYPTO_THREAD_lock_new();
    ret &= rand_bytes.lock != NULL;
    rand_bytes.curr = 0;
    rand_bytes.size = MAX_RANDOMNESS_HELD;
    /* TODO: Should this be secure malloc? */
    rand_bytes.buff = malloc(rand_bytes.size);
    ret &= rand_bytes.buff != NULL;

    rand_drbg.lock = CRYPTO_THREAD_lock_new();
    ret &= rand_drbg.lock != NULL;
    rand_drbg.size = RANDOMNESS_NEEDED;
    rand_drbg.randomness = OPENSSL_malloc(rand_drbg.size);
    ret &= rand_drbg.randomness != NULL;
    /* If you change these parameters, see RANDOMNESS_NEEDED */
    ret &= RAND_DRBG_set(&rand_drbg,
                         NID_aes_128_ctr, RAND_DRBG_FLAG_CTR_USE_DF) == 1;
    ret &= RAND_DRBG_set_callbacks(&rand_drbg, drbg_entropy_from_system,
                                   drbg_release_entropy,
                                   NULL, NULL) == 1;
205
    return ret;
206
}
207

R
Rich Salz 已提交
208 209 210 211 212 213 214 215 216 217 218
void rand_cleanup_int(void)
{
    const RAND_METHOD *meth = default_RAND_meth;

    if (meth != NULL && meth->cleanup != NULL)
        meth->cleanup();
    RAND_set_rand_method(NULL);
#ifndef OPENSSL_NO_ENGINE
    CRYPTO_THREAD_lock_free(rand_engine_lock);
#endif
    CRYPTO_THREAD_lock_free(rand_meth_lock);
R
Rich Salz 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
    CRYPTO_THREAD_lock_free(rand_bytes.lock);
    OPENSSL_clear_free(rand_drbg.randomness, rand_drbg.size);
    CRYPTO_THREAD_lock_free(rand_drbg.lock);
    RAND_DRBG_uninstantiate(&rand_drbg);
}

/*
 * RAND_poll_ex() gets a function pointer to call when it has random bytes.
 * RAND_poll() sets the function pointer to be a wrapper that calls RAND_add().
 */
static void call_rand_add(void* arg, const void *buf, int num, double r)
{
    RAND_add(buf, num, r);
}

int RAND_poll(void)
{
    return RAND_poll_ex(call_rand_add, NULL);
R
Rich Salz 已提交
237 238
}

239
int RAND_set_rand_method(const RAND_METHOD *meth)
240
{
R
Rich Salz 已提交
241
    if (!RUN_ONCE(&rand_init, do_rand_init))
242 243 244
        return 0;

    CRYPTO_THREAD_write_lock(rand_meth_lock);
245
#ifndef OPENSSL_NO_ENGINE
R
Rich Salz 已提交
246 247
    ENGINE_finish(funct_ref);
    funct_ref = NULL;
248
#endif
249
    default_RAND_meth = meth;
250
    CRYPTO_THREAD_unlock(rand_meth_lock);
251 252
    return 1;
}
253

254
const RAND_METHOD *RAND_get_rand_method(void)
255
{
256 257
    const RAND_METHOD *tmp_meth = NULL;

R
Rich Salz 已提交
258
    if (!RUN_ONCE(&rand_init, do_rand_init))
259 260 261
        return NULL;

    CRYPTO_THREAD_write_lock(rand_meth_lock);
R
Rich Salz 已提交
262
    if (default_RAND_meth == NULL) {
263
#ifndef OPENSSL_NO_ENGINE
R
Rich Salz 已提交
264 265 266 267 268
        ENGINE *e;

        /* If we have an engine that can do RAND, use it. */
        if ((e = ENGINE_get_default_RAND()) != NULL
                && (tmp_meth = ENGINE_get_RAND(e)) != NULL) {
269
            funct_ref = e;
R
Rich Salz 已提交
270 271 272
            default_RAND_meth = tmp_meth;
        } else {
            ENGINE_finish(e);
R
Rich Salz 已提交
273
            default_RAND_meth = &rand_meth;
R
Rich Salz 已提交
274 275
        }
#else
R
Rich Salz 已提交
276
        default_RAND_meth = &rand_meth;
277
#endif
278
    }
279 280 281
    tmp_meth = default_RAND_meth;
    CRYPTO_THREAD_unlock(rand_meth_lock);
    return tmp_meth;
282
}
283

284
#ifndef OPENSSL_NO_ENGINE
285
int RAND_set_rand_engine(ENGINE *engine)
286 287
{
    const RAND_METHOD *tmp_meth = NULL;
288

R
Rich Salz 已提交
289
    if (!RUN_ONCE(&rand_init, do_rand_init))
290 291
        return 0;

R
Rich Salz 已提交
292
    if (engine != NULL) {
293 294 295
        if (!ENGINE_init(engine))
            return 0;
        tmp_meth = ENGINE_get_RAND(engine);
R
Rich Salz 已提交
296
        if (tmp_meth == NULL) {
297 298 299 300
            ENGINE_finish(engine);
            return 0;
        }
    }
301
    CRYPTO_THREAD_write_lock(rand_engine_lock);
302 303 304
    /* This function releases any prior ENGINE so call it first */
    RAND_set_rand_method(tmp_meth);
    funct_ref = engine;
305
    CRYPTO_THREAD_unlock(rand_engine_lock);
306 307
    return 1;
}
308
#endif
309

310
void RAND_seed(const void *buf, int num)
311 312
{
    const RAND_METHOD *meth = RAND_get_rand_method();
R
Rich Salz 已提交
313 314

    if (meth->seed != NULL)
315 316
        meth->seed(buf, num);
}
317

R
Rich Salz 已提交
318
void RAND_add(const void *buf, int num, double randomness)
319 320
{
    const RAND_METHOD *meth = RAND_get_rand_method();
R
Rich Salz 已提交
321 322 323

    if (meth->add != NULL)
        meth->add(buf, num, randomness);
324
}
325

326
int RAND_bytes(unsigned char *buf, int num)
327 328
{
    const RAND_METHOD *meth = RAND_get_rand_method();
R
Rich Salz 已提交
329 330

    if (meth->bytes != NULL)
331
        return meth->bytes(buf, num);
R
Rich Salz 已提交
332
    RANDerr(RAND_F_RAND_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED);
R
Rich Salz 已提交
333
    return -1;
334
}
335

336
#if OPENSSL_API_COMPAT < 0x10100000L
337
int RAND_pseudo_bytes(unsigned char *buf, int num)
338 339
{
    const RAND_METHOD *meth = RAND_get_rand_method();
R
Rich Salz 已提交
340 341

    if (meth->pseudorand != NULL)
342
        return meth->pseudorand(buf, num);
R
Rich Salz 已提交
343
    return -1;
344
}
M
Matt Caswell 已提交
345
#endif
346 347

int RAND_status(void)
348 349
{
    const RAND_METHOD *meth = RAND_get_rand_method();
R
Rich Salz 已提交
350 351

    if (meth->status != NULL)
352 353 354
        return meth->status();
    return 0;
}