Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b63dd3d

Browse files
committed
Add hints about protocol-version-related SSL connection failures.
OpenSSL's native reports about problems related to protocol version restrictions are pretty opaque and inconsistent. When we get an SSL error that is plausibly due to this, emit a hint message that includes the range of SSL protocol versions we (think we) are allowing. This should at least get the user thinking in the right direction to resolve the problem, even if the hint isn't totally accurate, which it might not be for assorted reasons. Back-patch to v13 where we increased the default minimum protocol version, thereby increasing the risk of this class of failure. Patch by me, reviewed by Daniel Gustafsson Discussion: https://postgr.es/m/a9408304-4381-a5af-d259-e55d349ae4ce@2ndquadrant.com
1 parent 6e682f6 commit b63dd3d

File tree

3 files changed

+127
-2
lines changed

3 files changed

+127
-2
lines changed

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

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static bool dummy_ssl_passwd_cb_called = false;
7272
static bool ssl_is_server_start;
7373

7474
static int ssl_protocol_version_to_openssl(int v);
75+
static const char *ssl_protocol_version_to_string(int v);
7576

7677
/* ------------------------------------------------------------ */
7778
/* Public interface */
@@ -365,6 +366,7 @@ be_tls_open_server(Port *port)
365366
int err;
366367
int waitfor;
367368
unsigned long ecode;
369+
bool give_proto_hint;
368370

369371
Assert(!port->ssl);
370372
Assert(!port->peer);
@@ -451,10 +453,50 @@ be_tls_open_server(Port *port)
451453
errmsg("could not accept SSL connection: EOF detected")));
452454
break;
453455
case SSL_ERROR_SSL:
456+
switch (ERR_GET_REASON(ecode))
457+
{
458+
/*
459+
* UNSUPPORTED_PROTOCOL, WRONG_VERSION_NUMBER, and
460+
* TLSV1_ALERT_PROTOCOL_VERSION have been observed
461+
* when trying to communicate with an old OpenSSL
462+
* library, or when the client and server specify
463+
* disjoint protocol ranges. NO_PROTOCOLS_AVAILABLE
464+
* occurs if there's a local misconfiguration (which
465+
* can happen despite our checks, if openssl.cnf
466+
* injects a limit we didn't account for). It's not
467+
* very clear what would make OpenSSL return the other
468+
* codes listed here, but a hint about protocol
469+
* versions seems like it's appropriate for all.
470+
*/
471+
case SSL_R_NO_PROTOCOLS_AVAILABLE:
472+
case SSL_R_UNSUPPORTED_PROTOCOL:
473+
case SSL_R_BAD_PROTOCOL_VERSION_NUMBER:
474+
case SSL_R_UNKNOWN_PROTOCOL:
475+
case SSL_R_UNKNOWN_SSL_VERSION:
476+
case SSL_R_UNSUPPORTED_SSL_VERSION:
477+
case SSL_R_VERSION_TOO_HIGH:
478+
case SSL_R_VERSION_TOO_LOW:
479+
case SSL_R_WRONG_SSL_VERSION:
480+
case SSL_R_WRONG_VERSION_NUMBER:
481+
case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:
482+
give_proto_hint = true;
483+
break;
484+
default:
485+
give_proto_hint = false;
486+
break;
487+
}
454488
ereport(COMMERROR,
455489
(errcode(ERRCODE_PROTOCOL_VIOLATION),
456490
errmsg("could not accept SSL connection: %s",
457-
SSLerrmessage(ecode))));
491+
SSLerrmessage(ecode)),
492+
give_proto_hint ?
493+
errhint("This may indicate that the client does not support any SSL protocol version between %s and %s.",
494+
ssl_min_protocol_version ?
495+
ssl_protocol_version_to_string(ssl_min_protocol_version) :
496+
MIN_OPENSSL_TLS_VERSION,
497+
ssl_max_protocol_version ?
498+
ssl_protocol_version_to_string(ssl_max_protocol_version) :
499+
MAX_OPENSSL_TLS_VERSION) : 0));
458500
break;
459501
case SSL_ERROR_ZERO_RETURN:
460502
ereport(COMMERROR,
@@ -1328,6 +1370,29 @@ ssl_protocol_version_to_openssl(int v)
13281370
return -1;
13291371
}
13301372

1373+
/*
1374+
* Likewise provide a mapping to strings.
1375+
*/
1376+
static const char *
1377+
ssl_protocol_version_to_string(int v)
1378+
{
1379+
switch (v)
1380+
{
1381+
case PG_TLS_ANY:
1382+
return "any";
1383+
case PG_TLS1_VERSION:
1384+
return "TLSv1";
1385+
case PG_TLS1_1_VERSION:
1386+
return "TLSv1.1";
1387+
case PG_TLS1_2_VERSION:
1388+
return "TLSv1.2";
1389+
case PG_TLS1_3_VERSION:
1390+
return "TLSv1.3";
1391+
}
1392+
1393+
return "(unrecognized)";
1394+
}
1395+
13311396

13321397
static void
13331398
default_openssl_tls_init(SSL_CTX *context, bool isServerStart)

src/include/common/openssl.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,33 @@
1717
#ifdef USE_OPENSSL
1818
#include <openssl/ssl.h>
1919

20+
/*
21+
* OpenSSL doesn't provide any very nice way to identify the min/max
22+
* protocol versions the library supports, so we fake it as best we can.
23+
* Note in particular that this doesn't account for restrictions that
24+
* might be specified in the installation's openssl.cnf.
25+
*
26+
* We disable SSLv3 and older in library setup, so TLSv1 is the oldest
27+
* protocol version of interest.
28+
*/
29+
#define MIN_OPENSSL_TLS_VERSION "TLSv1"
30+
31+
#if defined(TLS1_3_VERSION)
32+
#define MAX_OPENSSL_TLS_VERSION "TLSv1.3"
33+
#elif defined(TLS1_2_VERSION)
34+
#define MAX_OPENSSL_TLS_VERSION "TLSv1.2"
35+
#elif defined(TLS1_1_VERSION)
36+
#define MAX_OPENSSL_TLS_VERSION "TLSv1.1"
37+
#else
38+
#define MAX_OPENSSL_TLS_VERSION "TLSv1"
39+
#endif
40+
2041
/* src/common/protocol_openssl.c */
2142
#ifndef SSL_CTX_set_min_proto_version
2243
extern int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);
2344
extern int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version);
2445
#endif
2546

26-
#endif
47+
#endif /* USE_OPENSSL */
2748

2849
#endif /* COMMON_OPENSSL_H */

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,45 @@ open_client_SSL(PGconn *conn)
13041304
libpq_gettext("SSL error: %s\n"),
13051305
err);
13061306
SSLerrfree(err);
1307+
switch (ERR_GET_REASON(ecode))
1308+
{
1309+
/*
1310+
* UNSUPPORTED_PROTOCOL, WRONG_VERSION_NUMBER, and
1311+
* TLSV1_ALERT_PROTOCOL_VERSION have been observed
1312+
* when trying to communicate with an old OpenSSL
1313+
* library, or when the client and server specify
1314+
* disjoint protocol ranges.
1315+
* NO_PROTOCOLS_AVAILABLE occurs if there's a
1316+
* local misconfiguration (which can happen
1317+
* despite our checks, if openssl.cnf injects a
1318+
* limit we didn't account for). It's not very
1319+
* clear what would make OpenSSL return the other
1320+
* codes listed here, but a hint about protocol
1321+
* versions seems like it's appropriate for all.
1322+
*/
1323+
case SSL_R_NO_PROTOCOLS_AVAILABLE:
1324+
case SSL_R_UNSUPPORTED_PROTOCOL:
1325+
case SSL_R_BAD_PROTOCOL_VERSION_NUMBER:
1326+
case SSL_R_UNKNOWN_PROTOCOL:
1327+
case SSL_R_UNKNOWN_SSL_VERSION:
1328+
case SSL_R_UNSUPPORTED_SSL_VERSION:
1329+
case SSL_R_VERSION_TOO_HIGH:
1330+
case SSL_R_VERSION_TOO_LOW:
1331+
case SSL_R_WRONG_SSL_VERSION:
1332+
case SSL_R_WRONG_VERSION_NUMBER:
1333+
case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:
1334+
appendPQExpBuffer(&conn->errorMessage,
1335+
libpq_gettext("This may indicate that the server does not support any SSL protocol version between %s and %s.\n"),
1336+
conn->ssl_min_protocol_version ?
1337+
conn->ssl_min_protocol_version :
1338+
MIN_OPENSSL_TLS_VERSION,
1339+
conn->ssl_max_protocol_version ?
1340+
conn->ssl_max_protocol_version :
1341+
MAX_OPENSSL_TLS_VERSION);
1342+
break;
1343+
default:
1344+
break;
1345+
}
13071346
pgtls_close(conn);
13081347
return PGRES_POLLING_FAILED;
13091348
}

0 commit comments

Comments
 (0)