>From dd4298d59464101f9df418a62fa884a554ff01e2 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Tue, 10 Jun 2014 23:30:51 +0300
Subject: [PATCH] Invent a new internal API for interfacing with SSL.

Refactor OpenSSL specific code to separate files, implementing the new API.

diff --git a/configure b/configure
index 0b0a656..4934795 100755
--- a/configure
+++ b/configure
@@ -5492,7 +5492,7 @@ if test "${with_openssl+set}" = set; then :
   case $withval in
     yes)
 
-$as_echo "#define USE_SSL 1" >>confdefs.h
+$as_echo "#define USE_OPENSSL 1" >>confdefs.h
 
       ;;
     no)
@@ -5513,6 +5513,7 @@ fi
 $as_echo "$with_openssl" >&6; }
 
 
+
 #
 # SELinux
 #
diff --git a/configure.in b/configure.in
index fd9eb71..a72c34c 100644
--- a/configure.in
+++ b/configure.in
@@ -657,9 +657,17 @@ AC_MSG_RESULT([$with_bonjour])
 #
 AC_MSG_CHECKING([whether to build with OpenSSL support])
 PGAC_ARG_BOOL(with, openssl, no, [build with OpenSSL support],
-              [AC_DEFINE([USE_SSL], 1, [Define to build with (Open)SSL support. (--with-openssl)])])
+              [AC_DEFINE([USE_OPENSSL], 1, [Define to build with OpenSSL support. (--with-openssl)])])
 AC_MSG_RESULT([$with_openssl])
 AC_SUBST(with_openssl)
+AH_VERBATIM([USE_SSL],
+[/*
+ * USE_SSL is defined when building with any SSL implementation (currently,
+ * only OpenSSL is supported).
+ */
+#ifdef USE_OPENSSL
+#define USE_SSL
+#endif])
 
 #
 # SELinux
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index e929864..8be0572 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -17,4 +17,8 @@ include $(top_builddir)/src/Makefile.global
 OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ip.o md5.o pqcomm.o \
        pqformat.o pqsignal.o
 
+ifeq ($(with_openssl),yes)
+OBJS += be-secure-openssl.o
+endif
+
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 70b0b93..b1974d1 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -161,7 +161,7 @@ static int	pg_SSPI_recvauth(Port *port);
  * RADIUS Authentication
  *----------------------------------------------------------------
  */
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 #include <openssl/rand.h>
 #endif
 static int	CheckRADIUSAuth(Port *port);
@@ -330,7 +330,7 @@ ClientAuthentication(Port *port)
 		 * already if it didn't verify ok.
 		 */
 #ifdef USE_SSL
-		if (!port->peer)
+		if (!port->peer_cert_valid)
 		{
 			ereport(FATAL,
 					(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
@@ -378,7 +378,7 @@ ClientAuthentication(Port *port)
 					   (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
 						errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\", %s",
 							   hostinfo, port->user_name,
-							   port->ssl ? _("SSL on") : _("SSL off"))));
+							   port->ssl_in_use ? _("SSL on") : _("SSL off"))));
 #else
 					ereport(FATAL,
 					   (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
@@ -394,7 +394,7 @@ ClientAuthentication(Port *port)
 						errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s",
 							   hostinfo, port->user_name,
 							   port->database_name,
-							   port->ssl ? _("SSL on") : _("SSL off"))));
+							   port->ssl_in_use ? _("SSL on") : _("SSL off"))));
 #else
 					ereport(FATAL,
 					   (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
@@ -452,7 +452,7 @@ ClientAuthentication(Port *port)
 					   (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
 						errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\", %s",
 							   hostinfo, port->user_name,
-							   port->ssl ? _("SSL on") : _("SSL off")),
+							   port->ssl_in_use ? _("SSL on") : _("SSL off")),
 						HOSTNAME_LOOKUP_DETAIL(port)));
 #else
 					ereport(FATAL,
@@ -470,7 +470,7 @@ ClientAuthentication(Port *port)
 						errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
 							   hostinfo, port->user_name,
 							   port->database_name,
-							   port->ssl ? _("SSL on") : _("SSL off")),
+							   port->ssl_in_use ? _("SSL on") : _("SSL off")),
 						HOSTNAME_LOOKUP_DETAIL(port)));
 #else
 					ereport(FATAL,
@@ -2315,7 +2315,7 @@ CheckRADIUSAuth(Port *port)
 	/* Construct RADIUS packet */
 	packet->code = RADIUS_ACCESS_REQUEST;
 	packet->length = RADIUS_HEADER_LENGTH;
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 	if (RAND_bytes(packet->vector, RADIUS_VECTOR_LENGTH) != 1)
 	{
 		ereport(LOG,
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
new file mode 100644
index 0000000..e3a284b
--- /dev/null
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -0,0 +1,1045 @@
+/*-------------------------------------------------------------------------
+ *
+ * be-secure-openssl.c
+ *	  functions for OpenSSL support in the backend.
+ *
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/libpq/be-secure-openssl.c
+ *
+ *	  Since the server static private key ($DataDir/server.key)
+ *	  will normally be stored unencrypted so that the database
+ *	  backend can restart automatically, it is important that
+ *	  we select an algorithm that continues to provide confidentiality
+ *	  even if the attacker has the server's private key.  Ephemeral
+ *	  DH (EDH) keys provide this, and in fact provide Perfect Forward
+ *	  Secrecy (PFS) except for situations where the session can
+ *	  be hijacked during a periodic handshake/renegotiation.
+ *	  Even that backdoor can be closed if client certificates
+ *	  are used (since the imposter will be unable to successfully
+ *	  complete renegotiation).
+ *
+ *	  N.B., the static private key should still be protected to
+ *	  the largest extent possible, to minimize the risk of
+ *	  impersonations.
+ *
+ *	  Another benefit of EDH is that it allows the backend and
+ *	  clients to use DSA keys.  DSA keys can only provide digital
+ *	  signatures, not encryption, and are often acceptable in
+ *	  jurisdictions where RSA keys are unacceptable.
+ *
+ *	  The downside to EDH is that it makes it impossible to
+ *	  use ssldump(1) if there's a problem establishing an SSL
+ *	  session.  In this case you'll need to temporarily disable
+ *	  EDH by commenting out the callback.
+ *
+ *	  ...
+ *
+ *	  Because the risk of cryptanalysis increases as large
+ *	  amounts of data are sent with the same session key, the
+ *	  session keys are periodically renegotiated.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/dh.h>
+#if SSLEAY_VERSION_NUMBER >= 0x0907000L
+#include <openssl/conf.h>
+#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH)
+#include <openssl/ec.h>
+#endif
+
+#include "libpq/libpq.h"
+#include "tcop/tcopprot.h"
+#include "utils/memutils.h"
+
+
+
+static DH  *load_dh_file(int keylength);
+static DH  *load_dh_buffer(const char *, size_t);
+static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);
+static int	verify_cb(int, X509_STORE_CTX *);
+static void info_cb(const SSL *ssl, int type, int args);
+static const char *SSLerrmessage(void);
+
+/* are we in the middle of a renegotiation? */
+static bool in_ssl_renegotiation = false;
+
+static SSL_CTX *SSL_context = NULL;
+
+/* ------------------------------------------------------------ */
+/*						 Hardcoded values						*/
+/* ------------------------------------------------------------ */
+
+/*
+ *	Hardcoded DH parameters, used in ephemeral DH keying.
+ *	As discussed above, EDH protects the confidentiality of
+ *	sessions even if the static private key is compromised,
+ *	so we are *highly* motivated to ensure that we can use
+ *	EDH even if the DBA... or an attacker... deletes the
+ *	$DataDir/dh*.pem files.
+ *
+ *	We could refuse SSL connections unless a good DH parameter
+ *	file exists, but some clients may quietly renegotiate an
+ *	unsecured connection without fully informing the user.
+ *	Very uncool.
+ *
+ *	Alternatively, the backend could attempt to load these files
+ *	on startup if SSL is enabled - and refuse to start if any
+ *	do not exist - but this would tend to piss off DBAs.
+ *
+ *	If you want to create your own hardcoded DH parameters
+ *	for fun and profit, review "Assigned Number for SKIP
+ *	Protocols" (http://www.skip-vpn.org/spec/numbers.html)
+ *	for suggestions.
+ */
+
+static const char file_dh512[] =
+"-----BEGIN DH PARAMETERS-----\n\
+MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\
+XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\
+-----END DH PARAMETERS-----\n";
+
+static const char file_dh1024[] =
+"-----BEGIN DH PARAMETERS-----\n\
+MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\
+jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\
+ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\
+-----END DH PARAMETERS-----\n";
+
+static const char file_dh2048[] =
+"-----BEGIN DH PARAMETERS-----\n\
+MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\
+89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50\n\
+T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb\n\
+zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX\n\
+Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\
+CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\
+-----END DH PARAMETERS-----\n";
+
+static const char file_dh4096[] =
+"-----BEGIN DH PARAMETERS-----\n\
+MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\
+l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\
+Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\
+Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\
+VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\
+alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\
+sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\
+ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\
+OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\
+AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\
+KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
+-----END DH PARAMETERS-----\n";
+
+/*
+ *	Write data to a secure connection.
+ */
+ssize_t
+be_tls_write(Port *port, void *ptr, size_t len)
+{
+	ssize_t		n;
+	int			err;
+
+	/*
+	 * If SSL renegotiations are enabled and we're getting close to the
+	 * limit, start one now; but avoid it if there's one already in
+	 * progress.  Request the renegotiation 1kB before the limit has
+	 * actually expired.
+	 */
+	if (ssl_renegotiation_limit && !in_ssl_renegotiation &&
+		port->count > (ssl_renegotiation_limit - 1) * 1024L)
+	{
+		in_ssl_renegotiation = true;
+
+		/*
+		 * The way we determine that a renegotiation has completed is by
+		 * observing OpenSSL's internal renegotiation counter.  Make sure
+		 * we start out at zero, and assume that the renegotiation is
+		 * complete when the counter advances.
+		 *
+		 * OpenSSL provides SSL_renegotiation_pending(), but this doesn't
+		 * seem to work in testing.
+		 */
+		SSL_clear_num_renegotiations(port->ssl);
+
+		SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
+								   sizeof(SSL_context));
+		if (SSL_renegotiate(port->ssl) <= 0)
+			ereport(COMMERROR,
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("SSL failure during renegotiation start")));
+		else
+		{
+			int			retries;
+
+			/*
+			 * A handshake can fail, so be prepared to retry it, but only
+			 * a few times.
+			 */
+			for (retries = 0;; retries++)
+			{
+				if (SSL_do_handshake(port->ssl) > 0)
+					break;	/* done */
+				ereport(COMMERROR,
+						(errcode(ERRCODE_PROTOCOL_VIOLATION),
+						 errmsg("SSL handshake failure on renegotiation, retrying")));
+				if (retries >= 20)
+					ereport(FATAL,
+							(errcode(ERRCODE_PROTOCOL_VIOLATION),
+							 errmsg("unable to complete SSL handshake")));
+			}
+		}
+	}
+
+wloop:
+	errno = 0;
+	n = SSL_write(port->ssl, ptr, len);
+	err = SSL_get_error(port->ssl, n);
+	switch (err)
+	{
+		case SSL_ERROR_NONE:
+			port->count += n;
+			break;
+		case SSL_ERROR_WANT_READ:
+		case SSL_ERROR_WANT_WRITE:
+#ifdef WIN32
+			pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
+										(err == SSL_ERROR_WANT_READ) ?
+									FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
+										INFINITE);
+#endif
+			goto wloop;
+		case SSL_ERROR_SYSCALL:
+			/* leave it to caller to ereport the value of errno */
+			if (n != -1)
+			{
+				errno = ECONNRESET;
+				n = -1;
+			}
+			break;
+		case SSL_ERROR_SSL:
+			ereport(COMMERROR,
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("SSL error: %s", SSLerrmessage())));
+			/* fall through */
+		case SSL_ERROR_ZERO_RETURN:
+			errno = ECONNRESET;
+			n = -1;
+			break;
+		default:
+			ereport(COMMERROR,
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("unrecognized SSL error code: %d",
+							err)));
+			errno = ECONNRESET;
+			n = -1;
+			break;
+	}
+
+	if (n >= 0)
+	{
+		/* is renegotiation complete? */
+		if (in_ssl_renegotiation &&
+			SSL_num_renegotiations(port->ssl) >= 1)
+		{
+			in_ssl_renegotiation = false;
+			port->count = 0;
+		}
+
+		/*
+		 * if renegotiation is still ongoing, and we've gone beyond the
+		 * limit, kill the connection now -- continuing to use it can be
+		 * considered a security problem.
+		 */
+		if (in_ssl_renegotiation &&
+			port->count > ssl_renegotiation_limit * 1024L)
+			ereport(FATAL,
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("SSL failed to renegotiate connection before limit expired")));
+	}
+
+	return n;
+}
+
+/* ------------------------------------------------------------ */
+/*						OpenSSL specific code					*/
+/* ------------------------------------------------------------ */
+
+/*
+ * Private substitute BIO: this does the sending and receiving using send() and
+ * recv() instead. This is so that we can enable and disable interrupts
+ * just while calling recv(). We cannot have interrupts occurring while
+ * the bulk of openssl runs, because it uses malloc() and possibly other
+ * non-reentrant libc facilities. We also need to call send() and recv()
+ * directly so it gets passed through the socket/signals layer on Win32.
+ *
+ * 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?
+ */
+
+static bool my_bio_initialized = false;
+static BIO_METHOD my_bio_methods;
+
+static int
+my_sock_read(BIO *h, char *buf, int size)
+{
+	int			res = 0;
+
+	if (buf != NULL)
+	{
+		res = secure_raw_read(((Port *)h->ptr), buf, size);
+		BIO_clear_retry_flags(h);
+		if (res <= 0)
+		{
+			/* If we were interrupted, tell caller to retry */
+			if (errno == EINTR)
+			{
+				BIO_set_retry_read(h);
+			}
+		}
+	}
+
+	return res;
+}
+
+static int
+my_sock_write(BIO *h, const char *buf, int size)
+{
+	int			res = 0;
+
+	res = secure_raw_write(((Port *) h->ptr), buf, size);
+	BIO_clear_retry_flags(h);
+	if (res <= 0)
+	{
+		if (errno == EINTR)
+		{
+			BIO_set_retry_write(h);
+		}
+	}
+
+	return res;
+}
+
+static BIO_METHOD *
+my_BIO_s_socket(void)
+{
+	if (!my_bio_initialized)
+	{
+		memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD));
+		my_bio_methods.bread = my_sock_read;
+		my_bio_methods.bwrite = my_sock_write;
+		my_bio_initialized = true;
+	}
+	return &my_bio_methods;
+}
+
+/* This should exactly match openssl's SSL_set_fd except for using my BIO */
+static int
+my_SSL_set_fd(Port *port, int fd)
+{
+	int			ret = 0;
+	BIO		   *bio = NULL;
+
+	bio = BIO_new(my_BIO_s_socket());
+
+	if (bio == NULL)
+	{
+		SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
+		goto err;
+	}
+	/* Use 'ptr' to store pointer to PGconn */
+	bio->ptr = port;
+
+	BIO_set_fd(bio, fd, BIO_NOCLOSE);
+	SSL_set_bio(port->ssl, bio, bio);
+	ret = 1;
+err:
+	return ret;
+}
+
+/*
+ *	Load precomputed DH parameters.
+ *
+ *	To prevent "downgrade" attacks, we perform a number of checks
+ *	to verify that the DBA-generated DH parameters file contains
+ *	what we expect it to contain.
+ */
+static DH  *
+load_dh_file(int keylength)
+{
+	FILE	   *fp;
+	char		fnbuf[MAXPGPATH];
+	DH		   *dh = NULL;
+	int			codes;
+
+	/* attempt to open file.  It's not an error if it doesn't exist. */
+	snprintf(fnbuf, sizeof(fnbuf), "dh%d.pem", keylength);
+	if ((fp = fopen(fnbuf, "r")) == NULL)
+		return NULL;
+
+/*	flock(fileno(fp), LOCK_SH); */
+	dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
+/*	flock(fileno(fp), LOCK_UN); */
+	fclose(fp);
+
+	/* is the prime the correct size? */
+	if (dh != NULL && 8 * DH_size(dh) < keylength)
+	{
+		elog(LOG, "DH errors (%s): %d bits expected, %d bits found",
+			 fnbuf, keylength, 8 * DH_size(dh));
+		dh = NULL;
+	}
+
+	/* make sure the DH parameters are usable */
+	if (dh != NULL)
+	{
+		if (DH_check(dh, &codes) == 0)
+		{
+			elog(LOG, "DH_check error (%s): %s", fnbuf, SSLerrmessage());
+			return NULL;
+		}
+		if (codes & DH_CHECK_P_NOT_PRIME)
+		{
+			elog(LOG, "DH error (%s): p is not prime", fnbuf);
+			return NULL;
+		}
+		if ((codes & DH_NOT_SUITABLE_GENERATOR) &&
+			(codes & DH_CHECK_P_NOT_SAFE_PRIME))
+		{
+			elog(LOG,
+				 "DH error (%s): neither suitable generator or safe prime",
+				 fnbuf);
+			return NULL;
+		}
+	}
+
+	return dh;
+}
+
+/*
+ *	Load hardcoded DH parameters.
+ *
+ *	To prevent problems if the DH parameters files don't even
+ *	exist, we can load DH parameters hardcoded into this file.
+ */
+static DH  *
+load_dh_buffer(const char *buffer, size_t len)
+{
+	BIO		   *bio;
+	DH		   *dh = NULL;
+
+	bio = BIO_new_mem_buf((char *) buffer, len);
+	if (bio == NULL)
+		return NULL;
+	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+	if (dh == NULL)
+		ereport(DEBUG2,
+				(errmsg_internal("DH load buffer: %s",
+								 SSLerrmessage())));
+	BIO_free(bio);
+
+	return dh;
+}
+
+/*
+ *	Generate an ephemeral DH key.  Because this can take a long
+ *	time to compute, we can use precomputed parameters of the
+ *	common key sizes.
+ *
+ *	Since few sites will bother to precompute these parameter
+ *	files, we also provide a fallback to the parameters provided
+ *	by the OpenSSL project.
+ *
+ *	These values can be static (once loaded or computed) since
+ *	the OpenSSL library can efficiently generate random keys from
+ *	the information provided.
+ */
+static DH  *
+tmp_dh_cb(SSL *s, int is_export, int keylength)
+{
+	DH		   *r = NULL;
+	static DH  *dh = NULL;
+	static DH  *dh512 = NULL;
+	static DH  *dh1024 = NULL;
+	static DH  *dh2048 = NULL;
+	static DH  *dh4096 = NULL;
+
+	switch (keylength)
+	{
+		case 512:
+			if (dh512 == NULL)
+				dh512 = load_dh_file(keylength);
+			if (dh512 == NULL)
+				dh512 = load_dh_buffer(file_dh512, sizeof file_dh512);
+			r = dh512;
+			break;
+
+		case 1024:
+			if (dh1024 == NULL)
+				dh1024 = load_dh_file(keylength);
+			if (dh1024 == NULL)
+				dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024);
+			r = dh1024;
+			break;
+
+		case 2048:
+			if (dh2048 == NULL)
+				dh2048 = load_dh_file(keylength);
+			if (dh2048 == NULL)
+				dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048);
+			r = dh2048;
+			break;
+
+		case 4096:
+			if (dh4096 == NULL)
+				dh4096 = load_dh_file(keylength);
+			if (dh4096 == NULL)
+				dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096);
+			r = dh4096;
+			break;
+
+		default:
+			if (dh == NULL)
+				dh = load_dh_file(keylength);
+			r = dh;
+	}
+
+	/* this may take a long time, but it may be necessary... */
+	if (r == NULL || 8 * DH_size(r) < keylength)
+	{
+		ereport(DEBUG2,
+				(errmsg_internal("DH: generating parameters (%d bits)",
+								 keylength)));
+		r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL);
+	}
+
+	return r;
+}
+
+/*
+ *	Certificate verification callback
+ *
+ *	This callback allows us to log intermediate problems during
+ *	verification, but for now we'll see if the final error message
+ *	contains enough information.
+ *
+ *	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;
+}
+
+/*
+ *	This callback is used to copy SSL information messages
+ *	into the PostgreSQL log.
+ */
+static void
+info_cb(const SSL *ssl, int type, int args)
+{
+	switch (type)
+	{
+		case SSL_CB_HANDSHAKE_START:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: handshake start")));
+			break;
+		case SSL_CB_HANDSHAKE_DONE:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: handshake done")));
+			break;
+		case SSL_CB_ACCEPT_LOOP:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: accept loop")));
+			break;
+		case SSL_CB_ACCEPT_EXIT:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: accept exit (%d)", args)));
+			break;
+		case SSL_CB_CONNECT_LOOP:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: connect loop")));
+			break;
+		case SSL_CB_CONNECT_EXIT:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: connect exit (%d)", args)));
+			break;
+		case SSL_CB_READ_ALERT:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: read alert (0x%04x)", args)));
+			break;
+		case SSL_CB_WRITE_ALERT:
+			ereport(DEBUG4,
+					(errmsg_internal("SSL: write alert (0x%04x)", args)));
+			break;
+	}
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH)
+static void
+initialize_ecdh(void)
+{
+	EC_KEY	   *ecdh;
+	int			nid;
+
+	nid = OBJ_sn2nid(SSLECDHCurve);
+	if (!nid)
+		ereport(FATAL,
+				(errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
+
+	ecdh = EC_KEY_new_by_curve_name(nid);
+	if (!ecdh)
+		ereport(FATAL,
+				(errmsg("ECDH: could not create key")));
+
+	SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_ECDH_USE);
+	SSL_CTX_set_tmp_ecdh(SSL_context, ecdh);
+	EC_KEY_free(ecdh);
+}
+#else
+#define initialize_ecdh()
+#endif
+
+/*
+ *	Initialize global SSL context.
+ */
+void
+be_tls_init(void)
+{
+	struct stat buf;
+
+	STACK_OF(X509_NAME) *root_cert_list = NULL;
+
+	if (!SSL_context)
+	{
+#if SSLEAY_VERSION_NUMBER >= 0x0907000L
+		OPENSSL_config(NULL);
+#endif
+		SSL_library_init();
+		SSL_load_error_strings();
+
+		/*
+		 * We use SSLv23_method() because it can negotiate use of the highest
+		 * mutually supported protocol version, while alternatives like
+		 * TLSv1_2_method() permit only one specific version.  Note that we
+		 * don't actually allow SSL v2 or v3, only TLS protocols (see below).
+		 */
+		SSL_context = SSL_CTX_new(SSLv23_method());
+		if (!SSL_context)
+			ereport(FATAL,
+					(errmsg("could not create SSL context: %s",
+							SSLerrmessage())));
+
+		/*
+		 * 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);
+
+		/*
+		 * Load and verify server's certificate and private key
+		 */
+		if (SSL_CTX_use_certificate_chain_file(SSL_context,
+											   ssl_cert_file) != 1)
+			ereport(FATAL,
+					(errcode(ERRCODE_CONFIG_FILE_ERROR),
+				  errmsg("could not load server certificate file \"%s\": %s",
+						 ssl_cert_file, SSLerrmessage())));
+
+		if (stat(ssl_key_file, &buf) != 0)
+			ereport(FATAL,
+					(errcode_for_file_access(),
+					 errmsg("could not access private key file \"%s\": %m",
+							ssl_key_file)));
+
+		/*
+		 * Require no public access to key file.
+		 *
+		 * XXX temporarily suppress check when on Windows, because there may
+		 * not be proper support for Unix-y file permissions.  Need to think
+		 * of a reasonable check to apply on Windows.  (See also the data
+		 * directory permission check in postmaster.c)
+		 */
+#if !defined(WIN32) && !defined(__CYGWIN__)
+		if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
+			ereport(FATAL,
+					(errcode(ERRCODE_CONFIG_FILE_ERROR),
+				  errmsg("private key file \"%s\" has group or world access",
+						 ssl_key_file),
+				   errdetail("Permissions should be u=rw (0600) or less.")));
+#endif
+
+		if (SSL_CTX_use_PrivateKey_file(SSL_context,
+										ssl_key_file,
+										SSL_FILETYPE_PEM) != 1)
+			ereport(FATAL,
+					(errmsg("could not load private key file \"%s\": %s",
+							ssl_key_file, SSLerrmessage())));
+
+		if (SSL_CTX_check_private_key(SSL_context) != 1)
+			ereport(FATAL,
+					(errmsg("check of private key failed: %s",
+							SSLerrmessage())));
+	}
+
+	/* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
+	SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
+	SSL_CTX_set_options(SSL_context,
+						SSL_OP_SINGLE_DH_USE |
+						SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+	/* set up ephemeral ECDH keys */
+	initialize_ecdh();
+
+	/* set up the allowed cipher list */
+	if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1)
+		elog(FATAL, "could not set the cipher list (no valid ciphers available)");
+
+	/* Let server choose order */
+	if (SSLPreferServerCiphers)
+		SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE);
+
+	/*
+	 * Load CA store, so we can verify client certificates if needed.
+	 */
+	if (ssl_ca_file[0])
+	{
+		if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 ||
+			(root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL)
+			ereport(FATAL,
+					(errmsg("could not load root certificate file \"%s\": %s",
+							ssl_ca_file, SSLerrmessage())));
+	}
+
+	/*----------
+	 * Load the Certificate Revocation List (CRL).
+	 * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
+	 *----------
+	 */
+	if (ssl_crl_file[0])
+	{
+		X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context);
+
+		if (cvstore)
+		{
+			/* Set the flags to check against the complete CRL chain */
+			if (X509_STORE_load_locations(cvstore, ssl_crl_file, 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
+				ereport(LOG,
+				(errmsg("SSL certificate revocation list file \"%s\" ignored",
+						ssl_crl_file),
+				 errdetail("SSL library does not support certificate revocation lists.")));
+#endif
+			}
+			else
+				ereport(FATAL,
+						(errmsg("could not load SSL certificate revocation list file \"%s\": %s",
+								ssl_crl_file, SSLerrmessage())));
+		}
+	}
+
+	if (ssl_ca_file[0])
+	{
+		/*
+		 * Always ask for SSL client cert, but don't fail if it's not
+		 * presented.  We might fail such connections later, depending on what
+		 * we find in pg_hba.conf.
+		 */
+		SSL_CTX_set_verify(SSL_context,
+						   (SSL_VERIFY_PEER |
+							SSL_VERIFY_CLIENT_ONCE),
+						   verify_cb);
+
+		/* Set flag to remember CA store is successfully loaded */
+		ssl_loaded_verify_locations = true;
+
+		/*
+		 * Tell OpenSSL to send the list of root certs we trust to clients in
+		 * CertificateRequests.  This lets a client with a keystore select the
+		 * appropriate client certificate to send to us.
+		 */
+		SSL_CTX_set_client_CA_list(SSL_context, root_cert_list);
+	}
+}
+
+/*
+ *	Attempt to negotiate SSL connection.
+ */
+int
+be_tls_open_server(Port *port)
+{
+	int			r;
+	int			err;
+
+	Assert(!port->ssl);
+	Assert(!port->peer);
+
+	if (!(port->ssl = SSL_new(SSL_context)))
+	{
+		ereport(COMMERROR,
+				(errcode(ERRCODE_PROTOCOL_VIOLATION),
+				 errmsg("could not initialize SSL connection: %s",
+						SSLerrmessage())));
+		be_tls_close(port);
+		return -1;
+	}
+	if (!my_SSL_set_fd(port, port->sock))
+	{
+		ereport(COMMERROR,
+				(errcode(ERRCODE_PROTOCOL_VIOLATION),
+				 errmsg("could not set SSL socket: %s",
+						SSLerrmessage())));
+		be_tls_close(port);
+		return -1;
+	}
+	port->ssl_in_use = true;
+
+aloop:
+	r = SSL_accept(port->ssl);
+	if (r <= 0)
+	{
+		err = SSL_get_error(port->ssl, r);
+		switch (err)
+		{
+			case SSL_ERROR_WANT_READ:
+			case SSL_ERROR_WANT_WRITE:
+#ifdef WIN32
+				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
+											(err == SSL_ERROR_WANT_READ) ?
+						FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE,
+											INFINITE);
+#endif
+				goto aloop;
+			case SSL_ERROR_SYSCALL:
+				if (r < 0)
+					ereport(COMMERROR,
+							(errcode_for_socket_access(),
+							 errmsg("could not accept SSL connection: %m")));
+				else
+					ereport(COMMERROR,
+							(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					errmsg("could not accept SSL connection: EOF detected")));
+				break;
+			case SSL_ERROR_SSL:
+				ereport(COMMERROR,
+						(errcode(ERRCODE_PROTOCOL_VIOLATION),
+						 errmsg("could not accept SSL connection: %s",
+								SSLerrmessage())));
+				break;
+			case SSL_ERROR_ZERO_RETURN:
+				ereport(COMMERROR,
+						(errcode(ERRCODE_PROTOCOL_VIOLATION),
+				   errmsg("could not accept SSL connection: EOF detected")));
+				break;
+			default:
+				ereport(COMMERROR,
+						(errcode(ERRCODE_PROTOCOL_VIOLATION),
+						 errmsg("unrecognized SSL error code: %d",
+								err)));
+				break;
+		}
+		be_tls_close(port);
+		return -1;
+	}
+
+	port->count = 0;
+
+	/* Get client certificate, if available. */
+	port->peer = SSL_get_peer_certificate(port->ssl);
+
+	/* and extract the Common Name from it. */
+	port->peer_cn = NULL;
+	port->peer_cert_valid = false;
+	if (port->peer != NULL)
+	{
+		int			len;
+
+		len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
+										NID_commonName, NULL, 0);
+		if (len != -1)
+		{
+			char	   *peer_cn;
+
+			peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1);
+			r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
+										  NID_commonName, peer_cn, len + 1);
+			peer_cn[len] = '\0';
+			if (r != len)
+			{
+				/* shouldn't happen */
+				pfree(peer_cn);
+				be_tls_close(port);
+				return -1;
+			}
+
+			/*
+			 * Reject embedded NULLs in certificate common name to prevent
+			 * attacks like CVE-2009-4034.
+			 */
+			if (len != strlen(peer_cn))
+			{
+				ereport(COMMERROR,
+						(errcode(ERRCODE_PROTOCOL_VIOLATION),
+						 errmsg("SSL certificate's common name contains embedded null")));
+				pfree(peer_cn);
+				be_tls_close(port);
+				return -1;
+			}
+
+			port->peer_cn = peer_cn;
+		}
+		port->peer_cert_valid = true;
+	}
+
+	ereport(DEBUG2,
+			(errmsg("SSL connection from \"%s\"",
+					port->peer_cn ? port->peer_cn : "(anonymous)")));
+
+	/* set up debugging/info callback */
+	SSL_CTX_set_info_callback(SSL_context, info_cb);
+
+	return 0;
+}
+
+/*
+ *	Close SSL connection.
+ */
+void
+be_tls_close(Port *port)
+{
+	if (port->ssl)
+	{
+		SSL_shutdown(port->ssl);
+		SSL_free(port->ssl);
+		port->ssl = NULL;
+		port->ssl_in_use = false;
+	}
+
+	if (port->peer)
+	{
+		X509_free(port->peer);
+		port->peer = NULL;
+	}
+
+	if (port->peer_cn)
+	{
+		pfree(port->peer_cn);
+		port->peer_cn = NULL;
+	}
+}
+
+ssize_t
+be_tls_read(Port *port, void *ptr, size_t len)
+{
+	ssize_t		n;
+	int			err;
+
+rloop:
+	errno = 0;
+	n = SSL_read(port->ssl, ptr, len);
+	err = SSL_get_error(port->ssl, n);
+	switch (err)
+	{
+		case SSL_ERROR_NONE:
+			port->count += n;
+			break;
+		case SSL_ERROR_WANT_READ:
+		case SSL_ERROR_WANT_WRITE:
+			if (port->noblock)
+			{
+				errno = EWOULDBLOCK;
+				n = -1;
+				break;
+			}
+#ifdef WIN32
+			pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
+										(err == SSL_ERROR_WANT_READ) ?
+									FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
+										INFINITE);
+#endif
+			goto rloop;
+		case SSL_ERROR_SYSCALL:
+			/* leave it to caller to ereport the value of errno */
+			if (n != -1)
+			{
+				errno = ECONNRESET;
+				n = -1;
+			}
+			break;
+		case SSL_ERROR_SSL:
+			ereport(COMMERROR,
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("SSL error: %s", SSLerrmessage())));
+			/* fall through */
+		case SSL_ERROR_ZERO_RETURN:
+			errno = ECONNRESET;
+			n = -1;
+			break;
+		default:
+			ereport(COMMERROR,
+					(errcode(ERRCODE_PROTOCOL_VIOLATION),
+					 errmsg("unrecognized SSL error code: %d",
+							err)));
+			errno = ECONNRESET;
+			n = -1;
+			break;
+	}
+
+	return n;
+}
+
+/*
+ * Obtain reason string for last SSL error
+ *
+ * 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 const char *
+SSLerrmessage(void)
+{
+	unsigned long errcode;
+	const char *errreason;
+	static char errbuf[32];
+
+	errcode = ERR_get_error();
+	if (errcode == 0)
+		return _("no SSL error reported");
+	errreason = ERR_reason_error_string(errcode);
+	if (errreason != NULL)
+		return errreason;
+	snprintf(errbuf, sizeof(errbuf), _("SSL error code %lu"), errcode);
+	return errbuf;
+}
+
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 59204cf..41ec1ad 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -13,38 +13,6 @@
  * IDENTIFICATION
  *	  src/backend/libpq/be-secure.c
  *
- *	  Since the server static private key ($DataDir/server.key)
- *	  will normally be stored unencrypted so that the database
- *	  backend can restart automatically, it is important that
- *	  we select an algorithm that continues to provide confidentiality
- *	  even if the attacker has the server's private key.  Ephemeral
- *	  DH (EDH) keys provide this, and in fact provide Perfect Forward
- *	  Secrecy (PFS) except for situations where the session can
- *	  be hijacked during a periodic handshake/renegotiation.
- *	  Even that backdoor can be closed if client certificates
- *	  are used (since the imposter will be unable to successfully
- *	  complete renegotiation).
- *
- *	  N.B., the static private key should still be protected to
- *	  the largest extent possible, to minimize the risk of
- *	  impersonations.
- *
- *	  Another benefit of EDH is that it allows the backend and
- *	  clients to use DSA keys.  DSA keys can only provide digital
- *	  signatures, not encryption, and are often acceptable in
- *	  jurisdictions where RSA keys are unacceptable.
- *
- *	  The downside to EDH is that it makes it impossible to
- *	  use ssldump(1) if there's a problem establishing an SSL
- *	  session.  In this case you'll need to temporarily disable
- *	  EDH by commenting out the callback.
- *
- *	  ...
- *
- *	  Because the risk of cryptanalysis increases as large
- *	  amounts of data are sent with the same session key, the
- *	  session keys are periodically renegotiated.
- *
  *-------------------------------------------------------------------------
  */
 
@@ -63,35 +31,11 @@
 #include <arpa/inet.h>
 #endif
 
-#ifdef USE_SSL
-#include <openssl/ssl.h>
-#include <openssl/dh.h>
-#if SSLEAY_VERSION_NUMBER >= 0x0907000L
-#include <openssl/conf.h>
-#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH)
-#include <openssl/ec.h>
-#endif
-#endif   /* USE_SSL */
-
 #include "libpq/libpq.h"
 #include "tcop/tcopprot.h"
 #include "utils/memutils.h"
 
 
-#ifdef USE_SSL
-
-static DH  *load_dh_file(int keylength);
-static DH  *load_dh_buffer(const char *, size_t);
-static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);
-static int	verify_cb(int, X509_STORE_CTX *);
-static void info_cb(const SSL *ssl, int type, int args);
-static void initialize_SSL(void);
-static int	open_server_SSL(Port *);
-static void close_SSL(Port *);
-static const char *SSLerrmessage(void);
-#endif
-
 char	   *ssl_cert_file;
 char	   *ssl_key_file;
 char	   *ssl_ca_file;
@@ -105,11 +49,7 @@ char	   *ssl_crl_file;
 int			ssl_renegotiation_limit;
 
 #ifdef USE_SSL
-/* are we in the middle of a renegotiation? */
-static bool in_ssl_renegotiation = false;
-
-static SSL_CTX *SSL_context = NULL;
-static bool ssl_loaded_verify_locations = false;
+bool ssl_loaded_verify_locations = false;
 #endif
 
 /* GUC variable controlling SSL cipher list */
@@ -122,73 +62,6 @@ char	   *SSLECDHCurve;
 bool		SSLPreferServerCiphers;
 
 /* ------------------------------------------------------------ */
-/*						 Hardcoded values						*/
-/* ------------------------------------------------------------ */
-
-/*
- *	Hardcoded DH parameters, used in ephemeral DH keying.
- *	As discussed above, EDH protects the confidentiality of
- *	sessions even if the static private key is compromised,
- *	so we are *highly* motivated to ensure that we can use
- *	EDH even if the DBA... or an attacker... deletes the
- *	$DataDir/dh*.pem files.
- *
- *	We could refuse SSL connections unless a good DH parameter
- *	file exists, but some clients may quietly renegotiate an
- *	unsecured connection without fully informing the user.
- *	Very uncool.
- *
- *	Alternatively, the backend could attempt to load these files
- *	on startup if SSL is enabled - and refuse to start if any
- *	do not exist - but this would tend to piss off DBAs.
- *
- *	If you want to create your own hardcoded DH parameters
- *	for fun and profit, review "Assigned Number for SKIP
- *	Protocols" (http://www.skip-vpn.org/spec/numbers.html)
- *	for suggestions.
- */
-#ifdef USE_SSL
-
-static const char file_dh512[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\
-XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh1024[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\
-jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\
-ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh2048[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\
-89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50\n\
-T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb\n\
-zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX\n\
-Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\
-CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh4096[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\
-l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\
-Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\
-Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\
-VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\
-alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\
-sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\
-ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\
-OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\
-AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\
-KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
------END DH PARAMETERS-----\n";
-#endif
-
-/* ------------------------------------------------------------ */
 /*			 Procedures common to all secure sessions			*/
 /* ------------------------------------------------------------ */
 
@@ -199,7 +72,7 @@ int
 secure_initialize(void)
 {
 #ifdef USE_SSL
-	initialize_SSL();
+	be_tls_init();
 #endif
 
 	return 0;
@@ -227,7 +100,7 @@ secure_open_server(Port *port)
 	int			r = 0;
 
 #ifdef USE_SSL
-	r = open_server_SSL(port);
+	r = be_tls_open_server(port);
 #endif
 
 	return r;
@@ -240,8 +113,8 @@ void
 secure_close(Port *port)
 {
 #ifdef USE_SSL
-	if (port->ssl)
-		close_SSL(port);
+	if (port->ssl_in_use)
+		be_tls_close(port);
 #endif
 }
 
@@ -254,908 +127,56 @@ secure_read(Port *port, void *ptr, size_t len)
 	ssize_t		n;
 
 #ifdef USE_SSL
-	if (port->ssl)
+	if (port->ssl_in_use)
 	{
-		int			err;
-
-rloop:
-		errno = 0;
-		n = SSL_read(port->ssl, ptr, len);
-		err = SSL_get_error(port->ssl, n);
-		switch (err)
-		{
-			case SSL_ERROR_NONE:
-				port->count += n;
-				break;
-			case SSL_ERROR_WANT_READ:
-			case SSL_ERROR_WANT_WRITE:
-				if (port->noblock)
-				{
-					errno = EWOULDBLOCK;
-					n = -1;
-					break;
-				}
-#ifdef WIN32
-				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
-											(err == SSL_ERROR_WANT_READ) ?
-									FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
-											INFINITE);
-#endif
-				goto rloop;
-			case SSL_ERROR_SYSCALL:
-				/* leave it to caller to ereport the value of errno */
-				if (n != -1)
-				{
-					errno = ECONNRESET;
-					n = -1;
-				}
-				break;
-			case SSL_ERROR_SSL:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("SSL error: %s", SSLerrmessage())));
-				/* fall through */
-			case SSL_ERROR_ZERO_RETURN:
-				errno = ECONNRESET;
-				n = -1;
-				break;
-			default:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("unrecognized SSL error code: %d",
-								err)));
-				errno = ECONNRESET;
-				n = -1;
-				break;
-		}
+		n = be_tls_read(port, ptr, len);
 	}
 	else
 #endif
 	{
-		prepare_for_client_read();
-
-		n = recv(port->sock, ptr, len, 0);
-
-		client_read_ended();
+		n = secure_raw_read(port, ptr, len);
 	}
 
 	return n;
 }
 
-/*
- *	Write data to a secure connection.
- */
 ssize_t
-secure_write(Port *port, void *ptr, size_t len)
+secure_raw_read(Port *port, void *ptr, size_t len)
 {
 	ssize_t		n;
 
-#ifdef USE_SSL
-	if (port->ssl)
-	{
-		int			err;
-
-		/*
-		 * If SSL renegotiations are enabled and we're getting close to the
-		 * limit, start one now; but avoid it if there's one already in
-		 * progress.  Request the renegotiation 1kB before the limit has
-		 * actually expired.
-		 */
-		if (ssl_renegotiation_limit && !in_ssl_renegotiation &&
-			port->count > (ssl_renegotiation_limit - 1) * 1024L)
-		{
-			in_ssl_renegotiation = true;
-
-			/*
-			 * The way we determine that a renegotiation has completed is by
-			 * observing OpenSSL's internal renegotiation counter.  Make sure
-			 * we start out at zero, and assume that the renegotiation is
-			 * complete when the counter advances.
-			 *
-			 * OpenSSL provides SSL_renegotiation_pending(), but this doesn't
-			 * seem to work in testing.
-			 */
-			SSL_clear_num_renegotiations(port->ssl);
-
-			SSL_set_session_id_context(port->ssl, (void *) &SSL_context,
-									   sizeof(SSL_context));
-			if (SSL_renegotiate(port->ssl) <= 0)
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("SSL failure during renegotiation start")));
-			else
-			{
-				int			retries;
-
-				/*
-				 * A handshake can fail, so be prepared to retry it, but only
-				 * a few times.
-				 */
-				for (retries = 0;; retries++)
-				{
-					if (SSL_do_handshake(port->ssl) > 0)
-						break;	/* done */
-					ereport(COMMERROR,
-							(errcode(ERRCODE_PROTOCOL_VIOLATION),
-							 errmsg("SSL handshake failure on renegotiation, retrying")));
-					if (retries >= 20)
-						ereport(FATAL,
-								(errcode(ERRCODE_PROTOCOL_VIOLATION),
-								 errmsg("unable to complete SSL handshake")));
-				}
-			}
-		}
-
-wloop:
-		errno = 0;
-		n = SSL_write(port->ssl, ptr, len);
-		err = SSL_get_error(port->ssl, n);
-		switch (err)
-		{
-			case SSL_ERROR_NONE:
-				port->count += n;
-				break;
-			case SSL_ERROR_WANT_READ:
-			case SSL_ERROR_WANT_WRITE:
-#ifdef WIN32
-				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
-											(err == SSL_ERROR_WANT_READ) ?
-									FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
-											INFINITE);
-#endif
-				goto wloop;
-			case SSL_ERROR_SYSCALL:
-				/* leave it to caller to ereport the value of errno */
-				if (n != -1)
-				{
-					errno = ECONNRESET;
-					n = -1;
-				}
-				break;
-			case SSL_ERROR_SSL:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("SSL error: %s", SSLerrmessage())));
-				/* fall through */
-			case SSL_ERROR_ZERO_RETURN:
-				errno = ECONNRESET;
-				n = -1;
-				break;
-			default:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("unrecognized SSL error code: %d",
-								err)));
-				errno = ECONNRESET;
-				n = -1;
-				break;
-		}
-
-		if (n >= 0)
-		{
-			/* is renegotiation complete? */
-			if (in_ssl_renegotiation &&
-				SSL_num_renegotiations(port->ssl) >= 1)
-			{
-				in_ssl_renegotiation = false;
-				port->count = 0;
-			}
-
-			/*
-			 * if renegotiation is still ongoing, and we've gone beyond the
-			 * limit, kill the connection now -- continuing to use it can be
-			 * considered a security problem.
-			 */
-			if (in_ssl_renegotiation &&
-				port->count > ssl_renegotiation_limit * 1024L)
-				ereport(FATAL,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("SSL failed to renegotiate connection before limit expired")));
-		}
-	}
-	else
-#endif
-		n = send(port->sock, ptr, len, 0);
-
-	return n;
-}
-
-/* ------------------------------------------------------------ */
-/*						  SSL specific code						*/
-/* ------------------------------------------------------------ */
-#ifdef USE_SSL
-
-/*
- * Private substitute BIO: this does the sending and receiving using send() and
- * recv() instead. This is so that we can enable and disable interrupts
- * just while calling recv(). We cannot have interrupts occurring while
- * the bulk of openssl runs, because it uses malloc() and possibly other
- * non-reentrant libc facilities. We also need to call send() and recv()
- * directly so it gets passed through the socket/signals layer on Win32.
- *
- * 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?
- */
-
-static bool my_bio_initialized = false;
-static BIO_METHOD my_bio_methods;
-
-static int
-my_sock_read(BIO *h, char *buf, int size)
-{
-	int			res = 0;
-
 	prepare_for_client_read();
 
-	if (buf != NULL)
-	{
-		res = recv(h->num, buf, size, 0);
-		BIO_clear_retry_flags(h);
-		if (res <= 0)
-		{
-			/* If we were interrupted, tell caller to retry */
-			if (errno == EINTR)
-			{
-				BIO_set_retry_read(h);
-			}
-		}
-	}
+	n = recv(port->sock, ptr, len, 0);
 
 	client_read_ended();
 
-	return res;
-}
-
-static int
-my_sock_write(BIO *h, const char *buf, int size)
-{
-	int			res = 0;
-
-	res = send(h->num, buf, size, 0);
-	BIO_clear_retry_flags(h);
-	if (res <= 0)
-	{
-		if (errno == EINTR)
-		{
-			BIO_set_retry_write(h);
-		}
-	}
-
-	return res;
-}
-
-static BIO_METHOD *
-my_BIO_s_socket(void)
-{
-	if (!my_bio_initialized)
-	{
-		memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD));
-		my_bio_methods.bread = my_sock_read;
-		my_bio_methods.bwrite = my_sock_write;
-		my_bio_initialized = true;
-	}
-	return &my_bio_methods;
-}
-
-/* This should exactly match openssl's SSL_set_fd except for using my BIO */
-static int
-my_SSL_set_fd(SSL *s, int fd)
-{
-	int			ret = 0;
-	BIO		   *bio = NULL;
-
-	bio = BIO_new(my_BIO_s_socket());
-
-	if (bio == NULL)
-	{
-		SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
-		goto err;
-	}
-	BIO_set_fd(bio, fd, BIO_NOCLOSE);
-	SSL_set_bio(s, bio, bio);
-	ret = 1;
-err:
-	return ret;
-}
-
-/*
- *	Load precomputed DH parameters.
- *
- *	To prevent "downgrade" attacks, we perform a number of checks
- *	to verify that the DBA-generated DH parameters file contains
- *	what we expect it to contain.
- */
-static DH  *
-load_dh_file(int keylength)
-{
-	FILE	   *fp;
-	char		fnbuf[MAXPGPATH];
-	DH		   *dh = NULL;
-	int			codes;
-
-	/* attempt to open file.  It's not an error if it doesn't exist. */
-	snprintf(fnbuf, sizeof(fnbuf), "dh%d.pem", keylength);
-	if ((fp = fopen(fnbuf, "r")) == NULL)
-		return NULL;
-
-/*	flock(fileno(fp), LOCK_SH); */
-	dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
-/*	flock(fileno(fp), LOCK_UN); */
-	fclose(fp);
-
-	/* is the prime the correct size? */
-	if (dh != NULL && 8 * DH_size(dh) < keylength)
-	{
-		elog(LOG, "DH errors (%s): %d bits expected, %d bits found",
-			 fnbuf, keylength, 8 * DH_size(dh));
-		dh = NULL;
-	}
-
-	/* make sure the DH parameters are usable */
-	if (dh != NULL)
-	{
-		if (DH_check(dh, &codes) == 0)
-		{
-			elog(LOG, "DH_check error (%s): %s", fnbuf, SSLerrmessage());
-			return NULL;
-		}
-		if (codes & DH_CHECK_P_NOT_PRIME)
-		{
-			elog(LOG, "DH error (%s): p is not prime", fnbuf);
-			return NULL;
-		}
-		if ((codes & DH_NOT_SUITABLE_GENERATOR) &&
-			(codes & DH_CHECK_P_NOT_SAFE_PRIME))
-		{
-			elog(LOG,
-				 "DH error (%s): neither suitable generator or safe prime",
-				 fnbuf);
-			return NULL;
-		}
-	}
-
-	return dh;
-}
-
-/*
- *	Load hardcoded DH parameters.
- *
- *	To prevent problems if the DH parameters files don't even
- *	exist, we can load DH parameters hardcoded into this file.
- */
-static DH  *
-load_dh_buffer(const char *buffer, size_t len)
-{
-	BIO		   *bio;
-	DH		   *dh = NULL;
-
-	bio = BIO_new_mem_buf((char *) buffer, len);
-	if (bio == NULL)
-		return NULL;
-	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-	if (dh == NULL)
-		ereport(DEBUG2,
-				(errmsg_internal("DH load buffer: %s",
-								 SSLerrmessage())));
-	BIO_free(bio);
-
-	return dh;
-}
-
-/*
- *	Generate an ephemeral DH key.  Because this can take a long
- *	time to compute, we can use precomputed parameters of the
- *	common key sizes.
- *
- *	Since few sites will bother to precompute these parameter
- *	files, we also provide a fallback to the parameters provided
- *	by the OpenSSL project.
- *
- *	These values can be static (once loaded or computed) since
- *	the OpenSSL library can efficiently generate random keys from
- *	the information provided.
- */
-static DH  *
-tmp_dh_cb(SSL *s, int is_export, int keylength)
-{
-	DH		   *r = NULL;
-	static DH  *dh = NULL;
-	static DH  *dh512 = NULL;
-	static DH  *dh1024 = NULL;
-	static DH  *dh2048 = NULL;
-	static DH  *dh4096 = NULL;
-
-	switch (keylength)
-	{
-		case 512:
-			if (dh512 == NULL)
-				dh512 = load_dh_file(keylength);
-			if (dh512 == NULL)
-				dh512 = load_dh_buffer(file_dh512, sizeof file_dh512);
-			r = dh512;
-			break;
-
-		case 1024:
-			if (dh1024 == NULL)
-				dh1024 = load_dh_file(keylength);
-			if (dh1024 == NULL)
-				dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024);
-			r = dh1024;
-			break;
-
-		case 2048:
-			if (dh2048 == NULL)
-				dh2048 = load_dh_file(keylength);
-			if (dh2048 == NULL)
-				dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048);
-			r = dh2048;
-			break;
-
-		case 4096:
-			if (dh4096 == NULL)
-				dh4096 = load_dh_file(keylength);
-			if (dh4096 == NULL)
-				dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096);
-			r = dh4096;
-			break;
-
-		default:
-			if (dh == NULL)
-				dh = load_dh_file(keylength);
-			r = dh;
-	}
-
-	/* this may take a long time, but it may be necessary... */
-	if (r == NULL || 8 * DH_size(r) < keylength)
-	{
-		ereport(DEBUG2,
-				(errmsg_internal("DH: generating parameters (%d bits)",
-								 keylength)));
-		r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL);
-	}
-
-	return r;
-}
-
-/*
- *	Certificate verification callback
- *
- *	This callback allows us to log intermediate problems during
- *	verification, but for now we'll see if the final error message
- *	contains enough information.
- *
- *	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;
-}
-
-/*
- *	This callback is used to copy SSL information messages
- *	into the PostgreSQL log.
- */
-static void
-info_cb(const SSL *ssl, int type, int args)
-{
-	switch (type)
-	{
-		case SSL_CB_HANDSHAKE_START:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: handshake start")));
-			break;
-		case SSL_CB_HANDSHAKE_DONE:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: handshake done")));
-			break;
-		case SSL_CB_ACCEPT_LOOP:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: accept loop")));
-			break;
-		case SSL_CB_ACCEPT_EXIT:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: accept exit (%d)", args)));
-			break;
-		case SSL_CB_CONNECT_LOOP:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: connect loop")));
-			break;
-		case SSL_CB_CONNECT_EXIT:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: connect exit (%d)", args)));
-			break;
-		case SSL_CB_READ_ALERT:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: read alert (0x%04x)", args)));
-			break;
-		case SSL_CB_WRITE_ALERT:
-			ereport(DEBUG4,
-					(errmsg_internal("SSL: write alert (0x%04x)", args)));
-			break;
-	}
+	return n;
 }
 
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH)
-static void
-initialize_ecdh(void)
-{
-	EC_KEY	   *ecdh;
-	int			nid;
-
-	nid = OBJ_sn2nid(SSLECDHCurve);
-	if (!nid)
-		ereport(FATAL,
-				(errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
-
-	ecdh = EC_KEY_new_by_curve_name(nid);
-	if (!ecdh)
-		ereport(FATAL,
-				(errmsg("ECDH: could not create key")));
-
-	SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_ECDH_USE);
-	SSL_CTX_set_tmp_ecdh(SSL_context, ecdh);
-	EC_KEY_free(ecdh);
-}
-#else
-#define initialize_ecdh()
-#endif
 
 /*
- *	Initialize global SSL context.
- */
-static void
-initialize_SSL(void)
-{
-	struct stat buf;
-
-	STACK_OF(X509_NAME) *root_cert_list = NULL;
-
-	if (!SSL_context)
-	{
-#if SSLEAY_VERSION_NUMBER >= 0x0907000L
-		OPENSSL_config(NULL);
-#endif
-		SSL_library_init();
-		SSL_load_error_strings();
-
-		/*
-		 * We use SSLv23_method() because it can negotiate use of the highest
-		 * mutually supported protocol version, while alternatives like
-		 * TLSv1_2_method() permit only one specific version.  Note that we
-		 * don't actually allow SSL v2 or v3, only TLS protocols (see below).
-		 */
-		SSL_context = SSL_CTX_new(SSLv23_method());
-		if (!SSL_context)
-			ereport(FATAL,
-					(errmsg("could not create SSL context: %s",
-							SSLerrmessage())));
-
-		/*
-		 * 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);
-
-		/*
-		 * Load and verify server's certificate and private key
-		 */
-		if (SSL_CTX_use_certificate_chain_file(SSL_context,
-											   ssl_cert_file) != 1)
-			ereport(FATAL,
-					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				  errmsg("could not load server certificate file \"%s\": %s",
-						 ssl_cert_file, SSLerrmessage())));
-
-		if (stat(ssl_key_file, &buf) != 0)
-			ereport(FATAL,
-					(errcode_for_file_access(),
-					 errmsg("could not access private key file \"%s\": %m",
-							ssl_key_file)));
-
-		/*
-		 * Require no public access to key file.
-		 *
-		 * XXX temporarily suppress check when on Windows, because there may
-		 * not be proper support for Unix-y file permissions.  Need to think
-		 * of a reasonable check to apply on Windows.  (See also the data
-		 * directory permission check in postmaster.c)
-		 */
-#if !defined(WIN32) && !defined(__CYGWIN__)
-		if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
-			ereport(FATAL,
-					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				  errmsg("private key file \"%s\" has group or world access",
-						 ssl_key_file),
-				   errdetail("Permissions should be u=rw (0600) or less.")));
-#endif
-
-		if (SSL_CTX_use_PrivateKey_file(SSL_context,
-										ssl_key_file,
-										SSL_FILETYPE_PEM) != 1)
-			ereport(FATAL,
-					(errmsg("could not load private key file \"%s\": %s",
-							ssl_key_file, SSLerrmessage())));
-
-		if (SSL_CTX_check_private_key(SSL_context) != 1)
-			ereport(FATAL,
-					(errmsg("check of private key failed: %s",
-							SSLerrmessage())));
-	}
-
-	/* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
-	SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
-	SSL_CTX_set_options(SSL_context,
-						SSL_OP_SINGLE_DH_USE |
-						SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
-
-	/* set up ephemeral ECDH keys */
-	initialize_ecdh();
-
-	/* set up the allowed cipher list */
-	if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1)
-		elog(FATAL, "could not set the cipher list (no valid ciphers available)");
-
-	/* Let server choose order */
-	if (SSLPreferServerCiphers)
-		SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE);
-
-	/*
-	 * Load CA store, so we can verify client certificates if needed.
-	 */
-	if (ssl_ca_file[0])
-	{
-		if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 ||
-			(root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL)
-			ereport(FATAL,
-					(errmsg("could not load root certificate file \"%s\": %s",
-							ssl_ca_file, SSLerrmessage())));
-	}
-
-	/*----------
-	 * Load the Certificate Revocation List (CRL).
-	 * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
-	 *----------
-	 */
-	if (ssl_crl_file[0])
-	{
-		X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context);
-
-		if (cvstore)
-		{
-			/* Set the flags to check against the complete CRL chain */
-			if (X509_STORE_load_locations(cvstore, ssl_crl_file, 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
-				ereport(LOG,
-				(errmsg("SSL certificate revocation list file \"%s\" ignored",
-						ssl_crl_file),
-				 errdetail("SSL library does not support certificate revocation lists.")));
-#endif
-			}
-			else
-				ereport(FATAL,
-						(errmsg("could not load SSL certificate revocation list file \"%s\": %s",
-								ssl_crl_file, SSLerrmessage())));
-		}
-	}
-
-	if (ssl_ca_file[0])
-	{
-		/*
-		 * Always ask for SSL client cert, but don't fail if it's not
-		 * presented.  We might fail such connections later, depending on what
-		 * we find in pg_hba.conf.
-		 */
-		SSL_CTX_set_verify(SSL_context,
-						   (SSL_VERIFY_PEER |
-							SSL_VERIFY_CLIENT_ONCE),
-						   verify_cb);
-
-		/* Set flag to remember CA store is successfully loaded */
-		ssl_loaded_verify_locations = true;
-
-		/*
-		 * Tell OpenSSL to send the list of root certs we trust to clients in
-		 * CertificateRequests.  This lets a client with a keystore select the
-		 * appropriate client certificate to send to us.
-		 */
-		SSL_CTX_set_client_CA_list(SSL_context, root_cert_list);
-	}
-}
-
-/*
- *	Attempt to negotiate SSL connection.
+ *	Write data to a secure connection.
  */
-static int
-open_server_SSL(Port *port)
+ssize_t
+secure_write(Port *port, void *ptr, size_t len)
 {
-	int			r;
-	int			err;
-
-	Assert(!port->ssl);
-	Assert(!port->peer);
+	ssize_t		n;
 
-	if (!(port->ssl = SSL_new(SSL_context)))
-	{
-		ereport(COMMERROR,
-				(errcode(ERRCODE_PROTOCOL_VIOLATION),
-				 errmsg("could not initialize SSL connection: %s",
-						SSLerrmessage())));
-		close_SSL(port);
-		return -1;
-	}
-	if (!my_SSL_set_fd(port->ssl, port->sock))
+#ifdef USE_SSL
+	if (port->ssl_in_use)
 	{
-		ereport(COMMERROR,
-				(errcode(ERRCODE_PROTOCOL_VIOLATION),
-				 errmsg("could not set SSL socket: %s",
-						SSLerrmessage())));
-		close_SSL(port);
-		return -1;
+		n = be_tls_write(port, ptr, len);
 	}
-
-aloop:
-	r = SSL_accept(port->ssl);
-	if (r <= 0)
-	{
-		err = SSL_get_error(port->ssl, r);
-		switch (err)
-		{
-			case SSL_ERROR_WANT_READ:
-			case SSL_ERROR_WANT_WRITE:
-#ifdef WIN32
-				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
-											(err == SSL_ERROR_WANT_READ) ?
-						FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE,
-											INFINITE);
+	else
 #endif
-				goto aloop;
-			case SSL_ERROR_SYSCALL:
-				if (r < 0)
-					ereport(COMMERROR,
-							(errcode_for_socket_access(),
-							 errmsg("could not accept SSL connection: %m")));
-				else
-					ereport(COMMERROR,
-							(errcode(ERRCODE_PROTOCOL_VIOLATION),
-					errmsg("could not accept SSL connection: EOF detected")));
-				break;
-			case SSL_ERROR_SSL:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("could not accept SSL connection: %s",
-								SSLerrmessage())));
-				break;
-			case SSL_ERROR_ZERO_RETURN:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-				   errmsg("could not accept SSL connection: EOF detected")));
-				break;
-			default:
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("unrecognized SSL error code: %d",
-								err)));
-				break;
-		}
-		close_SSL(port);
-		return -1;
-	}
-
-	port->count = 0;
-
-	/* Get client certificate, if available. */
-	port->peer = SSL_get_peer_certificate(port->ssl);
-
-	/* and extract the Common Name from it. */
-	port->peer_cn = NULL;
-	if (port->peer != NULL)
-	{
-		int			len;
+		n = secure_raw_write(port, ptr, len);
 
-		len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
-										NID_commonName, NULL, 0);
-		if (len != -1)
-		{
-			char	   *peer_cn;
-
-			peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1);
-			r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
-										  NID_commonName, peer_cn, len + 1);
-			peer_cn[len] = '\0';
-			if (r != len)
-			{
-				/* shouldn't happen */
-				pfree(peer_cn);
-				close_SSL(port);
-				return -1;
-			}
-
-			/*
-			 * Reject embedded NULLs in certificate common name to prevent
-			 * attacks like CVE-2009-4034.
-			 */
-			if (len != strlen(peer_cn))
-			{
-				ereport(COMMERROR,
-						(errcode(ERRCODE_PROTOCOL_VIOLATION),
-						 errmsg("SSL certificate's common name contains embedded null")));
-				pfree(peer_cn);
-				close_SSL(port);
-				return -1;
-			}
-
-			port->peer_cn = peer_cn;
-		}
-	}
-
-	ereport(DEBUG2,
-			(errmsg("SSL connection from \"%s\"",
-					port->peer_cn ? port->peer_cn : "(anonymous)")));
-
-	/* set up debugging/info callback */
-	SSL_CTX_set_info_callback(SSL_context, info_cb);
-
-	return 0;
-}
-
-/*
- *	Close SSL connection.
- */
-static void
-close_SSL(Port *port)
-{
-	if (port->ssl)
-	{
-		SSL_shutdown(port->ssl);
-		SSL_free(port->ssl);
-		port->ssl = NULL;
-	}
-
-	if (port->peer)
-	{
-		X509_free(port->peer);
-		port->peer = NULL;
-	}
-
-	if (port->peer_cn)
-	{
-		pfree(port->peer_cn);
-		port->peer_cn = NULL;
-	}
+	return n;
 }
 
-/*
- * Obtain reason string for last SSL error
- *
- * 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 const char *
-SSLerrmessage(void)
+ssize_t
+secure_raw_write(Port *port, const void *ptr, size_t len)
 {
-	unsigned long errcode;
-	const char *errreason;
-	static char errbuf[32];
-
-	errcode = ERR_get_error();
-	if (errcode == 0)
-		return _("no SSL error reported");
-	errreason = ERR_reason_error_string(errcode);
-	if (errreason != NULL)
-		return errreason;
-	snprintf(errbuf, sizeof(errbuf), _("SSL error code %lu"), errcode);
-	return errbuf;
+	return send(port->sock, ptr, len, 0);
 }
-
-#endif   /* USE_SSL */
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index fd98c60..84da823 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1685,7 +1685,7 @@ check_hba(hbaPort *port)
 
 			/* Check SSL state */
 #ifdef USE_SSL
-			if (port->ssl)
+			if (port->ssl_in_use)
 			{
 				/* Connection is SSL, match both "host" and "hostssl" */
 				if (hba->conntype == ctHostNoSSL)
diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c
index 5e5bd35..dd3abab 100644
--- a/src/backend/postmaster/fork_process.c
+++ b/src/backend/postmaster/fork_process.c
@@ -17,7 +17,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <unistd.h>
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 #include <openssl/rand.h>
 #endif
 
@@ -110,7 +110,7 @@ fork_process(void)
 		/*
 		 * Make sure processes do not share OpenSSL randomness state.
 		 */
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 		RAND_cleanup();
 #endif
 	}
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 28243ad..a5b9821 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -231,8 +231,8 @@ PerformAuthentication(Port *port)
 	{
 		if (am_walsender)
 		{
-#ifdef USE_SSL
-			if (port->ssl)
+#ifdef USE_OPENSSL
+			if (port->ssl_in_use)
 				ereport(LOG,
 						(errmsg("replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)",
 								port->user_name, SSL_get_version(port->ssl), SSL_get_cipher(port->ssl),
@@ -245,8 +245,8 @@ PerformAuthentication(Port *port)
 		}
 		else
 		{
-#ifdef USE_SSL
-			if (port->ssl)
+#ifdef USE_OPENSSL
+			if (port->ssl_in_use)
 				ereport(LOG,
 						(errmsg("connection authorized: user=%s database=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)",
 								port->user_name, port->database_name, SSL_get_version(port->ssl), SSL_get_cipher(port->ssl),
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6c52db8..9aa1bc4 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -125,9 +125,6 @@ extern char *default_tablespace;
 extern char *temp_tablespaces;
 extern bool ignore_checksum_failure;
 extern bool synchronize_seqscans;
-extern char *SSLCipherSuites;
-extern char *SSLECDHCurve;
-extern bool SSLPreferServerCiphers;
 
 #ifdef TRACE_SORT
 extern bool trace_sort;
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 161de75..958505d 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -30,7 +30,7 @@
 #include <sys/types.h>			/* for umask() */
 #include <sys/stat.h>			/* for stat() */
 #endif
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 #include <openssl/ssl.h>
 #endif
 
@@ -1791,7 +1791,7 @@ connection_warnings(bool in_startup)
 static void
 printSSLInfo(void)
 {
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 	int			sslbits = -1;
 	SSL		   *ssl;
 
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index e78c565..34e52e4 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -21,7 +21,7 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #endif
@@ -184,17 +184,33 @@ typedef struct Port
 #endif
 
 	/*
-	 * SSL structures (keep these last so that USE_SSL doesn't affect
-	 * locations of other fields)
+	 * SSL structures (keep these last so that the locations of other fields
+	 * are the same whether or not you build with SSL)
 	 */
 #ifdef USE_SSL
+	bool		ssl_in_use;
+	char	   *peer_cn;
+	bool		peer_cert_valid;
+#endif
+#ifdef USE_OPENSSL
 	SSL		   *ssl;
 	X509	   *peer;
-	char	   *peer_cn;
 	unsigned long count;
 #endif
 } Port;
 
+#ifdef USE_SSL
+/*
+ * These functions are implemented by the glue code specific to each
+ * SSL implementation (e.g. be-secure-openssl.c)
+ */
+extern void be_tls_init(void);
+extern int be_tls_open_server(Port *port);
+extern void be_tls_close(Port *port);
+extern ssize_t be_tls_read(Port *port, void *ptr, size_t len);
+extern ssize_t be_tls_write(Port *port, void *ptr, size_t len);
+
+#endif
 
 extern ProtocolVersion FrontendProtocol;
 
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index e4e354d..5da9d8d 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -82,5 +82,14 @@ extern int	secure_open_server(Port *port);
 extern void secure_close(Port *port);
 extern ssize_t secure_read(Port *port, void *ptr, size_t len);
 extern ssize_t secure_write(Port *port, void *ptr, size_t len);
+extern ssize_t secure_raw_read(Port *port, void *ptr, size_t len);
+extern ssize_t secure_raw_write(Port *port, const void *ptr, size_t len);
+
+extern bool ssl_loaded_verify_locations;
+
+/* GUCs */
+extern char *SSLCipherSuites;
+extern char *SSLECDHCurve;
+extern bool SSLPreferServerCiphers;
 
 #endif   /* LIBPQ_H */
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 4383ad5..7894573 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -778,14 +778,22 @@
 /* Define to select named POSIX semaphores. */
 #undef USE_NAMED_POSIX_SEMAPHORES
 
+/* Define to build with OpenSSL support. (--with-openssl) */
+#undef USE_OPENSSL
+
 /* Define to 1 to build with PAM support. (--with-pam) */
 #undef USE_PAM
 
 /* Use replacement snprintf() functions. */
 #undef USE_REPL_SNPRINTF
 
-/* Define to build with (Open)SSL support. (--with-openssl) */
-#undef USE_SSL
+/*
+ * USE_SSL is defined when building with any SSL implementation (currently,
+ * only OpenSSL is supported).
+ */
+#ifdef USE_OPENSSL
+#define USE_SSL
+#endif
 
 /* Define to select SysV-style semaphores. */
 #undef USE_SYSV_SEMAPHORES
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index f7c2419..d802019 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -628,14 +628,22 @@
 /* Define to select named POSIX semaphores. */
 /* #undef USE_NAMED_POSIX_SEMAPHORES */
 
+/* Define to build with OpenSSL support. (--with-openssl) */
+/* #undef USE_OPENSSL */
+
 /* Define to 1 to build with PAM support. (--with-pam) */
 /* #undef USE_PAM */
 
 /* Use replacement snprintf() functions. */
 #define USE_REPL_SNPRINTF 1
 
-/* Define to build with (Open)SSL support. (--with-openssl) */
-/* #undef USE_SSL */
+/*
+ * USE_SSL is defined when building with any SSL implementation (currently,
+ * only OpenSSL is supported).
+ */
+#ifdef USE_OPENSSL
+#define USE_SSL
+#endif
 
 /* Define to select SysV-style semaphores. */
 /* #undef USE_SYSV_SEMAPHORES */
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 718ecd6..a90cb89 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -44,6 +44,10 @@ OBJS += ip.o md5.o
 # utils/mb
 OBJS += encnames.o wchar.o
 
+ifeq ($(with_openssl),yes)
+OBJS += fe-secure-openssl.o
+endif
+
 ifeq ($(PORTNAME), cygwin)
 override shlib = cyg$(NAME)$(DLSUFFIX)
 endif
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 540426c..b0b0e1a 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1961,7 +1961,7 @@ keep_going:						/* We will come back to here until there is
 					conn->allow_ssl_try = false;
 				}
 				if (conn->allow_ssl_try && !conn->wait_ssl_try &&
-					conn->ssl == NULL)
+					!conn->ssl_in_use)
 				{
 					ProtocolVersion pv;
 
@@ -2040,7 +2040,7 @@ keep_going:						/* We will come back to here until there is
 				 * On first time through, get the postmaster's response to our
 				 * SSL negotiation packet.
 				 */
-				if (conn->ssl == NULL)
+				if (!conn->ssl_in_use)
 				{
 					/*
 					 * We use pqReadData here since it has the logic to
@@ -2310,7 +2310,7 @@ keep_going:						/* We will come back to here until there is
 					 * connection already, then retry with an SSL connection
 					 */
 					if (conn->sslmode[0] == 'a' /* "allow" */
-						&& conn->ssl == NULL
+						&& !conn->ssl_in_use
 						&& conn->allow_ssl_try
 						&& conn->wait_ssl_try)
 					{
@@ -2709,6 +2709,7 @@ makeEmptyPGconn(void)
 #ifdef USE_SSL
 	conn->allow_ssl_try = true;
 	conn->wait_ssl_try = false;
+	conn->ssl_in_use = false;
 #endif
 
 	/*
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index a75db19..fc930bd 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -751,7 +751,7 @@ retry3:
 	 */
 
 #ifdef USE_SSL
-	if (conn->ssl)
+	if (conn->ssl_in_use)
 		return 0;
 #endif
 
@@ -1051,7 +1051,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
 		return -1;
 	}
 
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 	/* Check for SSL library buffering read bytes */
 	if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0)
 	{
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
new file mode 100644
index 0000000..f950fc3
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -0,0 +1,1468 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-secure-openssl.c
+ *	  OpenSSL support
+ *
+ *
+ * Portions Copyright (c) 1996-2014, 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>
+#if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
+#include <openssl/conf.h>
+#endif
+#ifdef USE_SSL_ENGINE
+#include <openssl/engine.h>
+#endif
+
+static bool verify_peer_name_matches_certificate(PGconn *);
+static int	verify_cb(int ok, X509_STORE_CTX *ctx);
+static void destroy_ssl_system(void);
+static int	initialize_SSL(PGconn *conn);
+static PostgresPollingStatusType open_client_SSL(PGconn *);
+static char *SSLerrmessage(void);
+static void SSLerrfree(char *buf);
+
+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);
+static int my_SSL_set_fd(PGconn *conn, int fd);
+
+
+static bool pq_init_ssl_lib = true;
+static bool pq_init_crypto_lib = true;
+
+/*
+ * SSL_context is currently shared between threads and therefore we need to be
+ * careful to lock around any usage of it when providing thread safety.
+ * ssl_config_mutex is the mutex that we use to protect it.
+ */
+static SSL_CTX *SSL_context = NULL;
+
+#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)
+	{
+#ifdef ENABLE_THREAD_SAFETY
+		int			rc;
+#endif
+
+#ifdef ENABLE_THREAD_SAFETY
+		if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
+			return PGRES_POLLING_FAILED;
+		}
+#endif
+		/* Create a connection-specific SSL object */
+		if (!(conn->ssl = SSL_new(SSL_context)) ||
+			!SSL_set_app_data(conn->ssl, conn) ||
+			!my_SSL_set_fd(conn, conn->sock))
+		{
+			char	   *err = SSLerrmessage();
+
+			printfPQExpBuffer(&conn->errorMessage,
+				   libpq_gettext("could not establish SSL connection: %s\n"),
+							  err);
+			SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+			pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+			pgtls_close(conn);
+
+			return PGRES_POLLING_FAILED;
+		}
+		conn->ssl_in_use = true;
+
+#ifdef ENABLE_THREAD_SAFETY
+		pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+
+		/*
+		 * 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);
+}
+
+/*
+ *	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;
+
+rloop:
+	SOCK_ERRNO_SET(0);
+	n = SSL_read(conn->ssl, ptr, len);
+	err = SSL_get_error(conn->ssl, n);
+	switch (err)
+	{
+		case SSL_ERROR_NONE:
+			if (n < 0)
+			{
+				/* Not supposed to happen, so we don't translate the msg */
+				printfPQExpBuffer(&conn->errorMessage,
+								  "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"
+													"\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:
+			{
+				char	   *errm = SSLerrmessage();
+
+				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:
+
+			/*
+			 * 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,
+							  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;
+
+	SOCK_ERRNO_SET(0);
+	n = SSL_write(conn->ssl, ptr, len);
+	err = SSL_get_error(conn->ssl, n);
+	switch (err)
+	{
+		case SSL_ERROR_NONE:
+			if (n < 0)
+			{
+				/* Not supposed to happen, so we don't translate the msg */
+				printfPQExpBuffer(&conn->errorMessage,
+								  "SSL_write failed but did not provide error information\n");
+				/* assume the connection is broken */
+				result_errno = ECONNRESET;
+			}
+			break;
+		case SSL_ERROR_WANT_READ:
+
+			/*
+			 * 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"
+				   "\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:
+			{
+				char	   *errm = SSLerrmessage();
+
+				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:
+
+			/*
+			 * 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,
+							  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;
+}
+
+
+/*
+ *	Verify that common name resolves to peer.
+ */
+static bool
+verify_peer_name_matches_certificate(PGconn *conn)
+{
+	char	   *peer_cn;
+	int			r;
+	int			len;
+	bool		result;
+
+	/*
+	 * 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;
+
+	/*
+	 * Extract the common name from the certificate.
+	 *
+	 * XXX: Should support alternate names here
+	 */
+	/* First find out the name's length and allocate a buffer for it. */
+	len = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
+									NID_commonName, NULL, 0);
+	if (len == -1)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not get server common name from server certificate\n"));
+		return false;
+	}
+	peer_cn = malloc(len + 1);
+	if (peer_cn == NULL)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("out of memory\n"));
+		return false;
+	}
+
+	r = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
+								  NID_commonName, peer_cn, len + 1);
+	if (r != len)
+	{
+		/* Got different length than on the first call. Shouldn't happen. */
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not get server common name from server certificate\n"));
+		free(peer_cn);
+		return false;
+	}
+	peer_cn[len] = '\0';
+
+	/*
+	 * Reject embedded NULLs in certificate common name to prevent attacks
+	 * like CVE-2009-4034.
+	 */
+	if (len != strlen(peer_cn))
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("SSL certificate's common name contains embedded null\n"));
+		free(peer_cn);
+		return false;
+	}
+
+	/*
+	 * We got the peer's common name. Now compare it against the originally
+	 * given hostname.
+	 */
+	if (!(conn->pghost && conn->pghost[0] != '\0'))
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("host name must be specified for a verified SSL connection\n"));
+		result = false;
+	}
+	else
+	{
+		if (pg_strcasecmp(peer_cn, conn->pghost) == 0)
+			/* Exact name match */
+			result = true;
+		else if (wildcard_certificate_match(peer_cn, conn->pghost))
+			/* Matched wildcard certificate */
+			result = true;
+		else
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("server common name \"%s\" does not match host name \"%s\"\n"),
+							  peer_cn, conn->pghost);
+			result = false;
+		}
+	}
+
+	free(peer_cn);
+	return result;
+}
+
+#ifdef ENABLE_THREAD_SAFETY
+/*
+ *	Callback functions for OpenSSL internal locking
+ */
+
+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 */
+
+/*
+ * Initialize SSL system, in particular creating the SSL_context object
+ * that will be shared by all SSL-using connections in this process.
+ *
+ * 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;
+
+	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)
+		{
+			/* These are only required for threaded libcrypto applications */
+			CRYPTO_set_id_callback(pq_threadidcallback);
+			CRYPTO_set_locking_callback(pq_lockingcallback);
+		}
+	}
+#endif   /* ENABLE_THREAD_SAFETY */
+
+	if (!SSL_context)
+	{
+		if (pq_init_ssl_lib)
+		{
+#if SSLEAY_VERSION_NUMBER >= 0x00907000L
+			OPENSSL_config(NULL);
+#endif
+			SSL_library_init();
+			SSL_load_error_strings();
+		}
+
+		/*
+		 * We use SSLv23_method() because it can negotiate use of the highest
+		 * mutually supported protocol version, while alternatives like
+		 * TLSv1_2_method() permit only one specific version.  Note that we
+		 * don't actually allow SSL v2 or v3, only TLS protocols (see below).
+		 */
+		SSL_context = SSL_CTX_new(SSLv23_method());
+		if (!SSL_context)
+		{
+			char	   *err = SSLerrmessage();
+
+			printfPQExpBuffer(&conn->errorMessage,
+						 libpq_gettext("could not create SSL context: %s\n"),
+							  err);
+			SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+			pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+			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);
+	}
+
+#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
+ *	we only need to remove them in this case.
+ */
+static void
+destroy_ssl_system(void)
+{
+#ifdef ENABLE_THREAD_SAFETY
+	/* 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)
+	{
+		/* No connections left, unregister libcrypto callbacks */
+		CRYPTO_set_locking_callback(NULL);
+		CRYPTO_set_id_callback(NULL);
+
+		/*
+		 * We don't free the lock array or the SSL_context. 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
+}
+
+/*
+ *	Initialize (potentially) per-connection SSL data, namely the
+ *	client certificate, private key, and trusted CA certs.
+ *
+ *	conn->ssl must already be created.  It receives the connection's client
+ *	certificate and private key.  Note however that certificates also get
+ *	loaded into the SSL_context object, and are therefore accessible to all
+ *	connections in this process.  This should be OK as long as there aren't
+ *	any hash collisions among the certs.
+ *
+ *	Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
+ */
+static int
+initialize_SSL(PGconn *conn)
+{
+	struct stat buf;
+	char		homedir[MAXPGPATH];
+	char		fnbuf[MAXPGPATH];
+	char		sebuf[256];
+	bool		have_homedir;
+	bool		have_cert;
+	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;
+
+	/* Read the client certificate file */
+	if (conn->sslcert && strlen(conn->sslcert) > 0)
+		strncpy(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)));
+			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 actually have to
+		 * load the file twice.  The first call loads any extra certs after
+		 * the first one into chain-cert storage associated with the
+		 * SSL_context.  The second call loads the first cert (only) into the
+		 * SSL object, where it will be correctly paired with the private key
+		 * we load below.  We do it this way so that each connection
+		 * understands which subject cert to present, in case different
+		 * sslcert settings are used for different connections in the same
+		 * process.
+		 *
+		 * NOTE: This function may also modify our SSL_context and therefore
+		 * we have to lock around this call and any places where we use the
+		 * SSL_context struct.
+		 */
+#ifdef ENABLE_THREAD_SAFETY
+		int			rc;
+
+		if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
+			return -1;
+		}
+#endif
+		if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
+		{
+			char	   *err = SSLerrmessage();
+
+			printfPQExpBuffer(&conn->errorMessage,
+			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
+							  fnbuf, err);
+			SSLerrfree(err);
+
+#ifdef ENABLE_THREAD_SAFETY
+			pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+			return -1;
+		}
+
+		if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
+		{
+			char	   *err = SSLerrmessage();
+
+			printfPQExpBuffer(&conn->errorMessage,
+			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
+							  fnbuf, err);
+			SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+			pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+			return -1;
+		}
+
+		/* need to load the associated private key, too */
+		have_cert = true;
+
+#ifdef ENABLE_THREAD_SAFETY
+		pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+	}
+
+	/*
+	 * 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)
+			{
+				char	   *err = SSLerrmessage();
+
+				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)
+			{
+				char	   *err = SSLerrmessage();
+
+				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)
+			{
+				char	   *err = SSLerrmessage();
+
+				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)
+			{
+				char	   *err = SSLerrmessage();
+
+				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 */
+			strncpy(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)
+		{
+			char	   *err = SSLerrmessage();
+
+			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)
+	{
+		char	   *err = SSLerrmessage();
+
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
+						  fnbuf, err);
+		SSLerrfree(err);
+		return -1;
+	}
+
+	/*
+	 * 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)
+		strncpy(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;
+
+#ifdef ENABLE_THREAD_SAFETY
+		int			rc;
+
+		if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
+			return -1;
+		}
+#endif
+		if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
+		{
+			char	   *err = SSLerrmessage();
+
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("could not read root certificate file \"%s\": %s\n"),
+							  fnbuf, err);
+			SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+			pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+			return -1;
+		}
+
+		if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
+		{
+			if (conn->sslcrl && strlen(conn->sslcrl) > 0)
+				strncpy(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();
+
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
+								  fnbuf);
+				SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+				pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+				return -1;
+#endif
+			}
+			/* if not found, silently ignore;  we do not require CRL */
+		}
+#ifdef ENABLE_THREAD_SAFETY
+		pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+
+		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
+	}
+	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);
+			return -1;
+		}
+	}
+
+	/*
+	 * 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;
+
+	r = SSL_connect(conn->ssl);
+	if (r <= 0)
+	{
+		int			err = SSL_get_error(conn->ssl, r);
+
+		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:
+				{
+					char	   *err = SSLerrmessage();
+
+					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)
+	{
+		char	   *err = SSLerrmessage();
+
+		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();
+}
+
+
+/*
+ * Obtain reason string for last SSL error
+ *
+ * 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 *
+SSLerrmessage(void)
+{
+	unsigned long errcode;
+	const char *errreason;
+	char	   *errbuf;
+
+	errbuf = malloc(SSL_ERR_LEN);
+	if (!errbuf)
+		return ssl_nomem;
+	errcode = ERR_get_error();
+	if (errcode == 0)
+	{
+		snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported"));
+		return errbuf;
+	}
+	errreason = ERR_reason_error_string(errcode);
+	if (errreason != NULL)
+	{
+		strlcpy(errbuf, errreason, SSL_ERR_LEN);
+		return errbuf;
+	}
+	snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), errcode);
+	return errbuf;
+}
+
+static void
+SSLerrfree(char *buf)
+{
+	if (buf != ssl_nomem)
+		free(buf);
+}
+
+/*
+ *	Return pointer to OpenSSL object.
+ */
+void *
+PQgetssl(PGconn *conn)
+{
+	if (!conn)
+		return NULL;
+	return conn->ssl;
+}
+
+
+/*
+ * Private substitute BIO: this does the sending and receiving using send() and
+ * recv() instead. This is so that we can enable and disable interrupts
+ * just while calling recv(). We cannot have interrupts occurring while
+ * the bulk of openssl runs, because it uses malloc() and possibly other
+ * non-reentrant libc facilities. We also need to call send() and recv()
+ * directly so it gets passed through the socket/signals layer on Win32.
+ *
+ * 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?
+ */
+
+static bool my_bio_initialized = false;
+static BIO_METHOD my_bio_methods;
+
+static int
+my_sock_read(BIO *h, char *buf, int size)
+{
+	int			res;
+	int			save_errno;
+
+	res = pqsecure_raw_read((PGconn *) h->ptr, buf, size);
+	save_errno = errno;
+	BIO_clear_retry_flags(h);
+	if (res < 0)
+	{
+		switch (save_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;
+		}
+	}
+
+	errno = save_errno;
+	return res;
+}
+
+static int
+my_sock_write(BIO *h, const char *buf, int size)
+{
+	int			res;
+	int			save_errno;
+
+	res = pqsecure_raw_write((PGconn *) h->ptr, buf, size);
+	save_errno = errno;
+	BIO_clear_retry_flags(h);
+	if (res <= 0)
+	{
+		if (save_errno == EINTR)
+		{
+			BIO_set_retry_write(h);
+		}
+	}
+
+	return res;
+}
+
+static BIO_METHOD *
+my_BIO_s_socket(void)
+{
+	if (!my_bio_initialized)
+	{
+		memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD));
+		my_bio_methods.bread = my_sock_read;
+		my_bio_methods.bwrite = my_sock_write;
+		my_bio_initialized = true;
+	}
+	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;
+	BIO		   *bio = NULL;
+
+	bio = BIO_new(my_BIO_s_socket());
+	if (bio == NULL)
+	{
+		SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
+		goto err;
+	}
+	/* Use 'ptr' to store pointer to PGconn */
+	bio->ptr = conn;
+
+	SSL_set_bio(conn->ssl, bio, bio);
+	BIO_set_fd(bio, fd, BIO_NOCLOSE);
+	ret = 1;
+err:
+	return ret;
+}
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 9ba3567..66778b2 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -55,64 +55,6 @@
 #endif
 #endif
 
-#ifdef USE_SSL
-
-#include <openssl/ssl.h>
-#if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
-#include <openssl/conf.h>
-#endif
-#ifdef USE_SSL_ENGINE
-#include <openssl/engine.h>
-#endif
-
-
-#ifndef WIN32
-#define USER_CERT_FILE		".postgresql/postgresql.crt"
-#define USER_KEY_FILE		".postgresql/postgresql.key"
-#define ROOT_CERT_FILE		".postgresql/root.crt"
-#define ROOT_CRL_FILE		".postgresql/root.crl"
-#else
-/* On Windows, the "home" directory is already PostgreSQL-specific */
-#define USER_CERT_FILE		"postgresql.crt"
-#define USER_KEY_FILE		"postgresql.key"
-#define ROOT_CERT_FILE		"root.crt"
-#define ROOT_CRL_FILE		"root.crl"
-#endif
-
-static bool verify_peer_name_matches_certificate(PGconn *);
-static int	verify_cb(int ok, X509_STORE_CTX *ctx);
-static int	init_ssl_system(PGconn *conn);
-static void destroy_ssl_system(void);
-static int	initialize_SSL(PGconn *conn);
-static void destroySSL(void);
-static PostgresPollingStatusType open_client_SSL(PGconn *);
-static void close_SSL(PGconn *);
-static char *SSLerrmessage(void);
-static void SSLerrfree(char *buf);
-
-static bool pq_init_ssl_lib = true;
-static bool pq_init_crypto_lib = true;
-
-/*
- * SSL_context is currently shared between threads and therefore we need to be
- * careful to lock around any usage of it when providing thread safety.
- * ssl_config_mutex is the mutex that we use to protect it.
- */
-static SSL_CTX *SSL_context = NULL;
-
-#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 */
-#endif   /* SSL */
-
-
 /*
  * Macros to handle disabling and then restoring the state of SIGPIPE handling.
  * On Windows, these are all no-ops since there's no SIGPIPEs.
@@ -194,7 +136,9 @@ struct sigpipe_info
 void
 PQinitSSL(int do_init)
 {
-	PQinitOpenSSL(do_init, do_init);
+#ifdef USE_SSL
+	pgtls_init_library(do_init, do_init);
+#endif
 }
 
 /*
@@ -205,18 +149,7 @@ void
 PQinitOpenSSL(int do_ssl, int do_crypto)
 {
 #ifdef USE_SSL
-#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;
+	pgtls_init_library(do_ssl, do_crypto);
 #endif
 }
 
@@ -229,83 +162,20 @@ pqsecure_initialize(PGconn *conn)
 	int			r = 0;
 
 #ifdef USE_SSL
-	r = init_ssl_system(conn);
+	r = pgtls_init(conn);
 #endif
 
 	return r;
 }
 
 /*
- *	Destroy global context
- */
-void
-pqsecure_destroy(void)
-{
-#ifdef USE_SSL
-	destroySSL();
-#endif
-}
-
-/*
  *	Begin or continue negotiating a secure session.
  */
 PostgresPollingStatusType
 pqsecure_open_client(PGconn *conn)
 {
 #ifdef USE_SSL
-	/* First time through? */
-	if (conn->ssl == NULL)
-	{
-#ifdef ENABLE_THREAD_SAFETY
-		int			rc;
-#endif
-
-		/* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */
-		conn->sigpipe_flag = false;
-
-#ifdef ENABLE_THREAD_SAFETY
-		if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
-			return PGRES_POLLING_FAILED;
-		}
-#endif
-		/* Create a connection-specific SSL object */
-		if (!(conn->ssl = SSL_new(SSL_context)) ||
-			!SSL_set_app_data(conn->ssl, conn) ||
-			!SSL_set_fd(conn->ssl, conn->sock))
-		{
-			char	   *err = SSLerrmessage();
-
-			printfPQExpBuffer(&conn->errorMessage,
-				   libpq_gettext("could not establish SSL connection: %s\n"),
-							  err);
-			SSLerrfree(err);
-#ifdef ENABLE_THREAD_SAFETY
-			pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-			close_SSL(conn);
-
-			return PGRES_POLLING_FAILED;
-		}
-#ifdef ENABLE_THREAD_SAFETY
-		pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-
-		/*
-		 * Load client certificate, private key, and trusted CA certs.
-		 */
-		if (initialize_SSL(conn) != 0)
-		{
-			/* initialize_SSL already put a message in conn->errorMessage */
-			close_SSL(conn);
-			return PGRES_POLLING_FAILED;
-		}
-	}
-
-	/* Begin or continue the actual handshake */
-	return open_client_SSL(conn);
+	return pgtls_open_client(conn);
 #else
 	/* shouldn't get here */
 	return PGRES_POLLING_FAILED;
@@ -319,8 +189,8 @@ void
 pqsecure_close(PGconn *conn)
 {
 #ifdef USE_SSL
-	if (conn->ssl)
-		close_SSL(conn);
+	if (conn->ssl_in_use)
+		pgtls_close(conn);
 #endif
 }
 
@@ -335,149 +205,63 @@ ssize_t
 pqsecure_read(PGconn *conn, void *ptr, size_t len)
 {
 	ssize_t		n;
-	int			result_errno = 0;
-	char		sebuf[256];
 
 #ifdef USE_SSL
-	if (conn->ssl)
+	if (conn->ssl_in_use)
+	{
+		n = pgtls_read(conn, ptr, len);
+	}
+	else
+#endif
 	{
-		int			err;
+		n = pqsecure_raw_read(conn, ptr, len);
+	}
 
-		DECLARE_SIGPIPE_INFO(spinfo);
+	return n;
+}
 
-		/* SSL_read can write to the socket, so we need to disable SIGPIPE */
-		DISABLE_SIGPIPE(conn, spinfo, return -1);
+ssize_t
+pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
+{
+	ssize_t		n;
+	int			result_errno = 0;
+	char		sebuf[256];
 
-rloop:
-		SOCK_ERRNO_SET(0);
-		n = SSL_read(conn->ssl, ptr, len);
-		err = SSL_get_error(conn->ssl, n);
-		switch (err)
-		{
-			case SSL_ERROR_NONE:
-				if (n < 0)
-				{
-					/* Not supposed to happen, so we don't translate the msg */
-					printfPQExpBuffer(&conn->errorMessage,
-									  "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;
-					REMEMBER_EPIPE(spinfo, result_errno == EPIPE);
-					if (result_errno == EPIPE ||
-						result_errno == ECONNRESET)
-						printfPQExpBuffer(&conn->errorMessage,
-										  libpq_gettext(
-								"server closed the connection unexpectedly\n"
-														"\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:
-				{
-					char	   *errm = SSLerrmessage();
-
-					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:
-
-				/*
-				 * 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,
-								  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;
-		}
+	n = recv(conn->sock, ptr, len, 0);
 
-		RESTORE_SIGPIPE(conn, spinfo);
-	}
-	else
-#endif   /* USE_SSL */
+	if (n < 0)
 	{
-		n = recv(conn->sock, ptr, len, 0);
+		result_errno = SOCK_ERRNO;
 
-		if (n < 0)
+		/* Set error message if appropriate */
+		switch (result_errno)
 		{
-			result_errno = SOCK_ERRNO;
-
-			/* Set error message if appropriate */
-			switch (result_errno)
-			{
 #ifdef EAGAIN
-				case EAGAIN:
+			case EAGAIN:
 #endif
 #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
-				case EWOULDBLOCK:
+			case EWOULDBLOCK:
 #endif
-				case EINTR:
-					/* no error message, caller is expected to retry */
-					break;
+			case EINTR:
+				/* no error message, caller is expected to retry */
+				break;
 
 #ifdef ECONNRESET
-				case ECONNRESET:
-					printfPQExpBuffer(&conn->errorMessage,
-									  libpq_gettext(
+			case ECONNRESET:
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext(
 								"server closed the connection unexpectedly\n"
 					"\tThis probably means the server terminated abnormally\n"
 							 "\tbefore or while processing the request.\n"));
-					break;
+				break;
 #endif
 
-				default:
-					printfPQExpBuffer(&conn->errorMessage,
+			default:
+				printfPQExpBuffer(&conn->errorMessage,
 					libpq_gettext("could not receive data from server: %s\n"),
-									  SOCK_STRERROR(result_errno,
-													sebuf, sizeof(sebuf)));
-					break;
-			}
+								  SOCK_STRERROR(result_errno,
+												sebuf, sizeof(sebuf)));
+				break;
 		}
 	}
 
@@ -498,175 +282,94 @@ ssize_t
 pqsecure_write(PGconn *conn, const void *ptr, size_t len)
 {
 	ssize_t		n;
-	int			result_errno = 0;
-	char		sebuf[256];
-
-	DECLARE_SIGPIPE_INFO(spinfo);
 
 #ifdef USE_SSL
-	if (conn->ssl)
+	if (conn->ssl_in_use)
 	{
-		int			err;
-
-		DISABLE_SIGPIPE(conn, spinfo, return -1);
-
-		SOCK_ERRNO_SET(0);
-		n = SSL_write(conn->ssl, ptr, len);
-		err = SSL_get_error(conn->ssl, n);
-		switch (err)
-		{
-			case SSL_ERROR_NONE:
-				if (n < 0)
-				{
-					/* Not supposed to happen, so we don't translate the msg */
-					printfPQExpBuffer(&conn->errorMessage,
-									  "SSL_write failed but did not provide error information\n");
-					/* assume the connection is broken */
-					result_errno = ECONNRESET;
-				}
-				break;
-			case SSL_ERROR_WANT_READ:
-
-				/*
-				 * 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;
-					REMEMBER_EPIPE(spinfo, result_errno == EPIPE);
-					if (result_errno == EPIPE ||
-						result_errno == ECONNRESET)
-						printfPQExpBuffer(&conn->errorMessage,
-										  libpq_gettext(
-								"server closed the connection unexpectedly\n"
-														"\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:
-				{
-					char	   *errm = SSLerrmessage();
-
-					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:
-
-				/*
-				 * 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,
-								  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;
-		}
+		n = pgtls_write(conn, ptr, len);
 	}
 	else
-#endif   /* USE_SSL */
+#endif
 	{
-		int			flags = 0;
+		n = pqsecure_raw_write(conn, ptr, len);
+	}
+
+	return n;
+}
+
+ssize_t
+pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len)
+{
+	ssize_t		n;
+	int			flags = 0;
+	int			result_errno = 0;
+	char		sebuf[256];
+
+	DECLARE_SIGPIPE_INFO(spinfo);
 
 #ifdef MSG_NOSIGNAL
-		if (conn->sigpipe_flag)
-			flags |= MSG_NOSIGNAL;
+	if (conn->sigpipe_flag)
+		flags |= MSG_NOSIGNAL;
 
 retry_masked:
 #endif   /* MSG_NOSIGNAL */
 
-		DISABLE_SIGPIPE(conn, spinfo, return -1);
+	DISABLE_SIGPIPE(conn, spinfo, return -1);
 
-		n = send(conn->sock, ptr, len, flags);
+	n = send(conn->sock, ptr, len, flags);
 
-		if (n < 0)
-		{
-			result_errno = SOCK_ERRNO;
+	if (n < 0)
+	{
+		result_errno = SOCK_ERRNO;
 
-			/*
-			 * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't
-			 * available on this machine.  So, clear sigpipe_flag so we don't
-			 * try the flag again, and retry the send().
-			 */
+		/*
+		 * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't
+		 * available on this machine.  So, clear sigpipe_flag so we don't
+		 * try the flag again, and retry the send().
+		 */
 #ifdef MSG_NOSIGNAL
-			if (flags != 0 && result_errno == EINVAL)
-			{
-				conn->sigpipe_flag = false;
-				flags = 0;
-				goto retry_masked;
-			}
+		if (flags != 0 && result_errno == EINVAL)
+		{
+			conn->sigpipe_flag = false;
+			flags = 0;
+			goto retry_masked;
+		}
 #endif   /* MSG_NOSIGNAL */
 
-			/* Set error message if appropriate */
-			switch (result_errno)
-			{
+		/* Set error message if appropriate */
+		switch (result_errno)
+		{
 #ifdef EAGAIN
-				case EAGAIN:
+			case EAGAIN:
 #endif
 #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
-				case EWOULDBLOCK:
+			case EWOULDBLOCK:
 #endif
-				case EINTR:
-					/* no error message, caller is expected to retry */
-					break;
+			case EINTR:
+				/* no error message, caller is expected to retry */
+				break;
 
-				case EPIPE:
-					/* Set flag for EPIPE */
-					REMEMBER_EPIPE(spinfo, true);
-					/* FALL THRU */
+			case EPIPE:
+				/* Set flag for EPIPE */
+				REMEMBER_EPIPE(spinfo, true);
+				/* FALL THRU */
 
 #ifdef ECONNRESET
-				case ECONNRESET:
+			case ECONNRESET:
 #endif
-					printfPQExpBuffer(&conn->errorMessage,
-									  libpq_gettext(
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext(
 								"server closed the connection unexpectedly\n"
 					"\tThis probably means the server terminated abnormally\n"
 							 "\tbefore or while processing the request.\n"));
-					break;
+				break;
 
-				default:
-					printfPQExpBuffer(&conn->errorMessage,
+			default:
+				printfPQExpBuffer(&conn->errorMessage,
 						libpq_gettext("could not send data to server: %s\n"),
 									  SOCK_STRERROR(result_errno,
 													sebuf, sizeof(sebuf)));
-					break;
-			}
+				break;
 		}
 	}
 
@@ -678,981 +381,7 @@ retry_masked:
 	return n;
 }
 
-/* ------------------------------------------------------------ */
-/*						  SSL specific code						*/
-/* ------------------------------------------------------------ */
-#ifdef USE_SSL
-
-/*
- *	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;
-}
-
-
-/*
- *	Verify that common name resolves to peer.
- */
-static bool
-verify_peer_name_matches_certificate(PGconn *conn)
-{
-	char	   *peer_cn;
-	int			r;
-	int			len;
-	bool		result;
-
-	/*
-	 * 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;
-
-	/*
-	 * Extract the common name from the certificate.
-	 *
-	 * XXX: Should support alternate names here
-	 */
-	/* First find out the name's length and allocate a buffer for it. */
-	len = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
-									NID_commonName, NULL, 0);
-	if (len == -1)
-	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("could not get server common name from server certificate\n"));
-		return false;
-	}
-	peer_cn = malloc(len + 1);
-	if (peer_cn == NULL)
-	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("out of memory\n"));
-		return false;
-	}
-
-	r = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
-								  NID_commonName, peer_cn, len + 1);
-	if (r != len)
-	{
-		/* Got different length than on the first call. Shouldn't happen. */
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("could not get server common name from server certificate\n"));
-		free(peer_cn);
-		return false;
-	}
-	peer_cn[len] = '\0';
-
-	/*
-	 * Reject embedded NULLs in certificate common name to prevent attacks
-	 * like CVE-2009-4034.
-	 */
-	if (len != strlen(peer_cn))
-	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("SSL certificate's common name contains embedded null\n"));
-		free(peer_cn);
-		return false;
-	}
-
-	/*
-	 * We got the peer's common name. Now compare it against the originally
-	 * given hostname.
-	 */
-	if (!(conn->pghost && conn->pghost[0] != '\0'))
-	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("host name must be specified for a verified SSL connection\n"));
-		result = false;
-	}
-	else
-	{
-		if (pg_strcasecmp(peer_cn, conn->pghost) == 0)
-			/* Exact name match */
-			result = true;
-		else if (wildcard_certificate_match(peer_cn, conn->pghost))
-			/* Matched wildcard certificate */
-			result = true;
-		else
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-							  libpq_gettext("server common name \"%s\" does not match host name \"%s\"\n"),
-							  peer_cn, conn->pghost);
-			result = false;
-		}
-	}
-
-	free(peer_cn);
-	return result;
-}
-
-#ifdef ENABLE_THREAD_SAFETY
-/*
- *	Callback functions for OpenSSL internal locking
- */
-
-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 */
-
-/*
- * Initialize SSL system, in particular creating the SSL_context object
- * that will be shared by all SSL-using connections in this process.
- *
- * 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).
- */
-static int
-init_ssl_system(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;
-
-	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)
-		{
-			/* These are only required for threaded libcrypto applications */
-			CRYPTO_set_id_callback(pq_threadidcallback);
-			CRYPTO_set_locking_callback(pq_lockingcallback);
-		}
-	}
-#endif   /* ENABLE_THREAD_SAFETY */
-
-	if (!SSL_context)
-	{
-		if (pq_init_ssl_lib)
-		{
-#if SSLEAY_VERSION_NUMBER >= 0x00907000L
-			OPENSSL_config(NULL);
-#endif
-			SSL_library_init();
-			SSL_load_error_strings();
-		}
-
-		/*
-		 * We use SSLv23_method() because it can negotiate use of the highest
-		 * mutually supported protocol version, while alternatives like
-		 * TLSv1_2_method() permit only one specific version.  Note that we
-		 * don't actually allow SSL v2 or v3, only TLS protocols (see below).
-		 */
-		SSL_context = SSL_CTX_new(SSLv23_method());
-		if (!SSL_context)
-		{
-			char	   *err = SSLerrmessage();
-
-			printfPQExpBuffer(&conn->errorMessage,
-						 libpq_gettext("could not create SSL context: %s\n"),
-							  err);
-			SSLerrfree(err);
-#ifdef ENABLE_THREAD_SAFETY
-			pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-			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);
-	}
-
-#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
- *	we only need to remove them in this case.
- */
-static void
-destroy_ssl_system(void)
-{
-#ifdef ENABLE_THREAD_SAFETY
-	/* 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)
-	{
-		/* No connections left, unregister libcrypto callbacks */
-		CRYPTO_set_locking_callback(NULL);
-		CRYPTO_set_id_callback(NULL);
-
-		/*
-		 * We don't free the lock array or the SSL_context. 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
-}
-
-/*
- *	Initialize (potentially) per-connection SSL data, namely the
- *	client certificate, private key, and trusted CA certs.
- *
- *	conn->ssl must already be created.  It receives the connection's client
- *	certificate and private key.  Note however that certificates also get
- *	loaded into the SSL_context object, and are therefore accessible to all
- *	connections in this process.  This should be OK as long as there aren't
- *	any hash collisions among the certs.
- *
- *	Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
- */
-static int
-initialize_SSL(PGconn *conn)
-{
-	struct stat buf;
-	char		homedir[MAXPGPATH];
-	char		fnbuf[MAXPGPATH];
-	char		sebuf[256];
-	bool		have_homedir;
-	bool		have_cert;
-	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;
-
-	/* Read the client certificate file */
-	if (conn->sslcert && strlen(conn->sslcert) > 0)
-		strncpy(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)));
-			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 actually have to
-		 * load the file twice.  The first call loads any extra certs after
-		 * the first one into chain-cert storage associated with the
-		 * SSL_context.  The second call loads the first cert (only) into the
-		 * SSL object, where it will be correctly paired with the private key
-		 * we load below.  We do it this way so that each connection
-		 * understands which subject cert to present, in case different
-		 * sslcert settings are used for different connections in the same
-		 * process.
-		 *
-		 * NOTE: This function may also modify our SSL_context and therefore
-		 * we have to lock around this call and any places where we use the
-		 * SSL_context struct.
-		 */
-#ifdef ENABLE_THREAD_SAFETY
-		int			rc;
-
-		if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
-			return -1;
-		}
-#endif
-		if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
-		{
-			char	   *err = SSLerrmessage();
-
-			printfPQExpBuffer(&conn->errorMessage,
-			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
-							  fnbuf, err);
-			SSLerrfree(err);
-
-#ifdef ENABLE_THREAD_SAFETY
-			pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-			return -1;
-		}
-
-		if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
-		{
-			char	   *err = SSLerrmessage();
-
-			printfPQExpBuffer(&conn->errorMessage,
-			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
-							  fnbuf, err);
-			SSLerrfree(err);
-#ifdef ENABLE_THREAD_SAFETY
-			pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-			return -1;
-		}
-
-		/* need to load the associated private key, too */
-		have_cert = true;
-
-#ifdef ENABLE_THREAD_SAFETY
-		pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-	}
-
-	/*
-	 * 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)
-			{
-				char	   *err = SSLerrmessage();
-
-				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)
-			{
-				char	   *err = SSLerrmessage();
-
-				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)
-			{
-				char	   *err = SSLerrmessage();
-
-				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)
-			{
-				char	   *err = SSLerrmessage();
-
-				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 */
-			strncpy(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)
-		{
-			char	   *err = SSLerrmessage();
-
-			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)
-	{
-		char	   *err = SSLerrmessage();
-
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
-						  fnbuf, err);
-		SSLerrfree(err);
-		return -1;
-	}
-
-	/*
-	 * 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)
-		strncpy(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;
-
-#ifdef ENABLE_THREAD_SAFETY
-		int			rc;
-
-		if ((rc = pthread_mutex_lock(&ssl_config_mutex)))
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
-			return -1;
-		}
-#endif
-		if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
-		{
-			char	   *err = SSLerrmessage();
-
-			printfPQExpBuffer(&conn->errorMessage,
-							  libpq_gettext("could not read root certificate file \"%s\": %s\n"),
-							  fnbuf, err);
-			SSLerrfree(err);
-#ifdef ENABLE_THREAD_SAFETY
-			pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-			return -1;
-		}
-
-		if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
-		{
-			if (conn->sslcrl && strlen(conn->sslcrl) > 0)
-				strncpy(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();
-
-				printfPQExpBuffer(&conn->errorMessage,
-								  libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
-								  fnbuf);
-				SSLerrfree(err);
-#ifdef ENABLE_THREAD_SAFETY
-				pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-				return -1;
-#endif
-			}
-			/* if not found, silently ignore;  we do not require CRL */
-		}
-#ifdef ENABLE_THREAD_SAFETY
-		pthread_mutex_unlock(&ssl_config_mutex);
-#endif
-
-		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
-	}
-	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);
-			return -1;
-		}
-	}
-
-	/*
-	 * 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;
-}
-
-static void
-destroySSL(void)
-{
-	destroy_ssl_system();
-}
-
-/*
- *	Attempt to negotiate SSL connection.
- */
-static PostgresPollingStatusType
-open_client_SSL(PGconn *conn)
-{
-	int			r;
-
-	r = SSL_connect(conn->ssl);
-	if (r <= 0)
-	{
-		int			err = SSL_get_error(conn->ssl, r);
-
-		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"));
-					close_SSL(conn);
-					return PGRES_POLLING_FAILED;
-				}
-			case SSL_ERROR_SSL:
-				{
-					char	   *err = SSLerrmessage();
-
-					printfPQExpBuffer(&conn->errorMessage,
-									  libpq_gettext("SSL error: %s\n"),
-									  err);
-					SSLerrfree(err);
-					close_SSL(conn);
-					return PGRES_POLLING_FAILED;
-				}
-
-			default:
-				printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("unrecognized SSL error code: %d\n"),
-								  err);
-				close_SSL(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)
-	{
-		char	   *err = SSLerrmessage();
-
-		printfPQExpBuffer(&conn->errorMessage,
-					libpq_gettext("certificate could not be obtained: %s\n"),
-						  err);
-		SSLerrfree(err);
-		close_SSL(conn);
-		return PGRES_POLLING_FAILED;
-	}
-
-	if (!verify_peer_name_matches_certificate(conn))
-	{
-		close_SSL(conn);
-		return PGRES_POLLING_FAILED;
-	}
-
-	/* SSL handshake is complete */
-	return PGRES_POLLING_OK;
-}
-
-/*
- *	Close SSL connection.
- */
-static void
-close_SSL(PGconn *conn)
-{
-	bool		destroy_needed = false;
-
-	if (conn->ssl)
-	{
-		DECLARE_SIGPIPE_INFO(spinfo);
-
-		/*
-		 * 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;
-
-		DISABLE_SIGPIPE(conn, spinfo, (void) 0);
-		SSL_shutdown(conn->ssl);
-		SSL_free(conn->ssl);
-		conn->ssl = NULL;
-		/* We have to assume we got EPIPE */
-		REMEMBER_EPIPE(spinfo, true);
-		RESTORE_SIGPIPE(conn, spinfo);
-	}
-
-	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)
-		pqsecure_destroy();
-}
-
-/*
- * Obtain reason string for last SSL error
- *
- * 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 *
-SSLerrmessage(void)
-{
-	unsigned long errcode;
-	const char *errreason;
-	char	   *errbuf;
-
-	errbuf = malloc(SSL_ERR_LEN);
-	if (!errbuf)
-		return ssl_nomem;
-	errcode = ERR_get_error();
-	if (errcode == 0)
-	{
-		snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported"));
-		return errbuf;
-	}
-	errreason = ERR_reason_error_string(errcode);
-	if (errreason != NULL)
-	{
-		strlcpy(errbuf, errreason, SSL_ERR_LEN);
-		return errbuf;
-	}
-	snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), errcode);
-	return errbuf;
-}
-
-static void
-SSLerrfree(char *buf)
-{
-	if (buf != ssl_nomem)
-		free(buf);
-}
-
-/*
- *	Return pointer to OpenSSL object.
- */
-void *
-PQgetssl(PGconn *conn)
-{
-	if (!conn)
-		return NULL;
-	return conn->ssl;
-}
-#else							/* !USE_SSL */
-
+#ifndef USE_SSL
 void *
 PQgetssl(PGconn *conn)
 {
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 4aeb4fa..6032904 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -73,14 +73,14 @@ typedef struct
 #endif
 #endif   /* ENABLE_SSPI */
 
-#ifdef USE_SSL
+#ifdef USE_OPENSSL
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 
 #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
 #define USE_SSL_ENGINE
 #endif
-#endif   /* USE_SSL */
+#endif   /* USE_OPENSSL */
 
 /*
  * POSTGRES backend dependent Constants.
@@ -427,6 +427,8 @@ struct pg_conn
 	bool		allow_ssl_try;	/* Allowed to try SSL negotiation */
 	bool		wait_ssl_try;	/* Delay SSL negotiation until after
 								 * attempting normal connection */
+	bool		ssl_in_use;
+#ifdef USE_OPENSSL
 	SSL		   *ssl;			/* SSL status, if have SSL connection */
 	X509	   *peer;			/* X509 cert of server */
 #ifdef USE_SSL_ENGINE
@@ -435,6 +437,7 @@ struct pg_conn
 	void	   *engine;			/* dummy field to keep struct the same if
 								 * OpenSSL version changes */
 #endif
+#endif   /* USE_OPENSSL */
 #endif   /* USE_SSL */
 
 #ifdef ENABLE_GSS
@@ -482,6 +485,24 @@ struct pg_cancel
  */
 extern char *const pgresStatus[];
 
+
+#ifdef USE_SSL
+
+#ifndef WIN32
+#define USER_CERT_FILE		".postgresql/postgresql.crt"
+#define USER_KEY_FILE		".postgresql/postgresql.key"
+#define ROOT_CERT_FILE		".postgresql/root.crt"
+#define ROOT_CRL_FILE		".postgresql/root.crl"
+#else
+/* On Windows, the "home" directory is already PostgreSQL-specific */
+#define USER_CERT_FILE		"postgresql.crt"
+#define USER_KEY_FILE		"postgresql.key"
+#define ROOT_CERT_FILE		"root.crt"
+#define ROOT_CRL_FILE		"root.crl"
+#endif
+
+#endif   /* USE_SSL */
+
 /* ----------------
  * Internal functions of libpq
  * Functions declared here need to be visible across files of libpq,
@@ -603,6 +624,8 @@ extern PostgresPollingStatusType pqsecure_open_client(PGconn *);
 extern void pqsecure_close(PGconn *);
 extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
 extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
+extern ssize_t pqsecure_raw_read(PGconn *, void *ptr, size_t len);
+extern ssize_t pqsecure_raw_write(PGconn *, const void *ptr, size_t len);
 
 #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
 extern int	pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending);
@@ -611,6 +634,16 @@ extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending,
 #endif
 
 /*
+ * The SSL implementatation provides these functions (fe-secure-openssl.c)
+ */
+extern void pgtls_init_library(bool do_ssl, int do_crypto);
+extern int pgtls_init(PGconn *conn);
+extern PostgresPollingStatusType pgtls_open_client(PGconn *conn);
+extern void pgtls_close(PGconn *conn);
+extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len);
+extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len);
+
+/*
  * this is so that we can check if a connection is non-blocking internally
  * without the overhead of a function call
  */
diff --git a/src/interfaces/libpq/win32.mak b/src/interfaces/libpq/win32.mak
index 99fef27..39a0bc9 100644
--- a/src/interfaces/libpq/win32.mak
+++ b/src/interfaces/libpq/win32.mak
@@ -2,7 +2,7 @@
 
 # Will build a static library libpq(d).lib
 #        and a dynamic library libpq(d).dll with import library libpq(d)dll.lib
-# USE_SSL=1 will compile with OpenSSL
+# USE_OPENSSL=1 will compile with OpenSSL
 # USE_KFW=1 will compile with kfw(kerberos for Windows)
 # DEBUG=1 compiles with debugging symbols
 # ENABLE_THREAD_SAFETY=1 compiles with threading enabled
@@ -124,6 +124,9 @@ CLEAN :
 	-@erase "$(OUTDIR)\$(OUTFILENAME).dll.manifest"
 	-@erase "$(OUTDIR)\*.idb"
 	-@erase pg_config_paths.h"
+!IFDEF USE_OPENSSL
+	-@erase "$(INTDIR)\fe-secure-openssl.obj"
+!ENDIF
 
 
 LIB32=link.exe -lib
@@ -164,6 +167,9 @@ LIB32_OBJS= \
 	"$(INTDIR)\win32error.obj" \
 	"$(INTDIR)\win32setlocale.obj" \
 	"$(INTDIR)\pthread-win32.obj"
+!IFDEF USE_OPENSSL
+	LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-openssl.obj"
+!ENDIF
 
 
 config: ..\..\include\pg_config.h ..\..\include\pg_config_ext.h pg_config_paths.h  ..\..\include\pg_config_os.h
@@ -189,8 +195,8 @@ CPP_PROJ=/nologo /W3 /EHsc $(OPT) /I "..\..\include" /I "..\..\include\port\win3
  /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c  \
  /D "_CRT_SECURE_NO_DEPRECATE" $(ADD_DEFINES)
 
-!IFDEF USE_SSL
-CPP_PROJ=$(CPP_PROJ) /D USE_SSL
+!IFDEF USE_OPENSSL
+CPP_PROJ=$(CPP_PROJ) /D USE_OPENSSL
 SSL_LIBS=ssleay32.lib libeay32.lib gdi32.lib
 !ENDIF
 
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index b71da67..5d809ac 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -117,6 +117,12 @@ sub mkvcbuild
 	$postgres->AddLibrary('ws2_32.lib');
 	$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
 	$postgres->FullExportDLL('postgres.lib');
+	# The OBJS scraper doesn't know about ifdefs, so remove fe-secure-openssl.c
+	# if building without OpenSSL
+	if (!$solution->{options}->{openssl})
+	{
+		$postgres->RemoveFile('src\backend\libpq\be-secure-openssl.c');
+	}
 
 	my $snowball = $solution->AddProject('dict_snowball', 'dll', '',
 		'src\backend\snowball');
@@ -276,6 +282,12 @@ sub mkvcbuild
 	$libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c',
 		'src\interfaces\libpq\libpq.rc');
 	$libpq->AddReference($libpgport);
+	# The OBJS scraper doesn't know about ifdefs, so remove fe-secure-openssl.c
+	# if building without OpenSSL
+	if (!$solution->{options}->{openssl})
+	{
+		$libpq->RemoveFile('src\interfaces\libpq\fe-secure-openssl.c');
+	}
 
 	my $libpqwalreceiver =
 	  $solution->AddProject('libpqwalreceiver', 'dll', '',
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index e49c3f4..39e41f6 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -182,7 +182,7 @@ sub GenerateFiles
 		  if ($self->{options}->{integer_datetimes});
 		print O "#define USE_LDAP 1\n"   if ($self->{options}->{ldap});
 		print O "#define HAVE_LIBZ 1\n"  if ($self->{options}->{zlib});
-		print O "#define USE_SSL 1\n"    if ($self->{options}->{openssl});
+		print O "#define USE_OPENSSL 1\n" if ($self->{options}->{openssl});
 		print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls});
 
 		print O "#define BLCKSZ ", 1024 * $self->{options}->{blocksize}, "\n";
@@ -628,7 +628,7 @@ sub GetFakeConfigure
 	$cfg .= ' --with-ldap'  if ($self->{options}->{ldap});
 	$cfg .= ' --without-zlib' unless ($self->{options}->{zlib});
 	$cfg .= ' --with-extra-version' if ($self->{options}->{extraver});
-	$cfg .= ' --with-openssl'       if ($self->{options}->{ssl});
+	$cfg .= ' --with-openssl'       if ($self->{options}->{openssl});
 	$cfg .= ' --with-ossp-uuid'     if ($self->{options}->{uuid});
 	$cfg .= ' --with-libxml'        if ($self->{options}->{xml});
 	$cfg .= ' --with-libxslt'       if ($self->{options}->{xslt});
diff --git a/src/tools/msvc/config_default.pl b/src/tools/msvc/config_default.pl
index 20aee8b..e4d4810 100644
--- a/src/tools/msvc/config_default.pl
+++ b/src/tools/msvc/config_default.pl
@@ -16,7 +16,7 @@ our $config = {
 	tcl      => undef,   # --with-tls=<path>
 	perl     => undef,   # --with-perl
 	python   => undef,   # --with-python=<path>
-	openssl  => undef,   # --with-ssl=<path>
+	openssl  => undef,   # --with-openssl=<path>
 	uuid     => undef,   # --with-ossp-uuid
 	xml      => undef,   # --with-libxml=<path>
 	xslt     => undef,   # --with-libxslt=<path>
-- 
2.0.1

