diff --git a/src/test/ssl/ServerSetup.pm b/src/test/ssl/ServerSetup.pm index 45991d61a2a..27a676b65c2 100644 --- a/src/test/ssl/ServerSetup.pm +++ b/src/test/ssl/ServerSetup.pm @@ -27,7 +27,6 @@ use Test::More; use Exporter 'import'; our @EXPORT = qw( configure_test_server_for_ssl - run_test_psql switch_server_cert test_connect_fails test_connect_ok @@ -35,37 +34,28 @@ our @EXPORT = qw( # Define a couple of helper functions to test connecting to the server. -# Attempt connection to server with given connection string. -sub run_test_psql -{ - my $connstr = $_[0]; - - my $cmd = [ - 'psql', '-X', '-A', '-t', '-c', "SELECT \$\$connected with $connstr\$\$", - '-d', "$connstr" ]; - - my $result = run_log($cmd); - return $result; -} - # The first argument is a base connection string to use for connection. # The second argument is a complementary connection string. sub test_connect_ok { - my $common_connstr = $_[0]; - my $connstr = $_[1]; - my $test_name = $_[2]; + my ($common_connstr, $connstr, $test_name) = @_; - ok(run_test_psql("$common_connstr $connstr"), $test_name); + my $cmd = [ + 'psql', '-X', '-A', '-t', '-c', "SELECT \$\$connected with $connstr\$\$", + '-d', "$common_connstr $connstr" ]; + + command_ok($cmd, $test_name); } sub test_connect_fails { - my $common_connstr = $_[0]; - my $connstr = $_[1]; - my $test_name = $_[2]; + my ($common_connstr, $connstr, $expected_stderr, $test_name) = @_; - ok(!run_test_psql("$common_connstr $connstr"), $test_name); + my $cmd = [ + 'psql', '-X', '-A', '-t', '-c', "SELECT \$\$connected with $connstr\$\$", + '-d', "$common_connstr $connstr" ]; + + command_fails_like($cmd, $expected_stderr, $test_name); } # Copy a set of files, taking into account wildcards @@ -169,12 +159,12 @@ sub configure_hba_for_ssl print $hba "# TYPE DATABASE USER ADDRESS METHOD\n"; print $hba -"hostssl trustdb ssltestuser $serverhost/32 $authmethod\n"; +"hostssl trustdb all $serverhost/32 $authmethod\n"; print $hba -"hostssl trustdb ssltestuser ::1/128 $authmethod\n"; +"hostssl trustdb all ::1/128 $authmethod\n"; print $hba -"hostssl certdb ssltestuser $serverhost/32 cert\n"; +"hostssl certdb all $serverhost/32 cert\n"; print $hba -"hostssl certdb ssltestuser ::1/128 cert\n"; +"hostssl certdb all ::1/128 cert\n"; close $hba; } diff --git a/src/test/ssl/ssl/.gitignore b/src/test/ssl/ssl/.gitignore index 10b74f08480..af753d4c7df 100644 --- a/src/test/ssl/ssl/.gitignore +++ b/src/test/ssl/ssl/.gitignore @@ -1,3 +1,3 @@ /*.old /new_certs_dir/ -/client_tmp.key +/client*_tmp.key diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl index e53bd12ae9f..4b097a69bf2 100644 --- a/src/test/ssl/t/001_ssltests.pl +++ b/src/test/ssl/t/001_ssltests.pl @@ -2,7 +2,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 40; +use Test::More tests => 62; use ServerSetup; use File::Copy; @@ -20,6 +20,14 @@ my $common_connstr; # of the key stored in the code tree and update its permissions. copy("ssl/client.key", "ssl/client_tmp.key"); chmod 0600, "ssl/client_tmp.key"; +copy("ssl/client-revoked.key", "ssl/client-revoked_tmp.key"); +chmod 0600, "ssl/client-revoked_tmp.key"; + +# Also make a copy of that explicitly world-readable. We can't +# necessarily rely on the file in the source tree having those +# permissions. +copy("ssl/client.key", "ssl/client_wrongperms_tmp.key"); +chmod 0644, "ssl/client_wrongperms_tmp.key"; #### Part 0. Set up the server. @@ -48,6 +56,7 @@ $common_connstr = # The server should not accept non-SSL connections. test_connect_fails($common_connstr, "sslmode=disable", + qr/\Qno pg_hba.conf entry\E/, "server doesn't accept non-SSL connections"); # Try without a root cert. In sslmode=require, this should work. In verify-ca @@ -55,26 +64,32 @@ test_connect_fails($common_connstr, "sslmode=disable", test_connect_ok($common_connstr, "sslrootcert=invalid sslmode=require", "connect without server root cert sslmode=require"); test_connect_fails($common_connstr, "sslrootcert=invalid sslmode=verify-ca", + qr/root certificate file "invalid" does not exist/, "connect without server root cert sslmode=verify-ca"); test_connect_fails($common_connstr, "sslrootcert=invalid sslmode=verify-full", + qr/root certificate file "invalid" does not exist/, "connect without server root cert sslmode=verify-full"); # Try with wrong root cert, should fail. (We're using the client CA as the # root, but the server's key is signed by the server CA.) test_connect_fails($common_connstr, "sslrootcert=ssl/client_ca.crt sslmode=require", + qr/SSL error/, "connect with wrong server root cert sslmode=require"); test_connect_fails($common_connstr, "sslrootcert=ssl/client_ca.crt sslmode=verify-ca", + qr/SSL error/, "connect with wrong server root cert sslmode=verify-ca"); test_connect_fails($common_connstr, "sslrootcert=ssl/client_ca.crt sslmode=verify-full", + qr/SSL error/, "connect with wrong server root cert sslmode=verify-full"); # Try with just the server CA's cert. This fails because the root file # must contain the whole chain up to the root CA. test_connect_fails($common_connstr, "sslrootcert=ssl/server_ca.crt sslmode=verify-ca", + qr/SSL error/, "connect with server CA cert, without root CA"); # And finally, with the correct root cert. @@ -107,6 +122,7 @@ test_connect_ok($common_connstr, # A CRL belonging to a different CA is not accepted, fails test_connect_fails($common_connstr, "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/client.crl", + qr/SSL error/, "CRL belonging to a different CA"); # With the correct CRL, succeeds (this cert is not revoked) @@ -124,9 +140,9 @@ test_connect_ok($common_connstr, "sslmode=require host=wronghost.test", test_connect_ok($common_connstr, "sslmode=verify-ca host=wronghost.test", "mismatch between host name and server certificate sslmode=verify-ca"); test_connect_fails($common_connstr, "sslmode=verify-full host=wronghost.test", + qr/\Qserver certificate for "common-name.pg-ssltest.test" does not match host name "wronghost.test"\E/, "mismatch between host name and server certificate sslmode=verify-full"); - # Test Subject Alternative Names. switch_server_cert($node, 'server-multiple-alt-names'); @@ -141,9 +157,11 @@ test_connect_ok($common_connstr, "host=foo.wildcard.pg-ssltest.test", "host name matching with X.509 Subject Alternative Names wildcard"); test_connect_fails($common_connstr, "host=wronghost.alt-name.pg-ssltest.test", + qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "wronghost.alt-name.pg-ssltest.test"\E/, "host name not matching with X.509 Subject Alternative Names"); test_connect_fails($common_connstr, "host=deep.subdomain.wildcard.pg-ssltest.test", + qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/, "host name not matching with X.509 Subject Alternative Names wildcard"); # Test certificate with a single Subject Alternative Name. (this gives a @@ -157,9 +175,11 @@ test_connect_ok($common_connstr, "host=single.alt-name.pg-ssltest.test", "host name matching with a single X.509 Subject Alternative Name"); test_connect_fails($common_connstr, "host=wronghost.alt-name.pg-ssltest.test", + qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "wronghost.alt-name.pg-ssltest.test"\E/, "host name not matching with a single X.509 Subject Alternative Name"); test_connect_fails($common_connstr, "host=deep.subdomain.wildcard.pg-ssltest.test", + qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/, "host name not matching with a single X.509 Subject Alternative Name wildcard"); # Test server certificate with a CN and SANs. Per RFCs 2818 and 6125, the CN @@ -174,6 +194,7 @@ test_connect_ok($common_connstr, "host=dns1.alt-name.pg-ssltest.test", test_connect_ok($common_connstr, "host=dns2.alt-name.pg-ssltest.test", "certificate with both a CN and SANs 2"); test_connect_fails($common_connstr, "host=common-name.pg-ssltest.test", + qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 1 other name) does not match host name "common-name.pg-ssltest.test"\E/, "certificate with both a CN and SANs ignores CN"); # Finally, test a server certificate that has no CN or SANs. Of course, that's @@ -187,6 +208,7 @@ test_connect_ok($common_connstr, "server certificate without CN or SANs sslmode=verify-ca"); test_connect_fails($common_connstr, "sslmode=verify-full host=common-name.pg-ssltest.test", + qr/could not get server's host name from server certificate/, "server certificate without CN or SANs sslmode=verify-full"); # Test that the CRL works @@ -201,6 +223,7 @@ test_connect_ok($common_connstr, "connects without client-side CRL"); test_connect_fails($common_connstr, "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl", + qr/SSL error/, "does not connect with client-side CRL"); ### Part 2. Server-side tests. @@ -215,6 +238,7 @@ $common_connstr = # no client cert test_connect_fails($common_connstr, "user=ssltestuser sslcert=invalid", + qr/connection requires a valid client certificate/, "certificate authorization fails without client cert"); # correct client cert @@ -222,14 +246,22 @@ test_connect_ok($common_connstr, "user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key", "certificate authorization succeeds with correct client cert"); +# client key with wrong permissions +test_connect_fails($common_connstr, + "user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_wrongperms_tmp.key", + qr!\Qprivate key file "ssl/client_wrongperms_tmp.key" has group or world access\E!, + "certificate authorization fails because of file permissions"); + # client cert belonging to another user test_connect_fails($common_connstr, "user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key", + qr/certificate authentication failed for user "anotheruser"/, "certificate authorization fails with client cert belonging to another user"); # revoked client cert test_connect_fails($common_connstr, - "user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked.key", + "user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key", + qr/SSL error/, "certificate authorization fails with revoked client cert"); # intermediate client_ca.crt is provided by client, and isn't in server's ssl_ca_file @@ -241,7 +273,10 @@ test_connect_ok($common_connstr, "sslmode=require sslcert=ssl/client+client_ca.crt", "intermediate client certificate is provided by client"); test_connect_fails($common_connstr, "sslmode=require sslcert=ssl/client.crt", + qr/SSL error/, "intermediate client certificate is missing"); # clean up -unlink "ssl/client_tmp.key"; +unlink("ssl/client_tmp.key", + "ssl/client_wrongperms_tmp.key", + "ssl/client-revoked_tmp.key"); diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl index 67c1409a6ed..9460763a65a 100644 --- a/src/test/ssl/t/002_scram.pl +++ b/src/test/ssl/t/002_scram.pl @@ -4,7 +4,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 5; +use Test::More tests => 6; use ServerSetup; use File::Copy; @@ -59,8 +59,10 @@ else { test_connect_fails($common_connstr, "scram_channel_binding=tls-server-end-point", + qr/unsupported SCRAM channel-binding type/, "SCRAM authentication with tls-server-end-point as channel binding"); } test_connect_fails($common_connstr, "scram_channel_binding=not-exists", + qr/unsupported SCRAM channel-binding type/, "SCRAM authentication with invalid channel binding");