Skip to content

Commit a40e7b7

Browse files
committed
Fix handling of SCRAM-SHA-256's channel binding with RSA-PSS certificates
OpenSSL 1.1.1 and newer versions have added support for RSA-PSS certificates, which requires the use of a specific routine in OpenSSL to determine which hash function to use when compiling it when using channel binding in SCRAM-SHA-256. X509_get_signature_nid(), that is the original routine the channel binding code has relied on, is not able to determine which hash algorithm to use for such certificates. However, X509_get_signature_info(), new to OpenSSL 1.1.1, is able to do it. This commit switches the channel binding logic to rely on X509_get_signature_info() over X509_get_signature_nid(), which would be the choice when building with 1.1.1 or newer. The error could have been triggered on the client or the server, hence libpq and the backend need to have their related code paths patched. Note that attempting to load an RSA-PSS certificate with OpenSSL 1.1.0 or older leads to a failure due to an unsupported algorithm. The discovery of relying on X509_get_signature_info() comes from Jacob, the tests have been written by Heikki (with few tweaks from me), while I have bundled the whole together while adding the bits needed for MSVC and meson. This issue exists since channel binding exists, so backpatch all the way down. Some tests are added in 15~, triggered if compiling with OpenSSL 1.1.1 or newer, where the certificate and key files can easily be generated for RSA-PSS. Reported-by: Gunnar "Nick" Bluth Author: Jacob Champion, Heikki Linnakangas Discussion: https://postgr.es/m/17760-b6c61e752ec07060@postgresql.org Backpatch-through: 11
1 parent ac55abd commit a40e7b7

File tree

8 files changed

+41
-7
lines changed

8 files changed

+41
-7
lines changed

configure

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12658,6 +12658,18 @@ if test "x$ac_cv_func_CRYPTO_lock" = xyes; then :
1265812658
#define HAVE_CRYPTO_LOCK 1
1265912659
_ACEOF
1266012660

12661+
fi
12662+
done
12663+
12664+
# Function introduced in OpenSSL 1.1.1.
12665+
for ac_func in X509_get_signature_info
12666+
do :
12667+
ac_fn_c_check_func "$LINENO" "X509_get_signature_info" "ac_cv_func_X509_get_signature_info"
12668+
if test "x$ac_cv_func_X509_get_signature_info" = xyes; then :
12669+
cat >>confdefs.h <<_ACEOF
12670+
#define HAVE_X509_GET_SIGNATURE_INFO 1
12671+
_ACEOF
12672+
1266112673
fi
1266212674
done
1266312675

configure.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,8 @@ if test "$with_openssl" = yes ; then
12921292
# thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
12931293
# function was removed.
12941294
AC_CHECK_FUNCS([CRYPTO_lock])
1295+
# Function introduced in OpenSSL 1.1.1.
1296+
AC_CHECK_FUNCS([X509_get_signature_info])
12951297
# SSL_clear_options is a macro in OpenSSL from 0.9.8 to 1.0.2, and
12961298
# a function from 1.1.0 onwards so we cannot use AC_CHECK_FUNCS.
12971299
AC_CACHE_CHECK([for SSL_clear_options], ac_cv_func_ssl_clear_options,

src/backend/libpq/be-secure-openssl.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
11931193
ptr[0] = '\0';
11941194
}
11951195

1196-
#ifdef HAVE_X509_GET_SIGNATURE_NID
1196+
#if defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO)
11971197
char *
11981198
be_tls_get_certificate_hash(Port *port, size_t *len)
11991199
{
@@ -1211,10 +1211,15 @@ be_tls_get_certificate_hash(Port *port, size_t *len)
12111211

12121212
/*
12131213
* Get the signature algorithm of the certificate to determine the hash
1214-
* algorithm to use for the result.
1214+
* algorithm to use for the result. Prefer X509_get_signature_info(),
1215+
* introduced in OpenSSL 1.1.1, which can handle RSA-PSS signatures.
12151216
*/
1217+
#if HAVE_X509_GET_SIGNATURE_INFO
1218+
if (!X509_get_signature_info(server_cert, &algo_nid, NULL, NULL, NULL))
1219+
#else
12161220
if (!OBJ_find_sigid_algs(X509_get_signature_nid(server_cert),
12171221
&algo_nid, NULL))
1222+
#endif
12181223
elog(ERROR, "could not determine server certificate signature algorithm");
12191224

12201225
/*

src/include/libpq/libpq-be.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ extern void be_tls_get_peer_serial(Port *port, char *ptr, size_t len);
282282
* This is not supported with old versions of OpenSSL that don't have
283283
* the X509_get_signature_nid() function.
284284
*/
285-
#if defined(USE_OPENSSL) && defined(HAVE_X509_GET_SIGNATURE_NID)
285+
#if defined(USE_OPENSSL) && (defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO))
286286
#define HAVE_BE_TLS_GET_CERTIFICATE_HASH
287287
extern char *be_tls_get_certificate_hash(Port *port, size_t *len);
288288
#endif

src/include/pg_config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,9 @@
733733
/* Define to 1 if you have the <winldap.h> header file. */
734734
#undef HAVE_WINLDAP_H
735735

736+
/* Define to 1 if you have the `X509_get_signature_info' function. */
737+
#undef HAVE_X509_GET_SIGNATURE_INFO
738+
736739
/* Define to 1 if you have the `X509_get_signature_nid' function. */
737740
#undef HAVE_X509_GET_SIGNATURE_NID
738741

src/interfaces/libpq/fe-secure-openssl.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
369369
return n;
370370
}
371371

372-
#ifdef HAVE_X509_GET_SIGNATURE_NID
372+
#if defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO)
373373
char *
374374
pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
375375
{
@@ -389,10 +389,15 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
389389

390390
/*
391391
* Get the signature algorithm of the certificate to determine the hash
392-
* algorithm to use for the result.
392+
* algorithm to use for the result. Prefer X509_get_signature_info(),
393+
* introduced in OpenSSL 1.1.1, which can handle RSA-PSS signatures.
393394
*/
395+
#if HAVE_X509_GET_SIGNATURE_INFO
396+
if (!X509_get_signature_info(peer_cert, &algo_nid, NULL, NULL, NULL))
397+
#else
394398
if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert),
395399
&algo_nid, NULL))
400+
#endif
396401
{
397402
printfPQExpBuffer(&conn->errorMessage,
398403
libpq_gettext("could not determine server certificate signature algorithm\n"));

src/interfaces/libpq/libpq-int.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len);
750750
* This is not supported with old versions of OpenSSL that don't have
751751
* the X509_get_signature_nid() function.
752752
*/
753-
#if defined(USE_OPENSSL) && defined(HAVE_X509_GET_SIGNATURE_NID)
753+
#if defined(USE_OPENSSL) && (defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO))
754754
#define HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
755755
extern char *pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len);
756756
#endif

src/tools/msvc/Solution.pm

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,14 @@ sub GenerateFiles
253253

254254
my ($digit1, $digit2, $digit3) = $self->GetOpenSSLVersion();
255255

256-
# More symbols are needed with OpenSSL 1.1.0 and above.
256+
# Symbols needed with OpenSSL 1.1.1 and above.
257+
if ( ($digit1 >= '3' && $digit2 >= '0' && $digit3 >= '0')
258+
|| ($digit1 >= '1' && $digit2 >= '1' && $digit3 >= '1'))
259+
{
260+
print $o "#define HAVE_X509_GET_SIGNATURE_INFO 1\n";
261+
}
262+
263+
# Symbols needed with OpenSSL 1.1.0 and above.
257264
if ( ($digit1 >= '3' && $digit2 >= '0' && $digit3 >= '0')
258265
|| ($digit1 >= '1' && $digit2 >= '1' && $digit3 >= '0'))
259266
{

0 commit comments

Comments
 (0)