From 896b812499ca13a6aac42e6a599151144bef6abc Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Fri, 5 Jun 2026 00:05:45 +0200
Subject: [PATCH v2 3/4] ssl: Replace deprecated API to get commonName

X509_NAME_get_text_by_NID was deprecated in OpenSSL 4.0.0, and could
be removed in a future version of OpenSSL.  The replacement APIs are
available in all versions of OpenSSL and LibreSSL that we support so
we can easily change to make the code future proof.

The reason for the deprecation is that X509_NAME_get_text_by_NID can
only grab the first entry in a list, and doesn't handle multibyte
strings well.  The fix is to get the index of the name entry with
X509_NAME_get_index_by_NID and use X509_NAME_get_entry to extract
the data.

Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Tristan Partin <tristan@partin.io>
Reviewed-by: Andreas Karlsson <andreas@proxel.se>
Discussion: https://postgr.es/m/68B9881D-DAA8-467D-A251-C96E98E57BA0@yesql.se
---
 src/backend/libpq/be-secure-openssl.c | 28 +++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 48eec54c062..e3320b59c7b 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -1071,22 +1071,30 @@ aloop:
 		char	   *peer_dn;
 		BIO		   *bio = NULL;
 		BUF_MEM    *bio_buf = NULL;
+		int			index;
 
-		len = X509_NAME_get_text_by_NID(unconstify(X509_NAME *, x509name), NID_commonName, NULL, 0);
-		if (len != -1)
+		index = X509_NAME_get_index_by_NID(unconstify(X509_NAME *, x509name), NID_commonName, -1);
+		if (index >= 0)
 		{
+			const X509_NAME_ENTRY *entry;
+			const ASN1_STRING *peer_cn_asn1;
+			const unsigned char *peer_cn_internal;
 			char	   *peer_cn;
 
+			entry = X509_NAME_get_entry(unconstify(X509_NAME *, x509name), index);
+			peer_cn_asn1 = X509_NAME_ENTRY_get_data(entry);
+			len = ASN1_STRING_length(peer_cn_asn1);
+
+			/*
+			 * peer_cn_internal is an internal OpenSSL owned pointer to the
+			 * plain char representation for the ASN1_STRING, it must not be
+			 * freed or it's content modified.
+			 */
+			peer_cn_internal = ASN1_STRING_get0_data(peer_cn_asn1);
+
 			peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1);
-			r = X509_NAME_get_text_by_NID(unconstify(X509_NAME *, x509name), NID_commonName, peer_cn,
-										  len + 1);
+			memcpy(peer_cn, peer_cn_internal, len);
 			peer_cn[len] = '\0';
-			if (r != len)
-			{
-				/* shouldn't happen */
-				pfree(peer_cn);
-				return -1;
-			}
 
 			/*
 			 * Reject embedded NULLs in certificate common name to prevent
-- 
2.39.3 (Apple Git-146)

