From 724917cd546d24ac99f3d07c87c2c29a36884616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renaud=20M=C3=A9trich?= Date: Mon, 15 Jun 2026 09:41:58 +0200 Subject: [PATCH v2 8/8] Expand test coverage for dual certificate support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for: - Same-type alt cert rejection (both RSA -> startup error) - Single cert mode regression (no alt cert still works) - SIGHUP reload adds alt cert (ECDSA becomes available) - SIGHUP reload removes alt cert (ECDSA no longer available) Remove the global ssl_max_protocol_version=TLSv1.2 restriction so TLS 1.3 connections are actually exercised (the openssl s_client tests already force -tls1_2 explicitly). Refactor config rewriting into a write_sslconfig() helper. 29 subtests total, up from 22. Author: Renaud Métrich --- src/test/ssl/t/004_ssl_alt_cert.pl | 111 ++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/src/test/ssl/t/004_ssl_alt_cert.pl b/src/test/ssl/t/004_ssl_alt_cert.pl index a148e0a7fb1..b4973bfc996 100644 --- a/src/test/ssl/t/004_ssl_alt_cert.pl +++ b/src/test/ssl/t/004_ssl_alt_cert.pl @@ -77,10 +77,6 @@ $node->append_conf('sslconfig.conf', $node->append_conf('sslconfig.conf', "ssl_alt_key_file='$ecdsa_key'"); -# Force TLS 1.2 so we can control cipher selection -$node->append_conf('sslconfig.conf', - "ssl_max_protocol_version='TLSv1.2'"); - $node->restart; #### Tests. @@ -146,16 +142,34 @@ $result = $node->safe_psql('trustdb', like($result, qr/RSA/, 'ssl_server_cert_types() includes RSA'); like($result, qr/ECDSA/, 'ssl_server_cert_types() includes ECDSA'); +# Helper to rewrite sslconfig.conf from scratch +sub write_sslconfig +{ + my ($node, %opts) = @_; + my $conf = $node->data_dir . '/sslconfig.conf'; + unlink($conf); + $node->append_conf('sslconfig.conf', "ssl=on"); + $node->append_conf('sslconfig.conf', + "ssl_ca_file='root+client_ca.crt'"); + $node->append_conf('sslconfig.conf', + "ssl_cert_file='server-cn-only.crt'"); + $node->append_conf('sslconfig.conf', + "ssl_key_file='server-cn-only.key'"); + foreach my $key (sort keys %opts) + { + $node->append_conf('sslconfig.conf', "$key=$opts{$key}"); + } +} + # Test 8: Verify server rejects mismatched alt cert/key configuration note "testing server rejects ssl_alt_cert_file without ssl_alt_key_file"; -$node->append_conf('sslconfig.conf', - "ssl_alt_key_file=''"); +write_sslconfig($node, + ssl_alt_cert_file => "'$ecdsa_crt'"); $result = $node->restart(fail_ok => 1); is($result, 0, 'restart fails with ssl_alt_cert_file set but ssl_alt_key_file empty'); -# Check the log for the expected error message my $log = slurp_file($node->logfile); like($log, qr/ssl_alt_cert_file is set but ssl_alt_key_file is not/, 'log contains expected error for missing ssl_alt_key_file'); @@ -163,16 +177,8 @@ like($log, qr/ssl_alt_cert_file is set but ssl_alt_key_file is not/, # Test 9: Verify the reverse mismatch (key without cert) note "testing server rejects ssl_alt_key_file without ssl_alt_cert_file"; -ok(unlink($node->data_dir . '/sslconfig.conf')); -$node->append_conf('sslconfig.conf', "ssl=on"); -$node->append_conf('sslconfig.conf', - "ssl_ca_file='root+client_ca.crt'"); -$node->append_conf('sslconfig.conf', - "ssl_cert_file='server-cn-only.crt'"); -$node->append_conf('sslconfig.conf', - "ssl_key_file='server-cn-only.key'"); -$node->append_conf('sslconfig.conf', - "ssl_alt_key_file='$ecdsa_key'"); +write_sslconfig($node, + ssl_alt_key_file => "'$ecdsa_key'"); $result = $node->restart(fail_ok => 1); is($result, 0, 'restart fails with ssl_alt_key_file set but ssl_alt_cert_file empty'); @@ -181,15 +187,70 @@ $log = slurp_file($node->logfile); like($log, qr/ssl_alt_key_file is set but ssl_alt_cert_file is not/, 'log contains expected error for missing ssl_alt_cert_file'); -# Restore valid config so the node can be stopped cleanly -ok(unlink($node->data_dir . '/sslconfig.conf')); -$node->append_conf('sslconfig.conf', "ssl=on"); -$node->append_conf('sslconfig.conf', - "ssl_ca_file='root+client_ca.crt'"); +# Test 10: Verify server rejects same-type alt cert (both RSA) +note "testing server rejects same-type alternate certificate"; + +write_sslconfig($node, + ssl_alt_cert_file => "'server-cn-only.crt'", + ssl_alt_key_file => "'server-cn-only.key'"); + +$result = $node->restart(fail_ok => 1); +is($result, 0, 'restart fails with same-type alt cert'); + +$log = slurp_file($node->logfile); +like($log, qr/alternate certificate has the same key type/, + 'log contains expected error for same-type alt cert'); + +# Test 11: Verify single cert still works (no alt cert regression) +note "testing single cert mode (no alt cert)"; + +write_sslconfig($node); +$node->start; + +$node->connect_ok( + "$common_connstr sslcert=invalid", + "connect with single RSA cert (no alt cert)", + sql => "SELECT 1"); + +$result = $node->safe_psql('trustdb', + "SELECT ssl_server_cert_type()", + connstr => "$common_connstr sslcert=invalid"); +is($result, 'RSA', 'ssl_server_cert_type() returns RSA with single cert'); + +# Test 12: Verify SIGHUP reload adds alt cert +note "testing SIGHUP reload adds alt certificate"; + $node->append_conf('sslconfig.conf', - "ssl_cert_file='server-cn-only.crt'"); + "ssl_alt_cert_file='$ecdsa_crt'"); $node->append_conf('sslconfig.conf', - "ssl_key_file='server-cn-only.key'"); -$node->start; + "ssl_alt_key_file='$ecdsa_key'"); +$node->reload; + +# Wait briefly for reload to take effect +sleep(1); + +# Verify ECDSA cipher now works after reload +my $openssl_after_reload = `echo "QUIT" | openssl s_client -connect $SERVERHOSTADDR:${\$node->port} -starttls postgres -tls1_2 -cipher ECDHE-ECDSA-AES256-GCM-SHA384 2>&1`; +like($openssl_after_reload, qr/ECDHE-ECDSA-AES256-GCM-SHA384/, + 'ECDSA cipher works after SIGHUP reload'); + +# Test 13: Verify SIGHUP reload removes alt cert +note "testing SIGHUP reload removes alt certificate"; + +write_sslconfig($node); +$node->reload; + +sleep(1); + +# Verify ECDSA cipher no longer works after removing alt cert +my $openssl_after_remove = `echo "QUIT" | openssl s_client -connect $SERVERHOSTADDR:${\$node->port} -starttls postgres -tls1_2 -cipher ECDHE-ECDSA-AES256-GCM-SHA384 2>&1`; +unlike($openssl_after_remove, qr/ECDHE-ECDSA-AES256-GCM-SHA384/, + 'ECDSA cipher fails after alt cert removed via SIGHUP'); + +# RSA still works +$node->connect_ok( + "$common_connstr sslcert=invalid", + "RSA connection works after alt cert removed via SIGHUP", + sql => "SELECT 1"); done_testing(); -- 2.52.0