diff options
Diffstat (limited to 'src/interfaces/libpq/fe-secure.c')
-rw-r--r-- | src/interfaces/libpq/fe-secure.c | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 73a0b0cf078..f8a5f6e7a24 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -88,7 +88,7 @@ static int initialize_SSL(PGconn *conn); static void destroySSL(void); static PostgresPollingStatusType open_client_SSL(PGconn *); static void close_SSL(PGconn *); -static char *SSLerrmessage(void); +static char *SSLerrmessage(unsigned long ecode); static void SSLerrfree(char *buf); static bool pq_init_ssl_lib = true; @@ -277,7 +277,7 @@ pqsecure_open_client(PGconn *conn) !SSL_set_app_data(conn->ssl, conn) || !SSL_set_fd(conn->ssl, conn->sock)) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not establish SSL connection: %s\n"), @@ -342,6 +342,7 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len) if (conn->ssl) { int err; + unsigned long ecode; DECLARE_SIGPIPE_INFO(spinfo); @@ -349,9 +350,30 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len) DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: + /* + * Prepare to call SSL_get_error() by clearing thread's OpenSSL + * error queue. In general, the current thread's error queue must + * be empty before the TLS/SSL I/O operation is attempted, or + * SSL_get_error() will not work reliably. Since the possibility + * exists that other OpenSSL clients running in the same thread but + * not under our control will fail to call ERR_get_error() + * themselves (after their own I/O operations), pro-actively clear + * the per-thread error queue now. + */ SOCK_ERRNO_SET(0); + ERR_clear_error(); n = SSL_read(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); + + /* + * Other clients of OpenSSL may fail to call ERR_get_error(), but + * we always do, so as to not cause problems for OpenSSL clients + * that don't call ERR_clear_error() defensively. Be sure that + * this happens by calling now. SSL_get_error() relies on the + * OpenSSL per-thread error queue being intact, so this is the + * earliest possible point ERR_get_error() may be called. + */ + ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0; switch (err) { case SSL_ERROR_NONE: @@ -405,7 +427,7 @@ rloop: break; case SSL_ERROR_SSL: { - char *errm = SSLerrmessage(); + char *errm = SSLerrmessage(ecode); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); @@ -506,12 +528,15 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) if (conn->ssl) { int err; + unsigned long ecode; DISABLE_SIGPIPE(conn, spinfo, return -1); SOCK_ERRNO_SET(0); + ERR_clear_error(); n = SSL_write(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); + ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0; switch (err) { case SSL_ERROR_NONE: @@ -565,7 +590,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) break; case SSL_ERROR_SSL: { - char *errm = SSLerrmessage(); + char *errm = SSLerrmessage(ecode); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); @@ -974,7 +999,7 @@ init_ssl_system(PGconn *conn) SSL_context = SSL_CTX_new(SSLv23_method()); if (!SSL_context) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create SSL context: %s\n"), @@ -1139,7 +1164,7 @@ initialize_SSL(PGconn *conn) #endif if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), @@ -1154,7 +1179,7 @@ initialize_SSL(PGconn *conn) if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read certificate file \"%s\": %s\n"), @@ -1209,7 +1234,7 @@ initialize_SSL(PGconn *conn) conn->engine = ENGINE_by_id(engine_str); if (conn->engine == NULL) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load SSL engine \"%s\": %s\n"), @@ -1221,7 +1246,7 @@ initialize_SSL(PGconn *conn) if (ENGINE_init(conn->engine) == 0) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not initialize SSL engine \"%s\": %s\n"), @@ -1237,7 +1262,7 @@ initialize_SSL(PGconn *conn) NULL, NULL); if (pkey == NULL) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"), @@ -1251,7 +1276,7 @@ initialize_SSL(PGconn *conn) } if (SSL_use_PrivateKey(conn->ssl, pkey) != 1) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"), @@ -1307,7 +1332,7 @@ initialize_SSL(PGconn *conn) if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not load private key file \"%s\": %s\n"), @@ -1321,7 +1346,7 @@ initialize_SSL(PGconn *conn) if (have_cert && SSL_check_private_key(conn->ssl) != 1) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate does not match private key file \"%s\": %s\n"), @@ -1359,7 +1384,7 @@ initialize_SSL(PGconn *conn) #endif if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1) { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate file \"%s\": %s\n"), @@ -1389,7 +1414,7 @@ initialize_SSL(PGconn *conn) X509_STORE_set_flags(cvstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #else - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"), @@ -1452,11 +1477,14 @@ open_client_SSL(PGconn *conn) { int r; + ERR_clear_error(); r = SSL_connect(conn->ssl); if (r <= 0) { int err = SSL_get_error(conn->ssl, r); + unsigned long ecode; + ecode = ERR_get_error(); switch (err) { case SSL_ERROR_WANT_READ: @@ -1481,7 +1509,7 @@ open_client_SSL(PGconn *conn) } case SSL_ERROR_SSL: { - char *err = SSLerrmessage(); + char *err = SSLerrmessage(ecode); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), @@ -1509,7 +1537,9 @@ open_client_SSL(PGconn *conn) conn->peer = SSL_get_peer_certificate(conn->ssl); if (conn->peer == NULL) { - char *err = SSLerrmessage(); + char *err; + + err = SSLerrmessage(ERR_get_error()); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate could not be obtained: %s\n"), @@ -1585,7 +1615,9 @@ close_SSL(PGconn *conn) } /* - * Obtain reason string for last SSL error + * Obtain reason string for passed SSL errcode + * + * ERR_get_error() is used by caller to get errcode to pass here. * * Some caution is needed here since ERR_reason_error_string will * return NULL if it doesn't recognize the error code. We don't @@ -1596,28 +1628,26 @@ static char ssl_nomem[] = "out of memory allocating error description"; #define SSL_ERR_LEN 128 static char * -SSLerrmessage(void) +SSLerrmessage(unsigned long ecode) { - unsigned long errcode; const char *errreason; char *errbuf; errbuf = malloc(SSL_ERR_LEN); if (!errbuf) return ssl_nomem; - errcode = ERR_get_error(); - if (errcode == 0) + if (ecode == 0) { snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported")); return errbuf; } - errreason = ERR_reason_error_string(errcode); + errreason = ERR_reason_error_string(ecode); if (errreason != NULL) { strlcpy(errbuf, errreason, SSL_ERR_LEN); return errbuf; } - snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), errcode); + snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), ecode); return errbuf; } |