Revert "Replace PostmasterRandom() with a stronger way of generating randomness."
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 18 Oct 2016 13:28:23 +0000 (16:28 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
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');