tests.patch.txt
text/plain
commit a4d9cbf4d1228dcc17f2961b7811321a50e74617
Author: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Tue Mar 4 13:17:12 2025 -0800
Tests
diff --git a/src/test/ssl/t/004_sni.pl b/src/test/ssl/t/004_sni.pl
index f0ce048273a..72e64c6c00d 100644
--- a/src/test/ssl/t/004_sni.pl
+++ b/src/test/ssl/t/004_sni.pl
@@ -33,6 +33,11 @@ if (!$ENV{PG_TEST_EXTRA} || $ENV{PG_TEST_EXTRA} !~ /\bssl\b/)
my $ssl_server = SSL::Server->new();
+sub sslkey
+{
+ return $ssl_server->sslkey(@_);
+}
+
my $node = PostgreSQL::Test::Cluster->new('primary');
$node->init;
@@ -161,4 +166,57 @@ $node->connect_fails(
"connect fails since the passphrase protected key cannot be reloaded",
expected_stderr => qr/tlsv1 unrecognized name/);
+# Test client CAs.
+
+$connstr =
+ "user=ssltestuser dbname=certdb hostaddr=$SERVERHOSTADDR sslmode=require sslsni=1";
+
+ok(unlink($node->data_dir . '/pg_hosts.conf'));
+# example.org has an unconfigured CA.
+$node->append_conf('pg_hosts.conf', 'example.org server-cn-only.crt server-cn-only.key ""');
+# example.com uses the client CA.
+$node->append_conf('pg_hosts.conf', 'example.com server-cn-only.crt server-cn-only.key root+client_ca.crt');
+# example.net uses the server CA (which is wrong).
+$node->append_conf('pg_hosts.conf', 'example.net server-cn-only.crt server-cn-only.key root+server_ca.crt');
+$node->reload;
+
+my @cases = ( "", "root+client_ca", "root+server_ca" );
+foreach my $default_ca (@cases)
+{
+ # The default CA should, ideally, not matter for the purposes of these
+ # tests, since we connect to the other hosts explicitly.
+ $ssl_server->switch_server_cert(
+ $node,
+ certfile => 'server-cn-only',
+ cafile => $default_ca);
+
+ # example.org is unconfigured and should fail.
+ $node->connect_fails(
+ "$connstr host=example.org sslcertmode=require sslcert=ssl/client.crt " . sslkey('client.key'),
+ "example.org, $default_ca: connect with sslcert, no client CA configured",
+ expected_stderr => qr/client certificates can only be checked if a root certificate store is available/);
+
+ # example.com is configured and should require a valid client cert.
+ $node->connect_fails(
+ "$connstr host=example.com sslcertmode=disable",
+ "example.com, $default_ca: connect fails if no client certificate sent",
+ expected_stderr => qr/connection requires a valid client certificate/);
+
+ $node->connect_ok(
+ "$connstr host=example.com sslcertmode=require sslcert=ssl/client.crt " . sslkey('client.key'),
+ "example.com, $default_ca: connect with sslcert, client certificate sent");
+
+ # example.net is configured and should require a client cert, but will
+ # always fail verification.
+ $node->connect_fails(
+ "$connstr host=example.net sslcertmode=disable",
+ "example.net, $default_ca: connect fails if no client certificate sent",
+ expected_stderr => qr/connection requires a valid client certificate/);
+
+ $node->connect_fails(
+ "$connstr host=example.net sslcertmode=require sslcert=ssl/client.crt " . sslkey('client.key'),
+ "example.net, $default_ca: connect with sslcert, client certificate sent",
+ expected_stderr => qr/unknown ca/);
+}
+
done_testing();
diff --git a/src/test/ssl/t/SSL/Backend/OpenSSL.pm b/src/test/ssl/t/SSL/Backend/OpenSSL.pm
index e044318531f..bdcce84003e 100644
--- a/src/test/ssl/t/SSL/Backend/OpenSSL.pm
+++ b/src/test/ssl/t/SSL/Backend/OpenSSL.pm
@@ -71,6 +71,7 @@ sub init
chmod(0600, glob "$pgdata/server-*.key")
or die "failed to change permissions on server keys: $!";
_copy_files("ssl/root+client_ca.crt", $pgdata);
+ _copy_files("ssl/root+server_ca.crt", $pgdata);
_copy_files("ssl/root_ca.crt", $pgdata);
_copy_files("ssl/root+client.crl", $pgdata);
mkdir("$pgdata/root+client-crldir")
@@ -145,7 +146,8 @@ following parameters are supported:
=item cafile => B<value>
The CA certificate file to use for the C<ssl_ca_file> GUC. If omitted it will
-default to 'root+client_ca.crt'.
+default to 'root+client_ca.crt'. If empty, no C<ssl_ca_file> configuration
+parameter will be set.
=item certfile => B<value>
@@ -180,10 +182,11 @@ sub set_server_cert
unless defined $params->{keyfile};
my $sslconf =
- "ssl_ca_file='$params->{cafile}.crt'\n"
- . "ssl_cert_file='$params->{certfile}.crt'\n"
+ "ssl_cert_file='$params->{certfile}.crt'\n"
. "ssl_key_file='$params->{keyfile}.key'\n"
. "ssl_crl_file='$params->{crlfile}'\n";
+ $sslconf .= "ssl_ca_file='$params->{cafile}.crt'\n"
+ if $params->{cafile} ne "";
$sslconf .= "ssl_crl_dir='$params->{crldir}'\n"
if defined $params->{crldir};