Revert "Replace PostmasterRandom() with a stronger way of generating randomness."
authorHeikki Linnakangas <[email protected]>
Tue, 18 Oct 2016 13:28:23 +0000 (16:28 +0300)
committerHeikki Linnakangas <[email protected]>
Tue, 18 Oct 2016 13:28:23 +0000 (16:28 +0300)
This reverts commit 9e083fd4683294f41544e6d0d72f6e258ff3a77c. That was a
few bricks shy of a load:

* Query cancel stopped working
* Buildfarm member pademelon stopped working, because the box doesn't have
  /dev/urandom nor /dev/random.

This clearly needs some more discussion, and a quite different patch, so
revert for now.

contrib/pgcrypto/Makefile
contrib/pgcrypto/internal.c
contrib/pgcrypto/random.c [new file with mode: 0644]
src/backend/libpq/auth.c
src/backend/postmaster/postmaster.c
src/include/port.h
src/port/Makefile
src/port/pg_strong_random.c [deleted file]
src/tools/msvc/Mkvcbuild.pm

index 76c2f1aa17129e78e7ad422a4b618d710bd23fa3..805db7626b4ec519f5a2e41675d36513146f81ce 100644 (file)
@@ -1,7 +1,7 @@
 # contrib/pgcrypto/Makefile
 
 INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \
-       fortuna.c pgp-mpi-internal.c imath.c
+       fortuna.c random.c pgp-mpi-internal.c imath.c
 INT_TESTS = sha2
 
 OSSL_SRCS = openssl.c pgp-mpi-openssl.c
index ad942f733a2db4f45deb68507ce3a932ca1f00ec..02ff976c25a6e89c929208ececccfdf1b698a66c 100644 (file)
@@ -626,6 +626,8 @@ static time_t check_time = 0;
 static void
 system_reseed(void)
 {
+   uint8       buf[1024];
+   int         n;
    time_t      t;
    int         skip = 1;
 
@@ -640,34 +642,24 @@ system_reseed(void)
    else if (check_time == 0 ||
             (t - check_time) > SYSTEM_RESEED_CHECK_TIME)
    {
-       uint8       buf;
-
        check_time = t;
 
        /* roll dice */
-       px_get_random_bytes(&buf, 1);
-       skip = (buf >= SYSTEM_RESEED_CHANCE);
-
-       /* clear 1 byte */
-       px_memset(&buf, 0, sizeof(buf));
-   }
-   if (!skip)
-   {
-       /*
-        * fortuna_add_entropy passes the input to SHA-256, so there's no
-        * point in giving it more than 256 bits of input to begin with.
-        */
-       uint8       buf[32];
-
-       if (!pg_strong_random(buf, sizeof(buf)))
-           ereport(ERROR,
-                   (errcode(ERRCODE_INTERNAL_ERROR),
-                    errmsg("could not acquire random data")));
-       fortuna_add_entropy(buf, sizeof(buf));
-
-       seed_time = t;
-       px_memset(buf, 0, sizeof(buf));
+       px_get_random_bytes(buf, 1);
+       skip = buf[0] >= SYSTEM_RESEED_CHANCE;
    }
+   /* clear 1 byte */
+   px_memset(buf, 0, sizeof(buf));
+
+   if (skip)
+       return;
+
+   n = px_acquire_system_randomness(buf);
+   if (n > 0)
+       fortuna_add_entropy(buf, n);
+
+   seed_time = t;
+   px_memset(buf, 0, sizeof(buf));
 }
 
 int
diff --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c
new file mode 100644 (file)
index 0000000..d72679e
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * random.c
+ *     Acquire randomness from system.  For seeding RNG.
+ *
+ * Copyright (c) 2001 Marko Kreen
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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.
+ *
+ * contrib/pgcrypto/random.c
+ */
+
+#include "postgres.h"
+
+#include "px.h"
+#include "utils/memdebug.h"
+
+/* how many bytes to ask from system random provider */
+#define RND_BYTES  32
+
+/*
+ * Try to read from /dev/urandom or /dev/random on these OS'es.
+ *
+ * The list can be pretty liberal, as the device not existing
+ * is expected event.
+ */
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
+   || defined(__NetBSD__) || defined(__DragonFly__) \
+   || defined(__darwin__) || defined(__SOLARIS__) \
+   || defined(__hpux) || defined(__HPUX__) \
+   || defined(__CYGWIN__) || defined(_AIX)
+
+#define TRY_DEV_RANDOM
+
+#include <fcntl.h>
+#include <unistd.h>
+
+static int
+safe_read(int fd, void *buf, size_t count)
+{
+   int         done = 0;
+   char       *p = buf;
+   int         res;
+
+   while (count)
+   {
+       res = read(fd, p, count);
+       if (res <= 0)
+       {
+           if (errno == EINTR)
+               continue;
+           return PXE_DEV_READ_ERROR;
+       }
+       p += res;
+       done += res;
+       count -= res;
+   }
+   return done;
+}
+
+static uint8 *
+try_dev_random(uint8 *dst)
+{
+   int         fd;
+   int         res;
+
+   fd = open("/dev/urandom", O_RDONLY, 0);
+   if (fd == -1)
+   {
+       fd = open("/dev/random", O_RDONLY, 0);
+       if (fd == -1)
+           return dst;
+   }
+   res = safe_read(fd, dst, RND_BYTES);
+   close(fd);
+   if (res > 0)
+       dst += res;
+   return dst;
+}
+#endif
+
+/*
+ * Try to find randomness on Windows
+ */
+#ifdef WIN32
+
+#define TRY_WIN32_GENRAND
+#define TRY_WIN32_PERFC
+
+#include <windows.h>
+#include <wincrypt.h>
+
+/*
+ * this function is from libtomcrypt
+ *
+ * try to use Microsoft crypto API
+ */
+static uint8 *
+try_win32_genrand(uint8 *dst)
+{
+   int         res;
+   HCRYPTPROV  h = 0;
+
+   res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+                             (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
+   if (!res)
+       res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+              CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET);
+   if (!res)
+       return dst;
+
+   res = CryptGenRandom(h, RND_BYTES, dst);
+   if (res == TRUE)
+       dst += RND_BYTES;
+
+   CryptReleaseContext(h, 0);
+   return dst;
+}
+
+static uint8 *
+try_win32_perfc(uint8 *dst)
+{
+   int         res;
+   LARGE_INTEGER time;
+
+   res = QueryPerformanceCounter(&time);
+   if (!res)
+       return dst;
+
+   memcpy(dst, &time, sizeof(time));
+   return dst + sizeof(time);
+}
+#endif   /* WIN32 */
+
+
+/*
+ * If we are not on Windows, then hopefully we are
+ * on a unix-like system.  Use the usual suspects
+ * for randomness.
+ */
+#ifndef WIN32
+
+#define TRY_UNIXSTD
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+/*
+ * Everything here is predictible, only needs some patience.
+ *
+ * But there is a chance that the system-specific functions
+ * did not work.  So keep faith and try to slow the attacker down.
+ */
+static uint8 *
+try_unix_std(uint8 *dst)
+{
+   pid_t       pid;
+   int         x;
+   PX_MD      *md;
+   struct timeval tv;
+   int         res;
+
+   /* process id */
+   pid = getpid();
+   memcpy(dst, (uint8 *) &pid, sizeof(pid));
+   dst += sizeof(pid);
+
+   /* time */
+   gettimeofday(&tv, NULL);
+   memcpy(dst, (uint8 *) &tv, sizeof(tv));
+   dst += sizeof(tv);
+
+   /* pointless, but should not hurt */
+   x = random();
+   memcpy(dst, (uint8 *) &x, sizeof(x));
+   dst += sizeof(x);
+
+   /* hash of uninitialized stack and heap allocations */
+   res = px_find_digest("sha1", &md);
+   if (res >= 0)
+   {
+       uint8      *ptr;
+       uint8       stack[8192];
+       int         alloc = 32 * 1024;
+
+       VALGRIND_MAKE_MEM_DEFINED(stack, sizeof(stack));
+       px_md_update(md, stack, sizeof(stack));
+       ptr = px_alloc(alloc);
+       VALGRIND_MAKE_MEM_DEFINED(ptr, alloc);
+       px_md_update(md, ptr, alloc);
+       px_free(ptr);
+
+       px_md_finish(md, dst);
+       px_md_free(md);
+
+       dst += 20;
+   }
+
+   return dst;
+}
+#endif
+
+/*
+ * try to extract some randomness for initial seeding
+ *
+ * dst should have room for 1024 bytes.
+ */
+unsigned
+px_acquire_system_randomness(uint8 *dst)
+{
+   uint8      *p = dst;
+
+#ifdef TRY_DEV_RANDOM
+   p = try_dev_random(p);
+#endif
+#ifdef TRY_WIN32_GENRAND
+   p = try_win32_genrand(p);
+#endif
+#ifdef TRY_WIN32_PERFC
+   p = try_win32_perfc(p);
+#endif
+#ifdef TRY_UNIXSTD
+   p = try_unix_std(p);
+#endif
+   return p - dst;
+}
index 44b2212b1dabd0d6da798eb8a7da1756617cef99..0ba85301149a03be96f127b455d179645b23d95a 100644 (file)
@@ -45,12 +45,6 @@ static void auth_failed(Port *port, int status, char *logdetail);
 static char *recv_password_packet(Port *port);
 static int recv_and_check_password_packet(Port *port, char **logdetail);
 
-/*----------------------------------------------------------------
- * MD5 authentication
- *----------------------------------------------------------------
- */
-static int CheckMD5Auth(Port *port, char **logdetail);
-
 
 /*----------------------------------------------------------------
  * Ident authentication
@@ -541,7 +535,9 @@ ClientAuthentication(Port *port)
                ereport(FATAL,
                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
                         errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
-           status = CheckMD5Auth(port, &logdetail);
+           /* include the salt to use for computing the response */
+           sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4);
+           status = recv_and_check_password_packet(port, &logdetail);
            break;
 
        case uaPassword:
@@ -696,25 +692,10 @@ recv_password_packet(Port *port)
 
 
 /*----------------------------------------------------------------
- * MD5 and password authentication
+ * MD5 authentication
  *----------------------------------------------------------------
  */
 
-static int
-CheckMD5Auth(Port *port, char **logdetail)
-{
-   /* include the salt to use for computing the response */
-   if (!pg_strong_random(port->md5Salt, sizeof(port->md5Salt)))
-   {
-       *logdetail = psprintf(_("Could not generate random salt"));
-       return STATUS_ERROR;
-   }
-
-   sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4);
-   return recv_and_check_password_packet(port, logdetail);
-}
-
-
 /*
  * Called when we have sent an authorization request for a password.
  * Get the response and check it.
index 442013867338b8a0a2076cc5c58ea66109fc6834..2d43506cd0e362fee067fd1c3126fe8a29f6acbc 100644 (file)
@@ -358,6 +358,14 @@ static volatile bool avlauncher_needs_signal = false;
 static volatile bool StartWorkerNeeded = true;
 static volatile bool HaveCrashedWorker = false;
 
+/*
+ * State for assigning random salts and cancel keys.
+ * Also, the global MyCancelKey passes the cancel key assigned to a given
+ * backend from the postmaster to that backend (via fork).
+ */
+static unsigned int random_seed = 0;
+static struct timeval random_start_time;
+
 #ifdef USE_BONJOUR
 static DNSServiceRef bonjour_sdref = NULL;
 #endif
@@ -395,6 +403,8 @@ static void processCancelRequest(Port *port, void *pkt);
 static int initMasks(fd_set *rmask);
 static void report_fork_failure_to_client(Port *port, int errnum);
 static CAC_state canAcceptConnections(void);
+static long PostmasterRandom(void);
+static void RandomSalt(char *salt, int len);
 static void signal_child(pid_t pid, int signal);
 static bool SignalSomeChildren(int signal, int targets);
 static void TerminateChildren(int signal);
@@ -569,11 +579,9 @@ PostmasterMain(int argc, char *argv[])
     * Initialize random(3) so we don't get the same values in every run.
     *
     * Note: the seed is pretty predictable from externally-visible facts such
-    * as postmaster start time, so don't use random() for security-critical
-    * random values (use pg_strong_random() instead).  Backends select a
-    * somewhat more random seed after forking, in BackendRun(), based on the
-    * PID and session start timestamp, but that is still not suitable for
-    * security-critical values.
+    * as postmaster start time, so avoid using random() for security-critical
+    * random values during postmaster startup.  At the time of first
+    * connection, PostmasterRandom will select a hopefully-more-random seed.
     */
    srandom((unsigned int) (MyProcPid ^ MyStartTime));
 
@@ -1284,6 +1292,8 @@ PostmasterMain(int argc, char *argv[])
     * Remember postmaster startup time
     */
    PgStartTime = GetCurrentTimestamp();
+   /* PostmasterRandom wants its own copy */
+   gettimeofday(&random_start_time, NULL);
 
    /*
     * We're ready to rock and roll...
@@ -2333,6 +2343,15 @@ ConnCreate(int serverFd)
        return NULL;
    }
 
+   /*
+    * Precompute password salt values to use for this connection. It's
+    * slightly annoying to do this long in advance of knowing whether we'll
+    * need 'em or not, but we must do the random() calls before we fork, not
+    * after.  Else the postmaster's random sequence won't get advanced, and
+    * all backends would end up using the same salt...
+    */
+   RandomSalt(port->md5Salt, sizeof(port->md5Salt));
+
    /*
     * Allocate GSSAPI specific state struct
     */
@@ -3885,12 +3904,7 @@ BackendStartup(Port *port)
     * backend will have its own copy in the forked-off process' value of
     * MyCancelKey, so that it can transmit the key to the frontend.
     */
-   if (!pg_strong_random(&MyCancelKey, sizeof(MyCancelKey)))
-   {
-       ereport(LOG,
-               (errmsg("could not generate random query cancel key")));
-       return STATUS_ERROR;
-   }
+   MyCancelKey = PostmasterRandom();
    bn->cancel_key = MyCancelKey;
 
    /* Pass down canAcceptConnections state */
@@ -4198,6 +4212,13 @@ BackendRun(Port *port)
    int         usecs;
    int         i;
 
+   /*
+    * Don't want backend to be able to see the postmaster random number
+    * generator state.  We have to clobber the static random_seed *and* start
+    * a new random sequence in the random() library function.
+    */
+   random_seed = 0;
+   random_start_time.tv_usec = 0;
    /* slightly hacky way to convert timestamptz into integers */
    TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
    srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
@@ -5045,6 +5066,66 @@ StartupPacketTimeoutHandler(void)
 }
 
 
+/*
+ * RandomSalt
+ */
+static void
+RandomSalt(char *salt, int len)
+{
+   long        rand;
+   int         i;
+
+   /*
+    * We use % 255, sacrificing one possible byte value, so as to ensure that
+    * all bits of the random() value participate in the result. While at it,
+    * add one to avoid generating any null bytes.
+    */
+   for (i = 0; i < len; i++)
+   {
+       rand = PostmasterRandom();
+       salt[i] = (rand % 255) + 1;
+   }
+}
+
+/*
+ * PostmasterRandom
+ *
+ * Caution: use this only for values needed during connection-request
+ * processing.  Otherwise, the intended property of having an unpredictable
+ * delay between random_start_time and random_stop_time will be broken.
+ */
+static long
+PostmasterRandom(void)
+{
+   /*
+    * Select a random seed at the time of first receiving a request.
+    */
+   if (random_seed == 0)
+   {
+       do
+       {
+           struct timeval random_stop_time;
+
+           gettimeofday(&random_stop_time, NULL);
+
+           /*
+            * We are not sure how much precision is in tv_usec, so we swap
+            * the high and low 16 bits of 'random_stop_time' and XOR them
+            * with 'random_start_time'. On the off chance that the result is
+            * 0, we loop until it isn't.
+            */
+           random_seed = random_start_time.tv_usec ^
+               ((random_stop_time.tv_usec << 16) |
+                ((random_stop_time.tv_usec >> 16) & 0xffff));
+       }
+       while (random_seed == 0);
+
+       srandom(random_seed);
+   }
+
+   return random();
+}
+
 /*
  * Count up number of child processes of specified types (dead_end chidren
  * are always excluded).
@@ -5222,37 +5303,31 @@ StartAutovacuumWorker(void)
             * we'd better have something random in the field to prevent
             * unfriendly people from sending cancels to them.
             */
-           if (pg_strong_random(&MyCancelKey, sizeof(MyCancelKey)))
-           {
-               bn->cancel_key = MyCancelKey;
+           MyCancelKey = PostmasterRandom();
+           bn->cancel_key = MyCancelKey;
 
-               /* Autovac workers are not dead_end and need a child slot */
-               bn->dead_end = false;
-               bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
-               bn->bgworker_notify = false;
+           /* Autovac workers are not dead_end and need a child slot */
+           bn->dead_end = false;
+           bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
+           bn->bgworker_notify = false;
 
-               bn->pid = StartAutoVacWorker();
-               if (bn->pid > 0)
-               {
-                   bn->bkend_type = BACKEND_TYPE_AUTOVAC;
-                   dlist_push_head(&BackendList, &bn->elem);
+           bn->pid = StartAutoVacWorker();
+           if (bn->pid > 0)
+           {
+               bn->bkend_type = BACKEND_TYPE_AUTOVAC;
+               dlist_push_head(&BackendList, &bn->elem);
 #ifdef EXEC_BACKEND
-                   ShmemBackendArrayAdd(bn);
+               ShmemBackendArrayAdd(bn);
 #endif
-                   /* all OK */
-                   return;
-               }
-
-               /*
-                * fork failed, fall through to report -- actual error message
-                * was logged by StartAutoVacWorker
-                */
-               (void) ReleasePostmasterChildSlot(bn->child_slot);
+               /* all OK */
+               return;
            }
-           else
-               ereport(LOG,
-                    (errmsg("could not generate random query cancel key")));
 
+           /*
+            * fork failed, fall through to report -- actual error message was
+            * logged by StartAutoVacWorker
+            */
+           (void) ReleasePostmasterChildSlot(bn->child_slot);
            free(bn);
        }
        else
@@ -5540,11 +5615,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw)
     * have something random in the field to prevent unfriendly people from
     * sending cancels to them.
     */
-   if (!pg_strong_random(&MyCancelKey, sizeof(MyCancelKey)))
-   {
-       rw->rw_crashed_at = GetCurrentTimestamp();
-       return false;
-   }
+   MyCancelKey = PostmasterRandom();
    bn->cancel_key = MyCancelKey;
 
    bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
index 4bb9feeb019fd0a58c08a4451639046176522c16..b81fa4a89eb1130c6431bb41c80ee58198df893d 100644 (file)
@@ -454,9 +454,6 @@ extern int  pg_codepage_to_encoding(UINT cp);
 extern char *inet_net_ntop(int af, const void *src, int bits,
              char *dst, size_t size);
 
-/* port/pg_strong_random.c */
-extern bool pg_strong_random(void *buf, size_t len);
-
 /* port/pgcheckdir.c */
 extern int pg_check_dir(const char *dir);
 
index d34f409ee976be87439263cd7c93801f43304250..bc9b63add0479459d146550c0338e1a22a478400 100644 (file)
@@ -32,7 +32,7 @@ LIBS += $(PTHREAD_LIBS)
 
 OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
    noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
-   pg_strong_random.o pgstrcasecmp.o pqsignal.o \
+   pgstrcasecmp.o pqsignal.o \
    qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
 
 # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
deleted file mode 100644 (file)
index a404111..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_strong_random.c
- *   pg_strong_random() function to return a strong random number
- *
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
- *
- *
- * IDENTIFICATION
- *   src/port/pg_strong_random.c
- *
- *-------------------------------------------------------------------------
- */
-
-#ifndef FRONTEND
-#include "postgres.h"
-#else
-#include "postgres_fe.h"
-#endif
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#ifdef USE_SSL
-#include <openssl/rand.h>
-#endif
-#ifdef WIN32
-#include <Wincrypt.h>
-#endif
-
-static bool random_from_file(char *filename, void *buf, size_t len);
-
-#ifdef WIN32
-/*
- * Cache a global crypto provider that only gets freed when the process
- * exits, in case we need random numbers more than once.
- */
-static HCRYPTPROV hProvider = 0;
-#endif
-
-/*
- * Read (random) bytes from a file.
- */
-static bool
-random_from_file(char *filename, void *buf, size_t len)
-{
-   int         f;
-   char       *p = buf;
-   ssize_t     res;
-
-   f = open(filename, O_RDONLY, 0);
-   if (f == -1)
-       return false;
-
-   while (len)
-   {
-       res = read(f, p, len);
-       if (res <= 0)
-       {
-           if (errno == EINTR)
-               continue;       /* interrupted by signal, just retry */
-
-           close(f);
-           return false;
-       }
-
-       p += res;
-       len -= res;
-   }
-
-   close(f);
-   return true;
-}
-
-/*
- * pg_strong_random
- *
- * Generate requested number of random bytes. The bytes are
- * cryptographically strong random, suitable for use e.g. in key
- * generation.
- *
- * The bytes can be acquired from a number of sources, depending
- * on what's available. We try the following, in this order:
- *
- * 1. OpenSSL's RAND_bytes()
- * 2. Windows' CryptGenRandom() function
- * 3. /dev/urandom
- * 4. /dev/random
- *
- * Returns true on success, and false if none of the sources
- * were available. NB: It is important to check the return value!
- * Proceeding with key generation when no random data was available
- * would lead to predictable keys and security issues.
- */
-bool
-pg_strong_random(void *buf, size_t len)
-{
-#ifdef USE_SSL
-
-   /*
-    * When built with OpenSSL, first try the random generation function from
-    * there.
-    */
-   if (RAND_bytes(buf, len) == 1)
-       return true;
-#endif
-
-#ifdef WIN32
-
-   /*
-    * Windows has CryptoAPI for strong cryptographic numbers.
-    */
-   if (hProvider == 0)
-   {
-       if (!CryptAcquireContext(&hProvider,
-                                NULL,
-                                MS_DEF_PROV,
-                                PROV_RSA_FULL,
-                                CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
-       {
-           /*
-            * On failure, set back to 0 in case the value was for some reason
-            * modified.
-            */
-           hProvider = 0;
-       }
-   }
-
-   /* Re-check in case we just retrieved the provider */
-   if (hProvider != 0)
-   {
-       if (CryptGenRandom(hProvider, len, buf))
-           return true;
-   }
-#endif
-
-   /*
-    * If there is no OpenSSL and no CryptoAPI (or they didn't work), then
-    * fall back on reading /dev/urandom or even /dev/random.
-    */
-   if (random_from_file("/dev/urandom", buf, len))
-       return true;
-   if (random_from_file("/dev/random", buf, len))
-       return true;
-
-   /* None of the sources were available. */
-   return false;
-}
index e6c4aef99f373d0f98a429475bb30b6af4dd5047..de764dd4d44b28a37e18357f1ce99544a43cceff 100644 (file)
@@ -92,7 +92,7 @@ sub mkvcbuild
      srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
      erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
      pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
-     mkdtemp.c pg_strong_random.c qsort.c qsort_arg.c quotes.c system.c
+     mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
      sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
      win32env.c win32error.c win32security.c win32setlocale.c);
 
@@ -425,8 +425,8 @@ sub mkvcbuild
            'sha1.c',             'sha2.c',
            'internal.c',         'internal-sha2.c',
            'blf.c',              'rijndael.c',
-           'fortuna.c',          'pgp-mpi-internal.c',
-           'imath.c');
+           'fortuna.c',          'random.c',
+           'pgp-mpi-internal.c', 'imath.c');
    }
    $pgcrypto->AddReference($postgres);
    $pgcrypto->AddLibrary('ws2_32.lib');