From f8a34f9e3997923479d571c850acaf57f759c564 Mon Sep 17 00:00:00 2001 From: Michael Paquier 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