/* * 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 #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(buf, 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); }