From e6d64a38c864c3355585547219b58db7c21e5c78 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 28 Oct 2020 11:24:02 +0100
Subject: [PATCH v16 3/5] NSS pg_strong_random support

---
 configure                   |  8 +++++++-
 configure.ac                |  5 ++++-
 src/include/pg_config.h.in  |  3 +++
 src/port/pg_strong_random.c | 37 +++++++++++++++++++++++++++++++++++++
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/configure b/configure
index 6287a0e2fe..f78772bd42 100755
--- a/configure
+++ b/configure
@@ -18426,6 +18426,12 @@ $as_echo "#define USE_WIN32_RANDOM 1" >>confdefs.h
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
 $as_echo "Windows native" >&6; }
+elif test x"$USE_NSS_RANDOM" = x"1" ; then
+
+$as_echo "#define USE_NSS_RANDOM 1" >>confdefs.h
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: NSS" >&5
+$as_echo "NSS" >&6; }
 elif test x"$USE_DEV_URANDOM" = x"1" ; then
 
 $as_echo "#define USE_DEV_URANDOM 1" >>confdefs.h
@@ -18435,7 +18441,7 @@ $as_echo "/dev/urandom" >&6; }
 else
   as_fn_error $? "
 no source of strong random numbers was found
-PostgreSQL can use OpenSSL or /dev/urandom as a source of random numbers." "$LINENO" 5
+PostgreSQL can use OpenSSL, NSS, Windows native RNG or /dev/urandom as a source of random numbers." "$LINENO" 5
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/configure.ac b/configure.ac
index 706c9862e7..01c23356ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2215,13 +2215,16 @@ if test x"$USE_OPENSSL_RANDOM" = x"1" ; then
 elif test x"$USE_WIN32_RANDOM" = x"1" ; then
   AC_DEFINE(USE_WIN32_RANDOM, 1, [Define to use native Windows API for random number generation])
   AC_MSG_RESULT([Windows native])
+elif test x"$USE_NSS_RANDOM" = x"1" ; then
+  AC_DEFINE(USE_NSS_RANDOM, 1, [Define to use NSS for random number generation])
+  AC_MSG_RESULT([NSS])
 elif test x"$USE_DEV_URANDOM" = x"1" ; then
   AC_DEFINE(USE_DEV_URANDOM, 1, [Define to use /dev/urandom for random number generation])
   AC_MSG_RESULT([/dev/urandom])
 else
   AC_MSG_ERROR([
 no source of strong random numbers was found
-PostgreSQL can use OpenSSL or /dev/urandom as a source of random numbers.])
+PostgreSQL can use OpenSSL, NSS, Windows native RNG or /dev/urandom as a source of random numbers.])
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 31f808398c..73c39b449c 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -896,6 +896,9 @@
 /* Define to build with NSS support (--with-nss) */
 #undef USE_NSS
 
+/* Define to use NSS for random number generation */
+#undef USE_NSS_RANDOM
+
 /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */
 #undef USE_SLICING_BY_8_CRC32C
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index 14e8382cd8..33af92a60b 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -30,6 +30,20 @@
 #ifdef USE_WIN32_RANDOM
 #include <wincrypt.h>
 #endif
+#ifdef USE_NSS_RANDOM
+#define pg_BITS_PER_BYTE BITS_PER_BYTE
+#undef BITS_PER_BYTE
+#include <nss/nss.h>
+#include <nss/pk11pub.h>
+#if defined(BITS_PER_BYTE)
+#if BITS_PER_BYTE != pg_BITS_PER_BYTE
+#error "incompatible byte widths between NSPR and postgres"
+#endif
+#else
+#define BITS_PER_BYTE pg_BITS_PER_BYTE
+#endif
+#undef pg_BITS_PER_BYTE
+#endif
 
 #ifdef USE_WIN32_RANDOM
 /*
@@ -158,6 +172,29 @@ pg_strong_random(void *buf, size_t len)
 	}
 	return false;
 
+#elif defined(USE_NSS_RANDOM)
+	NSSInitParameters params;
+	NSSInitContext *nss_context;
+	SECStatus status;
+
+	memset(&params, 0, sizeof(params));
+	params.length = sizeof(params);
+	nss_context = NSS_InitContext("", "", "", "", &params,
+							  NSS_INIT_READONLY | NSS_INIT_NOCERTDB |
+							  NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
+							  NSS_INIT_NOROOTINIT | NSS_INIT_PK11RELOAD);
+
+	if (!nss_context)
+		return false;
+
+	status = PK11_GenerateRandom(buf, len);
+	NSS_ShutdownContext(nss_context);
+
+	if (status == SECSuccess)
+		return true;
+
+	return false;
+
 	/*
 	 * Read /dev/urandom ourselves.
 	 */
-- 
2.21.1 (Apple Git-122.3)

