From 71f650c1d87504e02309df00c138077f00e0d7bf 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 v3 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                                 | 78 +++++++++++++++++++----
 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, 211 insertions(+), 28 deletions(-)

diff --git a/configure b/configure
index 02e4ec7890f..28df8d20139 100755
--- a/configure
+++ b/configure
@@ -887,6 +887,7 @@ with_zstd
 with_ssl
 with_openssl
 enable_largefile
+with_strong_random
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1606,6 +1607,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
@@ -18400,24 +18403,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
@@ -18437,11 +18485,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 b90a220a635..c86083b2c74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2287,25 +2287,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 601aa3afb8e..db8ce2b0999 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -12124,6 +12124,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 fe8d73e1f8c..ce0283ddf5b 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 c3834a9dc8f..ce28ac4c616 100644
--- a/meson.build
+++ b/meson.build
@@ -2576,7 +2576,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 6a793f3e479..19321c53e68 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 7c60b125564..fad27367c26 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -2784,6 +2784,13 @@
   assign_hook => 'assign_stats_fetch_consistency',
 },
 
+{ 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 => 'subtransaction_buffers', type => 'int', context => 'PGC_POSTMASTER', group => 'RESOURCES_MEM',
   short_desc => 'Sets the size of the dedicated buffer pool used for the subtransaction cache.',
   long_desc => '0 means use a fraction of "shared_buffers".',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 73ff6ad0a32..ec008d48138 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -621,6 +621,13 @@ static int	effective_wal_level = WAL_LEVEL_REPLICA;
 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 2dd8f6b9a38..9bcc9c54ff8 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -660,6 +660,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 c8d8a70d896..cc6f598ac67 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

