From acdc90072ac0c78fe598522bd079f4456fb1ce3f Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 21 Oct 2025 16:25:23 -0700
Subject: [PATCH v2 1/2] Add configure-time selection of strong random number
 source.

Previously, the random number source was automatically selected: OpenSSL
was the first choice, with native platform sources (Windows API or
/dev/urandom) used as fallback options.

This commit adds the ability to specify the random number source at
configure time using either the --with-strong-random option for the
configure script or the -Dstrong_random option for meson.

The selected random source can be viewed through the read-only GUC
parameter strong_random_source.

Reviewed-by:
Discussion: https://postgr.es/m/
---
 configure                                 | 82 ++++++++++++++++++-----
 configure.ac                              | 50 ++++++++++----
 doc/src/sgml/config.sgml                  | 19 ++++++
 doc/src/sgml/installation.sgml            | 40 +++++++++++
 meson.build                               | 22 ++++++
 meson_options.txt                         |  4 ++
 src/backend/utils/misc/guc_parameters.dat |  7 ++
 src/backend/utils/misc/guc_tables.c       |  7 ++
 src/include/pg_config.h.in                |  6 ++
 src/port/pg_strong_random.c               |  6 +-
 10 files changed, 213 insertions(+), 30 deletions(-)

diff --git a/configure b/configure
index f7c24c8f576..c591f8d8fbd 100755
--- a/configure
+++ b/configure
@@ -886,6 +886,7 @@ with_zstd
 with_ssl
 with_openssl
 enable_largefile
+with_strong_random
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1605,6 +1606,8 @@ Optional Packages:
   --with-zstd             build with ZSTD support
   --with-ssl=LIB          use LIB for SSL/TLS support (openssl)
   --with-openssl          obsolete spelling of --with-ssl=openssl
+  --with-strong-random=NAME
+                          set strong random number source (system,openssl)
 
 Some influential environment variables:
   PG_TEST_EXTRA
@@ -15000,8 +15003,8 @@ fi
 
 
 # Even though restrict is in C99 and should be supported by all
-# supported compilers, but this macro is useful because it will prefer
-# a spelling that also works in C++ (often __restrict).  (restrict is
+# supported compilers, this test is useful because it will prefer a
+# spelling that also works in C++ (often __restrict).  (restrict is
 # not part of the C++ standard.)
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
 $as_echo_n "checking for C/C++ restrict keyword... " >&6; }
@@ -18267,24 +18270,69 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select strong random number source.
+#
+
+
+
+
+# Check whether --with-strong-random was given.
+if test "${with_strong_random+set}" = set; then :
+  withval=$with_strong_random;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with-strong-random option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with-strong-random option" "$LINENO" 5
+      ;;
+    *)
+      strong_random=$withval
+      ;;
+  esac
+
+fi
+
+
+
+# If nothing is specified to --with-strong-random, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$strong_random" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    strong_random=openssl
+  else
+    strong_random=system
+  fi
+elif test x"$strong_random" != x"openssl" -a x"$strong_random" != x"system" ; then
+  as_fn_error $? "--with-strong-random must sepcify one of system or openssl" "$LINENO" 5
+fi
+
+if test "$strong_random" = openssl -a x"$with_ssl" != x"openssl" ; then
+  as_fn_error $? "OpenSSL library is required for random number generation" "$LINENO" 5
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5
 $as_echo_n "checking which random number source to use... " >&6; }
-if test x"$with_ssl" = x"openssl" ; then
+if test "$strong_random" = openssl ; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
 $as_echo "OpenSSL" >&6; }
-elif test x"$PORTNAME" = x"win32" ; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
+
+$as_echo "#define STRONG_RANDOM_SOURCE_OPENSSL 1" >>confdefs.h
+
+else
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  if test x"$PORTNAME" = x"win32" ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
 $as_echo "Windows native" >&6; }
-elif test x"$cross_compiling" = x"yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5
+  elif test x"$cross_compiling" = x"yes"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5
 $as_echo "assuming /dev/urandom" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
 $as_echo_n "checking for /dev/urandom... " >&6; }
 if ${ac_cv_file__dev_urandom+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -18304,11 +18352,15 @@ if test "x$ac_cv_file__dev_urandom" = xyes; then :
 fi
 
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    as_fn_error $? "
+    if test x"$ac_cv_file__dev_urandom" = x"no" ; then
+      as_fn_error $? "
 no source of strong random numbers was found
 PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers." "$LINENO" 5
+    fi
   fi
+
+$as_echo "#define STRONG_RANDOM_SOURCE_SYSTEM 1" >>confdefs.h
+
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/configure.ac b/configure.ac
index 6c802deaacb..bfdb764f059 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2289,25 +2289,51 @@ else
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select strong random number source.
+#
+
+PGAC_ARG_REQ(with, strong-random, [NAME], [set strong random number source (system,openssl)],
+             [strong_random=$withval])
+
+# If nothing is specified to --with-strong-random, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$strong_random" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    strong_random=openssl
+  else
+    strong_random=system
+  fi
+elif test x"$strong_random" != x"openssl" -a x"$strong_random" != x"system" ; then
+  AC_MSG_ERROR([--with-strong-random must sepcify one of system or openssl])
+fi
+
+if test "$strong_random" = openssl -a x"$with_ssl" != x"openssl" ; then
+  AC_MSG_ERROR([OpenSSL library is required for random number generation])
+fi
+
 AC_MSG_CHECKING([which random number source to use])
-if test x"$with_ssl" = x"openssl" ; then
+if test "$strong_random" = openssl ; then
   AC_MSG_RESULT([OpenSSL])
-elif test x"$PORTNAME" = x"win32" ; then
-  AC_MSG_RESULT([Windows native])
-elif test x"$cross_compiling" = x"yes"; then
-  AC_MSG_RESULT([assuming /dev/urandom])
+  AC_DEFINE([STRONG_RANDOM_SOURCE_OPENSSL], 1, [Define to 1 to use OpenSSL libary for strong random number generation])
 else
-  AC_MSG_RESULT([/dev/urandom])
-  AC_CHECK_FILE([/dev/urandom], [], [])
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  if test x"$PORTNAME" = x"win32" ; then
+    AC_MSG_RESULT([Windows native])
+  elif test x"$cross_compiling" = x"yes"; then
+    AC_MSG_RESULT([assuming /dev/urandom])
+  else
+    AC_MSG_RESULT([/dev/urandom])
+    AC_CHECK_FILE([/dev/urandom], [], [])
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    AC_MSG_ERROR([
+    if test x"$ac_cv_file__dev_urandom" = x"no" ; then
+      AC_MSG_ERROR([
 no source of strong random numbers was found
 PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers.])
+    fi
   fi
+  AC_DEFINE([STRONG_RANDOM_SOURCE_SYSTEM], 1, [Define to 1 to use system native source for strong random number generation])
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 06d1e4403b5..d839f78e2db 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -12047,6 +12047,25 @@ dynamic_library_path = '/usr/local/lib/postgresql:$libdir'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-strong-random-source" xreflabel="strong_random_source">
+      <term><varname>strong_random_source</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>strong_random_source</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Reports the name of implementation used to generate cryptographically secure
+        random data: <literal>system</literal> or <literal>openssl</literal>. It
+        is determined when building the server. See more information see
+        <link linkend="configure-option-with-strong-random"><option>--with-strong-random
+        </option></link> for installation with Autoconf or
+        <link linkend="configure-strong-random-meson"><option>-Dstrong_random</option>
+        </link> for installation with Meson.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-wal-block-size" xreflabel="wal_block_size">
       <term><varname>wal_block_size</varname> (<type>integer</type>)
       <indexterm>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 593202f4fb2..3ff2f3fb5a1 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1531,6 +1531,26 @@ build-postgresql:
        </listitem>
       </varlistentry>
 
+      <varlistentry id="configure-option-with-strong-random">
+       <term><option>--with-strong-random=<replaceable>NAME</replaceable></option></term>
+       <listitem>
+        <para>
+         Specifies the imlementation used to generate cryptographically secure random
+         data. Valid values are <literal>system</literal> and <literal>openssl</literal>.
+        </para>
+        <para>
+         <productname>PostgreSQL</productname> relies on strong random numbers in
+         security-sensitive operations. For example, random values are used when generating
+         salts for <literal>SCRAM-SHA-256</literal> password storage and when creating
+         UUIDs. By default, the implementation is chosen based on the
+         <option>--with-ssl</option> option: if <productname>PostgreSQL</productname>
+         is built with <productname>OpenSSL</productname> support,
+         <productname>OpenSSL</productname>'s random generator is used; otherwise, the
+         operating system native secure random facility is used. This option overrides
+         that behavior and forces use of the specified source.
+        </para>
+       </listitem>
+      </varlistentry>
      </variablelist>
 
    </sect3>
@@ -3054,6 +3074,26 @@ ninja install
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry id="configure-strong-random-meson">
+      <term><option>-Dstrong_random={ auto | system | openssl }</option></term>
+       <listitem>
+        <para>
+         Specifies the imlementation used to generate cryptographically secure random
+         data.
+        </para>
+        <para>
+         <productname>PostgreSQL</productname> relies on strong random numbers in
+         security-sensitive operations. For example, random values are used when generating
+         salts for <literal>SCRAM-SHA-256</literal> password storage and when creating
+         UUIDs. Default to auto and the implementation will be chosen based on the
+         <option>-Dssl</option> option: if <productname>PostgreSQL</productname>
+         is built with <productname>OpenSSL</productname> support,
+         <productname>OpenSSL</productname>'s random generator is used; otherwise, the
+         operating system native secure random facility is used.
+        </para>
+       </listitem>
+     </varlistentry>
     </variablelist>
    </sect3>
 
diff --git a/meson.build b/meson.build
index 0f61ff6a700..90918fc12da 100644
--- a/meson.build
+++ b/meson.build
@@ -2547,7 +2547,29 @@ if not have_optimized_crc
   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
 endif
 
+###############################################################
+# Select strong random number source.
+###############################################################
+rand_src_opt = get_option('strong_random')
+if rand_src_opt == 'auto'
+  if ssl.found()
+    rand_src_opt = 'openssl'
+  else
+    rand_src_opt = 'system'
+  endif
+endif
+
+if rand_src_opt == 'openssl' and not ssl.found()
+  error('OpenSSL library must be enabled for strong random number generation')
+endif
 
+if rand_src_opt == 'system'
+  cdata.set('STRONG_RANDOM_SOURCE_SYSTEM', 1,
+            description: 'Define to 1 to use system native source for strong random number generation')
+else
+  cdata.set('STRONG_RANDOM_SOURCE_OPENSSL', 1,
+            description: 'Define to 1 to use OpenSSL libary for strong random number generation')
+endif
 
 ###############################################################
 # Other CPU specific stuff
diff --git a/meson_options.txt b/meson_options.txt
index 06bf5627d3c..46850404c18 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -142,6 +142,10 @@ option('pltcl', type: 'feature', value: 'auto',
 option('tcl_version', type: 'string', value: 'tcl',
   description: 'Tcl version')
 
+option('strong_random', type: 'combo', choices: ['auto', 'system', 'openssl'],
+  value: 'auto',
+  description: 'Select strong random number source')
+
 option('readline', type: 'feature', value: 'auto',
   description: 'Use GNU Readline or BSD Libedit for editing')
 
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index d6fc8333850..b70f00cfcc1 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -3195,6 +3195,13 @@
   assign_hook => 'assign_log_connections',
 },
 
+{ name => 'strong_random_source', type => 'string', context => 'PGC_INTERNAL', group => 'PRESET_OPTIONS',
+  short_desc => 'Shows implementation used for generating strong random number.',
+  flags => 'GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE',
+  variable => 'strong_random_source',
+  boot_val => 'DEFAULT_STRONG_RANDOM_SOURCE',
+},
+
 { name => 'backslash_quote', type => 'enum', context => 'PGC_USERSET', group => 'COMPAT_OPTIONS_PREVIOUS',
   short_desc => 'Sets whether "\\\\\'" is allowed in string literals.',
   variable => 'backslash_quote',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 00c8376cf4d..1a58d0d19c1 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -620,6 +620,13 @@ static int	num_os_semaphores;
 static bool data_checksums;
 static bool integer_datetimes;
 
+#ifdef STRONG_RANDOM_SOURCE_OPENSSL
+#define DEFAULT_STRONG_RANDOM_SOURCE "openssl"
+#else
+#define DEFAULT_STRONG_RANDOM_SOURCE "system"
+#endif
+static char *strong_random_source = DEFAULT_STRONG_RANDOM_SOURCE;
+
 #ifdef USE_ASSERT_CHECKING
 #define DEFAULT_ASSERT_ENABLED true
 #else
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index f52f14cc566..4aeceb53eb4 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -666,6 +666,12 @@
 /* Define to 1 if strerror_r() returns int. */
 #undef STRERROR_R_INT
 
+/* Define to 1 to use system's native source for strong random number generation  */
+#undef STRONG_RANDOM_SOURCE_SYSTEM
+
+/* Define to 1 to use OpenSSL libary for strong random number generation */
+#undef STRONG_RANDOM_SOURCE_OPENSSL
+
 /* Define to 1 to use ARMv8 CRC Extension. */
 #undef USE_ARMV8_CRC32C
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index ea6780dcc9f..0d3f00f588f 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -50,7 +50,7 @@
 
 
 
-#ifdef USE_OPENSSL
+#ifdef STRONG_RANDOM_SOURCE_OPENSSL
 
 #include <openssl/rand.h>
 
@@ -92,7 +92,7 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#elif WIN32
+#elif WIN32						/* STRONG_RANDOM_SOURCE_SYSTEM and WIN32 */
 
 #include <wincrypt.h>
 /*
@@ -134,7 +134,7 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#else							/* STRONG_RANDOM_SOURCE_SYSTEM and not WIN32 */
 
 /*
  * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
-- 
2.47.3

