From 28995f051e72a1efae0e85d0ea43f80c38166657 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 14 Aug 2026 07:37:01 +0900 Subject: [PATCH] Use explicit fetching of digests in channel binding (OpenSSL >= 3.0) This commit 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 direct EVP_sha256() or similar, just a EVP_MD_fetch() through EVP to get an algorythm type, based on a name. The pre-3.0 code is still required for LibreSSL and as long as we support OpenSSL 1.1.1. Similar work has been done in b91f79cd08ab and 1f3b9bb109b8. Author: Mark Atwood Co-authored-by: Michael Paquier Discussion: https://postgr.es/m/178596055149.1584250.13974609482797470185@reviewcommit.com --- 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 04764700845..4f4ffca21b8 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 3ef12987fee..47ca0f47014 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)