From 3f1f372feab12f1373973c4287a0cd5fcd4c2a6d Mon Sep 17 00:00:00 2001
From: Filip Janus <fjanus@redhat.com>
Date: Wed, 22 Oct 2025 22:31:25 +0200
Subject: [PATCH 1/2] Add regression test for ML-DSA channel binding support

Add a test case to verify that SCRAM channel binding works correctly
with ML-DSA-65 (post-quantum) server certificates.

This test is similar to the existing RSA-PSS test and verifies:
- ML-DSA-65 certificates can be loaded
- Channel binding works with post-quantum signature algorithms
- SCRAM-SHA-256 authentication succeeds
- No 'could not find digest for NID UNDEF' error occurs

The test uses a self-signed ML-DSA-65 certificate generated via
sslfiles.mk
---
 src/test/ssl/conf/server-mldsa65.config | 15 +++++++++++++++
 src/test/ssl/sslfiles.mk                | 14 ++++++++++++--
 src/test/ssl/t/002_scram.pl             | 19 +++++++++++++++++++
 3 files changed, 46 insertions(+), 2 deletions(-)
 create mode 100644 src/test/ssl/conf/server-mldsa65.config

diff --git a/src/test/ssl/conf/server-mldsa65.config b/src/test/ssl/conf/server-mldsa65.config
new file mode 100644
index 00000000000..acda640e58c
--- /dev/null
+++ b/src/test/ssl/conf/server-mldsa65.config
@@ -0,0 +1,15 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This is identical to server-cn-only certificate, but we specify
+# ML-DSA-65 as the algorithm on the command line.
+
+[ req ]
+distinguished_name     = req_distinguished_name
+prompt                 = no
+
+[ req_distinguished_name ]
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# No Subject Alternative Names
+
diff --git a/src/test/ssl/sslfiles.mk b/src/test/ssl/sslfiles.mk
index 23aaad0c766..b7e07ba5e44 100644
--- a/src/test/ssl/sslfiles.mk
+++ b/src/test/ssl/sslfiles.mk
@@ -40,14 +40,16 @@ CLIENTS := client client-dn client-revoked client_ext client-long \
 # To add a new non-standard certificate, add it to SPECIAL_CERTS and then add
 # a recipe for creating it to the "Special-case certificates" section below.
 #
-SPECIAL_CERTS := ssl/server-rsapss.crt
+SPECIAL_CERTS := ssl/server-rsapss.crt \
+	ssl/server-mldsa65.crt
 
 # Likewise for non-standard keys
 SPECIAL_KEYS := ssl/server-password.key \
 	ssl/client-der.key \
 	ssl/client-encrypted-pem.key \
 	ssl/client-encrypted-der.key \
-	ssl/server-rsapss.key
+	ssl/server-rsapss.key \
+	ssl/server-mldsa65.key
 
 #
 # These files are just concatenations of other files. You can add new ones to
@@ -101,6 +103,10 @@ ssl/root_ca.crt: ssl/root_ca.key conf/root_ca.config
 ssl/server-rsapss.crt: ssl/server-rsapss.key conf/server-rsapss.config
 	$(OPENSSL) req -new -x509 -config conf/server-rsapss.config -key $< -out $@
 
+# Certificate using ML-DSA-65 algorithm. Also self-signed.
+ssl/server-mldsa65.crt: ssl/server-mldsa65.key conf/server-mldsa65.config
+	$(OPENSSL) req -new -x509 -config conf/server-mldsa65.config -key $< -out $@
+
 #
 # Special-case keys
 #
@@ -115,6 +121,10 @@ ssl/server-password.key: ssl/server-cn-only.key
 ssl/server-rsapss.key:
 	$(OPENSSL) genpkey -algorithm rsa-pss -out $@
 
+# Key that uses the ML-DSA-65 algorithm
+ssl/server-mldsa65.key:
+	$(OPENSSL) genpkey -algorithm ML-DSA-65 -out $@
+
 # DER-encoded version of client.key
 ssl/client-der.key: ssl/client.key
 	$(OPENSSL) rsa -in $< -outform DER -out $@
diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl
index 60b60b28657..3132b6ba758 100644
--- a/src/test/ssl/t/002_scram.pl
+++ b/src/test/ssl/t/002_scram.pl
@@ -171,4 +171,23 @@ if ($supports_rsapss_certs)
 			qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
 		]);
 }
+
+# Now test with a server certificate that uses the ML-DSA-65 algorithm.
+# This tests post-quantum cryptography support for channel binding.
+SKIP:
+{
+	# Check if ML-DSA-65 certificate exists (requires OpenSSL 3.5+)
+	my $mldsa_cert = "ssl/server-mldsa65.crt";
+	skip "ML-DSA-65 requires OpenSSL 3.5+ for certificate generation", 1
+	  unless -f $mldsa_cert;
+
+	switch_server_cert($node, certfile => 'server-mldsa65');
+	$node->connect_ok(
+		"$common_connstr user=ssltestuser channel_binding=require",
+		"SCRAM with SSL and channel_binding=require, server certificate uses 'ML-DSA-65'",
+		log_like => [
+			qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
+		]);
+}
+
 done_testing();
-- 
2.39.5 (Apple Git-154)

