summaryrefslogtreecommitdiffstats
path: root/src/test/ssl/t/002_scram.pl
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ssl/t/002_scram.pl')
-rw-r--r--src/test/ssl/t/002_scram.pl152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl
new file mode 100644
index 0000000..566cb12
--- /dev/null
+++ b/src/test/ssl/t/002_scram.pl
@@ -0,0 +1,152 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Test SCRAM authentication and TLS channel binding types
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use File::Copy;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use SSL::Server;
+
+if ($ENV{with_ssl} ne 'openssl')
+{
+ plan skip_all => 'OpenSSL not supported by this build';
+}
+
+my $ssl_server = SSL::Server->new();
+
+sub sslkey
+{
+ return $ssl_server->sslkey(@_);
+}
+
+sub switch_server_cert
+{
+ $ssl_server->switch_server_cert(@_);
+}
+
+
+# This is the hostname used to connect to the server.
+my $SERVERHOSTADDR = '127.0.0.1';
+# This is the pattern to use in pg_hba.conf to match incoming connections.
+my $SERVERHOSTCIDR = '127.0.0.1/32';
+
+# Determine whether build supports tls-server-end-point.
+my $supports_tls_server_end_point =
+ check_pg_config("#define HAVE_X509_GET_SIGNATURE_NID 1");
+# Determine whether build supports detection of hash algorithms for
+# RSA-PSS certificates.
+my $supports_rsapss_certs =
+ check_pg_config("#define HAVE_X509_GET_SIGNATURE_INFO 1");
+
+# Allocation of base connection string shared among multiple tests.
+my $common_connstr;
+
+# Set up the server.
+
+note "setting up data directory";
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init;
+
+# PGHOST is enforced here to set up the node, subsequent connections
+# will use a dedicated connection string.
+$ENV{PGHOST} = $node->host;
+$ENV{PGPORT} = $node->port;
+$node->start;
+
+# Configure server for SSL connections, with password handling.
+$ssl_server->configure_test_server_for_ssl(
+ $node, $SERVERHOSTADDR, $SERVERHOSTCIDR,
+ "scram-sha-256",
+ 'password' => "pass",
+ 'password_enc' => "scram-sha-256");
+switch_server_cert($node, certfile => 'server-cn-only');
+$ENV{PGPASSWORD} = "pass";
+$common_connstr =
+ "dbname=trustdb sslmode=require sslcert=invalid sslrootcert=invalid hostaddr=$SERVERHOSTADDR host=localhost";
+
+# Default settings
+$node->connect_ok(
+ "$common_connstr user=ssltestuser",
+ "Basic SCRAM authentication with SSL");
+
+# Test channel_binding
+$node->connect_fails(
+ "$common_connstr user=ssltestuser channel_binding=invalid_value",
+ "SCRAM with SSL and channel_binding=invalid_value",
+ expected_stderr => qr/invalid channel_binding value: "invalid_value"/);
+$node->connect_ok("$common_connstr user=ssltestuser channel_binding=disable",
+ "SCRAM with SSL and channel_binding=disable");
+if ($supports_tls_server_end_point)
+{
+ $node->connect_ok(
+ "$common_connstr user=ssltestuser channel_binding=require",
+ "SCRAM with SSL and channel_binding=require");
+}
+else
+{
+ $node->connect_fails(
+ "$common_connstr user=ssltestuser channel_binding=require",
+ "SCRAM with SSL and channel_binding=require",
+ expected_stderr =>
+ qr/channel binding is required, but server did not offer an authentication method that supports channel binding/
+ );
+}
+
+# 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/
+);
+
+# Now test with auth method 'cert' by connecting to 'certdb'. Should fail,
+# because channel binding is not performed. Note that ssl/client.key may
+# be used in a different test, so the name of this temporary client key
+# is chosen here to be unique.
+my $cert_tempdir = PostgreSQL::Test::Utils::tempdir();
+my $client_tmp_key = "$cert_tempdir/client_scram.key";
+copy("ssl/client.key", "$cert_tempdir/client_scram.key")
+ or die
+ "couldn't copy ssl/client_key to $cert_tempdir/client_scram.key for permission change: $!";
+chmod 0600, "$cert_tempdir/client_scram.key"
+ or die "failed to change permissions on $cert_tempdir/client_scram.key: $!";
+$client_tmp_key =~ s!\\!/!g if $PostgreSQL::Test::Utils::windows_os;
+$node->connect_fails(
+ "sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR host=localhost dbname=certdb user=ssltestuser channel_binding=require",
+ "Cert authentication and channel_binding=require",
+ expected_stderr =>
+ qr/channel binding required, but server authenticated client without channel binding/
+);
+
+# Certificate verification at the connection level should still work fine.
+$node->connect_ok(
+ "sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR host=localhost dbname=verifydb user=ssltestuser",
+ "SCRAM with clientcert=verify-full",
+ log_like => [
+ qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
+ ]);
+
+# Now test with a server certificate that uses the RSA-PSS algorithm.
+# This checks that the certificate can be loaded and that channel binding
+# works. (see bug #17760)
+if ($supports_rsapss_certs)
+{
+ switch_server_cert($node, certfile => 'server-rsapss');
+ $node->connect_ok(
+ "$common_connstr user=ssltestuser channel_binding=require",
+ "SCRAM with SSL and channel_binding=require, server certificate uses 'rsassaPss'",
+ log_like => [
+ qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
+ ]);
+}
+done_testing();