drbg_lib.c 13.2 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 18 19

/*
 * Support framework for NIST SP 800-90A DRBG, AES-CTR mode.
R
Rich Salz 已提交
20 21
 * The RAND_DRBG is OpenSSL's pointer to an instance of the DRBG.
 *
R
Rich Salz 已提交
22 23 24 25 26 27 28 29
 * 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.)
 */

30 31
static CRYPTO_ONCE rand_init_drbg = CRYPTO_ONCE_STATIC_INIT;

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

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

    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 已提交
55
        ret = ctr_init(drbg);
R
Rich Salz 已提交
56 57 58 59 60 61 62 63 64 65
        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 已提交
66
 * NULL, will be used to auto-seed this RAND_DRBG as needed.
R
Rich Salz 已提交
67
 */
R
Rich Salz 已提交
68
RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent)
R
Rich Salz 已提交
69
{
R
Rich Salz 已提交
70
    RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg));
R
Rich Salz 已提交
71

R
Rich Salz 已提交
72
    if (drbg == NULL) {
R
Rich Salz 已提交
73
        RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
74
        goto err;
R
Rich Salz 已提交
75
    }
R
Rich Salz 已提交
76
    drbg->size = RANDOMNESS_NEEDED;
R
Rich Salz 已提交
77
    drbg->fork_count = rand_fork_count;
R
Rich Salz 已提交
78 79 80 81 82 83 84
    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,
85
                                     NULL, NULL))
R
Rich Salz 已提交
86
            goto err;
R
Rich Salz 已提交
87
    }
R
Rich Salz 已提交
88 89 90 91 92 93

    return drbg;

err:
    OPENSSL_free(drbg);
    return NULL;
R
Rich Salz 已提交
94 95 96
}

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

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

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

120
    if (perslen > drbg->max_perslen) {
R
Rich Salz 已提交
121 122
        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
                RAND_R_PERSONALISATION_STRING_TOO_LONG);
R
Rich Salz 已提交
123 124
        goto end;
    }
R
Rich Salz 已提交
125 126 127 128
    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 已提交
129 130 131
        goto end;
    }

R
Rich Salz 已提交
132 133
    drbg->state = DRBG_ERROR;
    if (drbg->get_entropy != NULL)
134 135 136
        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 已提交
137
        RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY);
R
Rich Salz 已提交
138 139 140
        goto end;
    }

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

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

R
Rich Salz 已提交
156 157
    drbg->state = DRBG_READY;
    drbg->reseed_counter = 1;
R
Rich Salz 已提交
158 159

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

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

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

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

    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 已提交
197 198 199 200
    }

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

R
Rich Salz 已提交
206 207
    drbg->state = DRBG_ERROR;
    if (drbg->get_entropy != NULL)
208 209 210
        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 已提交
211
        RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY);
R
Rich Salz 已提交
212 213 214
        goto end;
    }

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

end:
R
Rich Salz 已提交
221
    if (entropy != NULL && drbg->cleanup_entropy != NULL)
222
        drbg->cleanup_entropy(drbg, entropy, entropylen);
R
Rich Salz 已提交
223
    if (drbg->state == DRBG_READY)
R
Rich Salz 已提交
224 225 226 227 228 229 230 231 232
        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 已提交
233
int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
R
Rich Salz 已提交
234 235 236
                       int prediction_resistance,
                       const unsigned char *adin, size_t adinlen)
{
R
Rich Salz 已提交
237 238 239
    if (drbg->state == DRBG_ERROR) {
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE);
        return 0;
R
Rich Salz 已提交
240
    }
R
Rich Salz 已提交
241 242
    if (drbg->state == DRBG_UNINITIALISED) {
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED);
R
Rich Salz 已提交
243 244
        return 0;
    }
R
Rich Salz 已提交
245 246 247 248
    if (outlen > drbg->max_request) {
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG);
        return 0;
    }
249
    if (adinlen > drbg->max_adinlen) {
R
Rich Salz 已提交
250 251
        RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
        return 0;
R
Rich Salz 已提交
252 253
    }

R
Rich Salz 已提交
254 255 256 257 258
    if (drbg->fork_count != rand_fork_count) {
        drbg->fork_count = rand_fork_count;
        drbg->state = DRBG_RESEED;
    }

R
Rich Salz 已提交
259 260
    if (drbg->reseed_counter >= drbg->reseed_interval)
        drbg->state = DRBG_RESEED;
R
Rich Salz 已提交
261

R
Rich Salz 已提交
262 263 264 265
    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 已提交
266 267 268 269 270
        }
        adin = NULL;
        adinlen = 0;
    }

R
Rich Salz 已提交
271 272 273 274
    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 已提交
275
    }
R
Rich Salz 已提交
276 277 278

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

/*
R
Rich Salz 已提交
285 286
 * Set the callbacks for entropy and nonce.  We currently don't use
 * the nonce; that's mainly for the KATs
R
Rich Salz 已提交
287
 */
R
Rich Salz 已提交
288 289 290 291 292
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 已提交
293
{
R
Rich Salz 已提交
294
    if (drbg->state != DRBG_UNINITIALISED)
R
Rich Salz 已提交
295
        return 0;
R
Rich Salz 已提交
296 297 298 299
    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 已提交
300 301 302 303
    return 1;
}

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

/*
 * Get and set the EXDATA
 */
R
Rich Salz 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
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.
 */

333 334 335 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
/*
 * 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 已提交
382 383 384 385
static int drbg_bytes(unsigned char *out, int count)
{
    int ret = 0;
    size_t chunk;
386
    RAND_DRBG *drbg = RAND_DRBG_get0_global();
R
Rich Salz 已提交
387

388 389 390 391 392
    if (drbg == NULL)
        return 0;

    CRYPTO_THREAD_write_lock(drbg->lock);
    if (drbg->state == DRBG_UNINITIALISED)
R
Rich Salz 已提交
393 394 395 396
        goto err;

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

err:
406
    CRYPTO_THREAD_unlock(drbg->lock);
R
Rich Salz 已提交
407 408 409 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
    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 已提交
439
{
R
Rich Salz 已提交
440
    int ret;
441 442 443 444
    RAND_DRBG *drbg = RAND_DRBG_get0_global();

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

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

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
/*
 * 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 已提交
476
RAND_DRBG rand_drbg; /* The default global DRBG. */
477
RAND_DRBG priv_drbg; /* The global private-key DRBG. */
R
Rich Salz 已提交
478 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
}