Re: Allow tests to pass in OpenSSL FIPS mode - Mailing list pgsql-hackers

From Tom Lane
Subject Re: Allow tests to pass in OpenSSL FIPS mode
Date
Msg-id 2766054.1700080156@sss.pgh.pa.us
Whole thread Raw
In response to Re: Allow tests to pass in OpenSSL FIPS mode  (Daniel Gustafsson <daniel@yesql.se>)
Responses Re: Allow tests to pass in OpenSSL FIPS mode
List pgsql-hackers
Daniel Gustafsson <daniel@yesql.se> writes:
> Since the 3DES/DES deprecations aren't limited to FIPS, do we want to do
> anything for pgcrypto where we have DES/3DES encryption?  Maybe a doc patch
> which mentions the deprecation with a link to the SP could be in order?

A docs patch that marks both MD5 and 3DES as deprecated is probably
appropriate, but it seems like a matter for a separate thread and patch.

In the meantime, I've done a pass of review of Peter's v4 patches.
v4-0001 is already committed, so that's not considered here.

v4-0002: I think it is worth splitting up contrib/pgcrypto's
pgp-encrypt test, which has only one test case whose output changes,
and a bunch of others that don't.  v5-0002, attached, does it
like that.  It's otherwise the same as v4.

(It might be worth doing something similar for uuid_ossp's test,
but I have not bothered here.  That test script is stable enough
that I'm not too worried about future maintenance.)

The attached 0003, 0004, 0005 patches are identical to Peter's.
I think that it is possibly worth modifying the password test so that
we don't fail to create the roles, so as to reduce the delta between
password.out and password_1.out (and thereby ease future maintenance
of those files).  However you might disagree, so I split my proposal
out as a separate patch v5-0007-password-test-delta.patch; you can
drop that from the set if you don't like it.

v5-0006-allow-for-disabled-3DES.patch adds the necessary expected
file to make that pass on my Fedora 38 system.

With or without 0007, as you choose, I think it's committable.

            regards, tom lane

diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index 7fb59f51b7..5efa10c334 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -42,7 +42,7 @@ PGFILEDESC = "pgcrypto - cryptographic functions"
 REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
     sha2 des 3des cast5 \
     crypt-des crypt-md5 crypt-blowfish crypt-xdes \
-    pgp-armor pgp-decrypt pgp-encrypt $(CF_PGP_TESTS) \
+    pgp-armor pgp-decrypt pgp-encrypt pgp-encrypt-md5 $(CF_PGP_TESTS) \
     pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-info

 EXTRA_CLEAN = gen-rtab
diff --git a/contrib/pgcrypto/expected/crypt-md5_1.out b/contrib/pgcrypto/expected/crypt-md5_1.out
new file mode 100644
index 0000000000..0ffda34ab4
--- /dev/null
+++ b/contrib/pgcrypto/expected/crypt-md5_1.out
@@ -0,0 +1,16 @@
+--
+-- crypt() and gen_salt(): md5
+--
+SELECT crypt('', '$1$Szzz0yzz');
+ERROR:  crypt(3) returned NULL
+SELECT crypt('foox', '$1$Szzz0yzz');
+ERROR:  crypt(3) returned NULL
+CREATE TABLE ctest (data text, res text, salt text);
+INSERT INTO ctest VALUES ('password', '', '');
+UPDATE ctest SET salt = gen_salt('md5');
+UPDATE ctest SET res = crypt(data, salt);
+ERROR:  crypt(3) returned NULL
+SELECT res = crypt(data, res) AS "worked"
+FROM ctest;
+ERROR:  invalid salt
+DROP TABLE ctest;
diff --git a/contrib/pgcrypto/expected/hmac-md5_1.out b/contrib/pgcrypto/expected/hmac-md5_1.out
new file mode 100644
index 0000000000..56875b0f63
--- /dev/null
+++ b/contrib/pgcrypto/expected/hmac-md5_1.out
@@ -0,0 +1,44 @@
+--
+-- HMAC-MD5
+--
+SELECT hmac(
+'Hi There',
+'\x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'::bytea,
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+-- 2
+SELECT hmac(
+'Jefe',
+'what do ya want for nothing?',
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+-- 3
+SELECT hmac(
+'\xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'::bytea,
+'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea,
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+-- 4
+SELECT hmac(
+'\xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'::bytea,
+'\x0102030405060708090a0b0c0d0e0f10111213141516171819'::bytea,
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+-- 5
+SELECT hmac(
+'Test With Truncation',
+'\x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'::bytea,
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+-- 6
+SELECT hmac(
+'Test Using Larger Than Block-Size Key - Hash Key First',

+'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea,
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+-- 7
+SELECT hmac(
+'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data',

+'\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'::bytea,
+'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
diff --git a/contrib/pgcrypto/expected/md5_1.out b/contrib/pgcrypto/expected/md5_1.out
new file mode 100644
index 0000000000..decb215c48
--- /dev/null
+++ b/contrib/pgcrypto/expected/md5_1.out
@@ -0,0 +1,17 @@
+--
+-- MD5 message digest
+--
+SELECT digest('', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+SELECT digest('a', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+SELECT digest('abc', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+SELECT digest('message digest', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+SELECT digest('abcdefghijklmnopqrstuvwxyz', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+SELECT digest('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
+SELECT digest('12345678901234567890123456789012345678901234567890123456789012345678901234567890', 'md5');
+ERROR:  Cannot use "md5": Cipher cannot be initialized
diff --git a/contrib/pgcrypto/expected/pgp-encrypt-md5.out b/contrib/pgcrypto/expected/pgp-encrypt-md5.out
new file mode 100644
index 0000000000..339e12a434
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-encrypt-md5.out
@@ -0,0 +1,11 @@
+--
+-- PGP encrypt using MD5
+--
+select pgp_sym_decrypt(
+    pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
+    'key', 'expect-s2k-digest-algo=md5');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
diff --git a/contrib/pgcrypto/expected/pgp-encrypt-md5_1.out b/contrib/pgcrypto/expected/pgp-encrypt-md5_1.out
new file mode 100644
index 0000000000..612ca1d19c
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-encrypt-md5_1.out
@@ -0,0 +1,7 @@
+--
+-- PGP encrypt using MD5
+--
+select pgp_sym_decrypt(
+    pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
+    'key', 'expect-s2k-digest-algo=md5');
+ERROR:  Unsupported digest algorithm
diff --git a/contrib/pgcrypto/expected/pgp-encrypt.out b/contrib/pgcrypto/expected/pgp-encrypt.out
index 77e45abe53..50cd3f6daa 100644
--- a/contrib/pgcrypto/expected/pgp-encrypt.out
+++ b/contrib/pgcrypto/expected/pgp-encrypt.out
@@ -121,14 +121,6 @@ NOTICE:  pgp_decrypt: unexpected s2k_count: expected 65000000 got 65011712
 (1 row)

 -- s2k digest change
-select pgp_sym_decrypt(
-    pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
-    'key', 'expect-s2k-digest-algo=md5');
- pgp_sym_decrypt
------------------
- Secret.
-(1 row)
-
 select pgp_sym_decrypt(
         pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'),
     'key', 'expect-s2k-digest-algo=sha1');
diff --git a/contrib/pgcrypto/meson.build b/contrib/pgcrypto/meson.build
index df7dd50dbc..4f62ea0af0 100644
--- a/contrib/pgcrypto/meson.build
+++ b/contrib/pgcrypto/meson.build
@@ -48,6 +48,7 @@ pgcrypto_regress = [
   'pgp-armor',
   'pgp-decrypt',
   'pgp-encrypt',
+  'pgp-encrypt-md5',
   'pgp-pubkey-decrypt',
   'pgp-pubkey-encrypt',
   'pgp-info',
diff --git a/contrib/pgcrypto/sql/pgp-encrypt-md5.sql b/contrib/pgcrypto/sql/pgp-encrypt-md5.sql
new file mode 100644
index 0000000000..201636c820
--- /dev/null
+++ b/contrib/pgcrypto/sql/pgp-encrypt-md5.sql
@@ -0,0 +1,7 @@
+--
+-- PGP encrypt using MD5
+--
+
+select pgp_sym_decrypt(
+    pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
+    'key', 'expect-s2k-digest-algo=md5');
diff --git a/contrib/pgcrypto/sql/pgp-encrypt.sql b/contrib/pgcrypto/sql/pgp-encrypt.sql
index ed8b17776b..f67329c2c3 100644
--- a/contrib/pgcrypto/sql/pgp-encrypt.sql
+++ b/contrib/pgcrypto/sql/pgp-encrypt.sql
@@ -63,9 +63,6 @@ select pgp_sym_decrypt(
     'key', 'expect-s2k-count=65000000');

 -- s2k digest change
-select pgp_sym_decrypt(
-    pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=md5'),
-    'key', 'expect-s2k-digest-algo=md5');
 select pgp_sym_decrypt(
         pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'),
     'key', 'expect-s2k-digest-algo=sha1');
From 8feace1abca7aad6b9a9a58f464d571649e2d1e2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 5 Oct 2023 14:45:35 +0200
Subject: [PATCH v4 3/5] Allow tests to pass in OpenSSL FIPS mode (TAP tests)

Some tests using md5 authentication have to be skipped.  In other
cases, we can rewrite the tests to use a different authentication
method.
---
 src/test/authentication/t/001_password.pl | 121 ++++++++++++----------
 src/test/ssl/t/002_scram.pl               |  32 +++---
 2 files changed, 86 insertions(+), 67 deletions(-)

diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl
index 891860886a..884f44d45d 100644
--- a/src/test/authentication/t/001_password.pl
+++ b/src/test/authentication/t/001_password.pl
@@ -66,24 +66,26 @@ sub test_conn
 $node->append_conf('postgresql.conf', "log_connections = on\n");
 $node->start;

+my $md5_works = ($node->psql('postgres', "select md5('')") == 0);
+
 # Create 3 roles with different password methods for each one. The same
 # password is used for all of them.
-$node->safe_psql('postgres',
+is($node->psql('postgres',
     "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"
-);
-$node->safe_psql('postgres',
+), 0, 'created user with scram password');
+is($node->psql('postgres',
     "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';"
-);
+), $md5_works ? 0 : 3, 'created user with md5 password');
 # Set up a table for tests of SYSTEM_USER.
 $node->safe_psql(
     'postgres',
     "CREATE TABLE sysuser_data (n) AS SELECT NULL FROM generate_series(1, 10);
-     GRANT ALL ON sysuser_data TO md5_role;");
+     GRANT ALL ON sysuser_data TO scram_role;");
 $ENV{"PGPASSWORD"} = 'pass';

 # Create a role that contains a comma to stress the parsing.
 $node->safe_psql('postgres',
-    q{SET password_encryption='md5'; CREATE ROLE "md5,role" LOGIN PASSWORD 'pass';}
+    q{SET password_encryption='scram-sha-256'; CREATE ROLE "scram,role" LOGIN PASSWORD 'pass';}
 );

 # Create a role with a non-default iteration count
@@ -141,8 +143,11 @@ sub test_conn
 test_conn($node, 'user=scram_role', 'trust', 0,
     log_like =>
       [qr/connection authenticated: user="scram_role" method=trust/]);
-test_conn($node, 'user=md5_role', 'trust', 0,
-    log_like => [qr/connection authenticated: user="md5_role" method=trust/]);
+SKIP: {
+    skip "MD5 not supported" unless $md5_works;
+    test_conn($node, 'user=md5_role', 'trust', 0,
+        log_like => [qr/connection authenticated: user="md5_role" method=trust/]);
+}

 # SYSTEM_USER is null when not authenticated.
 $res = $node->safe_psql('postgres', "SELECT SYSTEM_USER IS NULL;");
@@ -157,7 +162,7 @@ sub test_conn
         SET max_parallel_workers_per_gather TO 2;

         SELECT bool_and(SYSTEM_USER IS NOT DISTINCT FROM n) FROM sysuser_data;),
-    connstr => "user=md5_role");
+    connstr => "user=scram_role");
 is($res, 't',
     "users with trust authentication use SYSTEM_USER = NULL in parallel workers"
 );
@@ -275,9 +280,12 @@ sub test_conn
 test_conn($node, 'user=scram_role', 'password', 0,
     log_like =>
       [qr/connection authenticated: identity="scram_role" method=password/]);
-test_conn($node, 'user=md5_role', 'password', 0,
-    log_like =>
-      [qr/connection authenticated: identity="md5_role" method=password/]);
+SKIP: {
+    skip "MD5 not supported" unless $md5_works;
+    test_conn($node, 'user=md5_role', 'password', 0,
+        log_like =>
+          [qr/connection authenticated: identity="md5_role" method=password/]);
+}

 # require_auth succeeds here with a plaintext password.
 $node->connect_ok("user=scram_role require_auth=password",
@@ -393,59 +401,62 @@ sub test_conn
 test_conn($node, 'user=scram_role', 'md5', 0,
     log_like =>
       [qr/connection authenticated: identity="scram_role" method=md5/]);
-test_conn($node, 'user=md5_role', 'md5', 0,
-    log_like =>
-      [qr/connection authenticated: identity="md5_role" method=md5/]);
+SKIP: {
+    skip "MD5 not supported" unless $md5_works;
+    test_conn($node, 'user=md5_role', 'md5', 0,
+        log_like =>
+          [qr/connection authenticated: identity="md5_role" method=md5/]);
+}

-# require_auth succeeds with MD5 required.
-$node->connect_ok("user=md5_role require_auth=md5",
-    "MD5 authentication required, works with MD5 auth");
-$node->connect_ok("user=md5_role require_auth=!none",
-    "any authentication required, works with MD5 auth");
+# require_auth succeeds with SCRAM required.
+$node->connect_ok("user=scram_role require_auth=scram-sha-256",
+    "SCRAM authentication required, works with SCRAM auth");
+$node->connect_ok("user=scram_role require_auth=!none",
+    "any authentication required, works with SCRAM auth");
 $node->connect_ok(
-    "user=md5_role require_auth=md5,scram-sha-256,password",
-    "multiple authentication types required, works with MD5 auth");
+    "user=scram_role require_auth=md5,scram-sha-256,password",
+    "multiple authentication types required, works with SCRAM auth");

 # Authentication fails if other types are required.
 $node->connect_fails(
-    "user=md5_role require_auth=password",
-    "password authentication required, fails with MD5 auth",
+    "user=scram_role require_auth=password",
+    "password authentication required, fails with SCRAM auth",
     expected_stderr =>
-      qr/authentication method requirement "password" failed: server requested a hashed password/
+      qr/authentication method requirement "password" failed: server requested SASL authentication/
 );
 $node->connect_fails(
-    "user=md5_role require_auth=scram-sha-256",
-    "SCRAM authentication required, fails with MD5 auth",
+    "user=scram_role require_auth=md5",
+    "MD5 authentication required, fails with SCRAM auth",
     expected_stderr =>
-      qr/authentication method requirement "scram-sha-256" failed: server requested a hashed password/
+      qr/authentication method requirement "md5" failed: server requested SASL authentication/
 );
 $node->connect_fails(
-    "user=md5_role require_auth=none",
-    "all authentication types forbidden, fails with MD5 auth",
+    "user=scram_role require_auth=none",
+    "all authentication types forbidden, fails with SCRAM auth",
     expected_stderr =>
-      qr/authentication method requirement "none" failed: server requested a hashed password/
+      qr/authentication method requirement "none" failed: server requested SASL authentication/
 );

-# Authentication fails if MD5 is forbidden.
+# Authentication fails if SCRAM is forbidden.
 $node->connect_fails(
-    "user=md5_role require_auth=!md5",
-    "password authentication forbidden, fails with MD5 auth",
+    "user=scram_role require_auth=!scram-sha-256",
+    "password authentication forbidden, fails with SCRAM auth",
     expected_stderr =>
-      qr/authentication method requirement "!md5" failed: server requested a hashed password/
+      qr/authentication method requirement "!scram-sha-256" failed: server requested SASL authentication/
 );
 $node->connect_fails(
-    "user=md5_role require_auth=!password,!md5,!scram-sha-256",
-    "multiple authentication types forbidden, fails with MD5 auth",
+    "user=scram_role require_auth=!password,!md5,!scram-sha-256",
+    "multiple authentication types forbidden, fails with SCRAM auth",
     expected_stderr =>
-      qr/authentication method requirement "!password,!md5,!scram-sha-256" failed: server requested a hashed password/
+      qr/authentication method requirement "!password,!md5,!scram-sha-256" failed: server requested SASL
authentication/
 );

 # Test SYSTEM_USER <> NULL with parallel workers.
 $node->safe_psql(
     'postgres',
     "TRUNCATE sysuser_data;
-INSERT INTO sysuser_data SELECT 'md5:md5_role' FROM generate_series(1, 10);",
-    connstr => "user=md5_role");
+INSERT INTO sysuser_data SELECT 'md5:scram_role' FROM generate_series(1, 10);",
+    connstr => "user=scram_role");
 $res = $node->safe_psql(
     'postgres', qq(
         SET min_parallel_table_scan_size TO 0;
@@ -454,7 +465,7 @@ sub test_conn
         SET max_parallel_workers_per_gather TO 2;

         SELECT bool_and(SYSTEM_USER IS NOT DISTINCT FROM n) FROM sysuser_data;),
-    connstr => "user=md5_role");
+    connstr => "user=scram_role");
 is($res, 't',
     "users with md5 authentication use SYSTEM_USER = md5:role in parallel workers"
 );
@@ -490,49 +501,49 @@ sub test_conn

 append_to_file(
     $pgpassfile, qq!
-*:*:*:md5_role:p\\ass
-*:*:*:md5,role:p\\ass
+*:*:*:scram_role:p\\ass
+*:*:*:scram,role:p\\ass
 !);

-test_conn($node, 'user=md5_role', 'password from pgpass', 0);
+test_conn($node, 'user=scram_role', 'password from pgpass', 0);

 # Testing with regular expression for username.  The third regexp matches.
-reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^md.*$', 'password');
-test_conn($node, 'user=md5_role', 'password, matching regexp for username', 0,
+reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^scr.*$', 'password');
+test_conn($node, 'user=scram_role', 'password, matching regexp for username', 0,
     log_like =>
-      [qr/connection authenticated: identity="md5_role" method=password/]);
+      [qr/connection authenticated: identity="scram_role" method=password/]);

 # The third regex does not match anymore.
-reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^m_d.*$', 'password');
-test_conn($node, 'user=md5_role',
+reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^sc_r.*$', 'password');
+test_conn($node, 'user=scram_role',
     'password, non matching regexp for username',
     2, log_unlike => [qr/connection authenticated:/]);

 # Test with a comma in the regular expression.  In this case, the use of
 # double quotes is mandatory so as this is not considered as two elements
 # of the user name list when parsing pg_hba.conf.
-reset_pg_hba($node, 'all', '"/^.*5,.*e$"', 'password');
-test_conn($node, 'user=md5,role', 'password, matching regexp for username', 0,
+reset_pg_hba($node, 'all', '"/^.*m,.*e$"', 'password');
+test_conn($node, 'user=scram,role', 'password, matching regexp for username', 0,
     log_like =>
-      [qr/connection authenticated: identity="md5,role" method=password/]);
+      [qr/connection authenticated: identity="scram,role" method=password/]);

 # Testing with regular expression for dbname. The third regex matches.
 reset_pg_hba($node, '/^.*nomatch.*$, baddb, /^regex_t.*b$', 'all',
     'password');
 test_conn(
     $node,
-    'user=md5_role dbname=regex_testdb',
+    'user=scram_role dbname=regex_testdb',
     'password, matching regexp for dbname',
     0,
     log_like =>
-      [qr/connection authenticated: identity="md5_role" method=password/]);
+      [qr/connection authenticated: identity="scram_role" method=password/]);

 # The third regexp does not match anymore.
 reset_pg_hba($node, '/^.*nomatch.*$, baddb, /^regex_t.*ba$',
     'all', 'password');
 test_conn(
     $node,
-    'user=md5_role dbname=regex_testdb',
+    'user=scram_role dbname=regex_testdb',
     'password, non matching regexp for dbname',
     2, log_unlike => [qr/connection authenticated:/]);

diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl
index 27abd02abf..d187f532de 100644
--- a/src/test/ssl/t/002_scram.pl
+++ b/src/test/ssl/t/002_scram.pl
@@ -64,6 +64,8 @@ sub switch_server_cert
 $ENV{PGPORT} = $node->port;
 $node->start;

+my $md5_works = ($node->psql('postgres', "select md5('')") == 0);
+
 # Configure server for SSL connections, with password handling.
 $ssl_server->configure_test_server_for_ssl(
     $node, $SERVERHOSTADDR, $SERVERHOSTCIDR,
@@ -91,12 +93,15 @@ sub switch_server_cert
     "SCRAM with SSL and channel_binding=require");

 # Now test when the user has an MD5-encrypted password; should fail
-$node->connect_fails(
-    "$common_connstr user=md5testuser channel_binding=require",
-    "MD5 with SSL and channel_binding=require",
-    expected_stderr =>
-      qr/channel binding required but not supported by server's authentication request/
-);
+SKIP: {
+    skip "MD5 not supported" unless $md5_works;
+    $node->connect_fails(
+        "$common_connstr user=md5testuser channel_binding=require",
+        "MD5 with SSL and channel_binding=require",
+        expected_stderr =>
+        qr/channel binding required but not supported by server's authentication request/
+    );
+}

 # Now test with auth method 'cert' by connecting to 'certdb'. Should fail,
 # because channel binding is not performed.  Note that ssl/client.key may
@@ -130,12 +135,15 @@ sub switch_server_cert
     "$common_connstr user=ssltestuser channel_binding=disable require_auth=scram-sha-256",
     "SCRAM with SSL, channel_binding=disable, and require_auth=scram-sha-256"
 );
-$node->connect_fails(
-    "$common_connstr user=md5testuser require_auth=md5 channel_binding=require",
-    "channel_binding can fail even when require_auth succeeds",
-    expected_stderr =>
-      qr/channel binding required but not supported by server's authentication request/
-);
+SKIP: {
+    skip "MD5 not supported" unless $md5_works;
+    $node->connect_fails(
+        "$common_connstr user=md5testuser require_auth=md5 channel_binding=require",
+        "channel_binding can fail even when require_auth succeeds",
+        expected_stderr =>
+        qr/channel binding required but not supported by server's authentication request/
+    );
+}
 $node->connect_ok(
     "$common_connstr user=ssltestuser channel_binding=require require_auth=scram-sha-256",
     "SCRAM with SSL, channel_binding=require, and require_auth=scram-sha-256"
--
2.42.0

From d1470936ab5784b1dafc5fdc777dd8004c5f57ba Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 5 Oct 2023 14:45:35 +0200
Subject: [PATCH v4 4/5] Allow tests to pass in OpenSSL FIPS mode (rest)

This adds alternative expected files for various tests.

XXX maybe some of these could be reorgnized to make the patch smaller?
---
 .../expected/passwordcheck_1.out              |  18 +++
 contrib/uuid-ossp/expected/uuid_ossp_1.out    | 135 ++++++++++++++++
 src/test/regress/expected/md5_1.out           |  35 ++++
 src/test/regress/expected/password_1.out      | 150 ++++++++++++++++++
 4 files changed, 338 insertions(+)
 create mode 100644 contrib/passwordcheck/expected/passwordcheck_1.out
 create mode 100644 contrib/uuid-ossp/expected/uuid_ossp_1.out
 create mode 100644 src/test/regress/expected/md5_1.out
 create mode 100644 src/test/regress/expected/password_1.out

diff --git a/contrib/passwordcheck/expected/passwordcheck_1.out b/contrib/passwordcheck/expected/passwordcheck_1.out
new file mode 100644
index 0000000000..5d8d5dcc1c
--- /dev/null
+++ b/contrib/passwordcheck/expected/passwordcheck_1.out
@@ -0,0 +1,18 @@
+LOAD 'passwordcheck';
+CREATE USER regress_passwordcheck_user1;
+-- ok
+ALTER USER regress_passwordcheck_user1 PASSWORD 'a_nice_long_password';
+-- error: too short
+ALTER USER regress_passwordcheck_user1 PASSWORD 'tooshrt';
+ERROR:  password is too short
+-- error: contains user name
+ALTER USER regress_passwordcheck_user1 PASSWORD 'xyzregress_passwordcheck_user1';
+ERROR:  password must not contain user name
+-- error: contains only letters
+ALTER USER regress_passwordcheck_user1 PASSWORD 'alessnicelongpassword';
+ERROR:  password must contain both letters and nonletters
+-- encrypted ok (password is "secret")
+ALTER USER regress_passwordcheck_user1 PASSWORD 'md592350e12ac34e52dd598f90893bb3ae7';
+-- error: password is user name
+ALTER USER regress_passwordcheck_user1 PASSWORD 'md507a112732ed9f2087fa90b192d44e358';
+DROP USER regress_passwordcheck_user1;
diff --git a/contrib/uuid-ossp/expected/uuid_ossp_1.out b/contrib/uuid-ossp/expected/uuid_ossp_1.out
new file mode 100644
index 0000000000..58104dbe18
--- /dev/null
+++ b/contrib/uuid-ossp/expected/uuid_ossp_1.out
@@ -0,0 +1,135 @@
+CREATE EXTENSION "uuid-ossp";
+SELECT uuid_nil();
+               uuid_nil
+--------------------------------------
+ 00000000-0000-0000-0000-000000000000
+(1 row)
+
+SELECT uuid_ns_dns();
+             uuid_ns_dns
+--------------------------------------
+ 6ba7b810-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_ns_url();
+             uuid_ns_url
+--------------------------------------
+ 6ba7b811-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_ns_oid();
+             uuid_ns_oid
+--------------------------------------
+ 6ba7b812-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_ns_x500();
+             uuid_ns_x500
+--------------------------------------
+ 6ba7b814-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+-- some quick and dirty field extraction functions
+-- this is actually timestamp concatenated with clock sequence, per RFC 4122
+CREATE FUNCTION uuid_timestamp_bits(uuid) RETURNS varbit AS
+$$ SELECT ('x' || substr($1::text, 15, 4) || substr($1::text, 10, 4) ||
+           substr($1::text, 1, 8) || substr($1::text, 20, 4))::bit(80)
+          & x'0FFFFFFFFFFFFFFF3FFF' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+CREATE FUNCTION uuid_version_bits(uuid) RETURNS varbit AS
+$$ SELECT ('x' || substr($1::text, 15, 2))::bit(8) & '11110000' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+CREATE FUNCTION uuid_reserved_bits(uuid) RETURNS varbit AS
+$$ SELECT ('x' || substr($1::text, 20, 2))::bit(8) & '11000000' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+CREATE FUNCTION uuid_multicast_bit(uuid) RETURNS bool AS
+$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000001') != '00000000' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+CREATE FUNCTION uuid_local_admin_bit(uuid) RETURNS bool AS
+$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000010') != '00000000' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+CREATE FUNCTION uuid_node(uuid) RETURNS text AS
+$$ SELECT substr($1::text, 25) $$
+LANGUAGE SQL STRICT IMMUTABLE;
+-- Ideally, the multicast bit would never be set in V1 output, but the
+-- UUID library may fall back to MC if it can't get the system MAC address.
+-- Also, the local-admin bit might be set (if so, we're probably inside a VM).
+-- So we can't test either bit here.
+SELECT uuid_version_bits(uuid_generate_v1()),
+       uuid_reserved_bits(uuid_generate_v1());
+ uuid_version_bits | uuid_reserved_bits
+-------------------+--------------------
+ 00010000          | 10000000
+(1 row)
+
+-- Although RFC 4122 only requires the multicast bit to be set in V1MC style
+-- UUIDs, our implementation always sets the local-admin bit as well.
+SELECT uuid_version_bits(uuid_generate_v1mc()),
+       uuid_reserved_bits(uuid_generate_v1mc()),
+       uuid_multicast_bit(uuid_generate_v1mc()),
+       uuid_local_admin_bit(uuid_generate_v1mc());
+ uuid_version_bits | uuid_reserved_bits | uuid_multicast_bit | uuid_local_admin_bit
+-------------------+--------------------+--------------------+----------------------
+ 00010000          | 10000000           | t                  | t
+(1 row)
+
+-- timestamp+clock sequence should be monotonic increasing in v1
+SELECT uuid_timestamp_bits(uuid_generate_v1()) < uuid_timestamp_bits(uuid_generate_v1());
+ ?column?
+----------
+ t
+(1 row)
+
+SELECT uuid_timestamp_bits(uuid_generate_v1mc()) < uuid_timestamp_bits(uuid_generate_v1mc());
+ ?column?
+----------
+ t
+(1 row)
+
+-- Ideally, the node value is stable in V1 addresses, but OSSP UUID
+-- falls back to V1MC behavior if it can't get the system MAC address.
+SELECT CASE WHEN uuid_multicast_bit(uuid_generate_v1()) AND
+                 uuid_local_admin_bit(uuid_generate_v1()) THEN
+         true -- punt, no test
+       ELSE
+         uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1())
+       END;
+ case
+------
+ t
+(1 row)
+
+-- In any case, V1MC node addresses should be random.
+SELECT uuid_node(uuid_generate_v1()) <> uuid_node(uuid_generate_v1mc());
+ ?column?
+----------
+ t
+(1 row)
+
+SELECT uuid_node(uuid_generate_v1mc()) <> uuid_node(uuid_generate_v1mc());
+ ?column?
+----------
+ t
+(1 row)
+
+SELECT uuid_generate_v3(uuid_ns_dns(), 'www.widgets.com');
+ERROR:  could not initialize MD5 context: unsupported
+SELECT uuid_generate_v5(uuid_ns_dns(), 'www.widgets.com');
+           uuid_generate_v5
+--------------------------------------
+ 21f7f8de-8051-5b89-8680-0195ef798b6a
+(1 row)
+
+SELECT uuid_version_bits(uuid_generate_v4()),
+       uuid_reserved_bits(uuid_generate_v4());
+ uuid_version_bits | uuid_reserved_bits
+-------------------+--------------------
+ 01000000          | 10000000
+(1 row)
+
+SELECT uuid_generate_v4() <> uuid_generate_v4();
+ ?column?
+----------
+ t
+(1 row)
+
diff --git a/src/test/regress/expected/md5_1.out b/src/test/regress/expected/md5_1.out
new file mode 100644
index 0000000000..174b70bafb
--- /dev/null
+++ b/src/test/regress/expected/md5_1.out
@@ -0,0 +1,35 @@
+--
+-- MD5 test suite - from IETF RFC 1321
+-- (see: https://www.rfc-editor.org/rfc/rfc1321)
+--
+-- (The md5() function will error in OpenSSL FIPS mode.  By keeping
+-- this test in a separate file, it is easier to manage variant
+-- results.)
+select md5('') = 'd41d8cd98f00b204e9800998ecf8427e' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('a') = '0cc175b9c0f1b6a831c399e269772661' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('abc') = '900150983cd24fb0d6963f7d28e17f72' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('message digest') = 'f96b697d7cb7938d525a2f31aaf161d0' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('abcdefghijklmnopqrstuvwxyz') = 'c3fcd3d76192e4007dfb496cca67e13b' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') = 'd174ab98d277d9f5a5611c2c9f419d9f' AS
"TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890') =
'57edf4a22be3c955ac49da2e2107b67a'AS "TRUE"; 
+ERROR:  could not compute MD5 hash: unsupported
+select md5(''::bytea) = 'd41d8cd98f00b204e9800998ecf8427e' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('a'::bytea) = '0cc175b9c0f1b6a831c399e269772661' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('abc'::bytea) = '900150983cd24fb0d6963f7d28e17f72' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('message digest'::bytea) = 'f96b697d7cb7938d525a2f31aaf161d0' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('abcdefghijklmnopqrstuvwxyz'::bytea) = 'c3fcd3d76192e4007dfb496cca67e13b' AS "TRUE";
+ERROR:  could not compute MD5 hash: unsupported
+select md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'::bytea) =
'd174ab98d277d9f5a5611c2c9f419d9f'AS "TRUE"; 
+ERROR:  could not compute MD5 hash: unsupported
+select md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890'::bytea) =
'57edf4a22be3c955ac49da2e2107b67a'AS "TRUE"; 
+ERROR:  could not compute MD5 hash: unsupported
diff --git a/src/test/regress/expected/password_1.out b/src/test/regress/expected/password_1.out
new file mode 100644
index 0000000000..3bb411949e
--- /dev/null
+++ b/src/test/regress/expected/password_1.out
@@ -0,0 +1,150 @@
+--
+-- Tests for password types
+--
+-- Tests for GUC password_encryption
+SET password_encryption = 'novalue'; -- error
+ERROR:  invalid value for parameter "password_encryption": "novalue"
+HINT:  Available values: md5, scram-sha-256.
+SET password_encryption = true; -- error
+ERROR:  invalid value for parameter "password_encryption": "true"
+HINT:  Available values: md5, scram-sha-256.
+SET password_encryption = 'md5'; -- ok
+SET password_encryption = 'scram-sha-256'; -- ok
+-- consistency of password entries
+SET password_encryption = 'md5';
+CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
+ERROR:  password encryption failed: unsupported
+CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
+ERROR:  password encryption failed: unsupported
+SET password_encryption = 'scram-sha-256';
+CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
+CREATE ROLE regress_passwd4 PASSWORD NULL;
+-- check list of created entries
+--
+-- The scram secret will look something like:
+--
SCRAM-SHA-256$4096:E4HxLGtnRzsYwg==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=
+--
+-- Since the salt is random, the exact value stored will be different on every test
+-- run. Use a regular expression to mask the changing parts.
+SELECT rolname, regexp_replace(rolpassword,
'(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=]+)\$([a-zA-Z0-9+=/]+):([a-zA-Z0-9+/=]+)','\1$\2:<salt>$<storedkey>:<serverkey>')
asrolpassword_masked 
+    FROM pg_authid
+    WHERE rolname LIKE 'regress_passwd%'
+    ORDER BY rolname, rolpassword;
+     rolname     |                rolpassword_masked
+-----------------+---------------------------------------------------
+ regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
+ regress_passwd4 |
+(2 rows)
+
+-- Rename a role
+ALTER ROLE regress_passwd2 RENAME TO regress_passwd2_new;
+ERROR:  role "regress_passwd2" does not exist
+-- md5 entry should have been removed
+SELECT rolname, rolpassword
+    FROM pg_authid
+    WHERE rolname LIKE 'regress_passwd2_new'
+    ORDER BY rolname, rolpassword;
+ rolname | rolpassword
+---------+-------------
+(0 rows)
+
+ALTER ROLE regress_passwd2_new RENAME TO regress_passwd2;
+ERROR:  role "regress_passwd2_new" does not exist
+-- Change passwords with ALTER USER. With plaintext or already-encrypted
+-- passwords.
+SET password_encryption = 'md5';
+-- encrypt with MD5
+ALTER ROLE regress_passwd2 PASSWORD 'foo';
+ERROR:  role "regress_passwd2" does not exist
+-- already encrypted, use as they are
+ALTER ROLE regress_passwd1 PASSWORD 'md5cd3578025fe2c3d7ed1b9a9b26238b70';
+ERROR:  role "regress_passwd1" does not exist
+ALTER ROLE regress_passwd3 PASSWORD
'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
+SET password_encryption = 'scram-sha-256';
+-- create SCRAM secret
+ALTER ROLE  regress_passwd4 PASSWORD 'foo';
+-- already encrypted with MD5, use as it is
+CREATE ROLE regress_passwd5 PASSWORD 'md5e73a4b11df52a6068f8b39f90be36023';
+-- This looks like a valid SCRAM-SHA-256 secret, but it is not
+-- so it should be hashed with SCRAM-SHA-256.
+CREATE ROLE regress_passwd6 PASSWORD 'SCRAM-SHA-256$1234';
+-- These may look like valid MD5 secrets, but they are not, so they
+-- should be hashed with SCRAM-SHA-256.
+-- trailing garbage at the end
+CREATE ROLE regress_passwd7 PASSWORD 'md5012345678901234567890123456789zz';
+-- invalid length
+CREATE ROLE regress_passwd8 PASSWORD 'md501234567890123456789012345678901zz';
+-- Changing the SCRAM iteration count
+SET scram_iterations = 1024;
+CREATE ROLE regress_passwd9 PASSWORD 'alterediterationcount';
+SELECT rolname, regexp_replace(rolpassword,
'(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=]+)\$([a-zA-Z0-9+=/]+):([a-zA-Z0-9+/=]+)','\1$\2:<salt>$<storedkey>:<serverkey>')
asrolpassword_masked 
+    FROM pg_authid
+    WHERE rolname LIKE 'regress_passwd%'
+    ORDER BY rolname, rolpassword;
+     rolname     |                rolpassword_masked
+-----------------+---------------------------------------------------
+ regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
+ regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
+ regress_passwd5 | md5e73a4b11df52a6068f8b39f90be36023
+ regress_passwd6 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
+ regress_passwd7 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
+ regress_passwd8 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
+ regress_passwd9 | SCRAM-SHA-256$1024:<salt>$<storedkey>:<serverkey>
+(7 rows)
+
+-- An empty password is not allowed, in any form
+CREATE ROLE regress_passwd_empty PASSWORD '';
+NOTICE:  empty string is not a valid password, clearing password
+ALTER ROLE regress_passwd_empty PASSWORD 'md585939a5ce845f1a1b620742e3c659e0a';
+ALTER ROLE regress_passwd_empty PASSWORD
'SCRAM-SHA-256$4096:hpFyHTUsSWcR7O9P$LgZFIt6Oqdo27ZFKbZ2nV+vtnYM995pDh9ca6WSi120=:qVV5NeluNfUPkwm7Vqat25RjSPLkGeoZBQs6wVv+um4=';
+NOTICE:  empty string is not a valid password, clearing password
+SELECT rolpassword FROM pg_authid WHERE rolname='regress_passwd_empty';
+ rolpassword
+-------------
+
+(1 row)
+
+-- Test with invalid stored and server keys.
+--
+-- The first is valid, to act as a control. The others have too long
+-- stored/server keys. They will be re-hashed.
+CREATE ROLE regress_passwd_sha_len0 PASSWORD
'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96Rqw=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZI=';
+CREATE ROLE regress_passwd_sha_len1 PASSWORD
'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96RqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZI=';
+CREATE ROLE regress_passwd_sha_len2 PASSWORD
'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96Rqw=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
+-- Check that the invalid secrets were re-hashed. A re-hashed secret
+-- should not contain the original salt.
+SELECT rolname, rolpassword not like '%A6xHKoH/494E941doaPOYg==%' as is_rolpassword_rehashed
+    FROM pg_authid
+    WHERE rolname LIKE 'regress_passwd_sha_len%'
+    ORDER BY rolname;
+         rolname         | is_rolpassword_rehashed
+-------------------------+-------------------------
+ regress_passwd_sha_len0 | f
+ regress_passwd_sha_len1 | t
+ regress_passwd_sha_len2 | t
+(3 rows)
+
+DROP ROLE regress_passwd1;
+ERROR:  role "regress_passwd1" does not exist
+DROP ROLE regress_passwd2;
+ERROR:  role "regress_passwd2" does not exist
+DROP ROLE regress_passwd3;
+DROP ROLE regress_passwd4;
+DROP ROLE regress_passwd5;
+DROP ROLE regress_passwd6;
+DROP ROLE regress_passwd7;
+DROP ROLE regress_passwd8;
+DROP ROLE regress_passwd9;
+DROP ROLE regress_passwd_empty;
+DROP ROLE regress_passwd_sha_len0;
+DROP ROLE regress_passwd_sha_len1;
+DROP ROLE regress_passwd_sha_len2;
+-- all entries should have been removed
+SELECT rolname, rolpassword
+    FROM pg_authid
+    WHERE rolname LIKE 'regress_passwd%'
+    ORDER BY rolname, rolpassword;
+ rolname | rolpassword
+---------+-------------
+(0 rows)
+
--
2.42.0

From 65b287b111fef67abed492c805519eb5c6b96efa Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 5 Oct 2023 14:45:35 +0200
Subject: [PATCH v4 5/5] WIP: Use fipshash in brin_multi test

---
 src/test/regress/expected/brin_multi.out | 24 ++++++++++++------------
 src/test/regress/sql/brin_multi.sql      |  4 ++--
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/test/regress/expected/brin_multi.out b/src/test/regress/expected/brin_multi.out
index 9f46934c9b..6773701c7e 100644
--- a/src/test/regress/expected/brin_multi.out
+++ b/src/test/regress/expected/brin_multi.out
@@ -740,19 +740,19 @@ RESET enable_seqscan;
 -- do some inequality tests for varlena data types
 CREATE TABLE brin_test_multi_2 (a UUID) WITH (fillfactor=10);
 INSERT INTO brin_test_multi_2
-SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT md5((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 
+SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT fipshash((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 
 CREATE INDEX brin_test_multi_2_idx ON brin_test_multi_2 USING brin (a uuid_minmax_multi_ops) WITH (pages_per_range=5);
 SET enable_seqscan=off;
 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a < '33e75ff0-9dd6-01bb-e69f-351039152189';
  count
 -------
-   195
+   156
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a > '33e75ff0-9dd6-01bb-e69f-351039152189';
  count
 -------
-   792
+   844
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a <= 'f457c545-a9de-d88f-18ec-ee47145a72c0';
@@ -764,19 +764,19 @@ SELECT COUNT(*) FROM brin_test_multi_2 WHERE a <= 'f457c545-a9de-d88f-18ec-ee471
 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a >= 'c51ce410-c124-a10e-0db5-e4b97fc2af39';
  count
 -------
-   272
+   221
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = 'cfcd2084-95d5-65ef-66e7-dff9f98764da';
  count
 -------
-    12
+     0
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = 'aab32389-22bc-c25a-6f60-6eb525ffdc56';
  count
 -------
-    13
+     0
 (1 row)

 -- now do the same, but insert the rows with the indexes already created
@@ -784,17 +784,17 @@ SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = 'aab32389-22bc-c25a-6f60-6eb525
 -- approach of adding rows into existing ranges
 TRUNCATE brin_test_multi_2;
 INSERT INTO brin_test_multi_2
-SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT md5((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 
+SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT fipshash((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 
 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a < '33e75ff0-9dd6-01bb-e69f-351039152189';
  count
 -------
-   195
+   156
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a > '33e75ff0-9dd6-01bb-e69f-351039152189';
  count
 -------
-   792
+   844
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a <= 'f457c545-a9de-d88f-18ec-ee47145a72c0';
@@ -806,19 +806,19 @@ SELECT COUNT(*) FROM brin_test_multi_2 WHERE a <= 'f457c545-a9de-d88f-18ec-ee471
 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a >= 'c51ce410-c124-a10e-0db5-e4b97fc2af39';
  count
 -------
-   272
+   221
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = 'cfcd2084-95d5-65ef-66e7-dff9f98764da';
  count
 -------
-    12
+     0
 (1 row)

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a = 'aab32389-22bc-c25a-6f60-6eb525ffdc56';
  count
 -------
-    13
+     0
 (1 row)

 DROP TABLE brin_test_multi_2;
diff --git a/src/test/regress/sql/brin_multi.sql b/src/test/regress/sql/brin_multi.sql
index d50dbdee68..5bca4fd350 100644
--- a/src/test/regress/sql/brin_multi.sql
+++ b/src/test/regress/sql/brin_multi.sql
@@ -545,7 +545,7 @@ CREATE INDEX brin_test_multi_1_idx_2 ON brin_test_multi_1 USING brin (b int8_min
 -- do some inequality tests for varlena data types
 CREATE TABLE brin_test_multi_2 (a UUID) WITH (fillfactor=10);
 INSERT INTO brin_test_multi_2
-SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT md5((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 
+SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT fipshash((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 

 CREATE INDEX brin_test_multi_2_idx ON brin_test_multi_2 USING brin (a uuid_minmax_multi_ops) WITH (pages_per_range=5);

@@ -570,7 +570,7 @@ CREATE INDEX brin_test_multi_2_idx ON brin_test_multi_2 USING brin (a uuid_minma

 TRUNCATE brin_test_multi_2;
 INSERT INTO brin_test_multi_2
-SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT md5((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 
+SELECT v::uuid FROM (SELECT row_number() OVER (ORDER BY v) c, v FROM (SELECT fipshash((i/13)::text) AS v FROM
generate_series(1,1000)s(i)) foo) bar ORDER BY c + 25 * random(); 

 SELECT COUNT(*) FROM brin_test_multi_2 WHERE a < '33e75ff0-9dd6-01bb-e69f-351039152189';

--
2.42.0

diff --git a/contrib/pgcrypto/expected/3des_1.out b/contrib/pgcrypto/expected/3des_1.out
new file mode 100644
index 0000000000..fb1d1f6f0c
--- /dev/null
+++ b/contrib/pgcrypto/expected/3des_1.out
@@ -0,0 +1,29 @@
+--
+-- 3DES cipher
+--
+-- test vector from somewhere
+SELECT encrypt('\x8000000000000000',
+               '\x010101010101010101010101010101010101010101010101',
+               '3des-ecb/pad:none');
+ERROR:  encrypt error: Cipher cannot be initialized
+select encrypt('', 'foo', '3des');
+ERROR:  encrypt error: Cipher cannot be initialized
+-- 10 bytes key
+select encrypt('foo', '0123456789', '3des');
+ERROR:  encrypt error: Cipher cannot be initialized
+-- 22 bytes key
+select encrypt('foo', '0123456789012345678901', '3des');
+ERROR:  encrypt error: Cipher cannot be initialized
+-- decrypt
+select encode(decrypt(encrypt('foo', '0123456', '3des'), '0123456', '3des'), 'escape');
+ERROR:  encrypt error: Cipher cannot be initialized
+-- iv
+select encrypt_iv('foo', '0123456', 'abcd', '3des');
+ERROR:  encrypt_iv error: Cipher cannot be initialized
+select encode(decrypt_iv('\x50735067b073bb93', '0123456', 'abcd', '3des'), 'escape');
+ERROR:  decrypt_iv error: Cipher cannot be initialized
+-- long message
+select encrypt('Lets try a longer message.', '0123456789012345678901', '3des');
+ERROR:  encrypt error: Cipher cannot be initialized
+select encode(decrypt(encrypt('Lets try a longer message.', '0123456789012345678901', '3des'),
'0123456789012345678901','3des'), 'escape'); 
+ERROR:  encrypt error: Cipher cannot be initialized
diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out
index 8475231735..924d6e001d 100644
--- a/src/test/regress/expected/password.out
+++ b/src/test/regress/expected/password.out
@@ -12,8 +12,10 @@ SET password_encryption = 'md5'; -- ok
 SET password_encryption = 'scram-sha-256'; -- ok
 -- consistency of password entries
 SET password_encryption = 'md5';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
-CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
+CREATE ROLE regress_passwd1;
+ALTER ROLE regress_passwd1 PASSWORD 'role_pwd1';
+CREATE ROLE regress_passwd2;
+ALTER ROLE regress_passwd2 PASSWORD 'role_pwd2';
 SET password_encryption = 'scram-sha-256';
 CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
 CREATE ROLE regress_passwd4 PASSWORD NULL;
diff --git a/src/test/regress/expected/password_1.out b/src/test/regress/expected/password_1.out
index 3bb411949e..9d2cc94f37 100644
--- a/src/test/regress/expected/password_1.out
+++ b/src/test/regress/expected/password_1.out
@@ -12,9 +12,11 @@ SET password_encryption = 'md5'; -- ok
 SET password_encryption = 'scram-sha-256'; -- ok
 -- consistency of password entries
 SET password_encryption = 'md5';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
+CREATE ROLE regress_passwd1;
+ALTER ROLE regress_passwd1 PASSWORD 'role_pwd1';
 ERROR:  password encryption failed: unsupported
-CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
+CREATE ROLE regress_passwd2;
+ALTER ROLE regress_passwd2 PASSWORD 'role_pwd2';
 ERROR:  password encryption failed: unsupported
 SET password_encryption = 'scram-sha-256';
 CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
@@ -32,33 +34,33 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
     ORDER BY rolname, rolpassword;
      rolname     |                rolpassword_masked
 -----------------+---------------------------------------------------
+ regress_passwd1 |
+ regress_passwd2 |
  regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd4 |
-(2 rows)
+(4 rows)

 -- Rename a role
 ALTER ROLE regress_passwd2 RENAME TO regress_passwd2_new;
-ERROR:  role "regress_passwd2" does not exist
 -- md5 entry should have been removed
 SELECT rolname, rolpassword
     FROM pg_authid
     WHERE rolname LIKE 'regress_passwd2_new'
     ORDER BY rolname, rolpassword;
- rolname | rolpassword
----------+-------------
-(0 rows)
+       rolname       | rolpassword
+---------------------+-------------
+ regress_passwd2_new |
+(1 row)

 ALTER ROLE regress_passwd2_new RENAME TO regress_passwd2;
-ERROR:  role "regress_passwd2_new" does not exist
 -- Change passwords with ALTER USER. With plaintext or already-encrypted
 -- passwords.
 SET password_encryption = 'md5';
 -- encrypt with MD5
 ALTER ROLE regress_passwd2 PASSWORD 'foo';
-ERROR:  role "regress_passwd2" does not exist
+ERROR:  password encryption failed: unsupported
 -- already encrypted, use as they are
 ALTER ROLE regress_passwd1 PASSWORD 'md5cd3578025fe2c3d7ed1b9a9b26238b70';
-ERROR:  role "regress_passwd1" does not exist
 ALTER ROLE regress_passwd3 PASSWORD
'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
 SET password_encryption = 'scram-sha-256';
 -- create SCRAM secret
@@ -83,6 +85,8 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
     ORDER BY rolname, rolpassword;
      rolname     |                rolpassword_masked
 -----------------+---------------------------------------------------
+ regress_passwd1 | md5cd3578025fe2c3d7ed1b9a9b26238b70
+ regress_passwd2 |
  regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd5 | md5e73a4b11df52a6068f8b39f90be36023
@@ -90,7 +94,7 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
  regress_passwd7 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd8 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd9 | SCRAM-SHA-256$1024:<salt>$<storedkey>:<serverkey>
-(7 rows)
+(9 rows)

 -- An empty password is not allowed, in any form
 CREATE ROLE regress_passwd_empty PASSWORD '';
@@ -125,9 +129,7 @@ SELECT rolname, rolpassword not like '%A6xHKoH/494E941doaPOYg==%' as is_rolpassw
 (3 rows)

 DROP ROLE regress_passwd1;
-ERROR:  role "regress_passwd1" does not exist
 DROP ROLE regress_passwd2;
-ERROR:  role "regress_passwd2" does not exist
 DROP ROLE regress_passwd3;
 DROP ROLE regress_passwd4;
 DROP ROLE regress_passwd5;
diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql
index 53e86b0b6c..bb82aa4aa2 100644
--- a/src/test/regress/sql/password.sql
+++ b/src/test/regress/sql/password.sql
@@ -10,8 +10,10 @@ SET password_encryption = 'scram-sha-256'; -- ok

 -- consistency of password entries
 SET password_encryption = 'md5';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
-CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
+CREATE ROLE regress_passwd1;
+ALTER ROLE regress_passwd1 PASSWORD 'role_pwd1';
+CREATE ROLE regress_passwd2;
+ALTER ROLE regress_passwd2 PASSWORD 'role_pwd2';
 SET password_encryption = 'scram-sha-256';
 CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
 CREATE ROLE regress_passwd4 PASSWORD NULL;

pgsql-hackers by date:

Previous
From: "Shankaran, Akash"
Date:
Subject: RE: Popcount optimization using AVX512
Next
From: Tom Lane
Date:
Subject: Re: On non-Windows, hard depend on uselocale(3)