From 7f8258e911779138e7271f42cf75e2dd414e86be Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 11 Jun 2014 00:39:28 +0300
Subject: [PATCH 2/2] Add crude version of Windows SChannel support.

libpq only ATM, no server-side support
---
 configure                                    |  47 +-
 configure.in                                 |  14 +
 src/backend/libpq/Makefile                   |   4 +
 src/backend/libpq/be-secure-winschannel.c    |  64 +++
 src/include/pg_config.h.in                   |   3 +
 src/include/pg_config.h.win32                |   3 +
 src/include/port.h                           |   5 +-
 src/interfaces/libpq/Makefile                |   4 +
 src/interfaces/libpq/fe-secure-winschannel.c | 822 +++++++++++++++++++++++++++
 src/interfaces/libpq/libpq-int.h             |  13 +-
 src/interfaces/libpq/win32.mak               |  12 +
 src/tools/msvc/Mkvcbuild.pm                  |  18 +
 src/tools/msvc/Solution.pm                   |   3 +
 src/tools/msvc/config_default.pl             |   1 +
 14 files changed, 1008 insertions(+), 5 deletions(-)
 create mode 100644 src/backend/libpq/be-secure-winschannel.c
 create mode 100644 src/interfaces/libpq/fe-secure-winschannel.c

diff --git a/configure b/configure
index 0e6b109..6244e38 100755
--- a/configure
+++ b/configure
@@ -708,6 +708,7 @@ XML2_CONFIG
 UUID_EXTRA_OBJS
 with_uuid
 with_selinux
+with_winschannel
 with_openssl
 krb_srvtab
 with_python
@@ -824,6 +825,7 @@ with_pam
 with_ldap
 with_bonjour
 with_openssl
+with_winschannel
 with_selinux
 with_readline
 with_libedit_preferred
@@ -1510,6 +1512,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
@@ -5516,6 +5519,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
@@ -10940,7 +10983,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -10964,7 +11007,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
diff --git a/configure.in b/configure.in
index 4bdd0f7..e1452da 100644
--- a/configure.in
+++ b/configure.in
@@ -663,6 +663,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-winschannel.c b/src/backend/libpq/be-secure-winschannel.c
new file mode 100644
index 0000000..5fee673
--- /dev/null
+++ b/src/backend/libpq/be-secure-winschannel.c
@@ -0,0 +1,64 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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
+ *
+ *	  TODO: this is just a dummy placeholder
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "libpq/libpq-be.h"
+
+/*
+ *	Write data to a secure connection.
+ */
+ssize_t
+be_tls_write(Port *port, void *ptr, size_t len)
+{
+	elog(ERROR, "be_tls_write not implemented");
+	return -1;
+}
+
+/*
+ *	Initialize global SSL context.
+ */
+void
+be_tls_init(void)
+{
+}
+
+/*
+ *	Attempt to negotiate SSL connection.
+ */
+int
+be_tls_open_server(Port *port)
+{
+	return -1;
+}
+
+/*
+ *	Close SSL connection.
+ */
+void
+be_tls_close(Port *port)
+{
+}
+
+ssize_t
+be_tls_read(Port *port, void *ptr, size_t len)
+{
+	elog(ERROR, "be_tls_read not implemented");
+	return -1;
+}
+
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 0a0e0d4..a9f7171 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -803,6 +803,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 6a6d2f3..c4f8ec4 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -650,6 +650,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/port.h b/src/include/port.h
index 7d2e0c4..c8b19d5 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -472,9 +472,10 @@ extern char *escape_single_quotes_ascii(const char *src);
 /* port/wait_error.c */
 extern char *wait_result_to_str(int exit_status);
 
-/* If we're building with OpenSSL, then we have SSL support */
+/* If we're building with OpenSSL or Windows SChannel, then we have SSL
+ * support */
 /* XXX: this doesn't belong here.. I couldn't find a precedence to follow */
-#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 7827ac0..3b11b5b 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-winschannel.c b/src/interfaces/libpq/fe-secure-winschannel.c
new file mode 100644
index 0000000..efdbd98
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-winschannel.c
@@ -0,0 +1,822 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-winschannel.c
+ *	  functions for 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-winschannel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+
+#include "win32.h"
+
+#include <sspi.h>
+#include <schnlsp.h>
+
+struct SchannelContext
+{
+	SecPkgContext_StreamSizes sizes;
+	CtxtHandle  ctxHandle;
+
+	char	   *encryptBuffer;
+	int			encryptBufferSize;
+	int			encryptBufferLen;
+	int			encryptBufferPos;
+	int			plaintextLen;
+	bool		encrypted;
+
+	char	   *decryptBuffer;
+	int			decryptBufferSize;
+	/*
+	 * These are the length and position of the ciphertext left in the buffer,
+	 * that hasn't been decrypted yet.
+	 */
+	int			decryptBufferLen;
+
+	/* decrypted data not returned to the caller yet */
+	char	   *decryptedData;
+	int			decryptedLen;
+
+	/*
+	 * extra data not decrypted yet (this is normally a pointer somewhere
+	 * in decryptBuffer
+	 */
+	char	   *extraData;
+	int			extraLen;
+};
+
+typedef struct SchannelContext SchannelContext;
+
+#define BUFSIZE 10000
+
+static CERT_CONTEXT *getClientCert();
+
+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];
+	CredHandle credHandle;
+	SECURITY_STATUS rc;
+	DWORD		flags;
+	DWORD		outflags;
+	int			n;
+	bool		first_call = (ctx == NULL);
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "pgtls_open_client called: %p\n", conn->windows_schannel);
+	fflush(stderr);
+#endif
+
+	if (first_call)
+	{
+		SCHANNEL_CRED credData;
+		CERT_CONTEXT *cert;
+
+		cert = getClientCert();
+
+		memset(&credData, 0, sizeof(credData));
+		credData.dwVersion = SCHANNEL_CRED_VERSION;
+		credData.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK |
+			SCH_CRED_MANUAL_CRED_VALIDATION; /* FIXME */
+		credData.cCreds = 1;
+		credData.paCred = &cert;
+
+		ctx = (SchannelContext *) malloc(sizeof(SchannelContext));
+		if (ctx == NULL)
+			goto fail;
+		memset(ctx, 0, sizeof(SchannelContext));
+
+		/* FIXME: check server cert */
+		rc = AcquireCredentialsHandle(NULL,
+									  UNISP_NAME,
+									  SECPKG_CRED_OUTBOUND,
+									  NULL,
+									  &credData,
+									  NULL,
+									  NULL,
+									  &credHandle,
+									  NULL);
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "AcquireCredentialsHandle returned %x\n", rc);
+		fflush(stderr);
+#endif
+		if (rc != SEC_E_OK)
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  "AcquireCredentialsHandle failed: %d\n", rc);
+			goto fail;
+		}
+
+		ctx->encryptBufferSize = ctx->decryptBufferSize =
+			BUFSIZE;
+		ctx->encryptBuffer = malloc(ctx->encryptBufferSize);
+		if (ctx->encryptBuffer == NULL)
+			goto fail;
+
+		ctx->decryptBuffer = malloc(ctx->encryptBufferSize);
+		if (ctx->decryptBuffer == NULL)
+			goto fail;
+
+		conn->windows_schannel = ctx;
+		conn->ssl_in_use = true;
+	}
+	else
+	{
+		int			maxsize;
+		int			readlen;
+
+		/* read more data to buffer, and decrypt */
+		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)
+			return PGRES_POLLING_FAILED; /* FIXME: error msg? */
+
+		ctx->decryptBufferLen += readlen;
+
+		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;
+
+		/* consume the input */
+		ctx->decryptBufferLen = 0;
+	}
+
+	flags = ISC_REQ_ALLOCATE_MEMORY |
+		ISC_REQ_CONFIDENTIALITY |
+		ISC_RET_EXTENDED_ERROR |
+		ISC_REQ_REPLAY_DETECT |
+		ISC_REQ_SEQUENCE_DETECT |
+		ISC_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 = InitializeSecurityContext(&credHandle,
+								   first_call ? NULL : &ctx->ctxHandle,
+								   NULL, /* pszTargetName */
+								   flags,
+								   0,
+								   0,
+								   first_call ? NULL : &insbufdesc,
+								   0,
+								   first_call ? &ctx->ctxHandle : NULL,
+								   &outsbufdesc,
+								   &outflags,
+								   NULL);
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "InitializeSecurityContext returned %x\n", (unsigned int) rc);
+	fflush(stderr);
+#endif
+
+	conn->windows_schannel = ctx;
+
+	switch(rc)
+	{
+		case SEC_E_OK:
+			/* SSL handshake is complete */
+			return PGRES_POLLING_OK;
+
+		case SEC_I_COMPLETE_AND_CONTINUE:
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_I_COMPLETE_AND_CONTINUE not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		case SEC_I_COMPLETE_NEEDED:
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_I_COMPLETE_NEEDED not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		case SEC_I_CONTINUE_NEEDED:
+			/*
+			 * Must send the token that InitializeSecurityContext put in
+			 * the out buffer.
+			 */
+#ifdef SCHANNEL_DEBUG
+			fprintf(stderr, "got SEC_I_CONTINUE_NEEDED. Sending %d bytes\n",
+					outsbufs[0].cbBuffer);
+			fflush(stderr);
+#endif
+			n = pqsecure_raw_write(conn,
+								   outsbufs[0].pvBuffer,
+								   outsbufs[0].cbBuffer);
+			if (n != outsbufs[0].cbBuffer)
+			{
+				printfPQExpBuffer(&conn->errorMessage,
+								  "short write\n", rc);
+				return PGRES_POLLING_FAILED;
+			}
+			FreeContextBuffer(outsbufs[0].pvBuffer);
+			outsbufs[0].pvBuffer = NULL;
+
+			return PGRES_POLLING_READING;
+
+		case SEC_I_INCOMPLETE_CREDENTIALS:
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_I_INCOMPLETE_CREDENTIALS not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		case SEC_E_INCOMPLETE_MESSAGE:
+			printfPQExpBuffer(&conn->errorMessage,
+							  "SEC_E_INCOMPLETE_MESSAGE not implemented\n", rc);
+			return PGRES_POLLING_FAILED;
+
+		default:
+			printfPQExpBuffer(&conn->errorMessage,
+							  "InitializeSecurityContext failed: %d\n", rc);
+			return PGRES_POLLING_FAILED;
+	}
+
+	rc = QueryContextAttributes(&ctx->ctxHandle,
+								SECPKG_ATTR_STREAM_SIZES, &ctx->sizes);
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "QueryContextAttributes returned %d\n", rc);
+	fflush(stderr);
+#endif
+	if (rc != SEC_E_OK)
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  "QueryContextAttributes failed: %d\n", rc);
+		goto fail; /* FIXME: set errno */
+	}
+
+	/* SSL handshake is complete */
+	return PGRES_POLLING_OK;
+
+fail:
+	if (ctx->decryptBuffer)
+		free(ctx->decryptBuffer);
+	if (ctx->encryptBuffer)
+		free(ctx->encryptBuffer);
+	if (ctx)
+		free(ctx);
+
+	return PGRES_POLLING_FAILED;
+}
+
+
+/*
+ *	Close SSL connection.
+ */
+void
+pgtls_close(PGconn *conn)
+{
+	/* TODO: Not implemented. We just leak everything */
+
+	if (conn->ssl_in_use)
+	{
+		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;
+	SecBufferDesc sbufdesc;
+	SecBuffer	sbufs[4];
+	int			readlen;
+	int			maxsize;
+	int			rc;
+	int			i;
+	int			totalreadlen = 0;
+	int			origlen = len;
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "pgtls_read called\n");
+	fflush(stderr);
+#endif
+
+	if (ctx->decryptedLen == 0)
+	{
+		/* read more data to buffer, and decrypt */
+		maxsize = ctx->decryptBufferSize - ctx->decryptBufferLen;
+		readlen = pqsecure_raw_read(conn,
+									&ctx->decryptBuffer[ctx->decryptBufferLen],
+									maxsize);
+		if (readlen < 0)
+			return readlen;
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "pgtls_read read %d bytes\n", readlen);
+		fflush(stderr);
+#endif
+
+		ctx->decryptBufferLen += readlen;
+	}
+
+retry:
+	if (ctx->decryptedLen == 0)
+	{
+		/* try to decrypt what we got */
+
+		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);
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "DecryptMessage returned %d\n", rc);
+		fflush(stderr);
+#endif
+
+		if (rc == SEC_E_INCOMPLETE_MESSAGE)
+		{
+			/* We don't have the full message yet. Need more data. */
+			return totalreadlen;
+		}
+		if (rc != SEC_E_OK && rc != SEC_I_RENEGOTIATE)
+		{
+			/* FIXME: set errno */
+			printfPQExpBuffer(&conn->errorMessage,
+							  "DecryptMessage failed: %d\n", rc);
+			return -1;
+		}
+
+		/* Did we not decrypt everything? */
+		ctx->extraData = NULL;
+		ctx->extraLen = 0;
+		ctx->decryptedData = NULL;
+		ctx->decryptedLen = 0;
+		for (i = 0; i < 4; i++)
+		{
+			if (sbufs[i].BufferType == SECBUFFER_EXTRA)
+			{
+				ctx->extraData = sbufs[i].pvBuffer;
+				ctx->extraLen = sbufs[i].cbBuffer;
+#ifdef SCHANNEL_DEBUG
+				fprintf(stderr, "found %d extra bytes\n", sbufs[i].cbBuffer);
+				fflush(stderr);
+#endif
+			}
+			if (sbufs[i].BufferType == SECBUFFER_DATA)
+			{
+				ctx->decryptedData = sbufs[i].pvBuffer;
+				ctx->decryptedLen = sbufs[i].cbBuffer;
+#ifdef SCHANNEL_DEBUG
+				fprintf(stderr, "found %d data bytes\n", sbufs[i].cbBuffer);
+				fflush(stderr);
+#endif
+			}
+		}
+	}
+
+	/* we should now have some decrypted data in the buffer. Return it */
+	readlen = len;
+	if (readlen > ctx->decryptedLen)
+		readlen = ctx->decryptedLen;
+
+	memcpy(buffer, ctx->decryptedData, readlen);
+	ctx->decryptedData += readlen;
+	ctx->decryptedLen -= readlen;
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "returning %d decrypted bytes (%d in total, %d max)\n", readlen, totalreadlen, origlen);
+	fflush(stderr);
+#endif
+
+	if (ctx->decryptedLen == 0)
+	{
+		/*
+		 * Finished returning this message. If there's some extra data in the
+		 * buffer, move it to beginning of buffer for next call.
+		 */
+		if (ctx->extraData > 0)
+		{
+			memmove(ctx->decryptBuffer,
+					ctx->extraData,
+					ctx->extraLen);
+#ifdef SCHANNEL_DEBUG
+			fprintf(stderr, "shifted %d extra bytes\n", ctx->extraLen);
+			fflush(stderr);
+#endif
+		}
+		ctx->decryptBufferLen = ctx->extraLen;
+		ctx->extraData = NULL;
+		ctx->extraLen = 0;
+	}
+
+	/*
+	 * If we decrypted some data, but it yielded 0 plaintext bytes (i.e. it
+	 * was all SSL's internal protocol stuff), try again.
+	 */
+	if (readlen == 0)
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "schannel_read got 0 bytes, retrying\n");
+		fflush(stderr);
+#endif
+		goto retry;
+	}
+
+	totalreadlen += readlen;
+
+	/*
+	 * If the target buffer has some room left, and we have more data in the
+	 * buffer that we could decrypt and yield more output, try that.
+	 */
+	if (readlen < len && ctx->decryptBufferLen > 0)
+	{
+		buffer += readlen;
+		len -= readlen;
+		goto retry;
+	}
+
+	return totalreadlen;
+}
+
+/*
+ *	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;
+	SecBufferDesc sbufdesc;
+	SecBuffer	sbufs[4];
+	int			sendlen;
+	SECURITY_STATUS rc;
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "pgtls_write called %d\n", len);
+	fflush(stderr);
+#endif
+	if (!ctx->encrypted)
+	{
+		sendlen = len;
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "pgtls_write sizes before %d + %d + %d\n",
+			ctx->sizes.cbHeader + ctx->sizes.cbMaximumMessage + ctx->sizes.cbTrailer);
+		fflush(stderr);
+#endif
+
+		rc = QueryContextAttributes(&ctx->ctxHandle,
+									SECPKG_ATTR_STREAM_SIZES, &ctx->sizes);
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "QueryContextAttributes returned %d\n", rc);
+		fflush(stderr);
+#endif
+		if (rc != SEC_E_OK)
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  "QueryContextAttributes failed: %d\n", rc);
+			return -1; /* FIXME: set errno */
+		}
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "pgtls_write sizes after %d + %d + %d\n",
+			ctx->sizes.cbHeader + ctx->sizes.cbMaximumMessage + ctx->sizes.cbTrailer);
+		fflush(stderr);
+#endif
+
+		if (ctx->sizes.cbHeader + ctx->sizes.cbTrailer + sendlen > ctx->encryptBufferSize)
+			sendlen = ctx->encryptBufferSize - (ctx->sizes.cbHeader + ctx->sizes.cbTrailer);
+
+		memcpy(&ctx->encryptBuffer[ctx->sizes.cbHeader], ptr, sendlen);
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "pgtls_write sendlen %d\n", sendlen);
+		fflush(stderr);
+#endif
+
+		sbufs[0].pvBuffer = ctx->encryptBuffer;
+		sbufs[0].cbBuffer = ctx->sizes.cbHeader;
+		sbufs[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+		sbufs[1].pvBuffer = &ctx->encryptBuffer[ctx->sizes.cbHeader];
+		sbufs[1].cbBuffer = sendlen;
+		sbufs[1].BufferType = SECBUFFER_DATA;
+
+		sbufs[2].pvBuffer = &ctx->encryptBuffer[ctx->sizes.cbHeader + sendlen];
+		sbufs[2].cbBuffer = ctx->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;
+
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "encrypting %d + %d + %d bytes\n",
+				sbufs[0].cbBuffer, sbufs[1].cbBuffer, sbufs[2].cbBuffer);
+		fflush(stderr);
+#endif
+		rc = EncryptMessage(&ctx->ctxHandle, 0, &sbufdesc, 0);
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "returned %d\n", rc),
+		fflush(stderr);
+#endif
+		if (rc != SEC_E_OK)
+		{
+			printfPQExpBuffer(&conn->errorMessage,
+							  "EncryptMessage failed: %d\n", rc);
+			return -1;
+		}
+
+		ctx->encryptBufferLen = sbufs[0].cbBuffer + sbufs[1].cbBuffer + sbufs[2].cbBuffer;
+		ctx->encryptBufferPos = 0;
+		ctx->plaintextLen = sendlen;
+		ctx->encrypted = true;
+	}
+
+	/* we now have some encrypted data in the buffer. Send it. */
+	sendlen = pqsecure_raw_write(conn,
+								 &ctx->encryptBuffer[ctx->encryptBufferPos],
+								 ctx->encryptBufferLen - ctx->encryptBufferPos);
+	if (sendlen <= 0)
+		return sendlen;
+
+	ctx->encryptBufferPos += sendlen;
+
+	if (ctx->encryptBufferPos == ctx->encryptBufferLen)
+	{
+		/* sent all the data in the buffer. */
+		ctx->encrypted = false;
+		return ctx->plaintextLen;
+	}
+	else
+		return 0;
+}
+
+static const char *keyStr =
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQC8K4U6m1APskR3VY277O3fp1/aEMC2UbgohFL2y/jo1Ij2tqr6\n"
+"dxIzwOD/KqjQ2/4DSEoGINDx8RObiLF4HWK6JhN135zn4gs++gN4DDYcZbWV107q\n"
+"zcq3G4FgH8obuUUl7BIWT2NuzfPw9nOJjGkE2ySCW27Iv0/yGG3Jv7am1QIDAQAB\n"
+"AoGAeP4S4KhVRoJ9+62LQTcLjS/2NiVnhNPu8j6DiiWFm1Bt8RVrwzkk/xoakng/\n"
+"rGyIXFvzHRWkxK0aynuOgYmDnMoQhil5aMvemnR7ANJP5JXq3J5sl1ghB1HdBtxd\n"
+"UhbpyoE3NMjHDBi6XDPiIut6w4wusc7EQxCa/L0yNZJ4R9ECQQD2b9/VyEaAwvib\n"
+"Y9UhHf8/KoUt4eC5MUDwDYPqmhyZZniq9D5ucgGQNHdPEK+yJQKcq+j/bo1vNzwu\n"
+"P49/cdrPAkEAw3jRGXVDeitLk0wJYhxr8b4nCMWHcIYfR6NvYlXwLbi2LbDF311W\n"
+"Zo6T+zsm8k/4YnhR1fMlrj8ScqfOxKr9GwJBAN/fIeiD2AiBFneTabp8FbS8W+Ai\n"
+"opOaOvPYU058Uh7JCDXFTDHpP6JRB1G8Rt/+3zCUu0XQmIvAEduxwhp0w+ECQQCq\n"
+"WKqY7glM+VgWWIhA2RX1CUqJKWMb27Z8vuA9qTjzD2qsLMZ0HqpCG/S4V1dcifaj\n"
+"Ecn3krr+u/Z+tuDJoV2LAkB9BHZbcdrYAOpWNfKJ3YyIOmb5ZMabDgav3QTGUXWN\n"
+"hLgVhgidvb6xa3zT2Ps2C8PvsIGpD5d3UzdJvUwcCZfP\n"
+	"-----END RSA PRIVATE KEY-----\n";
+
+static const char	*crtStr =
+"-----BEGIN CERTIFICATE-----\n"
+"MIICMjCCAZsCCQCyIo/FfT60NzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJG\n"
+"STETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\n"
+"cyBQdHkgTHRkMQ8wDQYDVQQDDAZIZWlra2kxHjAcBgkqhkiG9w0BCQEWD2hsaW5u\n"
+"YWthQGlraS5maTAeFw0xNDA2MDkxMzM0MzJaFw0xNDA3MDkxMzM0MzJaMEUxCzAJ\n"
+"BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l\n"
+"dCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALwr\n"
+"hTqbUA+yRHdVjbvs7d+nX9oQwLZRuCiEUvbL+OjUiPa2qvp3EjPA4P8qqNDb/gNI\n"
+"SgYg0PHxE5uIsXgdYromE3XfnOfiCz76A3gMNhxltZXXTurNyrcbgWAfyhu5RSXs\n"
+"EhZPY27N8/D2c4mMaQTbJIJbbsi/T/IYbcm/tqbVAgMBAAEwDQYJKoZIhvcNAQEL\n"
+"BQADgYEAjvK0hCMzGrAawUmSlf7SnCGv3fwjCVDka9NusHX16TQaFP4E1pYBQYkY\n"
+"vKwkSj+bZTrw7fWDHKpGXghS1S8JdqSMOG0uLeqTa2dasnj1SnhbTafK6VgUPB3U\n"
+"J/30HV9WioBqX+4tUzUEvLNl3JYbO4Rd4BX5Kzq2QkrtMX+yPaM=\n"
+	"-----END CERTIFICATE-----\n";
+
+/*
+ * Loads the certificate and associated private key into a Certificate
+ * Context.
+ */
+static CERT_CONTEXT *
+getClientCert()
+{
+	CERT_CONTEXT *cert_cxt;
+	char		crtBuf[50000]; /* TODO: enlarge as needed */
+	DWORD		crtBufLen = 50000;
+	char		keyBuf[50000]; /* TODO: enlarge as needed */
+	DWORD		keyBufLen = 50000;
+	char		privKeyBlob[50000];
+	int			privKeyBlobLen = 50000;
+	CERT_KEY_CONTEXT keyCtx;
+	HCRYPTPROV	cryptProvHandle;
+	HCRYPTKEY	keyHandle;
+	PUBLICKEYSTRUC *blob;
+
+	/* TODO: read cert from file */
+
+
+	/* convert from PEM to DER */
+	if (!CryptStringToBinary(
+			crtStr,
+			strlen(crtStr),
+			CRYPT_STRING_BASE64HEADER,
+			crtBuf,
+			&crtBufLen,
+			NULL,
+			NULL))
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "CryptStringToBinary failed: %d\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+
+	cert_cxt = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+											crtBuf,
+											crtBufLen);
+	if (cert_cxt == NULL)
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "CertCreateCertificateContext failed: %x\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "CertCreateCertificateContext succeeded!\n");
+	fflush(stderr);
+#endif
+
+	/*
+	 * Cool, got the cert. But we also need to get the private key associated
+	 * with it.
+	 */
+
+	/* convert from PEM to DER */
+	if (!CryptStringToBinary(
+			keyStr,
+			strlen(keyStr),
+			CRYPT_STRING_BASE64HEADER,
+			keyBuf,
+			&keyBufLen,
+			NULL,
+			NULL))
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "CryptStringToBinary failed: %d\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+
+	/*
+	 * Get private key
+	 */
+	if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+							 PKCS_RSA_PRIVATE_KEY,
+							 keyBuf,
+							 keyBufLen,
+							 0,
+							 NULL,
+							 privKeyBlob,
+							 &privKeyBlobLen))
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "CryptDecodeObjectEx failed: %x\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+	blob = (PUBLICKEYSTRUC *) privKeyBlob;
+
+#ifdef SCHANNEL_DEBUG
+	fprintf(stderr, "decoded bType %d bVersion %d, alg %d len %d\n",
+			blob->bType, blob->bVersion, blob->aiKeyAlg, privKeyBlobLen);
+	fflush(stderr);
+#endif
+
+	if (!CryptAcquireContext(&cryptProvHandle, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "CryptAcquireContext failed: %x\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+
+	if (!CryptImportKey(cryptProvHandle, privKeyBlob, privKeyBlobLen,
+						(HCRYPTKEY) NULL, 0, &keyHandle))
+	{
+#ifdef SCHANNEL_DEBUG
+        fprintf(stderr, "CryptImportKey failed: %x\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+
+	memset(&keyCtx, 0, sizeof(keyCtx));
+	keyCtx.cbSize = sizeof(keyCtx);
+	keyCtx.hCryptProv = cryptProvHandle;
+	keyCtx.dwKeySpec = AT_KEYEXCHANGE;
+
+	if (!CertSetCertificateContextProperty(cert_cxt,
+										   CERT_KEY_CONTEXT_PROP_ID,
+										   0,
+										   &keyCtx))
+	{
+#ifdef SCHANNEL_DEBUG
+		fprintf(stderr, "CertSetCertificateContextProperty failed: %x\n", GetLastError());
+		fflush(stderr);
+#endif
+		return NULL;
+	}
+
+	return cert_cxt;
+}
+
+
+
+/*
+ *	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;
+}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 6032904..4a1b413 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.
  */
@@ -428,6 +432,7 @@ struct pg_conn
 	bool		wait_ssl_try;	/* Delay SSL negotiation until after
 								 * attempting normal connection */
 	bool		ssl_in_use;
+
 #ifdef USE_OPENSSL
 	SSL		   *ssl;			/* SSL status, if have SSL connection */
 	X509	   *peer;			/* X509 cert of server */
@@ -438,6 +443,11 @@ struct pg_conn
 								 * OpenSSL version changes */
 #endif
 #endif   /* USE_OPENSSL */
+
+#ifdef USE_WINDOWS_SCHANNEL
+
+#endif	/* USE_WINDOWS_SCHANNEL */
+	struct SchannelContext *windows_schannel;
 #endif   /* USE_SSL */
 
 #ifdef ENABLE_GSS
@@ -634,7 +644,8 @@ extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending,
 #endif
 
 /*
- * The SSL implementatation provides these functions (fe-secure-openssl.c)
+ * The SSL implementation provides these functions (i.e. fe-secure-openssl.c
+ * or fe-secure-winschannel.c)
  */
 extern void pgtls_init_library(bool do_ssl, int do_crypto);
 extern int pgtls_init(PGconn *conn);
diff --git a/src/interfaces/libpq/win32.mak b/src/interfaces/libpq/win32.mak
index 79b6d49..6a78917 100644
--- a/src/interfaces/libpq/win32.mak
+++ b/src/interfaces/libpq/win32.mak
@@ -101,6 +101,12 @@ CLEAN :
 	-@erase "$(INTDIR)\fe-misc.obj"
 	-@erase "$(INTDIR)\fe-print.obj"
 	-@erase "$(INTDIR)\fe-secure.obj"
+!IFDEF USE_OPENSSL
+	-@erase "$(INTDIR)\fe-secure-openssl.obj"
+!ENDIF
+!IFDEF USE_WINDOWS_SCHANNEL
+	-@erase "$(INTDIR)\fe-secure-winschannel.obj"
+!ENDIF
 	-@erase "$(INTDIR)\libpq-events.obj"
 	-@erase "$(INTDIR)\pqexpbuffer.obj"
 	-@erase "$(INTDIR)\win32.obj"
@@ -171,6 +177,12 @@ LIB32_OBJS= \
 	LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-openssl.obj"
 !ENDIF
 
+!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
 
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index af231ba..d29f450 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -116,6 +116,10 @@ sub mkvcbuild
 	$postgres->AddLibrary('wsock32.lib');
 	$postgres->AddLibrary('ws2_32.lib');
 	$postgres->AddLibrary('secur32.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 fe-secure-openssl.c
@@ -124,6 +128,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');
@@ -278,6 +287,10 @@ sub mkvcbuild
 	$libpq->AddIncludeDir('src\port');
 	$libpq->AddLibrary('wsock32.lib');
 	$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');
@@ -290,6 +303,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 f66d1f6..8031acb 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -181,6 +181,8 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY
 		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";
@@ -625,6 +627,7 @@ sub GetFakeConfigure
 	$cfg .= ' --with-ldap'  if ($self->{options}->{ldap});
 	$cfg .= ' --without-zlib' unless ($self->{options}->{zlib});
 	$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 7c04de0..62bc9ab 100644
--- a/src/tools/msvc/config_default.pl
+++ b/src/tools/msvc/config_default.pl
@@ -16,6 +16,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>
-- 
2.0.0

