diff options
Diffstat (limited to 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand')
11 files changed, 5143 insertions, 0 deletions
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/build.info b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/build.info new file mode 100644 index 000000000..a4e7900bd --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/build.info @@ -0,0 +1,6 @@ +LIBS=../../libcrypto +SOURCE[../../libcrypto]=\ + randfile.c rand_lib.c rand_err.c rand_egd.c \ + rand_win.c rand_unix.c rand_vms.c drbg_lib.c drbg_ctr.c + +INCLUDE[drbg_ctr.o]=../modes diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/drbg_ctr.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/drbg_ctr.c new file mode 100644 index 000000000..0f0ad1b37 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/drbg_ctr.c @@ -0,0 +1,435 @@ +/* + * Copyright 2011-2020 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 <stdlib.h> +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include "modes_local.h" +#include "internal/thread_once.h" +#include "rand_local.h" + +/* + * Implementation of NIST SP 800-90A CTR DRBG. + */ + +static void inc_128(RAND_DRBG_CTR *ctr) +{ + unsigned char *p = &ctr->V[0]; + u32 n = 16, c = 1; + + do { + --n; + c += p[n]; + p[n] = (u8)c; + c >>= 8; + } while (n); +} + +static void ctr_XOR(RAND_DRBG_CTR *ctr, const unsigned char *in, size_t inlen) +{ + size_t i, n; + + if (in == NULL || inlen == 0) + return; + + /* + * Any zero padding will have no effect on the result as we + * are XORing. So just process however much input we have. + */ + n = inlen < ctr->keylen ? inlen : ctr->keylen; + for (i = 0; i < n; i++) + ctr->K[i] ^= in[i]; + if (inlen <= ctr->keylen) + return; + + n = inlen - ctr->keylen; + if (n > 16) { + /* Should never happen */ + n = 16; + } + for (i = 0; i < n; i++) + ctr->V[i] ^= in[i + ctr->keylen]; +} + +/* + * Process a complete block using BCC algorithm of SP 800-90A 10.3.3 + */ +__owur static int ctr_BCC_block(RAND_DRBG_CTR *ctr, unsigned char *out, + const unsigned char *in) +{ + int i, outlen = AES_BLOCK_SIZE; + + for (i = 0; i < 16; i++) + out[i] ^= in[i]; + + if (!EVP_CipherUpdate(ctr->ctx_df, out, &outlen, out, AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + return 1; +} + + +/* + * Handle several BCC operations for as much data as we need for K and X + */ +__owur static int ctr_BCC_blocks(RAND_DRBG_CTR *ctr, const unsigned char *in) +{ + if (!ctr_BCC_block(ctr, ctr->KX, in) + || !ctr_BCC_block(ctr, ctr->KX + 16, in)) + return 0; + if (ctr->keylen != 16 && !ctr_BCC_block(ctr, ctr->KX + 32, in)) + return 0; + return 1; +} + +/* + * Initialise BCC blocks: these have the value 0,1,2 in leftmost positions: + * see 10.3.1 stage 7. + */ +__owur static int ctr_BCC_init(RAND_DRBG_CTR *ctr) +{ + memset(ctr->KX, 0, 48); + memset(ctr->bltmp, 0, 16); + if (!ctr_BCC_block(ctr, ctr->KX, ctr->bltmp)) + return 0; + ctr->bltmp[3] = 1; + if (!ctr_BCC_block(ctr, ctr->KX + 16, ctr->bltmp)) + return 0; + if (ctr->keylen != 16) { + ctr->bltmp[3] = 2; + if (!ctr_BCC_block(ctr, ctr->KX + 32, ctr->bltmp)) + return 0; + } + return 1; +} + +/* + * Process several blocks into BCC algorithm, some possibly partial + */ +__owur static int ctr_BCC_update(RAND_DRBG_CTR *ctr, + const unsigned char *in, size_t inlen) +{ + if (in == NULL || inlen == 0) + return 1; + + /* If we have partial block handle it first */ + if (ctr->bltmp_pos) { + size_t left = 16 - ctr->bltmp_pos; + + /* If we now have a complete block process it */ + if (inlen >= left) { + memcpy(ctr->bltmp + ctr->bltmp_pos, in, left); + if (!ctr_BCC_blocks(ctr, ctr->bltmp)) + return 0; + ctr->bltmp_pos = 0; + inlen -= left; + in += left; + } + } + + /* Process zero or more complete blocks */ + for (; inlen >= 16; in += 16, inlen -= 16) { + if (!ctr_BCC_blocks(ctr, in)) + return 0; + } + + /* Copy any remaining partial block to the temporary buffer */ + if (inlen > 0) { + memcpy(ctr->bltmp + ctr->bltmp_pos, in, inlen); + ctr->bltmp_pos += inlen; + } + return 1; +} + +__owur static int ctr_BCC_final(RAND_DRBG_CTR *ctr) +{ + if (ctr->bltmp_pos) { + memset(ctr->bltmp + ctr->bltmp_pos, 0, 16 - ctr->bltmp_pos); + if (!ctr_BCC_blocks(ctr, ctr->bltmp)) + return 0; + } + return 1; +} + +__owur static int ctr_df(RAND_DRBG_CTR *ctr, + const unsigned char *in1, size_t in1len, + const unsigned char *in2, size_t in2len, + const unsigned char *in3, size_t in3len) +{ + static unsigned char c80 = 0x80; + size_t inlen; + unsigned char *p = ctr->bltmp; + int outlen = AES_BLOCK_SIZE; + + if (!ctr_BCC_init(ctr)) + return 0; + if (in1 == NULL) + in1len = 0; + if (in2 == NULL) + in2len = 0; + if (in3 == NULL) + in3len = 0; + inlen = in1len + in2len + in3len; + /* Initialise L||N in temporary block */ + *p++ = (inlen >> 24) & 0xff; + *p++ = (inlen >> 16) & 0xff; + *p++ = (inlen >> 8) & 0xff; + *p++ = inlen & 0xff; + + /* NB keylen is at most 32 bytes */ + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p = (unsigned char)((ctr->keylen + 16) & 0xff); + ctr->bltmp_pos = 8; + if (!ctr_BCC_update(ctr, in1, in1len) + || !ctr_BCC_update(ctr, in2, in2len) + || !ctr_BCC_update(ctr, in3, in3len) + || !ctr_BCC_update(ctr, &c80, 1) + || !ctr_BCC_final(ctr)) + return 0; + /* Set up key K */ + if (!EVP_CipherInit_ex(ctr->ctx, ctr->cipher, NULL, ctr->KX, NULL, 1)) + return 0; + /* X follows key K */ + if (!EVP_CipherUpdate(ctr->ctx, ctr->KX, &outlen, ctr->KX + ctr->keylen, + AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + if (!EVP_CipherUpdate(ctr->ctx, ctr->KX + 16, &outlen, ctr->KX, + AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + if (ctr->keylen != 16) + if (!EVP_CipherUpdate(ctr->ctx, ctr->KX + 32, &outlen, ctr->KX + 16, + AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + return 1; +} + +/* + * NB the no-df Update in SP800-90A specifies a constant input length + * of seedlen, however other uses of this algorithm pad the input with + * zeroes if necessary and have up to two parameters XORed together, + * so we handle both cases in this function instead. + */ +__owur static int ctr_update(RAND_DRBG *drbg, + const unsigned char *in1, size_t in1len, + const unsigned char *in2, size_t in2len, + const unsigned char *nonce, size_t noncelen) +{ + RAND_DRBG_CTR *ctr = &drbg->data.ctr; + int outlen = AES_BLOCK_SIZE; + + /* correct key is already set up. */ + inc_128(ctr); + if (!EVP_CipherUpdate(ctr->ctx, ctr->K, &outlen, ctr->V, AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + + /* If keylen longer than 128 bits need extra encrypt */ + if (ctr->keylen != 16) { + inc_128(ctr); + if (!EVP_CipherUpdate(ctr->ctx, ctr->K+16, &outlen, ctr->V, + AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + } + inc_128(ctr); + if (!EVP_CipherUpdate(ctr->ctx, ctr->V, &outlen, ctr->V, AES_BLOCK_SIZE) + || outlen != AES_BLOCK_SIZE) + return 0; + + /* If 192 bit key part of V is on end of K */ + if (ctr->keylen == 24) { + memcpy(ctr->V + 8, ctr->V, 8); + memcpy(ctr->V, ctr->K + 24, 8); + } + + if ((drbg->flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0) { + /* If no input reuse existing derived value */ + if (in1 != NULL || nonce != NULL || in2 != NULL) + if (!ctr_df(ctr, in1, in1len, nonce, noncelen, in2, in2len)) + return 0; + /* If this a reuse input in1len != 0 */ + if (in1len) + ctr_XOR(ctr, ctr->KX, drbg->seedlen); + } else { + ctr_XOR(ctr, in1, in1len); + ctr_XOR(ctr, in2, in2len); + } + + if (!EVP_CipherInit_ex(ctr->ctx, ctr->cipher, NULL, ctr->K, NULL, 1)) + return 0; + return 1; +} + +__owur static int drbg_ctr_instantiate(RAND_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *nonce, size_t noncelen, + const unsigned char *pers, size_t perslen) +{ + RAND_DRBG_CTR *ctr = &drbg->data.ctr; + + if (entropy == NULL) + return 0; + + memset(ctr->K, 0, sizeof(ctr->K)); + memset(ctr->V, 0, sizeof(ctr->V)); + if (!EVP_CipherInit_ex(ctr->ctx, ctr->cipher, NULL, ctr->K, NULL, 1)) + return 0; + if (!ctr_update(drbg, entropy, entropylen, pers, perslen, nonce, noncelen)) + return 0; + return 1; +} + +__owur static int drbg_ctr_reseed(RAND_DRBG *drbg, + const unsigned char *entropy, size_t entropylen, + const unsigned char *adin, size_t adinlen) +{ + if (entropy == NULL) + return 0; + if (!ctr_update(drbg, entropy, entropylen, adin, adinlen, NULL, 0)) + return 0; + return 1; +} + +__owur static int drbg_ctr_generate(RAND_DRBG *drbg, + unsigned char *out, size_t outlen, + const unsigned char *adin, size_t adinlen) +{ + RAND_DRBG_CTR *ctr = &drbg->data.ctr; + + if (adin != NULL && adinlen != 0) { + if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0)) + return 0; + /* This means we reuse derived value */ + if ((drbg->flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0) { + adin = NULL; + adinlen = 1; + } + } else { + adinlen = 0; + } + + for ( ; ; ) { + int outl = AES_BLOCK_SIZE; + + inc_128(ctr); + if (outlen < 16) { + /* Use K as temp space as it will be updated */ + if (!EVP_CipherUpdate(ctr->ctx, ctr->K, &outl, ctr->V, + AES_BLOCK_SIZE) + || outl != AES_BLOCK_SIZE) + return 0; + memcpy(out, ctr->K, outlen); + break; + } + if (!EVP_CipherUpdate(ctr->ctx, out, &outl, ctr->V, AES_BLOCK_SIZE) + || outl != AES_BLOCK_SIZE) + return 0; + out += 16; + outlen -= 16; + if (outlen == 0) + break; + } + + if (!ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0)) + return 0; + return 1; +} + +static int drbg_ctr_uninstantiate(RAND_DRBG *drbg) +{ + EVP_CIPHER_CTX_free(drbg->data.ctr.ctx); + EVP_CIPHER_CTX_free(drbg->data.ctr.ctx_df); + OPENSSL_cleanse(&drbg->data.ctr, sizeof(drbg->data.ctr)); + return 1; +} + +static RAND_DRBG_METHOD drbg_ctr_meth = { + drbg_ctr_instantiate, + drbg_ctr_reseed, + drbg_ctr_generate, + drbg_ctr_uninstantiate +}; + +int drbg_ctr_init(RAND_DRBG *drbg) +{ + RAND_DRBG_CTR *ctr = &drbg->data.ctr; + size_t keylen; + + switch (drbg->type) { + default: + /* This can't happen, but silence the compiler warning. */ + return 0; + case NID_aes_128_ctr: + keylen = 16; + ctr->cipher = EVP_aes_128_ecb(); + break; + case NID_aes_192_ctr: + keylen = 24; + ctr->cipher = EVP_aes_192_ecb(); + break; + case NID_aes_256_ctr: + keylen = 32; + ctr->cipher = EVP_aes_256_ecb(); + break; + } + + drbg->meth = &drbg_ctr_meth; + + ctr->keylen = keylen; + if (ctr->ctx == NULL) + ctr->ctx = EVP_CIPHER_CTX_new(); + if (ctr->ctx == NULL) + return 0; + drbg->strength = keylen * 8; + drbg->seedlen = keylen + 16; + + if ((drbg->flags & RAND_DRBG_FLAG_CTR_NO_DF) == 0) { + /* df initialisation */ + static const unsigned char df_key[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + + if (ctr->ctx_df == NULL) + ctr->ctx_df = EVP_CIPHER_CTX_new(); + if (ctr->ctx_df == NULL) + return 0; + /* Set key schedule for df_key */ + if (!EVP_CipherInit_ex(ctr->ctx_df, ctr->cipher, NULL, df_key, NULL, 1)) + return 0; + + drbg->min_entropylen = ctr->keylen; + drbg->max_entropylen = DRBG_MAX_LENGTH; + drbg->min_noncelen = drbg->min_entropylen / 2; + drbg->max_noncelen = DRBG_MAX_LENGTH; + drbg->max_perslen = DRBG_MAX_LENGTH; + drbg->max_adinlen = DRBG_MAX_LENGTH; + } else { + drbg->min_entropylen = drbg->seedlen; + drbg->max_entropylen = drbg->seedlen; + /* Nonce not used */ + drbg->min_noncelen = 0; + drbg->max_noncelen = 0; + drbg->max_perslen = drbg->seedlen; + drbg->max_adinlen = drbg->seedlen; + } + + drbg->max_request = 1 << 16; + + return 1; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/drbg_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/drbg_lib.c new file mode 100644 index 000000000..faf0590c6 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/drbg_lib.c @@ -0,0 +1,1162 @@ +/* + * Copyright 2011-2020 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_local.h" +#include "internal/thread_once.h" +#include "crypto/rand.h" +#include "crypto/cryptlib.h" + +/* + * Support framework for NIST SP 800-90A DRBG + * + * See manual page RAND_DRBG(7) for a general overview. + * + * 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.) + */ + +/* + * The three shared DRBG instances + * + * There are three shared DRBG instances: <master>, <public>, and <private>. + */ + +/* + * The <master> DRBG + * + * Not used directly by the application, only for reseeding the two other + * DRBGs. It reseeds itself by pulling either randomness from os entropy + * sources or by consuming randomness which was added by RAND_add(). + * + * The <master> DRBG is a global instance which is accessed concurrently by + * all threads. The necessary locking is managed automatically by its child + * DRBG instances during reseeding. + */ +static RAND_DRBG *master_drbg; +/* + * The <public> DRBG + * + * Used by default for generating random bytes using RAND_bytes(). + * + * The <public> DRBG is thread-local, i.e., there is one instance per thread. + */ +static CRYPTO_THREAD_LOCAL public_drbg; +/* + * The <private> DRBG + * + * Used by default for generating private keys using RAND_priv_bytes() + * + * The <private> DRBG is thread-local, i.e., there is one instance per thread. + */ +static CRYPTO_THREAD_LOCAL private_drbg; + + + +/* NIST SP 800-90A DRBG recommends the use of a personalization string. */ +static const char ossl_pers_string[] = "OpenSSL NIST SP 800-90A DRBG"; + +static CRYPTO_ONCE rand_drbg_init = CRYPTO_ONCE_STATIC_INIT; + + + +static int rand_drbg_type = RAND_DRBG_TYPE; +static unsigned int rand_drbg_flags = RAND_DRBG_FLAGS; + +static unsigned int master_reseed_interval = MASTER_RESEED_INTERVAL; +static unsigned int slave_reseed_interval = SLAVE_RESEED_INTERVAL; + +static time_t master_reseed_time_interval = MASTER_RESEED_TIME_INTERVAL; +static time_t slave_reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL; + +/* A logical OR of all used DRBG flag bits (currently there is only one) */ +static const unsigned int rand_drbg_used_flags = + RAND_DRBG_FLAG_CTR_NO_DF; + +static RAND_DRBG *drbg_setup(RAND_DRBG *parent); + +static RAND_DRBG *rand_drbg_new(int secure, + int type, + unsigned int flags, + RAND_DRBG *parent); + +/* + * Set/initialize |drbg| to be of type |type|, with optional |flags|. + * + * If |type| and |flags| are zero, use the defaults + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags) +{ + int ret = 1; + + if (type == 0 && flags == 0) { + type = rand_drbg_type; + flags = rand_drbg_flags; + } + + /* If set is called multiple times - clear the old one */ + if (drbg->type != 0 && (type != drbg->type || flags != drbg->flags)) { + drbg->meth->uninstantiate(drbg); + rand_pool_free(drbg->adin_pool); + drbg->adin_pool = NULL; + } + + drbg->state = DRBG_UNINITIALISED; + drbg->flags = flags; + drbg->type = type; + + switch (type) { + default: + drbg->type = 0; + drbg->flags = 0; + drbg->meth = NULL; + RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE); + return 0; + case 0: + /* Uninitialized; that's okay. */ + drbg->meth = NULL; + return 1; + case NID_aes_128_ctr: + case NID_aes_192_ctr: + case NID_aes_256_ctr: + ret = drbg_ctr_init(drbg); + break; + } + + if (ret == 0) { + drbg->state = DRBG_ERROR; + RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_ERROR_INITIALISING_DRBG); + } + return ret; +} + +/* + * Set/initialize default |type| and |flag| for new drbg instances. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set_defaults(int type, unsigned int flags) +{ + int ret = 1; + + switch (type) { + default: + RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_TYPE); + return 0; + case NID_aes_128_ctr: + case NID_aes_192_ctr: + case NID_aes_256_ctr: + break; + } + + if ((flags & ~rand_drbg_used_flags) != 0) { + RANDerr(RAND_F_RAND_DRBG_SET_DEFAULTS, RAND_R_UNSUPPORTED_DRBG_FLAGS); + return 0; + } + + rand_drbg_type = type; + rand_drbg_flags = flags; + + return ret; +} + + +/* + * Allocate memory and initialize a new DRBG. The DRBG is allocated on + * the secure heap if |secure| is nonzero and the secure heap is enabled. + * The |parent|, if not NULL, will be used as random source for reseeding. + * + * Returns a pointer to the new DRBG instance on success, NULL on failure. + */ +static RAND_DRBG *rand_drbg_new(int secure, + int type, + unsigned int flags, + RAND_DRBG *parent) +{ + RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg)) + : OPENSSL_zalloc(sizeof(*drbg)); + + if (drbg == NULL) { + RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + drbg->secure = secure && CRYPTO_secure_allocated(drbg); + drbg->fork_id = openssl_get_fork_id(); + drbg->parent = parent; + + if (parent == NULL) { + drbg->get_entropy = rand_drbg_get_entropy; + drbg->cleanup_entropy = rand_drbg_cleanup_entropy; +#ifndef RAND_DRBG_GET_RANDOM_NONCE + drbg->get_nonce = rand_drbg_get_nonce; + drbg->cleanup_nonce = rand_drbg_cleanup_nonce; +#endif + + drbg->reseed_interval = master_reseed_interval; + drbg->reseed_time_interval = master_reseed_time_interval; + } else { + drbg->get_entropy = rand_drbg_get_entropy; + drbg->cleanup_entropy = rand_drbg_cleanup_entropy; + /* + * Do not provide nonce callbacks, the child DRBGs will + * obtain their nonce using random bits from the parent. + */ + + drbg->reseed_interval = slave_reseed_interval; + drbg->reseed_time_interval = slave_reseed_time_interval; + } + + if (RAND_DRBG_set(drbg, type, flags) == 0) + goto err; + + if (parent != NULL) { + rand_drbg_lock(parent); + if (drbg->strength > parent->strength) { + /* + * We currently don't support the algorithm from NIST SP 800-90C + * 10.1.2 to use a weaker DRBG as source + */ + rand_drbg_unlock(parent); + RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); + goto err; + } + rand_drbg_unlock(parent); + } + + return drbg; + + err: + RAND_DRBG_free(drbg); + + return NULL; +} + +RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent) +{ + return rand_drbg_new(0, type, flags, parent); +} + +RAND_DRBG *RAND_DRBG_secure_new(int type, unsigned int flags, RAND_DRBG *parent) +{ + return rand_drbg_new(1, type, flags, parent); +} + +/* + * Uninstantiate |drbg| and free all memory. + */ +void RAND_DRBG_free(RAND_DRBG *drbg) +{ + if (drbg == NULL) + return; + + if (drbg->meth != NULL) + drbg->meth->uninstantiate(drbg); + rand_pool_free(drbg->adin_pool); + CRYPTO_THREAD_lock_free(drbg->lock); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data); + + if (drbg->secure) + OPENSSL_secure_clear_free(drbg, sizeof(*drbg)); + else + OPENSSL_clear_free(drbg, sizeof(*drbg)); +} + +/* + * Instantiate |drbg|, after it has been initialized. Use |pers| and + * |perslen| as prediction-resistance input. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_instantiate(RAND_DRBG *drbg, + const unsigned char *pers, size_t perslen) +{ + unsigned char *nonce = NULL, *entropy = NULL; + size_t noncelen = 0, entropylen = 0; + size_t min_entropy = drbg->strength; + size_t min_entropylen = drbg->min_entropylen; + size_t max_entropylen = drbg->max_entropylen; + + if (perslen > drbg->max_perslen) { + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, + RAND_R_PERSONALISATION_STRING_TOO_LONG); + goto end; + } + + if (drbg->meth == NULL) { + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, + RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); + goto end; + } + + if (drbg->state != DRBG_UNINITIALISED) { + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, + drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE + : RAND_R_ALREADY_INSTANTIATED); + goto end; + } + + drbg->state = DRBG_ERROR; + + /* + * NIST SP800-90Ar1 section 9.1 says you can combine getting the entropy + * and nonce in 1 call by increasing the entropy with 50% and increasing + * the minimum length to accommodate the length of the nonce. + * We do this in case a nonce is require and get_nonce is NULL. + */ + if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) { + min_entropy += drbg->strength / 2; + min_entropylen += drbg->min_noncelen; + max_entropylen += drbg->max_noncelen; + } + + drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); + if (drbg->reseed_next_counter) { + drbg->reseed_next_counter++; + if(!drbg->reseed_next_counter) + drbg->reseed_next_counter = 1; + } + + if (drbg->get_entropy != NULL) + entropylen = drbg->get_entropy(drbg, &entropy, min_entropy, + min_entropylen, max_entropylen, 0); + if (entropylen < min_entropylen + || entropylen > max_entropylen) { + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); + goto end; + } + + if (drbg->min_noncelen > 0 && drbg->get_nonce != NULL) { + noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, + drbg->min_noncelen, drbg->max_noncelen); + if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); + goto end; + } + } + + if (!drbg->meth->instantiate(drbg, entropy, entropylen, + nonce, noncelen, pers, perslen)) { + RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG); + goto end; + } + + drbg->state = DRBG_READY; + drbg->reseed_gen_counter = 1; + drbg->reseed_time = time(NULL); + tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); + + end: + if (entropy != NULL && drbg->cleanup_entropy != NULL) + drbg->cleanup_entropy(drbg, entropy, entropylen); + if (nonce != NULL && drbg->cleanup_nonce != NULL) + drbg->cleanup_nonce(drbg, nonce, noncelen); + if (drbg->state == DRBG_READY) + return 1; + return 0; +} + +/* + * Uninstantiate |drbg|. Must be instantiated before it can be used. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) +{ + if (drbg->meth == NULL) { + drbg->state = DRBG_ERROR; + RANDerr(RAND_F_RAND_DRBG_UNINSTANTIATE, + RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); + return 0; + } + + /* Clear the entire drbg->ctr struct, then reset some important + * members of the drbg->ctr struct (e.g. keysize, df_ks) to their + * initial values. + */ + drbg->meth->uninstantiate(drbg); + return RAND_DRBG_set(drbg, drbg->type, drbg->flags); +} + +/* + * Reseed |drbg|, mixing in the specified data + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_reseed(RAND_DRBG *drbg, + const unsigned char *adin, size_t adinlen, + int prediction_resistance) +{ + unsigned char *entropy = NULL; + size_t entropylen = 0; + + 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; + } + + if (adin == NULL) { + adinlen = 0; + } else if (adinlen > drbg->max_adinlen) { + RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + return 0; + } + + drbg->state = DRBG_ERROR; + + drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter); + if (drbg->reseed_next_counter) { + drbg->reseed_next_counter++; + if(!drbg->reseed_next_counter) + drbg->reseed_next_counter = 1; + } + + if (drbg->get_entropy != NULL) + entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, + drbg->min_entropylen, + drbg->max_entropylen, + prediction_resistance); + if (entropylen < drbg->min_entropylen + || entropylen > drbg->max_entropylen) { + RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY); + goto end; + } + + if (!drbg->meth->reseed(drbg, entropy, entropylen, adin, adinlen)) + goto end; + + drbg->state = DRBG_READY; + drbg->reseed_gen_counter = 1; + drbg->reseed_time = time(NULL); + tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter); + + end: + if (entropy != NULL && drbg->cleanup_entropy != NULL) + drbg->cleanup_entropy(drbg, entropy, entropylen); + if (drbg->state == DRBG_READY) + return 1; + return 0; +} + +/* + * Restart |drbg|, using the specified entropy or additional input + * + * Tries its best to get the drbg instantiated by all means, + * regardless of its current state. + * + * Optionally, a |buffer| of |len| random bytes can be passed, + * which is assumed to contain at least |entropy| bits of entropy. + * + * If |entropy| > 0, the buffer content is used as entropy input. + * + * If |entropy| == 0, the buffer content is used as additional input + * + * Returns 1 on success, 0 on failure. + * + * This function is used internally only. + */ +int rand_drbg_restart(RAND_DRBG *drbg, + const unsigned char *buffer, size_t len, size_t entropy) +{ + int reseeded = 0; + const unsigned char *adin = NULL; + size_t adinlen = 0; + + if (drbg->seed_pool != NULL) { + RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); + drbg->state = DRBG_ERROR; + rand_pool_free(drbg->seed_pool); + drbg->seed_pool = NULL; + return 0; + } + + if (buffer != NULL) { + if (entropy > 0) { + if (drbg->max_entropylen < len) { + RANDerr(RAND_F_RAND_DRBG_RESTART, + RAND_R_ENTROPY_INPUT_TOO_LONG); + drbg->state = DRBG_ERROR; + return 0; + } + + if (entropy > 8 * len) { + RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE); + drbg->state = DRBG_ERROR; + return 0; + } + + /* will be picked up by the rand_drbg_get_entropy() callback */ + drbg->seed_pool = rand_pool_attach(buffer, len, entropy); + if (drbg->seed_pool == NULL) + return 0; + } else { + if (drbg->max_adinlen < len) { + RANDerr(RAND_F_RAND_DRBG_RESTART, + RAND_R_ADDITIONAL_INPUT_TOO_LONG); + drbg->state = DRBG_ERROR; + return 0; + } + adin = buffer; + adinlen = len; + } + } + + /* repair error state */ + if (drbg->state == DRBG_ERROR) + RAND_DRBG_uninstantiate(drbg); + + /* repair uninitialized state */ + if (drbg->state == DRBG_UNINITIALISED) { + /* reinstantiate drbg */ + RAND_DRBG_instantiate(drbg, + (const unsigned char *) ossl_pers_string, + sizeof(ossl_pers_string) - 1); + /* already reseeded. prevent second reseeding below */ + reseeded = (drbg->state == DRBG_READY); + } + + /* refresh current state if entropy or additional input has been provided */ + if (drbg->state == DRBG_READY) { + if (adin != NULL) { + /* + * mix in additional input without reseeding + * + * Similar to RAND_DRBG_reseed(), but the provided additional + * data |adin| is mixed into the current state without pulling + * entropy from the trusted entropy source using get_entropy(). + * This is not a reseeding in the strict sense of NIST SP 800-90A. + */ + drbg->meth->reseed(drbg, adin, adinlen, NULL, 0); + } else if (reseeded == 0) { + /* do a full reseeding if it has not been done yet above */ + RAND_DRBG_reseed(drbg, NULL, 0, 0); + } + } + + rand_pool_free(drbg->seed_pool); + drbg->seed_pool = NULL; + + return drbg->state == DRBG_READY; +} + +/* + * 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|. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success, 0 on failure. + * + */ +int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, + int prediction_resistance, + const unsigned char *adin, size_t adinlen) +{ + int fork_id; + int reseed_required = 0; + + if (drbg->state != DRBG_READY) { + /* try to recover from previous errors */ + rand_drbg_restart(drbg, NULL, 0, 0); + + if (drbg->state == DRBG_ERROR) { + RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE); + return 0; + } + if (drbg->state == DRBG_UNINITIALISED) { + RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED); + return 0; + } + } + + if (outlen > drbg->max_request) { + RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG); + return 0; + } + if (adinlen > drbg->max_adinlen) { + RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG); + return 0; + } + + fork_id = openssl_get_fork_id(); + + if (drbg->fork_id != fork_id) { + drbg->fork_id = fork_id; + reseed_required = 1; + } + + if (drbg->reseed_interval > 0) { + if (drbg->reseed_gen_counter >= drbg->reseed_interval) + reseed_required = 1; + } + if (drbg->reseed_time_interval > 0) { + time_t now = time(NULL); + if (now < drbg->reseed_time + || now - drbg->reseed_time >= drbg->reseed_time_interval) + reseed_required = 1; + } + if (drbg->parent != NULL) { + unsigned int reseed_counter = tsan_load(&drbg->reseed_prop_counter); + if (reseed_counter > 0 + && tsan_load(&drbg->parent->reseed_prop_counter) + != reseed_counter) + reseed_required = 1; + } + + if (reseed_required || prediction_resistance) { + if (!RAND_DRBG_reseed(drbg, adin, adinlen, prediction_resistance)) { + RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR); + return 0; + } + adin = NULL; + adinlen = 0; + } + + if (!drbg->meth->generate(drbg, out, outlen, adin, adinlen)) { + drbg->state = DRBG_ERROR; + RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_GENERATE_ERROR); + return 0; + } + + drbg->reseed_gen_counter++; + + return 1; +} + +/* + * Generates |outlen| random bytes and stores them in |out|. It will + * using the given |drbg| to generate the bytes. + * + * Requires that drbg->lock is already locked for write, if non-null. + * + * Returns 1 on success 0 on failure. + */ +int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen) +{ + unsigned char *additional = NULL; + size_t additional_len; + size_t chunk; + size_t ret = 0; + + if (drbg->adin_pool == NULL) { + if (drbg->type == 0) + goto err; + drbg->adin_pool = rand_pool_new(0, 0, 0, drbg->max_adinlen); + if (drbg->adin_pool == NULL) + goto err; + } + + additional_len = rand_drbg_get_additional_data(drbg->adin_pool, + &additional); + + for ( ; outlen > 0; outlen -= chunk, out += chunk) { + chunk = outlen; + if (chunk > drbg->max_request) + chunk = drbg->max_request; + ret = RAND_DRBG_generate(drbg, out, chunk, 0, additional, additional_len); + if (!ret) + goto err; + } + ret = 1; + + err: + if (additional != NULL) + rand_drbg_cleanup_additional_data(drbg->adin_pool, additional); + + return ret; +} + +/* + * Set the RAND_DRBG callbacks for obtaining entropy and nonce. + * + * Setting the callbacks is allowed only if the drbg has not been + * initialized yet. Otherwise, the operation will fail. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set_callbacks(RAND_DRBG *drbg, + RAND_DRBG_get_entropy_fn get_entropy, + RAND_DRBG_cleanup_entropy_fn cleanup_entropy, + RAND_DRBG_get_nonce_fn get_nonce, + RAND_DRBG_cleanup_nonce_fn cleanup_nonce) +{ + if (drbg->state != DRBG_UNINITIALISED + || drbg->parent != NULL) + return 0; + drbg->get_entropy = get_entropy; + drbg->cleanup_entropy = cleanup_entropy; + drbg->get_nonce = get_nonce; + drbg->cleanup_nonce = cleanup_nonce; + return 1; +} + +/* + * Set the reseed interval. + * + * The drbg will reseed automatically whenever the number of generate + * requests exceeds the given reseed interval. If the reseed interval + * is 0, then this feature is disabled. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, unsigned int interval) +{ + if (interval > MAX_RESEED_INTERVAL) + return 0; + drbg->reseed_interval = interval; + return 1; +} + +/* + * Set the reseed time interval. + * + * The drbg will reseed automatically whenever the time elapsed since + * the last reseeding exceeds the given reseed time interval. For safety, + * a reseeding will also occur if the clock has been reset to a smaller + * value. + * + * Returns 1 on success, 0 on failure. + */ +int RAND_DRBG_set_reseed_time_interval(RAND_DRBG *drbg, time_t interval) +{ + if (interval > MAX_RESEED_TIME_INTERVAL) + return 0; + drbg->reseed_time_interval = interval; + return 1; +} + +/* + * Set the default values for reseed (time) intervals of new DRBG instances + * + * The default values can be set independently for master DRBG instances + * (without a parent) and slave DRBG instances (with parent). + * + * Returns 1 on success, 0 on failure. + */ + +int RAND_DRBG_set_reseed_defaults( + unsigned int _master_reseed_interval, + unsigned int _slave_reseed_interval, + time_t _master_reseed_time_interval, + time_t _slave_reseed_time_interval + ) +{ + if (_master_reseed_interval > MAX_RESEED_INTERVAL + || _slave_reseed_interval > MAX_RESEED_INTERVAL) + return 0; + + if (_master_reseed_time_interval > MAX_RESEED_TIME_INTERVAL + || _slave_reseed_time_interval > MAX_RESEED_TIME_INTERVAL) + return 0; + + master_reseed_interval = _master_reseed_interval; + slave_reseed_interval = _slave_reseed_interval; + + master_reseed_time_interval = _master_reseed_time_interval; + slave_reseed_time_interval = _slave_reseed_time_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->parent->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 + */ +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. + */ + +/* + * Allocates a new global DRBG on the secure heap (if enabled) and + * initializes it with default settings. + * + * Returns a pointer to the new DRBG instance on success, NULL on failure. + */ +static RAND_DRBG *drbg_setup(RAND_DRBG *parent) +{ + RAND_DRBG *drbg; + + drbg = RAND_DRBG_secure_new(rand_drbg_type, rand_drbg_flags, parent); + if (drbg == NULL) + return NULL; + + /* Only the master DRBG needs to have a lock */ + if (parent == NULL && rand_drbg_enable_locking(drbg) == 0) + goto err; + + /* enable seed propagation */ + tsan_store(&drbg->reseed_prop_counter, 1); + + /* + * Ignore instantiation error to support just-in-time instantiation. + * + * The state of the drbg will be checked in RAND_DRBG_generate() and + * an automatic recovery is attempted. + */ + (void)RAND_DRBG_instantiate(drbg, + (const unsigned char *) ossl_pers_string, + sizeof(ossl_pers_string) - 1); + return drbg; + +err: + RAND_DRBG_free(drbg); + return NULL; +} + +/* + * Initialize the global DRBGs on first use. + * Returns 1 on success, 0 on failure. + */ +DEFINE_RUN_ONCE_STATIC(do_rand_drbg_init) +{ + /* + * ensure that libcrypto is initialized, otherwise the + * DRBG locks are not cleaned up properly + */ + if (!OPENSSL_init_crypto(0, NULL)) + return 0; + + if (!CRYPTO_THREAD_init_local(&private_drbg, NULL)) + return 0; + + if (!CRYPTO_THREAD_init_local(&public_drbg, NULL)) + goto err1; + + master_drbg = drbg_setup(NULL); + if (master_drbg == NULL) + goto err2; + + return 1; + +err2: + CRYPTO_THREAD_cleanup_local(&public_drbg); +err1: + CRYPTO_THREAD_cleanup_local(&private_drbg); + return 0; +} + +/* Clean up the global DRBGs before exit */ +void rand_drbg_cleanup_int(void) +{ + if (master_drbg != NULL) { + RAND_DRBG_free(master_drbg); + master_drbg = NULL; + + CRYPTO_THREAD_cleanup_local(&private_drbg); + CRYPTO_THREAD_cleanup_local(&public_drbg); + } +} + +void drbg_delete_thread_state(void) +{ + RAND_DRBG *drbg; + + drbg = CRYPTO_THREAD_get_local(&public_drbg); + CRYPTO_THREAD_set_local(&public_drbg, NULL); + RAND_DRBG_free(drbg); + + drbg = CRYPTO_THREAD_get_local(&private_drbg); + CRYPTO_THREAD_set_local(&private_drbg, NULL); + RAND_DRBG_free(drbg); +} + +/* Implements the default OpenSSL RAND_bytes() method */ +static int drbg_bytes(unsigned char *out, int count) +{ + int ret; + RAND_DRBG *drbg = RAND_DRBG_get0_public(); + + if (drbg == NULL) + return 0; + + ret = RAND_DRBG_bytes(drbg, out, count); + + return ret; +} + +/* + * Calculates the minimum length of a full entropy buffer + * which is necessary to seed (i.e. instantiate) the DRBG + * successfully. + */ +size_t rand_drbg_seedlen(RAND_DRBG *drbg) +{ + /* + * If no os entropy source is available then RAND_seed(buffer, bufsize) + * is expected to succeed if and only if the buffer length satisfies + * the following requirements, which follow from the calculations + * in RAND_DRBG_instantiate(). + */ + size_t min_entropy = drbg->strength; + size_t min_entropylen = drbg->min_entropylen; + + /* + * Extra entropy for the random nonce in the absence of a + * get_nonce callback, see comment in RAND_DRBG_instantiate(). + */ + if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) { + min_entropy += drbg->strength / 2; + min_entropylen += drbg->min_noncelen; + } + + /* + * Convert entropy requirement from bits to bytes + * (dividing by 8 without rounding upwards, because + * all entropy requirements are divisible by 8). + */ + min_entropy >>= 3; + + /* Return a value that satisfies both requirements */ + return min_entropy > min_entropylen ? min_entropy : min_entropylen; +} + +/* Implements the default OpenSSL RAND_add() method */ +static int drbg_add(const void *buf, int num, double randomness) +{ + int ret = 0; + RAND_DRBG *drbg = RAND_DRBG_get0_master(); + size_t buflen; + size_t seedlen; + + if (drbg == NULL) + return 0; + + if (num < 0 || randomness < 0.0) + return 0; + + rand_drbg_lock(drbg); + seedlen = rand_drbg_seedlen(drbg); + + buflen = (size_t)num; + + if (buflen < seedlen || randomness < (double) seedlen) { +#if defined(OPENSSL_RAND_SEED_NONE) + /* + * If no os entropy source is available, a reseeding will fail + * inevitably. So we use a trick to mix the buffer contents into + * the DRBG state without forcing a reseeding: we generate a + * dummy random byte, using the buffer content as additional data. + * Note: This won't work with RAND_DRBG_FLAG_CTR_NO_DF. + */ + unsigned char dummy[1]; + + ret = RAND_DRBG_generate(drbg, dummy, sizeof(dummy), 0, buf, buflen); + rand_drbg_unlock(drbg); + return ret; +#else + /* + * If an os entropy source is available then we declare the buffer content + * as additional data by setting randomness to zero and trigger a regular + * reseeding. + */ + randomness = 0.0; +#endif + } + + + if (randomness > (double)seedlen) { + /* + * The purpose of this check is to bound |randomness| by a + * relatively small value in order to prevent an integer + * overflow when multiplying by 8 in the rand_drbg_restart() + * call below. Note that randomness is measured in bytes, + * not bits, so this value corresponds to eight times the + * security strength. + */ + randomness = (double)seedlen; + } + + ret = rand_drbg_restart(drbg, buf, buflen, (size_t)(8 * randomness)); + rand_drbg_unlock(drbg); + + return ret; +} + +/* Implements the default OpenSSL RAND_seed() method */ +static int drbg_seed(const void *buf, int num) +{ + return drbg_add(buf, num, num); +} + +/* Implements the default OpenSSL RAND_status() method */ +static int drbg_status(void) +{ + int ret; + RAND_DRBG *drbg = RAND_DRBG_get0_master(); + + if (drbg == NULL) + return 0; + + rand_drbg_lock(drbg); + ret = drbg->state == DRBG_READY ? 1 : 0; + rand_drbg_unlock(drbg); + return ret; +} + +/* + * Get the master DRBG. + * Returns pointer to the DRBG on success, NULL on failure. + * + */ +RAND_DRBG *RAND_DRBG_get0_master(void) +{ + if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init)) + return NULL; + + return master_drbg; +} + +/* + * Get the public DRBG. + * Returns pointer to the DRBG on success, NULL on failure. + */ +RAND_DRBG *RAND_DRBG_get0_public(void) +{ + RAND_DRBG *drbg; + + if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init)) + return NULL; + + drbg = CRYPTO_THREAD_get_local(&public_drbg); + if (drbg == NULL) { + if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND)) + return NULL; + drbg = drbg_setup(master_drbg); + CRYPTO_THREAD_set_local(&public_drbg, drbg); + } + return drbg; +} + +/* + * Get the private DRBG. + * Returns pointer to the DRBG on success, NULL on failure. + */ +RAND_DRBG *RAND_DRBG_get0_private(void) +{ + RAND_DRBG *drbg; + + if (!RUN_ONCE(&rand_drbg_init, do_rand_drbg_init)) + return NULL; + + drbg = CRYPTO_THREAD_get_local(&private_drbg); + if (drbg == NULL) { + if (!ossl_init_thread_start(OPENSSL_INIT_THREAD_RAND)) + return NULL; + drbg = drbg_setup(master_drbg); + CRYPTO_THREAD_set_local(&private_drbg, drbg); + } + return drbg; +} + +RAND_METHOD rand_meth = { + drbg_seed, + drbg_bytes, + NULL, + drbg_add, + drbg_bytes, + drbg_status +}; + +RAND_METHOD *RAND_OpenSSL(void) +{ + return &rand_meth; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c new file mode 100644 index 000000000..da3017df3 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_egd.c @@ -0,0 +1,158 @@ +/* + * Copyright 2000-2018 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 <openssl/opensslconf.h> +#ifdef OPENSSL_NO_EGD +NON_EMPTY_TRANSLATION_UNIT +#else + +# include <openssl/crypto.h> +# include <openssl/e_os2.h> +# include <openssl/rand.h> + +/* + * Query an EGD + */ + +# if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_VOS) || defined(OPENSSL_SYS_UEFI) +int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes) +{ + return -1; +} + +int RAND_egd(const char *path) +{ + return -1; +} + +int RAND_egd_bytes(const char *path, int bytes) +{ + return -1; +} + +# else + +# include OPENSSL_UNISTD +# include <stddef.h> +# include <sys/types.h> +# include <sys/socket.h> +# ifndef NO_SYS_UN_H +# ifdef OPENSSL_SYS_VXWORKS +# include <streams/un.h> +# else +# include <sys/un.h> +# endif +# else +struct sockaddr_un { + short sun_family; /* AF_UNIX */ + char sun_path[108]; /* path name (gag) */ +}; +# endif /* NO_SYS_UN_H */ +# include <string.h> +# include <errno.h> + +int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes) +{ + FILE *fp = NULL; + struct sockaddr_un addr; + int mybuffer, ret = -1, i, numbytes, fd; + unsigned char tempbuf[255]; + + if (bytes > (int)sizeof(tempbuf)) + return -1; + + /* Make socket. */ + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + if (strlen(path) >= sizeof(addr.sun_path)) + return -1; + strcpy(addr.sun_path, path); + i = offsetof(struct sockaddr_un, sun_path) + strlen(path); + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1 || (fp = fdopen(fd, "r+")) == NULL) + return -1; + setbuf(fp, NULL); + + /* Try to connect */ + for ( ; ; ) { + if (connect(fd, (struct sockaddr *)&addr, i) == 0) + break; +# ifdef EISCONN + if (errno == EISCONN) + break; +# endif + switch (errno) { +# ifdef EINTR + case EINTR: +# endif +# ifdef EAGAIN + case EAGAIN: +# endif +# ifdef EINPROGRESS + case EINPROGRESS: +# endif +# ifdef EALREADY + case EALREADY: +# endif + /* No error, try again */ + break; + default: + ret = -1; + goto err; + } + } + + /* Make request, see how many bytes we can get back. */ + tempbuf[0] = 1; + tempbuf[1] = bytes; + if (fwrite(tempbuf, sizeof(char), 2, fp) != 2 || fflush(fp) == EOF) + goto err; + if (fread(tempbuf, sizeof(char), 1, fp) != 1 || tempbuf[0] == 0) + goto err; + numbytes = tempbuf[0]; + + /* Which buffer are we using? */ + mybuffer = buf == NULL; + if (mybuffer) + buf = tempbuf; + + /* Read bytes. */ + i = fread(buf, sizeof(char), numbytes, fp); + if (i < numbytes) + goto err; + ret = numbytes; + if (mybuffer) + RAND_add(tempbuf, i, i); + + err: + if (fp != NULL) + fclose(fp); + return ret; +} + +int RAND_egd_bytes(const char *path, int bytes) +{ + int num; + + num = RAND_query_egd_bytes(path, NULL, bytes); + if (num < 0) + return -1; + if (RAND_status() != 1) + return -1; + return num; +} + +int RAND_egd(const char *path) +{ + return RAND_egd_bytes(path, 255); +} + +# endif + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c new file mode 100644 index 000000000..a3ae5f53c --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_err.c @@ -0,0 +1,139 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2020 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 <openssl/err.h> +#include <openssl/randerr.h> + +#ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA RAND_str_functs[] = { + {ERR_PACK(ERR_LIB_RAND, RAND_F_DATA_COLLECT_METHOD, 0), + "data_collect_method"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_DRBG_BYTES, 0), "drbg_bytes"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_DRBG_GET_ENTROPY, 0), "drbg_get_entropy"}, + {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_GET_ENTROPY, 0), + "rand_drbg_get_entropy"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_GET_NONCE, 0), + "rand_drbg_get_nonce"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_INSTANTIATE, 0), + "RAND_DRBG_instantiate"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_NEW, 0), "RAND_DRBG_new"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_RESEED, 0), "RAND_DRBG_reseed"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_RESTART, 0), "rand_drbg_restart"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_SET, 0), "RAND_DRBG_set"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_SET_DEFAULTS, 0), + "RAND_DRBG_set_defaults"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_DRBG_UNINSTANTIATE, 0), + "RAND_DRBG_uninstantiate"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_LOAD_FILE, 0), "RAND_load_file"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ACQUIRE_ENTROPY, 0), + "rand_pool_acquire_entropy"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD, 0), "rand_pool_add"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD_BEGIN, 0), + "rand_pool_add_begin"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ADD_END, 0), "rand_pool_add_end"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_ATTACH, 0), "rand_pool_attach"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_BYTES_NEEDED, 0), + "rand_pool_bytes_needed"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_GROW, 0), "rand_pool_grow"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_NEW, 0), "rand_pool_new"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_PSEUDO_BYTES, 0), "RAND_pseudo_bytes"}, + {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_WRITE_FILE, 0), "RAND_write_file"}, + {0, NULL} +}; + +static const ERR_STRING_DATA RAND_str_reasons[] = { + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ADDITIONAL_INPUT_TOO_LONG), + "additional input too long"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ALREADY_INSTANTIATED), + "already instantiated"}, + {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), + "entropy input too long"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ENTROPY_OUT_OF_RANGE), + "entropy out of range"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED), + "error entropy pool was ignored"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_INITIALISING_DRBG), + "error initialising drbg"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_INSTANTIATING_DRBG), + "error instantiating drbg"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT), + "error retrieving additional input"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_RETRIEVING_ENTROPY), + "error retrieving entropy"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_ERROR_RETRIEVING_NONCE), + "error retrieving nonce"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FAILED_TO_CREATE_LOCK), + "failed to create lock"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FUNC_NOT_IMPLEMENTED), + "Function not implemented"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_FWRITE_ERROR), "Error writing file"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_GENERATE_ERROR), "generate error"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_INTERNAL_ERROR), "internal error"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_IN_ERROR_STATE), "in error state"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_NOT_A_REGULAR_FILE), + "Not a regular file"}, + {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_PARENT_STRENGTH_TOO_WEAK), + "parent strength too weak"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PERSONALISATION_STRING_TOO_LONG), + "personalisation string too long"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED), + "prediction resistance not supported"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_RANDOM_POOL_OVERFLOW), + "random pool overflow"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_RANDOM_POOL_UNDERFLOW), + "random pool underflow"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG), + "request too large for drbg"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_RESEED_ERROR), "reseed error"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_SELFTEST_FAILURE), "selftest failure"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_TOO_LITTLE_NONCE_REQUESTED), + "too little nonce requested"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_TOO_MUCH_NONCE_REQUESTED), + "too much nonce requested"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_UNSUPPORTED_DRBG_FLAGS), + "unsupported drbg flags"}, + {ERR_PACK(ERR_LIB_RAND, 0, RAND_R_UNSUPPORTED_DRBG_TYPE), + "unsupported drbg type"}, + {0, NULL} +}; + +#endif + +int ERR_load_RAND_strings(void) +{ +#ifndef OPENSSL_NO_ERR + if (ERR_func_error_string(RAND_str_functs[0].error) == NULL) { + ERR_load_strings_const(RAND_str_functs); + ERR_load_strings_const(RAND_str_reasons); + } +#endif + return 1; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c new file mode 100644 index 000000000..ab4e9b548 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_lib.c @@ -0,0 +1,963 @@ +/* + * Copyright 1995-2020 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 <stdio.h> +#include <time.h> +#include "internal/cryptlib.h" +#include <openssl/opensslconf.h> +#include "crypto/rand.h" +#include <openssl/engine.h> +#include "internal/thread_once.h" +#include "rand_local.h" +#include "e_os.h" + +#ifndef OPENSSL_NO_ENGINE +/* non-NULL if default_RAND_meth is ENGINE-provided */ +static ENGINE *funct_ref; +static CRYPTO_RWLOCK *rand_engine_lock; +#endif +static CRYPTO_RWLOCK *rand_meth_lock; +static const RAND_METHOD *default_RAND_meth; +static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT; + +static CRYPTO_RWLOCK *rand_nonce_lock; +static int rand_nonce_count; + +static int rand_inited = 0; + +#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 it provides. + * 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!" + +/* + * Acquire entropy from high-speed clock + * + * Since we get some randomness from the low-order bits of the + * high-speed clock, it can help. + * + * Returns the total entropy count, if it exceeds the requested + * entropy count. Otherwise, returns an entropy count of 0. + */ +size_t rand_acquire_entropy_from_tsc(RAND_POOL *pool) +{ + unsigned char c; + int i; + + if ((OPENSSL_ia32cap_P[0] & (1 << 4)) != 0) { + for (i = 0; i < TSC_READ_COUNT; i++) { + c = (unsigned char)(OPENSSL_rdtsc() & 0xFF); + rand_pool_add(pool, &c, 1, 4); + } + } + return rand_pool_entropy_available(pool); +} +#endif + +#ifdef OPENSSL_RAND_SEED_RDCPU +size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len); +size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len); + +extern unsigned int OPENSSL_ia32cap_P[]; + +/* + * Acquire entropy using Intel-specific cpu instructions + * + * Uses the RDSEED instruction if available, otherwise uses + * RDRAND if available. + * + * For the differences between RDSEED and RDRAND, and why RDSEED + * is the preferred choice, see https://goo.gl/oK3KcN + * + * Returns the total entropy count, if it exceeds the requested + * entropy count. Otherwise, returns an entropy count of 0. + */ +size_t rand_acquire_entropy_from_cpu(RAND_POOL *pool) +{ + size_t bytes_needed; + unsigned char *buffer; + + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + if (bytes_needed > 0) { + buffer = rand_pool_add_begin(pool, bytes_needed); + + if (buffer != NULL) { + /* Whichever comes first, use RDSEED, RDRAND or nothing */ + if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) { + if (OPENSSL_ia32_rdseed_bytes(buffer, bytes_needed) + == bytes_needed) { + rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); + } + } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) { + if (OPENSSL_ia32_rdrand_bytes(buffer, bytes_needed) + == bytes_needed) { + rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); + } + } else { + rand_pool_add_end(pool, 0, 0); + } + } + } + + return rand_pool_entropy_available(pool); +} +#endif + + +/* + * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) + * + * If the DRBG has a parent, then the required amount of entropy input + * is fetched using the parent's RAND_DRBG_generate(). + * + * Otherwise, the entropy is polled from the system entropy sources + * using rand_pool_acquire_entropy(). + * + * If a random pool has been added to the DRBG using RAND_add(), then + * its entropy will be used up first. + */ +size_t rand_drbg_get_entropy(RAND_DRBG *drbg, + unsigned char **pout, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance) +{ + size_t ret = 0; + size_t entropy_available = 0; + RAND_POOL *pool; + + if (drbg->parent != NULL && drbg->strength > drbg->parent->strength) { + /* + * We currently don't support the algorithm from NIST SP 800-90C + * 10.1.2 to use a weaker DRBG as source + */ + RANDerr(RAND_F_RAND_DRBG_GET_ENTROPY, RAND_R_PARENT_STRENGTH_TOO_WEAK); + return 0; + } + + if (drbg->seed_pool != NULL) { + pool = drbg->seed_pool; + pool->entropy_requested = entropy; + } else { + pool = rand_pool_new(entropy, drbg->secure, min_len, max_len); + if (pool == NULL) + return 0; + } + + if (drbg->parent != NULL) { + size_t bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + unsigned char *buffer = rand_pool_add_begin(pool, bytes_needed); + + if (buffer != NULL) { + size_t bytes = 0; + + /* + * Get random data from parent. Include our address as additional input, + * in order to provide some additional distinction between different + * DRBG child instances. + * Our lock is already held, but we need to lock our parent before + * generating bits from it. (Note: taking the lock will be a no-op + * if locking if drbg->parent->lock == NULL.) + */ + rand_drbg_lock(drbg->parent); + if (RAND_DRBG_generate(drbg->parent, + buffer, bytes_needed, + prediction_resistance, + (unsigned char *)&drbg, sizeof(drbg)) != 0) + bytes = bytes_needed; + drbg->reseed_next_counter + = tsan_load(&drbg->parent->reseed_prop_counter); + rand_drbg_unlock(drbg->parent); + + rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = rand_pool_entropy_available(pool); + } + + } else { + if (prediction_resistance) { + /* + * We don't have any entropy sources that comply with the NIST + * standard to provide prediction resistance (see NIST SP 800-90C, + * Section 5.4). + */ + RANDerr(RAND_F_RAND_DRBG_GET_ENTROPY, + RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED); + goto err; + } + + /* Get entropy by polling system entropy sources. */ + entropy_available = rand_pool_acquire_entropy(pool); + } + + if (entropy_available > 0) { + ret = rand_pool_length(pool); + *pout = rand_pool_detach(pool); + } + + err: + if (drbg->seed_pool == NULL) + rand_pool_free(pool); + return ret; +} + +/* + * Implements the cleanup_entropy() callback (see RAND_DRBG_set_callbacks()) + * + */ +void rand_drbg_cleanup_entropy(RAND_DRBG *drbg, + unsigned char *out, size_t outlen) +{ + if (drbg->seed_pool == NULL) { + if (drbg->secure) + OPENSSL_secure_clear_free(out, outlen); + else + OPENSSL_clear_free(out, outlen); + } +} + + +/* + * Implements the get_nonce() callback (see RAND_DRBG_set_callbacks()) + * + */ +size_t rand_drbg_get_nonce(RAND_DRBG *drbg, + unsigned char **pout, + int entropy, size_t min_len, size_t max_len) +{ + size_t ret = 0; + RAND_POOL *pool; + + struct { + void * instance; + int count; + } data; + + memset(&data, 0, sizeof(data)); + pool = rand_pool_new(0, 0, min_len, max_len); + if (pool == NULL) + return 0; + + if (rand_pool_add_nonce_data(pool) == 0) + goto err; + + data.instance = drbg; + CRYPTO_atomic_add(&rand_nonce_count, 1, &data.count, rand_nonce_lock); + + if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0) + goto err; + + ret = rand_pool_length(pool); + *pout = rand_pool_detach(pool); + + err: + rand_pool_free(pool); + + return ret; +} + +/* + * Implements the cleanup_nonce() callback (see RAND_DRBG_set_callbacks()) + * + */ +void rand_drbg_cleanup_nonce(RAND_DRBG *drbg, + unsigned char *out, size_t outlen) +{ + OPENSSL_clear_free(out, outlen); +} + +/* + * Generate additional data that can be used for the drbg. The data does + * not need to contain entropy, but it's useful if it contains at least + * some bits that are unpredictable. + * + * Returns 0 on failure. + * + * On success it allocates a buffer at |*pout| and returns the length of + * the data. The buffer should get freed using OPENSSL_secure_clear_free(). + */ +size_t rand_drbg_get_additional_data(RAND_POOL *pool, unsigned char **pout) +{ + size_t ret = 0; + + if (rand_pool_add_additional_data(pool) == 0) + goto err; + + ret = rand_pool_length(pool); + *pout = rand_pool_detach(pool); + + err: + return ret; +} + +void rand_drbg_cleanup_additional_data(RAND_POOL *pool, unsigned char *out) +{ + rand_pool_reattach(pool, out); +} + +DEFINE_RUN_ONCE_STATIC(do_rand_init) +{ +#ifndef OPENSSL_NO_ENGINE + rand_engine_lock = CRYPTO_THREAD_lock_new(); + if (rand_engine_lock == NULL) + return 0; +#endif + + rand_meth_lock = CRYPTO_THREAD_lock_new(); + if (rand_meth_lock == NULL) + goto err1; + + rand_nonce_lock = CRYPTO_THREAD_lock_new(); + if (rand_nonce_lock == NULL) + goto err2; + + if (!rand_pool_init()) + goto err3; + + rand_inited = 1; + return 1; + +err3: + CRYPTO_THREAD_lock_free(rand_nonce_lock); + rand_nonce_lock = NULL; +err2: + CRYPTO_THREAD_lock_free(rand_meth_lock); + rand_meth_lock = NULL; +err1: +#ifndef OPENSSL_NO_ENGINE + CRYPTO_THREAD_lock_free(rand_engine_lock); + rand_engine_lock = NULL; +#endif + return 0; +} + +void rand_cleanup_int(void) +{ + const RAND_METHOD *meth = default_RAND_meth; + + if (!rand_inited) + return; + + if (meth != NULL && meth->cleanup != NULL) + meth->cleanup(); + RAND_set_rand_method(NULL); + rand_pool_cleanup(); +#ifndef OPENSSL_NO_ENGINE + CRYPTO_THREAD_lock_free(rand_engine_lock); + rand_engine_lock = NULL; +#endif + CRYPTO_THREAD_lock_free(rand_meth_lock); + rand_meth_lock = NULL; + CRYPTO_THREAD_lock_free(rand_nonce_lock); + rand_nonce_lock = NULL; + rand_inited = 0; +} + +/* + * RAND_close_seed_files() ensures that any seed file descriptors are + * closed after use. + */ +void RAND_keep_random_devices_open(int keep) +{ + if (RUN_ONCE(&rand_init, do_rand_init)) + rand_pool_keep_random_devices_open(keep); +} + +/* + * RAND_poll() reseeds the default RNG using random input + * + * The random input is obtained from polling various entropy + * sources which depend on the operating system and are + * configurable via the --with-rand-seed configure option. + */ +int RAND_poll(void) +{ + int ret = 0; + + RAND_POOL *pool = NULL; + + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth == NULL) + return 0; + + if (meth == RAND_OpenSSL()) { + /* fill random pool and seed the master DRBG */ + RAND_DRBG *drbg = RAND_DRBG_get0_master(); + + if (drbg == NULL) + return 0; + + rand_drbg_lock(drbg); + ret = rand_drbg_restart(drbg, NULL, 0, 0); + rand_drbg_unlock(drbg); + + return ret; + + } else { + /* fill random pool and seed the current legacy RNG */ + pool = rand_pool_new(RAND_DRBG_STRENGTH, 1, + (RAND_DRBG_STRENGTH + 7) / 8, + RAND_POOL_MAX_LENGTH); + if (pool == NULL) + return 0; + + if (rand_pool_acquire_entropy(pool) == 0) + goto err; + + if (meth->add == NULL + || meth->add(rand_pool_buffer(pool), + rand_pool_length(pool), + (rand_pool_entropy(pool) / 8.0)) == 0) + goto err; + + ret = 1; + } + +err: + rand_pool_free(pool); + return ret; +} + +/* + * Allocate memory and initialize a new random pool + */ + +RAND_POOL *rand_pool_new(int entropy_requested, int secure, + size_t min_len, size_t max_len) +{ + RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); + size_t min_alloc_size = RAND_POOL_MIN_ALLOCATION(secure); + + if (pool == NULL) { + RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + pool->min_len = min_len; + pool->max_len = (max_len > RAND_POOL_MAX_LENGTH) ? + RAND_POOL_MAX_LENGTH : max_len; + pool->alloc_len = min_len < min_alloc_size ? min_alloc_size : min_len; + if (pool->alloc_len > pool->max_len) + pool->alloc_len = pool->max_len; + + if (secure) + pool->buffer = OPENSSL_secure_zalloc(pool->alloc_len); + else + pool->buffer = OPENSSL_zalloc(pool->alloc_len); + + if (pool->buffer == NULL) { + RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE); + goto err; + } + + pool->entropy_requested = entropy_requested; + pool->secure = secure; + + return pool; + +err: + OPENSSL_free(pool); + return NULL; +} + +/* + * Attach new random pool to the given buffer + * + * This function is intended to be used only for feeding random data + * provided by RAND_add() and RAND_seed() into the <master> DRBG. + */ +RAND_POOL *rand_pool_attach(const unsigned char *buffer, size_t len, + size_t entropy) +{ + RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool)); + + if (pool == NULL) { + RANDerr(RAND_F_RAND_POOL_ATTACH, ERR_R_MALLOC_FAILURE); + return NULL; + } + + /* + * The const needs to be cast away, but attached buffers will not be + * modified (in contrary to allocated buffers which are zeroed and + * freed in the end). + */ + pool->buffer = (unsigned char *) buffer; + pool->len = len; + + pool->attached = 1; + + pool->min_len = pool->max_len = pool->alloc_len = pool->len; + pool->entropy = entropy; + + return pool; +} + +/* + * Free |pool|, securely erasing its buffer. + */ +void rand_pool_free(RAND_POOL *pool) +{ + if (pool == NULL) + return; + + /* + * Although it would be advisable from a cryptographical viewpoint, + * we are not allowed to clear attached buffers, since they are passed + * to rand_pool_attach() as `const unsigned char*`. + * (see corresponding comment in rand_pool_attach()). + */ + if (!pool->attached) { + if (pool->secure) + OPENSSL_secure_clear_free(pool->buffer, pool->alloc_len); + else + OPENSSL_clear_free(pool->buffer, pool->alloc_len); + } + + OPENSSL_free(pool); +} + +/* + * Return the |pool|'s buffer to the caller (readonly). + */ +const unsigned char *rand_pool_buffer(RAND_POOL *pool) +{ + return pool->buffer; +} + +/* + * Return the |pool|'s entropy to the caller. + */ +size_t rand_pool_entropy(RAND_POOL *pool) +{ + return pool->entropy; +} + +/* + * Return the |pool|'s buffer length to the caller. + */ +size_t rand_pool_length(RAND_POOL *pool) +{ + return pool->len; +} + +/* + * Detach the |pool| buffer and return it to the caller. + * It's the responsibility of the caller to free the buffer + * using OPENSSL_secure_clear_free() or to re-attach it + * again to the pool using rand_pool_reattach(). + */ +unsigned char *rand_pool_detach(RAND_POOL *pool) +{ + unsigned char *ret = pool->buffer; + pool->buffer = NULL; + pool->entropy = 0; + return ret; +} + +/* + * Re-attach the |pool| buffer. It is only allowed to pass + * the |buffer| which was previously detached from the same pool. + */ +void rand_pool_reattach(RAND_POOL *pool, unsigned char *buffer) +{ + pool->buffer = buffer; + OPENSSL_cleanse(pool->buffer, pool->len); + pool->len = 0; +} + +/* + * If |entropy_factor| bits contain 1 bit of entropy, how many bytes does one + * need to obtain at least |bits| bits of entropy? + */ +#define ENTROPY_TO_BYTES(bits, entropy_factor) \ + (((bits) * (entropy_factor) + 7) / 8) + + +/* + * Checks whether the |pool|'s entropy is available to the caller. + * This is the case when entropy count and buffer length are high enough. + * Returns + * + * |entropy| if the entropy count and buffer size is large enough + * 0 otherwise + */ +size_t rand_pool_entropy_available(RAND_POOL *pool) +{ + if (pool->entropy < pool->entropy_requested) + return 0; + + if (pool->len < pool->min_len) + return 0; + + return pool->entropy; +} + +/* + * Returns the (remaining) amount of entropy needed to fill + * the random pool. + */ + +size_t rand_pool_entropy_needed(RAND_POOL *pool) +{ + if (pool->entropy < pool->entropy_requested) + return pool->entropy_requested - pool->entropy; + + return 0; +} + +/* Increase the allocation size -- not usable for an attached pool */ +static int rand_pool_grow(RAND_POOL *pool, size_t len) +{ + if (len > pool->alloc_len - pool->len) { + unsigned char *p; + const size_t limit = pool->max_len / 2; + size_t newlen = pool->alloc_len; + + if (pool->attached || len > pool->max_len - pool->len) { + RANDerr(RAND_F_RAND_POOL_GROW, ERR_R_INTERNAL_ERROR); + return 0; + } + + do + newlen = newlen < limit ? newlen * 2 : pool->max_len; + while (len > newlen - pool->len); + + if (pool->secure) + p = OPENSSL_secure_zalloc(newlen); + else + p = OPENSSL_zalloc(newlen); + if (p == NULL) { + RANDerr(RAND_F_RAND_POOL_GROW, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(p, pool->buffer, pool->len); + if (pool->secure) + OPENSSL_secure_clear_free(pool->buffer, pool->alloc_len); + else + OPENSSL_clear_free(pool->buffer, pool->alloc_len); + pool->buffer = p; + pool->alloc_len = newlen; + } + return 1; +} + +/* + * Returns the number of bytes needed to fill the pool, assuming + * the input has 1 / |entropy_factor| entropy bits per data bit. + * In case of an error, 0 is returned. + */ + +size_t rand_pool_bytes_needed(RAND_POOL *pool, unsigned int entropy_factor) +{ + size_t bytes_needed; + size_t entropy_needed = rand_pool_entropy_needed(pool); + + if (entropy_factor < 1) { + RANDerr(RAND_F_RAND_POOL_BYTES_NEEDED, RAND_R_ARGUMENT_OUT_OF_RANGE); + return 0; + } + + bytes_needed = ENTROPY_TO_BYTES(entropy_needed, entropy_factor); + + if (bytes_needed > pool->max_len - pool->len) { + /* not enough space left */ + RANDerr(RAND_F_RAND_POOL_BYTES_NEEDED, RAND_R_RANDOM_POOL_OVERFLOW); + return 0; + } + + if (pool->len < pool->min_len && + bytes_needed < pool->min_len - pool->len) + /* to meet the min_len requirement */ + bytes_needed = pool->min_len - pool->len; + + /* + * Make sure the buffer is large enough for the requested amount + * of data. This guarantees that existing code patterns where + * rand_pool_add_begin, rand_pool_add_end or rand_pool_add + * are used to collect entropy data without any error handling + * whatsoever, continue to be valid. + * Furthermore if the allocation here fails once, make sure that + * we don't fall back to a less secure or even blocking random source, + * as that could happen by the existing code patterns. + * This is not a concern for additional data, therefore that + * is not needed if rand_pool_grow fails in other places. + */ + if (!rand_pool_grow(pool, bytes_needed)) { + /* persistent error for this pool */ + pool->max_len = pool->len = 0; + return 0; + } + + return bytes_needed; +} + +/* Returns the remaining number of bytes available */ +size_t rand_pool_bytes_remaining(RAND_POOL *pool) +{ + return pool->max_len - pool->len; +} + +/* + * Add random bytes to the random pool. + * + * It is expected that the |buffer| contains |len| bytes of + * random input which contains at least |entropy| bits of + * randomness. + * + * Returns 1 if the added amount is adequate, otherwise 0 + */ +int rand_pool_add(RAND_POOL *pool, + const unsigned char *buffer, size_t len, size_t entropy) +{ + if (len > pool->max_len - pool->len) { + RANDerr(RAND_F_RAND_POOL_ADD, RAND_R_ENTROPY_INPUT_TOO_LONG); + return 0; + } + + if (pool->buffer == NULL) { + RANDerr(RAND_F_RAND_POOL_ADD, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (len > 0) { + /* + * This is to protect us from accidentally passing the buffer + * returned from rand_pool_add_begin. + * The check for alloc_len makes sure we do not compare the + * address of the end of the allocated memory to something + * different, since that comparison would have an + * indeterminate result. + */ + if (pool->alloc_len > pool->len && pool->buffer + pool->len == buffer) { + RANDerr(RAND_F_RAND_POOL_ADD, ERR_R_INTERNAL_ERROR); + return 0; + } + /* + * We have that only for cases when a pool is used to collect + * additional data. + * For entropy data, as long as the allocation request stays within + * the limits given by rand_pool_bytes_needed this rand_pool_grow + * below is guaranteed to succeed, thus no allocation happens. + */ + if (!rand_pool_grow(pool, len)) + return 0; + memcpy(pool->buffer + pool->len, buffer, len); + pool->len += len; + pool->entropy += entropy; + } + + return 1; +} + +/* + * Start to add random bytes to the random pool in-place. + * + * Reserves the next |len| bytes for adding random bytes in-place + * and returns a pointer to the buffer. + * The caller is allowed to copy up to |len| bytes into the buffer. + * If |len| == 0 this is considered a no-op and a NULL pointer + * is returned without producing an error message. + * + * After updating the buffer, rand_pool_add_end() needs to be called + * to finish the update operation (see next comment). + */ +unsigned char *rand_pool_add_begin(RAND_POOL *pool, size_t len) +{ + if (len == 0) + return NULL; + + if (len > pool->max_len - pool->len) { + RANDerr(RAND_F_RAND_POOL_ADD_BEGIN, RAND_R_RANDOM_POOL_OVERFLOW); + return NULL; + } + + if (pool->buffer == NULL) { + RANDerr(RAND_F_RAND_POOL_ADD_BEGIN, ERR_R_INTERNAL_ERROR); + return NULL; + } + + /* + * As long as the allocation request stays within the limits given + * by rand_pool_bytes_needed this rand_pool_grow below is guaranteed + * to succeed, thus no allocation happens. + * We have that only for cases when a pool is used to collect + * additional data. Then the buffer might need to grow here, + * and of course the caller is responsible to check the return + * value of this function. + */ + if (!rand_pool_grow(pool, len)) + return NULL; + + return pool->buffer + pool->len; +} + +/* + * Finish to add random bytes to the random pool in-place. + * + * Finishes an in-place update of the random pool started by + * rand_pool_add_begin() (see previous comment). + * It is expected that |len| bytes of random input have been added + * to the buffer which contain at least |entropy| bits of randomness. + * It is allowed to add less bytes than originally reserved. + */ +int rand_pool_add_end(RAND_POOL *pool, size_t len, size_t entropy) +{ + if (len > pool->alloc_len - pool->len) { + RANDerr(RAND_F_RAND_POOL_ADD_END, RAND_R_RANDOM_POOL_OVERFLOW); + return 0; + } + + if (len > 0) { + pool->len += len; + pool->entropy += entropy; + } + + return 1; +} + +int RAND_set_rand_method(const RAND_METHOD *meth) +{ + if (!RUN_ONCE(&rand_init, do_rand_init)) + return 0; + + CRYPTO_THREAD_write_lock(rand_meth_lock); +#ifndef OPENSSL_NO_ENGINE + ENGINE_finish(funct_ref); + funct_ref = NULL; +#endif + default_RAND_meth = meth; + CRYPTO_THREAD_unlock(rand_meth_lock); + return 1; +} + +const RAND_METHOD *RAND_get_rand_method(void) +{ + const RAND_METHOD *tmp_meth = NULL; + + if (!RUN_ONCE(&rand_init, do_rand_init)) + return NULL; + + CRYPTO_THREAD_write_lock(rand_meth_lock); + if (default_RAND_meth == NULL) { +#ifndef OPENSSL_NO_ENGINE + 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) { + funct_ref = e; + default_RAND_meth = tmp_meth; + } else { + ENGINE_finish(e); + default_RAND_meth = &rand_meth; + } +#else + default_RAND_meth = &rand_meth; +#endif + } + tmp_meth = default_RAND_meth; + CRYPTO_THREAD_unlock(rand_meth_lock); + return tmp_meth; +} + +#ifndef OPENSSL_NO_ENGINE +int RAND_set_rand_engine(ENGINE *engine) +{ + const RAND_METHOD *tmp_meth = NULL; + + if (!RUN_ONCE(&rand_init, do_rand_init)) + return 0; + + if (engine != NULL) { + if (!ENGINE_init(engine)) + return 0; + tmp_meth = ENGINE_get_RAND(engine); + if (tmp_meth == NULL) { + ENGINE_finish(engine); + return 0; + } + } + CRYPTO_THREAD_write_lock(rand_engine_lock); + /* This function releases any prior ENGINE so call it first */ + RAND_set_rand_method(tmp_meth); + funct_ref = engine; + CRYPTO_THREAD_unlock(rand_engine_lock); + return 1; +} +#endif + +void RAND_seed(const void *buf, int num) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth->seed != NULL) + meth->seed(buf, num); +} + +void RAND_add(const void *buf, int num, double randomness) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth->add != NULL) + meth->add(buf, num, randomness); +} + +/* + * This function is not part of RAND_METHOD, so if we're not using + * the default method, then just call RAND_bytes(). Otherwise make + * sure we're instantiated and use the private DRBG. + */ +int RAND_priv_bytes(unsigned char *buf, int num) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + RAND_DRBG *drbg; + + if (meth != NULL && meth != RAND_OpenSSL()) + return RAND_bytes(buf, num); + + drbg = RAND_DRBG_get0_private(); + if (drbg != NULL) + return RAND_DRBG_bytes(drbg, buf, num); + + return 0; +} + +int RAND_bytes(unsigned char *buf, int num) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth->bytes != NULL) + return meth->bytes(buf, num); + RANDerr(RAND_F_RAND_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED); + return -1; +} + +#if OPENSSL_API_COMPAT < 0x10100000L +int RAND_pseudo_bytes(unsigned char *buf, int num) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth->pseudorand != NULL) + return meth->pseudorand(buf, num); + RANDerr(RAND_F_RAND_PSEUDO_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED); + return -1; +} +#endif + +int RAND_status(void) +{ + const RAND_METHOD *meth = RAND_get_rand_method(); + + if (meth != NULL && meth->status != NULL) + return meth->status(); + return 0; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_local.h b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_local.h new file mode 100644 index 000000000..1bc9bf7d2 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_local.h @@ -0,0 +1,299 @@ +/* + * Copyright 1995-2020 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 + */ + +#ifndef OSSL_CRYPTO_RAND_LOCAL_H +# define OSSL_CRYPTO_RAND_LOCAL_H + +# include <openssl/aes.h> +# include <openssl/evp.h> +# include <openssl/sha.h> +# include <openssl/hmac.h> +# include <openssl/ec.h> +# include <openssl/rand_drbg.h> +# include "internal/tsan_assist.h" + +# include "internal/numbers.h" + +/* How many times to read the TSC as a randomness source. */ +# define TSC_READ_COUNT 4 + +/* Maximum reseed intervals */ +# define MAX_RESEED_INTERVAL (1 << 24) +# define MAX_RESEED_TIME_INTERVAL (1 << 20) /* approx. 12 days */ + +/* Default reseed intervals */ +# define MASTER_RESEED_INTERVAL (1 << 8) +# define SLAVE_RESEED_INTERVAL (1 << 16) +# define MASTER_RESEED_TIME_INTERVAL (60*60) /* 1 hour */ +# define SLAVE_RESEED_TIME_INTERVAL (7*60) /* 7 minutes */ + + + +/* + * Maximum input size for the DRBG (entropy, nonce, personalization string) + * + * NIST SP800 90Ar1 allows a maximum of (1 << 35) bits i.e., (1 << 32) bytes. + * + * We lower it to 'only' INT32_MAX bytes, which is equivalent to 2 gigabytes. + */ +# define DRBG_MAX_LENGTH INT32_MAX + + +/* + * Maximum allocation size for RANDOM_POOL buffers + * + * The max_len value for the buffer provided to the rand_drbg_get_entropy() + * callback is currently 2^31 bytes (2 gigabytes), if a derivation function + * is used. Since this is much too large to be allocated, the rand_pool_new() + * function chooses more modest values as default pool length, bounded + * by RAND_POOL_MIN_LENGTH and RAND_POOL_MAX_LENGTH + * + * The choice of the RAND_POOL_FACTOR is large enough such that the + * RAND_POOL can store a random input which has a lousy entropy rate of + * 8/256 (= 0.03125) bits per byte. This input will be sent through the + * derivation function which 'compresses' the low quality input into a + * high quality output. + * + * The factor 1.5 below is the pessimistic estimate for the extra amount + * of entropy required when no get_nonce() callback is defined. + */ +# define RAND_POOL_FACTOR 256 +# define RAND_POOL_MAX_LENGTH (RAND_POOL_FACTOR * \ + 3 * (RAND_DRBG_STRENGTH / 16)) +/* + * = (RAND_POOL_FACTOR * \ + * 1.5 * (RAND_DRBG_STRENGTH / 8)) + */ + +/* + * Initial allocation minimum. + * + * There is a distinction between the secure and normal allocation minimums. + * Ideally, the secure allocation size should be a power of two. The normal + * allocation size doesn't have any such restriction. + * + * The secure value is based on 128 bits of secure material, which is 16 bytes. + * Typically, the DRBGs will set a minimum larger than this so optimal + * allocation ought to take place (for full quality seed material). + * + * The normal value has been chosen by noticing that the rand_drbg_get_nonce + * function is usually the largest of the built in allocation (twenty four + * bytes and then appending another sixteen bytes). This means the buffer ends + * with 40 bytes. The value of forty eight is comfortably above this which + * allows some slack in the platform specific values used. + */ +# define RAND_POOL_MIN_ALLOCATION(secure) ((secure) ? 16 : 48) + +/* DRBG status values */ +typedef enum drbg_status_e { + DRBG_UNINITIALISED, + DRBG_READY, + DRBG_ERROR +} DRBG_STATUS; + + +/* instantiate */ +typedef int (*RAND_DRBG_instantiate_fn)(RAND_DRBG *ctx, + const unsigned char *ent, + size_t entlen, + const unsigned char *nonce, + size_t noncelen, + const unsigned char *pers, + size_t perslen); +/* reseed */ +typedef int (*RAND_DRBG_reseed_fn)(RAND_DRBG *ctx, + const unsigned char *ent, + size_t entlen, + const unsigned char *adin, + size_t adinlen); +/* generate output */ +typedef int (*RAND_DRBG_generate_fn)(RAND_DRBG *ctx, + unsigned char *out, + size_t outlen, + const unsigned char *adin, + size_t adinlen); +/* uninstantiate */ +typedef int (*RAND_DRBG_uninstantiate_fn)(RAND_DRBG *ctx); + + +/* + * The DRBG methods + */ + +typedef struct rand_drbg_method_st { + RAND_DRBG_instantiate_fn instantiate; + RAND_DRBG_reseed_fn reseed; + RAND_DRBG_generate_fn generate; + RAND_DRBG_uninstantiate_fn uninstantiate; +} RAND_DRBG_METHOD; + + +/* + * The state of a DRBG AES-CTR. + */ +typedef struct rand_drbg_ctr_st { + EVP_CIPHER_CTX *ctx; + EVP_CIPHER_CTX *ctx_df; + const EVP_CIPHER *cipher; + size_t keylen; + unsigned char K[32]; + unsigned char V[16]; + /* Temporary block storage used by ctr_df */ + unsigned char bltmp[16]; + size_t bltmp_pos; + unsigned char KX[48]; +} RAND_DRBG_CTR; + + +/* + * The 'random pool' acts as a dumb container for collecting random + * input from various entropy sources. The pool has no knowledge about + * whether its randomness is fed into a legacy RAND_METHOD via RAND_add() + * or into a new style RAND_DRBG. It is the callers duty to 1) initialize the + * random pool, 2) pass it to the polling callbacks, 3) seed the RNG, and + * 4) cleanup the random pool again. + * + * The random pool contains no locking mechanism because its scope and + * lifetime is intended to be restricted to a single stack frame. + */ +struct rand_pool_st { + unsigned char *buffer; /* points to the beginning of the random pool */ + size_t len; /* current number of random bytes contained in the pool */ + + int attached; /* true pool was attached to existing buffer */ + int secure; /* 1: allocated on the secure heap, 0: otherwise */ + + size_t min_len; /* minimum number of random bytes requested */ + size_t max_len; /* maximum number of random bytes (allocated buffer size) */ + size_t alloc_len; /* current number of bytes allocated */ + size_t entropy; /* current entropy count in bits */ + size_t entropy_requested; /* requested entropy count in bits */ +}; + +/* + * The state of all types of DRBGs, even though we only have CTR mode + * right now. + */ +struct rand_drbg_st { + CRYPTO_RWLOCK *lock; + RAND_DRBG *parent; + int secure; /* 1: allocated on the secure heap, 0: otherwise */ + int type; /* the nid of the underlying algorithm */ + /* + * Stores the return value of openssl_get_fork_id() as of when we last + * reseeded. The DRBG reseeds automatically whenever drbg->fork_id != + * openssl_get_fork_id(). Used to provide fork-safety and reseed this + * DRBG in the child process. + */ + int fork_id; + unsigned short flags; /* various external flags */ + + /* + * The random_data is used by RAND_add()/drbg_add() to attach random + * data to the global drbg, such that the rand_drbg_get_entropy() callback + * can pull it during instantiation and reseeding. This is necessary to + * reconcile the different philosophies of the RAND and the RAND_DRBG + * with respect to how randomness is added to the RNG during reseeding + * (see PR #4328). + */ + struct rand_pool_st *seed_pool; + + /* + * Auxiliary pool for additional data. + */ + struct rand_pool_st *adin_pool; + + /* + * The following parameters are setup by the per-type "init" function. + * + * Currently the only type is CTR_DRBG, its init function is drbg_ctr_init(). + * + * The parameters are closely related to the ones described in + * section '10.2.1 CTR_DRBG' of [NIST SP 800-90Ar1], with one + * crucial difference: In the NIST standard, all counts are given + * in bits, whereas in OpenSSL entropy counts are given in bits + * and buffer lengths are given in bytes. + * + * Since this difference has lead to some confusion in the past, + * (see [GitHub Issue #2443], formerly [rt.openssl.org #4055]) + * the 'len' suffix has been added to all buffer sizes for + * clarification. + */ + + int strength; + size_t max_request; + size_t min_entropylen, max_entropylen; + size_t min_noncelen, max_noncelen; + size_t max_perslen, max_adinlen; + + /* Counts the number of generate requests since the last reseed. */ + unsigned int reseed_gen_counter; + /* + * Maximum number of generate requests until a reseed is required. + * This value is ignored if it is zero. + */ + unsigned int reseed_interval; + /* Stores the time when the last reseeding occurred */ + time_t reseed_time; + /* + * Specifies the maximum time interval (in seconds) between reseeds. + * This value is ignored if it is zero. + */ + time_t reseed_time_interval; + /* + * Counts the number of reseeds since instantiation. + * This value is ignored if it is zero. + * + * This counter is used only for seed propagation from the <master> DRBG + * to its two children, the <public> and <private> DRBG. This feature is + * very special and its sole purpose is to ensure that any randomness which + * is added by RAND_add() or RAND_seed() will have an immediate effect on + * the output of RAND_bytes() resp. RAND_priv_bytes(). + */ + TSAN_QUALIFIER unsigned int reseed_prop_counter; + unsigned int reseed_next_counter; + + size_t seedlen; + DRBG_STATUS state; + + /* Application data, mainly used in the KATs. */ + CRYPTO_EX_DATA ex_data; + + /* Implementation specific data (currently only one implementation) */ + union { + RAND_DRBG_CTR ctr; + } data; + + /* Implementation specific methods */ + RAND_DRBG_METHOD *meth; + + /* Callback functions. See comments in rand_lib.c */ + RAND_DRBG_get_entropy_fn get_entropy; + RAND_DRBG_cleanup_entropy_fn cleanup_entropy; + RAND_DRBG_get_nonce_fn get_nonce; + RAND_DRBG_cleanup_nonce_fn cleanup_nonce; +}; + +/* The global RAND method, and the global buffer and DRBG instance. */ +extern RAND_METHOD rand_meth; + +/* DRBG helpers */ +int rand_drbg_restart(RAND_DRBG *drbg, + const unsigned char *buffer, size_t len, size_t entropy); +size_t rand_drbg_seedlen(RAND_DRBG *drbg); +/* locking api */ +int rand_drbg_lock(RAND_DRBG *drbg); +int rand_drbg_unlock(RAND_DRBG *drbg); +int rand_drbg_enable_locking(RAND_DRBG *drbg); + + +/* initializes the AES-CTR DRBG implementation */ +int drbg_ctr_init(RAND_DRBG *drbg); + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c new file mode 100644 index 000000000..fe457cab4 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_unix.c @@ -0,0 +1,865 @@ +/* + * Copyright 1995-2020 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 + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include "e_os.h" +#include <stdio.h> +#include "internal/cryptlib.h" +#include <openssl/rand.h> +#include <openssl/crypto.h> +#include "rand_local.h" +#include "crypto/rand.h" +#include <stdio.h> +#include "internal/dso.h" +#ifdef __linux +# include <sys/syscall.h> +# ifdef DEVRANDOM_WAIT +# include <sys/shm.h> +# include <sys/utsname.h> +# endif +#endif +#if defined(__FreeBSD__) && !defined(OPENSSL_SYS_UEFI) +# include <sys/types.h> +# include <sys/sysctl.h> +# include <sys/param.h> +#endif +#if defined(__OpenBSD__) || defined(__NetBSD__) +# include <sys/param.h> +#endif + +#if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) +# include <sys/types.h> +# include <sys/stat.h> +# include <fcntl.h> +# include <unistd.h> +# include <sys/time.h> + +static uint64_t get_time_stamp(void); +static uint64_t get_timer_bits(void); + +/* Macro to convert two thirty two bit values into a sixty four bit one */ +# define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b)) + +/* + * Check for the existence and support of POSIX timers. The standard + * says that the _POSIX_TIMERS macro will have a positive value if they + * are available. + * + * However, we want an additional constraint: that the timer support does + * not require an extra library dependency. Early versions of glibc + * require -lrt to be specified on the link line to access the timers, + * so this needs to be checked for. + * + * It is worse because some libraries define __GLIBC__ but don't + * support the version testing macro (e.g. uClibc). This means + * an extra check is needed. + * + * The final condition is: + * "have posix timers and either not glibc or glibc without -lrt" + * + * The nested #if sequences are required to avoid using a parameterised + * macro that might be undefined. + */ +# undef OSSL_POSIX_TIMER_OKAY +# if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 +# if defined(__GLIBC__) +# if defined(__GLIBC_PREREQ) +# if __GLIBC_PREREQ(2, 17) +# define OSSL_POSIX_TIMER_OKAY +# endif +# endif +# else +# define OSSL_POSIX_TIMER_OKAY +# endif +# endif +#endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) + || defined(__DJGPP__) */ + +#if defined(OPENSSL_RAND_SEED_NONE) +/* none means none. this simplifies the following logic */ +# undef OPENSSL_RAND_SEED_OS +# undef OPENSSL_RAND_SEED_GETRANDOM +# undef OPENSSL_RAND_SEED_LIBRANDOM +# undef OPENSSL_RAND_SEED_DEVRANDOM +# undef OPENSSL_RAND_SEED_RDTSC +# undef OPENSSL_RAND_SEED_RDCPU +# undef OPENSSL_RAND_SEED_EGD +#endif + +#if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \ + !defined(OPENSSL_RAND_SEED_NONE) +# error "UEFI and VXWorks only support seeding NONE" +#endif + +#if defined(OPENSSL_SYS_VXWORKS) +/* empty implementation */ +int rand_pool_init(void) +{ + return 1; +} + +void rand_pool_cleanup(void) +{ +} + +void rand_pool_keep_random_devices_open(int keep) +{ +} + +size_t rand_pool_acquire_entropy(RAND_POOL *pool) +{ + return rand_pool_entropy_available(pool); +} +#endif + +#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \ + || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \ + || defined(OPENSSL_SYS_UEFI)) + +# if defined(OPENSSL_SYS_VOS) + +# ifndef OPENSSL_RAND_SEED_OS +# error "Unsupported seeding method configured; must be os" +# endif + +# if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32) +# error "Unsupported HP-PA and IA32 at the same time." +# endif +# if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32) +# error "Must have one of HP-PA or IA32" +# endif + +/* + * The following algorithm repeatedly samples the real-time clock (RTC) to + * generate a sequence of unpredictable data. The algorithm relies upon the + * uneven execution speed of the code (due to factors such as cache misses, + * interrupts, bus activity, and scheduling) and upon the rather large + * relative difference between the speed of the clock and the rate at which + * it can be read. If it is ported to an environment where execution speed + * is more constant or where the RTC ticks at a much slower rate, or the + * clock can be read with fewer instructions, it is likely that the results + * would be far more predictable. This should only be used for legacy + * platforms. + * + * As a precaution, we assume only 2 bits of entropy per byte. + */ +size_t rand_pool_acquire_entropy(RAND_POOL *pool) +{ + short int code; + int i, k; + size_t bytes_needed; + struct timespec ts; + unsigned char v; +# ifdef OPENSSL_SYS_VOS_HPPA + long duration; + extern void s$sleep(long *_duration, short int *_code); +# else + long long duration; + extern void s$sleep2(long long *_duration, short int *_code); +# endif + + bytes_needed = rand_pool_bytes_needed(pool, 4 /*entropy_factor*/); + + for (i = 0; i < bytes_needed; i++) { + /* + * burn some cpu; hope for interrupts, cache collisions, bus + * interference, etc. + */ + for (k = 0; k < 99; k++) + ts.tv_nsec = random(); + +# ifdef OPENSSL_SYS_VOS_HPPA + /* sleep for 1/1024 of a second (976 us). */ + duration = 1; + s$sleep(&duration, &code); +# else + /* sleep for 1/65536 of a second (15 us). */ + duration = 1; + s$sleep2(&duration, &code); +# endif + + /* Get wall clock time, take 8 bits. */ + clock_gettime(CLOCK_REALTIME, &ts); + v = (unsigned char)(ts.tv_nsec & 0xFF); + rand_pool_add(pool, arg, &v, sizeof(v) , 2); + } + return rand_pool_entropy_available(pool); +} + +void rand_pool_cleanup(void) +{ +} + +void rand_pool_keep_random_devices_open(int keep) +{ +} + +# else + +# if defined(OPENSSL_RAND_SEED_EGD) && \ + (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD)) +# error "Seeding uses EGD but EGD is turned off or no device given" +# endif + +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM) +# error "Seeding uses urandom but DEVRANDOM is not configured" +# endif + +# if defined(OPENSSL_RAND_SEED_OS) +# if !defined(DEVRANDOM) +# error "OS seeding requires DEVRANDOM to be configured" +# endif +# define OPENSSL_RAND_SEED_GETRANDOM +# define OPENSSL_RAND_SEED_DEVRANDOM +# endif + +# if defined(OPENSSL_RAND_SEED_LIBRANDOM) +# error "librandom not (yet) supported" +# endif + +# if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) +/* + * sysctl_random(): Use sysctl() to read a random number from the kernel + * Returns the number of bytes returned in buf on success, -1 on failure. + */ +static ssize_t sysctl_random(char *buf, size_t buflen) +{ + int mib[2]; + size_t done = 0; + size_t len; + + /* + * Note: sign conversion between size_t and ssize_t is safe even + * without a range check, see comment in syscall_random() + */ + + /* + * On FreeBSD old implementations returned longs, newer versions support + * variable sizes up to 256 byte. The code below would not work properly + * when the sysctl returns long and we want to request something not a + * multiple of longs, which should never be the case. + */ + if (!ossl_assert(buflen % sizeof(long) == 0)) { + errno = EINVAL; + return -1; + } + + /* + * On NetBSD before 4.0 KERN_ARND was an alias for KERN_URND, and only + * filled in an int, leaving the rest uninitialized. Since NetBSD 4.0 + * it returns a variable number of bytes with the current version supporting + * up to 256 bytes. + * Just return an error on older NetBSD versions. + */ +#if defined(__NetBSD__) && __NetBSD_Version__ < 400000000 + errno = ENOSYS; + return -1; +#endif + + mib[0] = CTL_KERN; + mib[1] = KERN_ARND; + + do { + len = buflen; + if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) + return done > 0 ? done : -1; + done += len; + buf += len; + buflen -= len; + } while (buflen > 0); + + return done; +} +# endif + +# if defined(OPENSSL_RAND_SEED_GETRANDOM) + +# if defined(__linux) && !defined(__NR_getrandom) +# if defined(__arm__) +# define __NR_getrandom (__NR_SYSCALL_BASE+384) +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define __NR_getrandom (__X32_SYSCALL_BIT + 318) +# else +# define __NR_getrandom 318 +# endif +# elif defined(__xtensa__) +# define __NR_getrandom 338 +# elif defined(__s390__) || defined(__s390x__) +# define __NR_getrandom 349 +# elif defined(__bfin__) +# define __NR_getrandom 389 +# elif defined(__powerpc__) +# define __NR_getrandom 359 +# elif defined(__mips__) || defined(__mips64) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_getrandom (__NR_Linux + 353) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_getrandom (__NR_Linux + 313) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_getrandom (__NR_Linux + 317) +# endif +# elif defined(__hppa__) +# define __NR_getrandom (__NR_Linux + 339) +# elif defined(__sparc__) +# define __NR_getrandom 347 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__alpha__) +# define __NR_getrandom 511 +# elif defined(__sh__) +# if defined(__SH5__) +# define __NR_getrandom 373 +# else +# define __NR_getrandom 384 +# endif +# elif defined(__avr32__) +# define __NR_getrandom 317 +# elif defined(__microblaze__) +# define __NR_getrandom 385 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__cris__) +# define __NR_getrandom 356 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# else /* generic */ +# define __NR_getrandom 278 +# endif +# endif + +/* + * syscall_random(): Try to get random data using a system call + * returns the number of bytes returned in buf, or < 0 on error. + */ +static ssize_t syscall_random(void *buf, size_t buflen) +{ + /* + * Note: 'buflen' equals the size of the buffer which is used by the + * get_entropy() callback of the RAND_DRBG. It is roughly bounded by + * + * 2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14 + * + * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion + * between size_t and ssize_t is safe even without a range check. + */ + + /* + * Do runtime detection to find getentropy(). + * + * Known OSs that should support this: + * - Darwin since 16 (OSX 10.12, IOS 10.0). + * - Solaris since 11.3 + * - OpenBSD since 5.6 + * - Linux since 3.17 with glibc 2.25 + * - FreeBSD since 12.0 (1200061) + */ +# if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) + extern int getentropy(void *buffer, size_t length) __attribute__((weak)); + + if (getentropy != NULL) + return getentropy(buf, buflen) == 0 ? (ssize_t)buflen : -1; +# else + union { + void *p; + int (*f)(void *buffer, size_t length); + } p_getentropy; + + /* + * We could cache the result of the lookup, but we normally don't + * call this function often. + */ + ERR_set_mark(); + p_getentropy.p = DSO_global_lookup("getentropy"); + ERR_pop_to_mark(); + if (p_getentropy.p != NULL) + return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1; +# endif + + /* Linux supports this since version 3.17 */ +# if defined(__linux) && defined(__NR_getrandom) + return syscall(__NR_getrandom, buf, buflen, 0); +# elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) + return sysctl_random(buf, buflen); +# else + errno = ENOSYS; + return -1; +# endif +} +# endif /* defined(OPENSSL_RAND_SEED_GETRANDOM) */ + +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) +static const char *random_device_paths[] = { DEVRANDOM }; +static struct random_device { + int fd; + dev_t dev; + ino_t ino; + mode_t mode; + dev_t rdev; +} random_devices[OSSL_NELEM(random_device_paths)]; +static int keep_random_devices_open = 1; + +# if defined(__linux) && defined(DEVRANDOM_WAIT) +static void *shm_addr; + +static void cleanup_shm(void) +{ + shmdt(shm_addr); +} + +/* + * Ensure that the system randomness source has been adequately seeded. + * This is done by having the first start of libcrypto, wait until the device + * /dev/random becomes able to supply a byte of entropy. Subsequent starts + * of the library and later reseedings do not need to do this. + */ +static int wait_random_seeded(void) +{ + static int seeded = OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID < 0; + static const int kernel_version[] = { DEVRANDOM_SAFE_KERNEL }; + int kernel[2]; + int shm_id, fd, r; + char c, *p; + struct utsname un; + fd_set fds; + + if (!seeded) { + /* See if anything has created the global seeded indication */ + if ((shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, 0)) == -1) { + /* + * Check the kernel's version and fail if it is too recent. + * + * Linux kernels from 4.8 onwards do not guarantee that + * /dev/urandom is properly seeded when /dev/random becomes + * readable. However, such kernels support the getentropy(2) + * system call and this should always succeed which renders + * this alternative but essentially identical source moot. + */ + if (uname(&un) == 0) { + kernel[0] = atoi(un.release); + p = strchr(un.release, '.'); + kernel[1] = p == NULL ? 0 : atoi(p + 1); + if (kernel[0] > kernel_version[0] + || (kernel[0] == kernel_version[0] + && kernel[1] >= kernel_version[1])) { + return 0; + } + } + /* Open /dev/random and wait for it to be readable */ + if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) { + if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) { + FD_ZERO(&fds); + FD_SET(fd, &fds); + while ((r = select(fd + 1, &fds, NULL, NULL, NULL)) < 0 + && errno == EINTR); + } else { + while ((r = read(fd, &c, 1)) < 0 && errno == EINTR); + } + close(fd); + if (r == 1) { + seeded = 1; + /* Create the shared memory indicator */ + shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, + IPC_CREAT | S_IRUSR | S_IRGRP | S_IROTH); + } + } + } + if (shm_id != -1) { + seeded = 1; + /* + * Map the shared memory to prevent its premature destruction. + * If this call fails, it isn't a big problem. + */ + shm_addr = shmat(shm_id, NULL, SHM_RDONLY); + if (shm_addr != (void *)-1) + OPENSSL_atexit(&cleanup_shm); + } + } + return seeded; +} +# else /* defined __linux */ +static int wait_random_seeded(void) +{ + return 1; +} +# endif + +/* + * Verify that the file descriptor associated with the random source is + * still valid. The rationale for doing this is the fact that it is not + * uncommon for daemons to close all open file handles when daemonizing. + * So the handle might have been closed or even reused for opening + * another file. + */ +static int check_random_device(struct random_device * rd) +{ + struct stat st; + + return rd->fd != -1 + && fstat(rd->fd, &st) != -1 + && rd->dev == st.st_dev + && rd->ino == st.st_ino + && ((rd->mode ^ st.st_mode) & ~(S_IRWXU | S_IRWXG | S_IRWXO)) == 0 + && rd->rdev == st.st_rdev; +} + +/* + * Open a random device if required and return its file descriptor or -1 on error + */ +static int get_random_device(size_t n) +{ + struct stat st; + struct random_device * rd = &random_devices[n]; + + /* reuse existing file descriptor if it is (still) valid */ + if (check_random_device(rd)) + return rd->fd; + + /* open the random device ... */ + if ((rd->fd = open(random_device_paths[n], O_RDONLY)) == -1) + return rd->fd; + + /* ... and cache its relevant stat(2) data */ + if (fstat(rd->fd, &st) != -1) { + rd->dev = st.st_dev; + rd->ino = st.st_ino; + rd->mode = st.st_mode; + rd->rdev = st.st_rdev; + } else { + close(rd->fd); + rd->fd = -1; + } + + return rd->fd; +} + +/* + * Close a random device making sure it is a random device + */ +static void close_random_device(size_t n) +{ + struct random_device * rd = &random_devices[n]; + + if (check_random_device(rd)) + close(rd->fd); + rd->fd = -1; +} + +int rand_pool_init(void) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(random_devices); i++) + random_devices[i].fd = -1; + + return 1; +} + +void rand_pool_cleanup(void) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(random_devices); i++) + close_random_device(i); +} + +void rand_pool_keep_random_devices_open(int keep) +{ + if (!keep) + rand_pool_cleanup(); + + keep_random_devices_open = keep; +} + +# else /* !defined(OPENSSL_RAND_SEED_DEVRANDOM) */ + +int rand_pool_init(void) +{ + return 1; +} + +void rand_pool_cleanup(void) +{ +} + +void rand_pool_keep_random_devices_open(int keep) +{ +} + +# endif /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */ + +/* + * Try the various seeding methods in turn, exit when successful. + * + * TODO(DRBG): If more than one entropy source is available, is it + * preferable to stop as soon as enough entropy has been collected + * (as favored by @rsalz) or should one rather be defensive and add + * more entropy than requested and/or from different sources? + * + * Currently, the user can select multiple entropy sources in the + * configure step, yet in practice only the first available source + * will be used. A more flexible solution has been requested, but + * currently it is not clear how this can be achieved without + * overengineering the problem. There are many parameters which + * could be taken into account when selecting the order and amount + * of input from the different entropy sources (trust, quality, + * possibility of blocking). + */ +size_t rand_pool_acquire_entropy(RAND_POOL *pool) +{ +# if defined(OPENSSL_RAND_SEED_NONE) + return rand_pool_entropy_available(pool); +# else + size_t entropy_available; + +# if defined(OPENSSL_RAND_SEED_GETRANDOM) + { + size_t bytes_needed; + unsigned char *buffer; + ssize_t bytes; + /* Maximum allowed number of consecutive unsuccessful attempts */ + int attempts = 3; + + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + while (bytes_needed != 0 && attempts-- > 0) { + buffer = rand_pool_add_begin(pool, bytes_needed); + bytes = syscall_random(buffer, bytes_needed); + if (bytes > 0) { + rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed -= bytes; + attempts = 3; /* reset counter after successful attempt */ + } else if (bytes < 0 && errno != EINTR) { + break; + } + } + } + entropy_available = rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# if defined(OPENSSL_RAND_SEED_LIBRANDOM) + { + /* Not yet implemented. */ + } +# endif + +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) + if (wait_random_seeded()) { + size_t bytes_needed; + unsigned char *buffer; + size_t i; + + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); + i++) { + ssize_t bytes = 0; + /* Maximum number of consecutive unsuccessful attempts */ + int attempts = 3; + const int fd = get_random_device(i); + + if (fd == -1) + continue; + + while (bytes_needed != 0 && attempts-- > 0) { + buffer = rand_pool_add_begin(pool, bytes_needed); + bytes = read(fd, buffer, bytes_needed); + + if (bytes > 0) { + rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed -= bytes; + attempts = 3; /* reset counter on successful attempt */ + } else if (bytes < 0 && errno != EINTR) { + break; + } + } + if (bytes < 0 || !keep_random_devices_open) + close_random_device(i); + + bytes_needed = rand_pool_bytes_needed(pool, 1); + } + entropy_available = rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; + } +# endif + +# if defined(OPENSSL_RAND_SEED_RDTSC) + entropy_available = rand_acquire_entropy_from_tsc(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# if defined(OPENSSL_RAND_SEED_RDCPU) + entropy_available = rand_acquire_entropy_from_cpu(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# if defined(OPENSSL_RAND_SEED_EGD) + { + static const char *paths[] = { DEVRANDOM_EGD, NULL }; + size_t bytes_needed; + unsigned char *buffer; + int i; + + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + for (i = 0; bytes_needed > 0 && paths[i] != NULL; i++) { + size_t bytes = 0; + int num; + + buffer = rand_pool_add_begin(pool, bytes_needed); + num = RAND_query_egd_bytes(paths[i], + buffer, (int)bytes_needed); + if (num == (int)bytes_needed) + bytes = bytes_needed; + + rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed = rand_pool_bytes_needed(pool, 1); + } + entropy_available = rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; + } +# endif + + return rand_pool_entropy_available(pool); +# endif +} +# endif +#endif + +#if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) +int rand_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + pid_t pid; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data = { 0 }; + + /* + * Add process id, thread id, and a high resolution timestamp to + * ensure that the nonce is unique with high probability for + * different process instances. + */ + data.pid = getpid(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_time_stamp(); + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + int fork_id; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data = { 0 }; + + /* + * Add some noise from the thread id and a high resolution timer. + * The fork_id adds some extra fork-safety. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.fork_id = openssl_get_fork_id(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_timer_bits(); + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + + +/* + * Get the current time with the highest possible resolution + * + * The time stamp is added to the nonce, so it is optimized for not repeating. + * The current time is ideal for this purpose, provided the computer's clock + * is synchronized. + */ +static uint64_t get_time_stamp(void) +{ +# if defined(OSSL_POSIX_TIMER_OKAY) + { + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + } +# endif +# if defined(__unix__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + { + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) + return TWO32TO64(tv.tv_sec, tv.tv_usec); + } +# endif + return time(NULL); +} + +/* + * Get an arbitrary timer value of the highest possible resolution + * + * The timer value is added as random noise to the additional data, + * which is not considered a trusted entropy sourec, so any result + * is acceptable. + */ +static uint64_t get_timer_bits(void) +{ + uint64_t res = OPENSSL_rdtsc(); + + if (res != 0) + return res; + +# if defined(__sun) || defined(__hpux) + return gethrtime(); +# elif defined(_AIX) + { + timebasestruct_t t; + + read_wall_time(&t, TIMEBASE_SZ); + return TWO32TO64(t.tb_high, t.tb_low); + } +# elif defined(OSSL_POSIX_TIMER_OKAY) + { + struct timespec ts; + +# ifdef CLOCK_BOOTTIME +# define CLOCK_TYPE CLOCK_BOOTTIME +# elif defined(_POSIX_MONOTONIC_CLOCK) +# define CLOCK_TYPE CLOCK_MONOTONIC +# else +# define CLOCK_TYPE CLOCK_REALTIME +# endif + + if (clock_gettime(CLOCK_TYPE, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + } +# endif +# if defined(__unix__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + { + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) + return TWO32TO64(tv.tv_sec, tv.tv_usec); + } +# endif + return time(NULL); +} +#endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) + || defined(__DJGPP__) */ diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c new file mode 100644 index 000000000..61c2f1029 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_vms.c @@ -0,0 +1,616 @@ +/* + * Copyright 2001-2020 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 "e_os.h" + +#if defined(OPENSSL_SYS_VMS) +# define __NEW_STARLET 1 /* New starlet definitions since VMS 7.0 */ +# include <unistd.h> +# include "internal/cryptlib.h" +# include <openssl/bio.h> +# include <openssl/err.h> +# include <openssl/rand.h> +# include "crypto/rand.h" +# include "rand_local.h" +# include <descrip.h> +# include <dvidef.h> +# include <jpidef.h> +# include <rmidef.h> +# include <syidef.h> +# include <ssdef.h> +# include <starlet.h> +# include <efndef.h> +# include <gen64def.h> +# include <iosbdef.h> +# include <iledef.h> +# include <lib$routines.h> +# ifdef __DECC +# pragma message disable DOLLARID +# endif + +# include <dlfcn.h> /* SYS$GET_ENTROPY presence */ + +# ifndef OPENSSL_RAND_SEED_OS +# error "Unsupported seeding method configured; must be os" +# endif + +/* + * DATA COLLECTION METHOD + * ====================== + * + * This is a method to get low quality entropy. + * It works by collecting all kinds of statistical data that + * VMS offers and using them as random seed. + */ + +/* We need to make sure we have the right size pointer in some cases */ +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size save +# pragma pointer_size 32 +# endif +typedef uint32_t *uint32_t__ptr32; +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size restore +# endif + +struct item_st { + short length, code; /* length is number of bytes */ +}; + +static const struct item_st DVI_item_data[] = { + {4, DVI$_ERRCNT}, + {4, DVI$_REFCNT}, +}; + +static const struct item_st JPI_item_data[] = { + {4, JPI$_BUFIO}, + {4, JPI$_CPUTIM}, + {4, JPI$_DIRIO}, + {4, JPI$_IMAGECOUNT}, + {4, JPI$_PAGEFLTS}, + {4, JPI$_PID}, + {4, JPI$_PPGCNT}, + {4, JPI$_WSPEAK}, + /* + * Note: the direct result is just a 32-bit address. However, it points + * to a list of 4 32-bit words, so we make extra space for them so we can + * do in-place replacement of values + */ + {16, JPI$_FINALEXC}, +}; + +static const struct item_st JPI_item_data_64bit[] = { + {8, JPI$_LAST_LOGIN_I}, + {8, JPI$_LOGINTIM}, +}; + +static const struct item_st RMI_item_data[] = { + {4, RMI$_COLPG}, + {4, RMI$_MWAIT}, + {4, RMI$_CEF}, + {4, RMI$_PFW}, + {4, RMI$_LEF}, + {4, RMI$_LEFO}, + {4, RMI$_HIB}, + {4, RMI$_HIBO}, + {4, RMI$_SUSP}, + {4, RMI$_SUSPO}, + {4, RMI$_FPG}, + {4, RMI$_COM}, + {4, RMI$_COMO}, + {4, RMI$_CUR}, +#if defined __alpha + {4, RMI$_FRLIST}, + {4, RMI$_MODLIST}, +#endif + {4, RMI$_FAULTS}, + {4, RMI$_PREADS}, + {4, RMI$_PWRITES}, + {4, RMI$_PWRITIO}, + {4, RMI$_PREADIO}, + {4, RMI$_GVALFLTS}, + {4, RMI$_WRTINPROG}, + {4, RMI$_FREFLTS}, + {4, RMI$_DZROFLTS}, + {4, RMI$_SYSFAULTS}, + {4, RMI$_ISWPCNT}, + {4, RMI$_DIRIO}, + {4, RMI$_BUFIO}, + {4, RMI$_MBREADS}, + {4, RMI$_MBWRITES}, + {4, RMI$_LOGNAM}, + {4, RMI$_FCPCALLS}, + {4, RMI$_FCPREAD}, + {4, RMI$_FCPWRITE}, + {4, RMI$_FCPCACHE}, + {4, RMI$_FCPCPU}, + {4, RMI$_FCPHIT}, + {4, RMI$_FCPSPLIT}, + {4, RMI$_FCPFAULT}, + {4, RMI$_ENQNEW}, + {4, RMI$_ENQCVT}, + {4, RMI$_DEQ}, + {4, RMI$_BLKAST}, + {4, RMI$_ENQWAIT}, + {4, RMI$_ENQNOTQD}, + {4, RMI$_DLCKSRCH}, + {4, RMI$_DLCKFND}, + {4, RMI$_NUMLOCKS}, + {4, RMI$_NUMRES}, + {4, RMI$_ARRLOCPK}, + {4, RMI$_DEPLOCPK}, + {4, RMI$_ARRTRAPK}, + {4, RMI$_TRCNGLOS}, + {4, RMI$_RCVBUFFL}, + {4, RMI$_ENQNEWLOC}, + {4, RMI$_ENQNEWIN}, + {4, RMI$_ENQNEWOUT}, + {4, RMI$_ENQCVTLOC}, + {4, RMI$_ENQCVTIN}, + {4, RMI$_ENQCVTOUT}, + {4, RMI$_DEQLOC}, + {4, RMI$_DEQIN}, + {4, RMI$_DEQOUT}, + {4, RMI$_BLKLOC}, + {4, RMI$_BLKIN}, + {4, RMI$_BLKOUT}, + {4, RMI$_DIRIN}, + {4, RMI$_DIROUT}, + /* We currently get a fault when trying these. TODO: To be figured out. */ +#if 0 + {140, RMI$_MSCP_EVERYTHING}, /* 35 32-bit words */ + {152, RMI$_DDTM_ALL}, /* 38 32-bit words */ + {80, RMI$_TMSCP_EVERYTHING} /* 20 32-bit words */ +#endif + {4, RMI$_LPZ_PAGCNT}, + {4, RMI$_LPZ_HITS}, + {4, RMI$_LPZ_MISSES}, + {4, RMI$_LPZ_EXPCNT}, + {4, RMI$_LPZ_ALLOCF}, + {4, RMI$_LPZ_ALLOC2}, + {4, RMI$_ACCESS}, + {4, RMI$_ALLOC}, + {4, RMI$_FCPCREATE}, + {4, RMI$_VOLWAIT}, + {4, RMI$_FCPTURN}, + {4, RMI$_FCPERASE}, + {4, RMI$_OPENS}, + {4, RMI$_FIDHIT}, + {4, RMI$_FIDMISS}, + {4, RMI$_FILHDR_HIT}, + {4, RMI$_DIRFCB_HIT}, + {4, RMI$_DIRFCB_MISS}, + {4, RMI$_DIRDATA_HIT}, + {4, RMI$_EXTHIT}, + {4, RMI$_EXTMISS}, + {4, RMI$_QUOHIT}, + {4, RMI$_QUOMISS}, + {4, RMI$_STORAGMAP_HIT}, + {4, RMI$_VOLLCK}, + {4, RMI$_SYNCHLCK}, + {4, RMI$_SYNCHWAIT}, + {4, RMI$_ACCLCK}, + {4, RMI$_XQPCACHEWAIT}, + {4, RMI$_DIRDATA_MISS}, + {4, RMI$_FILHDR_MISS}, + {4, RMI$_STORAGMAP_MISS}, + {4, RMI$_PROCCNTMAX}, + {4, RMI$_PROCBATCNT}, + {4, RMI$_PROCINTCNT}, + {4, RMI$_PROCNETCNT}, + {4, RMI$_PROCSWITCHCNT}, + {4, RMI$_PROCBALSETCNT}, + {4, RMI$_PROCLOADCNT}, + {4, RMI$_BADFLTS}, + {4, RMI$_EXEFAULTS}, + {4, RMI$_HDRINSWAPS}, + {4, RMI$_HDROUTSWAPS}, + {4, RMI$_IOPAGCNT}, + {4, RMI$_ISWPCNTPG}, + {4, RMI$_OSWPCNT}, + {4, RMI$_OSWPCNTPG}, + {4, RMI$_RDFAULTS}, + {4, RMI$_TRANSFLTS}, + {4, RMI$_WRTFAULTS}, +#if defined __alpha + {4, RMI$_USERPAGES}, +#endif + {4, RMI$_VMSPAGES}, + {4, RMI$_TTWRITES}, + {4, RMI$_BUFOBJPAG}, + {4, RMI$_BUFOBJPAGPEAK}, + {4, RMI$_BUFOBJPAGS01}, + {4, RMI$_BUFOBJPAGS2}, + {4, RMI$_BUFOBJPAGMAXS01}, + {4, RMI$_BUFOBJPAGMAXS2}, + {4, RMI$_BUFOBJPAGPEAKS01}, + {4, RMI$_BUFOBJPAGPEAKS2}, + {4, RMI$_BUFOBJPGLTMAXS01}, + {4, RMI$_BUFOBJPGLTMAXS2}, + {4, RMI$_DLCK_INCMPLT}, + {4, RMI$_DLCKMSGS_IN}, + {4, RMI$_DLCKMSGS_OUT}, + {4, RMI$_MCHKERRS}, + {4, RMI$_MEMERRS}, +}; + +static const struct item_st RMI_item_data_64bit[] = { +#if defined __ia64 + {8, RMI$_FRLIST}, + {8, RMI$_MODLIST}, +#endif + {8, RMI$_LCKMGR_REQCNT}, + {8, RMI$_LCKMGR_REQTIME}, + {8, RMI$_LCKMGR_SPINCNT}, + {8, RMI$_LCKMGR_SPINTIME}, + {8, RMI$_CPUINTSTK}, + {8, RMI$_CPUMPSYNCH}, + {8, RMI$_CPUKERNEL}, + {8, RMI$_CPUEXEC}, + {8, RMI$_CPUSUPER}, + {8, RMI$_CPUUSER}, +#if defined __ia64 + {8, RMI$_USERPAGES}, +#endif + {8, RMI$_TQETOTAL}, + {8, RMI$_TQESYSUB}, + {8, RMI$_TQEUSRTIMR}, + {8, RMI$_TQEUSRWAKE}, +}; + +static const struct item_st SYI_item_data[] = { + {4, SYI$_PAGEFILE_FREE}, +}; + +/* + * Input: + * items_data - an array of lengths and codes + * items_data_num - number of elements in that array + * + * Output: + * items - pre-allocated ILE3 array to be filled. + * It's assumed to have items_data_num elements plus + * one extra for the terminating NULL element + * databuffer - pre-allocated 32-bit word array. + * + * Returns the number of elements used in databuffer + */ +static size_t prepare_item_list(const struct item_st *items_input, + size_t items_input_num, + ILE3 *items, + uint32_t__ptr32 databuffer) +{ + size_t data_sz = 0; + + for (; items_input_num-- > 0; items_input++, items++) { + + items->ile3$w_code = items_input->code; + /* Special treatment of JPI$_FINALEXC */ + if (items->ile3$w_code == JPI$_FINALEXC) + items->ile3$w_length = 4; + else + items->ile3$w_length = items_input->length; + + items->ile3$ps_bufaddr = databuffer; + items->ile3$ps_retlen_addr = 0; + + databuffer += items_input->length / sizeof(databuffer[0]); + data_sz += items_input->length; + } + /* Terminating NULL entry */ + items->ile3$w_length = items->ile3$w_code = 0; + items->ile3$ps_bufaddr = items->ile3$ps_retlen_addr = NULL; + + return data_sz / sizeof(databuffer[0]); +} + +static void massage_JPI(ILE3 *items) +{ + /* + * Special treatment of JPI$_FINALEXC + * The result of that item's data buffer is a 32-bit address to a list of + * 4 32-bit words. + */ + for (; items->ile3$w_length != 0; items++) { + if (items->ile3$w_code == JPI$_FINALEXC) { + uint32_t *data = items->ile3$ps_bufaddr; + uint32_t *ptr = (uint32_t *)*data; + size_t j; + + /* + * We know we made space for 4 32-bit words, so we can do in-place + * replacement. + */ + for (j = 0; j < 4; j++) + data[j] = ptr[j]; + + break; + } + } +} + +/* + * This number expresses how many bits of data contain 1 bit of entropy. + * + * For the moment, we assume about 0.05 entropy bits per data bit, or 1 + * bit of entropy per 20 data bits. + */ +#define ENTROPY_FACTOR 20 + +size_t data_collect_method(RAND_POOL *pool) +{ + ILE3 JPI_items_64bit[OSSL_NELEM(JPI_item_data_64bit) + 1]; + ILE3 RMI_items_64bit[OSSL_NELEM(RMI_item_data_64bit) + 1]; + ILE3 DVI_items[OSSL_NELEM(DVI_item_data) + 1]; + ILE3 JPI_items[OSSL_NELEM(JPI_item_data) + 1]; + ILE3 RMI_items[OSSL_NELEM(RMI_item_data) + 1]; + ILE3 SYI_items[OSSL_NELEM(SYI_item_data) + 1]; + union { + /* This ensures buffer starts at 64 bit boundary */ + uint64_t dummy; + uint32_t buffer[OSSL_NELEM(JPI_item_data_64bit) * 2 + + OSSL_NELEM(RMI_item_data_64bit) * 2 + + OSSL_NELEM(DVI_item_data) + + OSSL_NELEM(JPI_item_data) + + OSSL_NELEM(RMI_item_data) + + OSSL_NELEM(SYI_item_data) + + 4 /* For JPI$_FINALEXC */]; + } data; + size_t total_elems = 0; + size_t total_length = 0; + size_t bytes_needed = rand_pool_bytes_needed(pool, ENTROPY_FACTOR); + size_t bytes_remaining = rand_pool_bytes_remaining(pool); + + /* Take all the 64-bit items first, to ensure proper alignment of data */ + total_elems += + prepare_item_list(JPI_item_data_64bit, OSSL_NELEM(JPI_item_data_64bit), + JPI_items_64bit, &data.buffer[total_elems]); + total_elems += + prepare_item_list(RMI_item_data_64bit, OSSL_NELEM(RMI_item_data_64bit), + RMI_items_64bit, &data.buffer[total_elems]); + /* Now the 32-bit items */ + total_elems += prepare_item_list(DVI_item_data, OSSL_NELEM(DVI_item_data), + DVI_items, &data.buffer[total_elems]); + total_elems += prepare_item_list(JPI_item_data, OSSL_NELEM(JPI_item_data), + JPI_items, &data.buffer[total_elems]); + total_elems += prepare_item_list(RMI_item_data, OSSL_NELEM(RMI_item_data), + RMI_items, &data.buffer[total_elems]); + total_elems += prepare_item_list(SYI_item_data, OSSL_NELEM(SYI_item_data), + SYI_items, &data.buffer[total_elems]); + total_length = total_elems * sizeof(data.buffer[0]); + + /* Fill data.buffer with various info bits from this process */ + { + uint32_t status; + uint32_t efn; + IOSB iosb; + $DESCRIPTOR(SYSDEVICE,"SYS$SYSDEVICE:"); + + if ((status = sys$getdviw(EFN$C_ENF, 0, &SYSDEVICE, DVI_items, + 0, 0, 0, 0, 0)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items_64bit, 0, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items, 0, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getsyiw(EFN$C_ENF, 0, 0, SYI_items, 0, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + /* + * The RMI service is a bit special, as there is no synchronous + * variant, so we MUST create an event flag to synchronise on. + */ + if ((status = lib$get_ef(&efn)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$getrmi(efn, 0, 0, RMI_items_64bit, &iosb, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if (iosb.iosb$l_getxxi_status != SS$_NORMAL) { + lib$signal(iosb.iosb$l_getxxi_status); + return 0; + } + if ((status = sys$getrmi(efn, 0, 0, RMI_items, &iosb, 0, 0)) + != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + if (iosb.iosb$l_getxxi_status != SS$_NORMAL) { + lib$signal(iosb.iosb$l_getxxi_status); + return 0; + } + if ((status = lib$free_ef(&efn)) != SS$_NORMAL) { + lib$signal(status); + return 0; + } + } + + massage_JPI(JPI_items); + + /* + * If we can't feed the requirements from the caller, we're in deep trouble. + */ + if (!ossl_assert(total_length >= bytes_needed)) { + char buf[100]; /* That should be enough */ + + BIO_snprintf(buf, sizeof(buf), "Needed: %zu, Available: %zu", + bytes_needed, total_length); + RANDerr(RAND_F_DATA_COLLECT_METHOD, RAND_R_RANDOM_POOL_UNDERFLOW); + ERR_add_error_data(1, buf); + return 0; + } + + /* + * Try not to overfeed the pool + */ + if (total_length > bytes_remaining) + total_length = bytes_remaining; + + /* We give the pessimistic value for the amount of entropy */ + rand_pool_add(pool, (unsigned char *)data.buffer, total_length, + 8 * total_length / ENTROPY_FACTOR); + return rand_pool_entropy_available(pool); +} + +int rand_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + pid_t pid; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data = { 0 }; + + /* + * Add process id, thread id, and a high resolution timestamp + * (where available, which is OpenVMS v8.4 and up) to ensure that + * the nonce is unique with high probability for different process + * instances. + */ + data.pid = getpid(); + data.tid = CRYPTO_THREAD_get_current_id(); +#if __CRTL_VER >= 80400000 + sys$gettim_prec(&data.time); +#else + sys$gettim((void*)&data.time); +#endif + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +/* + * SYS$GET_ENTROPY METHOD + * ====================== + * + * This is a high entropy method based on a new system service that is + * based on getentropy() from FreeBSD 12. It's only used if available, + * and its availability is detected at run-time. + * + * We assume that this function provides full entropy random output. + */ +#define PUBLIC_VECTORS "SYS$LIBRARY:SYS$PUBLIC_VECTORS.EXE" +#define GET_ENTROPY "SYS$GET_ENTROPY" + +static int get_entropy_address_flag = 0; +static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL; +static int init_get_entropy_address(void) +{ + if (get_entropy_address_flag == 0) + get_entropy_address = dlsym(dlopen(PUBLIC_VECTORS, 0), GET_ENTROPY); + get_entropy_address_flag = 1; + return get_entropy_address != NULL; +} + +size_t get_entropy_method(RAND_POOL *pool) +{ + /* + * The documentation says that SYS$GET_ENTROPY will give a maximum of + * 256 bytes of data. + */ + unsigned char buffer[256]; + size_t bytes_needed; + size_t bytes_to_get = 0; + uint32_t status; + + for (bytes_needed = rand_pool_bytes_needed(pool, 1); + bytes_needed > 0; + bytes_needed -= bytes_to_get) { + bytes_to_get = + bytes_needed > sizeof(buffer) ? sizeof(buffer) : bytes_needed; + + status = get_entropy_address(buffer, bytes_to_get); + if (status == SS$_RETRY) { + /* Set to zero so the loop doesn't diminish |bytes_needed| */ + bytes_to_get = 0; + /* Should sleep some amount of time */ + continue; + } + + if (status != SS$_NORMAL) { + lib$signal(status); + return 0; + } + + rand_pool_add(pool, buffer, bytes_to_get, 8 * bytes_to_get); + } + + return rand_pool_entropy_available(pool); +} + +/* + * MAIN ENTROPY ACQUISITION FUNCTIONS + * ================================== + * + * These functions are called by the RAND / DRBG functions + */ + +size_t rand_pool_acquire_entropy(RAND_POOL *pool) +{ + if (init_get_entropy_address()) + return get_entropy_method(pool); + return data_collect_method(pool); +} + + +int rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + CRYPTO_THREAD_ID tid; + uint64_t time; + } data = { 0 }; + + /* + * Add some noise from the thread id and a high resolution timer. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.tid = CRYPTO_THREAD_get_current_id(); +#if __CRTL_VER >= 80400000 + sys$gettim_prec(&data.time); +#else + sys$gettim((void*)&data.time); +#endif + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int rand_pool_init(void) +{ + return 1; +} + +void rand_pool_cleanup(void) +{ +} + +void rand_pool_keep_random_devices_open(int keep) +{ +} + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c new file mode 100644 index 000000000..903654600 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/rand_win.c @@ -0,0 +1,186 @@ +/* + * Copyright 1995-2019 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 "internal/cryptlib.h" +#include <openssl/rand.h> +#include "rand_local.h" +#include "crypto/rand.h" +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) + +# ifndef OPENSSL_RAND_SEED_OS +# error "Unsupported seeding method configured; must be os" +# endif + +# include <windows.h> +/* On Windows Vista or higher use BCrypt instead of the legacy CryptoAPI */ +# if defined(_MSC_VER) && _MSC_VER > 1500 /* 1500 = Visual Studio 2008 */ \ + && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 +# define USE_BCRYPTGENRANDOM +# endif + +# ifdef USE_BCRYPTGENRANDOM +# include <bcrypt.h> +# pragma comment(lib, "bcrypt.lib") +# ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +# endif +# else +# include <wincrypt.h> +/* + * Intel hardware RNG CSP -- available from + * http://developer.intel.com/design/security/rng/redist_license.htm + */ +# define PROV_INTEL_SEC 22 +# define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider" +# endif + +size_t rand_pool_acquire_entropy(RAND_POOL *pool) +{ +# ifndef USE_BCRYPTGENRANDOM + HCRYPTPROV hProvider; +# endif + unsigned char *buffer; + size_t bytes_needed; + size_t entropy_available = 0; + + +# ifdef OPENSSL_RAND_SEED_RDTSC + entropy_available = rand_acquire_entropy_from_tsc(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# ifdef OPENSSL_RAND_SEED_RDCPU + entropy_available = rand_acquire_entropy_from_cpu(pool); + if (entropy_available > 0) + return entropy_available; +# endif + +# ifdef USE_BCRYPTGENRANDOM + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + buffer = rand_pool_add_begin(pool, bytes_needed); + if (buffer != NULL) { + size_t bytes = 0; + if (BCryptGenRandom(NULL, buffer, bytes_needed, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) + bytes = bytes_needed; + + rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = rand_pool_entropy_available(pool); + } + if (entropy_available > 0) + return entropy_available; +# else + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + buffer = rand_pool_add_begin(pool, bytes_needed); + if (buffer != NULL) { + size_t bytes = 0; + /* poll the CryptoAPI PRNG */ + if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) { + if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0) + bytes = bytes_needed; + + CryptReleaseContext(hProvider, 0); + } + + rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = rand_pool_entropy_available(pool); + } + if (entropy_available > 0) + return entropy_available; + + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + buffer = rand_pool_add_begin(pool, bytes_needed); + if (buffer != NULL) { + size_t bytes = 0; + /* poll the Pentium PRG with CryptoAPI */ + if (CryptAcquireContextW(&hProvider, NULL, + INTEL_DEF_PROV, PROV_INTEL_SEC, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) { + if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0) + bytes = bytes_needed; + + CryptReleaseContext(hProvider, 0); + } + rand_pool_add_end(pool, bytes, 8 * bytes); + entropy_available = rand_pool_entropy_available(pool); + } + if (entropy_available > 0) + return entropy_available; +# endif + + return rand_pool_entropy_available(pool); +} + + +int rand_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + DWORD pid; + DWORD tid; + FILETIME time; + } data = { 0 }; + + /* + * Add process id, thread id, and a high resolution timestamp to + * ensure that the nonce is unique with high probability for + * different process instances. + */ + data.pid = GetCurrentProcessId(); + data.tid = GetCurrentThreadId(); + GetSystemTimeAsFileTime(&data.time); + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + DWORD tid; + LARGE_INTEGER time; + } data = { 0 }; + + /* + * Add some noise from the thread id and a high resolution timer. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.tid = GetCurrentThreadId(); + QueryPerformanceCounter(&data.time); + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +# if OPENSSL_API_COMPAT < 0x10100000L +int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + RAND_poll(); + return RAND_status(); +} + +void RAND_screen(void) +{ + RAND_poll(); +} +# endif + +int rand_pool_init(void) +{ + return 1; +} + +void rand_pool_cleanup(void) +{ +} + +void rand_pool_keep_random_devices_open(int keep) +{ +} + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c new file mode 100644 index 000000000..ba121eefb --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/rand/randfile.c @@ -0,0 +1,314 @@ +/* + * Copyright 1995-2019 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 "internal/cryptlib.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <openssl/crypto.h> +#include <openssl/rand.h> +#include <openssl/rand_drbg.h> +#include <openssl/buffer.h> + +#ifdef OPENSSL_SYS_VMS +# include <unixio.h> +#endif +#include <sys/types.h> +#ifndef OPENSSL_NO_POSIX_IO +# include <sys/stat.h> +# include <fcntl.h> +# ifdef _WIN32 +# include <windows.h> +# include <io.h> +# define stat _stat +# define chmod _chmod +# define open _open +# define fdopen _fdopen +# define fstat _fstat +# define fileno _fileno +# endif +#endif + +/* + * Following should not be needed, and we could have been stricter + * and demand S_IS*. But some systems just don't comply... Formally + * below macros are "anatomically incorrect", because normally they + * would look like ((m) & MASK == TYPE), but since MASK availability + * is as questionable, we settle for this poor-man fallback... + */ +# if !defined(S_ISREG) +# define S_ISREG(m) ((m) & S_IFREG) +# endif + +#define RAND_BUF_SIZE 1024 +#define RFILE ".rnd" + +#ifdef OPENSSL_SYS_VMS +/* + * __FILE_ptr32 is a type provided by DEC C headers (types.h specifically) + * to make sure the FILE* is a 32-bit pointer no matter what. We know that + * stdio functions return this type (a study of stdio.h proves it). + * + * This declaration is a nasty hack to get around vms' extension to fopen for + * passing in sharing options being disabled by /STANDARD=ANSI89 + */ +static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) = + (__FILE_ptr32 (*)(const char *, const char *, ...))fopen; +# define VMS_OPEN_ATTRS \ + "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0" +# define openssl_fopen(fname, mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS) +#endif + +/* + * Note that these functions are intended for seed files only. Entropy + * devices and EGD sockets are handled in rand_unix.c If |bytes| is + * -1 read the complete file; otherwise read the specified amount. + */ +int RAND_load_file(const char *file, long bytes) +{ + /* + * The load buffer size exceeds the chunk size by the comfortable amount + * of 'RAND_DRBG_STRENGTH' bytes (not bits!). This is done on purpose + * to avoid calling RAND_add() with a small final chunk. Instead, such + * a small final chunk will be added together with the previous chunk + * (unless it's the only one). + */ +#define RAND_LOAD_BUF_SIZE (RAND_BUF_SIZE + RAND_DRBG_STRENGTH) + unsigned char buf[RAND_LOAD_BUF_SIZE]; + +#ifndef OPENSSL_NO_POSIX_IO + struct stat sb; +#endif + int i, n, ret = 0; + FILE *in; + + if (bytes == 0) + return 0; + + if ((in = openssl_fopen(file, "rb")) == NULL) { + RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_CANNOT_OPEN_FILE); + ERR_add_error_data(2, "Filename=", file); + return -1; + } + +#ifndef OPENSSL_NO_POSIX_IO + if (fstat(fileno(in), &sb) < 0) { + RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_INTERNAL_ERROR); + ERR_add_error_data(2, "Filename=", file); + fclose(in); + return -1; + } + + if (bytes < 0) { + if (S_ISREG(sb.st_mode)) + bytes = sb.st_size; + else + bytes = RAND_DRBG_STRENGTH; + } +#endif + /* + * On VMS, setbuf() will only take 32-bit pointers, and a compilation + * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here. + * However, we trust that the C RTL will never give us a FILE pointer + * above the first 4 GB of memory, so we simply turn off the warning + * temporarily. + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma environment save +# pragma message disable maylosedata2 +#endif + /* + * Don't buffer, because even if |file| is regular file, we have + * no control over the buffer, so why would we want a copy of its + * contents lying around? + */ + setbuf(in, NULL); +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma environment restore +#endif + + for ( ; ; ) { + if (bytes > 0) + n = (bytes <= RAND_LOAD_BUF_SIZE) ? (int)bytes : RAND_BUF_SIZE; + else + n = RAND_LOAD_BUF_SIZE; + i = fread(buf, 1, n, in); +#ifdef EINTR + if (ferror(in) && errno == EINTR){ + clearerr(in); + if (i == 0) + continue; + } +#endif + if (i == 0) + break; + + RAND_add(buf, i, (double)i); + ret += i; + + /* If given a bytecount, and we did it, break. */ + if (bytes > 0 && (bytes -= i) <= 0) + break; + } + + OPENSSL_cleanse(buf, sizeof(buf)); + fclose(in); + if (!RAND_status()) { + RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_RESEED_ERROR); + ERR_add_error_data(2, "Filename=", file); + return -1; + } + + return ret; +} + +int RAND_write_file(const char *file) +{ + unsigned char buf[RAND_BUF_SIZE]; + int ret = -1; + FILE *out = NULL; +#ifndef OPENSSL_NO_POSIX_IO + struct stat sb; + + if (stat(file, &sb) >= 0 && !S_ISREG(sb.st_mode)) { + RANDerr(RAND_F_RAND_WRITE_FILE, RAND_R_NOT_A_REGULAR_FILE); + ERR_add_error_data(2, "Filename=", file); + return -1; + } +#endif + + /* Collect enough random data. */ + if (RAND_priv_bytes(buf, (int)sizeof(buf)) != 1) + return -1; + +#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && \ + !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS) + { +# ifndef O_BINARY +# define O_BINARY 0 +# endif + /* + * chmod(..., 0600) is too late to protect the file, permissions + * should be restrictive from the start + */ + int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600); + if (fd != -1) + out = fdopen(fd, "wb"); + } +#endif + +#ifdef OPENSSL_SYS_VMS + /* + * VMS NOTE: Prior versions of this routine created a _new_ version of + * the rand file for each call into this routine, then deleted all + * existing versions named ;-1, and finally renamed the current version + * as ';1'. Under concurrent usage, this resulted in an RMS race + * condition in rename() which could orphan files (see vms message help + * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares + * the top-level version of the rand file. Note that there may still be + * conditions where the top-level rand file is locked. If so, this code + * will then create a new version of the rand file. Without the delete + * and rename code, this can result in ascending file versions that stop + * at version 32767, and this routine will then return an error. The + * remedy for this is to recode the calling application to avoid + * concurrent use of the rand file, or synchronize usage at the + * application level. Also consider whether or not you NEED a persistent + * rand file in a concurrent use situation. + */ + out = openssl_fopen(file, "rb+"); +#endif + + if (out == NULL) + out = openssl_fopen(file, "wb"); + if (out == NULL) { + RANDerr(RAND_F_RAND_WRITE_FILE, RAND_R_CANNOT_OPEN_FILE); + ERR_add_error_data(2, "Filename=", file); + return -1; + } + +#if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO) + /* + * Yes it's late to do this (see above comment), but better than nothing. + */ + chmod(file, 0600); +#endif + + ret = fwrite(buf, 1, RAND_BUF_SIZE, out); + fclose(out); + OPENSSL_cleanse(buf, RAND_BUF_SIZE); + return ret; +} + +const char *RAND_file_name(char *buf, size_t size) +{ + char *s = NULL; + size_t len; + int use_randfile = 1; + +#if defined(_WIN32) && defined(CP_UTF8) && !defined(_WIN32_WCE) + DWORD envlen; + WCHAR *var; + + /* Look up various environment variables. */ + if ((envlen = GetEnvironmentVariableW(var = L"RANDFILE", NULL, 0)) == 0) { + use_randfile = 0; + if ((envlen = GetEnvironmentVariableW(var = L"HOME", NULL, 0)) == 0 + && (envlen = GetEnvironmentVariableW(var = L"USERPROFILE", + NULL, 0)) == 0) + envlen = GetEnvironmentVariableW(var = L"SYSTEMROOT", NULL, 0); + } + + /* If we got a value, allocate space to hold it and then get it. */ + if (envlen != 0) { + int sz; + WCHAR *val = _alloca(envlen * sizeof(WCHAR)); + + if (GetEnvironmentVariableW(var, val, envlen) < envlen + && (sz = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, + NULL, NULL)) != 0) { + s = _alloca(sz); + if (WideCharToMultiByte(CP_UTF8, 0, val, -1, s, sz, + NULL, NULL) == 0) + s = NULL; + } + } +#else + if ((s = ossl_safe_getenv("RANDFILE")) == NULL || *s == '\0') { + use_randfile = 0; + s = ossl_safe_getenv("HOME"); + } +#endif + +#ifdef DEFAULT_HOME + if (!use_randfile && s == NULL) + s = DEFAULT_HOME; +#endif + if (s == NULL || *s == '\0') + return NULL; + + len = strlen(s); + if (use_randfile) { + if (len + 1 >= size) + return NULL; + strcpy(buf, s); + } else { + if (len + 1 + strlen(RFILE) + 1 >= size) + return NULL; + strcpy(buf, s); +#ifndef OPENSSL_SYS_VMS + strcat(buf, "/"); +#endif + strcat(buf, RFILE); + } + + return buf; +} |