use Exporter 'import';
our @EXPORT = qw(
configure_test_server_for_ssl
- run_test_psql
switch_server_cert
test_connect_fails
test_connect_ok
# 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) = @_;
+
+ my $cmd = [
+ 'psql', '-X', '-A', '-t', '-c', "SELECT \$\$connected with $connstr\$\$",
+ '-d', "$common_connstr $connstr" ];
- ok(!run_test_psql("$common_connstr $connstr"), $test_name);
+ command_fails_like($cmd, $expected_stderr, $test_name);
}
# Copy a set of files, taking into account wildcards
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;
}
use warnings;
use PostgresNode;
use TestLib;
-use Test::More tests => 40;
+use Test::More tests => 62;
use ServerSetup;
use File::Copy;
# 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.
# 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
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.
# 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)
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');
"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
"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
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
"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
"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.
# 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
"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
"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");