LCOV
GCOV
enable_debug
+enable_strong_random
enable_rpath
default_port
WANTED_LANGUAGES
enable_rpath
enable_spinlocks
enable_atomics
+enable_strong_random
enable_debug
enable_profiling
enable_coverage
executables
--disable-spinlocks do not use spinlocks
--disable-atomics do not use atomic operations
+ --disable-strong-random do not use a strong random number source
--enable-debug build with debugging symbols (-g)
--enable-profiling build with profiling enabled
--enable-coverage build with coverage testing instrumentation
+#
+# Random number generation
+#
+
+
+# Check whether --enable-strong-random was given.
+if test "${enable_strong_random+set}" = set; then :
+ enableval=$enable_strong_random;
+ case $enableval in
+ yes)
+ :
+ ;;
+ no)
+ :
+ ;;
+ *)
+ as_fn_error $? "no argument expected for --enable-strong-random option" "$LINENO" 5
+ ;;
+ esac
+
+else
+ enable_strong_random=yes
+
+fi
+
+
+
+
#
# --enable-debug adds -g to compiler flags
#
SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
fi
+# Select random number source
+#
+# You can override this logic by setting the appropriate USE_*RANDOM flag to 1
+# in the template or configure command line.
+
+# If not selected manually, try to select a source automatically.
+if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then
+ if test x"$with_openssl" = x"yes" ; then
+ USE_OPENSSL_RANDOM=1
+ elif test "$PORTNAME" = x"win32" ; then
+ USE_WIN32_RANDOM=1
+ else
+ { $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
+else
+ test "$cross_compiling" = yes &&
+ as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+if test -r "/dev/urandom"; then
+ ac_cv_file__dev_urandom=yes
+else
+ ac_cv_file__dev_urandom=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_urandom" >&5
+$as_echo "$ac_cv_file__dev_urandom" >&6; }
+if test "x$ac_cv_file__dev_urandom" = xyes; then :
+
+fi
+
+
+ if test x"$ac_cv_file__dev_urandom" = x"yes" ; then
+ USE_DEV_URANDOM=1
+ fi
+ fi
+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 "$enable_strong_random" = yes ; then
+ if test x"$USE_OPENSSL_RANDOM" = x"1" ; then
+
+$as_echo "#define USE_OPENSSL_RANDOM 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
+$as_echo "OpenSSL" >&6; }
+ elif test x"$USE_WIN32_RANDOM" = x"1" ; then
+
+$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_DEV_URANDOM" = x"1" ; then
+
+$as_echo "#define USE_DEV_URANDOM 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
+$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,
+for authentication protocols. You can use --disable-strong-random to use of a built-in
+pseudo random number generator, but that may be insecure." "$LINENO" 5
+ fi
+
+$as_echo "#define HAVE_STRONG_RANDOM 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: weak builtin PRNG" >&5
+$as_echo "weak builtin PRNG" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+*** Not using a strong random number source may be insecure." >&5
+$as_echo "$as_me: WARNING:
+*** Not using a strong random number source may be insecure." >&2;}
+fi
+
# If not set in template file, set bytes to use libc memset()
if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
MEMSET_LOOP_LIMIT=1024
PGAC_ARG_BOOL(enable, atomics, yes,
[do not use atomic operations])
+#
+# Random number generation
+#
+PGAC_ARG_BOOL(enable, strong-random, yes,
+ [do not use a strong random number source])
+AC_SUBST(enable_strong_random)
+
#
# --enable-debug adds -g to compiler flags
#
SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
fi
+# Select random number source
+#
+# You can override this logic by setting the appropriate USE_*RANDOM flag to 1
+# in the template or configure command line.
+
+# If not selected manually, try to select a source automatically.
+if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then
+ if test x"$with_openssl" = x"yes" ; then
+ USE_OPENSSL_RANDOM=1
+ elif test "$PORTNAME" = x"win32" ; then
+ USE_WIN32_RANDOM=1
+ else
+ AC_CHECK_FILE([/dev/urandom], [], [])
+
+ if test x"$ac_cv_file__dev_urandom" = x"yes" ; then
+ USE_DEV_URANDOM=1
+ fi
+ fi
+fi
+
+AC_MSG_CHECKING([which random number source to use])
+if test "$enable_strong_random" = yes ; then
+ if test x"$USE_OPENSSL_RANDOM" = x"1" ; then
+ AC_DEFINE(USE_OPENSSL_RANDOM, 1, [Define to use OpenSSL for random number generation])
+ AC_MSG_RESULT([OpenSSL])
+ 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_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,
+for authentication protocols. You can use --disable-strong-random to use of a built-in
+pseudo random number generator, but that may be insecure.])
+ fi
+ AC_DEFINE(HAVE_STRONG_RANDOM, 1, [Define to use have a strong random number source])
+else
+ AC_MSG_RESULT([weak builtin PRNG])
+ AC_MSG_WARN([
+*** Not using a strong random number source may be insecure.])
+fi
+
# If not set in template file, set bytes to use libc memset()
if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
MEMSET_LOOP_LIMIT=1024
# contrib/pgcrypto/Makefile
INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \
- fortuna.c random.c pgp-mpi-internal.c imath.c
+ pgp-mpi-internal.c imath.c
INT_TESTS = sha2
OSSL_SRCS = openssl.c pgp-mpi-openssl.c
--- /dev/null
+--
+-- PGP compression support
+--
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+
+ww0ECQMCsci6AdHnELlh0kQB4jFcVwHMJg0Bulop7m3Mi36s15TAhBo0AnzIrRFrdLVCkKohsS6+
+DMcmR53SXfLoDJOv/M8uKj3QSq7oWNIp95pxfA==
+=tbSn
+-----END PGP MESSAGE-----
+'), 'key', 'expect-compress-algo=1');
+ pgp_sym_decrypt
+-----------------
+ Secret message
+(1 row)
+
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret message', 'key', 'compress-algo=0'),
+ 'key', 'expect-compress-algo=0');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret message', 'key', 'compress-algo=1'),
+ 'key', 'expect-compress-algo=1');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret message', 'key', 'compress-algo=2'),
+ 'key', 'expect-compress-algo=2');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- level=0 should turn compression off
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret message', 'key',
+ 'compress-algo=2, compress-level=0'),
+ 'key', 'expect-compress-algo=0');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
--- /dev/null
+--
+-- pgp_descrypt tests
+--
+-- Checking ciphers
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.blowfish.sha1.mdc.s2k3.z0
+
+jA0EBAMCfFNwxnvodX9g0jwB4n4s26/g5VmKzVab1bX1SmwY7gvgvlWdF3jKisvS
+yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE=
+=JcP+
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCci97v0Q6Z0Zg0kQBsVf5Oe3iC+FBzUmuMV9KxmAyOMyjCc/5i8f1Eest
+UTAsG35A1vYs02VARKzGz6xI2UHwFUirP+brPBg3Ee7muOx8pA==
+=XtrP
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes192.sha1.mdc.s2k3.z0
+
+jA0ECAMCI7YQpWqp3D1g0kQBCjB7GlX7+SQeXNleXeXQ78ZAPNliquGDq9u378zI
+5FPTqAhIB2/2fjY8QEIs1ai00qphjX2NitxV/3Wn+6dufB4Q4g==
+=rCZt
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes256.sha1.mdc.s2k3.z0
+
+jA0ECQMC4f/5djqCC1Rg0kQBTHEPsD+Sw7biBsM2er3vKyGPAQkuTBGKC5ie7hT/
+lceMfQdbAg6oTFyJpk/wH18GzRDphCofg0X8uLgkAKMrpcmgog==
+=fB6S
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+-- Checking MDC modes
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.nomdc.s2k3.z0
+
+jA0EBwMCnv07rlXqWctgyS2Dm2JfOKCRL4sLSLJUC8RS2cH7cIhKSuLitOtyquB+
+u9YkgfJfsuRJmgQ9tmo=
+=60ui
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCEeP3idNjQ1Bg0kQBf4G0wX+2QNzLh2YNwYkQgQkfYhn/hLXjV4nK9nsE
+8Ex1Dsdt5UPvOz8W8VKQRS6loOfOe+yyXil8W3IYFwUpdDUi+Q==
+=moGf
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+-- Checking hashes
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.md5.mdc.s2k3.z0
+
+jA0EBwMClrXXtOXetohg0kQBn0Kl1ymevQZRHkdoYRHgzCwSQEiss7zYff2UNzgO
+KyRrHf7zEBuZiZ2AG34jNVMOLToj1jJUg5zTSdecUzQVCykWTA==
+=NyLk
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCApbdlrURoWJg0kQBzHM/E0o7djY82bNuspjxjAcPFrrtp0uvDdMQ4z2m
+/PM8jhgI5vxFYfNQjLl8y3fHYIomk9YflN9K/Q13iq8A8sjeTw==
+=FxbQ
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+-- Checking S2K modes
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k0.z0
+
+jAQEBwAC0kQBKTaLAKE3xzps+QIZowqRNb2eAdzBw2LxEW2YD5PgNlbhJdGg+dvw
+Ah9GXjGS1TVALzTImJbz1uHUZRfhJlFbc5yGQw==
+=YvkV
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k1.z0
+
+jAwEBwEC/QTByBLI3b/SRAHPxKzI6SZBo5lAEOD+EsvKQWO4adL9tDY+++Iqy1xK
+4IaWXVKEj9R2Lr2xntWWMGZtcKtjD2lFFRXXd9dZp1ZThNDz
+=dbXm
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCEq4Su3ZqNEJg0kQB4QG5jBTKF0i04xtH+avzmLhstBNRxvV3nsmB3cwl
+z+9ZaA/XdSx5ZiFnMym8P6r8uY9rLjjNptvvRHlxIReF+p9MNg==
+=VJKg
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes192.sha1.mdc.s2k0.z0
+
+jAQECAAC0kQBBDnQWkgsx9YFaqDfWmpsiyAJ6y2xG/sBvap1dySYEMuZ+wJTXQ9E
+Cr3i2M7TgVZ0M4jp4QL0adG1lpN5iK7aQeOwMw==
+=cg+i
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes192.sha1.mdc.s2k1.z0
+
+jAwECAECruOfyNDFiTnSRAEVoGXm4A9UZKkWljdzjEO/iaE7mIraltIpQMkiqCh9
+7h8uZ2u9uRBOv222fZodGvc6bvq/4R4hAa/6qSHtm8mdmvGt
+=aHmC
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes192.sha1.mdc.s2k3.z0
+
+jA0ECAMCjFn6SRi3SONg0kQBqtSHPaD0m7rXfDAhCWU/ypAsI93GuHGRyM99cvMv
+q6eF6859ZVnli3BFSDSk3a4e/pXhglxmDYCfjAXkozKNYLo6yw==
+=K0LS
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes256.sha1.mdc.s2k0.z0
+
+jAQECQAC0kQB4L1eMbani07XF2ZYiXNK9LW3v8w41oUPl7dStmrJPQFwsdxmrDHu
+rQr3WbdKdY9ufjOE5+mXI+EFkSPrF9rL9NCq6w==
+=RGts
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes256.sha1.mdc.s2k1.z0
+
+jAwECQECKHhrou7ZOIXSRAHWIVP+xjVQcjAVBTt+qh9SNzYe248xFTwozkwev3mO
++KVJW0qhk0An+Y2KF99/bYFl9cL5D3Tl43fC8fXGl3x3m7pR
+=SUrU
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes256.sha1.mdc.s2k3.z0
+
+jA0ECQMCjc8lwZu8Fz1g0kQBkEzjImi21liep5jj+3dAJ2aZFfUkohi8b3n9z+7+
+4+NRzL7cMW2RLAFnJbiqXDlRHMwleeuLN1up2WIxsxtYYuaBjA==
+=XZrG
+-----END PGP MESSAGE-----
+'), 'foobar');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+-- Checking longer passwords
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCx6dBiuqrYNRg0kQBEo63AvA1SCslxP7ayanLf1H0/hlk2nONVhTwVEWi
+tTGup1mMz6Cfh1uDRErUuXpx9A0gdMu7zX0o5XjrL7WGDAZdSw==
+=XKKG
+-----END PGP MESSAGE-----
+'), '0123456789abcdefghij');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCBDvYuS990iFg0kQBW31UK5OiCjWf5x6KJ8qNNT2HZWQCjCBZMU0XsOC6
+CMxFKadf144H/vpoV9GA0f22keQgCl0EsTE4V4lweVOPTKCMJg==
+=gWDh
+-----END PGP MESSAGE-----
+'), '0123456789abcdefghij2jk4h5g2j54khg23h54g2kh54g2khj54g23hj54');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCqXbFafC+ofVg0kQBejyiPqH0QMERVGfmPOjtAxvyG5KDIJPYojTgVSDt
+FwsDabdQUz5O7bgNSnxfmyw1OifGF+W2bIn/8W+0rDf8u3+O+Q==
+=OxOF
+-----END PGP MESSAGE-----
+'), 'x');
+ pgp_sym_decrypt
+-----------------
+ Secret message.
+(1 row)
+
+-- Checking various data
+select encode(digest(pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat1.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCGJ+SpuOysINg0kQBJfSjzsW0x4OVcAyr17O7FBvMTwIGeGcJd99oTQU8
+Xtx3kDqnhUq9Z1fS3qPbi5iNP2A9NxOBxPWz2JzxhydANlgbxg==
+=W/ik
+-----END PGP MESSAGE-----
+'), '0123456789abcdefghij'), 'sha1'), 'hex');
+ encode
+------------------------------------------
+ 0225e3ede6f2587b076d021a189ff60aad67e066
+(1 row)
+
+-- expected: 0225e3ede6f2587b076d021a189ff60aad67e066
+select encode(digest(pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat2.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCvdpDvidNzMxg0jUBvj8eS2+1t/9/zgemxvhtc0fvdKGGbjH7dleaTJRB
+SaV9L04ky1qECNDx3XjnoKLC+H7IOQ==
+=Fxen
+-----END PGP MESSAGE-----
+'), '0123456789abcdefghij'), 'sha1'), 'hex');
+ encode
+------------------------------------------
+ da39a3ee5e6b4b0d3255bfef95601890afd80709
+(1 row)
+
+-- expected: da39a3ee5e6b4b0d3255bfef95601890afd80709
+select encode(digest(pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: dat3.aes.sha1.mdc.s2k3.z0
+
+jA0EBwMCxQvxJZ3G/HRg0lgBeYmTa7/uDAjPyFwSX4CYBgpZWVn/JS8JzILrcWF8
+gFnkUKIE0PSaYFp+Yi1VlRfUtRQ/X/LYNGa7tWZS+4VQajz2Xtz4vUeAEiYFYPXk
+73Hb8m1yRhQK
+=ivrD
+-----END PGP MESSAGE-----
+'), '0123456789abcdefghij'), 'sha1'), 'hex');
+ encode
+------------------------------------------
+ 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c
+(1 row)
+
+-- expected: 5e5c135efc0dd00633efc6dfd6e731ea408a5b4c
+-- Checking CRLF
+select encode(digest(pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: crlf mess
+
+ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms
+a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs
+=mBP9
+-----END PGP MESSAGE-----
+'), 'key', 'convert-crlf=0'), 'sha1'), 'hex');
+ encode
+------------------------------------------
+ 9353062be7720f1446d30b9e75573a4833886784
+(1 row)
+
+-- expected: 9353062be7720f1446d30b9e75573a4833886784
+select encode(digest(pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+Comment: crlf mess
+
+ww0ECQMCt7VAtby6l4Bi0lgB5KMIZiiF/b3CfMfUyY0eDncsGXtkbu1X+l9brjpMP8eJnY79Amms
+a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs
+=mBP9
+-----END PGP MESSAGE-----
+'), 'key', 'convert-crlf=1'), 'sha1'), 'hex');
+ encode
+------------------------------------------
+ 7efefcab38467f7484d6fa43dc86cf5281bd78e2
+(1 row)
+
+-- expected: 7efefcab38467f7484d6fa43dc86cf5281bd78e2
+-- check BUG #11905, problem with messages 6 less than a power of 2.
+select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',65530);
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- expected: true
+-- Negative tests
+-- Decryption with a certain incorrect key yields an apparent Literal Data
+-- packet reporting its content to be binary data. Ciphertext source:
+-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave
+-- rise to that property.
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+
+ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV
+VsxxqLSPzNLAeIspJk5G
+=mSd/
+-----END PGP MESSAGE-----
+'), 'wrong-key', 'debug=1');
+NOTICE: dbg: prefix_init: corrupt prefix
+NOTICE: dbg: parse_literal_data: data type=b
+NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr
+ERROR: Wrong key or corrupt data
+-- Routine text/binary mismatch.
+select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- Decryption with a certain incorrect key yields an apparent BZip2-compressed
+-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key')
+-- until the random prefix gave rise to that property.
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+
+ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP
+GXsd65oYJZp3Khz0qfyn
+=Nmpq
+-----END PGP MESSAGE-----
+'), 'wrong-key', 'debug=1');
+NOTICE: dbg: prefix_init: corrupt prefix
+NOTICE: dbg: parse_compressed_data: bzip2 unsupported
+NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr
+ERROR: Wrong key or corrupt data
+-- Routine use of BZip2 compression. Ciphertext source:
+-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \
+-- --personal-cipher-preferences aes --no-emit-version --batch \
+-- --symmetric --passphrase key --armor
+select pgp_sym_decrypt(dearmor('
+-----BEGIN PGP MESSAGE-----
+
+jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe
+QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R
+UCAAw2JRIISttRHMfDpDuZJpvYo=
+=AZ9M
+-----END PGP MESSAGE-----
+'), 'key', 'debug=1');
+NOTICE: dbg: parse_compressed_data: bzip2 unsupported
+ERROR: Unsupported compression algorithm
--- /dev/null
+--
+-- PGP encrypt
+--
+-- ensure consistent test output regardless of the default bytea format
+SET bytea_output TO escape;
+select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), 'key');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- check whether the defaults are ok
+select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
+ 'key', 'expect-cipher-algo=aes128,
+ expect-disable-mdc=0,
+ expect-sess-key=0,
+ expect-s2k-mode=3,
+ expect-s2k-digest-algo=sha1,
+ expect-compress-algo=0
+ ');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- maybe the expect- stuff simply does not work
+select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
+ 'key', 'expect-cipher-algo=bf,
+ expect-disable-mdc=1,
+ expect-sess-key=1,
+ expect-s2k-mode=0,
+ expect-s2k-digest-algo=md5,
+ expect-compress-algo=1
+ ');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- bytea as text
+select pgp_sym_decrypt(pgp_sym_encrypt_bytea('Binary', 'baz'), 'baz');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- text as bytea
+select pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- algorithm change
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes'),
+ 'key', 'expect-cipher-algo=aes128');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- s2k change
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-mode=0'),
+ 'key', 'expect-s2k-mode=0');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-mode=1'),
+ 'key', 'expect-s2k-mode=1');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'),
+ 'key', 'expect-s2k-mode=3');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- s2k count change
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'),
+ 'key', 'expect-s2k-count=1024');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- s2k_count rounds up
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'),
+ 'key', 'expect-s2k-count=65000000');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- s2k digest change
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
+ 'key', 'expect-s2k-digest-algo=md5');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'),
+ 'key', 'expect-s2k-digest-algo=sha1');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- sess key
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'sess-key=0'),
+ 'key', 'expect-sess-key=0');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'sess-key=1'),
+ 'key', 'expect-sess-key=1');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=bf'),
+ 'key', 'expect-sess-key=1, expect-cipher-algo=bf');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes192'),
+ 'key', 'expect-sess-key=1, expect-cipher-algo=aes192');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes256'),
+ 'key', 'expect-sess-key=1, expect-cipher-algo=aes256');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- no mdc
+select pgp_sym_decrypt(
+ pgp_sym_encrypt('Secret.', 'key', 'disable-mdc=1'),
+ 'key', 'expect-disable-mdc=1');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- crlf
+select encode(pgp_sym_decrypt_bytea(
+ pgp_sym_encrypt(E'1\n2\n3\r\n', 'key', 'convert-crlf=1'),
+ 'key'), 'hex');
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- conversion should be lossless
+select encode(digest(pgp_sym_decrypt(
+ pgp_sym_encrypt(E'\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'),
+ 'key', 'convert-crlf=1'), 'sha1'), 'hex') as result,
+ encode(digest(E'\r\n0\n1\r\r\n\n2\r', 'sha1'), 'hex') as expect;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
--- /dev/null
+--
+-- PGP Public Key Encryption
+--
+-- ensure consistent test output regardless of the default bytea format
+SET bytea_output TO escape;
+-- successful encrypt/decrypt
+select pgp_pub_decrypt(
+ pgp_pub_encrypt('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=1;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_pub_decrypt(
+ pgp_pub_encrypt('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=2;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_pub_decrypt(
+ pgp_pub_encrypt('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=3;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+select pgp_pub_decrypt(
+ pgp_pub_encrypt('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=6;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- try with rsa-sign only
+select pgp_pub_decrypt(
+ pgp_pub_encrypt('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=4;
+ERROR: No encryption key found
+-- try with secret key
+select pgp_pub_decrypt(
+ pgp_pub_encrypt('Secret msg', dearmor(seckey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=1;
+ERROR: Refusing to encrypt with secret key
+-- does text-to-bytea works
+select pgp_pub_decrypt_bytea(
+ pgp_pub_encrypt('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=1;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+-- and bytea-to-text?
+select pgp_pub_decrypt(
+ pgp_pub_encrypt_bytea('Secret msg', dearmor(pubkey)),
+ dearmor(seckey))
+from keytbl where keytbl.id=1;
+ERROR: pg_random_bytes() is not supported by this build
+DETAIL: This functionality requires a source of strong random numbers
+HINT: You need to rebuild PostgreSQL using --enable-strong-random
+++ /dev/null
-/*
- * fortuna.c
- * Fortuna-like PRNG.
- *
- * Copyright (c) 2005 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/fortuna.c
- */
-
-#include "postgres.h"
-
-#include <sys/time.h>
-#include <time.h>
-
-#include "px.h"
-#include "rijndael.h"
-#include "sha2.h"
-#include "fortuna.h"
-
-
-/*
- * Why Fortuna-like: There does not seem to be any definitive reference
- * on Fortuna in the net. Instead this implementation is based on
- * following references:
- *
- * http://en.wikipedia.org/wiki/Fortuna_(PRNG)
- * - Wikipedia article
- * http://jlcooke.ca/random/
- * - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux.
- */
-
-/*
- * There is some confusion about whether and how to carry forward
- * the state of the pools. Seems like original Fortuna does not
- * do it, resetting hash after each request. I guess expecting
- * feeding to happen more often that requesting. This is absolutely
- * unsuitable for pgcrypto, as nothing asynchronous happens here.
- *
- * J.L. Cooke fixed this by feeding previous hash to new re-initialized
- * hash context.
- *
- * Fortuna predecessor Yarrow requires ability to query intermediate
- * 'final result' from hash, without affecting it.
- *
- * This implementation uses the Yarrow method - asking intermediate
- * results, but continuing with old state.
- */
-
-
-/*
- * Algorithm parameters
- */
-
-/*
- * How many pools.
- *
- * Original Fortuna uses 32 pools, that means 32'th pool is
- * used not earlier than in 13th year. This is a waste in
- * pgcrypto, as we have very low-frequancy seeding. Here
- * is preferable to have all entropy usable in reasonable time.
- *
- * With 23 pools, 23th pool is used after 9 days which seems
- * more sane.
- *
- * In our case the minimal cycle time would be bit longer
- * than the system-randomness feeding frequency.
- */
-#define NUM_POOLS 23
-
-/* in microseconds */
-#define RESEED_INTERVAL 100000 /* 0.1 sec */
-
-/* for one big request, reseed after this many bytes */
-#define RESEED_BYTES (1024*1024)
-
-/*
- * Skip reseed if pool 0 has less than this many
- * bytes added since last reseed.
- */
-#define POOL0_FILL (256/8)
-
-/*
- * Algorithm constants
- */
-
-/* Both cipher key size and hash result size */
-#define BLOCK 32
-
-/* cipher block size */
-#define CIPH_BLOCK 16
-
-/* for internal wrappers */
-#define MD_CTX SHA256_CTX
-#define CIPH_CTX rijndael_ctx
-
-struct fortuna_state
-{
- uint8 counter[CIPH_BLOCK];
- uint8 result[CIPH_BLOCK];
- uint8 key[BLOCK];
- MD_CTX pool[NUM_POOLS];
- CIPH_CTX ciph;
- unsigned reseed_count;
- struct timeval last_reseed_time;
- unsigned pool0_bytes;
- unsigned rnd_pos;
- int tricks_done;
-};
-typedef struct fortuna_state FState;
-
-
-/*
- * Use our own wrappers here.
- * - Need to get intermediate result from digest, without affecting it.
- * - Need re-set key on a cipher context.
- * - Algorithms are guaranteed to exist.
- * - No memory allocations.
- */
-
-static void
-ciph_init(CIPH_CTX * ctx, const uint8 *key, int klen)
-{
- rijndael_set_key(ctx, (const uint32 *) key, klen, 1);
-}
-
-static void
-ciph_encrypt(CIPH_CTX * ctx, const uint8 *in, uint8 *out)
-{
- rijndael_encrypt(ctx, (const uint32 *) in, (uint32 *) out);
-}
-
-static void
-md_init(MD_CTX * ctx)
-{
- SHA256_Init(ctx);
-}
-
-static void
-md_update(MD_CTX * ctx, const uint8 *data, int len)
-{
- SHA256_Update(ctx, data, len);
-}
-
-static void
-md_result(MD_CTX * ctx, uint8 *dst)
-{
- SHA256_CTX tmp;
-
- memcpy(&tmp, ctx, sizeof(*ctx));
- SHA256_Final(dst, &tmp);
- px_memset(&tmp, 0, sizeof(tmp));
-}
-
-/*
- * initialize state
- */
-static void
-init_state(FState *st)
-{
- int i;
-
- memset(st, 0, sizeof(*st));
- for (i = 0; i < NUM_POOLS; i++)
- md_init(&st->pool[i]);
-}
-
-/*
- * Endianess does not matter.
- * It just needs to change without repeating.
- */
-static void
-inc_counter(FState *st)
-{
- uint32 *val = (uint32 *) st->counter;
-
- if (++val[0])
- return;
- if (++val[1])
- return;
- if (++val[2])
- return;
- ++val[3];
-}
-
-/*
- * This is called 'cipher in counter mode'.
- */
-static void
-encrypt_counter(FState *st, uint8 *dst)
-{
- ciph_encrypt(&st->ciph, st->counter, dst);
- inc_counter(st);
-}
-
-
-/*
- * The time between reseed must be at least RESEED_INTERVAL
- * microseconds.
- */
-static int
-enough_time_passed(FState *st)
-{
- int ok;
- struct timeval tv;
- struct timeval *last = &st->last_reseed_time;
-
- gettimeofday(&tv, NULL);
-
- /* check how much time has passed */
- ok = 0;
- if (tv.tv_sec > last->tv_sec + 1)
- ok = 1;
- else if (tv.tv_sec == last->tv_sec + 1)
- {
- if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
- ok = 1;
- }
- else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
- ok = 1;
-
- /* reseed will happen, update last_reseed_time */
- if (ok)
- memcpy(last, &tv, sizeof(tv));
-
- px_memset(&tv, 0, sizeof(tv));
-
- return ok;
-}
-
-/*
- * generate new key from all the pools
- */
-static void
-reseed(FState *st)
-{
- unsigned k;
- unsigned n;
- MD_CTX key_md;
- uint8 buf[BLOCK];
-
- /* set pool as empty */
- st->pool0_bytes = 0;
-
- /*
- * Both #0 and #1 reseed would use only pool 0. Just skip #0 then.
- */
- n = ++st->reseed_count;
-
- /*
- * The goal: use k-th pool only 1/(2^k) of the time.
- */
- md_init(&key_md);
- for (k = 0; k < NUM_POOLS; k++)
- {
- md_result(&st->pool[k], buf);
- md_update(&key_md, buf, BLOCK);
-
- if (n & 1 || !n)
- break;
- n >>= 1;
- }
-
- /* add old key into mix too */
- md_update(&key_md, st->key, BLOCK);
-
- /* now we have new key */
- md_result(&key_md, st->key);
-
- /* use new key */
- ciph_init(&st->ciph, st->key, BLOCK);
-
- px_memset(&key_md, 0, sizeof(key_md));
- px_memset(buf, 0, BLOCK);
-}
-
-/*
- * Pick a random pool. This uses key bytes as random source.
- */
-static unsigned
-get_rand_pool(FState *st)
-{
- unsigned rnd;
-
- /*
- * This slightly prefers lower pools - that is OK.
- */
- rnd = st->key[st->rnd_pos] % NUM_POOLS;
-
- st->rnd_pos++;
- if (st->rnd_pos >= BLOCK)
- st->rnd_pos = 0;
-
- return rnd;
-}
-
-/*
- * update pools
- */
-static void
-add_entropy(FState *st, const uint8 *data, unsigned len)
-{
- unsigned pos;
- uint8 hash[BLOCK];
- MD_CTX md;
-
- /* hash given data */
- md_init(&md);
- md_update(&md, data, len);
- md_result(&md, hash);
-
- /*
- * Make sure the pool 0 is initialized, then update randomly.
- */
- if (st->reseed_count == 0)
- pos = 0;
- else
- pos = get_rand_pool(st);
- md_update(&st->pool[pos], hash, BLOCK);
-
- if (pos == 0)
- st->pool0_bytes += len;
-
- px_memset(hash, 0, BLOCK);
- px_memset(&md, 0, sizeof(md));
-}
-
-/*
- * Just take 2 next blocks as new key
- */
-static void
-rekey(FState *st)
-{
- encrypt_counter(st, st->key);
- encrypt_counter(st, st->key + CIPH_BLOCK);
- ciph_init(&st->ciph, st->key, BLOCK);
-}
-
-/*
- * Hide public constants. (counter, pools > 0)
- *
- * This can also be viewed as spreading the startup
- * entropy over all of the components.
- */
-static void
-startup_tricks(FState *st)
-{
- int i;
- uint8 buf[BLOCK];
-
- /* Use next block as counter. */
- encrypt_counter(st, st->counter);
-
- /* Now shuffle pools, excluding #0 */
- for (i = 1; i < NUM_POOLS; i++)
- {
- encrypt_counter(st, buf);
- encrypt_counter(st, buf + CIPH_BLOCK);
- md_update(&st->pool[i], buf, BLOCK);
- }
- px_memset(buf, 0, BLOCK);
-
- /* Hide the key. */
- rekey(st);
-
- /* This can be done only once. */
- st->tricks_done = 1;
-}
-
-static void
-extract_data(FState *st, unsigned count, uint8 *dst)
-{
- unsigned n;
- unsigned block_nr = 0;
-
- /* Should we reseed? */
- if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0)
- if (enough_time_passed(st))
- reseed(st);
-
- /* Do some randomization on first call */
- if (!st->tricks_done)
- startup_tricks(st);
-
- while (count > 0)
- {
- /* produce bytes */
- encrypt_counter(st, st->result);
-
- /* copy result */
- if (count > CIPH_BLOCK)
- n = CIPH_BLOCK;
- else
- n = count;
- memcpy(dst, st->result, n);
- dst += n;
- count -= n;
-
- /* must not give out too many bytes with one key */
- block_nr++;
- if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
- {
- rekey(st);
- block_nr = 0;
- }
- }
- /* Set new key for next request. */
- rekey(st);
-}
-
-/*
- * public interface
- */
-
-static FState main_state;
-static int init_done = 0;
-
-void
-fortuna_add_entropy(const uint8 *data, unsigned len)
-{
- if (!init_done)
- {
- init_state(&main_state);
- init_done = 1;
- }
- if (!data || !len)
- return;
- add_entropy(&main_state, data, len);
-}
-
-void
-fortuna_get_bytes(unsigned len, uint8 *dst)
-{
- if (!init_done)
- {
- init_state(&main_state);
- init_done = 1;
- }
- if (!dst || !len)
- return;
- extract_data(&main_state, len, dst);
-}
+++ /dev/null
-/*
- * fortuna.c
- * Fortuna PRNG.
- *
- * Copyright (c) 2005 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/fortuna.h
- */
-
-#ifndef __FORTUNA_H
-#define __FORTUNA_H
-
-void fortuna_get_bytes(unsigned len, uint8 *dst);
-void fortuna_add_entropy(const uint8 *data, unsigned len);
-
-#endif
#include "sha1.h"
#include "blf.h"
#include "rijndael.h"
-#include "fortuna.h"
/*
* System reseeds should be separated at least this much.
*res = c;
return 0;
}
-
-/*
- * Randomness provider
- */
-
-static time_t seed_time = 0;
-static time_t check_time = 0;
-
-static void
-system_reseed(void)
-{
- uint8 buf[1024];
- int n;
- time_t t;
- int skip = 1;
-
- t = time(NULL);
-
- if (seed_time == 0)
- skip = 0;
- else if ((t - seed_time) < SYSTEM_RESEED_MIN)
- skip = 1;
- else if ((t - seed_time) > SYSTEM_RESEED_MAX)
- skip = 0;
- else if (check_time == 0 ||
- (t - check_time) > SYSTEM_RESEED_CHECK_TIME)
- {
- check_time = t;
-
- /* roll dice */
- 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
-px_get_random_bytes(uint8 *dst, unsigned count)
-{
- system_reseed();
- fortuna_get_bytes(count, dst);
- return 0;
-}
-
-int
-px_add_entropy(const uint8 *data, unsigned count)
-{
- system_reseed();
- fortuna_add_entropy(data, count);
- return 0;
-}
*res = c;
return 0;
}
-
-
-static int openssl_random_init = 0;
-
-/*
- * OpenSSL random should re-feeded occasionally. From /dev/urandom
- * preferably.
- */
-static void
-init_openssl_rand(void)
-{
- if (RAND_get_rand_method() == NULL)
- {
-#ifdef HAVE_RAND_OPENSSL
- RAND_set_rand_method(RAND_OpenSSL());
-#else
- RAND_set_rand_method(RAND_SSLeay());
-#endif
- }
- openssl_random_init = 1;
-}
-
-int
-px_get_random_bytes(uint8 *dst, unsigned count)
-{
- int res;
-
- if (!openssl_random_init)
- init_openssl_rand();
-
- res = RAND_bytes(dst, count);
- if (res == 1)
- return count;
-
- return PXE_OSSL_RAND_ERROR;
-}
-
-int
-px_add_entropy(const uint8 *data, unsigned count)
-{
- /*
- * estimate 0 bits
- */
- RAND_add(data, count, 0);
- return 0;
-}
#include <ctype.h>
#include "parser/scansup.h"
+#include "utils/backend_random.h"
#include "utils/builtins.h"
#include "utils/uuid.h"
Datum
pg_random_bytes(PG_FUNCTION_ARGS)
{
- int err;
+#ifdef HAVE_STRONG_RANDOM
int len = PG_GETARG_INT32(0);
bytea *res;
SET_VARSIZE(res, VARHDRSZ + len);
/* generate result */
- err = px_get_random_bytes((uint8 *) VARDATA(res), len);
- if (err < 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("Random generator error: %s", px_strerror(err))));
+ if (!pg_strong_random(VARDATA(res), len))
+ px_THROW_ERROR(PXE_NO_RANDOM);
PG_RETURN_BYTEA_P(res);
+#else
+ px_THROW_ERROR(PXE_NO_RANDOM);
+#endif
}
/* SQL function: gen_random_uuid() returns uuid */
pg_random_uuid(PG_FUNCTION_ARGS)
{
uint8 *buf = (uint8 *) palloc(UUID_LEN);
- int err;
- /* generate random bits */
- err = px_get_random_bytes(buf, UUID_LEN);
- if (err < 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("Random generator error: %s", px_strerror(err))));
+ /*
+ * Generate random bits. pg_backend_random() will do here, we don't
+ * promis UUIDs to be cryptographically random, when built with
+ * --disable-strong-random.
+ */
+ if (!pg_backend_random((char *) buf, UUID_LEN))
+ px_THROW_ERROR(PXE_NO_RANDOM);
/*
* Set magic numbers for a "version 4" (pseudorandom) UUID, see
#include "px.h"
#include "pgp.h"
+#include "utils/backend_random.h"
+
#define MDC_DIGEST_LEN 20
#define STREAM_ID 0xE0
static int
write_prefix(PGP_Context *ctx, PushFilter *dst)
{
+#ifdef HAVE_STRONG_RANDOM
uint8 prefix[PGP_MAX_BLOCK + 2];
int res,
bs;
bs = pgp_get_cipher_block_size(ctx->cipher_algo);
- res = px_get_random_bytes(prefix, bs);
- if (res < 0)
- return res;
+ if (!pg_backend_random((char *) prefix, bs))
+ return PXE_NO_RANDOM;
prefix[bs + 0] = prefix[bs - 2];
prefix[bs + 1] = prefix[bs - 1];
res = pushf_write(dst, prefix, bs + 2);
px_memset(prefix, 0, bs + 2);
return res < 0 ? res : 0;
+#else
+ return PXE_NO_RANDOM;
+#endif
}
/*
static int
init_sess_key(PGP_Context *ctx)
{
- int res;
-
if (ctx->use_sess_key || ctx->pub_key)
{
+#ifdef HAVE_STRONG_RANDOM
ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
- res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
- if (res < 0)
- return res;
+ if (!pg_strong_random((char *) ctx->sess_key, ctx->sess_key_len))
+ return PXE_NO_RANDOM;
+#else
+ return PXE_NO_RANDOM;
+#endif
}
else
{
static int
mp_px_rand(uint32 bits, mpz_t *res)
{
- int err;
+#ifdef HAVE_STRONG_RANDOM
unsigned bytes = (bits + 7) / 8;
int last_bits = bits & 7;
uint8 *buf;
buf = px_alloc(bytes);
- err = px_get_random_bytes(buf, bytes);
- if (err < 0)
+ if (!pg_strong_random((char *) buf, bytes))
{
px_free(buf);
- return err;
+ return PXE_NO_RANDOM;
}
/* clear unnecessary bits and set last bit to one */
px_free(buf);
return 0;
+#else
+ return PXE_NO_RANDOM;
+#endif
}
static void
PG_FUNCTION_INFO_V1(pg_dearmor);
PG_FUNCTION_INFO_V1(pgp_armor_headers);
-/*
- * Mix a block of data into RNG.
- */
-static void
-add_block_entropy(PX_MD *md, text *data)
-{
- uint8 sha1[20];
-
- px_md_reset(md);
- px_md_update(md, (uint8 *) VARDATA(data), VARSIZE(data) - VARHDRSZ);
- px_md_finish(md, sha1);
-
- px_add_entropy(sha1, 20);
-
- px_memset(sha1, 0, 20);
-}
-
-/*
- * Mix user data into RNG. It is for user own interests to have
- * RNG state shuffled.
- */
-static void
-add_entropy(text *data1, text *data2, text *data3)
-{
- PX_MD *md;
- uint8 rnd[3];
-
- if (!data1 && !data2 && !data3)
- return;
-
- if (px_get_random_bytes(rnd, 3) < 0)
- return;
-
- if (px_find_digest("sha1", &md) < 0)
- return;
-
- /*
- * Try to make the feeding unpredictable.
- *
- * Prefer data over keys, as it's rather likely that key is same in
- * several calls.
- */
-
- /* chance: 7/8 */
- if (data1 && rnd[0] >= 32)
- add_block_entropy(md, data1);
-
- /* chance: 5/8 */
- if (data2 && rnd[1] >= 160)
- add_block_entropy(md, data2);
-
- /* chance: 5/8 */
- if (data3 && rnd[2] >= 160)
- add_block_entropy(md, data3);
-
- px_md_free(md);
- px_memset(rnd, 0, sizeof(rnd));
-}
-
/*
* returns src in case of no conversion or error
*/
VARSIZE(args) - VARHDRSZ, ex);
if (err)
- {
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("%s", px_strerror(err))));
- }
+ px_THROW_ERROR(err);
if (ex->debug)
px_set_debug_handler(show_debug);
struct debug_expect ex;
text *tmp_data = NULL;
- /*
- * Add data and key info RNG.
- */
- add_entropy(data, key, NULL);
-
init_work(&ctx, is_text, args, &ex);
if (is_text && pgp_get_unicode_mode(ctx))
pgp_free(ctx);
mbuf_free(src);
mbuf_free(dst);
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("%s", px_strerror(err))));
+ px_THROW_ERROR(err);
}
/* res_len includes VARHDRSZ */
{
px_set_debug_handler(NULL);
mbuf_free(dst);
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("%s", px_strerror(err))));
+ px_THROW_ERROR(err);
}
res_len = mbuf_steal_data(dst, &restmp);
}
px_set_debug_handler(NULL);
- /*
- * add successful decryptions also into RNG
- */
- add_entropy(res, key, keypsw);
-
return res;
}
ret = pgp_armor_decode((uint8 *) VARDATA(data), data_len, &buf);
if (ret < 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("%s", px_strerror(ret))));
+ px_THROW_ERROR(ret);
res = palloc(VARHDRSZ + buf.len);
SET_VARSIZE(res, VARHDRSZ + buf.len);
memcpy(VARDATA(res), buf.data, buf.len);
&state->nheaders, &state->keys,
&state->values);
if (res < 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("%s", px_strerror(res))));
+ px_THROW_ERROR(res);
MemoryContextSwitchTo(oldcontext);
funcctx->user_fctx = state;
res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
- errmsg("%s", px_strerror(res_len))));
+ px_THROW_ERROR(res_len);
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0);
static int
pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
{
- int res;
+#ifdef HAVE_STRONG_RANDOM
uint8 *buf,
*p;
int pad_len = res_len - 2 - data_len;
buf = px_alloc(res_len);
buf[0] = 0x02;
- res = px_get_random_bytes(buf + 1, pad_len);
- if (res < 0)
+
+ if (!pg_strong_random((char *) buf + 1, pad_len))
{
px_free(buf);
- return res;
+ return PXE_NO_RANDOM;
}
/* pad must not contain zero bytes */
{
if (*p == 0)
{
- res = px_get_random_bytes(p, 1);
- if (res < 0)
+ if (!pg_strong_random((char *) p, 1))
+ {
+ px_memset(buf, 0, res_len);
+ px_free(buf);
break;
+ }
}
if (*p != 0)
p++;
}
- if (res < 0)
- {
- px_memset(buf, 0, res_len);
- px_free(buf);
- return res;
- }
-
buf[pad_len + 1] = 0;
memcpy(buf + pad_len + 2, data, data_len);
*res_p = buf;
return 0;
+
+#else
+ return PXE_NO_RANDOM;
+#endif
}
static int
#include "px.h"
#include "pgp.h"
+#include "utils/backend_random.h"
+
static int
calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
unsigned key_len)
case PGP_S2K_SIMPLE:
break;
case PGP_S2K_SALTED:
- res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT);
+ if (!pg_backend_random((char *) s2k->salt, PGP_S2K_SALT))
+ return PXE_NO_RANDOM;
break;
case PGP_S2K_ISALTED:
- res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT);
- if (res < 0)
- break;
- res = px_get_random_bytes(&tmp, 1);
- if (res < 0)
- break;
+ if (!pg_backend_random((char *) s2k->salt, PGP_S2K_SALT))
+ return PXE_NO_RANDOM;
+ if (!pg_backend_random((char *) &tmp, 1))
+ return PXE_NO_RANDOM;
s2k->iter = decide_s2k_iter(tmp, count);
break;
default:
#include "px.h"
#include "px-crypt.h"
+#include "utils/backend_random.h"
static char *
run_crypt_des(const char *psw, const char *salt,
int
px_gen_salt(const char *salt_type, char *buf, int rounds)
{
- int res;
struct generator *g;
char *p;
char rbuf[16];
return PXE_BAD_SALT_ROUNDS;
}
- res = px_get_random_bytes((uint8 *) rbuf, g->input_len);
- if (res < 0)
- return res;
+ if (!pg_backend_random(rbuf, g->input_len))
+ return PXE_NO_RANDOM;
p = g->gen(rounds, rbuf, g->input_len, buf, PX_MAX_SALT_LEN);
px_memset(rbuf, 0, sizeof(rbuf));
{PXE_CIPHER_INIT, "Cipher cannot be initialized ?"},
{PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
{PXE_DEV_READ_ERROR, "Error reading from random device"},
- {PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"},
{PXE_BUG, "pgcrypto bug"},
{PXE_ARGUMENT_ERROR, "Illegal argument to function"},
{PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
{0, NULL},
};
+/*
+ * Call ereport(ERROR, ...), with an error code and message corresponding to
+ * the PXE_* error code given as argument.
+ *
+ * This is similar to px_strerror(err), but for some errors, we fill in the
+ * error code and detail fields more appropriately.
+ */
+void
+px_THROW_ERROR(int err)
+{
+ if (err == PXE_NO_RANDOM)
+ {
+#ifdef HAVE_STRONG_RANDOM
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("could not generate a random number")));
+#else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("pg_random_bytes() is not supported by this build"),
+ errdetail("This functionality requires a source of strong random numbers"),
+ errhint("You need to rebuild PostgreSQL using --enable-strong-random")));
+#endif
+ }
+ else
+ {
+ /* For other errors, use the message from the above list. */
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+ errmsg("%s", px_strerror(err))));
+ }
+}
+
const char *
px_strerror(int err)
{
#define PXE_CIPHER_INIT -8
#define PXE_HASH_UNUSABLE_FOR_HMAC -9
#define PXE_DEV_READ_ERROR -10
-#define PXE_OSSL_RAND_ERROR -11
#define PXE_BUG -12
#define PXE_ARGUMENT_ERROR -13
#define PXE_UNKNOWN_SALT_ALGO -14
int px_find_cipher(const char *name, PX_Cipher **res);
int px_find_combo(const char *name, PX_Combo **res);
-int px_get_random_bytes(uint8 *dst, unsigned count);
-int px_add_entropy(const uint8 *data, unsigned count);
-
-unsigned px_acquire_system_randomness(uint8 *dst);
-
+void px_THROW_ERROR(int err) pg_attribute_noreturn();
const char *px_strerror(int err);
const char *px_resolve_alias(const PX_Alias *aliases, const char *name);
+++ /dev/null
-/*
- * 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;
-}
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--disable-strong-random</option></term>
+ <listitem>
+ <para>
+ Allow the build to succeed even if <productname>PostgreSQL</>
+ has no support for strong random numbers on the platform.
+ A source of random numbers is needed for some authentication
+ protocols, as well as some routines in <xref linkend="pgcrypto">
+ module. --disable-strong-random disables functionality that
+ requires cryptographically strong random numbers, and substitutes
+ a weak pseudo-random-number-generator for the generation of
+ authentication salt values and query cancel keys. It may make
+ authentication less secure.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--disable-thread-safety</option></term>
<listitem>
enable_coverage = @enable_coverage@
enable_tap_tests = @enable_tap_tests@
enable_thread_safety = @enable_thread_safety@
+enable_strong_random = @enable_strong_random@
python_includespec = @python_includespec@
python_libdir = @python_libdir@
#include "miscadmin.h"
#include "replication/walsender.h"
#include "storage/ipc.h"
+#include "utils/backend_random.h"
/*----------------------------------------------------------------
int extralen);
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);
+
+/*----------------------------------------------------------------
+ * Plaintext password authentication
+ *----------------------------------------------------------------
+ */
+
+static int CheckPasswordAuth(Port *port, char **logdetail);
+
/*----------------------------------------------------------------
* Ident authentication
*----------------------------------------------------------------
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
/* 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);
+ status = CheckMD5Auth(port, &logdetail);
break;
case uaPassword:
- sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
- status = recv_and_check_password_packet(port, &logdetail);
+ status = CheckPasswordAuth(port, &logdetail);
break;
case uaPAM:
*----------------------------------------------------------------
*/
-/*
- * Called when we have sent an authorization request for a password.
- * Get the response and check it.
- * On error, optionally store a detail string at *logdetail.
+static int
+CheckMD5Auth(Port *port, char **logdetail)
+{
+ char md5Salt[4]; /* Password salt */
+ char *passwd;
+ int result;
+
+ pg_backend_random(md5Salt, 4);
+
+ sendAuthRequest(port, AUTH_REQ_MD5, md5Salt, 4);
+
+ passwd = recv_password_packet(port);
+
+ if (passwd == NULL)
+ return STATUS_EOF; /* client wouldn't send password */
+
+ result = md5_crypt_verify(port, port->user_name, passwd, md5Salt, 4, logdetail);
+
+ pfree(passwd);
+
+ return result;
+}
+
+/*----------------------------------------------------------------
+ * Plaintext password authentication
+ *----------------------------------------------------------------
*/
+
static int
-recv_and_check_password_packet(Port *port, char **logdetail)
+CheckPasswordAuth(Port *port, char **logdetail)
{
char *passwd;
int result;
+ sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
+
passwd = recv_password_packet(port);
if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */
- result = md5_crypt_verify(port, port->user_name, passwd, logdetail);
+ result = md5_crypt_verify(port, port->user_name, passwd, NULL, 0, logdetail);
pfree(passwd);
(unsigned int) port->gss->outbuf.length);
sendAuthRequest(port, AUTH_REQ_GSS_CONT,
- port->gss->outbuf.value, port->gss->outbuf.length);
+ port->gss->outbuf.value, port->gss->outbuf.length);
gss_release_buffer(&lmin_s, &port->gss->outbuf);
}
port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
sendAuthRequest(port, AUTH_REQ_GSS_CONT,
- port->gss->outbuf.value, port->gss->outbuf.length);
+ port->gss->outbuf.value, port->gss->outbuf.length);
FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
}
*/
int
md5_crypt_verify(const Port *port, const char *role, char *client_pass,
- char **logdetail)
+ char *md5_salt, int md5_salt_len, char **logdetail)
{
int retval = STATUS_ERROR;
char *shadow_pass,
switch (port->hba->auth_method)
{
case uaMD5:
+ Assert(md5_salt != NULL && md5_salt_len > 0);
crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
if (isMD5(shadow_pass))
{
/* stored password already encrypted, only do salt */
if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
- port->md5Salt,
- sizeof(port->md5Salt), crypt_pwd))
+ md5_salt, md5_salt_len,
+ crypt_pwd))
{
pfree(crypt_pwd);
return STATUS_ERROR;
return STATUS_ERROR;
}
if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
- port->md5Salt,
- sizeof(port->md5Salt),
+ md5_salt, md5_salt_len,
crypt_pwd))
{
pfree(crypt_pwd);
typedef struct bkend
{
pid_t pid; /* process id of backend */
- long cancel_key; /* cancel key for cancels for this backend */
+ int32 cancel_key; /* cancel key for cancels for this backend */
int child_slot; /* PMChildSlot for this backend, if any */
/*
static volatile bool StartWorkerNeeded = true;
static volatile bool HaveCrashedWorker = false;
+#ifndef HAVE_STRONG_RANDOM
/*
- * State for assigning random salts and cancel keys.
+ * State for assigning 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;
+#endif
#ifdef USE_BONJOUR
static DNSServiceRef bonjour_sdref = NULL;
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 bool RandomCancelKey(int32 *cancel_key);
static void signal_child(pid_t pid, int signal);
static bool SignalSomeChildren(int signal, int targets);
static void TerminateChildren(int signal);
InheritableSocket portsocket;
char DataDir[MAXPGPATH];
pgsocket ListenSocket[MAXLISTEN];
- long MyCancelKey;
+ int32 MyCancelKey;
int MyPMChildSlot;
#ifndef WIN32
unsigned long UsedShmemSegID;
* Remember postmaster startup time
*/
PgStartTime = GetCurrentTimestamp();
- /* PostmasterRandom wants its own copy */
+#ifndef HAVE_STRONG_RANDOM
+ /* RandomCancelKey wants its own copy */
gettimeofday(&random_start_time, NULL);
+#endif
/*
* We're ready to rock and roll...
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
*/
* backend will have its own copy in the forked-off process' value of
* MyCancelKey, so that it can transmit the key to the frontend.
*/
- MyCancelKey = PostmasterRandom();
+ if (!RandomCancelKey(&MyCancelKey))
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("could not acquire random number")));
+ return STATUS_ERROR;
+ }
+
bn->cancel_key = MyCancelKey;
/* Pass down canAcceptConnections state */
* generator state. We have to clobber the static random_seed *and* start
* a new random sequence in the random() library function.
*/
+#ifndef HAVE_STRONG_RANDOM
random_seed = 0;
random_start_time.tv_usec = 0;
+#endif
/* slightly hacky way to convert timestamptz into integers */
TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
/*
- * RandomSalt
+ * Generate a random cancel key.
*/
-static void
-RandomSalt(char *salt, int len)
+static bool
+RandomCancelKey(int32 *cancel_key)
{
- long rand;
- int i;
-
+#ifdef HAVE_STRONG_RANDOM
+ return pg_strong_random((char *) cancel_key, sizeof(int32));
+#else
/*
- * 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.
+ * If built with --disable-strong-random, use plain old erand48.
+ *
+ * We cannot use pg_backend_random() in postmaster, because it stores
+ * its state in shared memory.
*/
- for (i = 0; i < len; i++)
- {
- rand = PostmasterRandom();
- salt[i] = (rand % 255) + 1;
- }
-}
+ static unsigned short seed[3];
-/*
- * 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;
+ struct timeval random_stop_time;
- gettimeofday(&random_stop_time, NULL);
+ 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);
+ seed[0] = (unsigned short) random_start_time.tv_usec;
+ seed[1] = (unsigned short) (random_stop_time.tv_usec) ^ (random_start_time.tv_usec >> 16);
+ seed[2] = (unsigned short) (random_stop_time.tv_usec >> 16);
- srandom(random_seed);
+ random_seed = 1;
}
- return random();
+ *cancel_key = pg_jrand48(seed);
+
+ return true;
+#endif
}
/*
*/
if (canAcceptConnections() == CAC_OK)
{
+ /*
+ * Compute the cancel key that will be assigned to this session.
+ * We probably don't need cancel keys for autovac workers, but
+ * we'd better have something random in the field to prevent
+ * unfriendly people from sending cancels to them.
+ */
+ if (!RandomCancelKey(&MyCancelKey))
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("could not acquire random number")));
+ return;
+ }
+
bn = (Backend *) malloc(sizeof(Backend));
if (bn)
{
- /*
- * Compute the cancel key that will be assigned to this session.
- * We probably don't need cancel keys for autovac workers, but
- * we'd better have something random in the field to prevent
- * unfriendly people from sending cancels to them.
- */
- MyCancelKey = PostmasterRandom();
bn->cancel_key = MyCancelKey;
/* Autovac workers are not dead_end and need a child slot */
static bool
assign_backendlist_entry(RegisteredBgWorker *rw)
{
- Backend *bn = malloc(sizeof(Backend));
+ Backend *bn;
+ /*
+ * Compute the cancel key that will be assigned to this session. We
+ * probably don't need cancel keys for background workers, but we'd better
+ * have something random in the field to prevent unfriendly people from
+ * sending cancels to them.
+ */
+ if (!RandomCancelKey(&MyCancelKey))
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("could not acquire random number")));
+
+ rw->rw_crashed_at = GetCurrentTimestamp();
+ return false;
+ }
+
+ bn = malloc(sizeof(Backend));
if (bn == NULL)
{
ereport(LOG,
return false;
}
- /*
- * Compute the cancel key that will be assigned to this session. We
- * probably don't need cancel keys for background workers, but we'd better
- * have something random in the field to prevent unfriendly people from
- * sending cancels to them.
- */
- MyCancelKey = PostmasterRandom();
bn->cancel_key = MyCancelKey;
-
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
bn->bkend_type = BACKEND_TYPE_BGWORKER;
bn->dead_end = false;
#include "storage/procsignal.h"
#include "storage/sinvaladt.h"
#include "storage/spin.h"
+#include "utils/backend_random.h"
#include "utils/snapmgr.h"
size = add_size(size, BTreeShmemSize());
size = add_size(size, SyncScanShmemSize());
size = add_size(size, AsyncShmemSize());
+ size = add_size(size, BackendRandomShmemSize());
#ifdef EXEC_BACKEND
size = add_size(size, ShmemBackendArraySize());
#endif
BTreeShmemInit();
SyncScanShmemInit();
AsyncShmemInit();
+ BackendRandomShmemInit();
#ifdef EXEC_BACKEND
ReplicationOriginLock 40
MultiXactTruncationLock 41
OldSnapshotTimeMapLock 42
+BackendRandomLock 43
int MyProcPid;
pg_time_t MyStartTime;
struct Port *MyProcPort;
-long MyCancelKey;
+int32 MyCancelKey;
int MyPMChildSlot;
/*
override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
-OBJS = guc.o help_config.o pg_config.o pg_controldata.o pg_rusage.o \
- ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o
+OBJS = backend_random.o guc.o help_config.o pg_config.o pg_controldata.o \
+ pg_rusage.o ps_status.o rls.o sampling.o superuser.o timeout.o \
+ tzparser.o
# This location might depend on the installation directories. Therefore
# we can't subsitute it into pg_config.h.
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * backend_random.c
+ * Backend random number generation routine.
+ *
+ * pg_backend_random() function fills a buffer with random bytes. Normally,
+ * it is just a thin wrapper around pg_strong_random(), but when compiled
+ * with --disable-strong-random, we provide a built-in implementation.
+ *
+ * This function is used for generating nonces in authentication, and for
+ * random salt generation in pgcrypto. The built-in implementation is not
+ * cryptographically strong, but if the user asked for it, we'll go ahead
+ * and use it anyway.
+ *
+ * The built-in implementation uses the standard erand48 algorithm, with
+ * a seed shared between all backends.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/utils/misc/backend_random.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <sys/time.h>
+
+#include "miscadmin.h"
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
+#include "utils/backend_random.h"
+#include "utils/timestamp.h"
+
+#ifdef HAVE_STRONG_RANDOM
+
+Size
+BackendRandomShmemSize(void)
+{
+ return 0;
+}
+
+void
+BackendRandomShmemInit(void)
+{
+ /* do nothing */
+}
+
+bool
+pg_backend_random(char *dst, int len)
+{
+ /* should not be called in postmaster */
+ Assert (IsUnderPostmaster || !IsPostmasterEnvironment);
+
+ return pg_strong_random(dst, len);
+}
+
+#else
+
+/*
+ * Seed for the PRNG, stored in shared memory.
+ *
+ * Protected by BackendRandomLock.
+ */
+typedef struct
+{
+ bool initialized;
+ unsigned short seed[3];
+} BackendRandomShmemStruct;
+
+static BackendRandomShmemStruct *BackendRandomShmem;
+
+Size
+BackendRandomShmemSize(void)
+{
+ return sizeof(BackendRandomShmemStruct);
+}
+
+void
+BackendRandomShmemInit(void)
+{
+ bool found;
+
+ BackendRandomShmem = (BackendRandomShmemStruct *)
+ ShmemInitStruct("Backend PRNG state",
+ BackendRandomShmemSize(),
+ &found);
+
+ if (!IsUnderPostmaster)
+ {
+ Assert(!found);
+
+ BackendRandomShmem->initialized = false;
+ }
+ else
+ Assert(found);
+}
+
+bool
+pg_backend_random(char *dst, int len)
+{
+ int i;
+ char *end = dst + len;
+
+ /* should not be called in postmaster */
+ Assert (IsUnderPostmaster || !IsPostmasterEnvironment);
+
+ LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE);
+
+ /*
+ * Seed the PRNG on the first use.
+ */
+ if (!BackendRandomShmem->initialized)
+ {
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ BackendRandomShmem->seed[0] = now.tv_sec;
+ BackendRandomShmem->seed[1] = (unsigned short) (now.tv_usec);
+ BackendRandomShmem->seed[2] = (unsigned short) (now.tv_usec >> 16);
+
+ /*
+ * Mix in the cancel key, generated by the postmaster. This adds
+ * what little entropy the postmaster had to the seed.
+ */
+ BackendRandomShmem->seed[0] ^= (MyCancelKey);
+ BackendRandomShmem->seed[1] ^= (MyCancelKey >> 16);
+
+ BackendRandomShmem->initialized = true;
+ }
+
+ for (i = 0; dst < end; i++)
+ {
+ uint32 r;
+ int j;
+
+ /*
+ * pg_jrand48 returns a 32-bit integer. Fill the next 4 bytes from it.
+ */
+ r = (uint32) pg_jrand48(BackendRandomShmem->seed);
+
+ for (j = 0; j < 4 && dst < end; j++)
+ {
+ *(dst++) = (char) (r & 0xFF);
+ r >>= 8;
+ }
+ }
+ LWLockRelease(BackendRandomLock);
+
+ return true;
+}
+
+
+#endif /* HAVE_STRONG_RANDOM */
#include "libpq/libpq-be.h"
extern int md5_crypt_verify(const Port *port, const char *role,
- char *client_pass, char **logdetail);
+ char *client_pass, char *md5_salt, int md5_salt_len, char **logdetail);
#endif
* Information that needs to be held during the authentication cycle.
*/
HbaLine *hba;
- char md5Salt[4]; /* Password salt */
/*
* Information that really has no business at all being in struct Port,
extern PGDLLIMPORT pg_time_t MyStartTime;
extern PGDLLIMPORT struct Port *MyProcPort;
extern PGDLLIMPORT struct Latch *MyLatch;
-extern long MyCancelKey;
+extern int32 MyCancelKey;
extern int MyPMChildSlot;
extern char OutputFileName[];
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
+/* Define to use have a strong random number source */
+#undef HAVE_STRONG_RANDOM
+
/* Define to 1 if you have the `strtoll' function. */
#undef HAVE_STRTOLL
/* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */
#undef USE_BSD_AUTH
+/* Define to use /dev/urandom for random number generation */
+#undef USE_DEV_URANDOM
+
/* Define to 1 if you want float4 values to be passed by value.
(--enable-float4-byval) */
#undef USE_FLOAT4_BYVAL
/* Define to build with OpenSSL support. (--with-openssl) */
#undef USE_OPENSSL
+/* Define to use OpenSSL for random number generation */
+#undef USE_OPENSSL_RANDOM
+
/* Define to 1 to build with PAM support. (--with-pam) */
#undef USE_PAM
/* Define to select unnamed POSIX semaphores. */
#undef USE_UNNAMED_POSIX_SEMAPHORES
+/* Define to use native Windows API for random number generation */
+#undef USE_WIN32_RANDOM
+
/* Define to select Win32-style semaphores. */
#undef USE_WIN32_SEMAPHORES
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
+/* Define to use have a strong random number source */
+#define HAVE_STRONG_RANDOM 1
+
/* Define to 1 if you have the `strtoll' function. */
//#define HAVE_STRTOLL 1
/* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */
/* #undef USE_BSD_AUTH */
+/* Define to use /dev/urandom for random number generation */
+/* #undef USE_DEV_URANDOM */
+
/* Define to 1 if you want 64-bit integer timestamp and interval support.
(--enable-integer-datetimes) */
/* #undef USE_INTEGER_DATETIMES */
/* Define to build with OpenSSL support. (--with-openssl) */
/* #undef USE_OPENSSL */
+/* Define to use OpenSSL for random number generation */
+/* #undef USE_OPENSSL_RANDOM */
+
/* Define to 1 to build with PAM support. (--with-pam) */
/* #undef USE_PAM */
/* Define to select unnamed POSIX semaphores. */
/* #undef USE_UNNAMED_POSIX_SEMAPHORES */
+/* Define to use native Windows API for random number generation */
+#define USE_WIN32_RANDOM 1
+
/* Define to select Win32-style semaphores. */
#define USE_WIN32_SEMAPHORES 1
extern double pg_erand48(unsigned short xseed[3]);
extern long pg_lrand48(void);
+extern long pg_jrand48(unsigned short xseed[3]);
extern void pg_srand48(long seed);
#ifndef HAVE_FLS
extern char *inet_net_ntop(int af, const void *src, int bits,
char *dst, size_t size);
+/* port/pg_strong_random.c */
+#ifdef HAVE_STRONG_RANDOM
+extern bool pg_strong_random(void *buf, size_t len);
+#endif
+
/* port/pgcheckdir.c */
extern int pg_check_dir(const char *dir);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * backend_random.h
+ * Declarations for backend random number generation
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ *
+ * src/include/utils/backend_random.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef BACKEND_RANDOM_H
+#define BACKEND_RANDOM_H
+
+extern Size BackendRandomShmemSize(void);
+extern void BackendRandomShmemInit(void);
+extern bool pg_backend_random(char *dst, int len);
+
+#endif /* BACKEND_RANDOM_H */
pgstrcasecmp.o pqsignal.o \
qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
+ifeq ($(enable_strong_random), yes)
+OBJS += pg_strong_random.o
+endif
+
# foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
OBJS_SRV = $(OBJS:%.o=%_srv.o)
return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
}
+long
+pg_jrand48(unsigned short xseed[3])
+{
+ _dorand48(xseed);
+ return ((long) xseed[2] << 16) + ((long) xseed[1]);
+}
+
void
pg_srand48(long seed)
{
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_strong_random.c
+ * generate a cryptographically secure random number
+ *
+ * Our definition of "strong" is that it's suitable for generating random
+ * salts and query cancellation keys, during authentication.
+ *
+ * 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>
+#include <sys/time.h>
+
+#ifdef USE_OPENSSL
+#include <openssl/rand.h>
+#endif
+#ifdef WIN32
+#include <Wincrypt.h>
+#endif
+
+#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
+
+#if defined(USE_DEV_URANDOM)
+/*
+ * 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;
+}
+#endif
+
+/*
+ * pg_strong_random
+ *
+ * Generate requested number of random bytes. The returned bytes are
+ * cryptographically secure, suitable for use e.g. in authentication.
+ *
+ * We rely on system facilities for actually generating the numbers.
+ * We support a number of sources:
+ *
+ * 1. OpenSSL's RAND_bytes()
+ * 2. Windows' CryptGenRandom() function
+ * 3. /dev/urandom
+ *
+ * The configure script will choose which one to use, and set
+ * a USE_*_RANDOM flag accordingly.
+ *
+ * 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)
+{
+ /*
+ * When built with OpenSSL, use OpenSSL's RAND_bytes function.
+ */
+#if defined(USE_OPENSSL_RANDOM)
+ if (RAND_bytes(buf, len) == 1)
+ return true;
+ return false;
+
+ /*
+ * Windows has CryptoAPI for strong cryptographic numbers.
+ */
+#elif defined(USE_WIN32_RANDOM)
+ 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;
+ }
+ return false;
+
+ /*
+ * Read /dev/urandom ourselves.
+ */
+#elif defined(USE_DEV_URANDOM)
+ if (random_from_file("/dev/urandom", buf, len))
+ return true;
+ return false;
+
+#else
+ /* The autoconf script should not have allowed this */
+#error no source of random numbers configured
+#endif
+}
chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
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 qsort.c qsort_arg.c quotes.c system.c
+ pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
+ pqsignal.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);
'sha1.c', 'sha2.c',
'internal.c', 'internal-sha2.c',
'blf.c', 'rijndael.c',
- 'fortuna.c', 'random.c',
'pgp-mpi-internal.c', 'imath.c');
}
$pgcrypto->AddReference($postgres);