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

1704 lines
43 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* fe-secure-openssl.c
* OpenSSL support
*
*
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/interfaces/libpq/fe-secure-openssl.c
*
* NOTES
*
* We don't provide informational callbacks here (like
* info_cb() in be-secure.c), since there's no good mechanism to
* display such information to the user.
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include "libpq-fe.h"
#include "fe-auth.h"
#include "libpq-int.h"
#ifdef WIN32
#include "win32.h"
#else
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#include <arpa/inet.h>
#endif
#include <sys/stat.h>
#ifdef ENABLE_THREAD_SAFETY
#ifdef WIN32
#include "pthread-win32.h"
#else
#include <pthread.h>
#endif
#endif
#include <openssl/ssl.h>
#include <openssl/conf.h>
#ifdef USE_SSL_ENGINE
#include <openssl/engine.h>
#endif
#include <openssl/x509v3.h>
static bool verify_peer_name_matches_certificate(PGconn *);
static int verify_cb(int ok, X509_STORE_CTX *ctx);
2015-05-24 03:35:49 +02:00
static int verify_peer_name_matches_certificate_name(PGconn *conn,
ASN1_STRING *name,
char **store_name);
static void destroy_ssl_system(void);
static int initialize_SSL(PGconn *conn);
static PostgresPollingStatusType open_client_SSL(PGconn *);
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
static char *SSLerrmessage(unsigned long ecode);
static void SSLerrfree(char *buf);
2015-05-24 03:35:49 +02:00
static int my_sock_read(BIO *h, char *buf, int size);
static int my_sock_write(BIO *h, const char *buf, int size);
static BIO_METHOD *my_BIO_s_socket(void);
2015-05-24 03:35:49 +02:00
static int my_SSL_set_fd(PGconn *conn, int fd);
static bool pq_init_ssl_lib = true;
static bool pq_init_crypto_lib = true;
static bool ssl_lib_initialized = false;
#ifdef ENABLE_THREAD_SAFETY
static long ssl_open_connections = 0;
#ifndef WIN32
static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
#else
static pthread_mutex_t ssl_config_mutex = NULL;
static long win32_ssl_create_mutex = 0;
#endif
#endif /* ENABLE_THREAD_SAFETY */
/* ------------------------------------------------------------ */
/* Procedures common to all secure sessions */
/* ------------------------------------------------------------ */
/*
* Exported function to allow application to tell us it's already
* initialized OpenSSL and/or libcrypto.
*/
void
pgtls_init_library(bool do_ssl, int do_crypto)
{
#ifdef ENABLE_THREAD_SAFETY
/*
* Disallow changing the flags while we have open connections, else we'd
* get completely confused.
*/
if (ssl_open_connections != 0)
return;
#endif
pq_init_ssl_lib = do_ssl;
pq_init_crypto_lib = do_crypto;
}
/*
* Begin or continue negotiating a secure session.
*/
PostgresPollingStatusType
pgtls_open_client(PGconn *conn)
{
/* First time through? */
if (conn->ssl == NULL)
{
/*
* Create a connection-specific SSL object, and load client certificate,
* private key, and trusted CA certs.
*/
if (initialize_SSL(conn) != 0)
{
/* initialize_SSL already put a message in conn->errorMessage */
pgtls_close(conn);
return PGRES_POLLING_FAILED;
}
}
/* Begin or continue the actual handshake */
return open_client_SSL(conn);
}
/*
2015-05-24 03:35:49 +02:00
* Is there unread data waiting in the SSL read buffer?
*/
bool
pgtls_read_pending(PGconn *conn)
{
return SSL_pending(conn->ssl);
}
/*
* Read data from a secure connection.
*
* On failure, this function is responsible for putting a suitable message
* into conn->errorMessage. The caller must still inspect errno, but only
* to determine whether to continue/retry after error.
*/
ssize_t
pgtls_read(PGconn *conn, void *ptr, size_t len)
{
ssize_t n;
int result_errno = 0;
char sebuf[256];
int err;
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
unsigned long ecode;
rloop:
2016-06-10 00:02:36 +02:00
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
/*
* Prepare to call SSL_get_error() by clearing thread's OpenSSL error
* queue. In general, the current thread's error queue must be empty
2016-06-10 00:02:36 +02:00
* 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.
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
*/
SOCK_ERRNO_SET(0);
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
ERR_clear_error();
n = SSL_read(conn->ssl, ptr, len);
err = SSL_get_error(conn->ssl, n);
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
/*
* Other clients of OpenSSL may fail to call ERR_get_error(), but we
2016-06-10 00:02:36 +02:00
* 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.
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
*/
ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0;
switch (err)
{
case SSL_ERROR_NONE:
if (n < 0)
{
/* Not supposed to happen, so we don't translate the msg */
printfPQExpBuffer(&conn->errorMessage,
2015-05-24 03:35:49 +02:00
"SSL_read failed but did not provide error information\n");
/* assume the connection is broken */
result_errno = ECONNRESET;
}
break;
case SSL_ERROR_WANT_READ:
n = 0;
break;
case SSL_ERROR_WANT_WRITE:
/*
* Returning 0 here would cause caller to wait for read-ready,
* which is not correct since what SSL wants is wait for
* write-ready. The former could get us stuck in an infinite
* wait, so don't risk it; busy-loop instead.
*/
goto rloop;
case SSL_ERROR_SYSCALL:
if (n < 0)
{
result_errno = SOCK_ERRNO;
if (result_errno == EPIPE ||
result_errno == ECONNRESET)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
2015-05-24 03:35:49 +02:00
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
else
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf)));
}
else
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n"));
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
}
break;
case SSL_ERROR_SSL:
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *errm = SSLerrmessage(ecode);
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL error: %s\n"), errm);
SSLerrfree(errm);
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
break;
}
case SSL_ERROR_ZERO_RETURN:
/*
2015-05-24 03:35:49 +02:00
* Per OpenSSL documentation, this error code is only returned for
* a clean connection closure, so we should not report it as a
* server crash.
*/
printfPQExpBuffer(&conn->errorMessage,
2015-05-24 03:35:49 +02:00
libpq_gettext("SSL connection has been closed unexpectedly\n"));
result_errno = ECONNRESET;
n = -1;
break;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized SSL error code: %d\n"),
err);
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
break;
}
/* ensure we return the intended errno to caller */
SOCK_ERRNO_SET(result_errno);
return n;
}
/*
* Write data to a secure connection.
*
* On failure, this function is responsible for putting a suitable message
* into conn->errorMessage. The caller must still inspect errno, but only
* to determine whether to continue/retry after error.
*/
ssize_t
pgtls_write(PGconn *conn, const void *ptr, size_t len)
{
ssize_t n;
int result_errno = 0;
char sebuf[256];
int err;
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
unsigned long ecode;
SOCK_ERRNO_SET(0);
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
ERR_clear_error();
n = SSL_write(conn->ssl, ptr, len);
err = SSL_get_error(conn->ssl, n);
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0;
switch (err)
{
case SSL_ERROR_NONE:
if (n < 0)
{
/* Not supposed to happen, so we don't translate the msg */
printfPQExpBuffer(&conn->errorMessage,
2015-05-24 03:35:49 +02:00
"SSL_write failed but did not provide error information\n");
/* assume the connection is broken */
result_errno = ECONNRESET;
}
break;
case SSL_ERROR_WANT_READ:
/*
2015-05-24 03:35:49 +02:00
* Returning 0 here causes caller to wait for write-ready, which
* is not really the right thing, but it's the best we can do.
*/
n = 0;
break;
case SSL_ERROR_WANT_WRITE:
n = 0;
break;
case SSL_ERROR_SYSCALL:
if (n < 0)
{
result_errno = SOCK_ERRNO;
if (result_errno == EPIPE || result_errno == ECONNRESET)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
2015-05-24 03:35:49 +02:00
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
else
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf)));
}
else
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n"));
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
}
break;
case SSL_ERROR_SSL:
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *errm = SSLerrmessage(ecode);
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL error: %s\n"), errm);
SSLerrfree(errm);
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
break;
}
case SSL_ERROR_ZERO_RETURN:
/*
2015-05-24 03:35:49 +02:00
* Per OpenSSL documentation, this error code is only returned for
* a clean connection closure, so we should not report it as a
* server crash.
*/
printfPQExpBuffer(&conn->errorMessage,
2015-05-24 03:35:49 +02:00
libpq_gettext("SSL connection has been closed unexpectedly\n"));
result_errno = ECONNRESET;
n = -1;
break;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized SSL error code: %d\n"),
err);
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
break;
}
/* ensure we return the intended errno to caller */
SOCK_ERRNO_SET(result_errno);
return n;
}
/* ------------------------------------------------------------ */
/* OpenSSL specific code */
/* ------------------------------------------------------------ */
/*
* Certificate verification callback
*
* This callback allows us to log intermediate problems during
* verification, but there doesn't seem to be a clean way to get
* our PGconn * structure. So we can't log anything!
*
* This callback also allows us to override the default acceptance
* criteria (e.g., accepting self-signed or expired certs), but
* for now we accept the default checks.
*/
static int
verify_cb(int ok, X509_STORE_CTX *ctx)
{
return ok;
}
/*
* Check if a wildcard certificate matches the server hostname.
*
* The rule for this is:
* 1. We only match the '*' character as wildcard
* 2. We match only wildcards at the start of the string
* 3. The '*' character does *not* match '.', meaning that we match only
* a single pathname component.
* 4. We don't support more than one '*' in a single pattern.
*
* This is roughly in line with RFC2818, but contrary to what most browsers
* appear to be implementing (point 3 being the difference)
*
* Matching is always case-insensitive, since DNS is case insensitive.
*/
static int
wildcard_certificate_match(const char *pattern, const char *string)
{
int lenpat = strlen(pattern);
int lenstr = strlen(string);
/* If we don't start with a wildcard, it's not a match (rule 1 & 2) */
if (lenpat < 3 ||
pattern[0] != '*' ||
pattern[1] != '.')
return 0;
if (lenpat > lenstr)
/* If pattern is longer than the string, we can never match */
return 0;
if (pg_strcasecmp(pattern + 1, string + lenstr - lenpat + 1) != 0)
/*
* If string does not end in pattern (minus the wildcard), we don't
* match
*/
return 0;
if (strchr(string, '.') < string + lenstr - lenpat)
/*
* If there is a dot left of where the pattern started to match, we
* don't match (rule 3)
*/
return 0;
/* String ended with pattern, and didn't have a dot before, so we match */
return 1;
}
/*
* Check if a name from a server's certificate matches the peer's hostname.
*
* Returns 1 if the name matches, and 0 if it does not. On error, returns
* -1, and sets the libpq error message.
*
* The name extracted from the certificate is returned in *store_name. The
* caller is responsible for freeing it.
*/
static int
verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry,
char **store_name)
{
int len;
char *name;
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
const unsigned char *namedata;
int result;
*store_name = NULL;
/* Should not happen... */
if (name_entry == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
2015-05-24 03:35:49 +02:00
libpq_gettext("SSL certificate's name entry is missing\n"));
return -1;
}
/*
* GEN_DNS can be only IA5String, equivalent to US ASCII.
*
* There is no guarantee the string returned from the certificate is
* NULL-terminated, so make a copy that is.
*/
#ifdef HAVE_ASN1_STRING_GET0_DATA
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
namedata = ASN1_STRING_get0_data(name_entry);
#else
namedata = ASN1_STRING_data(name_entry);
#endif
len = ASN1_STRING_length(name_entry);
name = malloc(len + 1);
if (name == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return -1;
}
memcpy(name, namedata, len);
name[len] = '\0';
/*
* Reject embedded NULLs in certificate common or alternative name to
* prevent attacks like CVE-2009-4034.
*/
if (len != strlen(name))
{
free(name);
printfPQExpBuffer(&conn->errorMessage,
2015-05-24 03:35:49 +02:00
libpq_gettext("SSL certificate's name contains embedded null\n"));
return -1;
}
if (pg_strcasecmp(name, conn->pghost) == 0)
{
/* Exact name match */
result = 1;
}
else if (wildcard_certificate_match(name, conn->pghost))
{
/* Matched wildcard name */
result = 1;
}
else
{
result = 0;
}
*store_name = name;
return result;
}
/*
* Verify that the server certificate matches the hostname we connected to.
*
* The certificate's Common Name and Subject Alternative Names are considered.
*/
static bool
verify_peer_name_matches_certificate(PGconn *conn)
{
int names_examined = 0;
bool found_match = false;
bool got_error = false;
char *first_name = NULL;
2015-05-24 03:35:49 +02:00
STACK_OF(GENERAL_NAME) *peer_san;
2015-05-24 03:35:49 +02:00
int i;
int rc;
/*
* If told not to verify the peer name, don't do it. Return true
* indicating that the verification was successful.
*/
if (strcmp(conn->sslmode, "verify-full") != 0)
return true;
/* Check that we have a hostname to compare with. */
if (!(conn->pghost && conn->pghost[0] != '\0'))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("host name must be specified for a verified SSL connection\n"));
return false;
}
/*
* First, get the Subject Alternative Names (SANs) from the certificate,
* and compare them against the originally given hostname.
*/
peer_san = (STACK_OF(GENERAL_NAME) *)
X509_get_ext_d2i(conn->peer, NID_subject_alt_name, NULL, NULL);
if (peer_san)
{
int san_len = sk_GENERAL_NAME_num(peer_san);
for (i = 0; i < san_len; i++)
{
const GENERAL_NAME *name = sk_GENERAL_NAME_value(peer_san, i);
if (name->type == GEN_DNS)
{
char *alt_name;
names_examined++;
rc = verify_peer_name_matches_certificate_name(conn,
2015-05-24 03:35:49 +02:00
name->d.dNSName,
&alt_name);
if (rc == -1)
got_error = true;
if (rc == 1)
found_match = true;
if (alt_name)
{
if (!first_name)
first_name = alt_name;
else
free(alt_name);
}
}
if (found_match || got_error)
break;
}
sk_GENERAL_NAME_free(peer_san);
}
2015-05-24 03:35:49 +02:00
/*
* If there is no subjectAltName extension of type dNSName, check the
* Common Name.
*
* (Per RFC 2818 and RFC 6125, if the subjectAltName extension of type
* dNSName is present, the CN must be ignored.)
*/
if (names_examined == 0)
{
X509_NAME *subject_name;
subject_name = X509_get_subject_name(conn->peer);
if (subject_name != NULL)
{
int cn_index;
cn_index = X509_NAME_get_index_by_NID(subject_name,
NID_commonName, -1);
if (cn_index >= 0)
{
names_examined++;
rc = verify_peer_name_matches_certificate_name(
2015-05-24 03:35:49 +02:00
conn,
X509_NAME_ENTRY_get_data(
X509_NAME_get_entry(subject_name, cn_index)),
&first_name);
if (rc == -1)
got_error = true;
else if (rc == 1)
found_match = true;
}
}
}
if (!found_match && !got_error)
{
/*
2015-05-24 03:35:49 +02:00
* No match. Include the name from the server certificate in the error
* message, to aid debugging broken configurations. If there are
* multiple names, only print the first one to avoid an overly long
* error message.
*/
if (names_examined > 1)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"\n",
"server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n",
names_examined - 1),
first_name, names_examined - 1, conn->pghost);
}
else if (names_examined == 1)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"),
first_name, conn->pghost);
}
else
{
printfPQExpBuffer(&conn->errorMessage,
2015-05-19 05:01:48 +02:00
libpq_gettext("could not get server's host name from server certificate\n"));
}
}
/* clean up */
if (first_name)
free(first_name);
return found_match && !got_error;
}
#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
/*
* Callback functions for OpenSSL internal locking. (OpenSSL 1.1.0
* does its own locking, and doesn't need these anymore. The
* CRYPTO_lock() function was removed in 1.1.0, when the callbacks
* were made obsolete, so we assume that if CRYPTO_lock() exists,
* the callbacks are still required.)
*/
static unsigned long
pq_threadidcallback(void)
{
/*
* This is not standards-compliant. pthread_self() returns pthread_t, and
* shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires
* it, so we have to do it.
*/
return (unsigned long) pthread_self();
}
static pthread_mutex_t *pq_lockarray;
static void
pq_lockingcallback(int mode, int n, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
{
if (pthread_mutex_lock(&pq_lockarray[n]))
PGTHREAD_ERROR("failed to lock mutex");
}
else
{
if (pthread_mutex_unlock(&pq_lockarray[n]))
PGTHREAD_ERROR("failed to unlock mutex");
}
}
#endif /* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */
/*
* Initialize SSL library.
*
* In threadsafe mode, this includes setting up libcrypto callback functions
* to do thread locking.
*
* If the caller has told us (through PQinitOpenSSL) that he's taking care
* of libcrypto, we expect that callbacks are already set, and won't try to
* override it.
*
* The conn parameter is only used to be able to pass back an error
* message - no connection-local setup is made here.
*
* Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
*/
int
pgtls_init(PGconn *conn)
{
#ifdef ENABLE_THREAD_SAFETY
#ifdef WIN32
/* Also see similar code in fe-connect.c, default_threadlock() */
if (ssl_config_mutex == NULL)
{
while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1)
/* loop, another thread own the lock */ ;
if (ssl_config_mutex == NULL)
{
if (pthread_mutex_init(&ssl_config_mutex, NULL))
return -1;
}
InterlockedExchange(&win32_ssl_create_mutex, 0);
}
#endif
if (pthread_mutex_lock(&ssl_config_mutex))
return -1;
#ifdef HAVE_CRYPTO_LOCK
if (pq_init_crypto_lib)
{
/*
* If necessary, set up an array to hold locks for libcrypto.
* libcrypto will tell us how big to make this array.
*/
if (pq_lockarray == NULL)
{
int i;
pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
if (!pq_lockarray)
{
pthread_mutex_unlock(&ssl_config_mutex);
return -1;
}
for (i = 0; i < CRYPTO_num_locks(); i++)
{
if (pthread_mutex_init(&pq_lockarray[i], NULL))
{
free(pq_lockarray);
pq_lockarray = NULL;
pthread_mutex_unlock(&ssl_config_mutex);
return -1;
}
}
}
if (ssl_open_connections++ == 0)
{
2015-05-24 03:35:49 +02:00
/*
* These are only required for threaded libcrypto applications,
* but make sure we don't stomp on them if they're already set.
*/
if (CRYPTO_get_id_callback() == NULL)
CRYPTO_set_id_callback(pq_threadidcallback);
if (CRYPTO_get_locking_callback() == NULL)
CRYPTO_set_locking_callback(pq_lockingcallback);
}
}
#endif /* HAVE_CRYPTO_LOCK */
#endif /* ENABLE_THREAD_SAFETY */
if (!ssl_lib_initialized)
{
if (pq_init_ssl_lib)
{
#ifdef HAVE_OPENSSL_INIT_SSL
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
#else
OPENSSL_config(NULL);
SSL_library_init();
SSL_load_error_strings();
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
#endif
}
ssl_lib_initialized = true;
}
#ifdef ENABLE_THREAD_SAFETY
pthread_mutex_unlock(&ssl_config_mutex);
#endif
return 0;
}
/*
* This function is needed because if the libpq library is unloaded
* from the application, the callback functions will no longer exist when
* libcrypto is used by other parts of the system. For this reason,
* we unregister the callback functions when the last libpq
* connection is closed. (The same would apply for OpenSSL callbacks
* if we had any.)
*
* Callbacks are only set when we're compiled in threadsafe mode, so
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
* we only need to remove them in this case. They are also not needed
* with OpenSSL 1.1.0 anymore.
*/
static void
destroy_ssl_system(void)
{
#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
/* Mutex is created in initialize_ssl_system() */
if (pthread_mutex_lock(&ssl_config_mutex))
return;
if (pq_init_crypto_lib && ssl_open_connections > 0)
--ssl_open_connections;
if (pq_init_crypto_lib && ssl_open_connections == 0)
{
2015-05-24 03:35:49 +02:00
/*
* No connections left, unregister libcrypto callbacks, if no one
* registered different ones in the meantime.
*/
if (CRYPTO_get_locking_callback() == pq_lockingcallback)
CRYPTO_set_locking_callback(NULL);
if (CRYPTO_get_id_callback() == pq_threadidcallback)
CRYPTO_set_id_callback(NULL);
/*
* We don't free the lock array. If we get another connection in
* this process, we will just re-use them with the existing mutexes.
*
* This means we leak a little memory on repeated load/unload of the
* library.
*/
}
pthread_mutex_unlock(&ssl_config_mutex);
#endif
}
/*
* Create per-connection SSL object, and load the client certificate,
* private key, and trusted CA certs.
*
* Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
*/
static int
initialize_SSL(PGconn *conn)
{
SSL_CTX *SSL_context;
struct stat buf;
char homedir[MAXPGPATH];
char fnbuf[MAXPGPATH];
char sebuf[256];
bool have_homedir;
bool have_cert;
bool have_rootcert;
EVP_PKEY *pkey = NULL;
/*
* We'll need the home directory if any of the relevant parameters are
* defaulted. If pqGetHomeDirectory fails, act as though none of the
* files could be found.
*/
if (!(conn->sslcert && strlen(conn->sslcert) > 0) ||
!(conn->sslkey && strlen(conn->sslkey) > 0) ||
!(conn->sslrootcert && strlen(conn->sslrootcert) > 0) ||
!(conn->sslcrl && strlen(conn->sslcrl) > 0))
have_homedir = pqGetHomeDirectory(homedir, sizeof(homedir));
else /* won't need it */
have_homedir = false;
/*
* Create a new SSL_CTX object.
*
* We used to share a single SSL_CTX between all connections, but it was
* complicated if connections used different certificates. So now we create
* a separate context for each connection, and accept the overhead.
*/
SSL_context = SSL_CTX_new(SSLv23_method());
if (!SSL_context)
{
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not create SSL context: %s\n"),
err);
SSLerrfree(err);
return -1;
}
/* Disable old protocol versions */
SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
/*
* Disable OpenSSL's moving-write-buffer sanity check, because it
* causes unnecessary failures in nonblocking send cases.
*/
SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
/*
* If the root cert file exists, load it so we can perform certificate
* verification. If sslmode is "verify-full" we will also do further
* verification after the connection has been completed.
*/
if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)
strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
else if (have_homedir)
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);
else
fnbuf[0] = '\0';
if (fnbuf[0] != '\0' &&
stat(fnbuf, &buf) == 0)
{
X509_STORE *cvstore;
if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
{
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read root certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
SSL_CTX_free(SSL_context);
return -1;
}
if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
{
if (conn->sslcrl && strlen(conn->sslcrl) > 0)
strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
else if (have_homedir)
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE);
else
fnbuf[0] = '\0';
/* Set the flags to check against the complete CRL chain */
if (fnbuf[0] != '\0' &&
X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
{
/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
#ifdef X509_V_FLAG_CRL_CHECK
X509_STORE_set_flags(cvstore,
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
#else
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
fnbuf);
SSLerrfree(err);
SSL_CTX_free(SSL_context);
return -1;
#endif
}
/* if not found, silently ignore; we do not require CRL */
}
have_rootcert = true;
}
else
{
/*
* stat() failed; assume root file doesn't exist. If sslmode is
* verify-ca or verify-full, this is an error. Otherwise, continue
* without performing any server cert verification.
*/
if (conn->sslmode[0] == 'v') /* "verify-ca" or "verify-full" */
{
/*
* The only way to reach here with an empty filename is if
* pqGetHomeDirectory failed. That's a sufficiently unusual case
* that it seems worth having a specialized error message for it.
*/
if (fnbuf[0] == '\0')
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get home directory to locate root certificate file\n"
"Either provide the file or change sslmode to disable server certificate verification.\n"));
else
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("root certificate file \"%s\" does not exist\n"
"Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
SSL_CTX_free(SSL_context);
return -1;
}
have_rootcert = false;
}
/* Read the client certificate file */
if (conn->sslcert && strlen(conn->sslcert) > 0)
strlcpy(fnbuf, conn->sslcert, sizeof(fnbuf));
else if (have_homedir)
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
else
fnbuf[0] = '\0';
if (fnbuf[0] == '\0')
{
/* no home directory, proceed without a client cert */
have_cert = false;
}
else if (stat(fnbuf, &buf) != 0)
{
/*
* If file is not present, just go on without a client cert; server
* might or might not accept the connection. Any other error,
* however, is grounds for complaint.
*/
if (errno != ENOENT && errno != ENOTDIR)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not open certificate file \"%s\": %s\n"),
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
SSL_CTX_free(SSL_context);
return -1;
}
have_cert = false;
}
else
{
/*
* Cert file exists, so load it. Since OpenSSL doesn't provide the
* equivalent of "SSL_use_certificate_chain_file", we have to load
* it into the SSL context, rather than the SSL object.
*/
if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
SSL_CTX_free(SSL_context);
return -1;
}
/* need to load the associated private key, too */
have_cert = true;
}
/*
* The SSL context is now loaded with the correct root and client certificates.
* Create a connection-specific SSL object. The private key is loaded directly
* into the SSL object. (We could load the private key into the context, too, but
* we have done it this way historically, and it doesn't really matter.)
*/
if (!(conn->ssl = SSL_new(SSL_context)) ||
!SSL_set_app_data(conn->ssl, conn) ||
!my_SSL_set_fd(conn, conn->sock))
{
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not establish SSL connection: %s\n"),
err);
SSLerrfree(err);
SSL_CTX_free(SSL_context);
return -1;
}
conn->ssl_in_use = true;
/*
* SSL contexts are reference counted by OpenSSL. We can free it as soon as we
* have created the SSL object, and it will stick around for as long as it's
* actually needed.
*/
SSL_CTX_free(SSL_context);
SSL_context = NULL;
/*
* Read the SSL key. If a key is specified, treat it as an engine:key
* combination if there is colon present - we don't support files with
* colon in the name. The exception is if the second character is a colon,
* in which case it can be a Windows filename with drive specification.
*/
if (have_cert && conn->sslkey && strlen(conn->sslkey) > 0)
{
#ifdef USE_SSL_ENGINE
if (strchr(conn->sslkey, ':')
#ifdef WIN32
&& conn->sslkey[1] != ':'
#endif
)
{
/* Colon, but not in second character, treat as engine:key */
char *engine_str = strdup(conn->sslkey);
char *engine_colon;
if (engine_str == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return -1;
}
/* cannot return NULL because we already checked before strdup */
engine_colon = strchr(engine_str, ':');
*engine_colon = '\0'; /* engine_str now has engine name */
engine_colon++; /* engine_colon now has key name */
conn->engine = ENGINE_by_id(engine_str);
if (conn->engine == NULL)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not load SSL engine \"%s\": %s\n"),
engine_str, err);
SSLerrfree(err);
free(engine_str);
return -1;
}
if (ENGINE_init(conn->engine) == 0)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not initialize SSL engine \"%s\": %s\n"),
engine_str, err);
SSLerrfree(err);
ENGINE_free(conn->engine);
conn->engine = NULL;
free(engine_str);
return -1;
}
pkey = ENGINE_load_private_key(conn->engine, engine_colon,
NULL, NULL);
if (pkey == NULL)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"),
engine_colon, engine_str, err);
SSLerrfree(err);
ENGINE_finish(conn->engine);
ENGINE_free(conn->engine);
conn->engine = NULL;
free(engine_str);
return -1;
}
if (SSL_use_PrivateKey(conn->ssl, pkey) != 1)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"),
engine_colon, engine_str, err);
SSLerrfree(err);
ENGINE_finish(conn->engine);
ENGINE_free(conn->engine);
conn->engine = NULL;
free(engine_str);
return -1;
}
free(engine_str);
fnbuf[0] = '\0'; /* indicate we're not going to load from a
* file */
}
else
#endif /* USE_SSL_ENGINE */
{
/* PGSSLKEY is not an engine, treat it as a filename */
strlcpy(fnbuf, conn->sslkey, sizeof(fnbuf));
}
}
else if (have_homedir)
{
/* No PGSSLKEY specified, load default file */
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
}
else
fnbuf[0] = '\0';
if (have_cert && fnbuf[0] != '\0')
{
/* read the client key from file */
if (stat(fnbuf, &buf) != 0)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
fnbuf);
return -1;
}
#ifndef WIN32
if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
fnbuf);
return -1;
}
#endif
if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not load private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
return -1;
}
}
/* verify that the cert and key go together */
if (have_cert &&
SSL_check_private_key(conn->ssl) != 1)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
return -1;
}
/*
* If a root cert was loaded, also set our certificate verification callback.
*/
if (have_rootcert)
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
/*
* If the OpenSSL version used supports it (from 1.0.0 on) and the user
* requested it, disable SSL compression.
*/
#ifdef SSL_OP_NO_COMPRESSION
if (conn->sslcompression && conn->sslcompression[0] == '0')
{
SSL_set_options(conn->ssl, SSL_OP_NO_COMPRESSION);
}
#endif
return 0;
}
/*
* Attempt to negotiate SSL connection.
*/
static PostgresPollingStatusType
open_client_SSL(PGconn *conn)
{
int r;
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
ERR_clear_error();
r = SSL_connect(conn->ssl);
if (r <= 0)
{
int err = SSL_get_error(conn->ssl, r);
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
unsigned long ecode;
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
ecode = ERR_get_error();
switch (err)
{
case SSL_ERROR_WANT_READ:
return PGRES_POLLING_READING;
case SSL_ERROR_WANT_WRITE:
return PGRES_POLLING_WRITING;
case SSL_ERROR_SYSCALL:
{
char sebuf[256];
if (r == -1)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
else
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n"));
pgtls_close(conn);
return PGRES_POLLING_FAILED;
}
case SSL_ERROR_SSL:
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err = SSLerrmessage(ecode);
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL error: %s\n"),
err);
SSLerrfree(err);
pgtls_close(conn);
return PGRES_POLLING_FAILED;
}
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("unrecognized SSL error code: %d\n"),
err);
pgtls_close(conn);
return PGRES_POLLING_FAILED;
}
}
/*
* We already checked the server certificate in initialize_SSL() using
* SSL_CTX_set_verify(), if root.crt exists.
*/
/* get server certificate */
conn->peer = SSL_get_peer_certificate(conn->ssl);
if (conn->peer == NULL)
{
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
char *err;
err = SSLerrmessage(ERR_get_error());
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate could not be obtained: %s\n"),
err);
SSLerrfree(err);
pgtls_close(conn);
return PGRES_POLLING_FAILED;
}
if (!verify_peer_name_matches_certificate(conn))
{
pgtls_close(conn);
return PGRES_POLLING_FAILED;
}
/* SSL handshake is complete */
return PGRES_POLLING_OK;
}
/*
* Close SSL connection.
*/
void
pgtls_close(PGconn *conn)
{
bool destroy_needed = false;
if (conn->ssl)
{
/*
* We can't destroy everything SSL-related here due to the possible
* later calls to OpenSSL routines which may need our thread
* callbacks, so set a flag here and check at the end.
*/
destroy_needed = true;
SSL_shutdown(conn->ssl);
SSL_free(conn->ssl);
conn->ssl = NULL;
conn->ssl_in_use = false;
}
if (conn->peer)
{
X509_free(conn->peer);
conn->peer = NULL;
}
#ifdef USE_SSL_ENGINE
if (conn->engine)
{
ENGINE_finish(conn->engine);
ENGINE_free(conn->engine);
conn->engine = NULL;
}
#endif
/*
* This will remove our SSL locking hooks, if this is the last SSL
* connection, which means we must wait to call it until after all SSL
* calls have been made, otherwise we can end up with a race condition and
* possible deadlocks.
*
* See comments above destroy_ssl_system().
*/
if (destroy_needed)
destroy_ssl_system();
}
/*
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
* 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
* want to return NULL ever.
*/
static char ssl_nomem[] = "out of memory allocating error description";
#define SSL_ERR_LEN 128
static char *
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
SSLerrmessage(unsigned long ecode)
{
const char *errreason;
char *errbuf;
errbuf = malloc(SSL_ERR_LEN);
if (!errbuf)
return ssl_nomem;
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
if (ecode == 0)
{
snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported"));
return errbuf;
}
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
errreason = ERR_reason_error_string(ecode);
if (errreason != NULL)
{
strlcpy(errbuf, errreason, SSL_ERR_LEN);
return errbuf;
}
Distrust external OpenSSL clients; clear err queue OpenSSL has an unfortunate tendency to mix per-session state error handling with per-thread error handling. This can cause problems when programs that link to libpq with OpenSSL enabled have some other use of OpenSSL; without care, one caller of OpenSSL may cause problems for the other caller. Backend code might similarly be affected, for example when a third party extension independently uses OpenSSL without taking the appropriate precautions. To fix, don't trust other users of OpenSSL to clear the per-thread error queue. Instead, clear the entire per-thread queue ahead of certain I/O operations when it appears that there might be trouble (these I/O operations mostly need to call SSL_get_error() to check for success, which relies on the queue being empty). This is slightly aggressive, but it's pretty clear that the other callers have a very dubious claim to ownership of the per-thread queue. Do this is both frontend and backend code. Finally, be more careful about clearing our own error queue, so as to not cause these problems ourself. It's possibly that control previously did not always reach SSLerrmessage(), where ERR_get_error() was supposed to be called to clear the queue's earliest code. Make sure ERR_get_error() is always called, so as to spare other users of OpenSSL the possibility of similar problems caused by libpq (as opposed to problems caused by a third party OpenSSL library like PHP's OpenSSL extension). Again, do this is both frontend and backend code. See bug #12799 and https://bugs.php.net/bug.php?id=68276 Based on patches by Dave Vitek and Peter Eisentraut. From: Peter Geoghegan <pg@bowt.ie>
2016-04-08 19:48:14 +02:00
snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), ecode);
return errbuf;
}
static void
SSLerrfree(char *buf)
{
if (buf != ssl_nomem)
free(buf);
}
/* ------------------------------------------------------------ */
/* SSL information functions */
/* ------------------------------------------------------------ */
int
PQsslInUse(PGconn *conn)
{
if (!conn)
return 0;
return conn->ssl_in_use;
}
/*
* Return pointer to OpenSSL object.
*/
void *
PQgetssl(PGconn *conn)
{
if (!conn)
return NULL;
return conn->ssl;
}
void *
PQsslStruct(PGconn *conn, const char *struct_name)
{
if (!conn)
return NULL;
if (strcmp(struct_name, "OpenSSL") == 0)
return conn->ssl;
return NULL;
}
const char *const *
PQsslAttributeNames(PGconn *conn)
{
static const char *const result[] = {
"library",
"key_bits",
"cipher",
"compression",
"protocol",
NULL
};
2015-05-24 03:35:49 +02:00
return result;
}
const char *
PQsslAttribute(PGconn *conn, const char *attribute_name)
{
if (!conn)
return NULL;
if (conn->ssl == NULL)
return NULL;
if (strcmp(attribute_name, "library") == 0)
return "OpenSSL";
if (strcmp(attribute_name, "key_bits") == 0)
{
static char sslbits_str[10];
2015-05-24 03:35:49 +02:00
int sslbits;
SSL_get_cipher_bits(conn->ssl, &sslbits);
snprintf(sslbits_str, sizeof(sslbits_str), "%d", sslbits);
return sslbits_str;
}
if (strcmp(attribute_name, "cipher") == 0)
return SSL_get_cipher(conn->ssl);
if (strcmp(attribute_name, "compression") == 0)
return SSL_get_current_compression(conn->ssl) ? "on" : "off";
if (strcmp(attribute_name, "protocol") == 0)
return SSL_get_version(conn->ssl);
2015-05-24 03:35:49 +02:00
return NULL; /* unknown attribute */
}
/*
* Private substitute BIO: this does the sending and receiving using
* pqsecure_raw_write() and pqsecure_raw_read() instead, to allow those
* functions to disable SIGPIPE and give better error messages on I/O errors.
*
* These functions are closely modelled on the standard socket BIO in OpenSSL;
* see sock_read() and sock_write() in OpenSSL's crypto/bio/bss_sock.c.
* XXX OpenSSL 1.0.1e considers many more errcodes than just EINTR as reasons
* to retry; do we need to adopt their logic for that?
*/
#ifndef HAVE_BIO_GET_DATA
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
#define BIO_get_data(bio) (bio->ptr)
#define BIO_set_data(bio, data) (bio->ptr = data)
#endif
static BIO_METHOD *my_bio_methods;
static int
my_sock_read(BIO *h, char *buf, int size)
{
int res;
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
res = pqsecure_raw_read((PGconn *) BIO_get_data(h), buf, size);
BIO_clear_retry_flags(h);
if (res < 0)
{
/* If we were interrupted, tell caller to retry */
switch (SOCK_ERRNO)
{
#ifdef EAGAIN
case EAGAIN:
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
case EWOULDBLOCK:
#endif
case EINTR:
BIO_set_retry_read(h);
break;
default:
break;
}
}
return res;
}
static int
my_sock_write(BIO *h, const char *buf, int size)
{
int res;
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
res = pqsecure_raw_write((PGconn *) BIO_get_data(h), buf, size);
BIO_clear_retry_flags(h);
if (res <= 0)
{
/* If we were interrupted, tell caller to retry */
switch (SOCK_ERRNO)
{
#ifdef EAGAIN
case EAGAIN:
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
case EWOULDBLOCK:
#endif
case EINTR:
BIO_set_retry_write(h);
break;
default:
break;
}
}
return res;
}
static BIO_METHOD *
my_BIO_s_socket(void)
{
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
if (!my_bio_methods)
{
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
#ifdef HAVE_BIO_METH_NEW
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
int my_bio_index;
my_bio_index = BIO_get_new_index();
if (my_bio_index == -1)
return NULL;
my_bio_methods = BIO_meth_new(my_bio_index, "libpq socket");
if (!my_bio_methods)
return NULL;
/*
* As of this writing, these functions never fail. But check anyway, like
* OpenSSL's own examples do.
*/
if (!BIO_meth_set_write(my_bio_methods, my_sock_write) ||
!BIO_meth_set_read(my_bio_methods, my_sock_read) ||
!BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) ||
!BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
!BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
!BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
!BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
!BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
{
BIO_meth_free(my_bio_methods);
my_bio_methods = NULL;
return NULL;
}
#else
my_bio_methods = malloc(sizeof(BIO_METHOD));
if (!my_bio_methods)
return NULL;
memcpy(my_bio_methods, biom, sizeof(BIO_METHOD));
my_bio_methods->bread = my_sock_read;
my_bio_methods->bwrite = my_sock_write;
#endif
}
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
return my_bio_methods;
}
/* This should exactly match openssl's SSL_set_fd except for using my BIO */
static int
my_SSL_set_fd(PGconn *conn, int fd)
{
int ret = 0;
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
BIO *bio;
BIO_METHOD *bio_method;
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
bio_method = my_BIO_s_socket();
if (bio_method == NULL)
{
SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
goto err;
}
bio = BIO_new(bio_method);
if (bio == NULL)
{
SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
goto err;
}
Support OpenSSL 1.1.0. Changes needed to build at all: - Check for SSL_new in configure, now that SSL_library_init is a macro. - Do not access struct members directly. This includes some new code in pgcrypto, to use the resource owner mechanism to ensure that we don't leak OpenSSL handles, now that we can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
2016-09-15 11:36:21 +02:00
BIO_set_data(bio, conn);
SSL_set_bio(conn->ssl, bio, bio);
BIO_set_fd(bio, fd, BIO_NOCLOSE);
ret = 1;
err:
return ret;
}