On Wed, Aug 12, 2026 at 10:20:33AM +0900, Michael Paquier wrote:
> Now I think that this patch should be reworked in a style closer to
> what has been done in 1f3b9bb109b8 and b91f79cd08ab:
> - Keep the variable declarations at the top of each function.  For
> example algo_type is shared between the pre-3.0 block and the post-3.0
> block.  No need for two declarations.
> - The #if parts work as the way as the curly brackets, let's remove
> one level of indentation.  Your patch makes the whole diff harder to
> parse and the pre-3.0 code is still the same.
> - Minimization of the diffs by planting more #if blocks.  Here I am
> looking at the EVP_MD_free() calls.  Let's minimize the duplicated
> libpq_append_conn_error() and elog(ERROR) calls in the final result.

As this part was itching me, I have taken a shot at simplifying the
patch, and it looks much better once adapted among these lines.  The
EVP_MD_free() feel slightly annoying, but they're isolated enough that
they don't matter to me.  A second thing is the const marker for
EVP_MD, which avoids some casts or some unconstify().  At the end that
feels like the best thing to do.

Attached is the refined version.  Comments and/or objections?
--
Michael
From f8a34f9e3997923479d571c850acaf57f759c564 Mon Sep 17 00:00:00 2001
From: Michael Paquier <[email protected]>
Date: Thu, 13 Aug 2026 09:57:27 +0900
Subject: [PATCH v2] Use explicit fetching of digests in channel binding
 (OpenSSL >= 3.0)

This touches both the libpq and backend-side code of channel binding
where respectively pgtls_get_peer_certificate_hash() and
be_tls_get_certificate_hash() are upgraded to retrieve digests using the
method recommended by OpenSSL 3.0: no more EVP_sha256(), just a
EVP_get_digestbynid() through EVP.

The pre-3.0 code is still required for LibreSSL and as long as we
support OpenSSL 1.1.1.
---
 src/backend/libpq/be-secure-openssl.c    | 34 +++++++++++++++++++++
 src/interfaces/libpq/fe-secure-openssl.c | 38 ++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/src/backend/libpq/be-secure-openssl.c 
b/src/backend/libpq/be-secure-openssl.c
index 047647008458..4f4ffca21b86 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -2282,7 +2282,12 @@ be_tls_get_certificate_hash(Port *port, size_t *len)
 {
        X509       *server_cert;
        char       *cert_hash;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       EVP_MD     *algo_type;
+       const char *algo_name;
+#else
        const EVP_MD *algo_type = NULL;
+#endif
        unsigned char hash[EVP_MAX_MD_SIZE];    /* size for SHA-512 */
        unsigned int hash_size;
        int                     algo_nid;
@@ -2311,6 +2316,25 @@ be_tls_get_certificate_hash(Port *port, size_t *len)
         * (https://tools.ietf.org/html/rfc5929#section-4.1).  If something else
         * is used, the same hash as the signature algorithm is used.
         */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       switch (algo_nid)
+       {
+               case NID_md5:
+               case NID_sha1:
+                       algo_name = "SHA256";
+                       break;
+               default:
+                       algo_name = OBJ_nid2sn(algo_nid);
+                       if (algo_name == NULL)
+                               elog(ERROR, "could not find digest for NID %s",
+                                        OBJ_nid2sn(algo_nid));
+                       break;
+       }
+
+       algo_type = EVP_MD_fetch(NULL, algo_name, NULL);
+       if (algo_type == NULL)
+               elog(ERROR, "could not fetch digest \"%s\"", algo_name);
+#else
        switch (algo_nid)
        {
                case NID_md5:
@@ -2324,10 +2348,20 @@ be_tls_get_certificate_hash(Port *port, size_t *len)
                                         OBJ_nid2sn(algo_nid));
                        break;
        }
+#endif
 
        /* generate and save the certificate hash */
        if (!X509_digest(server_cert, algo_type, hash, &hash_size))
+       {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+               EVP_MD_free(algo_type);
+#endif
                elog(ERROR, "could not generate server certificate hash");
+       }
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       EVP_MD_free(algo_type);
+#endif
 
        cert_hash = palloc(hash_size);
        memcpy(cert_hash, hash, hash_size);
diff --git a/src/interfaces/libpq/fe-secure-openssl.c 
b/src/interfaces/libpq/fe-secure-openssl.c
index 3ef12987feea..47ca0f470141 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -371,7 +371,12 @@ char *
 pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
 {
        X509       *peer_cert;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       EVP_MD     *algo_type;
+       const char *algo_name;
+#else
        const EVP_MD *algo_type;
+#endif
        unsigned char hash[EVP_MAX_MD_SIZE];    /* size for SHA-512 */
        unsigned int hash_size;
        int                     algo_nid;
@@ -406,6 +411,31 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
         * (https://tools.ietf.org/html/rfc5929#section-4.1).  If something else
         * is used, the same hash as the signature algorithm is used.
         */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       switch (algo_nid)
+       {
+               case NID_md5:
+               case NID_sha1:
+                       algo_name = "SHA256";
+                       break;
+               default:
+                       algo_name = OBJ_nid2sn(algo_nid);
+                       if (algo_name == NULL)
+                       {
+                               libpq_append_conn_error(conn, "could not find 
digest for NID %s",
+                                                                               
OBJ_nid2sn(algo_nid));
+                               return NULL;
+                       }
+                       break;
+       }
+
+       algo_type = EVP_MD_fetch(NULL, algo_name, NULL);
+       if (algo_type == NULL)
+       {
+               libpq_append_conn_error(conn, "could not fetch digest \"%s\"", 
algo_name);
+               return NULL;
+       }
+#else
        switch (algo_nid)
        {
                case NID_md5:
@@ -422,13 +452,21 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
                        }
                        break;
        }
+#endif
 
        if (!X509_digest(peer_cert, algo_type, hash, &hash_size))
        {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+               EVP_MD_free(algo_type);
+#endif
                libpq_append_conn_error(conn, "could not generate peer 
certificate hash");
                return NULL;
        }
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+       EVP_MD_free(algo_type);
+#endif
+
        /* save result */
        cert_hash = malloc(hash_size);
        if (cert_hash == NULL)
-- 
2.55.0

Attachment: signature.asc
Description: PGP signature

Reply via email to