drbg_lib.c 13.3 KB
Newer Older
R
Rich Salz 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright 2011-2017 The OpenSSL Project Authors. All Rights Reserved.
 *
 * 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
 */

#include <string.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "rand_lcl.h"
15 16
#include "internal/thread_once.h"
#include "internal/rand_int.h"
R
Rich Salz 已提交
17

K
Kurt Roeckx 已提交
18 19 20
static RAND_DRBG rand_drbg; /* The default global DRBG. */
static RAND_DRBG priv_drbg; /* The global private-key DRBG. */

R
Rich Salz 已提交
21 22
/*
 * Support framework for NIST SP 800-90A DRBG, AES-CTR mode.
R
Rich Salz 已提交
23 24
 * The RAND_DRBG is OpenSSL's pointer to an instance of the DRBG.
 *
R
Rich Salz 已提交
25 26 27 28 29 30 31 32
 * The OpenSSL model is to have new and free functions, and that new
 * does all initialization.  That is not the NIST model, which has
 * instantiation and un-instantiate, and re-use within a new/free
 * lifecycle.  (No doubt this comes from the desire to support hardware
 * DRBG, where allocation of resources on something like an HSM is
 * a much bigger deal than just re-setting an allocated resource.)
 */

33 34
static CRYPTO_ONCE rand_init_drbg = CRYPTO_ONCE_STATIC_INIT;

R
Rich Salz 已提交
35
/*
R
Rich Salz 已提交
36
 * Set/initialize |drbg| to be of type |nid|, with optional |flags|.
R
Rich Salz 已提交
37 38 39
 * Return -2 if the type is not supported, 1 on success and -1 on
 * failure.
 */
R
Rich Salz 已提交
40
int RAND_DRBG_set(RAND_DRBG *drbg, int nid, unsigned int flags)
R
Rich Salz 已提交
41 42 43
{
    int ret = 1;

R
Rich Salz 已提交
44 45 46
    drbg->state = DRBG_UNINITIALISED;
    drbg->flags = flags;
    drbg->nid = nid;
R
Rich Salz 已提交
47 48 49 50 51 52 53 54 55 56 57

    switch (nid) {
    default:
        RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE);
        return -2;
    case 0:
        /* Uninitialized; that's okay. */
        return 1;
    case NID_aes_128_ctr:
    case NID_aes_192_ctr:
    case NID_aes_256_ctr:
R
Rich Salz 已提交
58
        ret = ctr_init(drbg);
R
Rich Salz 已提交
59 60 61 62 63 64 65 66 67 68
        break;
    }

    if (ret < 0)
        RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_ERROR_INITIALISING_DRBG);
    return ret;
}

/*
 * Allocate memory and initialize a new DRBG.  The |parent|, if not
R
Rich Salz 已提交
69
 * NULL, will be used to auto-seed this RAND_DRBG as needed.
R
Rich Salz 已提交
70
 */
R
Rich Salz 已提交
71
RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
R
Rich Salz 已提交
72
{
R
Rich Salz 已提交
73
    RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg));
R
Rich Salz 已提交
74

R
Rich Salz 已提交
75
    if (drbg == NULL) {
R
Rich Salz 已提交
76
        RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
77
        goto err;
R
Rich Salz 已提交
78
    }
R
Rich Salz 已提交
79
    drbg->size = RANDOMNESS_NEEDED;
R
Rich Salz 已提交
80
    drbg->fork_count = rand_fork_count;
R
Rich Salz 已提交
81 82 83 84 85 86 87
    drbg->parent = parent;
    if (RAND_DRBG_set(drbg, type, flags) < 0)
        goto err;

    if (parent != NULL) {
        if (!RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_parent,
                                     drbg_release_entropy,
88
                                     NULL, NULL))
R
Rich Salz 已提交
89
            goto err;
R
Rich Salz 已提交
90
    }
R
Rich Salz 已提交
91 92 93 94 95 96

    return drbg;

err:
    OPENSSL_free(drbg);
    return NULL;
R
Rich Salz 已提交
97 98 99
}

/*
R
Rich Salz 已提交
100
 * Uninstantiate |drbg| and free all memory.
R
Rich Salz 已提交
101
 */
R
Rich Salz 已提交
102
void RAND_DRBG_free(RAND_DRBG *drbg)
R
Rich Salz 已提交
103
{
104
    /* The global DRBG is free'd by rand_cleanup_drbg_int() */
R
Rich Salz 已提交
105
    if (drbg == NULL || drbg == &rand_drbg)
R
Rich Salz 已提交
106 107
        return;

R
Rich Salz 已提交
108 109 110
    ctr_uninstantiate(drbg);
    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data);
    OPENSSL_clear_free(drbg, sizeof(*drbg));
R
Rich Salz 已提交
111 112 113
}

/*
R
Rich Salz 已提交
114
 * Instantiate |drbg|, after it has been initialized.  Use |pers| and
R
Rich Salz 已提交
115 116
 * |perslen| as prediction-resistance input.
 */
R
Rich Salz 已提交
117
int RAND_DRBG_instantiate(RAND_DRBG *drbg,
R
Rich Salz 已提交
118 119 120
                          const unsigned char *pers, size_t perslen)
{
    unsigned char *nonce = NULL, *entropy = NULL;
121
    size_t noncelen = 0, entropylen = 0;
R
Rich Salz 已提交
122

123
    if (perslen > drbg->max_perslen) {
R
Rich Salz 已提交
124 125
        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
                RAND_R_PERSONALISATION_STRING_TOO_LONG);
R
Rich Salz 已提交
126 127
        goto end;
    }
R
Rich Salz 已提交
128 129 130 131
    if (drbg->state != DRBG_UNINITIALISED) {
        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
                drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE
                                          : RAND_R_ALREADY_INSTANTIATED);
R
Rich Salz 已提交
132 133 134
        goto end;
    }

R
Rich Salz 已提交
135 136
    drbg->state = DRBG_ERROR;
    if (drbg->get_entropy != NULL)
137 138 139
        entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
                                   drbg->min_entropylen, drbg->max_entropylen);
    if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) {
R
Rich Salz 已提交
140
        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY);
R
Rich Salz 已提交
141 142 143
        goto end;
    }

144
    if (drbg->max_noncelen > 0 && drbg->get_nonce != NULL) {
R
Rich Salz 已提交
145
        noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2,
146 147
                                   drbg->min_noncelen, drbg->max_noncelen);
        if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) {
R
Rich Salz 已提交
148
            RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE);
R
Rich Salz 已提交
149 150 151 152
            goto end;
        }
    }

153
    if (!ctr_instantiate(drbg, entropy, entropylen,
R
Rich Salz 已提交
154
                         nonce, noncelen, pers, perslen)) {
R
Rich Salz 已提交
155
        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG);
R
Rich Salz 已提交
156 157 158
        goto end;
    }

R
Rich Salz 已提交
159 160
    drbg->state = DRBG_READY;
    drbg->reseed_counter = 1;
R
Rich Salz 已提交
161 162

end:
R
Rich Salz 已提交
163
    if (entropy != NULL && drbg->cleanup_entropy != NULL)
164
        drbg->cleanup_entropy(drbg, entropy, entropylen);
R
Rich Salz 已提交
165
    if (nonce != NULL && drbg->cleanup_nonce!= NULL )
166
        drbg->cleanup_nonce(drbg, nonce, noncelen);
R
Rich Salz 已提交
167
    if (drbg->state == DRBG_READY)
R
Rich Salz 已提交
168 169 170 171 172
        return 1;
    return 0;
}

/*
R
Rich Salz 已提交
173
 * Uninstantiate |drbg|. Must be instantiated before it can be used.
R
Rich Salz 已提交
174
 */
R
Rich Salz 已提交
175
int RAND_DRBG_uninstantiate(RAND_DRBG *drbg)
R
Rich Salz 已提交
176
{
R
Rich Salz 已提交
177
    int ret = ctr_uninstantiate(drbg);
R
Rich Salz 已提交
178

R
Rich Salz 已提交
179 180
    OPENSSL_cleanse(&drbg->ctr, sizeof(drbg->ctr));
    drbg->state = DRBG_UNINITIALISED;
R
Rich Salz 已提交
181 182 183 184
    return ret;
}

/*
R
Rich Salz 已提交
185
 * Mix in the specified data to reseed |drbg|.
R
Rich Salz 已提交
186
 */
R
Rich Salz 已提交
187
int RAND_DRBG_reseed(RAND_DRBG *drbg,
R
Rich Salz 已提交
188 189 190
                     const unsigned char *adin, size_t adinlen)
{
    unsigned char *entropy = NULL;
191
    size_t entropylen = 0;
R
Rich Salz 已提交
192 193 194 195 196 197 198 199

    if (drbg->state == DRBG_ERROR) {
        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_IN_ERROR_STATE);
        return 0;
    }
    if (drbg->state == DRBG_UNINITIALISED) {
        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_NOT_INSTANTIATED);
        return 0;
R
Rich Salz 已提交
200 201 202 203
    }

    if (adin == NULL)
        adinlen = 0;
204
    else if (adinlen > drbg->max_adinlen) {
R
Rich Salz 已提交
205 206
        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
        return 0;
R
Rich Salz 已提交
207 208
    }

R
Rich Salz 已提交
209 210
    drbg->state = DRBG_ERROR;
    if (drbg->get_entropy != NULL)
211 212 213
        entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
                                   drbg->min_entropylen, drbg->max_entropylen);
    if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) {
R
Rich Salz 已提交
214
        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY);
R
Rich Salz 已提交
215 216 217
        goto end;
    }

218
    if (!ctr_reseed(drbg, entropy, entropylen, adin, adinlen))
R
Rich Salz 已提交
219
        goto end;
R
Rich Salz 已提交
220 221
    drbg->state = DRBG_READY;
    drbg->reseed_counter = 1;
R
Rich Salz 已提交
222 223

end:
R
Rich Salz 已提交
224
    if (entropy != NULL && drbg->cleanup_entropy != NULL)
225
        drbg->cleanup_entropy(drbg, entropy, entropylen);
R
Rich Salz 已提交
226
    if (drbg->state == DRBG_READY)
R
Rich Salz 已提交
227 228 229 230 231 232 233 234 235
        return 1;
    return 0;
}

/*
 * Generate |outlen| bytes into the buffer at |out|.  Reseed if we need
 * to or if |prediction_resistance| is set.  Additional input can be
 * sent in |adin| and |adinlen|.
 */
R
Rich Salz 已提交
236
int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
R
Rich Salz 已提交
237 238 239
                       int prediction_resistance,
                       const unsigned char *adin, size_t adinlen)
{
R
Rich Salz 已提交
240 241 242
    if (drbg->state == DRBG_ERROR) {
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE);
        return 0;
R
Rich Salz 已提交
243
    }
R
Rich Salz 已提交
244 245
    if (drbg->state == DRBG_UNINITIALISED) {
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED);
R
Rich Salz 已提交
246 247
        return 0;
    }
R
Rich Salz 已提交
248 249 250 251
    if (outlen > drbg->max_request) {
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG);
        return 0;
    }
252
    if (adinlen > drbg->max_adinlen) {
R
Rich Salz 已提交
253 254
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
        return 0;
R
Rich Salz 已提交
255 256
    }

R
Rich Salz 已提交
257 258 259 260 261
    if (drbg->fork_count != rand_fork_count) {
        drbg->fork_count = rand_fork_count;
        drbg->state = DRBG_RESEED;
    }

R
Rich Salz 已提交
262 263
    if (drbg->reseed_counter >= drbg->reseed_interval)
        drbg->state = DRBG_RESEED;
R
Rich Salz 已提交
264

R
Rich Salz 已提交
265 266 267 268
    if (drbg->state == DRBG_RESEED || prediction_resistance) {
        if (!RAND_DRBG_reseed(drbg, adin, adinlen)) {
            RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR);
            return 0;
R
Rich Salz 已提交
269 270 271 272 273
        }
        adin = NULL;
        adinlen = 0;
    }

R
Rich Salz 已提交
274 275 276 277
    if (!ctr_generate(drbg, out, outlen, adin, adinlen)) {
        drbg->state = DRBG_ERROR;
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_GENERATE_ERROR);
        return 0;
R
Rich Salz 已提交
278
    }
R
Rich Salz 已提交
279 280 281

    if (drbg->reseed_counter >= drbg->reseed_interval)
        drbg->state = DRBG_RESEED;
R
Rich Salz 已提交
282
    else
R
Rich Salz 已提交
283
        drbg->reseed_counter++;
R
Rich Salz 已提交
284 285 286 287
    return 1;
}

/*
R
Rich Salz 已提交
288 289
 * Set the callbacks for entropy and nonce.  We currently don't use
 * the nonce; that's mainly for the KATs
R
Rich Salz 已提交
290
 */
R
Rich Salz 已提交
291 292 293 294 295
int RAND_DRBG_set_callbacks(RAND_DRBG *drbg,
                            RAND_DRBG_get_entropy_fn cb_get_entropy,
                            RAND_DRBG_cleanup_entropy_fn cb_cleanup_entropy,
                            RAND_DRBG_get_nonce_fn cb_get_nonce,
                            RAND_DRBG_cleanup_nonce_fn cb_cleanup_nonce)
R
Rich Salz 已提交
296
{
R
Rich Salz 已提交
297
    if (drbg->state != DRBG_UNINITIALISED)
R
Rich Salz 已提交
298
        return 0;
R
Rich Salz 已提交
299 300 301 302
    drbg->get_entropy = cb_get_entropy;
    drbg->cleanup_entropy = cb_cleanup_entropy;
    drbg->get_nonce = cb_get_nonce;
    drbg->cleanup_nonce = cb_cleanup_nonce;
R
Rich Salz 已提交
303 304 305 306
    return 1;
}

/*
R
Rich Salz 已提交
307
 * Set the reseed interval.
R
Rich Salz 已提交
308
 */
R
Rich Salz 已提交
309
int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, int interval)
R
Rich Salz 已提交
310
{
311 312
    if (interval < 0 || interval > MAX_RESEED)
        return 0;
R
Rich Salz 已提交
313
    drbg->reseed_interval = interval;
314
    return 1;
R
Rich Salz 已提交
315 316 317 318 319
}

/*
 * Get and set the EXDATA
 */
R
Rich Salz 已提交
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
int RAND_DRBG_set_ex_data(RAND_DRBG *drbg, int idx, void *arg)
{
    return CRYPTO_set_ex_data(&drbg->ex_data, idx, arg);
}

void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx)
{
    return CRYPTO_get_ex_data(&drbg->ex_data, idx);
}


/*
 * The following functions provide a RAND_METHOD that works on the
 * global DRBG.  They lock.
 */

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/*
 * Creates a global DRBG with default settings.
 * Returns 1 on success, 0 on failure
 */
static int setup_drbg(RAND_DRBG *drbg)
{
    int ret = 1;

    drbg->lock = CRYPTO_THREAD_lock_new();
    ret &= drbg->lock != NULL;
    drbg->size = RANDOMNESS_NEEDED;
    drbg->secure = CRYPTO_secure_malloc_initialized();
    /* If you change these parameters, see RANDOMNESS_NEEDED */
    ret &= RAND_DRBG_set(drbg,
                         NID_aes_128_ctr, RAND_DRBG_FLAG_CTR_USE_DF) == 1;
    ret &= RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_system,
                                   drbg_release_entropy, NULL, NULL) == 1;
    ret &= RAND_DRBG_instantiate(drbg, NULL, 0) == 1;
    return ret;
}

/*
 * Initialize the global DRBGs on first use.
 * Returns 1 on success, 0 on failure.
 */
DEFINE_RUN_ONCE_STATIC(do_rand_init_drbg)
{
    int ret = 1;

    ret &= setup_drbg(&rand_drbg);
    ret &= setup_drbg(&priv_drbg);

    return ret;
}

/* Clean up a DRBG and free it */
static void free_drbg(RAND_DRBG *drbg)
{
    CRYPTO_THREAD_lock_free(drbg->lock);
    RAND_DRBG_uninstantiate(drbg);
}

/* Clean up the global DRBGs before exit */
void rand_cleanup_drbg_int(void)
{
    free_drbg(&rand_drbg);
    free_drbg(&priv_drbg);
}

R
Rich Salz 已提交
385 386 387 388
static int drbg_bytes(unsigned char *out, int count)
{
    int ret = 0;
    size_t chunk;
389
    RAND_DRBG *drbg = RAND_DRBG_get0_global();
R
Rich Salz 已提交
390

391 392 393 394 395
    if (drbg == NULL)
        return 0;

    CRYPTO_THREAD_write_lock(drbg->lock);
    if (drbg->state == DRBG_UNINITIALISED)
R
Rich Salz 已提交
396 397 398 399
        goto err;

    for ( ; count > 0; count -= chunk, out += chunk) {
        chunk = count;
400 401 402
        if (chunk > drbg->max_request)
            chunk = drbg->max_request;
        ret = RAND_DRBG_generate(drbg, out, chunk, 0, NULL, 0);
R
Rich Salz 已提交
403 404 405 406 407 408
        if (!ret)
            goto err;
    }
    ret = 1;

err:
409
    CRYPTO_THREAD_unlock(drbg->lock);
R
Rich Salz 已提交
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    return ret;
}

static int drbg_add(const void *buf, int num, double randomness)
{
    unsigned char *in = (unsigned char *)buf;
    unsigned char *out, *end;

    CRYPTO_THREAD_write_lock(rand_bytes.lock);
    out = &rand_bytes.buff[rand_bytes.curr];
    end = &rand_bytes.buff[rand_bytes.size];

    /* Copy whatever fits into the end of the buffer. */
    for ( ; --num >= 0 && out < end; rand_bytes.curr++)
        *out++ = *in++;

    /* XOR any the leftover. */
    while (num > 0) {
        for (out = rand_bytes.buff; --num >= 0 && out < end; )
            *out++ ^= *in++;
    }

    CRYPTO_THREAD_unlock(rand_bytes.lock);
    return 1;
}

static int drbg_seed(const void *buf, int num)
{
    return drbg_add(buf, num, num);
}

static int drbg_status(void)
R
Rich Salz 已提交
442
{
R
Rich Salz 已提交
443
    int ret;
444 445 446 447
    RAND_DRBG *drbg = RAND_DRBG_get0_global();

    if (drbg == NULL)
        return 0;
R
Rich Salz 已提交
448

449 450 451
    CRYPTO_THREAD_write_lock(drbg->lock);
    ret = drbg->state == DRBG_READY ? 1 : 0;
    CRYPTO_THREAD_unlock(drbg->lock);
R
Rich Salz 已提交
452
    return ret;
R
Rich Salz 已提交
453 454
}

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
/*
 * Get the global public DRBG.
 * Returns pointer to the DRBG on success, NULL on failure.
 */
RAND_DRBG *RAND_DRBG_get0_global(void)
{
    if (!RUN_ONCE(&rand_init_drbg, do_rand_init_drbg))
        return NULL;

    return &rand_drbg;
}

/*
 * Get the global private DRBG.
 * Returns pointer to the DRBG on success, NULL on failure.
 */
RAND_DRBG *RAND_DRBG_get0_priv_global(void)
{
    if (!RUN_ONCE(&rand_init_drbg, do_rand_init_drbg))
        return NULL;

    return &priv_drbg;
}

R
Rich Salz 已提交
479 480 481
RAND_METHOD rand_meth = {
    drbg_seed,
    drbg_bytes,
482
    NULL,
R
Rich Salz 已提交
483 484 485 486 487 488
    drbg_add,
    drbg_bytes,
    drbg_status
};

RAND_METHOD *RAND_OpenSSL(void)
R
Rich Salz 已提交
489
{
R
Rich Salz 已提交
490
    return &rand_meth;
R
Rich Salz 已提交
491
}