aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/rand
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/rand')
-rw-r--r--crypto/rand/Makefile166
-rw-r--r--crypto/rand/build.info4
-rw-r--r--crypto/rand/drbg_ctr.c438
-rw-r--r--crypto/rand/drbg_lib.c1070
-rw-r--r--crypto/rand/md_rand.c616
-rw-r--r--crypto/rand/rand.h150
-rw-r--r--crypto/rand/rand_egd.c352
-rw-r--r--crypto/rand/rand_err.c192
-rwxr-xr-xcrypto/rand/rand_lcl.h396
-rw-r--r--crypto/rand/rand_lib.c911
-rw-r--r--crypto/rand/rand_unix.c943
-rw-r--r--crypto/rand/randfile.c428
-rw-r--r--crypto/rand/randtest.c209
13 files changed, 3455 insertions, 2420 deletions
diff --git a/crypto/rand/Makefile b/crypto/rand/Makefile
deleted file mode 100644
index df44369a0823..000000000000
--- a/crypto/rand/Makefile
+++ /dev/null
@@ -1,166 +0,0 @@
-#
-# OpenSSL/crypto/rand/Makefile
-#
-
-DIR= rand
-TOP= ../..
-CC= cc
-INCLUDES=
-CFLAG=-g
-MAKEFILE= Makefile
-AR= ar r
-
-CFLAGS= $(INCLUDES) $(CFLAG)
-
-GENERAL=Makefile
-TEST= randtest.c
-APPS=
-
-LIB=$(TOP)/libcrypto.a
-LIBSRC=md_rand.c randfile.c rand_lib.c rand_err.c rand_egd.c \
- rand_win.c rand_unix.c rand_os2.c rand_nw.c
-LIBOBJ=md_rand.o randfile.o rand_lib.o rand_err.o rand_egd.o \
- rand_win.o rand_unix.o rand_os2.o rand_nw.o
-
-SRC= $(LIBSRC)
-
-EXHEADER= rand.h
-HEADER= $(EXHEADER)
-
-ALL= $(GENERAL) $(SRC) $(HEADER)
-
-top:
- (cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all)
-
-all: lib
-
-lib: $(LIBOBJ)
- $(AR) $(LIB) $(LIBOBJ)
- $(RANLIB) $(LIB) || echo Never mind.
- @touch lib
-
-files:
- $(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
-
-links:
- @$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER)
- @$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST)
- @$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS)
-
-install:
- @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile...
- @headerlist="$(EXHEADER)"; for i in $$headerlist ; \
- do \
- (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
- done;
-
-tags:
- ctags $(SRC)
-
-tests:
-
-lint:
- lint -DLINT $(INCLUDES) $(SRC)>fluff
-
-update: depend
-
-depend:
- @[ -n "$(MAKEDEPEND)" ] # should be set by upper Makefile...
- $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC)
-
-dclean:
- $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
- mv -f Makefile.new $(MAKEFILE)
-
-clean:
- rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-
-md_rand.o: ../../e_os.h ../../include/openssl/asn1.h
-md_rand.o: ../../include/openssl/bio.h ../../include/openssl/crypto.h
-md_rand.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h
-md_rand.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h
-md_rand.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
-md_rand.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h
-md_rand.o: ../../include/openssl/ossl_typ.h ../../include/openssl/rand.h
-md_rand.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h
-md_rand.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
-md_rand.o: md_rand.c rand_lcl.h
-rand_egd.o: ../../include/openssl/buffer.h ../../include/openssl/e_os2.h
-rand_egd.o: ../../include/openssl/opensslconf.h
-rand_egd.o: ../../include/openssl/ossl_typ.h ../../include/openssl/rand.h
-rand_egd.o: rand_egd.c
-rand_err.o: ../../include/openssl/bio.h ../../include/openssl/crypto.h
-rand_err.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h
-rand_err.o: ../../include/openssl/lhash.h ../../include/openssl/opensslconf.h
-rand_err.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-rand_err.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h
-rand_err.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
-rand_err.o: rand_err.c
-rand_lib.o: ../../e_os.h ../../include/openssl/asn1.h
-rand_lib.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h
-rand_lib.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
-rand_lib.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h
-rand_lib.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h
-rand_lib.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-rand_lib.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
-rand_lib.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
-rand_lib.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-rand_lib.o: ../../include/openssl/pkcs7.h ../../include/openssl/rand.h
-rand_lib.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h
-rand_lib.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
-rand_lib.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h
-rand_lib.o: ../cryptlib.h rand_lib.c
-rand_nw.o: ../../e_os.h ../../include/openssl/asn1.h
-rand_nw.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h
-rand_nw.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
-rand_nw.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-rand_nw.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
-rand_nw.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
-rand_nw.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-rand_nw.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h
-rand_nw.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
-rand_nw.o: ../../include/openssl/symhacks.h ../cryptlib.h rand_lcl.h rand_nw.c
-rand_os2.o: ../../e_os.h ../../include/openssl/asn1.h
-rand_os2.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h
-rand_os2.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
-rand_os2.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-rand_os2.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
-rand_os2.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
-rand_os2.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-rand_os2.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h
-rand_os2.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
-rand_os2.o: ../../include/openssl/symhacks.h ../cryptlib.h rand_lcl.h
-rand_os2.o: rand_os2.c
-rand_unix.o: ../../e_os.h ../../include/openssl/asn1.h
-rand_unix.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h
-rand_unix.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
-rand_unix.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-rand_unix.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
-rand_unix.o: ../../include/openssl/objects.h
-rand_unix.o: ../../include/openssl/opensslconf.h
-rand_unix.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-rand_unix.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h
-rand_unix.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
-rand_unix.o: ../../include/openssl/symhacks.h ../cryptlib.h rand_lcl.h
-rand_unix.o: rand_unix.c
-rand_win.o: ../../e_os.h ../../include/openssl/asn1.h
-rand_win.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h
-rand_win.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
-rand_win.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-rand_win.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
-rand_win.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
-rand_win.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-rand_win.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h
-rand_win.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
-rand_win.o: ../../include/openssl/symhacks.h ../cryptlib.h rand_lcl.h
-rand_win.o: rand_win.c
-randfile.o: ../../e_os.h ../../include/openssl/buffer.h
-randfile.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
-randfile.o: ../../include/openssl/opensslconf.h
-randfile.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
-randfile.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h
-randfile.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
-randfile.o: randfile.c
diff --git a/crypto/rand/build.info b/crypto/rand/build.info
new file mode 100644
index 000000000000..df9bac67f04c
--- /dev/null
+++ b/crypto/rand/build.info
@@ -0,0 +1,4 @@
+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
diff --git a/crypto/rand/drbg_ctr.c b/crypto/rand/drbg_ctr.c
new file mode 100644
index 000000000000..fe15164451e8
--- /dev/null
+++ b/crypto/rand/drbg_ctr.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2011-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 <stdlib.h>
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include "internal/thread_once.h"
+#include "internal/thread_once.h"
+#include "rand_lcl.h"
+/*
+ * Implementation of NIST SP 800-90A CTR DRBG.
+ */
+
+static void inc_128(RAND_DRBG_CTR *ctr)
+{
+ int i;
+ unsigned char c;
+ unsigned char *p = &ctr->V[15];
+
+ for (i = 0; i < 16; i++, p--) {
+ c = *p;
+ c++;
+ *p = c;
+ if (c != 0) {
+ /* If we didn't wrap around, we're done. */
+ break;
+ }
+ }
+}
+
+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_MINMAX_FACTOR * drbg->min_entropylen;
+ drbg->min_noncelen = drbg->min_entropylen / 2;
+ drbg->max_noncelen = DRBG_MINMAX_FACTOR * drbg->min_noncelen;
+ 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/crypto/rand/drbg_lib.c b/crypto/rand/drbg_lib.c
new file mode 100644
index 000000000000..729b49c94372
--- /dev/null
+++ b/crypto/rand/drbg_lib.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright 2011-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 <string.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include "rand_lcl.h"
+#include "internal/thread_once.h"
+#include "internal/rand_int.h"
+#include "internal/cryptlib_int.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;
+
+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;
+ }
+
+ drbg->state = DRBG_UNINITIALISED;
+ drbg->flags = flags;
+ drbg->type = type;
+
+ switch (type) {
+ default:
+ RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE);
+ return 0;
+ case 0:
+ /* Uninitialized; that's okay. */
+ 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)
+ 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_count = rand_fork_count;
+ 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:
+ if (drbg->secure)
+ OPENSSL_secure_free(drbg);
+ else
+ OPENSSL_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);
+ 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 accomadate 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;
+ }
+
+ 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->generate_counter = 0;
+ drbg->reseed_time = time(NULL);
+ if (drbg->reseed_counter > 0) {
+ if (drbg->parent == NULL)
+ drbg->reseed_counter++;
+ else
+ drbg->reseed_counter = drbg->parent->reseed_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->pool != NULL) {
+ if (drbg->state == DRBG_READY) {
+ RANDerr(RAND_F_RAND_DRBG_INSTANTIATE,
+ RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED);
+ drbg->state = DRBG_ERROR;
+ }
+ rand_pool_free(drbg->pool);
+ drbg->pool = NULL;
+ }
+ 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) {
+ 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;
+ 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->generate_counter = 0;
+ drbg->reseed_time = time(NULL);
+ if (drbg->reseed_counter > 0) {
+ if (drbg->parent == NULL)
+ drbg->reseed_counter++;
+ else
+ drbg->reseed_counter = drbg->parent->reseed_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->pool != NULL) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
+ rand_pool_free(drbg->pool);
+ drbg->pool = NULL;
+ }
+
+ if (buffer != NULL) {
+ if (entropy > 0) {
+ if (drbg->max_entropylen < len) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART,
+ RAND_R_ENTROPY_INPUT_TOO_LONG);
+ return 0;
+ }
+
+ if (entropy > 8 * len) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE);
+ return 0;
+ }
+
+ /* will be picked up by the rand_drbg_get_entropy() callback */
+ drbg->pool = rand_pool_new(entropy, len, len);
+ if (drbg->pool == NULL)
+ return 0;
+
+ rand_pool_add(drbg->pool, buffer, len, entropy);
+ } else {
+ if (drbg->max_adinlen < len) {
+ RANDerr(RAND_F_RAND_DRBG_RESTART,
+ RAND_R_ADDITIONAL_INPUT_TOO_LONG);
+ 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);
+ }
+ }
+
+ /* check whether a given entropy pool was cleared properly during reseed */
+ if (drbg->pool != NULL) {
+ drbg->state = DRBG_ERROR;
+ RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR);
+ rand_pool_free(drbg->pool);
+ drbg->pool = NULL;
+ return 0;
+ }
+
+ 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 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;
+ }
+
+ if (drbg->fork_count != rand_fork_count) {
+ drbg->fork_count = rand_fork_count;
+ reseed_required = 1;
+ }
+
+ if (drbg->reseed_interval > 0) {
+ if (drbg->generate_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->reseed_counter > 0 && drbg->parent != NULL) {
+ if (drbg->reseed_counter != drbg->parent->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->generate_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;
+
+ additional_len = rand_drbg_get_additional_data(&additional, drbg->max_adinlen);
+
+ 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_len != 0)
+ OPENSSL_secure_clear_free(additional, additional_len);
+
+ 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)
+ 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 */
+ drbg->reseed_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;
+}
+
+/* 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();
+
+ if (drbg == NULL)
+ return 0;
+
+ if (num < 0 || randomness < 0.0)
+ return 0;
+
+ if (randomness > (double)drbg->max_entropylen) {
+ /*
+ * 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.
+ */
+ return 0;
+ }
+
+ rand_drbg_lock(drbg);
+ ret = rand_drbg_restart(drbg, buf,
+ (size_t)(unsigned int)num,
+ (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/crypto/rand/md_rand.c b/crypto/rand/md_rand.c
deleted file mode 100644
index a7af9f9d8671..000000000000
--- a/crypto/rand/md_rand.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/* crypto/rand/md_rand.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#define OPENSSL_FIPSEVP
-
-#ifdef MD_RAND_DEBUG
-# ifndef NDEBUG
-# define NDEBUG
-# endif
-#endif
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "e_os.h"
-
-#include <openssl/crypto.h>
-#include <openssl/rand.h>
-#include "rand_lcl.h"
-
-#include <openssl/err.h>
-
-#ifdef BN_DEBUG
-# define PREDICT
-#endif
-
-/* #define PREDICT 1 */
-
-#define STATE_SIZE 1023
-static size_t state_num = 0, state_index = 0;
-static unsigned char state[STATE_SIZE + MD_DIGEST_LENGTH];
-static unsigned char md[MD_DIGEST_LENGTH];
-static long md_count[2] = { 0, 0 };
-
-static double entropy = 0;
-static int initialized = 0;
-
-static unsigned int crypto_lock_rand = 0; /* may be set only when a thread
- * holds CRYPTO_LOCK_RAND (to
- * prevent double locking) */
-/* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */
-/* valid iff crypto_lock_rand is set */
-static CRYPTO_THREADID locking_threadid;
-
-#ifdef PREDICT
-int rand_predictable = 0;
-#endif
-
-const char RAND_version[] = "RAND" OPENSSL_VERSION_PTEXT;
-
-static void ssleay_rand_cleanup(void);
-static void ssleay_rand_seed(const void *buf, int num);
-static void ssleay_rand_add(const void *buf, int num, double add_entropy);
-static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num);
-static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num);
-static int ssleay_rand_status(void);
-
-RAND_METHOD rand_ssleay_meth = {
- ssleay_rand_seed,
- ssleay_rand_nopseudo_bytes,
- ssleay_rand_cleanup,
- ssleay_rand_add,
- ssleay_rand_pseudo_bytes,
- ssleay_rand_status
-};
-
-RAND_METHOD *RAND_SSLeay(void)
-{
- return (&rand_ssleay_meth);
-}
-
-static void ssleay_rand_cleanup(void)
-{
- OPENSSL_cleanse(state, sizeof(state));
- state_num = 0;
- state_index = 0;
- OPENSSL_cleanse(md, MD_DIGEST_LENGTH);
- md_count[0] = 0;
- md_count[1] = 0;
- entropy = 0;
- initialized = 0;
-}
-
-static void ssleay_rand_add(const void *buf, int num, double add)
-{
- int i, j, k, st_idx;
- long md_c[2];
- unsigned char local_md[MD_DIGEST_LENGTH];
- EVP_MD_CTX m;
- int do_not_lock;
-
- if (!num)
- return;
-
- /*
- * (Based on the rand(3) manpage)
- *
- * The input is chopped up into units of 20 bytes (or less for
- * the last block). Each of these blocks is run through the hash
- * function as follows: The data passed to the hash function
- * is the current 'md', the same number of bytes from the 'state'
- * (the location determined by in incremented looping index) as
- * the current 'block', the new key data 'block', and 'count'
- * (which is incremented after each use).
- * The result of this is kept in 'md' and also xored into the
- * 'state' at the same locations that were used as input into the
- * hash function.
- */
-
- /* check if we already have the lock */
- if (crypto_lock_rand) {
- CRYPTO_THREADID cur;
- CRYPTO_THREADID_current(&cur);
- CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
- do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
- CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
- } else
- do_not_lock = 0;
-
- if (!do_not_lock)
- CRYPTO_w_lock(CRYPTO_LOCK_RAND);
- st_idx = state_index;
-
- /*
- * use our own copies of the counters so that even if a concurrent thread
- * seeds with exactly the same data and uses the same subarray there's
- * _some_ difference
- */
- md_c[0] = md_count[0];
- md_c[1] = md_count[1];
-
- memcpy(local_md, md, sizeof(md));
-
- /* state_index <= state_num <= STATE_SIZE */
- state_index += num;
- if (state_index >= STATE_SIZE) {
- state_index %= STATE_SIZE;
- state_num = STATE_SIZE;
- } else if (state_num < STATE_SIZE) {
- if (state_index > state_num)
- state_num = state_index;
- }
- /* state_index <= state_num <= STATE_SIZE */
-
- /*
- * state[st_idx], ..., state[(st_idx + num - 1) % STATE_SIZE] are what we
- * will use now, but other threads may use them as well
- */
-
- md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
-
- if (!do_not_lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
-
- EVP_MD_CTX_init(&m);
- for (i = 0; i < num; i += MD_DIGEST_LENGTH) {
- j = (num - i);
- j = (j > MD_DIGEST_LENGTH) ? MD_DIGEST_LENGTH : j;
-
- if (!MD_Init(&m) ||
- !MD_Update(&m, local_md, MD_DIGEST_LENGTH))
- goto err;
- k = (st_idx + j) - STATE_SIZE;
- if (k > 0) {
- if (!MD_Update(&m, &(state[st_idx]), j - k) ||
- !MD_Update(&m, &(state[0]), k))
- goto err;
- } else
- if (!MD_Update(&m, &(state[st_idx]), j))
- goto err;
-
- /* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
- if (!MD_Update(&m, buf, j))
- goto err;
- /*
- * We know that line may cause programs such as purify and valgrind
- * to complain about use of uninitialized data. The problem is not,
- * it's with the caller. Removing that line will make sure you get
- * really bad randomness and thereby other problems such as very
- * insecure keys.
- */
-
- if (!MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c)) ||
- !MD_Final(&m, local_md))
- goto err;
- md_c[1]++;
-
- buf = (const char *)buf + j;
-
- for (k = 0; k < j; k++) {
- /*
- * Parallel threads may interfere with this, but always each byte
- * of the new state is the XOR of some previous value of its and
- * local_md (itermediate values may be lost). Alway using locking
- * could hurt performance more than necessary given that
- * conflicts occur only when the total seeding is longer than the
- * random state.
- */
- state[st_idx++] ^= local_md[k];
- if (st_idx >= STATE_SIZE)
- st_idx = 0;
- }
- }
-
- if (!do_not_lock)
- CRYPTO_w_lock(CRYPTO_LOCK_RAND);
- /*
- * Don't just copy back local_md into md -- this could mean that other
- * thread's seeding remains without effect (except for the incremented
- * counter). By XORing it we keep at least as much entropy as fits into
- * md.
- */
- for (k = 0; k < (int)sizeof(md); k++) {
- md[k] ^= local_md[k];
- }
- if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
- entropy += add;
- if (!do_not_lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
-
-#if !defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32)
- assert(md_c[1] == md_count[1]);
-#endif
-
- err:
- EVP_MD_CTX_cleanup(&m);
-}
-
-static void ssleay_rand_seed(const void *buf, int num)
-{
- ssleay_rand_add(buf, num, (double)num);
-}
-
-int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo, int lock)
-{
- static volatile int stirred_pool = 0;
- int i, j, k;
- size_t num_ceil, st_idx, st_num;
- int ok;
- long md_c[2];
- unsigned char local_md[MD_DIGEST_LENGTH];
- EVP_MD_CTX m;
-#ifndef GETPID_IS_MEANINGLESS
- pid_t curr_pid = getpid();
-#endif
- int do_stir_pool = 0;
-
-#ifdef PREDICT
- if (rand_predictable) {
- static unsigned char val = 0;
-
- for (i = 0; i < num; i++)
- buf[i] = val++;
- return (1);
- }
-#endif
-
- if (num <= 0)
- return 1;
-
- EVP_MD_CTX_init(&m);
- /* round upwards to multiple of MD_DIGEST_LENGTH/2 */
- num_ceil =
- (1 + (num - 1) / (MD_DIGEST_LENGTH / 2)) * (MD_DIGEST_LENGTH / 2);
-
- /*
- * (Based on the rand(3) manpage:)
- *
- * For each group of 10 bytes (or less), we do the following:
- *
- * Input into the hash function the local 'md' (which is initialized from
- * the global 'md' before any bytes are generated), the bytes that are to
- * be overwritten by the random bytes, and bytes from the 'state'
- * (incrementing looping index). From this digest output (which is kept
- * in 'md'), the top (up to) 10 bytes are returned to the caller and the
- * bottom 10 bytes are xored into the 'state'.
- *
- * Finally, after we have finished 'num' random bytes for the
- * caller, 'count' (which is incremented) and the local and global 'md'
- * are fed into the hash function and the results are kept in the
- * global 'md'.
- */
- if (lock)
- CRYPTO_w_lock(CRYPTO_LOCK_RAND);
-
- /* prevent ssleay_rand_bytes() from trying to obtain the lock again */
- CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
- CRYPTO_THREADID_current(&locking_threadid);
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
- crypto_lock_rand = 1;
-
- if (!initialized) {
- RAND_poll();
- initialized = 1;
- }
-
- if (!stirred_pool)
- do_stir_pool = 1;
-
- ok = (entropy >= ENTROPY_NEEDED);
- if (!ok) {
- /*
- * If the PRNG state is not yet unpredictable, then seeing the PRNG
- * output may help attackers to determine the new state; thus we have
- * to decrease the entropy estimate. Once we've had enough initial
- * seeding we don't bother to adjust the entropy count, though,
- * because we're not ambitious to provide *information-theoretic*
- * randomness. NOTE: This approach fails if the program forks before
- * we have enough entropy. Entropy should be collected in a separate
- * input pool and be transferred to the output pool only when the
- * entropy limit has been reached.
- */
- entropy -= num;
- if (entropy < 0)
- entropy = 0;
- }
-
- if (do_stir_pool) {
- /*
- * In the output function only half of 'md' remains secret, so we
- * better make sure that the required entropy gets 'evenly
- * distributed' through 'state', our randomness pool. The input
- * function (ssleay_rand_add) chains all of 'md', which makes it more
- * suitable for this purpose.
- */
-
- int n = STATE_SIZE; /* so that the complete pool gets accessed */
- while (n > 0) {
-#if MD_DIGEST_LENGTH > 20
-# error "Please adjust DUMMY_SEED."
-#endif
-#define DUMMY_SEED "...................." /* at least MD_DIGEST_LENGTH */
- /*
- * Note that the seed does not matter, it's just that
- * ssleay_rand_add expects to have something to hash.
- */
- ssleay_rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0);
- n -= MD_DIGEST_LENGTH;
- }
- if (ok)
- stirred_pool = 1;
- }
-
- st_idx = state_index;
- st_num = state_num;
- md_c[0] = md_count[0];
- md_c[1] = md_count[1];
- memcpy(local_md, md, sizeof(md));
-
- state_index += num_ceil;
- if (state_index > state_num)
- state_index %= state_num;
-
- /*
- * state[st_idx], ..., state[(st_idx + num_ceil - 1) % st_num] are now
- * ours (but other threads may use them too)
- */
-
- md_count[0] += 1;
-
- /* before unlocking, we must clear 'crypto_lock_rand' */
- crypto_lock_rand = 0;
- if (lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
-
- while (num > 0) {
- /* num_ceil -= MD_DIGEST_LENGTH/2 */
- j = (num >= MD_DIGEST_LENGTH / 2) ? MD_DIGEST_LENGTH / 2 : num;
- num -= j;
- if (!MD_Init(&m))
- goto err;
-#ifndef GETPID_IS_MEANINGLESS
- if (curr_pid) { /* just in the first iteration to save time */
- if (!MD_Update(&m, (unsigned char *)&curr_pid, sizeof(curr_pid)))
- goto err;
- curr_pid = 0;
- }
-#endif
- if (!MD_Update(&m, local_md, MD_DIGEST_LENGTH) ||
- !MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
- goto err;
-
-#ifndef PURIFY /* purify complains */
- /*
- * The following line uses the supplied buffer as a small source of
- * entropy: since this buffer is often uninitialised it may cause
- * programs such as purify or valgrind to complain. So for those
- * builds it is not used: the removal of such a small source of
- * entropy has negligible impact on security.
- */
- if (!MD_Update(&m, buf, j))
- goto err;
-#endif
-
- k = (st_idx + MD_DIGEST_LENGTH / 2) - st_num;
- if (k > 0) {
- if (!MD_Update(&m, &(state[st_idx]), MD_DIGEST_LENGTH / 2 - k) ||
- !MD_Update(&m, &(state[0]), k))
- goto err;
- } else {
- if (!MD_Update(&m, &(state[st_idx]), MD_DIGEST_LENGTH / 2))
- goto err;
- }
- if (!MD_Final(&m, local_md))
- goto err;
-
- for (i = 0; i < MD_DIGEST_LENGTH / 2; i++) {
- /* may compete with other threads */
- state[st_idx++] ^= local_md[i];
- if (st_idx >= st_num)
- st_idx = 0;
- if (i < j)
- *(buf++) = local_md[i + MD_DIGEST_LENGTH / 2];
- }
- }
-
- if (!MD_Init(&m) ||
- !MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c)) ||
- !MD_Update(&m, local_md, MD_DIGEST_LENGTH))
- goto err;
- if (lock)
- CRYPTO_w_lock(CRYPTO_LOCK_RAND);
- if (!MD_Update(&m, md, MD_DIGEST_LENGTH) ||
- !MD_Final(&m, md)) {
- if (lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
- goto err;
- }
- if (lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
-
- EVP_MD_CTX_cleanup(&m);
- if (ok)
- return (1);
- else if (pseudo)
- return 0;
- else {
- RANDerr(RAND_F_SSLEAY_RAND_BYTES, RAND_R_PRNG_NOT_SEEDED);
- ERR_add_error_data(1, "You need to read the OpenSSL FAQ, "
- "http://www.openssl.org/support/faq.html");
- return (0);
- }
-
- err:
- EVP_MD_CTX_cleanup(&m);
- return (0);
-}
-
-static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num)
-{
- return ssleay_rand_bytes(buf, num, 0, 1);
-}
-
-/*
- * pseudo-random bytes that are guaranteed to be unique but not unpredictable
- */
-static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num)
-{
- return ssleay_rand_bytes(buf, num, 1, 1);
-}
-
-static int ssleay_rand_status(void)
-{
- CRYPTO_THREADID cur;
- int ret;
- int do_not_lock;
-
- CRYPTO_THREADID_current(&cur);
- /*
- * check if we already have the lock (could happen if a RAND_poll()
- * implementation calls RAND_status())
- */
- if (crypto_lock_rand) {
- CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
- do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
- CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
- } else
- do_not_lock = 0;
-
- if (!do_not_lock) {
- CRYPTO_w_lock(CRYPTO_LOCK_RAND);
-
- /*
- * prevent ssleay_rand_bytes() from trying to obtain the lock again
- */
- CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
- CRYPTO_THREADID_cpy(&locking_threadid, &cur);
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
- crypto_lock_rand = 1;
- }
-
- if (!initialized) {
- RAND_poll();
- initialized = 1;
- }
-
- ret = entropy >= ENTROPY_NEEDED;
-
- if (!do_not_lock) {
- /* before unlocking, we must clear 'crypto_lock_rand' */
- crypto_lock_rand = 0;
-
- CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
- }
-
- return ret;
-}
diff --git a/crypto/rand/rand.h b/crypto/rand/rand.h
deleted file mode 100644
index 2553afda2001..000000000000
--- a/crypto/rand/rand.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* crypto/rand/rand.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#ifndef HEADER_RAND_H
-# define HEADER_RAND_H
-
-# include <stdlib.h>
-# include <openssl/ossl_typ.h>
-# include <openssl/e_os2.h>
-
-# if defined(OPENSSL_SYS_WINDOWS)
-# include <windows.h>
-# endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-# if defined(OPENSSL_FIPS)
-# define FIPS_RAND_SIZE_T size_t
-# endif
-
-/* Already defined in ossl_typ.h */
-/* typedef struct rand_meth_st RAND_METHOD; */
-
-struct rand_meth_st {
- void (*seed) (const void *buf, int num);
- int (*bytes) (unsigned char *buf, int num);
- void (*cleanup) (void);
- void (*add) (const void *buf, int num, double entropy);
- int (*pseudorand) (unsigned char *buf, int num);
- int (*status) (void);
-};
-
-# ifdef BN_DEBUG
-extern int rand_predictable;
-# endif
-
-int RAND_set_rand_method(const RAND_METHOD *meth);
-const RAND_METHOD *RAND_get_rand_method(void);
-# ifndef OPENSSL_NO_ENGINE
-int RAND_set_rand_engine(ENGINE *engine);
-# endif
-RAND_METHOD *RAND_SSLeay(void);
-void RAND_cleanup(void);
-int RAND_bytes(unsigned char *buf, int num);
-int RAND_pseudo_bytes(unsigned char *buf, int num);
-void RAND_seed(const void *buf, int num);
-void RAND_add(const void *buf, int num, double entropy);
-int RAND_load_file(const char *file, long max_bytes);
-int RAND_write_file(const char *file);
-const char *RAND_file_name(char *file, size_t num);
-int RAND_status(void);
-int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes);
-int RAND_egd(const char *path);
-int RAND_egd_bytes(const char *path, int bytes);
-int RAND_poll(void);
-
-# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-
-void RAND_screen(void);
-int RAND_event(UINT, WPARAM, LPARAM);
-
-# endif
-
-# ifdef OPENSSL_FIPS
-void RAND_set_fips_drbg_type(int type, int flags);
-int RAND_init_fips(void);
-# endif
-
-/* BEGIN ERROR CODES */
-/*
- * The following lines are auto generated by the script mkerr.pl. Any changes
- * made after this point may be overwritten when the script is next run.
- */
-void ERR_load_RAND_strings(void);
-
-/* Error codes for the RAND functions. */
-
-/* Function codes. */
-# define RAND_F_RAND_GET_RAND_METHOD 101
-# define RAND_F_RAND_INIT_FIPS 102
-# define RAND_F_SSLEAY_RAND_BYTES 100
-
-/* Reason codes. */
-# define RAND_R_DUAL_EC_DRBG_DISABLED 104
-# define RAND_R_ERROR_INITIALISING_DRBG 102
-# define RAND_R_ERROR_INSTANTIATING_DRBG 103
-# define RAND_R_NO_FIPS_RANDOM_METHOD_SET 101
-# define RAND_R_PRNG_NOT_SEEDED 100
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/crypto/rand/rand_egd.c b/crypto/rand/rand_egd.c
index 66fb14c87efd..da3017df3142 100644
--- a/crypto/rand/rand_egd.c
+++ b/crypto/rand/rand_egd.c
@@ -1,292 +1,158 @@
-/* crypto/rand/rand_egd.c */
-/* Written by Ulf Moeller and Lutz Jaenicke for the OpenSSL project. */
-/* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
+/*
+ * 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/e_os2.h>
-#include <openssl/rand.h>
-#include <openssl/buffer.h>
+#include <openssl/opensslconf.h>
+#ifdef OPENSSL_NO_EGD
+NON_EMPTY_TRANSLATION_UNIT
+#else
-/*-
- * Query the EGD <URL: http://www.lothar.com/tech/crypto/>.
- *
- * This module supplies three routines:
- *
- * RAND_query_egd_bytes(path, buf, bytes)
- * will actually query "bytes" bytes of entropy form the egd-socket located
- * at path and will write them to buf (if supplied) or will directly feed
- * it to RAND_seed() if buf==NULL.
- * The number of bytes is not limited by the maximum chunk size of EGD,
- * which is 255 bytes. If more than 255 bytes are wanted, several chunks
- * of entropy bytes are requested. The connection is left open until the
- * query is competed.
- * RAND_query_egd_bytes() returns with
- * -1 if an error occured during connection or communication.
- * num the number of bytes read from the EGD socket. This number is either
- * the number of bytes requested or smaller, if the EGD pool is
- * drained and the daemon signals that the pool is empty.
- * This routine does not touch any RAND_status(). This is necessary, since
- * PRNG functions may call it during initialization.
- *
- * RAND_egd_bytes(path, bytes) will query "bytes" bytes and have them
- * used to seed the PRNG.
- * RAND_egd_bytes() is a wrapper for RAND_query_egd_bytes() with buf=NULL.
- * Unlike RAND_query_egd_bytes(), RAND_status() is used to test the
- * seed status so that the return value can reflect the seed state:
- * -1 if an error occured during connection or communication _or_
- * if the PRNG has still not received the required seeding.
- * num the number of bytes read from the EGD socket. This number is either
- * the number of bytes requested or smaller, if the EGD pool is
- * drained and the daemon signals that the pool is empty.
- *
- * RAND_egd(path) will query 255 bytes and use the bytes retreived to seed
- * the PRNG.
- * RAND_egd() is a wrapper for RAND_egd_bytes() with numbytes=255.
+# 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_NETWARE) || defined(OPENSSL_SYS_VOS) || defined(OPENSSL_SYS_BEOS)
+# 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);
+ return -1;
}
int RAND_egd(const char *path)
{
- return (-1);
+ return -1;
}
int RAND_egd_bytes(const char *path, int bytes)
{
- return (-1);
+ return -1;
}
-#else
-# include <openssl/opensslconf.h>
-# 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
+
+# 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>
-
-# ifndef offsetof
-# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-# endif
+# endif /* NO_SYS_UN_H */
+# include <string.h>
+# include <errno.h>
int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
{
- int ret = 0;
+ FILE *fp = NULL;
struct sockaddr_un addr;
- int len, num, numbytes;
- int fd = -1;
- int success;
- unsigned char egdbuf[2], tempbuf[255], *retrievebuf;
+ 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);
- BUF_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
- len = offsetof(struct sockaddr_un, sun_path) + strlen(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)
- return (-1);
- success = 0;
- while (!success) {
- if (connect(fd, (struct sockaddr *)&addr, len) == 0)
- success = 1;
- else {
- 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;
-# ifdef EISCONN
- case EISCONN:
- success = 1;
- break;
-# endif
- default:
- goto err; /* failure */
- }
- }
- }
+ if (fd == -1 || (fp = fdopen(fd, "r+")) == NULL)
+ return -1;
+ setbuf(fp, NULL);
- while (bytes > 0) {
- egdbuf[0] = 1;
- egdbuf[1] = bytes < 255 ? bytes : 255;
- numbytes = 0;
- while (numbytes != 2) {
- num = write(fd, egdbuf + numbytes, 2 - numbytes);
- if (num >= 0)
- numbytes += num;
- else {
- switch (errno) {
-# ifdef EINTR
- case EINTR:
-# endif
-# ifdef EAGAIN
- case EAGAIN:
-# endif
- /* No error, try again */
- break;
- default:
- ret = -1;
- goto err; /* failure */
- }
- }
- }
- numbytes = 0;
- while (numbytes != 1) {
- num = read(fd, egdbuf, 1);
- if (num == 0)
- goto err; /* descriptor closed */
- else if (num > 0)
- numbytes += num;
- else {
- switch (errno) {
-# ifdef EINTR
- case EINTR:
-# endif
-# ifdef EAGAIN
- case EAGAIN:
-# endif
- /* No error, try again */
- break;
- default:
- ret = -1;
- goto err; /* failure */
- }
- }
- }
- if (egdbuf[0] == 0)
+ /* 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;
- if (buf)
- retrievebuf = buf + ret;
- else
- retrievebuf = tempbuf;
- numbytes = 0;
- while (numbytes != egdbuf[0]) {
- num = read(fd, retrievebuf + numbytes, egdbuf[0] - numbytes);
- if (num == 0)
- goto err; /* descriptor closed */
- else if (num > 0)
- numbytes += num;
- else {
- switch (errno) {
-# ifdef EINTR
- case EINTR:
-# endif
-# ifdef EAGAIN
- case EAGAIN:
-# endif
- /* No error, try again */
- break;
- default:
- ret = -1;
- goto err; /* failure */
- }
- }
}
- ret += egdbuf[0];
- bytes -= egdbuf[0];
- if (!buf)
- RAND_seed(tempbuf, egdbuf[0]);
}
+
+ /* 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 (fd != -1)
- close(fd);
- return (ret);
+ if (fp != NULL)
+ fclose(fp);
+ return ret;
}
int RAND_egd_bytes(const char *path, int bytes)
{
- int num, ret = 0;
+ int num;
num = RAND_query_egd_bytes(path, NULL, bytes);
- if (num < 1)
- goto err;
- if (RAND_status() == 1)
- ret = num;
- err:
- return (ret);
+ 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));
+ return RAND_egd_bytes(path, 255);
}
+# endif
+
#endif
diff --git a/crypto/rand/rand_err.c b/crypto/rand/rand_err.c
index 55d86ea8a385..31480a682838 100644
--- a/crypto/rand/rand_err.c
+++ b/crypto/rand/rand_err.c
@@ -1,100 +1,134 @@
-/* crypto/rand/rand_err.c */
-/* ====================================================================
- * Copyright (c) 1999-2011 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
/*
- * NOTE: this file was auto generated by the mkerr.pl script: any changes
- * made to it will be overwritten when the script next updates this file,
- * only reason strings will be preserved.
+ * Generated by util/mkerr.pl DO NOT EDIT
+ * Copyright 1995-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 <stdio.h>
#include <openssl/err.h>
-#include <openssl/rand.h>
+#include <openssl/randerr.h>
-/* BEGIN ERROR CODES */
#ifndef OPENSSL_NO_ERR
-# define ERR_FUNC(func) ERR_PACK(ERR_LIB_RAND,func,0)
-# define ERR_REASON(reason) ERR_PACK(ERR_LIB_RAND,0,reason)
-
-static ERR_STRING_DATA RAND_str_functs[] = {
- {ERR_FUNC(RAND_F_RAND_GET_RAND_METHOD), "RAND_get_rand_method"},
- {ERR_FUNC(RAND_F_RAND_INIT_FIPS), "RAND_init_fips"},
- {ERR_FUNC(RAND_F_SSLEAY_RAND_BYTES), "SSLEAY_RAND_BYTES"},
+static const ERR_STRING_DATA RAND_str_functs[] = {
+ {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_BYTES_NEEDED, 0),
+ "rand_pool_bytes_needed"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_POOL_NEW, 0), "rand_pool_new"},
+ {ERR_PACK(ERR_LIB_RAND, RAND_F_RAND_WRITE_FILE, 0), "RAND_write_file"},
{0, NULL}
};
-static ERR_STRING_DATA RAND_str_reasons[] = {
- {ERR_REASON(RAND_R_DUAL_EC_DRBG_DISABLED), "dual ec drbg disabled"},
- {ERR_REASON(RAND_R_ERROR_INITIALISING_DRBG), "error initialising drbg"},
- {ERR_REASON(RAND_R_ERROR_INSTANTIATING_DRBG), "error instantiating drbg"},
- {ERR_REASON(RAND_R_NO_FIPS_RANDOM_METHOD_SET),
- "no fips random method set"},
- {ERR_REASON(RAND_R_PRNG_NOT_SEEDED), "PRNG not seeded"},
+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
-void ERR_load_RAND_strings(void)
+int ERR_load_RAND_strings(void)
{
#ifndef OPENSSL_NO_ERR
-
if (ERR_func_error_string(RAND_str_functs[0].error) == NULL) {
- ERR_load_strings(0, RAND_str_functs);
- ERR_load_strings(0, RAND_str_reasons);
+ ERR_load_strings_const(RAND_str_functs);
+ ERR_load_strings_const(RAND_str_reasons);
}
#endif
+ return 1;
}
diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h
index f9fda3eb89c9..94ffc96f20e2 100755
--- a/crypto/rand/rand_lcl.h
+++ b/crypto/rand/rand_lcl.h
@@ -1,158 +1,258 @@
-/* crypto/rand/rand_lcl.h */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
+/*
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
+ * 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
*/
-/* ====================================================================
- * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
+
+#ifndef HEADER_RAND_LCL_H
+# define HEADER_RAND_LCL_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>
+
+/* 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 */
+
+
+
+/* Max size of additional input and personalization string. */
+# define DRBG_MAX_LENGTH 4096
+
+/*
+ * The quotient between max_{entropy,nonce}len and min_{entropy,nonce}len
*
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
+ * The current factor is large enough that the RAND_POOL can store a
+ * random input which has a lousy entropy rate of 0.0625 bits per byte.
+ * This input will be sent through the derivation function which 'compresses'
+ * the low quality input into a high quality output.
+ */
+# define DRBG_MINMAX_FACTOR 128
+
+
+/* DRBG status values */
+typedef enum drbg_status_e {
+ DRBG_UNINITIALISED,
+ DRBG_READY,
+ DRBG_ERROR
+} DRBG_STATUS;
+
+
+/* intantiate */
+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);
+/* generat 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 */
-#ifndef HEADER_RAND_LCL_H
-# define HEADER_RAND_LCL_H
+ size_t min_len; /* minimum number of random bytes requested */
+ size_t max_len; /* maximum number of random bytes (allocated buffer size) */
+ size_t entropy; /* current entropy count in bits */
+ size_t requested_entropy; /* requested entropy count in bits */
+};
-# define ENTROPY_NEEDED 32 /* require 256 bits = 32 bytes of randomness */
-
-# if !defined(USE_MD5_RAND) && !defined(USE_SHA1_RAND) && !defined(USE_MDC2_RAND) && !defined(USE_MD2_RAND)
-# if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1)
-# define USE_SHA1_RAND
-# elif !defined(OPENSSL_NO_MD5)
-# define USE_MD5_RAND
-# elif !defined(OPENSSL_NO_MDC2) && !defined(OPENSSL_NO_DES)
-# define USE_MDC2_RAND
-# elif !defined(OPENSSL_NO_MD2)
-# define USE_MD2_RAND
-# else
-# error No message digest algorithm available
-# endif
-# endif
+/*
+ * 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 value of the rand_fork_count global as of when we last
+ * reseeded. The DRG reseeds automatically whenever drbg->fork_count !=
+ * rand_fork_count. Used to provide fork-safety and reseed this DRBG in
+ * the child process.
+ */
+ int fork_count;
+ unsigned short flags; /* various external flags */
-# include <openssl/evp.h>
-# define MD_Update(a,b,c) EVP_DigestUpdate(a,b,c)
-# define MD_Final(a,b) EVP_DigestFinal_ex(a,b,NULL)
-# if defined(USE_MD5_RAND)
-# include <openssl/md5.h>
-# define MD_DIGEST_LENGTH MD5_DIGEST_LENGTH
-# define MD_Init(a) EVP_DigestInit_ex(a,EVP_md5(), NULL)
-# define MD(a,b,c) EVP_Digest(a,b,c,NULL,EVP_md5(), NULL)
-# elif defined(USE_SHA1_RAND)
-# include <openssl/sha.h>
-# define MD_DIGEST_LENGTH SHA_DIGEST_LENGTH
-# define MD_Init(a) EVP_DigestInit_ex(a,EVP_sha1(), NULL)
-# define MD(a,b,c) EVP_Digest(a,b,c,NULL,EVP_sha1(), NULL)
-# elif defined(USE_MDC2_RAND)
-# include <openssl/mdc2.h>
-# define MD_DIGEST_LENGTH MDC2_DIGEST_LENGTH
-# define MD_Init(a) EVP_DigestInit_ex(a,EVP_mdc2(), NULL)
-# define MD(a,b,c) EVP_Digest(a,b,c,NULL,EVP_mdc2(), NULL)
-# elif defined(USE_MD2_RAND)
-# include <openssl/md2.h>
-# define MD_DIGEST_LENGTH MD2_DIGEST_LENGTH
-# define MD_Init(a) EVP_DigestInit_ex(a,EVP_md2(), NULL)
-# define MD(a,b,c) EVP_Digest(a,b,c,NULL,EVP_md2(), NULL)
-# endif
-
-int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo, int lock);
+ /*
+ * The random pool 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 *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 generate_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().
+ */
+ unsigned int reseed_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;
+
+/*
+ * A "generation count" of forks. Incremented in the child process after a
+ * fork. Since rand_fork_count is increment-only, and only ever written to in
+ * the child process of the fork, which is guaranteed to be single-threaded, no
+ * locking is needed for normal (read) accesses; the rest of pthread fork
+ * processing is assumed to introduce the necessary memory barriers. Sibling
+ * children of a given parent will produce duplicate values, but this is not
+ * problematic because the reseeding process pulls input from the system CSPRNG
+ * and/or other global sources, so the siblings will end up generating
+ * different output streams.
+ */
+extern int rand_fork_count;
+
+/* DRBG helpers */
+int rand_drbg_restart(RAND_DRBG *drbg,
+ const unsigned char *buffer, size_t len, size_t entropy);
+
+/* 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/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index 88a78d350656..e9bc9522101c 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -1,300 +1,799 @@
-/* crypto/rand/rand_lib.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+/*
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
+ * 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 "cryptlib.h"
-#include <openssl/rand.h>
+#include "internal/cryptlib.h"
+#include <openssl/opensslconf.h>
+#include "internal/rand_int.h"
+#include <openssl/engine.h>
+#include "internal/thread_once.h"
+#include "rand_lcl.h"
+#include "e_os.h"
#ifndef OPENSSL_NO_ENGINE
-# include <openssl/engine.h>
+/* 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;
-#ifdef OPENSSL_FIPS
-# include <openssl/fips.h>
-# include <openssl/fips_rand.h>
-# include "rand_lcl.h"
-#endif
+int rand_fork_count;
-#ifndef OPENSSL_NO_ENGINE
-/* non-NULL if default_RAND_meth is ENGINE-provided */
-static ENGINE *funct_ref = NULL;
-#endif
-static const RAND_METHOD *default_RAND_meth = NULL;
+static CRYPTO_RWLOCK *rand_nonce_lock;
+static int rand_nonce_count;
-int RAND_set_rand_method(const RAND_METHOD *meth)
+static int rand_cleaning_up = 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)
{
-#ifndef OPENSSL_NO_ENGINE
- if (funct_ref) {
- ENGINE_finish(funct_ref);
- funct_ref = NULL;
+ 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);
+ }
}
-#endif
- default_RAND_meth = meth;
- return 1;
+ return rand_pool_entropy_available(pool);
}
+#endif
-const RAND_METHOD *RAND_get_rand_method(void)
+#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)
{
- if (!default_RAND_meth) {
-#ifndef OPENSSL_NO_ENGINE
- ENGINE *e = ENGINE_get_default_RAND();
- if (e) {
- default_RAND_meth = ENGINE_get_RAND(e);
- if (!default_RAND_meth) {
- ENGINE_finish(e);
- e = NULL;
+ 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);
}
}
- if (e)
- funct_ref = e;
- else
-#endif
- default_RAND_meth = RAND_SSLeay();
}
- return default_RAND_meth;
+
+ return rand_pool_entropy_available(pool);
}
+#endif
-#ifndef OPENSSL_NO_ENGINE
-int RAND_set_rand_engine(ENGINE *engine)
+
+/*
+ * 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)
{
- const RAND_METHOD *tmp_meth = NULL;
- if (engine) {
- if (!ENGINE_init(engine))
- return 0;
- tmp_meth = ENGINE_get_RAND(engine);
- if (!tmp_meth) {
- ENGINE_finish(engine);
- return 0;
+ size_t ret = 0;
+ size_t entropy_available = 0;
+ RAND_POOL *pool;
+
+ if (drbg->parent && 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;
+ }
+
+ pool = rand_pool_new(entropy, min_len, max_len);
+ if (pool == NULL)
+ return 0;
+
+ if (drbg->pool) {
+ rand_pool_add(pool,
+ rand_pool_buffer(drbg->pool),
+ rand_pool_length(drbg->pool),
+ rand_pool_entropy(drbg->pool));
+ rand_pool_free(drbg->pool);
+ drbg->pool = NULL;
+ }
+
+ if (drbg->parent) {
+ 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 from parent, include our state as additional input.
+ * 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,
+ NULL, 0) != 0)
+ bytes = bytes_needed;
+ 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);
}
- /* This function releases any prior ENGINE so call it first */
- RAND_set_rand_method(tmp_meth);
- funct_ref = engine;
- return 1;
+
+ if (entropy_available > 0) {
+ ret = rand_pool_length(pool);
+ *pout = rand_pool_detach(pool);
+ }
+
+ err:
+ 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)
+{
+ OPENSSL_secure_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 = { 0 };
+
+ pool = rand_pool_new(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_secure_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(unsigned char **pout, size_t max_len)
+{
+ size_t ret = 0;
+ RAND_POOL *pool;
+
+ pool = rand_pool_new(0, 0, max_len);
+ if (pool == NULL)
+ return 0;
+
+ if (rand_pool_add_additional_data(pool) == 0)
+ goto err;
+
+ ret = rand_pool_length(pool);
+ *pout = rand_pool_detach(pool);
+
+ err:
+ rand_pool_free(pool);
+
+ return ret;
+}
+
+void rand_drbg_cleanup_additional_data(unsigned char *out, size_t outlen)
+{
+ OPENSSL_secure_clear_free(out, outlen);
+}
+
+void rand_fork(void)
+{
+ rand_fork_count++;
+}
+
+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
-void RAND_cleanup(void)
+ 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_cleaning_up && !rand_pool_init())
+ goto err3;
+
+ return 1;
+
+err3:
+ rand_pool_cleanup();
+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 = RAND_get_rand_method();
- if (meth && meth->cleanup)
+ const RAND_METHOD *meth = default_RAND_meth;
+
+ rand_cleaning_up = 1;
+
+ 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;
}
-void RAND_seed(const void *buf, int num)
+/*
+ * RAND_close_seed_files() ensures that any seed file decriptors are
+ * closed after use.
+ */
+void RAND_keep_random_devices_open(int keep)
{
- const RAND_METHOD *meth = RAND_get_rand_method();
- if (meth && meth->seed)
- meth->seed(buf, num);
+ rand_pool_keep_random_devices_open(keep);
}
-void RAND_add(const void *buf, int num, double entropy)
+/*
+ * 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 && meth->add)
- meth->add(buf, num, entropy);
+
+ 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,
+ RAND_DRBG_STRENGTH / 8,
+ DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8));
+ 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;
}
-int RAND_bytes(unsigned char *buf, int num)
+/*
+ * Allocate memory and initialize a new random pool
+ */
+
+RAND_POOL *rand_pool_new(int entropy, size_t min_len, size_t max_len)
{
- const RAND_METHOD *meth = RAND_get_rand_method();
- if (meth && meth->bytes)
- return meth->bytes(buf, num);
- return (-1);
+ RAND_POOL *pool = OPENSSL_zalloc(sizeof(*pool));
+
+ if (pool == NULL) {
+ RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ pool->min_len = min_len;
+ pool->max_len = max_len;
+
+ pool->buffer = OPENSSL_secure_zalloc(pool->max_len);
+ if (pool->buffer == NULL) {
+ RANDerr(RAND_F_RAND_POOL_NEW, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ pool->requested_entropy = entropy;
+
+ return pool;
+
+err:
+ OPENSSL_free(pool);
+ return NULL;
}
-int RAND_pseudo_bytes(unsigned char *buf, int num)
+/*
+ * Free |pool|, securely erasing its buffer.
+ */
+void rand_pool_free(RAND_POOL *pool)
{
- const RAND_METHOD *meth = RAND_get_rand_method();
- if (meth && meth->pseudorand)
- return meth->pseudorand(buf, num);
- return (-1);
+ if (pool == NULL)
+ return;
+
+ OPENSSL_secure_clear_free(pool->buffer, pool->max_len);
+ OPENSSL_free(pool);
}
-int RAND_status(void)
+/*
+ * Return the |pool|'s buffer to the caller (readonly).
+ */
+const unsigned char *rand_pool_buffer(RAND_POOL *pool)
{
- const RAND_METHOD *meth = RAND_get_rand_method();
- if (meth && meth->status)
- return meth->status();
- return 0;
+ return pool->buffer;
}
-#ifdef OPENSSL_FIPS
+/*
+ * Return the |pool|'s entropy to the caller.
+ */
+size_t rand_pool_entropy(RAND_POOL *pool)
+{
+ return pool->entropy;
+}
/*
- * FIPS DRBG initialisation code. This sets up the DRBG for use by the rest
- * of OpenSSL.
+ * Return the |pool|'s buffer length to the caller.
*/
+size_t rand_pool_length(RAND_POOL *pool)
+{
+ return pool->len;
+}
/*
- * Entropy gatherer: use standard OpenSSL PRNG to seed (this will gather
- * entropy internally through RAND_poll().
+ * 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().
*/
+unsigned char *rand_pool_detach(RAND_POOL *pool)
+{
+ unsigned char *ret = pool->buffer;
+ pool->buffer = NULL;
+ return ret;
+}
+
+
+/*
+ * 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)
+
-static size_t drbg_get_entropy(DRBG_CTX *ctx, unsigned char **pout,
- int entropy, size_t min_len, size_t max_len)
+/*
+ * 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)
{
- /* Round up request to multiple of block size */
- min_len = ((min_len + 19) / 20) * 20;
- *pout = OPENSSL_malloc(min_len);
- if (!*pout)
+ if (pool->entropy < pool->requested_entropy)
return 0;
- if (ssleay_rand_bytes(*pout, min_len, 0, 0) <= 0) {
- OPENSSL_free(*pout);
- *pout = NULL;
+
+ if (pool->len < pool->min_len)
return 0;
- }
- return min_len;
-}
-static void drbg_free_entropy(DRBG_CTX *ctx, unsigned char *out, size_t olen)
-{
- if (out) {
- OPENSSL_cleanse(out, olen);
- OPENSSL_free(out);
- }
+ return pool->entropy;
}
/*
- * Set "additional input" when generating random data. This uses the current
- * PID, a time value and a counter.
+ * Returns the (remaining) amount of entropy needed to fill
+ * the random pool.
*/
-static size_t drbg_get_adin(DRBG_CTX *ctx, unsigned char **pout)
+size_t rand_pool_entropy_needed(RAND_POOL *pool)
{
- /* Use of static variables is OK as this happens under a lock */
- static unsigned char buf[16];
- static unsigned long counter;
- FIPS_get_timevec(buf, &counter);
- *pout = buf;
- return sizeof(buf);
+ if (pool->entropy < pool->requested_entropy)
+ return pool->requested_entropy - pool->entropy;
+
+ return 0;
}
/*
- * RAND_add() and RAND_seed() pass through to OpenSSL PRNG so it is
- * correctly seeded by RAND_poll().
+ * 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.
*/
-static int drbg_rand_add(DRBG_CTX *ctx, const void *in, int inlen,
- double entropy)
+size_t rand_pool_bytes_needed(RAND_POOL *pool, unsigned int entropy_factor)
{
- RAND_SSLeay()->add(in, inlen, entropy);
- return 1;
+ 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;
+
+ return bytes_needed;
}
-static int drbg_rand_seed(DRBG_CTX *ctx, const void *in, int inlen)
+/* Returns the remaining number of bytes available */
+size_t rand_pool_bytes_remaining(RAND_POOL *pool)
{
- RAND_SSLeay()->seed(in, inlen);
- return 1;
+ return pool->max_len - pool->len;
}
-# ifndef OPENSSL_DRBG_DEFAULT_TYPE
-# define OPENSSL_DRBG_DEFAULT_TYPE NID_aes_256_ctr
-# endif
-# ifndef OPENSSL_DRBG_DEFAULT_FLAGS
-# define OPENSSL_DRBG_DEFAULT_FLAGS DRBG_FLAG_CTR_USE_DF
-# endif
+/*
+ * 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 (len > 0) {
+ memcpy(pool->buffer + pool->len, buffer, len);
+ pool->len += len;
+ pool->entropy += entropy;
+ }
-static int fips_drbg_type = OPENSSL_DRBG_DEFAULT_TYPE;
-static int fips_drbg_flags = OPENSSL_DRBG_DEFAULT_FLAGS;
+ return 1;
+}
-void RAND_set_fips_drbg_type(int type, int flags)
+/*
+ * 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 udpate operation (see next comment).
+ */
+unsigned char *rand_pool_add_begin(RAND_POOL *pool, size_t len)
{
- fips_drbg_type = type;
- fips_drbg_flags = flags;
+ 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;
+ }
+
+ return pool->buffer + pool->len;
}
-int RAND_init_fips(void)
+/*
+ * 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)
{
- DRBG_CTX *dctx;
- size_t plen;
- unsigned char pers[32], *p;
-# ifndef OPENSSL_ALLOW_DUAL_EC_DRBG
- if (fips_drbg_type >> 16) {
- RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_DUAL_EC_DRBG_DISABLED);
+ if (len > pool->max_len - pool->len) {
+ RANDerr(RAND_F_RAND_POOL_ADD_END, RAND_R_RANDOM_POOL_OVERFLOW);
return 0;
}
-# endif
- dctx = FIPS_get_default_drbg();
- if (FIPS_drbg_init(dctx, fips_drbg_type, fips_drbg_flags) <= 0) {
- RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INITIALISING_DRBG);
+ 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;
- FIPS_drbg_set_callbacks(dctx,
- drbg_get_entropy, drbg_free_entropy, 20,
- drbg_get_entropy, drbg_free_entropy);
- FIPS_drbg_set_rand_callbacks(dctx, drbg_get_adin, 0,
- drbg_rand_seed, drbg_rand_add);
- /* Personalisation string: a string followed by date time vector */
- strcpy((char *)pers, "OpenSSL DRBG2.0");
- plen = drbg_get_adin(dctx, &p);
- memcpy(pers + 16, p, plen);
-
- if (FIPS_drbg_instantiate(dctx, pers, sizeof(pers)) <= 0) {
- RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INSTANTIATING_DRBG);
+ 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;
+ }
}
- FIPS_rand_set_method(FIPS_drbg_method());
+ 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->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->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;
+ int ret;
+
+ if (meth != RAND_OpenSSL())
+ return RAND_bytes(buf, num);
+
+ drbg = RAND_DRBG_get0_private();
+ if (drbg == NULL)
+ return 0;
+
+ ret = RAND_DRBG_bytes(drbg, buf, num);
+ return ret;
+}
+
+int RAND_bytes(unsigned char *buf, int num)
+{
+ const RAND_METHOD *meth = RAND_get_rand_method();
+
+ if (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->pseudorand != NULL)
+ return meth->pseudorand(buf, num);
+ return -1;
+}
#endif
+
+int RAND_status(void)
+{
+ const RAND_METHOD *meth = RAND_get_rand_method();
+
+ if (meth->status != NULL)
+ return meth->status();
+ return 0;
+}
diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c
index 097e4099181a..9c62a04ebf89 100644
--- a/crypto/rand/rand_unix.c
+++ b/crypto/rand/rand_unix.c
@@ -1,198 +1,138 @@
-/* crypto/rand/rand_unix.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
+/*
+ * Copyright 1995-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 <stdio.h>
-#define USE_SOCKETS
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include "e_os.h"
-#include "cryptlib.h"
+#include <stdio.h>
+#include "internal/cryptlib.h"
#include <openssl/rand.h>
#include "rand_lcl.h"
+#include "internal/rand_int.h"
+#include <stdio.h>
+#include "internal/dso.h"
+#if defined(__linux)
+# include <sys/syscall.h>
+#endif
+#if defined(__FreeBSD__)
+# 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_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE))
-
+#if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__)
# include <sys/types.h>
-# include <sys/time.h>
-# include <sys/times.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
-# include <time.h>
-# if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually
- * everywhere */
-# include <poll.h>
-# endif
-# include <limits.h>
-# ifndef FD_SETSIZE
-# define FD_SETSIZE (8*sizeof(fd_set))
+# 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(__DJGPP__) */
+
+#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_WINDOWS) || defined(OPENSSL_SYS_WIN32) \
+ || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \
+ || defined(OPENSSL_SYS_UEFI))
+
+static ssize_t syscall_random(void *buf, size_t buflen);
# 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 this code 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.
+ * 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 generate 4 times the minimum required amount of seed
- * data.
+ * As a precaution, we assume only 2 bits of entropy per byte.
*/
-
-int RAND_poll(void)
+size_t rand_pool_acquire_entropy(RAND_POOL *pool)
{
short int code;
- gid_t curr_gid;
- pid_t curr_pid;
- uid_t curr_uid;
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
-# ifdef OPENSSL_SYS_VOS_IA32
long long duration;
extern void s$sleep2(long long *_duration, short int *_code);
-# else
-# error "Unsupported Platform."
-# endif /* OPENSSL_SYS_VOS_IA32 */
-# endif /* OPENSSL_SYS_VOS_HPPA */
-
- /*
- * Seed with the gid, pid, and uid, to ensure *some* variation between
- * different processes.
- */
-
- curr_gid = getgid();
- RAND_add(&curr_gid, sizeof(curr_gid), 1);
- curr_gid = 0;
-
- curr_pid = getpid();
- RAND_add(&curr_pid, sizeof(curr_pid), 1);
- curr_pid = 0;
+# endif
- curr_uid = getuid();
- RAND_add(&curr_uid, sizeof(curr_uid), 1);
- curr_uid = 0;
+ bytes_needed = rand_pool_bytes_needed(pool, 4 /*entropy_factor*/);
- for (i = 0; i < (ENTROPY_NEEDED * 4); i++) {
+ for (i = 0; i < bytes_needed; i++) {
/*
* burn some cpu; hope for interrupts, cache collisions, bus
* interference, etc.
@@ -205,243 +145,544 @@ int RAND_poll(void)
duration = 1;
s$sleep(&duration, &code);
# else
-# ifdef OPENSSL_SYS_VOS_IA32
/* sleep for 1/65536 of a second (15 us). */
duration = 1;
s$sleep2(&duration, &code);
-# endif /* OPENSSL_SYS_VOS_IA32 */
-# endif /* OPENSSL_SYS_VOS_HPPA */
+# endif
- /* get wall clock time. */
+ /* Get wall clock time, take 8 bits. */
clock_gettime(CLOCK_REALTIME, &ts);
-
- /* take 8 bits */
- v = (unsigned char)(ts.tv_nsec % 256);
- RAND_add(&v, sizeof(v), 1);
- v = 0;
+ v = (unsigned char)(ts.tv_nsec & 0xFF);
+ rand_pool_add(pool, arg, &v, sizeof(v) , 2);
}
- return 1;
+ return rand_pool_entropy_available(pool);
}
-# elif defined __OpenBSD__
-int RAND_poll(void)
-{
- u_int32_t rnd = 0, i;
- unsigned char buf[ENTROPY_NEEDED];
-
- for (i = 0; i < sizeof(buf); i++) {
- if (i % 4 == 0)
- rnd = arc4random();
- buf[i] = rnd;
- rnd >>= 8;
- }
- RAND_add(buf, sizeof(buf), ENTROPY_NEEDED);
- OPENSSL_cleanse(buf, sizeof(buf));
- return 1;
+void rand_pool_cleanup(void)
+{
}
-# else /* !defined(__OpenBSD__) */
-int RAND_poll(void)
+
+void rand_pool_keep_random_devices_open(int keep)
{
- unsigned long l;
- pid_t curr_pid = getpid();
-# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
- unsigned char tmpbuf[ENTROPY_NEEDED];
- int n = 0;
+}
+
+# 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
-# ifdef DEVRANDOM
- static const char *randomfiles[] = { DEVRANDOM };
- struct stat randomstats[sizeof(randomfiles) / sizeof(randomfiles[0])];
- int fd;
- unsigned int i;
+
+# 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
-# ifdef DEVRANDOM_EGD
- static const char *egdsockets[] = { DEVRANDOM_EGD, NULL };
- const char **egdsocket = NULL;
+
+# if defined(OPENSSL_RAND_SEED_LIBRANDOM)
+# error "librandom not (yet) supported"
# endif
-# ifdef DEVRANDOM
- memset(randomstats, 0, sizeof(randomstats));
+# 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;
+
/*
- * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have
- * this. Use /dev/urandom if you can as /dev/random may block if it runs
- * out of random entries.
+ * Note: sign conversion between size_t and ssize_t is safe even
+ * without a range check, see comment in syscall_random()
*/
- for (i = 0; (i < sizeof(randomfiles) / sizeof(randomfiles[0])) &&
- (n < ENTROPY_NEEDED); i++) {
- if ((fd = open(randomfiles[i], O_RDONLY
-# ifdef O_NONBLOCK
- | O_NONBLOCK
-# endif
-# ifdef O_BINARY
- | O_BINARY
+ /*
+ * 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
+
+/*
+ * 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 * DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^13
+ *
+ * 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(SYS_getrandom)
+ return syscall(SYS_getrandom, buf, buflen, 0);
+# elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND)
+ return sysctl_random(buf, buflen);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+
+#if !defined(OPENSSL_RAND_SEED_NONE) && 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;
+
+/*
+ * 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;
+}
+
+static void open_random_devices(void)
+{
+ size_t i;
+
+ for (i = 0; i < OSSL_NELEM(random_devices); i++)
+ (void)get_random_device(i);
+}
+
+int rand_pool_init(void)
+{
+ size_t i;
+
+ for (i = 0; i < OSSL_NELEM(random_devices); i++)
+ random_devices[i].fd = -1;
+ open_random_devices();
+ 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)
+ open_random_devices();
+ else
+ rand_pool_cleanup();
+ keep_random_devices_open = keep;
+}
+
+# else /* defined(OPENSSL_RAND_SEED_NONE)
+ * || !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_NONE)
+ * && 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)
+{
+# ifdef OPENSSL_RAND_SEED_NONE
+ return rand_pool_entropy_available(pool);
+# else
+ size_t bytes_needed;
+ size_t entropy_available = 0;
+ unsigned char *buffer;
+
+# ifdef OPENSSL_RAND_SEED_GETRANDOM
+ {
+ 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
-# ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do
- * not make it our controlling tty */
- | O_NOCTTY
+
+# if defined(OPENSSL_RAND_SEED_LIBRANDOM)
+ {
+ /* Not yet implemented. */
+ }
# endif
- )) >= 0) {
- int usec = 10 * 1000; /* spend 10ms on each file */
- int r;
- unsigned int j;
- struct stat *st = &randomstats[i];
-
- /*
- * Avoid using same input... Used to be O_NOFOLLOW above, but
- * it's not universally appropriate...
- */
- if (fstat(fd, st) != 0) {
- close(fd);
+
+# ifdef OPENSSL_RAND_SEED_DEVRANDOM
+ bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+ {
+ size_t i;
+
+ for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); i++) {
+ ssize_t bytes = 0;
+ /* Maximum allowed number of consecutive unsuccessful attempts */
+ int attempts = 3;
+ const int fd = get_random_device(i);
+
+ if (fd == -1)
continue;
- }
- for (j = 0; j < i; j++) {
- if (randomstats[j].st_ino == st->st_ino &&
- randomstats[j].st_dev == st->st_dev)
+
+ 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 after successful attempt */
+ } else if (bytes < 0 && errno != EINTR) {
break;
+ }
}
- if (j < i) {
- close(fd);
- continue;
- }
+ if (bytes < 0 || !keep_random_devices_open)
+ close_random_device(i);
- do {
- int try_read = 0;
-
-# if defined(OPENSSL_SYS_BEOS_R5)
- /*
- * select() is broken in BeOS R5, so we simply try to read
- * something and snooze if we couldn't
- */
- try_read = 1;
-
-# elif defined(OPENSSL_SYS_LINUX)
- /* use poll() */
- struct pollfd pset;
-
- pset.fd = fd;
- pset.events = POLLIN;
- pset.revents = 0;
-
- if (poll(&pset, 1, usec / 1000) < 0)
- usec = 0;
- else
- try_read = (pset.revents & POLLIN) != 0;
-
-# else
- /* use select() */
- fd_set fset;
- struct timeval t;
-
- t.tv_sec = 0;
- t.tv_usec = usec;
-
- if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) {
- /*
- * can't use select, so just try to read once anyway
- */
- try_read = 1;
- } else {
- FD_ZERO(&fset);
- FD_SET(fd, &fset);
-
- if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) {
- usec = t.tv_usec;
- if (FD_ISSET(fd, &fset))
- try_read = 1;
- } else
- usec = 0;
- }
+ bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+ }
+ entropy_available = rand_pool_entropy_available(pool);
+ if (entropy_available > 0)
+ return entropy_available;
+ }
# endif
- if (try_read) {
- r = read(fd, (unsigned char *)tmpbuf + n,
- ENTROPY_NEEDED - n);
- if (r > 0)
- n += r;
-# if defined(OPENSSL_SYS_BEOS_R5)
- if (r == 0)
- snooze(t.tv_usec);
+# ifdef OPENSSL_RAND_SEED_RDTSC
+ entropy_available = rand_acquire_entropy_from_tsc(pool);
+ if (entropy_available > 0)
+ return entropy_available;
# endif
- } else
- r = -1;
-
- /*
- * Some Unixen will update t in select(), some won't. For
- * those who won't, or if we didn't use select() in the first
- * place, give up here, otherwise, we will do this once again
- * for the remaining time.
- */
- if (usec == 10 * 1000)
- usec = 0;
- }
- while ((r > 0 ||
- (errno == EINTR || errno == EAGAIN)) && usec != 0
- && n < ENTROPY_NEEDED);
- close(fd);
+# ifdef OPENSSL_RAND_SEED_RDCPU
+ entropy_available = rand_acquire_entropy_from_cpu(pool);
+ if (entropy_available > 0)
+ return entropy_available;
+# endif
+
+# ifdef OPENSSL_RAND_SEED_EGD
+ bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+ if (bytes_needed > 0) {
+ static const char *paths[] = { DEVRANDOM_EGD, NULL };
+ int i;
+
+ for (i = 0; paths[i] != NULL; i++) {
+ buffer = rand_pool_add_begin(pool, bytes_needed);
+ if (buffer != NULL) {
+ size_t bytes = 0;
+ int 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);
+ entropy_available = rand_pool_entropy_available(pool);
+ }
+ if (entropy_available > 0)
+ return entropy_available;
}
}
-# endif /* defined(DEVRANDOM) */
+# 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 };
-# ifdef DEVRANDOM_EGD
/*
- * Use an EGD socket to read entropy from an EGD or PRNGD entropy
- * collecting daemon.
+ * Add process id, thread id, and a high resolution timestamp to
+ * ensure that the nonce is unique whith high probability for
+ * different process instances.
*/
+ data.pid = getpid();
+ data.tid = CRYPTO_THREAD_get_current_id();
+ data.time = get_time_stamp();
- for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED;
- egdsocket++) {
- int r;
+ return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
+}
+
+int rand_pool_add_additional_data(RAND_POOL *pool)
+{
+ struct {
+ CRYPTO_THREAD_ID tid;
+ uint64_t time;
+ } data = { 0 };
- r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n,
- ENTROPY_NEEDED - n);
- if (r > 0)
- n += r;
+ /*
+ * 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();
+ 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 /* defined(DEVRANDOM_EGD) */
+# endif
+# if defined(__unix__) \
+ || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)
+ {
+ struct timeval tv;
-# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
- if (n > 0) {
- RAND_add(tmpbuf, sizeof(tmpbuf), (double)n);
- OPENSSL_cleanse(tmpbuf, n);
+ if (gettimeofday(&tv, NULL) == 0)
+ return TWO32TO64(tv.tv_sec, tv.tv_usec);
}
-# endif
+# endif
+ return time(NULL);
+}
- /* put in some default random data, we need more than just this */
- l = curr_pid;
- RAND_add(&l, sizeof(l), 0.0);
- l = getuid();
- RAND_add(&l, sizeof(l), 0.0);
+/*
+ * 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();
- l = time(NULL);
- RAND_add(&l, sizeof(l), 0.0);
+ if (res != 0)
+ return res;
-# if defined(OPENSSL_SYS_BEOS)
+# if defined(__sun) || defined(__hpux)
+ return gethrtime();
+# elif defined(_AIX)
{
- system_info sysInfo;
- get_system_info(&sysInfo);
- RAND_add(&sysInfo, sizeof(sysInfo), 0);
+ timebasestruct_t t;
+
+ read_wall_time(&t, TIMEBASE_SZ);
+ return TWO32TO64(t.tb_high, t.tb_low);
}
-# endif
+# elif defined(OSSL_POSIX_TIMER_OKAY)
+ {
+ struct timespec ts;
-# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
- return 1;
+# ifdef CLOCK_BOOTTIME
+# define CLOCK_TYPE CLOCK_BOOTTIME
+# elif defined(_POSIX_MONOTONIC_CLOCK)
+# define CLOCK_TYPE CLOCK_MONOTONIC
# else
- return 0;
+# define CLOCK_TYPE CLOCK_REALTIME
# endif
-}
-# endif /* defined(__OpenBSD__) */
-#endif /* !(defined(OPENSSL_SYS_WINDOWS) ||
- * defined(OPENSSL_SYS_WIN32) ||
- * defined(OPENSSL_SYS_VMS) ||
- * defined(OPENSSL_SYS_OS2) ||
- * defined(OPENSSL_SYS_VXWORKS) ||
- * defined(OPENSSL_SYS_NETWARE)) */
+ 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 defined(OPENSSL_SYS_VXWORKS)
-int RAND_poll(void)
-{
- return 0;
+ if (gettimeofday(&tv, NULL) == 0)
+ return TWO32TO64(tv.tv_sec, tv.tv_usec);
+ }
+# endif
+ return time(NULL);
}
-#endif
+#endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */
diff --git a/crypto/rand/randfile.c b/crypto/rand/randfile.c
index 728fd0a721b5..c652ddcf1e6c 100644
--- a/crypto/rand/randfile.c
+++ b/crypto/rand/randfile.c
@@ -1,67 +1,19 @@
-/* crypto/rand/randfile.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+/*
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
+ * 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 "e_os.h"
#include <openssl/crypto.h>
#include <openssl/rand.h>
#include <openssl/buffer.h>
@@ -69,12 +21,22 @@
#ifdef OPENSSL_SYS_VMS
# include <unixio.h>
#endif
-#ifndef NO_SYS_TYPES_H
-# include <sys/types.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
@@ -82,176 +44,134 @@
* would look like ((m) & MASK == TYPE), but since MASK availability
* is as questionable, we settle for this poor-man fallback...
*/
-# if !defined(S_ISBLK)
-# if defined(_S_IFBLK)
-# define S_ISBLK(m) ((m) & _S_IFBLK)
-# elif defined(S_IFBLK)
-# define S_ISBLK(m) ((m) & S_IFBLK)
-# elif defined(_WIN32)
-# define S_ISBLK(m) 0 /* no concept of block devices on Windows */
-# endif
-# endif
-# if !defined(S_ISCHR)
-# if defined(_S_IFCHR)
-# define S_ISCHR(m) ((m) & _S_IFCHR)
-# elif defined(S_IFCHR)
-# define S_ISCHR(m) ((m) & S_IFCHR)
-# endif
+# if !defined(S_ISREG)
+# define S_ISREG(m) ((m) & S_IFREG)
# endif
-#endif
-
-#ifdef _WIN32
-# define stat _stat
-# define chmod _chmod
-# define open _open
-# define fdopen _fdopen
-#endif
-#undef BUFSIZE
-#define BUFSIZE 1024
-#define RAND_DATA 1024
+#define RAND_FILE_SIZE 1024
+#define RFILE ".rnd"
-#if (defined(OPENSSL_SYS_VMS) && (defined(__alpha) || defined(__ia64)))
+#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 our /STANDARD=ANSI89
+ * passing in sharing options being disabled by /STANDARD=ANSI89
*/
-static FILE *(*const vms_fopen)(const char *, const char *, ...) =
- (FILE *(*)(const char *, const char *, ...))fopen;
-# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
+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
-/* #define RFILE ".rnd" - defined in ../../e_os.h */
-
/*
* Note that these functions are intended for seed files only. Entropy
- * devices and EGD sockets are handled in rand_unix.c
+ * 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)
{
- /*-
- * If bytes >= 0, read up to 'bytes' bytes.
- * if bytes == -1, read complete file.
- */
-
- MS_STATIC unsigned char buf[BUFSIZE];
+ unsigned char buf[RAND_FILE_SIZE];
#ifndef OPENSSL_NO_POSIX_IO
struct stat sb;
#endif
- int i, ret = 0, n;
-/*
- * If setvbuf() is to be called, then the FILE pointer
- * to it must be 32 bit.
-*/
-
-#if !defined OPENSSL_NO_SETVBUF_IONBF && defined(OPENSSL_SYS_VMS) && defined(__VMS_VER) && (__VMS_VER >= 70000000)
- /* For 64-bit-->32 bit API Support*/
-#if __INITIAL_POINTER_SIZE == 64
-#pragma __required_pointer_size __save
-#pragma __required_pointer_size 32
-#endif
- FILE *in; /* setvbuf() requires 32-bit pointers */
-#if __INITIAL_POINTER_SIZE == 64
-#pragma __required_pointer_size __restore
-#endif
-#else
+ int i, n, ret = 0;
FILE *in;
-#endif /* OPENSSL_SYS_VMS */
- if (file == NULL)
- return (0);
+ 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
-# ifdef PURIFY
+ 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 (!S_ISREG(sb.st_mode) && bytes < 0)
+ bytes = 256;
+#endif
/*
- * struct stat can have padding and unused fields that may not be
- * initialized in the call to stat(). We need to clear the entire
- * structure before calling RAND_add() to avoid complaints from
- * applications such as Valgrind.
+ * 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.
*/
- memset(&sb, 0, sizeof(sb));
-# endif
- if (stat(file, &sb) < 0)
- return (0);
- RAND_add(&sb, sizeof(sb), 0.0);
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma environment save
+# pragma message disable maylosedata2
#endif
- if (bytes == 0)
- return (ret);
-
-#ifdef OPENSSL_SYS_VMS
- in = vms_fopen(file, "rb", VMS_OPEN_ATTRS);
-#else
- in = fopen(file, "rb");
-#endif
- if (in == NULL)
- goto err;
-#if defined(S_ISBLK) && defined(S_ISCHR) && !defined(OPENSSL_NO_POSIX_IO)
- if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
- /*
- * this file is a device. we don't want read an infinite number of
- * bytes from a random device, nor do we want to use buffered I/O
- * because we will waste system entropy.
- */
- bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
-# ifndef OPENSSL_NO_SETVBUF_IONBF
- setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */
-# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */
- }
+ /*
+ * 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 (;;) {
+
+ for ( ; ; ) {
if (bytes > 0)
- n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE;
+ n = (bytes < RAND_FILE_SIZE) ? (int)bytes : RAND_FILE_SIZE;
else
- n = BUFSIZE;
+ n = RAND_FILE_SIZE;
i = fread(buf, 1, n, in);
- if (i <= 0)
+#ifdef EINTR
+ if (ferror(in) && errno == EINTR){
+ clearerr(in);
+ if (i == 0)
+ continue;
+ }
+#endif
+ if (i == 0)
break;
-#ifdef PURIFY
+
RAND_add(buf, i, (double)i);
-#else
- /* even if n != i, use the full array */
- RAND_add(buf, n, (double)i);
-#endif
ret += i;
- if (bytes > 0) {
- bytes -= n;
- if (bytes <= 0)
- break;
- }
+
+ /* If given a bytecount, and we did it, break. */
+ if (bytes > 0 && (bytes -= i) <= 0)
+ break;
}
+
+ OPENSSL_cleanse(buf, sizeof(buf));
fclose(in);
- OPENSSL_cleanse(buf, BUFSIZE);
- err:
- return (ret);
+ return ret;
}
int RAND_write_file(const char *file)
{
- unsigned char buf[BUFSIZE];
- int i, ret = 0, rand_err = 0;
+ unsigned char buf[RAND_FILE_SIZE];
+ int ret = -1;
FILE *out = NULL;
- int n;
#ifndef OPENSSL_NO_POSIX_IO
struct stat sb;
- i = stat(file, &sb);
- if (i != -1) {
-# if defined(S_ISBLK) && defined(S_ISCHR)
- if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
- /*
- * this file is a device. we don't write back to it. we
- * "succeed" on the assumption this is some sort of random
- * device. Otherwise attempting to write to and chmod the device
- * causes problems.
- */
- return (1);
- }
-# endif
+ 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
-#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS)
+ /* 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
@@ -266,7 +186,7 @@ int RAND_write_file(const char *file)
}
#endif
-#if (defined(OPENSSL_SYS_VMS) && (defined(__alpha) || defined(__ia64)))
+#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
@@ -284,89 +204,93 @@ int RAND_write_file(const char *file)
* application level. Also consider whether or not you NEED a persistent
* rand file in a concurrent use situation.
*/
-
- out = vms_fopen(file, "rb+", VMS_OPEN_ATTRS);
- if (out == NULL)
- out = vms_fopen(file, "wb", VMS_OPEN_ATTRS);
-#else
- if (out == NULL)
- out = fopen(file, "wb");
+ out = openssl_fopen(file, "rb+");
#endif
+
if (out == NULL)
- goto err;
+ 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;
+ }
-#ifndef NO_CHMOD
+#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
- n = RAND_DATA;
- for (;;) {
- i = (n > BUFSIZE) ? BUFSIZE : n;
- n -= BUFSIZE;
- if (RAND_bytes(buf, i) <= 0)
- rand_err = 1;
- i = fwrite(buf, 1, i, out);
- if (i <= 0) {
- ret = 0;
- break;
- }
- ret += i;
- if (n <= 0)
- break;
- }
+ ret = fwrite(buf, 1, RAND_FILE_SIZE, out);
fclose(out);
- OPENSSL_cleanse(buf, BUFSIZE);
- err:
- return (rand_err ? -1 : ret);
+ OPENSSL_cleanse(buf, RAND_FILE_SIZE);
+ return ret;
}
const char *RAND_file_name(char *buf, size_t size)
{
char *s = NULL;
-#ifdef __OpenBSD__
- struct stat sb;
+ size_t len;
+ int use_randfile = 1;
+
+#if defined(_WIN32) && defined(CP_UTF8)
+ 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 (OPENSSL_issetugid() != 0) {
+ use_randfile = 0;
+ } else if ((s = getenv("RANDFILE")) == NULL || *s == '\0') {
+ use_randfile = 0;
+ s = getenv("HOME");
+ }
#endif
- if (OPENSSL_issetugid() == 0)
- s = getenv("RANDFILE");
- if (s != NULL && *s && strlen(s) + 1 < size) {
- if (BUF_strlcpy(buf, s, size) >= size)
- return NULL;
- } else {
- if (OPENSSL_issetugid() == 0)
- s = getenv("HOME");
#ifdef DEFAULT_HOME
- if (s == NULL) {
- s = DEFAULT_HOME;
- }
+ if (!use_randfile && s == NULL)
+ s = DEFAULT_HOME;
#endif
- if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) {
- BUF_strlcpy(buf, s, size);
+ 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
- BUF_strlcat(buf, "/", size);
+ strcat(buf, "/");
#endif
- BUF_strlcat(buf, RFILE, size);
- } else
- buf[0] = '\0'; /* no file name */
+ strcat(buf, RFILE);
}
-#ifdef __OpenBSD__
- /*
- * given that all random loads just fail if the file can't be seen on a
- * stat, we stat the file we're returning, if it fails, use /dev/arandom
- * instead. this allows the user to use their own source for good random
- * data, but defaults to something hopefully decent if that isn't
- * available.
- */
-
- if (!buf[0])
- if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) {
- return (NULL);
- }
- if (stat(buf, &sb) == -1)
- if (BUF_strlcpy(buf, "/dev/arandom", size) >= size) {
- return (NULL);
- }
-#endif
- return (buf);
+ return buf;
}
diff --git a/crypto/rand/randtest.c b/crypto/rand/randtest.c
deleted file mode 100644
index 91bcac9906b2..000000000000
--- a/crypto/rand/randtest.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* crypto/rand/randtest.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <openssl/rand.h>
-
-#include "../e_os.h"
-
-/* some FIPS 140-1 random number test */
-/* some simple tests */
-
-int main(int argc, char **argv)
-{
- unsigned char buf[2500];
- int i, j, k, s, sign, nsign, err = 0;
- unsigned long n1;
- unsigned long n2[16];
- unsigned long runs[2][34];
- /*
- * double d;
- */
- long d;
-
- i = RAND_pseudo_bytes(buf, 2500);
- if (i < 0) {
- printf("init failed, the rand method is not properly installed\n");
- err++;
- goto err;
- }
-
- n1 = 0;
- for (i = 0; i < 16; i++)
- n2[i] = 0;
- for (i = 0; i < 34; i++)
- runs[0][i] = runs[1][i] = 0;
-
- /* test 1 and 2 */
- sign = 0;
- nsign = 0;
- for (i = 0; i < 2500; i++) {
- j = buf[i];
-
- n2[j & 0x0f]++;
- n2[(j >> 4) & 0x0f]++;
-
- for (k = 0; k < 8; k++) {
- s = (j & 0x01);
- if (s == sign)
- nsign++;
- else {
- if (nsign > 34)
- nsign = 34;
- if (nsign != 0) {
- runs[sign][nsign - 1]++;
- if (nsign > 6)
- runs[sign][5]++;
- }
- sign = s;
- nsign = 1;
- }
-
- if (s)
- n1++;
- j >>= 1;
- }
- }
- if (nsign > 34)
- nsign = 34;
- if (nsign != 0)
- runs[sign][nsign - 1]++;
-
- /* test 1 */
- if (!((9654 < n1) && (n1 < 10346))) {
- printf("test 1 failed, X=%lu\n", n1);
- err++;
- }
- printf("test 1 done\n");
-
- /* test 2 */
-#ifdef undef
- d = 0;
- for (i = 0; i < 16; i++)
- d += n2[i] * n2[i];
- d = d * 16.0 / 5000.0 - 5000.0;
- if (!((1.03 < d) && (d < 57.4))) {
- printf("test 2 failed, X=%.2f\n", d);
- err++;
- }
-#endif
- d = 0;
- for (i = 0; i < 16; i++)
- d += n2[i] * n2[i];
- d = (d * 8) / 25 - 500000;
- if (!((103 < d) && (d < 5740))) {
- printf("test 2 failed, X=%ld.%02ld\n", d / 100L, d % 100L);
- err++;
- }
- printf("test 2 done\n");
-
- /* test 3 */
- for (i = 0; i < 2; i++) {
- if (!((2267 < runs[i][0]) && (runs[i][0] < 2733))) {
- printf("test 3 failed, bit=%d run=%d num=%lu\n",
- i, 1, runs[i][0]);
- err++;
- }
- if (!((1079 < runs[i][1]) && (runs[i][1] < 1421))) {
- printf("test 3 failed, bit=%d run=%d num=%lu\n",
- i, 2, runs[i][1]);
- err++;
- }
- if (!((502 < runs[i][2]) && (runs[i][2] < 748))) {
- printf("test 3 failed, bit=%d run=%d num=%lu\n",
- i, 3, runs[i][2]);
- err++;
- }
- if (!((223 < runs[i][3]) && (runs[i][3] < 402))) {
- printf("test 3 failed, bit=%d run=%d num=%lu\n",
- i, 4, runs[i][3]);
- err++;
- }
- if (!((90 < runs[i][4]) && (runs[i][4] < 223))) {
- printf("test 3 failed, bit=%d run=%d num=%lu\n",
- i, 5, runs[i][4]);
- err++;
- }
- if (!((90 < runs[i][5]) && (runs[i][5] < 223))) {
- printf("test 3 failed, bit=%d run=%d num=%lu\n",
- i, 6, runs[i][5]);
- err++;
- }
- }
- printf("test 3 done\n");
-
- /* test 4 */
- if (runs[0][33] != 0) {
- printf("test 4 failed, bit=%d run=%d num=%lu\n", 0, 34, runs[0][33]);
- err++;
- }
- if (runs[1][33] != 0) {
- printf("test 4 failed, bit=%d run=%d num=%lu\n", 1, 34, runs[1][33]);
- err++;
- }
- printf("test 4 done\n");
- err:
- err = ((err) ? 1 : 0);
-#ifdef OPENSSL_SYS_NETWARE
- if (err)
- printf("ERROR: %d\n", err);
-#endif
- EXIT(err);
- return (err);
-}