diff --git a/configure b/configure
index 0f435b5..d00290a 100755
--- a/configure
+++ b/configure
@@ -707,6 +707,7 @@ XML2_CONFIG
 UUID_EXTRA_OBJS
 with_uuid
 with_selinux
+with_winschannel
 with_openssl
 krb_srvtab
 with_python
@@ -823,6 +824,7 @@ with_pam
 with_ldap
 with_bonjour
 with_openssl
+with_winschannel
 with_selinux
 with_readline
 with_libedit_preferred
@@ -1509,6 +1511,7 @@ Optional Packages:
   --with-ldap             build with LDAP support
   --with-bonjour          build with Bonjour support
   --with-openssl          build with OpenSSL support
+  --with-winschannel      build with Windows SChannel support
   --with-selinux          build with SELinux support
   --without-readline      do not use GNU Readline nor BSD Libedit for editing
   --with-libedit-preferred
@@ -5514,6 +5517,46 @@ $as_echo "$with_openssl" >&6; }
 
 
 #
+# Windows SChannel
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with native Windows SSL support" >&5
+$as_echo_n "checking whether to build with native Windows SSL support... " >&6; }
+
+
+
+# Check whether --with-winschannel was given.
+if test "${with_winschannel+set}" = set; then :
+  withval=$with_winschannel;
+  case $withval in
+    yes)
+
+$as_echo "#define USE_WINDOWS_SCHANNEL 1" >>confdefs.h
+
+      ;;
+    no)
+      :
+      ;;
+    *)
+      as_fn_error $? "no argument expected for --with-winschannel option" "$LINENO" 5
+      ;;
+  esac
+
+else
+  with_winschannel=no
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_winschannel" >&5
+$as_echo "$with_winschannel" >&6; }
+
+
+if test "$with_openssl" = yes -a "$with_winschannel" = yes ; then
+  as_fn_error $? "
+*** Cannot select both OpenSSL and Windows SChannel." "$LINENO" 5
+fi
+
+#
 # SELinux
 #
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with SELinux support" >&5
diff --git a/configure.in b/configure.in
index f8a4507..132fb0a 100644
--- a/configure.in
+++ b/configure.in
@@ -662,6 +662,20 @@ AC_MSG_RESULT([$with_openssl])
 AC_SUBST(with_openssl)
 
 #
+# Windows SChannel
+#
+AC_MSG_CHECKING([whether to build with native Windows SSL support])
+PGAC_ARG_BOOL(with, winschannel, no, [build with Windows SChannel support],
+              [AC_DEFINE([USE_WINDOWS_SCHANNEL], 1, [Define to build with Windows SChannel support. (--with-winschannel)])])
+AC_MSG_RESULT([$with_winschannel])
+AC_SUBST(with_winschannel)
+
+if test "$with_openssl" = yes -a "$with_winschannel" = yes ; then
+  AC_MSG_ERROR([
+*** Cannot select both OpenSSL and Windows SChannel.])
+fi
+
+#
 # SELinux
 #
 AC_MSG_CHECKING([whether to build with SELinux support])
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 8be0572..88d0b8b 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -21,4 +21,8 @@ ifeq ($(with_openssl),yes)
 OBJS += be-secure-openssl.o
 endif
 
+ifeq ($(with_winschannel),yes)
+OBJS += be-secure-winschannel.o
+endif
+
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index e3a284b..651162e 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -922,10 +922,6 @@ aloop:
 		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);
 
diff --git a/src/backend/libpq/be-secure-winschannel.c b/src/backend/libpq/be-secure-winschannel.c
new file mode 100644
index 0000000..306f265
--- /dev/null
+++ b/src/backend/libpq/be-secure-winschannel.c
@@ -0,0 +1,1098 @@
+/*-------------------------------------------------------------------------
+ *
+ * be-secure-winschannel.c
+ *	  SSL support using Windows SChannel APIs
+ *
+ *
+ * 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-winschannel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "libpq/libpq-be.h"
+#include "libpq/libpq.h"
+#include "miscadmin.h"
+#include "storage/fd.h"
+
+#include <sspi.h>
+#include <schnlsp.h>
+
+#include <wincrypt.h>
+
+/*
+ * Name of the Crypto API key container to use for storing the server
+ * certificate and private key. 
+ */
+#define PG_KEY_CONTAINER_NAME L"PostgreSQL server key container"
+
+#define SCHANNEL_DEBUG LOG
+
+struct SchannelContext
+{
+	/* SChannel handle for the connection */
+	CtxtHandle  ctxHandle;
+	bool		ctxHandle_valid;
+	CredHandle	credHandle;
+	bool		credHandle_valid;
+
+	bool		remote_shutdown;
+
+	/*
+	 * Buffer for encrypting data to be written.
+	 *
+	 * When encryptedLen > 0, the buffer contains some encrypted data that
+	 * should be written out to the client.
+	 *
+	 * When encryptedLen == 0, call encryptBuffer() to load the buffer with
+	 * more data, and encrypt it.
+	 */
+	char	   *encryptBuffer;
+	int			encryptBufferSize;
+	int			encryptBufferLen;
+
+	char	   *encryptedData;
+	size_t		encryptedLen;
+
+	/*
+	 * Number of plaintext bytes the buffer currently holds in encrypted form.
+	 * This is less than the number of encrypted bytes, because the SSL
+	 * protocol adds framing. (it could also be more, when compression is used)
+	 */
+	int			plaintextLen;
+
+	/*
+	 * Buffer for decrypting read data.
+	 *
+	 * decryptBufferSize is the allocated size of decryptBuffer.
+	 * decryptBufferLen is the number of ciphertext bytes loaded to the buffer.
+	 *
+	 * The buffer can be in one of two states. In the first state, it contains
+	 * zero or more raw bytes, and more can be loaded into it. In the other
+	 * state, it contains decrypted data that can be read out.
+	 *
+	 * When the buffer contains decrypted data, decryptedLen > 0, and
+	 * decryptedData points to the data. The buffer can also contain some
+	 * leftover raw data that has not been decrypted yet (extraData/extraLen).
+	 *
+	 * Before reading more raw data to the buffer, call
+	 * prepareDecryptBufferForRead. It moves any leftover raw data to the
+	 * beginning of the buffer.
+	 */
+	char	   *decryptBuffer;
+	int			decryptBufferSize;
+	int			decryptBufferLen; 	/* ciphertext bytes loaded in decryptBuffer */
+
+	/* decrypted data not returned to the caller yet */
+	char	   *decryptedData;
+	int			decryptedLen;
+
+	char	   *extraData;
+	int			extraLen;
+};
+
+typedef struct SchannelContext SchannelContext;
+
+/*
+ * Somewhat arbitrarily, use a 10k buffer for both input and output.
+ *
+ * XXX: A buffer size somewhat larger than 8k probably makes sense at least
+ * for input, because the pqcomm.c uses an 8k buffer. (the extra is to contain
+ * SSL headers in the raw input). But I haven't done any performance testing.
+ */
+#define BUFSIZE 10000
+
+/* Functions for managing the encrypt/decrypt buffers */
+static ssize_t encryptBuffer(SchannelContext *ctx, void *ptr, int len);
+static void prepareDecryptBufferForRead(SchannelContext *ctx);
+static int decryptBuffer(SchannelContext *ctx);
+
+static int schannel_handshake(Port *port);
+
+/* Functions for dealing with certificates */
+static void importServerKey(void);
+static CERT_CONTEXT *getServerCert(void);
+static CERT_CONTEXT *getClientRootCert(void);
+static bool validateClientCert(CERT_CONTEXT *cert);
+
+/* Functions for converting error codes to strings */
+static const char *getSecurityStatus(SECURITY_STATUS dwerror);
+
+static char *slurpFile(const char *path, int *size);
+
+/*
+ *	Write data to a secure connection.
+ */
+ssize_t
+be_tls_write(Port *port, void *ptr, size_t len)
+{
+	SchannelContext *ctx = port->windows_schannel;
+	int			sendlen;
+
+	/*
+	 * If the output buffer is empty, encrypt (some of) the input data to fill
+	 * it.
+	 */
+	if (ctx->encryptedLen == 0)
+	{
+		int			plaintextLen;
+
+		plaintextLen = encryptBuffer(ctx, ptr, len);
+		if (plaintextLen < 0)
+			return -1;
+		ctx->plaintextLen = plaintextLen;
+	}
+
+	/*
+	 * Write out the encrypted data in the buffer
+	 */
+	sendlen = secure_raw_write(port,
+							   ctx->encryptedData,
+							   ctx->encryptedLen);
+	if (sendlen <= 0)
+		return sendlen;
+
+	ctx->encryptedData += sendlen;
+	ctx->encryptedLen -= sendlen;
+
+	if (ctx->encryptedLen == 0)
+	{
+		/* sent all the data in the buffer. */
+		return ctx->plaintextLen;
+	}
+	else
+	{
+		/* return 0 to indicate that the caller has to retry. */
+		return 0;
+	}
+}
+
+/*
+ * Encrypt more data. Helper function for be_tls_write().
+ */
+static ssize_t
+encryptBuffer(SchannelContext *ctx, void *ptr, int len)
+{
+	SecPkgContext_StreamSizes sizes;
+	SecBufferDesc sbufdesc;
+	SecBuffer	sbufs[4];
+	SECURITY_STATUS rc;
+
+	/* we should've sent out all encrypted data from previous round first */
+	Assert(ctx->encryptedLen == 0);
+
+	rc = QueryContextAttributes(&ctx->ctxHandle,
+								SECPKG_ATTR_STREAM_SIZES, &sizes);
+	if (rc != SEC_E_OK)
+	{
+		elog(COMMERROR, "QueryContextAttributes failed: %s", getSecurityStatus(rc));
+		return -1;
+	}
+	if (sizes.cbHeader + sizes.cbTrailer + len > ctx->encryptBufferSize)
+		len = ctx->encryptBufferSize - (sizes.cbHeader + sizes.cbTrailer);
+
+	memcpy(&ctx->encryptBuffer[sizes.cbHeader], ptr, len);
+
+	sbufs[0].pvBuffer = ctx->encryptBuffer;
+	sbufs[0].cbBuffer = sizes.cbHeader;
+	sbufs[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+	sbufs[1].pvBuffer = &ctx->encryptBuffer[sizes.cbHeader];
+	sbufs[1].cbBuffer = len;
+	sbufs[1].BufferType = SECBUFFER_DATA;
+
+	sbufs[2].pvBuffer = &ctx->encryptBuffer[sizes.cbHeader + len];
+	sbufs[2].cbBuffer = sizes.cbTrailer;
+	sbufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+	sbufs[3].pvBuffer = NULL;
+	sbufs[3].cbBuffer = 0;
+	sbufs[3].BufferType = SECBUFFER_EMPTY;
+
+	sbufdesc.ulVersion = SECBUFFER_VERSION;
+	sbufdesc.cBuffers = 4;
+	sbufdesc.pBuffers = sbufs;
+
+	rc = EncryptMessage(&ctx->ctxHandle, 0, &sbufdesc, 0);
+	if (rc != SEC_E_OK)
+	{
+		elog(ERROR, "EncryptMessage failed: %s", getSecurityStatus(rc));
+		return -1;
+	}
+
+	ctx->encryptedData = ctx->encryptBuffer;
+	ctx->encryptedLen = sbufs[0].cbBuffer + sbufs[1].cbBuffer + sbufs[2].cbBuffer;
+
+	return len;
+}
+
+/*
+ *	Initialize global SSL context.
+ */
+void
+be_tls_init(void)
+{
+	/*
+	 * Import the server's private key into the key container. (This only
+	 * needs to be done once at server startup.)
+	 */
+	if (IsUnderPostmaster)
+		importServerKey();
+}
+
+static int
+schannel_handshake(Port *port)
+{
+	SchannelContext *ctx = port->windows_schannel;
+	SecBufferDesc insbufdesc;
+	SecBuffer	insbufs[2];
+	SecBufferDesc outsbufdesc;
+	SecBuffer	outsbufs[1];
+	DWORD		flags;
+	DWORD		outflags;
+	SECURITY_STATUS rc;
+	ssize_t		readlen;
+	bool		handshake_complete = false;
+
+	do
+	{
+		/* read more raw data to buffer */
+		readlen = secure_raw_read(port,
+								  &ctx->decryptBuffer[ctx->decryptBufferLen],
+								  ctx->decryptBufferSize - ctx->decryptBufferLen);
+		if (readlen < 0)
+		{
+			ereport(COMMERROR,
+					(errcode_for_socket_access(),
+					 errmsg("could not accept SSL connection: %m")));
+			be_tls_close(port);
+			return -1;
+		}
+
+		ctx->decryptBufferLen += readlen;
+
+		/*
+		 * Pass the raw data read this far to AcceptSecurityContext.
+		 * Per Microsoft documentation, AcceptSecurityContext requires two
+		 * input buffers, one with SECBUFFER_TOKEN containing the input data,
+		 * and one SECBUFFER_EMPTY.
+		 */
+		insbufs[0].pvBuffer = ctx->decryptBuffer;
+		insbufs[0].cbBuffer = ctx->decryptBufferLen;
+		insbufs[0].BufferType = SECBUFFER_TOKEN;
+
+		insbufs[1].pvBuffer = NULL;
+		insbufs[1].cbBuffer = 0;
+		insbufs[1].BufferType = SECBUFFER_EMPTY;
+
+		insbufdesc.cBuffers = 2;
+		insbufdesc.pBuffers = insbufs;
+		insbufdesc.ulVersion = SECBUFFER_VERSION;
+
+		/*
+		 * The ASC_REQ_MUTUAL_AUTH means that we request a client cert. The
+		 * connection will still succeed if the client doesn't provide one.
+		 */
+		flags = ASC_REQ_ALLOCATE_MEMORY |
+			ASC_REQ_CONFIDENTIALITY |
+			ASC_RET_EXTENDED_ERROR |
+			ASC_REQ_REPLAY_DETECT |
+			ASC_REQ_SEQUENCE_DETECT |
+			ASC_REQ_MUTUAL_AUTH |
+			ASC_REQ_STREAM;
+
+		outsbufs[0].pvBuffer   = NULL;
+		outsbufs[0].BufferType = SECBUFFER_TOKEN;
+		outsbufs[0].cbBuffer   = 0;
+
+		outsbufdesc.cBuffers = 1;
+		outsbufdesc.pBuffers = outsbufs;
+		outsbufdesc.ulVersion = SECBUFFER_VERSION;
+
+		rc = AcceptSecurityContext(&ctx->credHandle,
+								   ctx->ctxHandle_valid ? &ctx->ctxHandle : NULL,
+								   &insbufdesc,
+								   flags,
+								   0,
+								   ctx->ctxHandle_valid ? NULL : &ctx->ctxHandle,
+								   &outsbufdesc,
+								   &outflags,
+								   NULL);
+		ctx->ctxHandle_valid = true;
+
+		/*
+		 * If AcceptSecurityContext returns SEC_E_OK or SEC_I_CONTINUE_NEEDED,
+		 * it has consumed (some of) the raw input. It may have also produced
+		 * some output that we need to write back to the client.
+		 */
+		if (rc == SEC_E_OK || rc == SEC_I_CONTINUE_NEEDED)
+		{
+			/*
+			 * AcceptSecurityContext might not have processed all the input
+			 * data. The number of unprocessed bytes is returned in input
+			 * buffer 1, as an SECBUFFER_EXTRA buffer.
+			 */
+			if (insbufs[1].BufferType == SECBUFFER_EXTRA)
+			{
+				size_t extraLen = insbufs[1].cbBuffer;
+
+				memmove(ctx->decryptBuffer, &ctx->decryptBuffer[ctx->decryptBufferLen - extraLen], extraLen);
+				ctx->decryptBufferLen = extraLen;
+			}
+			else
+				ctx->decryptBufferLen = 0;
+
+			if (outsbufs[0].pvBuffer)
+			{
+				ssize_t		totalsent = 0;
+				ssize_t		sendlen;
+
+				while(totalsent < outsbufs[0].cbBuffer)
+				{
+					sendlen = secure_raw_write(port,
+											   outsbufs[0].pvBuffer,
+											   outsbufs[0].cbBuffer);
+					/* Note: we assume that the socket is in blocking mode */
+					if (sendlen <= 0)
+					{
+						ereport(COMMERROR,
+								(errcode(ERRCODE_PROTOCOL_VIOLATION),
+								 errmsg("could not send")));
+						return -1;
+					}
+
+					totalsent += sendlen;
+				}
+
+				FreeContextBuffer(outsbufs[0].pvBuffer);
+				outsbufs[0].pvBuffer = NULL;
+			}
+		}
+
+		switch(rc)
+		{
+			case SEC_E_OK:
+				/* SSL handshake is complete */
+				handshake_complete = true;
+				break;
+
+			case SEC_I_COMPLETE_AND_CONTINUE:
+				elog(COMMERROR, "SEC_I_COMPLETE_AND_CONTINUE not implemented", rc);
+				be_tls_close(port);
+				return -1;
+
+			case SEC_I_COMPLETE_NEEDED:
+				elog(COMMERROR, "SEC_I_COMPLETE_NEEDED not implemented", rc);
+				be_tls_close(port);
+				return -1;
+
+			case SEC_I_CONTINUE_NEEDED:
+				/* Need more input from the client to continue */
+				break;
+
+			case SEC_I_INCOMPLETE_CREDENTIALS:
+				elog(COMMERROR, "SEC_I_INCOMPLETE_CREDENTIALS not implemented");
+				be_tls_close(port);
+				return -1;
+
+			case SEC_E_INCOMPLETE_MESSAGE:
+				/*
+				 * The input didn't contain a full SSL message. Loop back to
+				 * read more data, leaving the input already read in the
+				 * buffer, and retry.
+				 */
+				break;
+
+			default:
+				ereport(COMMERROR,
+						(errcode(ERRCODE_PROTOCOL_VIOLATION),
+						 errmsg("could not initialize SSL connection"),
+						 errdetail("AcceptSecurityContext failed: %s", getSecurityStatus(rc))));
+				be_tls_close(port);
+				return -1;
+		}
+	} while (!handshake_complete);
+
+	/* success! */
+	return 0;
+}
+
+/*
+ *	Attempt to negotiate SSL connection.
+ */
+int
+be_tls_open_server(Port *port)
+{
+	SchannelContext *ctx = port->windows_schannel;
+	SECURITY_STATUS rc;
+	SCHANNEL_CRED credData;
+	CERT_CONTEXT *serverCert;
+	CERT_CONTEXT *remoteCert;
+
+	serverCert = getServerCert();
+
+	memset(&credData, 0, sizeof(credData));
+	credData.dwVersion = SCHANNEL_CRED_VERSION;
+	credData.dwFlags |= SCH_CRED_NO_SYSTEM_MAPPER;
+	credData.cCreds = 1;
+	credData.paCred = &serverCert;
+
+	ctx = (SchannelContext *) palloc0(sizeof(SchannelContext));
+
+	rc = AcquireCredentialsHandle(NULL,
+								  UNISP_NAME,
+								  SECPKG_CRED_INBOUND,
+								  NULL,
+								  &credData,
+								  NULL,
+								  NULL,
+								  &ctx->credHandle,
+								  NULL);
+	if (rc != SEC_E_OK)
+	{
+		ereport(COMMERROR,
+				(errcode(ERRCODE_PROTOCOL_VIOLATION),
+				 errmsg("could not initialize SSL"),
+				 errdetail("AcquireCredentialsHandle failed: %s", getSecurityStatus(rc))));
+		be_tls_close(port);
+		return -1;
+	}
+	ctx->credHandle_valid = true;
+
+	ctx->encryptBufferSize = BUFSIZE;
+	ctx->encryptBuffer = palloc(ctx->encryptBufferSize);
+	ctx->decryptBufferSize = BUFSIZE;
+	ctx->decryptBuffer = palloc(ctx->encryptBufferSize);
+
+	port->windows_schannel = ctx;
+	port->ssl_in_use = true;
+
+	if (schannel_handshake(port) < 0)
+		return -1;
+
+	/* SSL handshake complete */
+	elog(SCHANNEL_DEBUG, "SSL handshake completed");
+
+	/* Get client certificate, if available */
+	rc = QueryContextAttributes(&ctx->ctxHandle,
+								SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+								(PVOID) &remoteCert);
+	if (rc == SEC_E_OK)
+	{
+		/*
+		 * Validate the client cert. If it passes, extract the Common Name,
+		 * to be used later in cert authentication.
+		 */
+		if (validateClientCert(remoteCert))
+		{
+			char	   *cn;
+			DWORD		len;
+			DWORD		len2;
+
+			port->peer_cert_valid = true;
+			elog(SCHANNEL_DEBUG, "client certificate validated");
+
+			/*
+			 * Call CertGetNameString without passing a buffer, to get the
+			 * required length.
+			 */
+			len = CertGetNameString(remoteCert,
+									CERT_NAME_ATTR_TYPE,
+									0,
+									szOID_COMMON_NAME,
+									NULL,
+									0);
+			if (len > 1)
+			{
+				cn = palloc(len);
+				len2 = CertGetNameString(remoteCert,
+										 CERT_NAME_ATTR_TYPE,
+										 0,
+										 szOID_COMMON_NAME,
+										 cn,
+										 len);
+				if (len != len2)
+				{
+					/* shouldn't happen */
+					pfree(cn);
+					be_tls_close(port);
+					return -1;
+				}
+				port->peer_cn = cn;
+				elog(SCHANNEL_DEBUG, "client cert name: %s", cn);
+			}
+		}
+		else
+			elog(SCHANNEL_DEBUG, "client certificate validation failed");
+
+		CertFreeCertificateContext(remoteCert);
+	}
+
+	return 0;
+}
+
+/*
+ *	Close SSL connection.
+ */
+void
+be_tls_close(Port *port)
+{
+	SchannelContext *ctx = port->windows_schannel;
+	DWORD		token;
+	SecBufferDesc outsbufdesc;
+	SecBuffer	outsbufs[1];
+	SECURITY_STATUS rc;
+
+	if (ctx->ctxHandle_valid)
+	{
+		/*
+		 *  "Shutting Down an Schannel Connection",
+		 *  http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138%28v=vs.85%29.aspx
+		 */
+		token = SCHANNEL_SHUTDOWN;
+
+		outsbufdesc.ulVersion = SECBUFFER_VERSION;
+		outsbufdesc.cBuffers = 1;
+		outsbufdesc.pBuffers = outsbufs;
+
+		outsbufs[0].BufferType = SECBUFFER_TOKEN;
+		outsbufs[0].cbBuffer = sizeof( token );
+		outsbufs[0].pvBuffer = &token;
+
+		rc = ApplyControlToken(&ctx->ctxHandle, &outsbufdesc);
+
+		/*
+		 * Use AcceptSecurityContext to finish the shutdown, just like the
+		 * initiation handshake is done.
+		 */
+		(void) schannel_handshake(port);
+
+		DeleteSecurityContext(&ctx->ctxHandle);
+		ctx->ctxHandle_valid = false;
+	}
+	if (ctx->credHandle_valid)
+	{
+		FreeCredentialsHandle(&ctx->credHandle);
+		ctx->credHandle_valid = false;
+	}
+
+	if (ctx->encryptBuffer)
+		pfree(ctx->encryptBuffer);
+	if (ctx->decryptBuffer)
+		pfree(ctx->decryptBuffer);
+
+	pfree(ctx);
+
+	if (port->peer_cn)
+	{
+		pfree(port->peer_cn);
+		port->peer_cn = NULL;
+	}
+	port->peer_cert_valid = false;
+
+	port->windows_schannel = NULL;
+	port->ssl_in_use = false;
+}
+
+/*
+ *	Read data from a secure connection.
+ */
+ssize_t
+be_tls_read(Port *port, void *ptr, size_t len)
+{
+	SchannelContext *ctx = port->windows_schannel;
+	int			readlen;
+	int			maxsize;
+	size_t		totalreadlen = 0;
+	char	   *dst = ptr;
+
+	for (;;)
+	{
+		/* if we already have some decrypted data, copy it to the target buffer */
+		if (ctx->decryptedLen > 0)
+		{
+			maxsize = len - totalreadlen;
+			if (maxsize > ctx->decryptedLen)
+				maxsize = ctx->decryptedLen;
+			memcpy(dst, &ctx->decryptedData[totalreadlen], maxsize);
+			dst += maxsize;
+			totalreadlen += maxsize;
+			ctx->decryptedLen -= maxsize;
+			ctx->decryptedData += maxsize;
+		}
+
+		/* If we have some data to return, return it. */
+		if (totalreadlen > 0)
+		{
+			return totalreadlen;
+		}
+
+		/*
+		 * there shouldn't be any decrypted data left in the buffer, we copied
+		 * it all to the target.
+		 */
+		Assert(ctx->decryptedLen == 0);
+
+		/*
+		 * Need to decrypt more data, and for that, need to read more raw
+		 * data.
+		 */
+		prepareDecryptBufferForRead(ctx);
+		while (ctx->decryptedLen == 0)
+		{
+			/* read more data to buffer */
+			maxsize = ctx->decryptBufferSize - ctx->decryptBufferLen;
+			readlen = secure_raw_read(port,
+									  &ctx->decryptBuffer[ctx->decryptBufferLen],
+									  maxsize);
+			if (readlen < 0)
+				return readlen;
+			if (readlen == 0)
+			{
+				/* this implies we're in non-blocking mode */
+				return totalreadlen;
+			}
+
+			ctx->decryptBufferLen += readlen;
+
+			/* decrypt what we got */
+			if (decryptBuffer(ctx) == -1)
+				return -1;
+			if (ctx->remote_shutdown)
+				return totalreadlen;
+
+			/* If decryptBuffer needs more data, decrypteLen is still 0. */
+		}
+	}
+
+	return totalreadlen;
+}
+
+/*
+ * Prepare the buffer for reading in more cipher text.
+ */
+static void
+prepareDecryptBufferForRead(SchannelContext *ctx)
+{
+	/*
+	 * should've consumed all the previous decrypted data in the buffer befor
+	 * decrypting more.
+	 */
+	Assert(ctx->decryptedLen == 0);
+
+	/*
+	 * If there's any ciphertext left in the buffer from previous round, move
+	 * it to beginning.
+	 */
+	if (ctx->extraLen > 0)
+		memmove(ctx->decryptBuffer,	ctx->extraData,	ctx->extraLen);
+	ctx->decryptBufferLen = ctx->extraLen;
+	ctx->extraData = NULL;
+	ctx->extraLen = 0;
+	ctx->decryptedData = NULL;
+	ctx->decryptedLen = 0;
+}
+
+/*
+ * Try to decrypt the data currently in decryptBuffer. On success,
+ * decryptedData points to the decrypted data. DecryptMessage decrypts
+ * in-place, so decryptedData points to somewhere within the buffer!
+ *
+ * On success, returns 1. On error, returns -1. If more raw data is needed
+ * to decrypt, returns 0. If the client shut down the connection, also
+ * returns 0, and sets ctx->remote_shutdown flag.
+ */
+static int
+decryptBuffer(SchannelContext *ctx)
+{
+	/*
+	 * Call DecryptBuffer until it returns some data, fails, or indicates that
+	 * it needs more input
+	 */
+	while(ctx->decryptedLen == 0)
+	{
+		SecBufferDesc sbufdesc;
+		SecBuffer	sbufs[4];
+		SECURITY_STATUS rc;
+		int			i;
+
+		Assert(ctx->decryptBufferLen > 0);
+		Assert(ctx->extraLen == 0);
+
+		sbufs[0].pvBuffer = ctx->decryptBuffer;
+		sbufs[0].cbBuffer = ctx->decryptBufferLen;
+		sbufs[0].BufferType = SECBUFFER_DATA;
+		sbufs[1].pvBuffer = NULL;
+		sbufs[1].cbBuffer = 0;
+		sbufs[1].BufferType   = SECBUFFER_EMPTY;
+		sbufs[2].pvBuffer = NULL;
+		sbufs[2].cbBuffer = 0;
+		sbufs[2].BufferType   = SECBUFFER_EMPTY;
+		sbufs[3].pvBuffer = NULL;
+		sbufs[3].cbBuffer = 0;
+		sbufs[3].BufferType   = SECBUFFER_EMPTY;
+
+		sbufdesc.ulVersion = SECBUFFER_VERSION;
+		sbufdesc.cBuffers = 4;
+		sbufdesc.pBuffers = sbufs;
+
+		rc = DecryptMessage(&ctx->ctxHandle, &sbufdesc, 0, NULL);
+
+		if (rc == SEC_E_INCOMPLETE_MESSAGE)
+		{
+			/* We don't have the full message yet. Need more data. */
+			return 0;
+		}
+		if (rc == SEC_I_CONTEXT_EXPIRED)
+		{
+			elog(SCHANNEL_DEBUG, "DecryptMessage returned SEC_I_CONTEXT_EXPIRED");
+			ctx->remote_shutdown = true;
+			return 0;
+		}
+		if (rc == SEC_I_RENEGOTIATE)
+		{
+			/* TODO */
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("SSL renegotiated not implemented")));
+		}
+		if (rc != SEC_E_OK)
+		{
+			/* FIXME: set errno */
+			elog(COMMERROR, "DecryptMessage failed: %s", getSecurityStatus(rc));
+			return -1;
+		}
+
+		for (i = 0; i < 4; i++)
+		{
+			if (sbufs[i].BufferType == SECBUFFER_EXTRA)
+			{
+				ctx->extraData = sbufs[i].pvBuffer;
+				ctx->extraLen = sbufs[i].cbBuffer;
+			}
+			if (sbufs[i].BufferType == SECBUFFER_DATA)
+			{
+				ctx->decryptedData = sbufs[i].pvBuffer;
+				ctx->decryptedLen = sbufs[i].cbBuffer;
+			}
+		}
+		if (ctx->decryptedLen == 0)
+		{
+			/*
+			 * DecryptMessage didn't decrypt anything. Shift the extra data
+			 * to beginning of buffer, and retry.
+			 */
+			prepareDecryptBufferForRead(ctx);
+		}
+	}
+
+	return 1;
+}
+
+/**** Certificate handling functions ****/
+
+static char *
+slurpFile(const char *path, int *size)
+{
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *content;
+	int			r;
+
+	if (stat(path, &statbuf) != 0)
+	{
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat certificate file \"%s\": %m",
+						path)));
+	}
+	fp = AllocateFile(path, "r");
+	if (!fp)
+	{
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read certificate file \"%s\": %m",
+						path)));
+	}
+	content = palloc(statbuf.st_size + 1);
+	r = fread(content, statbuf.st_size, 1, fp);
+	content[statbuf.st_size] = '\0';
+
+	if (r != 1 || ferror(fp) || FreeFile(fp))
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						path)));
+
+	if (size)
+		*size = statbuf.st_size;
+
+	return content;
+}
+
+/*
+ * Import the server's private key into the key container.
+ */
+static void
+importServerKey(void)
+{
+	char	   *content;
+	int			filelen;
+	char		buf[50000];
+	DWORD		buflen = 50000;
+	char		privKeyBlob[50000];
+	DWORD		privKeyBlobLen = 50000;
+	HCRYPTPROV	cryptProvHandle;
+	HCRYPTKEY	keyHandle;
+
+	content = slurpFile(ssl_key_file, &filelen);
+
+	/* convert from PEM to DER */
+	buflen = 50000;
+	if (!CryptStringToBinary(content, filelen, CRYPT_STRING_BASE64HEADER,
+							 buf, &buflen, NULL, NULL))
+	{
+		elog(ERROR, "CryptStringToBinary (key) failed: 0x%x", GetLastError());		
+	}
+	pfree(content);
+
+	if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+							 PKCS_RSA_PRIVATE_KEY,
+							 buf, buflen,
+							 0,
+							 NULL,
+							 privKeyBlob,
+							 &privKeyBlobLen))
+	{
+		elog(ERROR, "CryptDecodeObjectEx (key) failed: 0x%x", GetLastError());
+	}
+
+	/* Open the key container */
+	if (!CryptAcquireContextW(&cryptProvHandle, PG_KEY_CONTAINER_NAME, MS_DEF_RSA_SCHANNEL_PROV_W, PROV_RSA_SCHANNEL, 0))
+	{
+		if (GetLastError() == NTE_BAD_KEYSET)
+		{
+			/*
+			 * The key container could not be accessed. Most probable cause
+			 * is that it doesn't exist, so try to create it.
+			 */
+			if (!CryptAcquireContextW(&cryptProvHandle, PG_KEY_CONTAINER_NAME, MS_DEF_RSA_SCHANNEL_PROV_W, PROV_RSA_SCHANNEL, CRYPT_NEWKEYSET))
+			{
+				elog(ERROR, "CryptAcquireContext failed: 0x%x", GetLastError());
+			}
+			else
+				elog(LOG, "SChannel key container created");
+		}
+		else
+			elog(ERROR, "CryptAcquireContext failed: 0x%x", GetLastError());
+	}
+
+	if (!CryptImportKey(cryptProvHandle, privKeyBlob, privKeyBlobLen,
+						(HCRYPTKEY) NULL, 0, &keyHandle))
+	{
+		elog(ERROR, "CryptImportKey failed: 0x%x", GetLastError());
+	}
+
+	CryptDestroyKey(keyHandle);
+
+	if (!CryptReleaseContext(cryptProvHandle, 0))
+		elog(ERROR, "CryptReleaseContext failed: 0x%x", GetLastError());
+}
+
+static CERT_CONTEXT *
+getServerCert(void)
+{
+	CERT_CONTEXT *cert_cxt;
+	char	   *content;
+	int			filelen;
+	char		buf[50000];
+	DWORD		buflen = 50000;
+	CRYPT_KEY_PROV_INFO keyProvInfo;
+
+	content = slurpFile(ssl_cert_file, &filelen);
+
+	/* convert from PEM to DER */
+	if (!CryptStringToBinary(content, filelen, CRYPT_STRING_BASE64HEADER,
+							 buf, &buflen, NULL, NULL))
+	{
+		elog(ERROR, "CryptStringToBinary failed: 0x%x", GetLastError());		
+	}
+
+	cert_cxt = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+											buf,
+											buflen);
+	if (cert_cxt == NULL)
+	{
+		elog(ERROR, "CertCreateCertificateContext failed: 0x%x", GetLastError());
+	}
+	pfree(content);
+
+	/* Tell the Crypto API how to find the private key */
+	memset(&keyProvInfo, 0, sizeof(keyProvInfo));
+	keyProvInfo.pwszContainerName = PG_KEY_CONTAINER_NAME;
+	keyProvInfo.pwszProvName = MS_DEF_RSA_SCHANNEL_PROV_W;
+	keyProvInfo.dwProvType = PROV_RSA_SCHANNEL;
+	keyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
+
+	if (!CertSetCertificateContextProperty(cert_cxt,
+										   CERT_KEY_PROV_INFO_PROP_ID,
+										   0,
+										   &keyProvInfo))
+	{
+		elog(ERROR, "CertSetCertificateContextProperty failed: %x", GetLastError());
+	}
+
+	return cert_cxt;
+}
+
+static bool
+validateClientCert(CERT_CONTEXT *cert)
+{
+	CERT_CONTEXT *rootCert;
+	DWORD flags;
+
+	/*
+	 * Per MSDN documentation [1], we must check the following things:
+	 *
+	 * 1. The certificate chain is complete and the root is a certificate from
+	 *    a trusted certification authority (CA).
+	 * 2. The current time is not beyond the begin and end dates for each of
+	 *    the certificates in the certificate chain.
+	 * 3. None of the certificates in the certificate chain have been revoked.
+	 * 4. The depth of the leaf certificate is not deeper than the maximum
+	 *    allowable depth specified in the certificate extension. This check is
+	 *    only necessary if there is a depth specified.
+	 * 5. The usage of the certificate is correct, for example, a client
+	 *    certificate should not be used to authenticate a server.
+	 *
+	 * [1] "Manually Validating Schannel Credential",
+	 *     http://msdn.microsoft.com/en-us/library/windows/desktop/aa378740%28v=vs.85%29.aspx
+	 */
+
+	/*
+	 * 1. Check the chain
+	 * 2. Check expiration
+	 *
+	 * TODO: Currently, we only support client certs signed by the root client
+	 * CA. Intermediary CA's are not supported.
+	 */
+	rootCert = getClientRootCert();
+
+	/* TODO: CRL's are not actually supported */
+	flags = CERT_STORE_SIGNATURE_FLAG |
+		CERT_STORE_TIME_VALIDITY_FLAG;
+	if (!CertVerifySubjectCertificateContext(
+			cert,
+			rootCert,
+			&flags))
+	{
+		elog(LOG, "failed to verify client cert");
+		return false;
+	}
+	if (flags != 0)
+	{
+		if ((flags & CERT_STORE_SIGNATURE_FLAG) != 0)
+			elog(LOG, "signature check failed on client cert");
+		if ((flags & CERT_STORE_REVOCATION_FLAG) != 0)
+			elog(LOG, "client cert was revoked");
+		if ((flags & CERT_STORE_TIME_VALIDITY_FLAG) != 0)
+			elog(LOG, "client cert is not valid at this time");
+
+		return false;
+	}
+
+	/*
+	 * We succeeded to get the issuer's certificate from the trusted root store,
+	 * and the signature on the client cert passed, so we're good to go.
+	 */
+
+	return true;
+}
+
+static CERT_CONTEXT *
+getClientRootCert(void)
+{
+	char	  *client_ca_file;
+	int			client_ca_file_len;
+	char		crtBuf[50000]; /* TODO: enlarge as needed */
+	DWORD		crtBufLen = 50000;
+	CERT_CONTEXT *client_root_cxt;
+
+	client_ca_file = slurpFile(ssl_ca_file, &client_ca_file_len);
+	if (client_ca_file == NULL)
+		return NULL;
+
+	/* convert from PEM to DER */
+	if (!CryptStringToBinary(
+			client_ca_file,
+			client_ca_file_len,
+			CRYPT_STRING_BASE64HEADER,
+			crtBuf,
+			&crtBufLen,
+			NULL,
+			NULL))
+	{
+		elog(ERROR, "failed to convert client root cert from PEM to DER format");
+	}
+
+	client_root_cxt = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+												   crtBuf,
+												   crtBufLen);
+	if (client_root_cxt == NULL)
+		elog(ERROR, "CertCreateCertificateContext failed: 0x%x", GetLastError());
+
+	return client_root_cxt;
+}
+
+/*** Printing error codes ***/
+
+#define ERRORCODE_STR(x) { x, #x }
+
+typedef struct
+{
+	uint32 rc;
+	const char *str;
+} errorcode_str;
+
+static const char *
+getErrorStr(uint32 rc, errorcode_str *map)
+{
+	static char buf[100];
+	int i;
+
+	for (i = 0; map[i].str != NULL; i++)
+	{
+		if (map[i].rc == rc)
+			return map[i].str;
+	}
+	snprintf(buf, sizeof(buf), "0x%X", rc);
+	return buf;
+}
+
+static const char *
+getSecurityStatus(SECURITY_STATUS rc)
+{
+	static errorcode_str sec_status_codes[] = {
+		ERRORCODE_STR(SEC_E_OK),
+		ERRORCODE_STR(SEC_E_INCOMPLETE_MESSAGE),
+		ERRORCODE_STR(SEC_E_INSUFFICIENT_MEMORY),
+		ERRORCODE_STR(SEC_E_INTERNAL_ERROR),
+		ERRORCODE_STR(SEC_E_INVALID_HANDLE),
+		ERRORCODE_STR(SEC_E_INVALID_TOKEN),
+		ERRORCODE_STR(SEC_E_LOGON_DENIED),
+		ERRORCODE_STR(SEC_E_NO_AUTHENTICATING_AUTHORITY),
+		ERRORCODE_STR(SEC_E_NO_CREDENTIALS),
+		ERRORCODE_STR(SEC_I_COMPLETE_AND_CONTINUE),
+		ERRORCODE_STR(SEC_I_COMPLETE_NEEDED),
+		ERRORCODE_STR(SEC_I_CONTINUE_NEEDED),
+		ERRORCODE_STR(SEC_E_ILLEGAL_MESSAGE),
+		{ 0, NULL }
+	};
+	return getErrorStr(rc, sec_status_codes);
+}
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 41ec1ad..fcd5ea2 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -103,6 +103,10 @@ secure_open_server(Port *port)
 	r = be_tls_open_server(port);
 #endif
 
+	ereport(DEBUG2,
+			(errmsg("SSL connection from \"%s\"",
+					port->peer_cn ? port->peer_cn : "(anonymous)")));
+
 	return r;
 }
 
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 34e52e4..7fcee98 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -53,6 +53,10 @@
 #include <security.h>
 #undef SECURITY_WIN32
 
+#ifdef USE_WINDOWS_SCHANNEL
+struct SchannelContext;
+#endif
+
 #ifndef ENABLE_GSS
 /*
  * Define a fake structure compatible with GSSAPI on Unix.
@@ -197,6 +201,9 @@ typedef struct Port
 	X509	   *peer;
 	unsigned long count;
 #endif
+#ifdef USE_WINDOWS_SCHANNEL
+	struct SchannelContext *windows_schannel;
+#endif
 } Port;
 
 #ifdef USE_SSL
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 5bdfa47..e4d8574 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -802,6 +802,9 @@
 /* Define to select Win32-style shared memory. */
 #undef USE_WIN32_SHARED_MEMORY
 
+/* Define to build with Windows SChannel support. (--with-winschannel) */
+#undef USE_WINDOWS_SCHANNEL
+
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
 #if defined AC_APPLE_UNIVERSAL_BUILD
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 00be15f..901de03 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -649,6 +649,9 @@
 /* Define to select Win32-style semaphores. */
 #define USE_WIN32_SEMAPHORES 1
 
+/* Define to build with Windows SChannel support. (--with-winschannel) */
+#undef USE_WINDOWS_SCHANNEL
+
 /* Number of bits in a file offset, on hosts where this is settable. */
 /* #undef _FILE_OFFSET_BITS */
 
diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
index d78f38e..54ed4b2 100644
--- a/src/include/pg_config_manual.h
+++ b/src/include/pg_config_manual.h
@@ -146,10 +146,9 @@
 
 /*
  * USE_SSL code should be compiled only when compiling with an SSL
- * implementation.  (Currently, only OpenSSL is supported, but we might add
- * more implementations in the future.)
+ * implementation.
  */
-#ifdef USE_OPENSSL
+#if defined (USE_OPENSSL) || defined(USE_WINDOWS_SCHANNEL)
 #define USE_SSL
 #endif
 
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index a90cb89..7968266 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -48,6 +48,10 @@ ifeq ($(with_openssl),yes)
 OBJS += fe-secure-openssl.o
 endif
 
+ifeq ($(with_winschannel),yes)
+OBJS += fe-secure-winschannel.o
+endif
+
 ifeq ($(PORTNAME), cygwin)
 override shlib = cyg$(NAME)$(DLSUFFIX)
 endif
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index f950fc3..cee7b2e 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -780,57 +780,21 @@ destroy_ssl_system(void)
 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
+	char	   *sslcertfile = NULL;
+	char	   *engine = NULL;
+	char	   *keyname = NULL;
+	char	   *sslkeyfile = NULL;
+	char	   *sslrootcert = NULL;
+	char	   *sslcrl = NULL;
+	int			ret = -1;
+
+	if (!pqsecure_get_ssl_files(conn,
+								&sslcertfile, &sslkeyfile, &engine, &keyname,
+								&sslrootcert, &sslcrl))
+		return PGRES_POLLING_READING;
+
+	if (sslcertfile)
 	{
 		/*
 		 * Cert file exists, so load it.  Since OpenSSL doesn't provide the
@@ -855,216 +819,146 @@ initialize_SSL(PGconn *conn)
 		{
 			printfPQExpBuffer(&conn->errorMessage,
 			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
-			return -1;
+			goto fail;
 		}
 #endif
-		if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
+		if (SSL_CTX_use_certificate_chain_file(SSL_context, sslcertfile) != 1)
 		{
 			char	   *err = SSLerrmessage();
 
 			printfPQExpBuffer(&conn->errorMessage,
 			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
-							  fnbuf, err);
+							  sslcertfile, err);
 			SSLerrfree(err);
 
 #ifdef ENABLE_THREAD_SAFETY
 			pthread_mutex_unlock(&ssl_config_mutex);
 #endif
-			return -1;
+			goto fail;
 		}
 
-		if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
+		if (SSL_use_certificate_file(conn->ssl, sslcertfile, SSL_FILETYPE_PEM) != 1)
 		{
 			char	   *err = SSLerrmessage();
 
 			printfPQExpBuffer(&conn->errorMessage,
 			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
-							  fnbuf, err);
+							  sslcertfile, err);
 			SSLerrfree(err);
 #ifdef ENABLE_THREAD_SAFETY
 			pthread_mutex_unlock(&ssl_config_mutex);
 #endif
-			return -1;
+			goto fail;
 		}
 
-		/* 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 an engine:key specification was given, load that.
 	 */
-	if (have_cert && conn->sslkey && strlen(conn->sslkey) > 0)
+	if (engine)
 	{
 #ifdef USE_SSL_ENGINE
-		if (strchr(conn->sslkey, ':')
-#ifdef WIN32
-			&& conn->sslkey[1] != ':'
-#endif
-			)
+		conn->engine = ENGINE_by_id(engine);
+		if (conn->engine == NULL)
 		{
-			/* 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();
+			char	   *err = SSLerrmessage();
 
-				printfPQExpBuffer(&conn->errorMessage,
+			printfPQExpBuffer(&conn->errorMessage,
 					 libpq_gettext("could not load SSL engine \"%s\": %s\n"),
-								  engine_str, err);
-				SSLerrfree(err);
-				free(engine_str);
-				return -1;
-			}
+							  engine, err);
+			SSLerrfree(err);
+			goto fail;
+		}
 
-			if (ENGINE_init(conn->engine) == 0)
-			{
-				char	   *err = SSLerrmessage();
+		if (ENGINE_init(conn->engine) == 0)
+		{
+			char	   *err = SSLerrmessage();
 
-				printfPQExpBuffer(&conn->errorMessage,
+			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));
+							  engine, err);
+			SSLerrfree(err);
+			ENGINE_free(conn->engine);
+			conn->engine = NULL;
+			goto fail;
 		}
-	}
-	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)
+		pkey = ENGINE_load_private_key(conn->engine, keyname, NULL, NULL);
+		if (pkey == NULL)
 		{
+			char	   *err = SSLerrmessage();
+
 			printfPQExpBuffer(&conn->errorMessage,
-							  libpq_gettext("certificate present, but not private key file \"%s\"\n"),
-							  fnbuf);
-			return -1;
+							  libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"),
+							  keyname, engine, err);
+			SSLerrfree(err);
+			ENGINE_finish(conn->engine);
+			ENGINE_free(conn->engine);
+			conn->engine = NULL;
+			goto fail;
 		}
-#ifndef WIN32
-		if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
+		if (SSL_use_PrivateKey(conn->ssl, pkey) != 1)
 		{
+			char	   *err = SSLerrmessage();
+
 			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;
+							  libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"),
+							  keyname, engine, err);
+			SSLerrfree(err);
+			ENGINE_finish(conn->engine);
+			ENGINE_free(conn->engine);
+			conn->engine = NULL;
+			goto fail;
 		}
-#endif
+#else
+		/*
+		 * should not happen; pqsecure_get_ssl_files doesn't return an
+		 * engine spec if not compiled with USE_SSL_ENGINE.
+		 */
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("engine not supported\n"));
+		goto fail;
+#endif   /* USE_SSL_ENGINE */
+	}
 
-		if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
+	/* Read the client private key file */
+	if (sslkeyfile)
+	{
+		if (SSL_use_PrivateKey_file(conn->ssl, sslkeyfile, SSL_FILETYPE_PEM) != 1)
 		{
 			char	   *err = SSLerrmessage();
 
 			printfPQExpBuffer(&conn->errorMessage,
 			   libpq_gettext("could not load private key file \"%s\": %s\n"),
-							  fnbuf, err);
+							  sslkeyfile, err);
 			SSLerrfree(err);
-			return -1;
+			goto fail;
 		}
 	}
 
-	/* verify that the cert and key go together */
-	if (have_cert &&
+	/* Verify that the cert and key go together */
+	if (sslcertfile &&
 		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);
+						  sslkeyfile, err);
 		SSLerrfree(err);
-		return -1;
+		goto fail;
 	}
 
 	/*
-	 * 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.
+	 * Load root cert, if exists. (pqsecure_get_ssl_files already complained
+	 * if no root cert was configured but sslmode requires verification
+	 * of server certificates.)
 	 */
-	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)
+	if (sslrootcert)
 	{
 		X509_STORE *cvstore;
 
@@ -1075,35 +969,28 @@ initialize_SSL(PGconn *conn)
 		{
 			printfPQExpBuffer(&conn->errorMessage,
 			   libpq_gettext("could not acquire mutex: %s\n"), strerror(rc));
-			return -1;
+			goto fail;
 		}
 #endif
-		if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
+		if (SSL_CTX_load_verify_locations(SSL_context, sslrootcert, NULL) != 1)
 		{
 			char	   *err = SSLerrmessage();
 
 			printfPQExpBuffer(&conn->errorMessage,
 							  libpq_gettext("could not read root certificate file \"%s\": %s\n"),
-							  fnbuf, err);
+							  sslrootcert, err);
 			SSLerrfree(err);
 #ifdef ENABLE_THREAD_SAFETY
 			pthread_mutex_unlock(&ssl_config_mutex);
 #endif
-			return -1;
+			goto fail;
 		}
 
 		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)
+			if (sslcrl &&
+				X509_STORE_load_locations(cvstore, sslcrl, NULL) == 1)
 			{
 				/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
 #ifdef X509_V_FLAG_CRL_CHECK
@@ -1114,12 +1001,12 @@ initialize_SSL(PGconn *conn)
 
 				printfPQExpBuffer(&conn->errorMessage,
 								  libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
-								  fnbuf);
+								  sslcrl);
 				SSLerrfree(err);
 #ifdef ENABLE_THREAD_SAFETY
 				pthread_mutex_unlock(&ssl_config_mutex);
 #endif
-				return -1;
+				goto fail;
 #endif
 			}
 			/* if not found, silently ignore;  we do not require CRL */
@@ -1130,31 +1017,6 @@ initialize_SSL(PGconn *conn)
 
 		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
@@ -1167,9 +1029,27 @@ initialize_SSL(PGconn *conn)
 	}
 #endif
 
-	return 0;
+	/* success */
+	ret = 0;
+
+fail:
+	if (sslcertfile)
+		free(sslcertfile);
+	if (engine)
+		free(engine);
+	if (keyname)
+		free(keyname);
+	if (sslkeyfile)
+		free(sslkeyfile);
+	if (sslrootcert)
+		free(sslrootcert);
+	if (sslcrl)
+		free(sslcrl);
+
+	return ret;
 }
 
+
 /*
  *	Attempt to negotiate SSL connection.
  */
diff --git a/src/interfaces/libpq/fe-secure-winschannel.c b/src/interfaces/libpq/fe-secure-winschannel.c
new file mode 100644
index 0000000..4af5936
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-winschannel.c
@@ -0,0 +1,1353 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-secure-winschannel.c
+ *	  Windows Schannel SSL implementation
+ *
+ * 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-winschannel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+
+#include "win32.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sspi.h>
+#include <schnlsp.h>
+
+#define SCHANNEL_DEBUG
+
+typedef enum
+{
+	ISC_INIT,		/* before first call to InitializeSecurityContext */
+	ISC_NEED_READ,	/* need to pass more input to InitializeSecurityContext */
+	ISC_NEED_WRITE, /* need to write data to client */
+	ISC_FINAL_WRITE, /* handshake complete after sending last output to client */
+	ISC_COMPLETED	/* handshake complete */
+} HandshakeState;
+
+struct SchannelContext
+{
+	/* SChannel handle for the connection */
+	CtxtHandle  ctxHandle;
+	bool		ctxHandle_valid;
+	CredHandle	credHandle;
+	bool		credHandle_valid;
+
+	/* client certificate to send to server */
+	CERT_CONTEXT *clientCert;
+	/* Root certificate for validating server certificates */
+	CERT_CONTEXT *rootCert;
+
+	HandshakeState handshakeState;
+	bool		remote_shutdown;
+
+	/*
+	 * Buffer for encrypting data to be written.
+	 *
+	 * When encryptedLen > 0, the buffer contains some encrypted data that
+	 * should be written out to the client.
+	 *
+	 * When encryptedLen == 0, call encryptBuffer() to load the buffer with
+	 * more data, and encrypt it.
+	 */
+	char	   *encryptBuffer;
+	int			encryptBufferSize;
+	int			encryptBufferLen;
+
+	char	   *encryptedData;
+	size_t		encryptedLen;
+
+	/*
+	 * Number of plaintext bytes the buffer currently holds in encrypted form.
+	 * This is less than the number of encrypted bytes, because the SSL
+	 * protocol adds framing. (it could also be more, when compression is used)
+	 */
+	int			plaintextLen;
+
+	/*
+	 * Buffer for decrypting read data.
+	 *
+	 * decryptBufferSize is the allocated size of decryptBuffer.
+	 * decryptBufferLen is the number of ciphertext bytes loaded to the buffer.
+	 *
+	 * The buffer can be in one of two states. In the first state, it contains
+	 * zero or more raw bytes, and more can be loaded into it. In the other
+	 * state, it contains decrypted data that can be read out.
+	 *
+	 * When the buffer contains decrypted data, decryptedLen > 0, and
+	 * decryptedData points to the data. The buffer can also contain some
+	 * leftover raw data that has not been decrypted yet (extraData/extraLen).
+	 *
+	 * Before reading more raw data to the buffer, call
+	 * prepareDecryptBufferForRead. It moves any leftover raw data to the
+	 * beginning of the buffer.
+	 */
+	char	   *decryptBuffer;
+	int			decryptBufferSize;
+	int			decryptBufferLen; 	/* ciphertext bytes loaded in decryptBuffer */
+
+	/* decrypted data not returned to the caller yet */
+	char	   *decryptedData;
+	int			decryptedLen;
+
+	char	   *extraData;
+	int			extraLen;
+};
+
+typedef struct SchannelContext SchannelContext;
+
+/*
+ * Somewhat arbitrarily, use a 10k buffer for both input and output.
+ */
+#define BUFSIZE 10000
+
+/* Functions for managing the encrypt/decrypt buffers */
+static ssize_t encryptBuffer(PGconn *conn, const void *ptr, int len);
+static void prepareDecryptBufferForRead(SchannelContext *ctx);
+static int decryptBuffer(PGconn *conn);
+
+/* Functions for dealing with certificates */
+static bool loadCerts(PGconn *conn);
+static bool validateServerCert(PGconn *conn);
+
+/* Functions for converting error codes to strings */
+static const char *getSSLPolicyStatusCode(DWORD dwerror);
+static const char *getSecurityStatus(SECURITY_STATUS dwerror);
+
+void
+pgtls_init_library(bool do_ssl, int do_crypto)
+{
+}
+
+
+/*
+ * Initialize SSL system, in particular creating the SSL_context object
+ * that will be shared by all SSL-using connections in this process.
+ *
+ * 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)
+{
+	/* nothing to do here ATM */
+	return 0;
+}
+
+
+/*
+ *	Begin or continue negotiating a secure session.
+ */
+PostgresPollingStatusType
+pgtls_open_client(PGconn *conn)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	SecBufferDesc outsbufdesc;
+	SecBuffer	outsbufs[1];
+	SecBufferDesc insbufdesc;
+	SecBuffer	insbufs[2];
+	SECURITY_STATUS rc;
+	DWORD		flags;
+	DWORD		outflags;
+	int			n;
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "pgtls_open_client called: %d\n", ctx ? ctx->handshakeState : -1);
+	fflush(stderr);
+#endif
+
+	/* On first call, allocate the context struct and buffers */
+	if (ctx == NULL)
+	{
+		ctx = (SchannelContext *) malloc(sizeof(SchannelContext));
+		if (ctx == NULL)
+		{
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("out of memory\n"));
+			return PGRES_POLLING_FAILED;
+		}
+		memset(ctx, 0, sizeof(SchannelContext));
+		conn->windows_schannel = ctx;
+
+		ctx->encryptBufferSize = BUFSIZE;
+		ctx->encryptBuffer = malloc(ctx->encryptBufferSize);
+		if (ctx->encryptBuffer == NULL)
+		{
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("out of memory\n"));
+			return PGRES_POLLING_FAILED;
+		}
+
+		ctx->decryptBufferSize = BUFSIZE;
+		ctx->decryptBuffer = malloc(ctx->encryptBufferSize);
+		if (ctx->decryptBuffer == NULL)
+		{
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("out of memory\n"));
+			return PGRES_POLLING_FAILED;
+		}
+
+		ctx->handshakeState = ISC_INIT;
+
+		conn->windows_schannel = ctx;
+		conn->ssl_in_use = true;
+	}
+
+	if (!ctx->credHandle_valid)
+	{
+		SCHANNEL_CRED credData;
+
+		if (!loadCerts(conn))
+		{
+			pgtls_close(conn);
+			return PGRES_POLLING_FAILED;
+		}
+
+		memset(&credData, 0, sizeof(credData));
+		credData.dwVersion = SCHANNEL_CRED_VERSION;
+		credData.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK |
+			SCH_CRED_NO_DEFAULT_CREDS |
+			SCH_CRED_MANUAL_CRED_VALIDATION;
+		if (ctx->clientCert)
+		{
+			credData.cCreds = 1;
+			credData.paCred = &ctx->clientCert;
+		}
+		else
+			credData.cCreds = 0;
+
+		/* FIXME: check server cert */
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "calling AcquireCredentialsHandle\n");
+		fflush(stderr);
+#endif
+		rc = AcquireCredentialsHandle(NULL,
+									  UNISP_NAME,
+									  SECPKG_CRED_OUTBOUND,
+									  NULL,
+									  &credData,
+									  NULL,
+									  NULL,
+									  &ctx->credHandle,
+									  NULL);
+		if (rc != SEC_E_OK)
+		{
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("could not acquire credentials handle: %s\n"),
+							  getSecurityStatus(rc));
+			return PGRES_POLLING_FAILED;
+		}
+		ctx->credHandle_valid = true;
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "AcquireCredentialsHandle succeeded\n");
+		fflush(stderr);
+#endif
+	}
+
+	/* If we have any pending outgoing data, flush that first */
+	if (ctx->handshakeState == ISC_NEED_WRITE ||
+		ctx->handshakeState == ISC_FINAL_WRITE)
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "Sending %d handshake bytes\n",
+				ctx->encryptedLen);
+		fflush(stderr);
+#endif
+		n = pqsecure_raw_write(conn, ctx->encryptBuffer, ctx->encryptedLen);
+		if (n < 0)
+		{
+			int result_errno = SOCK_ERRNO;
+			if (result_errno == EINTR
+#ifdef EAGAIN
+				|| result_errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+				|| result_errno == EWOULDBLOCK)
+#endif
+			{
+				return PGRES_POLLING_WRITING;
+			}
+			else
+			{
+				pgtls_close(conn);
+				/* pqsecure_raw_write already set error message */
+				return PGRES_POLLING_FAILED;
+			}
+		}
+		ctx->encryptedData += n;
+		ctx->encryptedLen -= n;
+		if (ctx->encryptedLen > 0)
+			return PGRES_POLLING_WRITING;
+		else
+		{
+			if (ctx->handshakeState == ISC_NEED_WRITE)
+			{
+				/*
+				 * Successfully sent the data to client that
+				 * InitializeSecurityContext asked us to sent. Now wait for
+				 * a reply.
+				 */
+				ctx->handshakeState = ISC_NEED_READ;
+			}
+			else
+			{
+				ctx->handshakeState = ISC_COMPLETED;
+				return PGRES_POLLING_OK;
+			}
+		}
+	}
+
+	/* call InitializeSecurityContext */
+
+	flags = ISC_REQ_ALLOCATE_MEMORY |
+		ISC_REQ_CONFIDENTIALITY |
+		ISC_RET_EXTENDED_ERROR |
+		ISC_REQ_REPLAY_DETECT |
+		ISC_REQ_SEQUENCE_DETECT |
+		ISC_REQ_STREAM |
+		ISC_REQ_MANUAL_CRED_VALIDATION;
+
+	outsbufs[0].pvBuffer   = NULL;
+	outsbufs[0].BufferType = SECBUFFER_TOKEN;
+	outsbufs[0].cbBuffer   = 0;
+
+	outsbufdesc.cBuffers = 1;
+	outsbufdesc.pBuffers = outsbufs;
+	outsbufdesc.ulVersion = SECBUFFER_VERSION;
+
+	/* Read some data if needed */
+	if (ctx->handshakeState == ISC_NEED_READ)
+	{
+		int			maxsize;
+		int			readlen;
+
+		/* read more data to buffer */
+		maxsize = ctx->decryptBufferSize - ctx->decryptBufferLen;
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "reading maxsize %d buflen %d\n", maxsize, ctx->decryptBufferLen);
+		fflush(stderr);
+#endif
+		readlen = pqsecure_raw_read(conn,
+									&ctx->decryptBuffer[ctx->decryptBufferLen],
+									maxsize);
+		fprintf(stderr, "received %d bytes in handshake\n", readlen);
+		fflush(stderr);
+		if (readlen < 0)
+		{
+			int result_errno = SOCK_ERRNO;
+			if (result_errno == EINTR
+#ifdef EAGAIN
+				|| result_errno == EAGAIN
+#endif
+#ifdef EWOULDBLOCK
+				|| result_errno == EWOULDBLOCK)
+#endif
+			{
+				return PGRES_POLLING_READING;
+			}
+
+			pgtls_close(conn);
+			/* pqsecure_raw_read set error message */
+			return PGRES_POLLING_FAILED;
+		}
+
+		ctx->decryptBufferLen += readlen;
+	}
+
+	/*
+	 * On first call, don't pass input buffer. The function will return
+	 * a context. On subsequent calls, pass any input data in a buffer,
+	 * and pass the handle we got on first call.
+	 */
+	if (ctx->handshakeState == ISC_INIT)
+	{
+		rc = InitializeSecurityContext(&ctx->credHandle,
+									   NULL,
+									   NULL,
+									   flags,
+									   0,
+									   0,
+									   NULL,
+									   0,
+									   &ctx->ctxHandle,
+									   &outsbufdesc,
+									   &outflags,
+									   NULL);
+	}
+	else
+	{
+		insbufs[0].pvBuffer = ctx->decryptBuffer;
+		insbufs[0].cbBuffer = ctx->decryptBufferLen;
+		insbufs[0].BufferType = SECBUFFER_TOKEN;
+
+		insbufs[1].pvBuffer = NULL;
+		insbufs[1].cbBuffer = 0;
+		insbufs[1].BufferType = SECBUFFER_EMPTY;
+
+		insbufdesc.cBuffers = 2;
+		insbufdesc.pBuffers = insbufs;
+		insbufdesc.ulVersion = SECBUFFER_VERSION;
+
+		rc = InitializeSecurityContext(&ctx->credHandle,
+									   &ctx->ctxHandle,
+									   NULL,
+									   flags,
+									   0,
+									   0,
+									   &insbufdesc,
+									   0,
+									   NULL,
+									   &outsbufdesc,
+									   &outflags,
+									   NULL);
+		/*
+		 * The following return codes are considered success, in the sense
+		 * that a context was created and must eventually be destroyed to
+		 * avoid leaking memory.
+		 */
+		if (rc == SEC_I_COMPLETE_AND_CONTINUE ||
+			rc == SEC_I_COMPLETE_NEEDED ||
+			rc == SEC_I_CONTINUE_NEEDED ||
+			rc == SEC_I_INCOMPLETE_CREDENTIALS ||
+			rc == SEC_E_INCOMPLETE_MESSAGE ||
+			rc == SEC_E_OK)
+		{
+			ctx->ctxHandle_valid = true;
+		}
+	}
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "InitializeSecurityContext returned %x\n", (unsigned int) rc);
+	fflush(stderr);
+#endif
+
+	if (rc == SEC_E_OK || rc == SEC_I_CONTINUE_NEEDED)
+	{
+		size_t outLen;
+
+		/*
+		 * InitializeSecurityContext might not have consumed all of the input
+		 * data.
+		 */
+		if (ctx->handshakeState == ISC_NEED_READ)
+		{
+			if (insbufs[1].BufferType == SECBUFFER_EXTRA)
+			{
+				int extraLen = insbufs[1].cbBuffer;
+
+				memmove(ctx->decryptBuffer,
+						&ctx->decryptBuffer[ctx->decryptBufferLen - extraLen],
+						extraLen);
+				ctx->decryptBufferLen = extraLen;
+			}
+			else
+				ctx->decryptBufferLen = 0;
+		}
+
+		/*
+		 * Must send the token that InitializeSecurityContext put in the
+		 * output buffer (if any).
+		 */
+		outLen = outsbufs[0].cbBuffer;
+		if (outLen > 0)
+		{
+			/* enlarge the output buffer if required. */
+			if (outLen > ctx->encryptBufferSize)
+			{
+				char	   *newbuf;
+				newbuf = realloc(ctx->encryptBuffer, outsbufs[0].cbBuffer);
+				if (newbuf == NULL)
+				{
+					pgtls_close(conn);
+					printfPQExpBuffer(&conn->errorMessage,
+									  libpq_gettext("out of memory\n"));
+					return PGRES_POLLING_FAILED;
+				}
+				ctx->encryptBuffer = newbuf;
+				ctx->encryptBufferSize = outLen;
+			}
+			memcpy(ctx->encryptBuffer, outsbufs[0].pvBuffer, outLen);
+			ctx->encryptedData = ctx->encryptBuffer;
+			ctx->encryptedLen = outLen;
+
+			FreeContextBuffer(outsbufs[0].pvBuffer);
+		}
+	}
+
+	switch(rc)
+	{
+		case SEC_E_OK:
+			/*
+			 * SSL handshake is complete. But we might still have some
+			 * data pending in the output buffer.
+			 */
+			if (!validateServerCert(conn))
+			{
+				pgtls_close(conn);
+				return PGRES_POLLING_FAILED;
+			}
+
+			if (ctx->encryptedLen > 0)
+			{
+				ctx->handshakeState = ISC_FINAL_WRITE;
+				return PGRES_POLLING_WRITING;
+			}
+
+			return PGRES_POLLING_OK;
+
+		case SEC_I_COMPLETE_AND_CONTINUE:
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_I_COMPLETE_AND_CONTINUE not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		case SEC_I_COMPLETE_NEEDED:
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_I_COMPLETE_NEEDED not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		case SEC_I_CONTINUE_NEEDED:
+			/*
+			 * Write the output data that InitializeSecurityContext returned,
+			 * and wait for reply.
+			 */
+			ctx->handshakeState = ISC_NEED_WRITE;
+			return PGRES_POLLING_WRITING;
+
+		case SEC_I_INCOMPLETE_CREDENTIALS:
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_I_INCOMPLETE_CREDENTIALS not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		case SEC_E_INCOMPLETE_MESSAGE:
+			/* read more input data and retry */
+			ctx->handshakeState = ISC_NEED_READ;
+			return PGRES_POLLING_READING;
+
+		default:
+			pgtls_close(conn);
+			printfPQExpBuffer(&conn->errorMessage,
+							  "InitializeSecurityContext failed: %s\n",
+							  getSecurityStatus(rc));
+			return PGRES_POLLING_FAILED;
+	}
+	/* not reached */
+
+fail:
+	pgtls_close(conn);
+	return PGRES_POLLING_FAILED;
+}
+
+/*
+ *	Close SSL connection.
+ */
+void
+pgtls_close(PGconn *conn)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+
+	/* TODO: should do a proper SSL shutdown. */
+
+	if (ctx)
+	{
+		if (ctx->encryptBuffer)
+			free(ctx->encryptBuffer);
+		if (ctx->decryptBuffer)
+			free(ctx->decryptBuffer);
+
+		if (ctx->credHandle_valid)
+			FreeCredentialsHandle(&ctx->credHandle);
+
+		if (ctx->ctxHandle_valid)
+			DeleteSecurityContext(&ctx->ctxHandle);
+
+		free(ctx);
+		conn->windows_schannel = NULL;
+	}
+	conn->ssl_in_use = false;
+}
+
+/*
+ *	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, char *buffer, size_t len)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	int			readlen;
+	int			maxsize;
+	size_t		totalreadlen = 0;
+	char	   *dst = buffer;
+
+	for (;;)
+	{
+		/* if we already have some decrypted data, copy it to the target buffer */
+		if (ctx->decryptedLen > 0)
+		{
+			maxsize = len - totalreadlen;
+			if (maxsize > ctx->decryptedLen)
+				maxsize = ctx->decryptedLen;
+			memcpy(dst, &ctx->decryptedData[totalreadlen], maxsize);
+			dst += maxsize;
+			totalreadlen += maxsize;
+			ctx->decryptedLen -= maxsize;
+			ctx->decryptedData += maxsize;
+		}
+
+		/* If we have some data to return, return it. */
+		if (totalreadlen > 0)
+		{
+			return totalreadlen;
+		}
+
+		/*
+		 * there shouldn't be any decrypted data left in the buffer, we copied
+		 * it all to the target.
+		 */
+		Assert(ctx->decryptedLen == 0);
+
+		/*
+		 * Need to decrypt more data, and for that, need to read more raw
+		 * data.
+		 */
+		prepareDecryptBufferForRead(ctx);
+		while (ctx->decryptedLen == 0)
+		{
+			/* read more data to buffer */
+			maxsize = ctx->decryptBufferSize - ctx->decryptBufferLen;
+			readlen = pqsecure_raw_read(conn,
+										&ctx->decryptBuffer[ctx->decryptBufferLen],
+										maxsize);
+			if (readlen < 0)
+				return readlen;
+			if (readlen == 0)
+			{
+				/* this implies we're in non-blocking mode */
+				return totalreadlen;
+			}
+
+			ctx->decryptBufferLen += readlen;
+
+			/* decrypt what we got */
+			if (decryptBuffer(conn) == -1)
+				return -1;
+			if (ctx->remote_shutdown)
+				return totalreadlen;
+
+			/* If decryptBuffer needs more data, decrypteLen is still 0. */
+		}
+	}
+
+	return totalreadlen;
+}
+
+
+/*
+ * Prepare the buffer for reading in more cipher text.
+ */
+static void
+prepareDecryptBufferForRead(SchannelContext *ctx)
+{
+	/*
+	 * should've consumed all the previous decrypted data in the buffer befor
+	 * decrypting more.
+	 */
+	Assert(ctx->decryptedLen == 0);
+
+	/*
+	 * If there's any ciphertext left in the buffer from previous round, move
+	 * it to beginning.
+	 */
+	if (ctx->extraLen > 0)
+		memmove(ctx->decryptBuffer,	ctx->extraData,	ctx->extraLen);
+	ctx->decryptBufferLen = ctx->extraLen;
+	ctx->extraData = NULL;
+	ctx->extraLen = 0;
+	ctx->decryptedData = NULL;
+	ctx->decryptedLen = 0;
+}
+
+/*
+ * Try to decrypt the data currently in decryptBuffer. On success,
+ * decryptedData points to the decrypted data. DecryptMessage decrypts
+ * in-place, so decryptedData points to somewhere within the buffer!
+ *
+ * On success, returns 1. On error, returns -1. If more raw data is needed
+ * to decrypt, returns 0. If the client shut down the connection, also
+ * returns 0, and sets ctx->remote_shutdown flag.
+ */
+static int
+decryptBuffer(PGconn *conn)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	/*
+	 * Call DecryptBuffer until it returns some data, fails, or indicates that
+	 * it needs more input
+	 */
+	while(ctx->decryptedLen == 0)
+	{
+		SecBufferDesc sbufdesc;
+		SecBuffer	sbufs[4];
+		SECURITY_STATUS rc;
+		int			i;
+
+		Assert(ctx->decryptBufferLen > 0);
+		Assert(ctx->extraLen == 0);
+
+		sbufs[0].pvBuffer = ctx->decryptBuffer;
+		sbufs[0].cbBuffer = ctx->decryptBufferLen;
+		sbufs[0].BufferType = SECBUFFER_DATA;
+		sbufs[1].pvBuffer = NULL;
+		sbufs[1].cbBuffer = 0;
+		sbufs[1].BufferType   = SECBUFFER_EMPTY;
+		sbufs[2].pvBuffer = NULL;
+		sbufs[2].cbBuffer = 0;
+		sbufs[2].BufferType   = SECBUFFER_EMPTY;
+		sbufs[3].pvBuffer = NULL;
+		sbufs[3].cbBuffer = 0;
+		sbufs[3].BufferType   = SECBUFFER_EMPTY;
+
+		sbufdesc.ulVersion = SECBUFFER_VERSION;
+		sbufdesc.cBuffers = 4;
+		sbufdesc.pBuffers = sbufs;
+
+		rc = DecryptMessage(&ctx->ctxHandle, &sbufdesc, 0, NULL);
+
+		if (rc == SEC_E_INCOMPLETE_MESSAGE)
+		{
+			/* We don't have the full message yet. Need more data. */
+			return 0;
+		}
+		if (rc == SEC_I_CONTEXT_EXPIRED)
+		{
+			ctx->remote_shutdown = true;
+			return 0;
+		}
+		if (rc == SEC_I_RENEGOTIATE)
+		{
+			/* TODO */
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("SSL renegotiation not implemented\n\n"));
+			return -1;
+		}
+		if (rc != SEC_E_OK)
+		{
+			/* FIXME: set errno */
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("could not decrypt received data: %s\n"),
+							  getSecurityStatus(rc));
+			return -1;
+		}
+
+		for (i = 0; i < 4; i++)
+		{
+			if (sbufs[i].BufferType == SECBUFFER_EXTRA)
+			{
+				ctx->extraData = sbufs[i].pvBuffer;
+				ctx->extraLen = sbufs[i].cbBuffer;
+			}
+			if (sbufs[i].BufferType == SECBUFFER_DATA)
+			{
+				ctx->decryptedData = sbufs[i].pvBuffer;
+				ctx->decryptedLen = sbufs[i].cbBuffer;
+			}
+		}
+		if (ctx->decryptedLen == 0)
+		{
+			/*
+			 * DecryptMessage didn't decrypt anything. Shift the extra data
+			 * to beginning of buffer, and retry.
+			 */
+			prepareDecryptBufferForRead(ctx);
+		}
+	}
+
+	return 1;
+}
+
+/*
+ *	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)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	int			sendlen;
+
+	/*
+	 * If the output buffer is empty, encrypt (some of) the input data to fill
+	 * it.
+	 */
+	if (ctx->encryptedLen == 0)
+	{
+		int			plaintextLen;
+
+		plaintextLen = encryptBuffer(conn, ptr, len);
+		if (plaintextLen < 0)
+			return -1;
+		ctx->plaintextLen = plaintextLen;
+	}
+
+	/*
+	 * Write out the encrypted data in the buffer
+	 */
+	sendlen = pqsecure_raw_write(conn,
+								 ctx->encryptedData,
+								 ctx->encryptedLen);
+	if (sendlen <= 0)
+		return sendlen;
+
+	ctx->encryptedData += sendlen;
+	ctx->encryptedLen -= sendlen;
+
+	if (ctx->encryptedLen == 0)
+	{
+		/* sent all the data in the buffer. */
+		return ctx->plaintextLen;
+	}
+	else
+	{
+		/* return 0 to indicate that the caller has to retry. */
+		return 0;
+	}
+}
+
+
+/*
+ * Encrypt more data. Helper function for pgtls_write().
+ */
+static ssize_t
+encryptBuffer(PGconn *conn, const void *ptr, int len)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	SecPkgContext_StreamSizes sizes;
+	SecBufferDesc sbufdesc;
+	SecBuffer	sbufs[4];
+	SECURITY_STATUS rc;
+
+	/* we should've sent out all encrypted data from previous round first */
+	Assert(ctx->encryptedLen == 0);
+
+	rc = QueryContextAttributes(&ctx->ctxHandle,
+								SECPKG_ATTR_STREAM_SIZES, &sizes);
+	if (rc != SEC_E_OK)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("QueryContextAttributes failed: %x"),
+						  rc);
+		return -1;
+	}
+	if (sizes.cbHeader + sizes.cbTrailer + len > ctx->encryptBufferSize)
+		len = ctx->encryptBufferSize - (sizes.cbHeader + sizes.cbTrailer);
+
+	memcpy(&ctx->encryptBuffer[sizes.cbHeader], ptr, len);
+
+	sbufs[0].pvBuffer = ctx->encryptBuffer;
+	sbufs[0].cbBuffer = sizes.cbHeader;
+	sbufs[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+	sbufs[1].pvBuffer = &ctx->encryptBuffer[sizes.cbHeader];
+	sbufs[1].cbBuffer = len;
+	sbufs[1].BufferType = SECBUFFER_DATA;
+
+	sbufs[2].pvBuffer = &ctx->encryptBuffer[sizes.cbHeader + len];
+	sbufs[2].cbBuffer = sizes.cbTrailer;
+	sbufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+	sbufs[3].pvBuffer = NULL;
+	sbufs[3].cbBuffer = 0;
+	sbufs[3].BufferType = SECBUFFER_EMPTY;
+
+	sbufdesc.ulVersion = SECBUFFER_VERSION;
+	sbufdesc.cBuffers = 4;
+	sbufdesc.pBuffers = sbufs;
+
+	rc = EncryptMessage(&ctx->ctxHandle, 0, &sbufdesc, 0);
+	if (rc != SEC_E_OK)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("EncryptMessage failed: %x"),
+						  rc);
+		return -1;
+	}
+
+	ctx->encryptedData = ctx->encryptBuffer;
+	ctx->encryptedLen = sbufs[0].cbBuffer + sbufs[1].cbBuffer + sbufs[2].cbBuffer;
+
+	return len;
+}
+
+/**** Certificate handling functions ****/
+
+static bool
+validateServerCert(PGconn *conn)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	CERT_CONTEXT *remoteCert;
+	SECURITY_STATUS rc;
+	DWORD flags;
+
+	/* Get server certificate */
+	rc = QueryContextAttributes(&ctx->ctxHandle,
+								SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+								(PVOID) &remoteCert);
+	if (rc != SEC_E_OK)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not get server certificate: %s\n"),
+						  getSecurityStatus(rc));
+		return false;
+	}
+
+	/*
+	 * Per MSDN documentation [1], we must check the following things:
+	 *
+	 * 1. The certificate chain is complete and the root is a certificate from
+	 *    a trusted certification authority (CA).
+	 * 2. The current time is not beyond the begin and end dates for each of
+	 *    the certificates in the certificate chain.
+	 * 3. None of the certificates in the certificate chain have been revoked.
+	 * 4. The depth of the leaf certificate is not deeper than the maximum
+	 *    allowable depth specified in the certificate extension. This check is
+	 *    only necessary if there is a depth specified.
+	 * 5. The usage of the certificate is correct, for example, a client
+	 *    certificate should not be used to authenticate a server.
+	 *
+	 * [1] "Manually Validating Schannel Credential",
+	 *     http://msdn.microsoft.com/en-us/library/windows/desktop/aa378740%28v=vs.85%29.aspx
+	 */
+
+	/*
+	 * 1. Check the chain
+	 * 2. Check expiration
+	 *
+	 * TODO: Currently, we only support client certs signed by the root client
+	 * CA. Intermediary CA's are not supported.
+	 */
+
+	/* TODO: CRL's are not actually supported */
+	flags = CERT_STORE_SIGNATURE_FLAG |
+		CERT_STORE_TIME_VALIDITY_FLAG;
+	if (!CertVerifySubjectCertificateContext(
+			remoteCert,
+			ctx->rootCert,
+			&flags))
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not verify server certificate\n"));
+		return false;
+	}
+	if (flags != 0)
+	{
+		if ((flags & CERT_STORE_SIGNATURE_FLAG) != 0)
+			printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("signature check failed on client cert\n"));
+		else if ((flags & CERT_STORE_REVOCATION_FLAG) != 0)
+			printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("server certificate was revoked\n"));
+		else if ((flags & CERT_STORE_TIME_VALIDITY_FLAG) != 0)
+			printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("server certificate is not valid at this time\n"));
+		else
+			printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("server certificate is not valid\n"));
+
+		return false;
+	}
+
+	/*
+	 * We succeeded to get the issuer's certificate from the trusted root store,
+	 * and the signature on the client cert passed, so we're good to go.
+	 */
+
+	return true;
+}
+
+
+/*
+ * Loads the certificate into a Certificate Context.
+ *
+ * on error, sets an error message in conn and returns NULL.
+ */
+static CERT_CONTEXT *
+loadCert(PGconn *conn, char *path)
+{
+	CERT_CONTEXT *cert_cxt;
+	char		crtBuf[50000]; /* TODO: enlarge as needed */
+	DWORD		crtBufLen = 50000;
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *content;
+	int			r;
+	int			filelen;
+
+	/* Read file into memory */
+	if (stat(path, &statbuf) != 0)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not stat certificate file \"%s\""),
+						  path);
+		return NULL;
+	}
+	filelen = statbuf.st_size;
+
+	fp = fopen(path, "rb");
+	if (!fp)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not open certificate file \"%s\""),
+						  path);
+		return NULL;
+	}
+	content = malloc(filelen);
+	r = fread(content, filelen, 1, fp);
+	if (r != 1 || ferror(fp) || fclose(fp))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not read certificate file \"%s\""),
+						  path);
+		return NULL;
+	}
+
+	/* convert from PEM to DER */
+	if (!CryptStringToBinary(
+			content,
+			filelen,
+			CRYPT_STRING_BASE64HEADER,
+			crtBuf,
+			&crtBufLen,
+			NULL,
+			NULL))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not convert certificate file \"%s\" from PEM format"),
+						  path);
+		return NULL;
+	}
+	if (crtBufLen > sizeof(crtBuf))
+	{
+		/* TODO: enlarge buffer */
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("out of memory"));
+		return NULL;
+	}
+
+	cert_cxt = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+											crtBuf,
+											crtBufLen);
+	if (cert_cxt == NULL)
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not create certificate context"));
+		return NULL;
+	}
+
+	return cert_cxt;
+
+}
+
+static bool
+loadPrivateKey(PGconn *conn, CERT_CONTEXT *cert, char *path)
+{
+	char		keyBuf[50000]; /* TODO: enlarge as needed */
+	DWORD		keyBufLen = 50000;
+	CERT_KEY_PROV_INFO key;
+	HCRYPTPROV	cryptProvHandle;
+	HCRYPTKEY	keyHandle;
+	PUBLICKEYSTRUC *blob;
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *content;
+	int			r;
+	int			filelen;
+	char		privKeyBlob[50000];
+	int			privKeyBlobLen = 50000;
+
+	/* Read file into memory */
+	if (stat(path, &statbuf) != 0)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not read private key file \"%s\""),
+						  path);
+		return false;
+	}
+	filelen = statbuf.st_size;
+
+	fp = fopen(path, "rb");
+	if (!fp)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not read private key file \"%s\""),
+						  path);
+		return false;
+	}
+	content = malloc(filelen);
+	r = fread(content, filelen, 1, fp);
+	if (r != 1 || ferror(fp) || fclose(fp))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not read private key file \"%s\""),
+						  path);
+		return false;
+	}
+
+	/* convert from PEM to DER */
+	if (!CryptStringToBinary(
+			content,
+			filelen,
+			CRYPT_STRING_BASE64HEADER,
+			keyBuf,
+			&keyBufLen,
+			NULL,
+			NULL))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not convert private key file \"%s\" from PEM format"),
+						  path);
+		return false;
+	}
+	if (keyBufLen > sizeof(keyBuf))
+	{
+		/* TODO: enlarge buffer */
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("out of memory"));
+		return false;
+	}
+
+	/*
+	 * Load the key.
+	 */
+	if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+							 PKCS_RSA_PRIVATE_KEY,
+							 keyBuf,
+							 keyBufLen,
+							 0,
+							 NULL,
+							 privKeyBlob,
+							 &privKeyBlobLen))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+					  libpq_gettext("could not parse private key file \"%s\""),
+						  path);
+		return false;
+	}
+	blob = (PUBLICKEYSTRUC *) privKeyBlob;
+
+	if (!CryptAcquireContext(&cryptProvHandle, "mycontainer", MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("CryptAcquireContext failed"));
+		return false;
+	}
+
+	if (!CryptImportKey(cryptProvHandle, privKeyBlob, privKeyBlobLen,
+						(HCRYPTKEY) NULL, 0, &keyHandle))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("CryptAcquireContext failed"));
+		return false;
+	}
+
+	memset(&keyCtx, 0, sizeof(keyCtx));
+	keyCtx.cbSize = sizeof(keyCtx);
+	keyCtx.hCryptProv = cryptProvHandle;
+	keyCtx.dwKeySpec = AT_KEYEXCHANGE;
+
+	if (!CertSetCertificateContextProperty(cert,
+										   CERT_KEY_CONTEXT_PROP_ID,
+										   0,
+										   &keyCtx))
+	{
+		free(content);
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("CertSetCertificateContextProperty failed"));
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+loadCerts(PGconn *conn)
+{
+	SchannelContext *ctx = conn->windows_schannel;
+	char	   *sslcertfile = NULL;
+	char	   *engine = NULL;
+	char	   *keyname = NULL;
+	char	   *sslkeyfile = NULL;
+	char	   *sslrootcert = NULL;
+	char	   *sslcrl = NULL;
+	bool		ret = false;
+
+	if (!pqsecure_get_ssl_files(conn, &sslcertfile, &engine, &keyname, &sslkeyfile,
+								&sslrootcert, &sslcrl))
+		return false;
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "files: %s %s %s\n",
+			sslcertfile ? sslcertfile : "<no client cert>",
+			sslkeyfile ? sslkeyfile : "<no client key>",
+			sslrootcert ? sslrootcert : "<no root cert>",
+			sslcrl ? sslcrl : "<no crl>");
+	fflush(stderr);
+#endif
+
+	if (engine || keyname)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("engines not supported"));
+		goto fail;
+	}
+
+	if (sslcertfile)
+	{
+		ctx->clientCert = loadCert(conn, sslcertfile);
+		if (ctx->clientCert == NULL)
+			goto fail;
+
+		/*
+		 * Cool, got the client cert. Also load the private key associated
+		 * with it.
+		 */
+		if (!loadPrivateKey(conn, ctx->clientCert, sslkeyfile))
+			goto fail;
+	}
+
+	/* Load root certificate for validating server certificates */
+	if (sslrootcert)
+	{
+		ctx->rootCert = loadCert(conn, sslrootcert);
+		if (ctx->rootCert == NULL)
+			goto fail;
+	}
+
+	ret = true;
+
+fail:
+	if (sslcertfile)
+		free(sslcertfile);
+	if (engine)
+		free(engine);
+	if (keyname)
+		free(keyname);
+	if (sslkeyfile)
+		free(sslkeyfile);
+	if (sslrootcert)
+		free(sslrootcert);
+	if (sslcrl)
+		free(sslcrl);
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "certs loaded: %d\n", ret);
+	fflush(stderr);
+#endif
+
+	return ret;
+}
+
+
+/*
+ *	TODO: need a new API for this.
+ */
+void *
+PQgetssl(PGconn *conn)
+{
+	/*
+	 * return non-zero, so that psql reports that SSL is used. Of course, it's
+	 * totally bogus for anyone who actually tries to get the OpenSSL
+	 * SSL struct.
+	 */
+	return (void *) 1;
+}
+
+/*** Printing error codes ***/
+
+#define ERRORCODE_STR(x) { x, #x }
+
+typedef struct
+{
+	uint32 rc;
+	const char *str;
+} errorcode_str;
+
+static const char *
+getErrorStr(uint32 rc, errorcode_str *map)
+{
+	static char buf[100];
+	int i;
+
+	for (i = 0; map[i].str != NULL; i++)
+	{
+		if (map[i].rc == rc)
+			return map[i].str;
+	}
+	snprintf(buf, sizeof(buf), "0x%X", rc);
+	return buf;
+}
+
+static const char *
+getSecurityStatus(SECURITY_STATUS rc)
+{
+	static errorcode_str sec_status_codes[] = {
+		ERRORCODE_STR(SEC_E_OK),
+		ERRORCODE_STR(SEC_E_INCOMPLETE_MESSAGE),
+		ERRORCODE_STR(SEC_E_INSUFFICIENT_MEMORY),
+		ERRORCODE_STR(SEC_E_INTERNAL_ERROR),
+		ERRORCODE_STR(SEC_E_INVALID_HANDLE),
+		ERRORCODE_STR(SEC_E_INVALID_TOKEN),
+		ERRORCODE_STR(SEC_E_LOGON_DENIED),
+		ERRORCODE_STR(SEC_E_NO_AUTHENTICATING_AUTHORITY),
+		ERRORCODE_STR(SEC_E_NO_CREDENTIALS),
+		ERRORCODE_STR(SEC_I_COMPLETE_AND_CONTINUE),
+		ERRORCODE_STR(SEC_I_COMPLETE_NEEDED),
+		ERRORCODE_STR(SEC_I_CONTINUE_NEEDED),
+
+		ERRORCODE_STR(SEC_E_ALGORITHM_MISMATCH),
+		ERRORCODE_STR(SEC_E_UNSUPPORTED_FUNCTION),
+		ERRORCODE_STR(SEC_E_UNTRUSTED_ROOT),
+		{ 0, NULL }
+	};
+	return getErrorStr(rc, sec_status_codes);
+}
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 66778b2..e19fc61 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -475,3 +475,297 @@ pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
 }
 
 #endif   /* ENABLE_THREAD_SAFETY && !WIN32 */
+
+/*
+ *	Determine the filenames of SSL related files.
+ *
+ * The filenames returned are checked to exist; the caller should throw an
+ * error if one of the returned files can not be opened. This function
+ * performs some preliminariry sanity checks, e.g. if a certificate file
+ * exists, we must also find the corresponding private key file.
+ *
+ * *sslcert is set to the path of the client's certificate, and *sslkey to
+ * the path to the corresponding private key.  If compiled with
+ * USE_SSL_ENGINE, a pathname containing a colon is interpreted as a
+ * a two-part "engin:key" string, for specifying a hardware key.
+ *
+ * *sslrootcert and *sslcrl are set to the paths to CA certificate and
+ * CRL files, used to validate the server certificate.
+ *
+ * The returned strings are malloc'd, and the caller is responsible for
+ * freeing them. On error, returns false and sets the libpq error message.
+ */
+bool
+pqsecure_get_ssl_files(PGconn *conn, char **sslcert, char **sslkey,
+					   char **engine, char **keyname,
+					   char **sslrootcert, char **sslcrl)
+{
+	struct stat buf;
+	char		homedir[MAXPGPATH];
+	char		fnbuf[MAXPGPATH];
+	char		sebuf[256];
+	bool		have_homedir;
+
+	*sslcert = NULL;
+	*sslkey = NULL;
+	*engine = NULL;
+	*keyname = NULL;
+	*sslrootcert = NULL;
+	*sslcrl = 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;
+
+	/* Find 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 */
+	}
+	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)));
+			goto fail;
+		}
+	}
+	else
+	{
+		*sslcert = strdup(fnbuf);
+		if (*sslcert == NULL)
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("out of memory\n"));
+			goto fail;
+		}
+	}
+
+	/*
+	 * 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 (*sslcert && 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"));
+				goto fail;
+			}
+
+			/* 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 */
+
+			*engine = strdup(engine_str);
+			if (*engine)
+				*keyname = strdup(engine_colon);
+
+			free(engine_str);
+
+			if (*engine == NULL || *keyname == NULL)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext("out of memory\n"));
+				goto fail;
+			}
+
+			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 (*sslcert && 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);
+			goto fail;
+		}
+#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);
+			goto fail;
+		}
+#endif
+
+		*sslkey = strdup(fnbuf);
+		if (*sslkey == NULL)
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("out of memory\n"));
+			goto fail;
+		}
+	}
+
+	/*
+	 * 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)
+	{
+		*sslrootcert = strdup(fnbuf);
+		if (*sslrootcert == NULL)
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  libpq_gettext("out of memory\n"));
+			goto fail;
+		}
+	}
+	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);
+			goto fail;
+		}
+	}
+
+	/* If we have a root certificate, also try to load a CRL */
+	if (*sslrootcert)
+	{
+		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';
+
+		if (fnbuf[0] != '\0' &&
+			stat(fnbuf, &buf) != 0)
+		{
+			/*
+			 * If not found, silently ignore;  we do not require CRL.
+			 * 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)));
+				goto fail;
+			}
+		}
+		else
+		{
+			*sslcrl = strdup(fnbuf);
+			if (*sslcrl == NULL)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext("out of memory\n"));
+				goto fail;
+			}
+		}
+	}
+
+	/* all done! */
+	return true;
+
+fail:
+	if (*sslcert)
+		free(*sslcert);
+	if (*engine)
+		free(*engine);
+	if (*keyname)
+		free(*keyname);
+	if (*sslkey)
+		free(*sslkey);
+	if (*sslrootcert)
+		free(*sslrootcert);
+	if (*sslcrl)
+		free(*sslcrl);
+
+	*sslcert = NULL;
+	*engine = NULL;
+	*keyname = NULL;
+	*sslkey = NULL;
+	*sslrootcert = NULL;
+	*sslcrl = NULL;
+
+	return false;
+}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 6032904..35b1c9e 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -82,6 +82,10 @@ typedef struct
 #endif
 #endif   /* USE_OPENSSL */
 
+#ifdef USE_WINDOWS_SCHANNEL
+struct SchannelContext;
+#endif
+
 /*
  * POSTGRES backend dependent Constants.
  */
@@ -440,6 +444,10 @@ struct pg_conn
 #endif   /* USE_OPENSSL */
 #endif   /* USE_SSL */
 
+#ifdef USE_WINDOWS_SCHANNEL
+	struct SchannelContext *windows_schannel;
+#endif   /* USE_WINDOWS_SCHANNEL */
+
 #ifdef ENABLE_GSS
 	gss_ctx_id_t gctx;			/* GSS context */
 	gss_name_t	gtarg_nam;		/* GSS target name */
@@ -627,6 +635,8 @@ 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);
 
+extern bool pqsecure_get_ssl_files(PGconn *, char **sslcert, char **sslkey, char **engine, char **keyname, char **sslrootcert, char **sslcrl);
+
 #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
 extern int	pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending);
 extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending,
diff --git a/src/interfaces/libpq/win32.mak b/src/interfaces/libpq/win32.mak
index 39a0bc9..5793fce 100644
--- a/src/interfaces/libpq/win32.mak
+++ b/src/interfaces/libpq/win32.mak
@@ -127,6 +127,9 @@ CLEAN :
 !IFDEF USE_OPENSSL
 	-@erase "$(INTDIR)\fe-secure-openssl.obj"
 !ENDIF
+!IFDEF USE_WINDOWS_SCHANNEL
+	-@erase "$(INTDIR)\fe-secure-winschannel.obj"
+!ENDIF
 
 
 LIB32=link.exe -lib
@@ -170,7 +173,9 @@ LIB32_OBJS= \
 !IFDEF USE_OPENSSL
 	LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-openssl.obj"
 !ENDIF
-
+!IFDEF USE_WINDOWS_SCHANNEL
+	LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-winschannel.obj"
+!ENDIF
 
 config: ..\..\include\pg_config.h ..\..\include\pg_config_ext.h pg_config_paths.h  ..\..\include\pg_config_os.h
 
@@ -200,6 +205,11 @@ CPP_PROJ=$(CPP_PROJ) /D USE_OPENSSL
 SSL_LIBS=ssleay32.lib libeay32.lib gdi32.lib
 !ENDIF
 
+!IFDEF USE_WINDOWS_SCHANNEL
+CPP_PROJ=$(CPP_PROJ) /D USE_WINDOWS_SCHANNEL
+SSL_LIBS=crypt32.lib
+!ENDIF
+
 !IFDEF USE_KFW
 CPP_PROJ=$(CPP_PROJ) /D KRB5
 KFW_LIBS=krb5_32.lib comerr32.lib gssapi32.lib
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index e6fb3ec..fa2ac8c 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -115,6 +115,10 @@ sub mkvcbuild
 	$postgres->AddDefine('BUILDING_DLL');
 	$postgres->AddLibrary('secur32.lib');
 	$postgres->AddLibrary('ws2_32.lib');
+	if ($solution->{options}->{winschannel})
+	{
+		$postgres->AddLibrary('crypt32.lib');
+	}
 	$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
 	$postgres->FullExportDLL('postgres.lib');
 	# The OBJS scraper doesn't know about ifdefs, so remove be-secure-openssl.c
@@ -123,6 +127,11 @@ sub mkvcbuild
 	{
 		$postgres->RemoveFile('src\backend\libpq\be-secure-openssl.c');
 	}
+	# and same for winschannel
+	if (!$solution->{options}->{winschannel})
+	{
+		$postgres->RemoveFile('src\backend\libpq\be-secure-winschannel.c');
+	}
 
 	my $snowball = $solution->AddProject('dict_snowball', 'dll', '',
 		'src\backend\snowball');
@@ -276,6 +285,10 @@ sub mkvcbuild
 	$libpq->AddDefine('UNSAFE_STAT_OK');
 	$libpq->AddIncludeDir('src\port');
 	$libpq->AddLibrary('secur32.lib');
+	if ($solution->{options}->{winschannel})
+	{
+		$libpq->AddLibrary('crypt32.lib');
+	}
 	$libpq->AddLibrary('ws2_32.lib');
 	$libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
 	$libpq->UseDef('src\interfaces\libpq\libpqdll.def');
@@ -288,6 +301,11 @@ sub mkvcbuild
 	{
 		$libpq->RemoveFile('src\interfaces\libpq\fe-secure-openssl.c');
 	}
+	# and same for winschannel
+	if (!$solution->{options}->{winschannel})
+	{
+		$libpq->RemoveFile('src\interfaces\libpq\fe-secure-winschannel.c');
+	}
 
 	my $libpqwalreceiver =
 	  $solution->AddProject('libpqwalreceiver', 'dll', '',
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 39e41f6..7034eea 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -183,6 +183,8 @@ sub GenerateFiles
 		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_OPENSSL 1\n" if ($self->{options}->{openssl});
+		print O "#define USE_WINDOWS_SCHANNEL 1\n"
+		  if ($self->{options}->{winschannel});
 		print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls});
 
 		print O "#define BLCKSZ ", 1024 * $self->{options}->{blocksize}, "\n";
@@ -629,6 +631,7 @@ sub GetFakeConfigure
 	$cfg .= ' --without-zlib' unless ($self->{options}->{zlib});
 	$cfg .= ' --with-extra-version' if ($self->{options}->{extraver});
 	$cfg .= ' --with-openssl'       if ($self->{options}->{openssl});
+	$cfg .= ' --with-winschannel'   if ($self->{options}->{winschannel});
 	$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 e4d4810..ab4001a 100644
--- a/src/tools/msvc/config_default.pl
+++ b/src/tools/msvc/config_default.pl
@@ -17,6 +17,7 @@ our $config = {
 	perl     => undef,   # --with-perl
 	python   => undef,   # --with-python=<path>
 	openssl  => undef,   # --with-openssl=<path>
+	winschannel => 1,    # --with-winschannel
 	uuid     => undef,   # --with-ossp-uuid
 	xml      => undef,   # --with-libxml=<path>
 	xslt     => undef,   # --with-libxslt=<path>
