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. 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.
Reported-by: Jacob Champion
Discussion: https://www.postgresql.org/message-id/
6aedcaa5-60f3-49af-a857-
2c76ba55a1f3@iki.fi
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;
+ }
}
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