0001-Reject-SSL-connection-if-ALPN-is-used-but-there-s-no.patch
text/x-patch
Filename: 0001-Reject-SSL-connection-if-ALPN-is-used-but-there-s-no.patch
Type: text/x-patch
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: Reject SSL connection if ALPN is used but there's no common protocol
| File | + | − |
|---|---|---|
| src/backend/libpq/be-secure-openssl.c | 7 | 3 |
| src/interfaces/libpq/fe-secure-openssl.c | 12 | 0 |
From 125e9adda6cdab644b660772e29c713863e93cc2 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Sat, 27 Apr 2024 01:47:55 +0300
Subject: [PATCH 1/1] Reject SSL connection if ALPN is used but there's no
common protocol
If the client supports ALPN but tries to use some other protocol, like
HTTPS, reject the connection in the server. That is surely a confusion
of some sort like trying to PostgreSQL server with a
browser. Furthermore, the ALPN RFC 7301 says:
> In the event that the server supports no protocols that the client
> advertises, then the server SHALL respond with a fatal
> "no_application_protocol" alert.
This commit makes the server follow that advice.
In the client, specifically check for the OpenSSL error code for the
"no_application_protocol" alert. Otherwise you got a cryptic "SSL
error: SSL error code 167773280" error if you tried to connect to a
non-PostgreSQL server that rejects the connection with
"no_application_protocol". ERR_reason_error_string() returns NULL for
that code, which frankly seems like an OpenSSL bug to me, but we can
easily print a better message ourselves.
---
src/backend/libpq/be-secure-openssl.c | 10 +++++++---
src/interfaces/libpq/fe-secure-openssl.c | 12 ++++++++++++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index fc46a33539..60cf68aac4 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -1336,10 +1336,14 @@ alpn_cb(SSL *ssl,
if (retval == OPENSSL_NPN_NEGOTIATED)
return SSL_TLSEXT_ERR_OK;
- else if (retval == OPENSSL_NPN_NO_OVERLAP)
- return SSL_TLSEXT_ERR_NOACK;
else
- return SSL_TLSEXT_ERR_NOACK;
+ {
+ /*
+ * The client doesn't support our protocol. Reject the connection
+ * with TLS "no_application_protocol" alert, per RFC 7301.
+ */
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
}
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index 0de21dc7e4..ee1a47f2b1 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -1741,6 +1741,18 @@ SSLerrmessage(unsigned long ecode)
return errbuf;
}
+ if (ERR_GET_LIB(ecode) == ERR_LIB_SSL &&
+ ERR_GET_REASON(ecode) == SSL_AD_REASON_OFFSET + SSL_AD_NO_APPLICATION_PROTOCOL)
+ {
+ /*
+ * Server aborted the connection with TLS "no_application_protocol"
+ * alert. The ERR_reason_error_string() function doesn't give any
+ * error string for that for some reason, so do it ourselves.
+ */
+ snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no application protocol"));
+ return errbuf;
+ }
+
/*
* In OpenSSL 3.0.0 and later, ERR_reason_error_string randomly refuses to
* map system errno values. We can cover that shortcoming with this bit
--
2.39.2