From c0966084b91818bdf3d35e87666399c7e59298d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Mon, 15 Jun 2026 08:15:50 +0200
Subject: [PATCH v2 4/8] Load alternate certificates only for the default host
 context
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The global ssl_alt_cert_file/ssl_alt_key_file GUCs were being loaded
into every host context, including per-host SNI entries from
pg_hosts.conf.  This caused unintended behavior: if an SNI host used
a different key type, the alt cert was added as an alternative; if the
same type, it silently replaced the host cert.

Add an is_default parameter to init_host_context() and only load the
alternate certificate for the default host context (postgresql.conf),
not for per-host SNI entries.

Author: Renaud Métrich <rmetrich@redhat.com>
---
 src/backend/libpq/be-secure-openssl.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index fa9f551e22a..6964830c5af 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -98,7 +98,7 @@ static bool initialize_dh(SSL_CTX *context, bool isServerStart);
 static bool initialize_ecdh(SSL_CTX *context, bool isServerStart);
 static const char *SSLerrmessageExt(unsigned long ecode, const char *replacement);
 static const char *SSLerrmessage(unsigned long ecode);
-static bool init_host_context(HostsLine *host, bool isServerStart);
+static bool init_host_context(HostsLine *host, bool isServerStart, bool is_default);
 static void host_context_cleanup_cb(void *arg);
 #ifdef HAVE_SSL_CTX_SET_CLIENT_HELLO_CB
 static int	sni_clienthello_cb(SSL *ssl, int *al, void *arg);
@@ -251,7 +251,7 @@ be_tls_init(bool isServerStart)
 		{
 			HostsLine  *host = lfirst(line);
 
-			if (!init_host_context(host, isServerStart))
+			if (!init_host_context(host, isServerStart, false))
 				goto error;
 
 			/*
@@ -346,7 +346,7 @@ be_tls_init(bool isServerStart)
 		pgconf->ssl_passphrase_cmd = ssl_passphrase_command;
 		pgconf->ssl_passphrase_reload = ssl_passphrase_command_supports_reload;
 
-		if (!init_host_context(pgconf, isServerStart))
+		if (!init_host_context(pgconf, isServerStart, true))
 			goto error;
 
 		/*
@@ -655,7 +655,7 @@ host_context_cleanup_cb(void *arg)
 }
 
 static bool
-init_host_context(HostsLine *host, bool isServerStart)
+init_host_context(HostsLine *host, bool isServerStart, bool is_default)
 {
 	SSL_CTX    *ctx = SSL_CTX_new(SSLv23_method());
 	static bool init_warned = false;
@@ -784,23 +784,25 @@ init_host_context(HostsLine *host, bool isServerStart)
 	/*
 	 * Load alternate certificate (e.g. ECDSA alongside RSA) into the same
 	 * context.  OpenSSL supports one certificate per key type and selects
-	 * the appropriate one during the TLS handshake.
+	 * the appropriate one during the TLS handshake.  Only load for the
+	 * default host context (postgresql.conf), not for per-host SNI entries
+	 * from pg_hosts.conf.
 	 */
-	if (ssl_alt_cert_file[0] && !ssl_alt_key_file[0])
+	if (is_default && ssl_alt_cert_file[0] && !ssl_alt_key_file[0])
 	{
 		ereport(isServerStart ? FATAL : LOG,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("ssl_alt_cert_file is set but ssl_alt_key_file is not")));
 		goto error;
 	}
-	if (!ssl_alt_cert_file[0] && ssl_alt_key_file[0])
+	if (is_default && !ssl_alt_cert_file[0] && ssl_alt_key_file[0])
 	{
 		ereport(isServerStart ? FATAL : LOG,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("ssl_alt_key_file is set but ssl_alt_cert_file is not")));
 		goto error;
 	}
-	if (ssl_alt_cert_file[0] && ssl_alt_key_file[0])
+	if (is_default && ssl_alt_cert_file[0] && ssl_alt_key_file[0])
 	{
 		if (SSL_CTX_use_certificate_chain_file(ctx, ssl_alt_cert_file) != 1)
 		{
-- 
2.52.0

