From 403604b99aaebedaa8e409604f5c2ced584bd15f Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 15:19:54 +0200
Subject: [PATCH 01/55] Removed specific SSL libraries list from https_getsock
 fallback

---
 lib/http.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/lib/http.c b/lib/http.c
index 0ce575b..15a325c 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1398,8 +1398,6 @@ static int https_getsock(struct connectdata *conn,
   return CURLE_OK;
 }
 #else
-#if defined(USE_NSS) || defined(USE_QSOSSL) || \
-  defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_CYASSL)
 static int https_getsock(struct connectdata *conn,
                          curl_socket_t *socks,
                          int numsocks)
@@ -1409,7 +1407,6 @@ static int https_getsock(struct connectdata *conn,
   (void)numsocks;
   return GETSOCK_BLANK;
 }
-#endif /* USE_AXTLS || USE_POLARSSL || USE_QSOSSL || USE_NSS */
 #endif /* USE_SSLEAY || USE_GNUTLS */
 
 /*
-- 
1.7.9


From 15f8c036246b65fddd74dfc1b854c12dc58229f9 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 15:40:06 +0200
Subject: [PATCH 02/55] Added SSL/TLS support using Microsoft Windows Schannel
 SSPI

---
 lib/curl_schannel.c |  828 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/curl_schannel.h |   63 ++++
 lib/sslgen.c        |    2 +
 lib/urldata.h       |   17 +
 4 files changed, 910 insertions(+), 0 deletions(-)
 create mode 100755 lib/curl_schannel.c
 create mode 100755 lib/curl_schannel.h

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
new file mode 100755
index 0000000..af0b584
--- /dev/null
+++ b/lib/curl_schannel.c
@@ -0,0 +1,828 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all SChannel-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ *
+ */
+
+/*
+ * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
+ *   Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
+ *   Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * Thanks for code and inspiration!
+ */
+
+/*
+ * TODO list for TLS/SSL implementation:
+ * - implement session handling and re-use
+ * - implement write buffering
+ * - implement verification options
+ * - implement verification results
+ * - implement SSL/TLS shutdown
+ * - special cases: negotiation, certificates, algorithms
+ */
+
+#include "setup.h"
+
+#ifdef USE_WINDOWS_SSPI
+#ifdef USE_SCHANNEL
+
+#include <schnlsp.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "curl_sspi.h"
+#include "curl_schannel.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Uncomment to force verbose output
+ * #define infof(x, y, ...) printf(y, __VA_ARGS__)
+ * #define failf(x, y, ...) printf(y, __VA_ARGS__)
+ */
+
+static Curl_recv schannel_recv;
+static Curl_send schannel_send;
+
+static CURLcode
+schannel_connect_step1(struct connectdata *conn, int sockindex) {
+  ssize_t write = -1;
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+  SecBuffer outbuf;
+  SecBufferDesc outbuf_desc;
+  SCHANNEL_CRED schannel_cred;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+
+  infof(data, "schannel: Connecting to %s:%d (step 1/3)\n",
+        conn->host.name, conn->remote_port);
+
+  /* setup Schannel API options */
+  memset(&schannel_cred, 0, sizeof(schannel_cred));
+  schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+  schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
+                          SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+  switch(data->set.ssl.version) {
+    case CURL_SSLVERSION_TLSv1:
+      schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
+                                            SP_PROT_TLS1_1_CLIENT |
+                                            SP_PROT_TLS1_2_CLIENT;
+      break;
+    case CURL_SSLVERSION_SSLv3:
+      schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
+      break;
+    case CURL_SSLVERSION_SSLv2:
+      schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
+      break;
+  }
+
+  /* TODO: implement verification options */
+
+  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
+  sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL, SSPI_SCHANNEL_API,
+    SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
+    &connssl->cred_handle, &connssl->time_stamp);
+
+  if(sspi_status != SEC_E_OK) {
+    failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
+          sspi_status);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  connssl->schannel = TRUE;
+
+  /* setup output buffer */
+  outbuf.pvBuffer = NULL;
+  outbuf.cbBuffer = 0;
+  outbuf.BufferType = SECBUFFER_EMPTY;
+
+  outbuf_desc.pBuffers = &outbuf;
+  outbuf_desc.cBuffers = 1;
+  outbuf_desc.ulVersion = SECBUFFER_VERSION;
+
+  /* setup request flags */
+  connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+                       ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY |
+                       ISC_REQ_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY |
+                       ISC_REQ_STREAM;
+
+  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
+  sspi_status = s_pSecFn->InitializeSecurityContextA(&connssl->cred_handle,
+    NULL, conn->host.name, connssl->req_flags, 0, 0, NULL, 0,
+    &connssl->ctxt_handle, &outbuf_desc,
+    &connssl->ret_flags, &connssl->time_stamp);
+
+  if(sspi_status != SEC_I_CONTINUE_NEEDED) {
+    failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n",
+          sspi_status);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  infof(data, "schannel: sending initial handshake data: %d ...\n",
+        outbuf.cbBuffer);
+
+  /* send initial handshake data which is now stored in output buffer */
+  write = swrite(conn->sock[sockindex], outbuf.pvBuffer, outbuf.cbBuffer);
+  s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+  if(write != outbuf.cbBuffer) {
+    failf(data, "schannel: failed to send initial handshake data: %d\n", write);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  infof(data, "schannel: sent initial handshake data: %d\n", write);
+
+  /* continue to second handshake step */
+  connssl->connecting_state = ssl_connect_2;
+
+  return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step2(struct connectdata *conn, int sockindex) {
+  int i;
+  ssize_t read = -1, write = -1;
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+  SecBuffer outbuf[2];
+  SecBufferDesc outbuf_desc;
+  SecBuffer inbuf[2];
+  SecBufferDesc inbuf_desc;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+
+  infof(data, "schannel: Connecting to %s:%d (step 2/3)\n",
+        conn->host.name, conn->remote_port);
+
+  connssl->connecting_state = ssl_connect_2;
+
+  /* buffer to store previously received and encrypted data */
+  if(connssl->encdata_buffer == NULL) {
+    connssl->encdata_offset = 0;
+    connssl->encdata_length = 4096;
+    connssl->encdata_buffer = malloc(connssl->encdata_length);
+    if(connssl->encdata_buffer == NULL) {
+      failf(data, "schannel: unable to allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  /* read encrypted handshake data from socket */
+  read = sread(conn->sock[sockindex],
+               connssl->encdata_buffer + connssl->encdata_offset,
+               connssl->encdata_length - connssl->encdata_offset);
+  if(read < 0) {
+    connssl->connecting_state = ssl_connect_2_reading;
+    infof(data, "schannel: failed to receive handshake, waiting for more: %d\n",
+          read);
+    return CURLE_OK;
+  }
+  else if(read == 0) {
+    failf(data, "schannel: failed to receive handshake, connection failed\n");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  else if(read > 0) {
+    /* increase encrypted data buffer offset */
+    connssl->encdata_offset += read;
+  }
+
+  infof(data, "schannel: encrypted data buffer %d/%d\n",
+    connssl->encdata_offset, connssl->encdata_length);
+
+  /* setup input buffers */
+  inbuf[0].pvBuffer = malloc(connssl->encdata_offset);
+  inbuf[0].cbBuffer = connssl->encdata_offset;
+  inbuf[0].BufferType = SECBUFFER_TOKEN;
+
+  inbuf[1].pvBuffer = NULL;
+  inbuf[1].cbBuffer = 0;
+  inbuf[1].BufferType = SECBUFFER_EMPTY;
+
+  inbuf_desc.pBuffers = &inbuf[0];
+  inbuf_desc.cBuffers = 2;
+  inbuf_desc.ulVersion = SECBUFFER_VERSION;
+
+  /* setup output buffers */
+  outbuf[0].pvBuffer = NULL;
+  outbuf[0].cbBuffer = 0;
+  outbuf[0].BufferType = SECBUFFER_TOKEN;
+
+  outbuf[1].pvBuffer = NULL;
+  outbuf[1].cbBuffer = 0;
+  outbuf[1].BufferType = SECBUFFER_ALERT;
+
+  outbuf_desc.pBuffers = &outbuf[0];
+  outbuf_desc.cBuffers = 2;
+  outbuf_desc.ulVersion = SECBUFFER_VERSION;
+
+  if(inbuf[0].pvBuffer == NULL) {
+    failf(data, "schannel: unable to allocate memory");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* copy received handshake data into input buffer */
+  memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, connssl->encdata_offset);
+
+  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
+  sspi_status = s_pSecFn->InitializeSecurityContextA(
+    &connssl->cred_handle, &connssl->ctxt_handle, conn->host.name,
+    connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc,
+    &connssl->ret_flags, &connssl->time_stamp);
+
+  /* free buffer for received handshake data */
+  free(inbuf[0].pvBuffer);
+
+  /* check if the handshake was incomplete */
+  if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+    connssl->connecting_state = ssl_connect_2_reading;
+    infof(data, "schannel: received incomplete message, need more data: %d\n",
+          sspi_status);
+    return CURLE_OK;
+  }
+
+  /* check if the handshake needs to be continued */
+  if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
+    for(i = 0; i < 2; i++) {
+      /* search for handshake tokens that need to be send */
+      if(outbuf[i].BufferType = SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
+        infof(data, "schannel: sending next handshake data: %d ...\n",
+              outbuf[i].cbBuffer);
+
+        /* send handshake token to server */
+        write = swrite(conn->sock[sockindex],
+                       outbuf[i].pvBuffer, outbuf[i].cbBuffer);
+        if(write != outbuf[i].cbBuffer) {
+          failf(data, "schannel: failed to send next handshake data: %d\n",
+                write);
+          return CURLE_SSL_CONNECT_ERROR;
+        }
+      }
+
+      /* free obsolete buffer */
+      if(outbuf[i].pvBuffer != NULL) {
+        s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
+      }
+    }
+  }
+  else {
+    failf(data, "schannel: next InitializeSecurityContextA failed: %d\n",
+          sspi_status);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* check if there was additional remaining encrypted data */
+  if(inbuf[1].BufferType = SECBUFFER_EXTRA) {
+    infof(data, "schannel: encrypted data length: %d\n", inbuf[1].cbBuffer);
+
+    /* check if the remaining data is less than the total amount
+     * and therefore begins after the already processed data
+     */
+    if (connssl->encdata_offset > inbuf[1].cbBuffer) {
+      memmove(connssl->encdata_buffer,
+              (connssl->encdata_buffer + connssl->encdata_offset) -
+                inbuf[1].cbBuffer, inbuf[1].cbBuffer);
+      connssl->encdata_offset = inbuf[1].cbBuffer;
+    }
+  }
+  else {
+    connssl->encdata_offset = 0;
+  }
+
+  /* check if the handshake needs to be continued */
+  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+    connssl->connecting_state = ssl_connect_2_reading;
+    return CURLE_OK;
+  }
+
+  /* check if the handshake is complete */
+  if(sspi_status == SEC_E_OK) {
+    infof(data, "schannel: handshake complete\n");
+
+    /* TODO: implement verification results */
+
+    connssl->connecting_state = ssl_connect_3;
+    infof(data, "SSL connected\n");
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step3(struct connectdata *conn, int sockindex) {
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+  connssl->connecting_state = ssl_connect_done;
+
+  return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_common(struct connectdata *conn, int sockindex,
+                        bool nonblocking, bool *done) {
+  CURLcode retcode;
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  curl_socket_t sockfd = conn->sock[sockindex];
+  long timeout_ms;
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    /* check out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    retcode = schannel_connect_step1(conn, sockindex);
+    if(retcode)
+      return retcode;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+       || connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+
+      what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if
+     * this connection is part of a multi handle and this loop would
+     * execute again. This permits the owner of a multi handle to
+     * abort a connection attempt before step2 has completed while
+     * ensuring that a client using select() or epoll() will always
+     * have a valid fdset to wait on.
+     */
+    retcode = schannel_connect_step2(conn, sockindex);
+    if(retcode || (nonblocking &&
+                   (ssl_connect_2 == connssl->connecting_state ||
+                    ssl_connect_2_reading == connssl->connecting_state ||
+                    ssl_connect_2_writing == connssl->connecting_state)))
+      return retcode;
+
+  } /* repeat step2 until all transactions are done. */
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    retcode = schannel_connect_step3(conn, sockindex);
+    if(retcode)
+      return retcode;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    conn->recv[sockindex] = schannel_recv;
+    conn->send[sockindex] = schannel_send;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* reset our connection state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+static ssize_t
+schannel_send(struct connectdata *conn, int sockindex,
+              const void *buf, size_t len, CURLcode *err) {
+  ssize_t ret = -1;
+  size_t data_len = 0;
+  unsigned char *data = NULL;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  SecBuffer outbuf[4];
+  SecBufferDesc outbuf_desc;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+
+  /* check if the maximum stream sizes were queried */
+  if(connssl->stream_sizes.cbMaximumMessage == 0) {
+    sspi_status = s_pSecFn->QueryContextAttributesA(&connssl->ctxt_handle,
+                                                    SECPKG_ATTR_STREAM_SIZES,
+                                                    &connssl->stream_sizes);
+    if(sspi_status != SEC_E_OK) {
+      *err = CURLE_SEND_ERROR;
+      return -1;
+    }
+  }
+
+  /* check if the buffer is longer than the maximum message length */
+  if(len > connssl->stream_sizes.cbMaximumMessage) {
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+
+  /* calculate the complete message length and allocate a buffer for it */
+  data_len = connssl->stream_sizes.cbHeader + len +
+              connssl->stream_sizes.cbTrailer;
+  data = (unsigned char*) malloc(data_len);
+  if(data == NULL) {
+    *err = CURLE_OUT_OF_MEMORY;
+    return -1;
+  }
+
+  /* setup output buffers (header, data, trailer, empty) */
+  outbuf[0].pvBuffer = data;
+  outbuf[0].cbBuffer = connssl->stream_sizes.cbHeader;
+  outbuf[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+  outbuf[1].pvBuffer = data + connssl->stream_sizes.cbHeader;
+  outbuf[1].cbBuffer = len;
+  outbuf[1].BufferType = SECBUFFER_DATA;
+
+  outbuf[2].pvBuffer = data + connssl->stream_sizes.cbHeader + len;
+  outbuf[2].cbBuffer = connssl->stream_sizes.cbTrailer;
+  outbuf[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+  outbuf[3].pvBuffer = NULL;
+  outbuf[3].cbBuffer = 0;
+  outbuf[3].BufferType = SECBUFFER_EMPTY;
+
+  outbuf_desc.pBuffers = &outbuf[0];
+  outbuf_desc.cBuffers = 4;
+  outbuf_desc.ulVersion = SECBUFFER_VERSION;
+
+  /* copy data into output buffer */
+  memcpy(outbuf[1].pvBuffer, buf, len);
+
+  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
+  sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt_handle, 0,
+                                         &outbuf_desc, 0);
+
+  /* check if the message was encrypted */
+  if(sspi_status == SEC_E_OK) {
+    /* send the encrypted message including header, data and trailer */
+    len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
+    ret = swrite(conn->sock[sockindex], data, len);
+    /* TODO: implement write buffering */
+  }
+  else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
+    *err = CURLE_OUT_OF_MEMORY;
+  }
+  else{
+    *err = CURLE_SEND_ERROR;
+  }
+
+  free(data);
+
+  return ret;
+}
+
+static ssize_t
+schannel_recv(struct connectdata *conn, int sockindex,
+              char *buf, size_t len, CURLcode *err) {
+  int i = 0;
+  size_t size = 0;
+  ssize_t read = 0, ret = -1;
+  CURLcode retcode;
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  bool done = FALSE;
+  SecBuffer inbuf[4];
+  SecBufferDesc inbuf_desc;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+
+  infof(data, "schannel: client wants to read %d\n", len);
+  *err = CURLE_OK;
+
+  /* buffer to store previously received and decrypted data */
+  if(connssl->decdata_buffer == NULL) {
+    connssl->decdata_offset = 0;
+    connssl->decdata_length = 4096;
+    connssl->decdata_buffer = malloc(connssl->decdata_length);
+    if(connssl->decdata_buffer == NULL) {
+      failf(data, "schannel: unable to allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  /* increase buffers in order to fit the requested amount of data */
+  while(connssl->encdata_length - connssl->encdata_offset < 2048 ||
+        connssl->encdata_length < len) {
+    /* increase internal encrypted data buffer */
+    connssl->encdata_length += 2048;
+    connssl->encdata_buffer = realloc(connssl->encdata_buffer,
+                                      connssl->encdata_length);
+    if(connssl->encdata_buffer == NULL) {
+      failf(data, "schannel: unable to re-allocate memory");
+      *err = CURLE_OUT_OF_MEMORY;
+      return -1;
+    }
+
+    /* increase internal decrypted data buffer */
+    connssl->decdata_length += 2048;
+    connssl->decdata_buffer = realloc(connssl->decdata_buffer,
+                                      connssl->decdata_length);
+    if(connssl->decdata_buffer == NULL) {
+      failf(data, "schannel: unable to re-allocate memory");
+      *err = CURLE_OUT_OF_MEMORY;
+      return -1;
+    }
+  }
+
+  /* read encrypted data from socket */
+  infof(data, "schannel: encrypted data buffer %d/%d\n",
+        connssl->encdata_offset, connssl->encdata_length);
+  size = connssl->encdata_length - connssl->encdata_offset;
+  if (size > 0) {
+    read = sread(conn->sock[sockindex],
+                 connssl->encdata_buffer + connssl->encdata_offset, size);
+    infof(data, "schannel: encrypted data received %d\n", read);
+
+    /* check for received data */
+    if(read > 0) {
+      /* increase encrypted data buffer offset */
+      connssl->encdata_offset += read;
+    }
+  }
+
+  infof(data, "schannel: encrypted data buffer %d/%d\n",
+    connssl->encdata_offset, connssl->encdata_length);
+
+  /* check if we still have some data in our buffers */
+  while(connssl->encdata_offset > 0 &&
+        sspi_status != SEC_E_INCOMPLETE_MESSAGE) {
+
+    /* prepare data buffer for DecryptMessage call */
+    inbuf[0].pvBuffer = connssl->encdata_buffer;
+    inbuf[0].cbBuffer = connssl->encdata_offset;
+    inbuf[0].BufferType = SECBUFFER_DATA;
+
+    /* we need 3 more empty input buffers for possible output */
+    inbuf[1].pvBuffer = NULL;
+    inbuf[1].cbBuffer = 0;
+    inbuf[1].BufferType = SECBUFFER_EMPTY;
+
+    inbuf[2].pvBuffer = NULL;
+    inbuf[2].cbBuffer = 0;
+    inbuf[2].BufferType = SECBUFFER_EMPTY;
+
+    inbuf[3].pvBuffer = NULL;
+    inbuf[3].cbBuffer = 0;
+    inbuf[3].BufferType = SECBUFFER_EMPTY;
+
+    inbuf_desc.pBuffers = &inbuf[0];
+    inbuf_desc.cBuffers = 4;
+    inbuf_desc.ulVersion = SECBUFFER_VERSION;
+
+    /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
+    sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt_handle,
+                                           &inbuf_desc, 0, NULL);
+    infof(data, "schannel: DecryptMessage %d\n", sspi_status);
+
+    /* check if everything went fine (server may want to renegotiate context) */
+    if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE) {
+      /* check for successfully decrypted data */
+      if(inbuf[1].BufferType == SECBUFFER_DATA) {
+        infof(data, "schannel: decrypted data length: %d\n", inbuf[1].cbBuffer);
+
+        /* copy decrypted data to internal buffer */
+        size = connssl->decdata_length - connssl->decdata_offset;
+        size = size < inbuf[1].cbBuffer ? size : inbuf[1].cbBuffer;
+        if(size > 0) {
+          memcpy(connssl->decdata_buffer + connssl->decdata_offset,
+                 inbuf[1].pvBuffer, size);
+          connssl->decdata_offset += size;
+        }
+
+        infof(data, "schannel: decrypted data added: %d\n", size);
+        infof(data, "schannel: decrypted data cached: %d/%d\n",
+              connssl->decdata_offset, connssl->decdata_length);
+      }
+
+      /* check for remaining encrypted data */
+      if(inbuf[3].BufferType = SECBUFFER_EXTRA) {
+        infof(data, "schannel: encrypted data length: %d\n", inbuf[3].cbBuffer);
+
+        /* check if the remaining data is less than the total amount
+         * and therefore begins after the already processed data
+        */
+        if(connssl->encdata_offset > inbuf[3].cbBuffer) {
+          /* move remaining encrypted data forward to the beginning of buffer */
+          memmove(connssl->encdata_buffer,
+                  (connssl->encdata_buffer + connssl->encdata_offset) -
+                    inbuf[3].cbBuffer, inbuf[3].cbBuffer);
+          connssl->encdata_offset = inbuf[3].cbBuffer;
+        }
+
+        infof(data, "schannel: encrypted data cached: %d/%d\n",
+              connssl->encdata_offset, connssl->encdata_length);
+      }
+      else{
+        /* reset encrypted buffer offset, because there is no data remaining */
+        connssl->encdata_offset = 0;
+      }
+    }
+
+    /* check if server wants to renegotiate the connection context */
+    if(sspi_status == SEC_I_RENEGOTIATE) {
+      infof(data, "schannel: client needs to renegotiate with server\n");
+
+      /* begin renegotiation */
+      connssl->state = ssl_connection_negotiating;
+      retcode = schannel_connect_common(conn, sockindex, FALSE, &done);
+      if(retcode)
+        *err = retcode;
+    }
+  }
+
+  /* copy requested decrypted data to supplied buffer */
+  size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
+  if(size > 0) {
+    memcpy(buf, connssl->decdata_buffer, size);
+    ret = size;
+
+    /* move remaining decrypted data forward to the beginning of buffer */
+    memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
+            connssl->decdata_offset - size);
+    connssl->decdata_offset -= size;
+  }
+
+  /* reduce internal buffer length to reduce memory usage */
+  if(connssl->encdata_length > 4096) {
+    connssl->encdata_length = connssl->encdata_offset > 0 ?
+                              connssl->encdata_offset + 2048 : 4096;
+    connssl->encdata_buffer = realloc(connssl->encdata_buffer,
+                                      connssl->encdata_length);
+  }
+  if(connssl->decdata_length > 4096) {
+    connssl->decdata_length = connssl->decdata_offset > 0 ?
+                              connssl->decdata_offset + 2048 : 4096;
+    connssl->decdata_buffer = realloc(connssl->decdata_buffer,
+                                      connssl->decdata_length);
+  }
+
+  /* check if something went wrong and we need to return an error */
+  if(ret < 0) {
+    if(sspi_status == SEC_E_INCOMPLETE_MESSAGE)
+      *err = CURLE_AGAIN;
+    else if(sspi_status != SEC_E_OK)
+      *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  /* everything went fine */
+  infof(data, "schannel: read returns %d with error code %d\n", ret, *err);
+
+  return ret;
+}
+
+CURLcode
+Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
+                                  bool *done) {
+  return schannel_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_schannel_connect(struct connectdata *conn, int sockindex) {
+  CURLcode retcode;
+  bool done = FALSE;
+
+  retcode = schannel_connect_common(conn, sockindex, FALSE, &done);
+  if(retcode)
+    return retcode;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) {
+  const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  if(connssl->schannel) /* SSL is in use */
+    return (connssl->encdata_offset > 0 ||
+            connssl->decdata_offset > 0 ) ? TRUE : FALSE;
+  else
+    return FALSE;
+}
+
+void Curl_schannel_close(struct connectdata *conn, int sockindex) {
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  infof(data, "schannel: Closing connection with %s:%d\n",
+        conn->host.name, conn->remote_port);
+
+  /* free SSPI Schannel API context and handle */
+  if(connssl->schannel) {
+    s_pSecFn->DeleteSecurityContext(&connssl->ctxt_handle);
+    s_pSecFn->FreeCredentialsHandle(&connssl->cred_handle);
+  }
+
+  /* free internal buffer for received encrypted data */
+  if(connssl->encdata_buffer != NULL) {
+    free(connssl->encdata_buffer);
+    connssl->encdata_buffer = NULL;
+    connssl->encdata_length = 0;
+    connssl->encdata_offset = 0;
+  }
+
+  /* free internal buffer for received decrypted data */
+  if(connssl->decdata_buffer != NULL) {
+    free(connssl->decdata_buffer);
+    connssl->decdata_buffer = NULL;
+    connssl->decdata_length = 0;
+    connssl->decdata_offset = 0;
+  }
+}
+
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) {
+  return CURLE_NOT_BUILT_IN; /* TODO: implement SSL/TLS shutdown */
+}
+
+int Curl_schannel_init() {
+  return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
+}
+
+void Curl_schannel_cleanup() {
+  Curl_sspi_global_cleanup();
+}
+
+size_t Curl_schannel_version(char *buffer, size_t size)
+{
+  unsigned long version = s_pSecFn ? s_pSecFn->dwVersion : 0;
+  return snprintf(buffer, size, "Schannel/%d.%d.%d.%d",
+                  (version>>0)&0xff, (version>>8)&0xff,
+                  (version>>16)&0xff, (version>>24)&0xff);
+}
+
+#endif /* USE_SCHANNEL */
+#endif /* USE_WINDOWS_SSPI */
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
new file mode 100755
index 0000000..f5213ab
--- /dev/null
+++ b/lib/curl_schannel.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_SCHANNEL_H
+#define HEADER_SCHANNEL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef USE_WINDOWS_SSPI
+#ifdef USE_SCHANNEL
+
+#define SSPI_SCHANNEL_API "Microsoft Unified Security Protocol Provider"
+
+CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
+                                           int sockindex,
+                                           bool *done);
+
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
+void Curl_schannel_close(struct connectdata *conn, int sockindex);
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
+
+int Curl_schannel_init();
+void Curl_schannel_cleanup();
+size_t Curl_schannel_version(char *buffer, size_t size);
+
+/* API setup for Schannel */
+#define curlssl_init Curl_schannel_init
+#define curlssl_cleanup Curl_schannel_cleanup
+#define curlssl_connect Curl_schannel_connect
+#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking
+#define curlssl_session_free(x)  (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_close_all(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_close Curl_schannel_close
+#define curlssl_shutdown Curl_schannel_shutdown
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_schannel_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending Curl_schannel_data_pending
+
+#endif /* USE_SCHANNEL */
+#endif /* USE_WINDOWS_SSPI */
+#endif /* HEADER_SCHANNEL_H */
diff --git a/lib/sslgen.c b/lib/sslgen.c
index a77fd78..5d2ead0 100644
--- a/lib/sslgen.c
+++ b/lib/sslgen.c
@@ -33,6 +33,7 @@
    Curl_nss_ - prefix for NSS ones
    Curl_polarssl_ - prefix for PolarSSL ones
    Curl_cyassl_ - prefix for CyaSSL ones
+   Curl_schannel_ - prefix for Schannel SSPI ones
 
    Note that this source code uses curlssl_* functions, and they are all
    defines/macros #defined by the lib-specific header files.
@@ -57,6 +58,7 @@
 #include "polarssl.h" /* PolarSSL versions */
 #include "axtls.h"  /* axTLS versions */
 #include "cyassl.h"  /* CyaSSL versions */
+#include "curl_schannel.h" /* Schannel SSPI version */
 #include "sendf.h"
 #include "rawstr.h"
 #include "url.h"
diff --git a/lib/urldata.h b/lib/urldata.h
index 3474431..d371288 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -131,6 +131,11 @@
 #undef realloc
 #endif /* USE_AXTLS */
 
+#ifdef USE_SCHANNEL
+#include <schnlsp.h>
+#include "curl_sspi.h"
+#endif
+
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -284,6 +289,18 @@ struct ssl_connect_data {
   SSL_CTX* ssl_ctx;
   SSL*     ssl;
 #endif /* USE_AXTLS */
+#ifdef USE_SCHANNEL
+  bool schannel;
+  TimeStamp time_stamp;
+  CredHandle cred_handle;
+  CtxtHandle ctxt_handle;
+  SecPkgContext_StreamSizes stream_sizes;
+  ssl_connect_state connecting_state;
+  size_t encdata_length, decdata_length;
+  size_t encdata_offset, decdata_offset;
+  unsigned char *encdata_buffer, *decdata_buffer;
+  unsigned long req_flags, ret_flags;
+#endif /* USE_SCHANNEL */
 };
 
 struct ssl_config_data {
-- 
1.7.9


From d62fa1cd36138f386459fc25bce033ed62e82b1f Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 15:40:51 +0200
Subject: [PATCH 03/55] Updated winbuild scripts to add WITH_SSL=schannel
 option

---
 lib/Makefile.inc          |    4 ++--
 winbuild/Makefile.vc      |    4 ++++
 winbuild/MakefileBuild.vc |   11 +++++++----
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 69ad159..4d720f4 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -23,7 +23,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c	\
   curl_rtmp.c openldap.c curl_gethostname.c gopher.c axtls.c		\
   idn_win32.c http_negotiate_sspi.c cyassl.c http_proxy.c non-ascii.c	\
   asyn-ares.c asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c	\
-  curl_ntlm_core.c curl_ntlm_msgs.c
+  curl_ntlm_core.c curl_ntlm_msgs.c curl_schannel.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
@@ -39,4 +39,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
   curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h	\
   warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h	\
   gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h \
-  curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h
+  curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h curl_schannel.h
diff --git a/winbuild/Makefile.vc b/winbuild/Makefile.vc
index 8fafecf..de2488a 100644
--- a/winbuild/Makefile.vc
+++ b/winbuild/Makefile.vc
@@ -67,6 +67,10 @@ SSL=dll
 !ELSEIF "$(WITH_SSL)"=="static"
 USE_SSL      = true
 SSL=static
+!ELSEIF "$(WITH_SSL)"=="schannel"
+USE_SSL      = true
+USE_SSPI     = true
+SSL=schannel
 !ENDIF
 
 !IF "$(WITH_ZLIB)"=="dll"
diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc
index 238b3ea..6053ba6 100644
--- a/winbuild/MakefileBuild.vc
+++ b/winbuild/MakefileBuild.vc
@@ -96,16 +96,19 @@ LFLAGS         = $(LFLAGS) "/LIBPATH:$(DEVEL_LIB)"
 
 !IF "$(WITH_SSL)"=="dll"
 SSL_LIBS     = libeay32.lib ssleay32.lib
+SSL_CFLAGS   = /DUSE_SSLEAY /I"$(DEVEL_INCLUDE)/openssl"
 USE_SSL      = true
 SSL=dll
 !ELSEIF "$(WITH_SSL)"=="static"
 SSL_LIBS     = libeay32.lib ssleay32.lib gdi32.lib user32.lib advapi32.lib
+SSL_CFLAGS   = /DUSE_SSLEAY /I"$(DEVEL_INCLUDE)/openssl"
 USE_SSL      = true
 SSL=static
-!ENDIF
-
-!IFDEF USE_SSL
-SSL_CFLAGS   = /DUSE_SSLEAY /I"$(DEVEL_INCLUDE)/openssl"
+!ELSEIF "$(WITH_SSL)"=="schannel"
+USE_SSL      = true
+USE_SSPI     = yes
+SSL_CFLAGS   = /DUSE_SSL /DUSE_SCHANNEL
+SSL=schannel
 !ENDIF
 
 !IF "$(WITH_ZLIB)"=="dll"
-- 
1.7.9


From 8f33082c4e164d269a1c0838db814dc078ceba3f Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 17:01:38 +0200
Subject: [PATCH 04/55] Removed obsolete include files

---
 lib/curl_schannel.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index af0b584..6efe60b 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -54,15 +54,12 @@
 #include <schnlsp.h>
 
 #include "urldata.h"
-#include "sendf.h"
-#include "inet_pton.h"
 #include "curl_sspi.h"
 #include "curl_schannel.h"
 #include "sslgen.h"
-#include "parsedate.h"
+#include "sendf.h"
 #include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "rawstr.h"
+#include "select.h" /* for the socket readyness */
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
-- 
1.7.9


From e0fbcb4752117fd834f47e971afb53b6f417c332 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 18:03:37 +0200
Subject: [PATCH 05/55] Disable SNI for IP address based connections

---
 lib/curl_schannel.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 6efe60b..e4d7428 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -60,6 +60,7 @@
 #include "sendf.h"
 #include "connect.h" /* for the connect timeout */
 #include "select.h" /* for the socket readyness */
+#include "inet_pton.h" /* for IP addr SNI check */
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -84,6 +85,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   SecBufferDesc outbuf_desc;
   SCHANNEL_CRED schannel_cred;
   SECURITY_STATUS sspi_status = SEC_E_OK;
+  struct in_addr addr;
+#ifdef ENABLE_IPV6
+  struct in6_addr addr6;
+#endif
 
   infof(data, "schannel: Connecting to %s:%d (step 1/3)\n",
         conn->host.name, conn->remote_port);
@@ -94,6 +99,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
                           SCH_CRED_REVOCATION_CHECK_CHAIN;
 
+  if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
+#ifdef ENABLE_IPV6
+  || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
+#endif
+     ) {
+    schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+    infof(data, "schannel: using IP address, disable SNI servername check\n");
+  }
+
   switch(data->set.ssl.version) {
     case CURL_SSLVERSION_TLSv1:
       schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
-- 
1.7.9


From e340214d87ecd7c47bf239f467c9d8d7d407b7c6 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 18:23:50 +0200
Subject: [PATCH 06/55] Allow SNI being manually deactivated

---
 lib/curl_schannel.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index e4d7428..515abe2 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -99,11 +99,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
                           SCH_CRED_REVOCATION_CHECK_CHAIN;
 
-  if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
+  if(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
 #ifdef ENABLE_IPV6
-  || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
+     Curl_inet_pton(AF_INET6, conn->host.name, &addr6) ||
 #endif
-     ) {
+     data->set.ssl.verifyhost < 2) {
     schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
     infof(data, "schannel: using IP address, disable SNI servername check\n");
   }
-- 
1.7.9


From 30bc5c4e361918de06b208cdd491ed3779e64a6c Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 18:35:00 +0200
Subject: [PATCH 07/55] Allow certificate and revocation checks being
 deactivated

---
 lib/curl_schannel.c |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 515abe2..f7eb29b 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -96,8 +96,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   /* setup Schannel API options */
   memset(&schannel_cred, 0, sizeof(schannel_cred));
   schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-  schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
-                          SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+  if(data->set.ssl.verifypeer) {
+    schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
+                            SCH_CRED_REVOCATION_CHECK_CHAIN;
+    infof(data, "schannel: checking server certificate and revocation\n");
+  }
+  else {
+    schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+                            SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+                            SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+    infof(data, "schannel: disable server certificate and revocation checks\n");
+  }
 
   if(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
 #ifdef ENABLE_IPV6
-- 
1.7.9


From adfc861a2602496824ec60e6a571a08f941b8e27 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 18:35:14 +0200
Subject: [PATCH 08/55] Fixed spaces in front of braces

---
 lib/curl_schannel.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index f7eb29b..c82fe31 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -331,7 +331,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
     /* check if the remaining data is less than the total amount
      * and therefore begins after the already processed data
      */
-    if (connssl->encdata_offset > inbuf[1].cbBuffer) {
+    if(connssl->encdata_offset > inbuf[1].cbBuffer) {
       memmove(connssl->encdata_buffer,
               (connssl->encdata_buffer + connssl->encdata_offset) -
                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
@@ -622,7 +622,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
   infof(data, "schannel: encrypted data buffer %d/%d\n",
         connssl->encdata_offset, connssl->encdata_length);
   size = connssl->encdata_length - connssl->encdata_offset;
-  if (size > 0) {
+  if(size > 0) {
     read = sread(conn->sock[sockindex],
                  connssl->encdata_buffer + connssl->encdata_offset, size);
     infof(data, "schannel: encrypted data received %d\n", read);
-- 
1.7.9


From 7f55ed1e6f1b4766cec701eca297d1badae9503c Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 18:42:28 +0200
Subject: [PATCH 09/55] Improved error message for SNI or certificate check
 failure

---
 lib/curl_schannel.c |   24 ++++++++++++++++++------
 1 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index c82fe31..57168c5 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -140,8 +140,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
     &connssl->cred_handle, &connssl->time_stamp);
 
   if(sspi_status != SEC_E_OK) {
-    failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
-          sspi_status);
+    if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+      failf(data, "schannel: SNI or certificate check failed\n",
+            sspi_status);
+    else
+      failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
+            sspi_status);
     return CURLE_SSL_CONNECT_ERROR;
   }
 
@@ -169,8 +173,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
     &connssl->ret_flags, &connssl->time_stamp);
 
   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
-    failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n",
-          sspi_status);
+    if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+      failf(data, "schannel: SNI or certificate check failed\n",
+            sspi_status);
+    else
+      failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n",
+            sspi_status);
     return CURLE_SSL_CONNECT_ERROR;
   }
 
@@ -319,8 +327,12 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
     }
   }
   else {
-    failf(data, "schannel: next InitializeSecurityContextA failed: %d\n",
-          sspi_status);
+    if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+      failf(data, "schannel: SNI or certificate check failed\n",
+            sspi_status);
+    else
+      failf(data, "schannel: next InitializeSecurityContextA failed: %d\n",
+            sspi_status);
     return CURLE_SSL_CONNECT_ERROR;
   }
 
-- 
1.7.9


From 8700877500cf88922e7ff1c4ad1e4bb414fc26f0 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 18:44:10 +0200
Subject: [PATCH 10/55] Removed obsolete string format argument

---
 lib/curl_schannel.c |    9 +++------
 1 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 57168c5..9b26f45 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -141,8 +141,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
 
   if(sspi_status != SEC_E_OK) {
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-      failf(data, "schannel: SNI or certificate check failed\n",
-            sspi_status);
+      failf(data, "schannel: SNI or certificate check failed\n");
     else
       failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
             sspi_status);
@@ -174,8 +173,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
 
   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-      failf(data, "schannel: SNI or certificate check failed\n",
-            sspi_status);
+      failf(data, "schannel: SNI or certificate check failed\n");
     else
       failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n",
             sspi_status);
@@ -328,8 +326,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   }
   else {
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-      failf(data, "schannel: SNI or certificate check failed\n",
-            sspi_status);
+      failf(data, "schannel: SNI or certificate check failed\n");
     else
       failf(data, "schannel: next InitializeSecurityContextA failed: %d\n",
             sspi_status);
-- 
1.7.9


From da01909970f6fae8037c12f4ab39428cde0da238 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 22:08:32 +0200
Subject: [PATCH 11/55] Replaced custom SSPI_SCHANNEL_API with UNISP_NAME_A

---
 lib/curl_schannel.c |    6 +++---
 lib/curl_schannel.h |    4 +++-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 9b26f45..158b30c 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -135,9 +135,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   /* TODO: implement verification options */
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
-  sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL, SSPI_SCHANNEL_API,
-    SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
-    &connssl->cred_handle, &connssl->time_stamp);
+  sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL,
+    UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred,
+    NULL, NULL, &connssl->cred_handle, &connssl->time_stamp);
 
   if(sspi_status != SEC_E_OK) {
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index f5213ab..3de932b 100755
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -26,7 +26,9 @@
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_SCHANNEL
 
-#define SSPI_SCHANNEL_API "Microsoft Unified Security Protocol Provider"
+#ifndef UNISP_NAME_A
+#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
+#endif
 
 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
 
-- 
1.7.9


From f981b3298147f57d8fdcb6c61b2f30458cad4553 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 22:33:21 +0200
Subject: [PATCH 12/55] Integrity is not specified/supported by Schannel API

See MakeSignature documentation:
This function is not supported by the
Schannel security support provider (SSP).
---
 lib/curl_schannel.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 158b30c..ac083d1 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -161,9 +161,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
 
   /* setup request flags */
   connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
-                       ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY |
-                       ISC_REQ_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY |
-                       ISC_REQ_STREAM;
+                       ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR |
+                       ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
   sspi_status = s_pSecFn->InitializeSecurityContextA(&connssl->cred_handle,
-- 
1.7.9


From 26caddacfa3bd71fcfed707d753d58bbd5f6687c Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 22:33:58 +0200
Subject: [PATCH 13/55] Check for required context attributes

---
 lib/curl_schannel.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index ac083d1..2ad0e0d 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -371,10 +371,27 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
 
 static CURLcode
 schannel_connect_step3(struct connectdata *conn, int sockindex) {
+  struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
+  if (connssl->ret_flags != connssl->req_flags) {
+    if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
+      failf(data, "schannel: failed to setup sequence detection\n");
+    if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
+      failf(data, "schannel: failed to setup replay detection\n");
+    if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
+      failf(data, "schannel: failed to setup confidentiality\n");
+    if(!(connssl->ret_flags & ISC_RET_EXTENDED_ERROR))
+      failf(data, "schannel: failed to setup extended errors\n");
+    if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
+      failf(data, "schannel: failed to setup memory allocation\n");
+    if(!(connssl->ret_flags & ISC_RET_STREAM))
+      failf(data, "schannel: failed to setup stream orientation\n");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
   connssl->connecting_state = ssl_connect_done;
 
   return CURLE_OK;
-- 
1.7.9


From 5bf6b5d2da4da7600733e04f1ed4f825de58954e Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 22:43:48 +0200
Subject: [PATCH 14/55] Removed obsolete info messages

---
 lib/curl_schannel.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 2ad0e0d..2e5cb63 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -358,12 +358,10 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
 
   /* check if the handshake is complete */
   if(sspi_status == SEC_E_OK) {
-    infof(data, "schannel: handshake complete\n");
-
     /* TODO: implement verification results */
 
     connssl->connecting_state = ssl_connect_3;
-    infof(data, "SSL connected\n");
+    infof(data, "schannel: handshake complete\n");
   }
 
   return CURLE_OK;
-- 
1.7.9


From 286f96e79faf7bf5cf225e278365d913fcdd474a Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 22:44:04 +0200
Subject: [PATCH 15/55] Updated TODO lines

---
 lib/curl_schannel.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 2e5cb63..e25a2e6 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -40,10 +40,8 @@
  * TODO list for TLS/SSL implementation:
  * - implement session handling and re-use
  * - implement write buffering
- * - implement verification options
- * - implement verification results
  * - implement SSL/TLS shutdown
- * - special cases: negotiation, certificates, algorithms
+ * - special cases: renegotiation, certificates, algorithms
  */
 
 #include "setup.h"
@@ -132,8 +130,6 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
       break;
   }
 
-  /* TODO: implement verification options */
-
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
   sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL,
     UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred,
@@ -358,8 +354,6 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
 
   /* check if the handshake is complete */
   if(sspi_status == SEC_E_OK) {
-    /* TODO: implement verification results */
-
     connssl->connecting_state = ssl_connect_3;
     infof(data, "schannel: handshake complete\n");
   }
-- 
1.7.9


From 306621bf027d97cc09ecfa637800abf1aa460be6 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 22:49:17 +0200
Subject: [PATCH 16/55] Removed single space in front of brace

---
 lib/curl_schannel.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index e25a2e6..7619338 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -368,7 +368,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
-  if (connssl->ret_flags != connssl->req_flags) {
+  if(connssl->ret_flags != connssl->req_flags) {
     if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
       failf(data, "schannel: failed to setup sequence detection\n");
     if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
-- 
1.7.9


From f0134da3d284762c3dc9d5add10c695315a8ebf3 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 9 Apr 2012 23:24:55 +0200
Subject: [PATCH 17/55] Experimental: cache credential handles in session
 cache

---
 lib/curl_schannel.c |  131 +++++++++++++++++++++++++++++++++------------------
 1 files changed, 85 insertions(+), 46 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 7619338..cc5aff5 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -83,6 +83,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   SecBufferDesc outbuf_desc;
   SCHANNEL_CRED schannel_cred;
   SECURITY_STATUS sspi_status = SEC_E_OK;
+  CredHandle *old_cred_handle = NULL;
+  size_t old_cred_handle_size = 0;
   struct in_addr addr;
 #ifdef ENABLE_IPV6
   struct in6_addr addr6;
@@ -91,57 +93,63 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   infof(data, "schannel: Connecting to %s:%d (step 1/3)\n",
         conn->host.name, conn->remote_port);
 
-  /* setup Schannel API options */
-  memset(&schannel_cred, 0, sizeof(schannel_cred));
-  schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-
-  if(data->set.ssl.verifypeer) {
-    schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
-                            SCH_CRED_REVOCATION_CHECK_CHAIN;
-    infof(data, "schannel: checking server certificate and revocation\n");
+  if(!Curl_ssl_getsessionid(conn, &old_cred_handle, &old_cred_handle_size)) {
+    memcpy(&connssl->cred_handle, old_cred_handle, old_cred_handle_size);
+    infof(data, "schannel: re-using existing credential handle\n");
   }
   else {
-    schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
-                            SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
-                            SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-    infof(data, "schannel: disable server certificate and revocation checks\n");
-  }
+    /* setup Schannel API options */
+    memset(&schannel_cred, 0, sizeof(schannel_cred));
+    schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+
+    if(data->set.ssl.verifypeer) {
+      schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
+                              SCH_CRED_REVOCATION_CHECK_CHAIN;
+      infof(data, "schannel: checking server certificate and revocation\n");
+    }
+    else {
+      schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+                              SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+                              SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+      infof(data, "schannel: disable server certificate and revocation checks\n");
+    }
 
-  if(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
+    if(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
 #ifdef ENABLE_IPV6
-     Curl_inet_pton(AF_INET6, conn->host.name, &addr6) ||
+       Curl_inet_pton(AF_INET6, conn->host.name, &addr6) ||
 #endif
-     data->set.ssl.verifyhost < 2) {
-    schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
-    infof(data, "schannel: using IP address, disable SNI servername check\n");
-  }
-
-  switch(data->set.ssl.version) {
-    case CURL_SSLVERSION_TLSv1:
-      schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
-                                            SP_PROT_TLS1_1_CLIENT |
-                                            SP_PROT_TLS1_2_CLIENT;
-      break;
-    case CURL_SSLVERSION_SSLv3:
-      schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
-      break;
-    case CURL_SSLVERSION_SSLv2:
-      schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
-      break;
-  }
-
-  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
-  sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL,
-    UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred,
-    NULL, NULL, &connssl->cred_handle, &connssl->time_stamp);
-
-  if(sspi_status != SEC_E_OK) {
-    if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-      failf(data, "schannel: SNI or certificate check failed\n");
-    else
-      failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
-            sspi_status);
-    return CURLE_SSL_CONNECT_ERROR;
+       data->set.ssl.verifyhost < 2) {
+      schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+      infof(data, "schannel: using IP address, disable SNI servername check\n");
+    }
+
+    switch(data->set.ssl.version) {
+      case CURL_SSLVERSION_TLSv1:
+        schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
+                                              SP_PROT_TLS1_1_CLIENT |
+                                              SP_PROT_TLS1_2_CLIENT;
+        break;
+      case CURL_SSLVERSION_SSLv3:
+        schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
+        break;
+      case CURL_SSLVERSION_SSLv2:
+        schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
+        break;
+    }
+
+    /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
+    sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL,
+      UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred,
+      NULL, NULL, &connssl->cred_handle, &connssl->time_stamp);
+
+    if(sspi_status != SEC_E_OK) {
+      if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+        failf(data, "schannel: SNI or certificate check failed\n");
+      else
+        failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
+              sspi_status);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
   }
 
   connssl->schannel = TRUE;
@@ -363,11 +371,17 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
 
 static CURLcode
 schannel_connect_step3(struct connectdata *conn, int sockindex) {
+  CURLcode retcode = CURLE_OK;
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  CredHandle *our_cred_handle = &conn->ssl[sockindex].cred_handle;
+  CredHandle *old_cred_handle = NULL;
+  CredHandle *new_cred_handle = NULL;
+  int incache;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
+  /* check if the required context attributes are met */
   if(connssl->ret_flags != connssl->req_flags) {
     if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
       failf(data, "schannel: failed to setup sequence detection\n");
@@ -384,6 +398,31 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
     return CURLE_SSL_CONNECT_ERROR;
   }
 
+  /* save the current session data for possible re-use */
+  incache = !(Curl_ssl_getsessionid(conn, &old_cred_handle, NULL));
+  if(incache) {
+    if(old_cred_handle != our_cred_handle) {
+      infof(data, "schannel: old credential handle is stale, removing\n");
+      Curl_ssl_delsessionid(conn, old_cred_handle);
+      incache = FALSE;
+    }
+  }
+  if(!incache) {
+    new_cred_handle = malloc(sizeof(CredHandle));
+    if(new_cred_handle) {
+      memcpy(new_cred_handle, our_cred_handle, sizeof(CredHandle));
+      retcode = Curl_ssl_addsessionid(conn,
+                                      new_cred_handle, sizeof(CredHandle));
+    }
+    else {
+      retcode = CURLE_OUT_OF_MEMORY;
+    }
+    if(retcode) {
+      failf(data, "schannel: failed to store credential handle\n");
+      return retcode;
+    }
+  }
+
   connssl->connecting_state = ssl_connect_done;
 
   return CURLE_OK;
-- 
1.7.9


From 416cc67c7e1b23f66d614e7ce04611517dda3c32 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 12:43:15 +0200
Subject: [PATCH 18/55] Free credential handle using managed session free
 function

---
 lib/curl_schannel.c |   11 +++++++++--
 lib/curl_schannel.h |    3 ++-
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index cc5aff5..bd8a840 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -401,7 +401,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
   /* save the current session data for possible re-use */
   incache = !(Curl_ssl_getsessionid(conn, &old_cred_handle, NULL));
   if(incache) {
-    if(old_cred_handle != our_cred_handle) {
+    if(memcmp(old_cred_handle, our_cred_handle, sizeof(CredHandle))) {
       infof(data, "schannel: old credential handle is stale, removing\n");
       Curl_ssl_delsessionid(conn, old_cred_handle);
       incache = FALSE;
@@ -421,6 +421,9 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
       failf(data, "schannel: failed to store credential handle\n");
       return retcode;
     }
+    else {
+      infof(data, "schannel: stored crendential handle\n");
+    }
   }
 
   connssl->connecting_state = ssl_connect_done;
@@ -861,7 +864,6 @@ void Curl_schannel_close(struct connectdata *conn, int sockindex) {
   /* free SSPI Schannel API context and handle */
   if(connssl->schannel) {
     s_pSecFn->DeleteSecurityContext(&connssl->ctxt_handle);
-    s_pSecFn->FreeCredentialsHandle(&connssl->cred_handle);
   }
 
   /* free internal buffer for received encrypted data */
@@ -885,6 +887,11 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) {
   return CURLE_NOT_BUILT_IN; /* TODO: implement SSL/TLS shutdown */
 }
 
+void Curl_schannel_session_free(void *ptr) {
+  s_pSecFn->FreeCredentialsHandle((CredHandle*) ptr);
+  free(ptr);
+}
+
 int Curl_schannel_init() {
   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
 }
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index 3de932b..108fa2e 100755
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -39,6 +39,7 @@ CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
 bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
 void Curl_schannel_close(struct connectdata *conn, int sockindex);
 int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
+void Curl_schannel_session_free(void *ptr);
 
 int Curl_schannel_init();
 void Curl_schannel_cleanup();
@@ -49,7 +50,7 @@ size_t Curl_schannel_version(char *buffer, size_t size);
 #define curlssl_cleanup Curl_schannel_cleanup
 #define curlssl_connect Curl_schannel_connect
 #define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking
-#define curlssl_session_free(x)  (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_session_free Curl_schannel_session_free
 #define curlssl_close_all(x) (x=x, CURLE_NOT_BUILT_IN)
 #define curlssl_close Curl_schannel_close
 #define curlssl_shutdown Curl_schannel_shutdown
-- 
1.7.9


From e5e1a974edb78eaccfd7b9b7dff8ece20c20b258 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 13:33:15 +0200
Subject: [PATCH 19/55] Rewrote session handling to use shared memory
 allocation

This change makes it possible to actually detect if a credential
or security context handle needs to be freed. It also makes it
much easier to share exactly the same session between connections.
The expire timestamps are now also kept separately per handle.
---
 lib/curl_schannel.c |   99 +++++++++++++++++++++++++++++----------------------
 lib/curl_schannel.h |   12 ++++++
 lib/urldata.h       |    8 ++---
 3 files changed, 71 insertions(+), 48 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index bd8a840..370eb73 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -49,8 +49,6 @@
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_SCHANNEL
 
-#include <schnlsp.h>
-
 #include "urldata.h"
 #include "curl_sspi.h"
 #include "curl_schannel.h"
@@ -83,8 +81,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   SecBufferDesc outbuf_desc;
   SCHANNEL_CRED schannel_cred;
   SECURITY_STATUS sspi_status = SEC_E_OK;
-  CredHandle *old_cred_handle = NULL;
-  size_t old_cred_handle_size = 0;
+  curl_schannel_cred *old_cred = NULL;
   struct in_addr addr;
 #ifdef ENABLE_IPV6
   struct in6_addr addr6;
@@ -93,8 +90,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   infof(data, "schannel: Connecting to %s:%d (step 1/3)\n",
         conn->host.name, conn->remote_port);
 
-  if(!Curl_ssl_getsessionid(conn, &old_cred_handle, &old_cred_handle_size)) {
-    memcpy(&connssl->cred_handle, old_cred_handle, old_cred_handle_size);
+  /* check for an existing re-usable credential handle */
+  if(!Curl_ssl_getsessionid(conn, &old_cred, NULL)) {
+    connssl->cred = old_cred;
     infof(data, "schannel: re-using existing credential handle\n");
   }
   else {
@@ -137,10 +135,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
         break;
     }
 
+    /* allocate memory for the re-usable credential handle */
+    connssl->cred = malloc(sizeof(curl_schannel_cred));
+    if (!connssl->cred) {
+      failf(data, "schannel: unable to allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+    memset(connssl->cred, 0, sizeof(curl_schannel_cred));
+
     /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
     sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL,
-      UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred,
-      NULL, NULL, &connssl->cred_handle, &connssl->time_stamp);
+      UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
+      &connssl->cred->cred_handle, &connssl->cred->time_stamp);
 
     if(sspi_status != SEC_E_OK) {
       if(sspi_status == SEC_E_WRONG_PRINCIPAL)
@@ -148,12 +154,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
       else
         failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
               sspi_status);
+      free(connssl->cred);
+      connssl->cred = NULL;
       return CURLE_SSL_CONNECT_ERROR;
     }
   }
 
-  connssl->schannel = TRUE;
-
   /* setup output buffer */
   outbuf.pvBuffer = NULL;
   outbuf.cbBuffer = 0;
@@ -168,11 +174,19 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
                        ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR |
                        ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
 
+  /* allocate memory for the security context handle */
+  connssl->ctxt = malloc(sizeof(curl_schannel_ctxt));
+  if (!connssl->ctxt) {
+    failf(data, "schannel: unable to allocate memory");
+    return CURLE_OUT_OF_MEMORY;
+  }
+  memset(connssl->ctxt, 0, sizeof(curl_schannel_ctxt));
+
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
-  sspi_status = s_pSecFn->InitializeSecurityContextA(&connssl->cred_handle,
-    NULL, conn->host.name, connssl->req_flags, 0, 0, NULL, 0,
-    &connssl->ctxt_handle, &outbuf_desc,
-    &connssl->ret_flags, &connssl->time_stamp);
+  sspi_status = s_pSecFn->InitializeSecurityContextA(
+    &connssl->cred->cred_handle, NULL, conn->host.name,
+    connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle,
+    &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
@@ -180,6 +194,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
     else
       failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n",
             sspi_status);
+    free(connssl->ctxt);
+    connssl->ctxt = NULL;
     return CURLE_SSL_CONNECT_ERROR;
   }
 
@@ -288,9 +304,9 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
   sspi_status = s_pSecFn->InitializeSecurityContextA(
-    &connssl->cred_handle, &connssl->ctxt_handle, conn->host.name,
-    connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc,
-    &connssl->ret_flags, &connssl->time_stamp);
+    &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
+    conn->host.name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+    &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
   /* free buffer for received handshake data */
   free(inbuf[0].pvBuffer);
@@ -374,9 +390,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
   CURLcode retcode = CURLE_OK;
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  CredHandle *our_cred_handle = &conn->ssl[sockindex].cred_handle;
-  CredHandle *old_cred_handle = NULL;
-  CredHandle *new_cred_handle = NULL;
+  curl_schannel_cred *old_cred = NULL;
   int incache;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -399,24 +413,17 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
   }
 
   /* save the current session data for possible re-use */
-  incache = !(Curl_ssl_getsessionid(conn, &old_cred_handle, NULL));
+  incache = !(Curl_ssl_getsessionid(conn, &old_cred, NULL));
   if(incache) {
-    if(memcmp(old_cred_handle, our_cred_handle, sizeof(CredHandle))) {
+    if(old_cred != connssl->cred) {
       infof(data, "schannel: old credential handle is stale, removing\n");
-      Curl_ssl_delsessionid(conn, old_cred_handle);
+      Curl_ssl_delsessionid(conn, old_cred);
       incache = FALSE;
     }
   }
   if(!incache) {
-    new_cred_handle = malloc(sizeof(CredHandle));
-    if(new_cred_handle) {
-      memcpy(new_cred_handle, our_cred_handle, sizeof(CredHandle));
-      retcode = Curl_ssl_addsessionid(conn,
-                                      new_cred_handle, sizeof(CredHandle));
-    }
-    else {
-      retcode = CURLE_OUT_OF_MEMORY;
-    }
+    retcode = Curl_ssl_addsessionid(conn, connssl->cred,
+                                    sizeof(curl_schannel_cred));
     if(retcode) {
       failf(data, "schannel: failed to store credential handle\n");
       return retcode;
@@ -554,9 +561,9 @@ schannel_send(struct connectdata *conn, int sockindex,
 
   /* check if the maximum stream sizes were queried */
   if(connssl->stream_sizes.cbMaximumMessage == 0) {
-    sspi_status = s_pSecFn->QueryContextAttributesA(&connssl->ctxt_handle,
-                                                    SECPKG_ATTR_STREAM_SIZES,
-                                                    &connssl->stream_sizes);
+    sspi_status = s_pSecFn->QueryContextAttributesA(
+                              &connssl->ctxt->ctxt_handle,
+                              SECPKG_ATTR_STREAM_SIZES, &connssl->stream_sizes);
     if(sspi_status != SEC_E_OK) {
       *err = CURLE_SEND_ERROR;
       return -1;
@@ -603,7 +610,7 @@ schannel_send(struct connectdata *conn, int sockindex,
   memcpy(outbuf[1].pvBuffer, buf, len);
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
-  sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt_handle, 0,
+  sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
                                          &outbuf_desc, 0);
 
   /* check if the message was encrypted */
@@ -723,7 +730,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
     inbuf_desc.ulVersion = SECBUFFER_VERSION;
 
     /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
-    sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt_handle,
+    sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
                                            &inbuf_desc, 0, NULL);
     infof(data, "schannel: DecryptMessage %d\n", sspi_status);
 
@@ -847,7 +854,7 @@ Curl_schannel_connect(struct connectdata *conn, int sockindex) {
 bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) {
   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
-  if(connssl->schannel) /* SSL is in use */
+  if(connssl->use) /* SSL is in use */
     return (connssl->encdata_offset > 0 ||
             connssl->decdata_offset > 0 ) ? TRUE : FALSE;
   else
@@ -861,9 +868,11 @@ void Curl_schannel_close(struct connectdata *conn, int sockindex) {
   infof(data, "schannel: Closing connection with %s:%d\n",
         conn->host.name, conn->remote_port);
 
-  /* free SSPI Schannel API context and handle */
-  if(connssl->schannel) {
-    s_pSecFn->DeleteSecurityContext(&connssl->ctxt_handle);
+  /* free SSPI Schannel API security context handle */
+  if(connssl->ctxt) {
+    s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
+    free(connssl->ctxt);
+    connssl->ctxt = NULL;
   }
 
   /* free internal buffer for received encrypted data */
@@ -888,8 +897,12 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) {
 }
 
 void Curl_schannel_session_free(void *ptr) {
-  s_pSecFn->FreeCredentialsHandle((CredHandle*) ptr);
-  free(ptr);
+  curl_schannel_cred *cred = ptr;
+
+  if(cred) {
+    s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+    free(cred);
+  }
 }
 
 int Curl_schannel_init() {
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index 108fa2e..fa6fc90 100755
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -26,10 +26,22 @@
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_SCHANNEL
 
+#include <schnlsp.h>
+
 #ifndef UNISP_NAME_A
 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
 #endif
 
+typedef struct curl_schannel_cred {
+  CredHandle cred_handle;
+  TimeStamp time_stamp;
+} curl_schannel_cred;
+
+typedef struct curl_schannel_ctxt {
+  CtxtHandle ctxt_handle;
+  TimeStamp time_stamp;
+} curl_schannel_ctxt;
+
 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
 
 CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
diff --git a/lib/urldata.h b/lib/urldata.h
index d371288..1bcc45c 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -132,8 +132,8 @@
 #endif /* USE_AXTLS */
 
 #ifdef USE_SCHANNEL
-#include <schnlsp.h>
 #include "curl_sspi.h"
+#include "curl_schannel.h"
 #endif
 
 #ifdef HAVE_NETINET_IN_H
@@ -290,10 +290,8 @@ struct ssl_connect_data {
   SSL*     ssl;
 #endif /* USE_AXTLS */
 #ifdef USE_SCHANNEL
-  bool schannel;
-  TimeStamp time_stamp;
-  CredHandle cred_handle;
-  CtxtHandle ctxt_handle;
+  curl_schannel_cred *cred;
+  curl_schannel_ctxt *ctxt;
   SecPkgContext_StreamSizes stream_sizes;
   ssl_connect_state connecting_state;
   size_t encdata_length, decdata_length;
-- 
1.7.9


From b48ccd87891b3441e2a9d744310d713fbe1e87cc Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 13:43:24 +0200
Subject: [PATCH 20/55] Removed TODO entry

Session handling and re-use has been implemented and tested on Win7
---
 lib/curl_schannel.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 370eb73..9157bda 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -38,7 +38,6 @@
 
 /*
  * TODO list for TLS/SSL implementation:
- * - implement session handling and re-use
  * - implement write buffering
  * - implement SSL/TLS shutdown
  * - special cases: renegotiation, certificates, algorithms
-- 
1.7.9


From b1a97354a1fd0e1c23cc66897af7a0dba3889757 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 21:21:31 +0200
Subject: [PATCH 21/55] Implemented SSL/TLS renegotiation

---
 lib/curl_schannel.c |   30 ++++++++++++++++++++++--------
 1 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 9157bda..ded3bb7 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -40,7 +40,9 @@
  * TODO list for TLS/SSL implementation:
  * - implement write buffering
  * - implement SSL/TLS shutdown
- * - special cases: renegotiation, certificates, algorithms
+ * - implement client certificates
+ * - implement server certificates
+ * - implement algorithm option
  */
 
 #include "setup.h"
@@ -232,8 +234,6 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   infof(data, "schannel: Connecting to %s:%d (step 2/3)\n",
         conn->host.name, conn->remote_port);
 
-  connssl->connecting_state = ssl_connect_2;
-
   /* buffer to store previously received and encrypted data */
   if(connssl->encdata_buffer == NULL) {
     connssl->encdata_offset = 0;
@@ -249,13 +249,13 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   read = sread(conn->sock[sockindex],
                connssl->encdata_buffer + connssl->encdata_offset,
                connssl->encdata_length - connssl->encdata_offset);
-  if(read < 0) {
+  if(read < 0 && connssl->connecting_state != ssl_connect_2_writing) {
     connssl->connecting_state = ssl_connect_2_reading;
     infof(data, "schannel: failed to receive handshake, waiting for more: %d\n",
           read);
     return CURLE_OK;
   }
-  else if(read == 0) {
+  else if(read == 0 && connssl->connecting_state != ssl_connect_2_writing) {
     failf(data, "schannel: failed to receive handshake, connection failed\n");
     return CURLE_SSL_CONNECT_ERROR;
   }
@@ -697,15 +697,19 @@ schannel_recv(struct connectdata *conn, int sockindex,
       /* increase encrypted data buffer offset */
       connssl->encdata_offset += read;
     }
+    else if(connssl->encdata_offset == 0) {
+      if(read == 0)
+        ret = 0;
+      else
+        *err = CURLE_AGAIN;
+    }
   }
 
   infof(data, "schannel: encrypted data buffer %d/%d\n",
     connssl->encdata_offset, connssl->encdata_length);
 
   /* check if we still have some data in our buffers */
-  while(connssl->encdata_offset > 0 &&
-        sspi_status != SEC_E_INCOMPLETE_MESSAGE) {
-
+  while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK) {
     /* prepare data buffer for DecryptMessage call */
     inbuf[0].pvBuffer = connssl->encdata_buffer;
     inbuf[0].cbBuffer = connssl->encdata_offset;
@@ -783,9 +787,12 @@ schannel_recv(struct connectdata *conn, int sockindex,
 
       /* begin renegotiation */
       connssl->state = ssl_connection_negotiating;
+      connssl->connecting_state = ssl_connect_2_writing;
       retcode = schannel_connect_common(conn, sockindex, FALSE, &done);
       if(retcode)
         *err = retcode;
+      else /* now retry receiving data */
+        return schannel_recv(conn, sockindex, buf, len, err);
     }
   }
 
@@ -815,6 +822,13 @@ schannel_recv(struct connectdata *conn, int sockindex,
                                       connssl->decdata_length);
   }
 
+  /* check if the server closed the connection */
+  if(ret <= 0 && sspi_status == SEC_I_CONTEXT_EXPIRED) {
+    infof(data, "schannel: server closed the connection\n");
+    *err = CURLE_OK;
+    return 0;
+  }
+
   /* check if something went wrong and we need to return an error */
   if(ret < 0) {
     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE)
-- 
1.7.9


From 8777d1438cbefee0c212c93a72152ea5f715254d Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 21:22:01 +0200
Subject: [PATCH 22/55] Updated verbose messages in negotiation steps

---
 lib/curl_schannel.c |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index ded3bb7..3b38c07 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -88,7 +88,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   struct in6_addr addr6;
 #endif
 
-  infof(data, "schannel: Connecting to %s:%d (step 1/3)\n",
+  infof(data, "schannel: connecting to %s:%d (step 1/3)\n",
         conn->host.name, conn->remote_port);
 
   /* check for an existing re-usable credential handle */
@@ -231,7 +231,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   SecBufferDesc inbuf_desc;
   SECURITY_STATUS sspi_status = SEC_E_OK;
 
-  infof(data, "schannel: Connecting to %s:%d (step 2/3)\n",
+  infof(data, "schannel: connecting to %s:%d (step 2/3)\n",
         conn->host.name, conn->remote_port);
 
   /* buffer to store previously received and encrypted data */
@@ -394,6 +394,9 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
+  infof(data, "schannel: connecting to %s:%d (step 3/3)\n",
+        conn->host.name, conn->remote_port);
+
   /* check if the required context attributes are met */
   if(connssl->ret_flags != connssl->req_flags) {
     if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
-- 
1.7.9


From a6a1614f178ea10001f78e3576e0042642b515c9 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 21:49:35 +0200
Subject: [PATCH 23/55] Added special shutdown check for Windows 2000
 Professional

Windows 2000 Professional:  Schannel returns SEC_E_OK instead
of SEC_I_CONTEXT_EXPIRED. If the length of the output buffer
is zero and the first byte of the encrypted packet is 0x15,
the application can safely assume that the message was a
close_notify message and change the return value to
SEC_I_CONTEXT_EXPIRED.
---
 lib/curl_schannel.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 3b38c07..430414b 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -826,7 +826,9 @@ schannel_recv(struct connectdata *conn, int sockindex,
   }
 
   /* check if the server closed the connection */
-  if(ret <= 0 && sspi_status == SEC_I_CONTEXT_EXPIRED) {
+  if(ret <= 0 && ( /* special check for Windows 2000 Professional */
+      sspi_status == SEC_I_CONTEXT_EXPIRED || (sspi_status == SEC_E_OK &&
+        connssl->encdata_offset > 0 && connssl->encdata_buffer[0] == 0x15))) {
     infof(data, "schannel: server closed the connection\n");
     *err = CURLE_OK;
     return 0;
-- 
1.7.9


From 7ff8dde3a8c6091f0d13e5232699be7ccf990c95 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 22:29:50 +0200
Subject: [PATCH 24/55] Connection shutdown does not mean that there is no
 data to read

---
 lib/curl_schannel.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 430414b..9930665 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -741,7 +741,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
     infof(data, "schannel: DecryptMessage %d\n", sspi_status);
 
     /* check if everything went fine (server may want to renegotiate context) */
-    if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE) {
+    if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
+                                  sspi_status == SEC_I_CONTEXT_EXPIRED) {
       /* check for successfully decrypted data */
       if(inbuf[1].BufferType == SECBUFFER_DATA) {
         infof(data, "schannel: decrypted data length: %d\n", inbuf[1].cbBuffer);
-- 
1.7.9


From e86df0ef3fddc5a0c6d1ae044a8519f13574b1eb Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 22:30:20 +0200
Subject: [PATCH 25/55] Correctly handle incomplete message and ask curl to
 re-read

---
 lib/curl_schannel.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 9930665..a1adb49 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -740,6 +740,13 @@ schannel_recv(struct connectdata *conn, int sockindex,
                                            &inbuf_desc, 0, NULL);
     infof(data, "schannel: DecryptMessage %d\n", sspi_status);
 
+    /* check if we need more data */
+    if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+      infof(data, "schannel: failed to decrypt data, need more data\n");
+      *err = CURLE_AGAIN;
+      return -1;
+    }
+
     /* check if everything went fine (server may want to renegotiate context) */
     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
                                   sspi_status == SEC_I_CONTEXT_EXPIRED) {
@@ -836,11 +843,9 @@ schannel_recv(struct connectdata *conn, int sockindex,
   }
 
   /* check if something went wrong and we need to return an error */
-  if(ret < 0) {
-    if(sspi_status == SEC_E_INCOMPLETE_MESSAGE)
-      *err = CURLE_AGAIN;
-    else if(sspi_status != SEC_E_OK)
-      *err = CURLE_RECV_ERROR;
+  if(ret < 0 && sspi_status != SEC_E_OK) {
+    infof(data, "schannel: failed to read data from server\n");
+    *err = CURLE_RECV_ERROR;
     return -1;
   }
 
-- 
1.7.9


From 4f45174f9ace9d33edd20a3fb916f5024b2c1bc4 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 22:36:05 +0200
Subject: [PATCH 26/55] Re-added SSL check around https_getsock fallback

---
 lib/http.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lib/http.c b/lib/http.c
index 15a325c..54c613f 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1398,6 +1398,7 @@ static int https_getsock(struct connectdata *conn,
   return CURLE_OK;
 }
 #else
+#ifdef USE_SSL
 static int https_getsock(struct connectdata *conn,
                          curl_socket_t *socks,
                          int numsocks)
@@ -1407,6 +1408,7 @@ static int https_getsock(struct connectdata *conn,
   (void)numsocks;
   return GETSOCK_BLANK;
 }
+#endif /* USE_SSL */
 #endif /* USE_SSLEAY || USE_GNUTLS */
 
 /*
-- 
1.7.9


From 0490f9c361638f6e6ea8a667a2961e0b87f7de21 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Tue, 10 Apr 2012 22:51:40 +0200
Subject: [PATCH 27/55] Fixed buffer for decrypted being to small

---
 lib/curl_schannel.c |   30 +++++++++++++++++-------------
 1 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index a1adb49..4c485b7 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -662,7 +662,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
     }
   }
 
-  /* increase buffers in order to fit the requested amount of data */
+  /* increase buffer in order to fit the requested amount of data */
   while(connssl->encdata_length - connssl->encdata_offset < 2048 ||
         connssl->encdata_length < len) {
     /* increase internal encrypted data buffer */
@@ -674,16 +674,6 @@ schannel_recv(struct connectdata *conn, int sockindex,
       *err = CURLE_OUT_OF_MEMORY;
       return -1;
     }
-
-    /* increase internal decrypted data buffer */
-    connssl->decdata_length += 2048;
-    connssl->decdata_buffer = realloc(connssl->decdata_buffer,
-                                      connssl->decdata_length);
-    if(connssl->decdata_buffer == NULL) {
-      failf(data, "schannel: unable to re-allocate memory");
-      *err = CURLE_OUT_OF_MEMORY;
-      return -1;
-    }
   }
 
   /* read encrypted data from socket */
@@ -754,9 +744,23 @@ schannel_recv(struct connectdata *conn, int sockindex,
       if(inbuf[1].BufferType == SECBUFFER_DATA) {
         infof(data, "schannel: decrypted data length: %d\n", inbuf[1].cbBuffer);
 
+        /* increase buffer in order to fit the received amount of data */
+        size = inbuf[1].cbBuffer > 2048 ? inbuf[1].cbBuffer : 2048;
+        while(connssl->decdata_length - connssl->decdata_offset < size ||
+              connssl->decdata_length < len) {
+          /* increase internal decrypted data buffer */
+          connssl->decdata_length += size;
+          connssl->decdata_buffer = realloc(connssl->decdata_buffer,
+                                            connssl->decdata_length);
+          if(connssl->decdata_buffer == NULL) {
+            failf(data, "schannel: unable to re-allocate memory");
+            *err = CURLE_OUT_OF_MEMORY;
+            return -1;
+          }
+        }
+
         /* copy decrypted data to internal buffer */
-        size = connssl->decdata_length - connssl->decdata_offset;
-        size = size < inbuf[1].cbBuffer ? size : inbuf[1].cbBuffer;
+        size = inbuf[1].cbBuffer;
         if(size > 0) {
           memcpy(connssl->decdata_buffer + connssl->decdata_offset,
                  inbuf[1].pvBuffer, size);
-- 
1.7.9


From 9cba2e82e66cbb65d44df63a74111d8aec94ab07 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 11 Apr 2012 17:23:01 +0200
Subject: [PATCH 28/55] Re-structured read condition to be more effective

---
 lib/curl_schannel.c |   23 ++++++++++++-----------
 1 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 4c485b7..a58be66 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -249,20 +249,21 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   read = sread(conn->sock[sockindex],
                connssl->encdata_buffer + connssl->encdata_offset,
                connssl->encdata_length - connssl->encdata_offset);
-  if(read < 0 && connssl->connecting_state != ssl_connect_2_writing) {
-    connssl->connecting_state = ssl_connect_2_reading;
-    infof(data, "schannel: failed to receive handshake, waiting for more: %d\n",
-          read);
-    return CURLE_OK;
-  }
-  else if(read == 0 && connssl->connecting_state != ssl_connect_2_writing) {
-    failf(data, "schannel: failed to receive handshake, connection failed\n");
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-  else if(read > 0) {
+  if(read > 0) {
     /* increase encrypted data buffer offset */
     connssl->encdata_offset += read;
   }
+  else if(connssl->connecting_state != ssl_connect_2_writing) {
+    if(read < 0) {
+      connssl->connecting_state = ssl_connect_2_reading;
+      infof(data, "schannel: failed to receive handshake, need more data\n");
+      return CURLE_OK;
+    }
+    else if(read == 0) {
+      failf(data, "schannel: failed to receive handshake, connection failed\n");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
 
   infof(data, "schannel: encrypted data buffer %d/%d\n",
     connssl->encdata_offset, connssl->encdata_length);
-- 
1.7.9


From ed8a504244d237e0d22c911ad54f5e77322ddffd Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 11 Apr 2012 17:24:04 +0200
Subject: [PATCH 29/55] Removed obsolete verbose messages

---
 lib/curl_schannel.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index a58be66..55706d2 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -729,7 +729,6 @@ schannel_recv(struct connectdata *conn, int sockindex,
     /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
     sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
                                            &inbuf_desc, 0, NULL);
-    infof(data, "schannel: DecryptMessage %d\n", sspi_status);
 
     /* check if we need more data */
     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
@@ -854,9 +853,6 @@ schannel_recv(struct connectdata *conn, int sockindex,
     return -1;
   }
 
-  /* everything went fine */
-  infof(data, "schannel: read returns %d with error code %d\n", ret, *err);
-
   return ret;
 }
 
-- 
1.7.9


From a84b289eb9105c49db6e410e3716c2107c21fd66 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 11 Apr 2012 17:25:26 +0200
Subject: [PATCH 30/55] Added formatted SSPI error messages

---
 lib/curl_schannel.c |   76 +++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 55706d2..f111897 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -70,6 +70,45 @@
  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
  */
 
+/* helper function which always returns a usable status message string */
+#ifdef WIN32
+static char* sspi_status_msg(SECURITY_STATUS status) {
+  LPSTR format_msg = NULL;
+  char *status_msg = NULL;
+  int status_len = 0;
+
+  status_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                             FORMAT_MESSAGE_FROM_SYSTEM |
+                             FORMAT_MESSAGE_IGNORE_INSERTS,
+                             NULL, status, 0, (LPTSTR)&format_msg, 0, NULL);
+  if(status_len > 0 && format_msg) {
+    status_msg = strdup(format_msg);
+    LocalFree(format_msg);
+
+    /* remove trailing CR+LF */
+    if(status_len > 0) {
+      if(status_msg[status_len-1] == '\n') {
+        status_msg[status_len-1] = '\0';
+        if(status_len > 1) {
+          if(status_msg[status_len-2] == '\r') {
+            status_msg[status_len-2] = '\0';
+          }
+        }
+      }
+    }
+  }
+  else {
+    status_msg = curl_maprintf("%08X", status);
+  }
+
+  return status_msg;
+}
+#else
+static char* sspi_status_msg(SECURITY_STATUS status) {
+  return curl_maprintf("%08X", status);
+}
+#endif
+
 static Curl_recv schannel_recv;
 static Curl_send schannel_send;
 
@@ -83,6 +122,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   SCHANNEL_CRED schannel_cred;
   SECURITY_STATUS sspi_status = SEC_E_OK;
   curl_schannel_cred *old_cred = NULL;
+  char *sspi_msg = NULL;
   struct in_addr addr;
 #ifdef ENABLE_IPV6
   struct in6_addr addr6;
@@ -150,11 +190,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
       &connssl->cred->cred_handle, &connssl->cred->time_stamp);
 
     if(sspi_status != SEC_E_OK) {
+      sspi_msg = sspi_status_msg(sspi_status);
       if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-        failf(data, "schannel: SNI or certificate check failed\n");
+        failf(data, "schannel: SNI or certificate check failed: %s\n",
+              sspi_msg);
       else
-        failf(data, "schannel: AcquireCredentialsHandleA failed: %d\n",
-              sspi_status);
+        failf(data, "schannel: AcquireCredentialsHandleA failed: %s\n",
+              sspi_msg);
+      free(sspi_msg);
       free(connssl->cred);
       connssl->cred = NULL;
       return CURLE_SSL_CONNECT_ERROR;
@@ -190,11 +233,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
+    sspi_msg = sspi_status_msg(sspi_status);
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-      failf(data, "schannel: SNI or certificate check failed\n");
+      failf(data, "schannel: SNI or certificate check failed: %s\n",
+            sspi_msg);
     else
-      failf(data, "schannel: initial InitializeSecurityContextA failed: %d\n",
-            sspi_status);
+      failf(data, "schannel: initial InitializeSecurityContextA failed: %s\n",
+            sspi_msg);
+    free(sspi_msg);
     free(connssl->ctxt);
     connssl->ctxt = NULL;
     return CURLE_SSL_CONNECT_ERROR;
@@ -230,6 +276,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   SecBuffer inbuf[2];
   SecBufferDesc inbuf_desc;
   SECURITY_STATUS sspi_status = SEC_E_OK;
+  char *sspi_msg = NULL;
 
   infof(data, "schannel: connecting to %s:%d (step 2/3)\n",
         conn->host.name, conn->remote_port);
@@ -314,8 +361,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   /* check if the handshake was incomplete */
   if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
     connssl->connecting_state = ssl_connect_2_reading;
-    infof(data, "schannel: received incomplete message, need more data: %d\n",
-          sspi_status);
+    infof(data, "schannel: received incomplete message, need more data\n");
     return CURLE_OK;
   }
 
@@ -344,11 +390,14 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
     }
   }
   else {
+    sspi_msg = sspi_status_msg(sspi_status);
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
-      failf(data, "schannel: SNI or certificate check failed\n");
+      failf(data, "schannel: SNI or certificate check failed: %s\n",
+            sspi_msg);
     else
-      failf(data, "schannel: next InitializeSecurityContextA failed: %d\n",
-            sspi_status);
+      failf(data, "schannel: next InitializeSecurityContextA failed: %s\n",
+            sspi_msg);
+    free(sspi_msg);
     return CURLE_SSL_CONNECT_ERROR;
   }
 
@@ -648,6 +697,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
   SecBuffer inbuf[4];
   SecBufferDesc inbuf_desc;
   SECURITY_STATUS sspi_status = SEC_E_OK;
+  char *sspi_msg = NULL;
 
   infof(data, "schannel: client wants to read %d\n", len);
   *err = CURLE_OK;
@@ -848,7 +898,9 @@ schannel_recv(struct connectdata *conn, int sockindex,
 
   /* check if something went wrong and we need to return an error */
   if(ret < 0 && sspi_status != SEC_E_OK) {
-    infof(data, "schannel: failed to read data from server\n");
+    sspi_msg = sspi_status_msg(sspi_status);
+    infof(data, "schannel: failed to read data from server: %s\n", sspi_msg);
+    free(sspi_msg);
     *err = CURLE_RECV_ERROR;
     return -1;
   }
-- 
1.7.9


From db7b0938304635bf407cec53bdfc895f6f7d06d5 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 11 Apr 2012 18:40:04 +0200
Subject: [PATCH 31/55] Refactored socks_sspi and curl_schannel to use same
 error message functions

Moved the error constant switch to curl_sspi.c and added two new helper
functions to curl_sspi.[ch] which either return the constant or a fully
translated message representing the SSPI security status.
Updated socks_sspi.c and curl_schannel.c to use the new functions.
---
 lib/curl_schannel.c |   47 ++---------------
 lib/curl_sspi.c     |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/curl_sspi.h     |    2 +
 lib/socks_sspi.c    |   90 ++-----------------------------
 4 files changed, 159 insertions(+), 129 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index f111897..d6d304a 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -70,45 +70,6 @@
  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
  */
 
-/* helper function which always returns a usable status message string */
-#ifdef WIN32
-static char* sspi_status_msg(SECURITY_STATUS status) {
-  LPSTR format_msg = NULL;
-  char *status_msg = NULL;
-  int status_len = 0;
-
-  status_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                             FORMAT_MESSAGE_FROM_SYSTEM |
-                             FORMAT_MESSAGE_IGNORE_INSERTS,
-                             NULL, status, 0, (LPTSTR)&format_msg, 0, NULL);
-  if(status_len > 0 && format_msg) {
-    status_msg = strdup(format_msg);
-    LocalFree(format_msg);
-
-    /* remove trailing CR+LF */
-    if(status_len > 0) {
-      if(status_msg[status_len-1] == '\n') {
-        status_msg[status_len-1] = '\0';
-        if(status_len > 1) {
-          if(status_msg[status_len-2] == '\r') {
-            status_msg[status_len-2] = '\0';
-          }
-        }
-      }
-    }
-  }
-  else {
-    status_msg = curl_maprintf("%08X", status);
-  }
-
-  return status_msg;
-}
-#else
-static char* sspi_status_msg(SECURITY_STATUS status) {
-  return curl_maprintf("%08X", status);
-}
-#endif
-
 static Curl_recv schannel_recv;
 static Curl_send schannel_send;
 
@@ -190,7 +151,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
       &connssl->cred->cred_handle, &connssl->cred->time_stamp);
 
     if(sspi_status != SEC_E_OK) {
-      sspi_msg = sspi_status_msg(sspi_status);
+      sspi_msg = Curl_sspi_status_msg(sspi_status);
       if(sspi_status == SEC_E_WRONG_PRINCIPAL)
         failf(data, "schannel: SNI or certificate check failed: %s\n",
               sspi_msg);
@@ -233,7 +194,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
-    sspi_msg = sspi_status_msg(sspi_status);
+    sspi_msg = Curl_sspi_status_msg(sspi_status);
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
       failf(data, "schannel: SNI or certificate check failed: %s\n",
             sspi_msg);
@@ -390,7 +351,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
     }
   }
   else {
-    sspi_msg = sspi_status_msg(sspi_status);
+    sspi_msg = Curl_sspi_status_msg(sspi_status);
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
       failf(data, "schannel: SNI or certificate check failed: %s\n",
             sspi_msg);
@@ -898,7 +859,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
 
   /* check if something went wrong and we need to return an error */
   if(ret < 0 && sspi_status != SEC_E_OK) {
-    sspi_msg = sspi_status_msg(sspi_status);
+    sspi_msg = Curl_sspi_status_msg(sspi_status);
     infof(data, "schannel: failed to read data from server: %s\n", sspi_msg);
     free(sspi_msg);
     *err = CURLE_RECV_ERROR;
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index b985dbc..d915710 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -118,4 +118,153 @@ Curl_sspi_global_cleanup(void)
   }
 }
 
+
+/*
+ * Curl_sspi_status(SECURIY_STATUS status)
+ *
+ * This function returns a string representing an SSPI status.
+ * It will in any case return a usable string pointer which needs to be freed.
+ */
+char*
+Curl_sspi_status(SECURITY_STATUS status)
+{
+  const char* status_const;
+
+  switch(status) {
+    case SEC_I_COMPLETE_AND_CONTINUE:
+      status_const = "SEC_I_COMPLETE_AND_CONTINUE";
+      break;
+    case SEC_I_COMPLETE_NEEDED:
+      status_const = "SEC_I_COMPLETE_NEEDED";
+      break;
+    case SEC_I_CONTINUE_NEEDED:
+      status_const = "SEC_I_CONTINUE_NEEDED";
+      break;
+    case SEC_I_CONTEXT_EXPIRED:
+      status_const = "SEC_I_CONTEXT_EXPIRED";
+      break;
+    case SEC_I_INCOMPLETE_CREDENTIALS:
+      status_const = "SEC_I_INCOMPLETE_CREDENTIALS";
+      break;
+    case SEC_I_RENEGOTIATE:
+      status_const = "SEC_I_RENEGOTIATE";
+      break;
+    case SEC_E_BUFFER_TOO_SMALL:
+      status_const = "SEC_E_BUFFER_TOO_SMALL";
+      break;
+    case SEC_E_CONTEXT_EXPIRED:
+      status_const = "SEC_E_CONTEXT_EXPIRED";
+      break;
+    case SEC_E_CRYPTO_SYSTEM_INVALID:
+      status_const = "SEC_E_CRYPTO_SYSTEM_INVALID";
+      break;
+    case SEC_E_INCOMPLETE_MESSAGE:
+      status_const = "SEC_E_INCOMPLETE_MESSAGE";
+      break;
+    case SEC_E_INSUFFICIENT_MEMORY:
+      status_const = "SEC_E_INSUFFICIENT_MEMORY";
+      break;
+    case SEC_E_INTERNAL_ERROR:
+      status_const = "SEC_E_INTERNAL_ERROR";
+      break;
+    case SEC_E_INVALID_HANDLE:
+      status_const = "SEC_E_INVALID_HANDLE";
+      break;
+    case SEC_E_INVALID_TOKEN:
+      status_const = "SEC_E_INVALID_TOKEN";
+      break;
+    case SEC_E_LOGON_DENIED:
+      status_const = "SEC_E_LOGON_DENIED";
+      break;
+    case SEC_E_MESSAGE_ALTERED:
+      status_const = "SEC_E_MESSAGE_ALTERED";
+      break;
+    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+      status_const = "SEC_E_NO_AUTHENTICATING_AUTHORITY";
+      break;
+    case SEC_E_NO_CREDENTIALS:
+      status_const = "SEC_E_NO_CREDENTIALS";
+      break;
+    case SEC_E_NOT_OWNER:
+      status_const = "SEC_E_NOT_OWNER";
+      break;
+    case SEC_E_OK:
+      status_const = "SEC_E_OK";
+      break;
+    case SEC_E_OUT_OF_SEQUENCE:
+      status_const = "SEC_E_OUT_OF_SEQUENCE";
+      break;
+    case SEC_E_QOP_NOT_SUPPORTED:
+      status_const = "SEC_E_QOP_NOT_SUPPORTED";
+      break;
+    case SEC_E_SECPKG_NOT_FOUND:
+      status_const = "SEC_E_SECPKG_NOT_FOUND";
+      break;
+    case SEC_E_TARGET_UNKNOWN:
+      status_const = "SEC_E_TARGET_UNKNOWN";
+      break;
+    case SEC_E_UNKNOWN_CREDENTIALS:
+      status_const = "SEC_E_UNKNOWN_CREDENTIALS";
+      break;
+    case SEC_E_UNSUPPORTED_FUNCTION:
+      status_const = "SEC_E_UNSUPPORTED_FUNCTION";
+      break;
+    case SEC_E_WRONG_PRINCIPAL:
+      status_const = "SEC_E_WRONG_PRINCIPAL";
+      break;
+    default:
+      status_const = "Unknown error";
+  }
+
+  return curl_maprintf("%s (0x%08X)", status_const, status);
+}
+
+/*
+ * Curl_sspi_status_msg(SECURITY_STATUS status)
+ *
+ * This function returns a message representing an SSPI status.
+ * It will in any case return a usable string pointer which needs to be freed.
+ */
+
+char*
+Curl_sspi_status_msg(SECURITY_STATUS status)
+{
+  LPSTR format_msg = NULL;
+  char *status_msg = NULL, *status_const = NULL;
+  int status_len = 0;
+
+  status_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                             FORMAT_MESSAGE_FROM_SYSTEM |
+                             FORMAT_MESSAGE_IGNORE_INSERTS,
+                             NULL, status, 0, (LPTSTR)&format_msg, 0, NULL);
+
+  if(status_len > 0 && format_msg) {
+    status_msg = strdup(format_msg);
+    LocalFree(format_msg);
+
+    /* remove trailing CR+LF */
+    if(status_len > 0) {
+      if(status_msg[status_len-1] == '\n') {
+        status_msg[status_len-1] = '\0';
+        if(status_len > 1) {
+          if(status_msg[status_len-2] == '\r') {
+            status_msg[status_len-2] = '\0';
+          }
+        }
+      }
+    }
+  }
+
+  status_const = Curl_sspi_status(status);
+  if(status_msg) {
+    status_msg = curl_maprintf("%s [%s]", status_msg, status_const);
+    free(status_const);
+  }
+  else {
+    status_msg = status_const;
+  }
+
+  return status_msg;
+}
+
 #endif /* USE_WINDOWS_SSPI */
diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h
index c0e4f36..8174878 100644
--- a/lib/curl_sspi.h
+++ b/lib/curl_sspi.h
@@ -63,6 +63,8 @@
 
 CURLcode Curl_sspi_global_init(void);
 void Curl_sspi_global_cleanup(void);
+char* Curl_sspi_status(SECURITY_STATUS status);
+char* Curl_sspi_status_msg(SECURITY_STATUS status);
 
 /* Forward-declaration of global variables defined in curl_sspi.c */
 
diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c
index d96a82e..1e724bb 100644
--- a/lib/socks_sspi.c
+++ b/lib/socks_sspi.c
@@ -53,98 +53,16 @@ static int check_sspi_err(struct SessionHandle *data,
                           SECURITY_STATUS minor_status,
                           const char* function)
 {
-  const char *txt;
+  char *sspi_msg = NULL;
   (void)minor_status;
 
   if(major_status != SEC_E_OK &&
      major_status != SEC_I_COMPLETE_AND_CONTINUE &&
      major_status != SEC_I_COMPLETE_NEEDED &&
      major_status != SEC_I_CONTINUE_NEEDED) {
-    failf(data, "SSPI error: %s failed: %d\n", function, major_status);
-    switch (major_status) {
-    case SEC_I_COMPLETE_AND_CONTINUE:
-      txt="SEC_I_COMPLETE_AND_CONTINUE";
-      break;
-    case SEC_I_COMPLETE_NEEDED:
-      txt="SEC_I_COMPLETE_NEEDED";
-      break;
-    case SEC_I_CONTINUE_NEEDED:
-      txt="SEC_I_CONTINUE_NEEDED";
-      break;
-    case SEC_I_CONTEXT_EXPIRED:
-      txt="SEC_I_CONTEXT_EXPIRED";
-      break;
-    case SEC_I_INCOMPLETE_CREDENTIALS:
-      txt="SEC_I_INCOMPLETE_CREDENTIALS";
-      break;
-    case SEC_I_RENEGOTIATE:
-      txt="SEC_I_RENEGOTIATE";
-      break;
-    case SEC_E_BUFFER_TOO_SMALL:
-      txt="SEC_E_BUFFER_TOO_SMALL";
-      break;
-    case SEC_E_CONTEXT_EXPIRED:
-      txt="SEC_E_CONTEXT_EXPIRED";
-      break;
-    case SEC_E_CRYPTO_SYSTEM_INVALID:
-      txt="SEC_E_CRYPTO_SYSTEM_INVALID";
-      break;
-    case SEC_E_INCOMPLETE_MESSAGE:
-      txt="SEC_E_INCOMPLETE_MESSAGE";
-      break;
-    case SEC_E_INSUFFICIENT_MEMORY:
-      txt="SEC_E_INSUFFICIENT_MEMORY";
-      break;
-    case SEC_E_INTERNAL_ERROR:
-      txt="SEC_E_INTERNAL_ERROR";
-      break;
-    case SEC_E_INVALID_HANDLE:
-      txt="SEC_E_INVALID_HANDLE";
-      break;
-    case SEC_E_INVALID_TOKEN:
-      txt="SEC_E_INVALID_TOKEN";
-      break;
-    case SEC_E_LOGON_DENIED:
-      txt="SEC_E_LOGON_DENIED";
-      break;
-    case SEC_E_MESSAGE_ALTERED:
-      txt="SEC_E_MESSAGE_ALTERED";
-      break;
-    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
-      txt="SEC_E_NO_AUTHENTICATING_AUTHORITY";
-      break;
-    case SEC_E_NO_CREDENTIALS:
-      txt="SEC_E_NO_CREDENTIALS";
-      break;
-    case SEC_E_NOT_OWNER:
-      txt="SEC_E_NOT_OWNER";
-      break;
-    case SEC_E_OUT_OF_SEQUENCE:
-      txt="SEC_E_OUT_OF_SEQUENCE";
-      break;
-    case SEC_E_QOP_NOT_SUPPORTED:
-      txt="SEC_E_QOP_NOT_SUPPORTED";
-      break;
-    case SEC_E_SECPKG_NOT_FOUND:
-      txt="SEC_E_SECPKG_NOT_FOUND";
-      break;
-    case SEC_E_TARGET_UNKNOWN:
-      txt="SEC_E_TARGET_UNKNOWN";
-      break;
-    case SEC_E_UNKNOWN_CREDENTIALS:
-      txt="SEC_E_UNKNOWN_CREDENTIALS";
-      break;
-    case SEC_E_UNSUPPORTED_FUNCTION:
-      txt="SEC_E_UNSUPPORTED_FUNCTION";
-      break;
-    case SEC_E_WRONG_PRINCIPAL:
-      txt="SEC_E_WRONG_PRINCIPAL";
-      break;
-    default:
-      txt="Unknown error";
-
-    }
-    failf(data, "SSPI error: %s failed: %s\n", function, txt);
+    sspi_msg = Curl_sspi_status_msg(major_status);
+    failf(data, "SSPI error: %s failed: %s\n", function, sspi_msg);
+    free(sspi_msg);
     return 1;
   }
   return 0;
-- 
1.7.9


From 92d20c751ab2f3d0206ac2c762e101f91108c159 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 11 Apr 2012 19:41:37 +0200
Subject: [PATCH 32/55] Changed memory reduction method to keep a minimum
 buffer of size 4096

---
 lib/curl_schannel.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index d6d304a..afec8cf 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -836,14 +836,14 @@ schannel_recv(struct connectdata *conn, int sockindex,
 
   /* reduce internal buffer length to reduce memory usage */
   if(connssl->encdata_length > 4096) {
-    connssl->encdata_length = connssl->encdata_offset > 0 ?
-                              connssl->encdata_offset + 2048 : 4096;
+    connssl->encdata_length = connssl->encdata_offset > 4096 ?
+                              connssl->encdata_offset : 4096;
     connssl->encdata_buffer = realloc(connssl->encdata_buffer,
                                       connssl->encdata_length);
   }
   if(connssl->decdata_length > 4096) {
-    connssl->decdata_length = connssl->decdata_offset > 0 ?
-                              connssl->decdata_offset + 2048 : 4096;
+    connssl->decdata_length = connssl->decdata_offset > 4096 ?
+                              connssl->decdata_offset : 4096;
     connssl->decdata_buffer = realloc(connssl->decdata_buffer,
                                       connssl->decdata_length);
   }
-- 
1.7.9


From f3a0d00d4f664669469edbe521d63fe446efb72d Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 11 Apr 2012 20:05:29 +0200
Subject: [PATCH 33/55] Updated TODO information and added related MSDN
 articles

---
 lib/curl_schannel.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index afec8cf..990c81f 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -40,9 +40,15 @@
  * TODO list for TLS/SSL implementation:
  * - implement write buffering
  * - implement SSL/TLS shutdown
- * - implement client certificates
- * - implement server certificates
- * - implement algorithm option
+ * - implement client certificate authentication
+ * - implement custom server certificate validation
+ * - implement cipher/algorithm option
+ *
+ * Related articles on MSDN:
+ * - Getting a Certificate for Schannel
+ *   http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
+ * - Specifying Schannel Ciphers and Cipher Strengths
+ *   http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
  */
 
 #include "setup.h"
-- 
1.7.9


From 9192604c0a12a99ecabb770cfb84006e656b6add Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:02:59 +0200
Subject: [PATCH 34/55] Fixed critical typo in conditions and added buffer
 length checks

---
 lib/curl_schannel.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 990c81f..d80de65 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -336,7 +336,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
     for(i = 0; i < 2; i++) {
       /* search for handshake tokens that need to be send */
-      if(outbuf[i].BufferType = SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
+      if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
         infof(data, "schannel: sending next handshake data: %d ...\n",
               outbuf[i].cbBuffer);
 
@@ -369,7 +369,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   }
 
   /* check if there was additional remaining encrypted data */
-  if(inbuf[1].BufferType = SECBUFFER_EXTRA) {
+  if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
     infof(data, "schannel: encrypted data length: %d\n", inbuf[1].cbBuffer);
 
     /* check if the remaining data is less than the total amount
@@ -790,7 +790,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
       }
 
       /* check for remaining encrypted data */
-      if(inbuf[3].BufferType = SECBUFFER_EXTRA) {
+      if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
         infof(data, "schannel: encrypted data length: %d\n", inbuf[3].cbBuffer);
 
         /* check if the remaining data is less than the total amount
-- 
1.7.9


From 37c40905fb09ead62641965ffda7e044cb5ab5b7 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:04:53 +0200
Subject: [PATCH 35/55] Moved interal struct types to urldata.h in order to
 avoid inclusion loop

---
 lib/curl_schannel.c |    1 -
 lib/curl_schannel.h |   10 +---------
 lib/urldata.h       |   18 ++++++++++++++++--
 3 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index d80de65..469f92b 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -56,7 +56,6 @@
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_SCHANNEL
 
-#include "urldata.h"
 #include "curl_sspi.h"
 #include "curl_schannel.h"
 #include "sslgen.h"
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index fa6fc90..aea47b2 100755
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -26,21 +26,13 @@
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_SCHANNEL
 
-#include <schnlsp.h>
+#include "urldata.h"
 
 #ifndef UNISP_NAME_A
 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
 #endif
 
-typedef struct curl_schannel_cred {
-  CredHandle cred_handle;
-  TimeStamp time_stamp;
-} curl_schannel_cred;
 
-typedef struct curl_schannel_ctxt {
-  CtxtHandle ctxt_handle;
-  TimeStamp time_stamp;
-} curl_schannel_ctxt;
 
 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
 
diff --git a/lib/urldata.h b/lib/urldata.h
index 1bcc45c..137da4d 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -132,8 +132,9 @@
 #endif /* USE_AXTLS */
 
 #ifdef USE_SCHANNEL
-#include "curl_sspi.h"
-#include "curl_schannel.h"
+#include <schnlsp.h>
+#include <sspi.h>
+#include <schannel.h>
 #endif
 
 #ifdef HAVE_NETINET_IN_H
@@ -219,6 +220,19 @@ enum protection_level {
 };
 #endif
 
+#ifdef USE_SCHANNEL
+/* Structs to store Schannel handles */
+typedef struct curl_schannel_cred {
+  CredHandle cred_handle;
+  TimeStamp time_stamp;
+} curl_schannel_cred;
+
+typedef struct curl_schannel_ctxt {
+  CtxtHandle ctxt_handle;
+  TimeStamp time_stamp;
+} curl_schannel_ctxt;
+#endif
+
 /* enum for the nonblocking SSL connection state machine */
 typedef enum {
   ssl_connect_1,
-- 
1.7.9


From 3f06a3b1b47c6fc9f5a5ab07d6b118bb8aa9f08e Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:05:26 +0200
Subject: [PATCH 36/55] Fixed compiler warnings about pointer type assignments

---
 lib/curl_schannel.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 469f92b..96df8a4 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -98,7 +98,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
         conn->host.name, conn->remote_port);
 
   /* check for an existing re-usable credential handle */
-  if(!Curl_ssl_getsessionid(conn, &old_cred, NULL)) {
+  if(!Curl_ssl_getsessionid(conn, (void**)&old_cred, NULL)) {
     connssl->cred = old_cred;
     infof(data, "schannel: re-using existing credential handle\n");
   }
@@ -431,16 +431,16 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
   }
 
   /* save the current session data for possible re-use */
-  incache = !(Curl_ssl_getsessionid(conn, &old_cred, NULL));
+  incache = !(Curl_ssl_getsessionid(conn, (void**)&old_cred, NULL));
   if(incache) {
     if(old_cred != connssl->cred) {
       infof(data, "schannel: old credential handle is stale, removing\n");
-      Curl_ssl_delsessionid(conn, old_cred);
+      Curl_ssl_delsessionid(conn, (void*)old_cred);
       incache = FALSE;
     }
   }
   if(!incache) {
-    retcode = Curl_ssl_addsessionid(conn, connssl->cred,
+    retcode = Curl_ssl_addsessionid(conn, (void*)connssl->cred,
                                     sizeof(curl_schannel_cred));
     if(retcode) {
       failf(data, "schannel: failed to store credential handle\n");
-- 
1.7.9


From a1d7b470ec56f1a9d5a1ac15fcbcf7803aebae0b Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:08:40 +0200
Subject: [PATCH 37/55] Removed obsolete/unused variable

---
 lib/curl_schannel.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 96df8a4..057d91c 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -653,7 +653,6 @@ schannel_send(struct connectdata *conn, int sockindex,
 static ssize_t
 schannel_recv(struct connectdata *conn, int sockindex,
               char *buf, size_t len, CURLcode *err) {
-  int i = 0;
   size_t size = 0;
   ssize_t read = 0, ret = -1;
   CURLcode retcode;
-- 
1.7.9


From d56cd876853a042869a15b77f60b86a5104f8723 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:09:24 +0200
Subject: [PATCH 38/55] Added definitions which are missing in mingw32

---
 lib/curl_schannel.h |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index aea47b2..3e24fad 100755
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -32,6 +32,65 @@
 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
 #endif
 
+#ifndef UNISP_NAME_W
+#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME
+#ifdef UNICODE
+#define UNISP_NAME  UNISP_NAME_W
+#else
+#define UNISP_NAME  UNISP_NAME_A
+#endif
+#endif
+
+#ifndef SP_PROT_SSL2_CLIENT
+#define SP_PROT_SSL2_CLIENT             0x00000008
+#endif
+
+#ifndef SP_PROT_SSL3_CLIENT
+#define SP_PROT_SSL3_CLIENT             0x00000008
+#endif
+
+#ifndef SP_PROT_TLS1_CLIENT
+#define SP_PROT_TLS1_CLIENT             0x00000080
+#endif
+
+#ifndef SP_PROT_TLS1_0_CLIENT
+#define SP_PROT_TLS1_0_CLIENT           SP_PROT_TLS1_CLIENT
+#endif
+
+#ifndef SP_PROT_TLS1_1_CLIENT
+#define SP_PROT_TLS1_1_CLIENT           0x00000200
+#endif
+
+#ifndef SP_PROT_TLS1_2_CLIENT
+#define SP_PROT_TLS1_2_CLIENT           0x00000800
+#endif
+
+#ifndef SECBUFFER_ALERT
+#define SECBUFFER_ALERT                 17
+#endif
+
+#ifndef ISC_RET_REPLAY_DETECT
+#define ISC_RET_REPLAY_DETECT           0x00000004
+#endif
+
+#ifndef ISC_RET_SEQUENCE_DETECT
+#define ISC_RET_SEQUENCE_DETECT         0x00000008
+#endif
+
+#ifndef ISC_RET_CONFIDENTIALITY
+#define ISC_RET_CONFIDENTIALITY         0x00000010
+#endif
+
+#ifndef ISC_RET_ALLOCATED_MEMORY
+#define ISC_RET_ALLOCATED_MEMORY        0x00000100
+#endif
+
+#ifndef ISC_RET_STREAM
+#define ISC_RET_STREAM                  0x00008000
+#endif
 
 
 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
-- 
1.7.9


From 77d7875b1aa282f11ef1a3d8216011b309f43269 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:10:09 +0200
Subject: [PATCH 39/55] Call general SSPI function defines instead of ASCII
 declarations

---
 lib/curl_schannel.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 057d91c..dc1a9d1 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -151,7 +151,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
     memset(connssl->cred, 0, sizeof(curl_schannel_cred));
 
     /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
-    sspi_status = s_pSecFn->AcquireCredentialsHandleA(NULL,
+    sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL,
       UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
       &connssl->cred->cred_handle, &connssl->cred->time_stamp);
 
@@ -193,7 +193,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
   memset(connssl->ctxt, 0, sizeof(curl_schannel_ctxt));
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
-  sspi_status = s_pSecFn->InitializeSecurityContextA(
+  sspi_status = s_pSecFn->InitializeSecurityContext(
     &connssl->cred->cred_handle, NULL, conn->host.name,
     connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle,
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
@@ -316,7 +316,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, connssl->encdata_offset);
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
-  sspi_status = s_pSecFn->InitializeSecurityContextA(
+  sspi_status = s_pSecFn->InitializeSecurityContext(
     &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
     conn->host.name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
@@ -579,7 +579,7 @@ schannel_send(struct connectdata *conn, int sockindex,
 
   /* check if the maximum stream sizes were queried */
   if(connssl->stream_sizes.cbMaximumMessage == 0) {
-    sspi_status = s_pSecFn->QueryContextAttributesA(
+    sspi_status = s_pSecFn->QueryContextAttributes(
                               &connssl->ctxt->ctxt_handle,
                               SECPKG_ATTR_STREAM_SIZES, &connssl->stream_sizes);
     if(sspi_status != SEC_E_OK) {
-- 
1.7.9


From 319eb7f457fb2fd2799e3be77e7fe83d2d4be38a Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:15:40 +0200
Subject: [PATCH 40/55] Fixed VC compilation which requires SECURITY_WIN32 or
 SECURITY_KERNEL

---
 lib/urldata.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/urldata.h b/lib/urldata.h
index 137da4d..d066cb2 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -132,8 +132,8 @@
 #endif /* USE_AXTLS */
 
 #ifdef USE_SCHANNEL
+#include "curl_sspi.h"
 #include <schnlsp.h>
-#include <sspi.h>
 #include <schannel.h>
 #endif
 
-- 
1.7.9


From 9aa76981f266e891006a636d1ae37dbc4b057ae4 Mon Sep 17 00:00:00 2001
From: Guenter Knauf <lists@gknw.net>
Date: Fri, 13 Apr 2012 13:17:57 +0200
Subject: [PATCH 41/55] Updated mingw32 makefiles

---
 lib/Makefile.m32 |   13 +++++++++++--
 src/Makefile.m32 |    9 +++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index a6270b2..07aa613 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -124,6 +124,11 @@ endif
 ifeq ($(findstring -ipv6,$(CFG)),-ipv6)
 IPV6 = 1
 endif
+ifeq ($(findstring -schannel,$(CFG)),-schannel)
+SCHANNEL = 1
+SSPI = 1
+SSL = 1
+endif
 
 INCLUDES = -I. -I../include
 CFLAGS += -DBUILDING_LIBCURL
@@ -145,12 +150,16 @@ ifdef SSH2
   DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2
 endif
 ifdef SSL
+  CFLAGS += -DCURL_WANTS_CA_BUNDLE_ENV
+ifdef SCHANNEL
+  CFLAGS += -DUSE_SSL -DUSE_SCHANNEL
+else
   INCLUDES += -I"$(OPENSSL_INCLUDE)"
   CFLAGS += -DUSE_SSLEAY -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \
-            -DHAVE_ENGINE_LOAD_BUILTIN_ENGINES -DOPENSSL_NO_KRB5 \
-            -DCURL_WANTS_CA_BUNDLE_ENV
+            -DHAVE_ENGINE_LOAD_BUILTIN_ENGINES -DOPENSSL_NO_KRB5
   DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
 endif
+endif
 ifdef ZLIB
   INCLUDES += -I"$(ZLIB_PATH)"
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
diff --git a/src/Makefile.m32 b/src/Makefile.m32
index 29edc28..e6752f5 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -122,6 +122,11 @@ endif
 ifeq ($(findstring -ipv6,$(CFG)),-ipv6)
 IPV6 = 1
 endif
+ifeq ($(findstring -schannel,$(CFG)),-schannel)
+SCHANNEL = 1
+SSPI = 1
+SSL = 1
+endif
 
 INCLUDES = -I. -I.. -I../include -I../lib
 
@@ -149,9 +154,13 @@ ifdef SSH2
   curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
 endif
 ifdef SSL
+ifdef SCHANNEL
+  CFLAGS += -DUSE_SSL -DUSE_SCHANNEL
+else
   CFLAGS += -DUSE_SSLEAY -DHAVE_OPENSSL_ENGINE_H
   curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
 endif
+endif
 ifdef ZLIB
   INCLUDES += -I"$(ZLIB_PATH)"
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
-- 
1.7.9


From 10ba123908d1848183b22e96de8909ca7184e937 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Fri, 13 Apr 2012 13:29:37 +0200
Subject: [PATCH 42/55] Use generic UNISP_NAME definition instead of ASCII
 definition

---
 lib/curl_schannel.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index dc1a9d1..08ba20b 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -152,7 +152,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
 
     /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
     sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL,
-      UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
+      UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
       &connssl->cred->cred_handle, &connssl->cred->time_stamp);
 
     if(sspi_status != SEC_E_OK) {
-- 
1.7.9


From 878cb141bce1881623469dfd2e7b0c0fca8b1d35 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 14 Apr 2012 01:20:50 +0200
Subject: [PATCH 43/55] Fixed link to MSDN article Getting a Certificate for
 Schannel

---
 lib/curl_schannel.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 08ba20b..c9a3906 100755
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -46,7 +46,7 @@
  *
  * Related articles on MSDN:
  * - Getting a Certificate for Schannel
- *   http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
+ *   http://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx
  * - Specifying Schannel Ciphers and Cipher Strengths
  *   http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
  */
-- 
1.7.9


From 93a4180f340dc1d4c7fd04fc1bd849fe3a9372c0 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 14 Apr 2012 08:35:00 +0200
Subject: [PATCH 44/55] Removed executable flag set by cygwin from source
 files

---
 0 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100755 => 100644 lib/curl_schannel.c
 mode change 100755 => 100644 lib/curl_schannel.h

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
old mode 100755
new mode 100644
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
old mode 100755
new mode 100644
-- 
1.7.9


From d38f3da4822c8585cfaa865a4db8b9308316db95 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 14 Apr 2012 15:00:33 +0200
Subject: [PATCH 45/55] curl_sspi: Added Curl_sspi_version function

Added new function to get SSPI version as string.
Added required library version.lib to makefiles.
Changed curl_schannel.c to use Curl_sspi_version.
---
 lib/Makefile.m32          |    1 +
 lib/curl_schannel.c       |    8 +++---
 lib/curl_sspi.c           |   50 +++++++++++++++++++++++++++++++++++++++++++++
 lib/curl_sspi.h           |    1 +
 src/Makefile.m32          |    1 +
 winbuild/MakefileBuild.vc |    2 +
 6 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index 07aa613..cb91ba1 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -178,6 +178,7 @@ endif
 endif
 ifdef SSPI
   CFLAGS += -DUSE_WINDOWS_SSPI
+  DLL_LIBS += -lversion
 endif
 ifdef SPNEGO
   CFLAGS += -DHAVE_SPNEGO
diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index c9a3906..c7b51cb 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -957,10 +957,10 @@ void Curl_schannel_cleanup() {
 
 size_t Curl_schannel_version(char *buffer, size_t size)
 {
-  unsigned long version = s_pSecFn ? s_pSecFn->dwVersion : 0;
-  return snprintf(buffer, size, "Schannel/%d.%d.%d.%d",
-                  (version>>0)&0xff, (version>>8)&0xff,
-                  (version>>16)&0xff, (version>>24)&0xff);
+  char* version = Curl_sspi_version();
+  size = snprintf(buffer, size, "Schannel-%s", version);
+  free(version);
+  return size;
 }
 
 #endif /* USE_SCHANNEL */
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index d915710..d3533a2 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -120,6 +120,55 @@ Curl_sspi_global_cleanup(void)
 
 
 /*
+ * Curl_sspi_version()
+ *
+ * This function returns a string representing the SSPI library version.
+ * It will in any case return a usable string pointer which needs to be freed.
+ */
+char *
+Curl_sspi_version()
+{
+  VS_FIXEDFILEINFO *version_info = NULL;
+  LPTSTR version = NULL;
+  LPTSTR path = NULL;
+  LPVOID data = NULL;
+  DWORD size, handle;
+
+  if(s_hSecDll) {
+    path = malloc(MAX_PATH);
+    if(path) {
+      if(GetModuleFileName(s_hSecDll, path, MAX_PATH)) {
+        size = GetFileVersionInfoSize(path, &handle);
+        if(size) {
+          data = malloc(size);
+          if(data) {
+            if(GetFileVersionInfo(path, handle, size, data)) {
+              if(VerQueryValue(data, "\\", &version_info, &handle)) {
+                version = curl_maprintf("SSPI/%d.%d.%d.%d",
+                  (version_info->dwProductVersionMS>>16)&0xffff,
+                  (version_info->dwProductVersionMS>>0)&0xffff,
+                  (version_info->dwProductVersionLS>>16)&0xffff,
+                  (version_info->dwProductVersionLS>>0)&0xffff);
+              }
+            }
+            free(data);
+          }
+        }
+      }
+      free(path);
+    }
+    if(!version)
+      version = strdup("SSPI/Unknown");
+  }
+
+  if(!version)
+    version = strdup("");
+
+  return version;
+}
+
+
+/*
  * Curl_sspi_status(SECURIY_STATUS status)
  *
  * This function returns a string representing an SSPI status.
@@ -219,6 +268,7 @@ Curl_sspi_status(SECURITY_STATUS status)
   return curl_maprintf("%s (0x%08X)", status_const, status);
 }
 
+
 /*
  * Curl_sspi_status_msg(SECURITY_STATUS status)
  *
diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h
index 8174878..1865ee4 100644
--- a/lib/curl_sspi.h
+++ b/lib/curl_sspi.h
@@ -63,6 +63,7 @@
 
 CURLcode Curl_sspi_global_init(void);
 void Curl_sspi_global_cleanup(void);
+char* Curl_sspi_version();
 char* Curl_sspi_status(SECURITY_STATUS status);
 char* Curl_sspi_status_msg(SECURITY_STATUS status);
 
diff --git a/src/Makefile.m32 b/src/Makefile.m32
index e6752f5..8592de9 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -177,6 +177,7 @@ endif
 endif
 ifdef SSPI
   CFLAGS += -DUSE_WINDOWS_SSPI
+  curl_LDADD += -lversion
 endif
 ifdef SPNEGO
   CFLAGS += -DHAVE_SPNEGO
diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc
index 6053ba6..92dbe14 100644
--- a/winbuild/MakefileBuild.vc
+++ b/winbuild/MakefileBuild.vc
@@ -148,6 +148,7 @@ USE_SSPI=yes
 
 !IF "$(USE_SSPI)"=="yes"
 CFLAGS_SSPI = /DUSE_WINDOWS_SSPI
+LFLAGS_SSPI = version.lib
 USE_SSPI=true
 !ENDIF
 
@@ -286,6 +287,7 @@ CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ipv6
 
 !IF "$(USE_SSPI)"=="true"
 CFLAGS = $(CFLAGS) $(CFLAGS_SSPI)
+LFLAGS = $(LFLAGS) $(LFLAGS_SSPI)
 CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-sspi
 !ENDIF
 
-- 
1.7.9


From 69adbe9d053833164f06090552b6b15689b1e864 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 15 Apr 2012 04:12:26 +0200
Subject: [PATCH 46/55] curl_sspi.c: Fixed mingw32-gcc compiler warnings

---
 lib/curl_sspi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index d3533a2..c2652b3 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -133,6 +133,7 @@ Curl_sspi_version()
   LPTSTR path = NULL;
   LPVOID data = NULL;
   DWORD size, handle;
+  UINT length;
 
   if(s_hSecDll) {
     path = malloc(MAX_PATH);
@@ -143,7 +144,7 @@ Curl_sspi_version()
           data = malloc(size);
           if(data) {
             if(GetFileVersionInfo(path, handle, size, data)) {
-              if(VerQueryValue(data, "\\", &version_info, &handle)) {
+              if(VerQueryValue(data, "\\", (LPVOID*)&version_info, &length)) {
                 version = curl_maprintf("SSPI/%d.%d.%d.%d",
                   (version_info->dwProductVersionMS>>16)&0xffff,
                   (version_info->dwProductVersionMS>>0)&0xffff,
-- 
1.7.9


From ef357c4fdf6fe899e373d8560061df9c621101b8 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 15 Apr 2012 08:53:11 +0200
Subject: [PATCH 47/55] curl_sspi.c: Fixed length of error code hex output

The hex value was printed as signed 64-bit value on 64-bit systems:
SEC_E_WRONG_PRINCIPAL (0xFFFFFFFF80090322)

It is now correctly printed as the following:
SEC_E_WRONG_PRINCIPAL (0x80090322)
---
 lib/curl_sspi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index c2652b3..202a9e6 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -266,7 +266,8 @@ Curl_sspi_status(SECURITY_STATUS status)
       status_const = "Unknown error";
   }
 
-  return curl_maprintf("%s (0x%08X)", status_const, status);
+  return curl_maprintf("%s (0x%04X%04X)", status_const,
+                       (status>>16)&0xffff, status&0xffff);
 }
 
 
-- 
1.7.9


From af0ac5297ef1d9f44504b2e3613456cbb08ce5c8 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 15 Apr 2012 08:57:51 +0200
Subject: [PATCH 48/55] curl_sspi.c: Fallback to security function table
 version number

Instead of reporting an unknown version, the interface version is used.
---
 lib/curl_sspi.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 202a9e6..4f8f66f 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -159,7 +159,7 @@ Curl_sspi_version()
       free(path);
     }
     if(!version)
-      version = strdup("SSPI/Unknown");
+      version = curl_maprintf("SSPI/%d", s_pSecFn ? s_pSecFn->dwVersion : 0);
   }
 
   if(!version)
-- 
1.7.9


From 0879a5410aea708a22234fd512c731ff140015bb Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 15 Apr 2012 09:15:52 +0200
Subject: [PATCH 49/55] curl_sspi.c: Removed SSPI/ version prefix from
 Curl_sspi_version

curl_schannel.c: Version is now printed as
Schannel/a.b.c.d instead of Schannel-SSPI/a.b.c.d
---
 lib/curl_schannel.c |    2 +-
 lib/curl_sspi.c     |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index c7b51cb..da24a96 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -958,7 +958,7 @@ void Curl_schannel_cleanup() {
 size_t Curl_schannel_version(char *buffer, size_t size)
 {
   char* version = Curl_sspi_version();
-  size = snprintf(buffer, size, "Schannel-%s", version);
+  size = snprintf(buffer, size, "Schannel/%s", version);
   free(version);
   return size;
 }
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 4f8f66f..29f8a43 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -145,7 +145,7 @@ Curl_sspi_version()
           if(data) {
             if(GetFileVersionInfo(path, handle, size, data)) {
               if(VerQueryValue(data, "\\", (LPVOID*)&version_info, &length)) {
-                version = curl_maprintf("SSPI/%d.%d.%d.%d",
+                version = curl_maprintf("%d.%d.%d.%d",
                   (version_info->dwProductVersionMS>>16)&0xffff,
                   (version_info->dwProductVersionMS>>0)&0xffff,
                   (version_info->dwProductVersionLS>>16)&0xffff,
@@ -159,7 +159,7 @@ Curl_sspi_version()
       free(path);
     }
     if(!version)
-      version = curl_maprintf("SSPI/%d", s_pSecFn ? s_pSecFn->dwVersion : 0);
+      version = curl_maprintf("%d", s_pSecFn ? s_pSecFn->dwVersion : 0);
   }
 
   if(!version)
-- 
1.7.9


From 53704849b3c8aecfce5debb6b2b3cf92a22981fa Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 21 Apr 2012 18:43:49 +0200
Subject: [PATCH 50/55] curl_schannel: Replaced static buffer sizes with
 defined names

---
 lib/curl_schannel.c |   27 +++++++++++++++------------
 lib/curl_schannel.h |    4 ++++
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index da24a96..1ba1940 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -250,7 +250,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
   /* buffer to store previously received and encrypted data */
   if(connssl->encdata_buffer == NULL) {
     connssl->encdata_offset = 0;
-    connssl->encdata_length = 4096;
+    connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
     connssl->encdata_buffer = malloc(connssl->encdata_length);
     if(connssl->encdata_buffer == NULL) {
       failf(data, "schannel: unable to allocate memory");
@@ -670,7 +670,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
   /* buffer to store previously received and decrypted data */
   if(connssl->decdata_buffer == NULL) {
     connssl->decdata_offset = 0;
-    connssl->decdata_length = 4096;
+    connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
     connssl->decdata_buffer = malloc(connssl->decdata_length);
     if(connssl->decdata_buffer == NULL) {
       failf(data, "schannel: unable to allocate memory");
@@ -679,10 +679,10 @@ schannel_recv(struct connectdata *conn, int sockindex,
   }
 
   /* increase buffer in order to fit the requested amount of data */
-  while(connssl->encdata_length - connssl->encdata_offset < 2048 ||
-        connssl->encdata_length < len) {
+  while(connssl->encdata_length - connssl->encdata_offset <
+        CURL_SCHANNEL_BUFFER_STEP_SIZE || connssl->encdata_length < len) {
     /* increase internal encrypted data buffer */
-    connssl->encdata_length += 2048;
+    connssl->encdata_length += CURL_SCHANNEL_BUFFER_STEP_SIZE;
     connssl->encdata_buffer = realloc(connssl->encdata_buffer,
                                       connssl->encdata_length);
     if(connssl->encdata_buffer == NULL) {
@@ -760,7 +760,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
         infof(data, "schannel: decrypted data length: %d\n", inbuf[1].cbBuffer);
 
         /* increase buffer in order to fit the received amount of data */
-        size = inbuf[1].cbBuffer > 2048 ? inbuf[1].cbBuffer : 2048;
+        size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_STEP_SIZE ?
+               inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_STEP_SIZE;
         while(connssl->decdata_length - connssl->decdata_offset < size ||
               connssl->decdata_length < len) {
           /* increase internal decrypted data buffer */
@@ -839,15 +840,17 @@ schannel_recv(struct connectdata *conn, int sockindex,
   }
 
   /* reduce internal buffer length to reduce memory usage */
-  if(connssl->encdata_length > 4096) {
-    connssl->encdata_length = connssl->encdata_offset > 4096 ?
-                              connssl->encdata_offset : 4096;
+  if(connssl->encdata_length > CURL_SCHANNEL_BUFFER_INIT_SIZE) {
+    connssl->encdata_length =
+      connssl->encdata_offset > CURL_SCHANNEL_BUFFER_INIT_SIZE ?
+      connssl->encdata_offset : CURL_SCHANNEL_BUFFER_INIT_SIZE;
     connssl->encdata_buffer = realloc(connssl->encdata_buffer,
                                       connssl->encdata_length);
   }
-  if(connssl->decdata_length > 4096) {
-    connssl->decdata_length = connssl->decdata_offset > 4096 ?
-                              connssl->decdata_offset : 4096;
+  if(connssl->decdata_length > CURL_SCHANNEL_BUFFER_INIT_SIZE) {
+    connssl->decdata_length =
+      connssl->decdata_offset > CURL_SCHANNEL_BUFFER_INIT_SIZE ?
+      connssl->decdata_offset : CURL_SCHANNEL_BUFFER_INIT_SIZE;
     connssl->decdata_buffer = realloc(connssl->decdata_buffer,
                                       connssl->decdata_length);
   }
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index 3e24fad..fa19a02 100644
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -93,6 +93,10 @@
 #endif
 
 
+#define CURL_SCHANNEL_BUFFER_INIT_SIZE  4096
+#define CURL_SCHANNEL_BUFFER_STEP_SIZE  2048
+
+
 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
 
 CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
-- 
1.7.9


From 82dfb3baad80952de83f4d0a3cbd6f0be34b035a Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 21 Apr 2012 18:46:23 +0200
Subject: [PATCH 51/55] curl_schannel.c: First brace when declaring functions
 on column 0

---
 lib/curl_schannel.c |   42 ++++++++++++++++++++++++++++--------------
 1 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 1ba1940..86ed252 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -79,7 +79,8 @@ static Curl_recv schannel_recv;
 static Curl_send schannel_send;
 
 static CURLcode
-schannel_connect_step1(struct connectdata *conn, int sockindex) {
+schannel_connect_step1(struct connectdata *conn, int sockindex)
+{
   ssize_t write = -1;
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
@@ -232,7 +233,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) {
 }
 
 static CURLcode
-schannel_connect_step2(struct connectdata *conn, int sockindex) {
+schannel_connect_step2(struct connectdata *conn, int sockindex)
+{
   int i;
   ssize_t read = -1, write = -1;
   struct SessionHandle *data = conn->data;
@@ -401,7 +403,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
 }
 
 static CURLcode
-schannel_connect_step3(struct connectdata *conn, int sockindex) {
+schannel_connect_step3(struct connectdata *conn, int sockindex)
+{
   CURLcode retcode = CURLE_OK;
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -458,7 +461,8 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) {
 
 static CURLcode
 schannel_connect_common(struct connectdata *conn, int sockindex,
-                        bool nonblocking, bool *done) {
+                        bool nonblocking, bool *done)
+{
   CURLcode retcode;
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -568,7 +572,8 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
 
 static ssize_t
 schannel_send(struct connectdata *conn, int sockindex,
-              const void *buf, size_t len, CURLcode *err) {
+              const void *buf, size_t len, CURLcode *err)
+{
   ssize_t ret = -1;
   size_t data_len = 0;
   unsigned char *data = NULL;
@@ -652,7 +657,8 @@ schannel_send(struct connectdata *conn, int sockindex,
 
 static ssize_t
 schannel_recv(struct connectdata *conn, int sockindex,
-              char *buf, size_t len, CURLcode *err) {
+              char *buf, size_t len, CURLcode *err)
+{
   size_t size = 0;
   ssize_t read = 0, ret = -1;
   CURLcode retcode;
@@ -878,12 +884,14 @@ schannel_recv(struct connectdata *conn, int sockindex,
 
 CURLcode
 Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
-                                  bool *done) {
+                                  bool *done)
+{
   return schannel_connect_common(conn, sockindex, TRUE, done);
 }
 
 CURLcode
-Curl_schannel_connect(struct connectdata *conn, int sockindex) {
+Curl_schannel_connect(struct connectdata *conn, int sockindex)
+{
   CURLcode retcode;
   bool done = FALSE;
 
@@ -896,7 +904,8 @@ Curl_schannel_connect(struct connectdata *conn, int sockindex) {
   return CURLE_OK;
 }
 
-bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) {
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
+{
   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   if(connssl->use) /* SSL is in use */
@@ -906,7 +915,8 @@ bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) {
     return FALSE;
 }
 
-void Curl_schannel_close(struct connectdata *conn, int sockindex) {
+void Curl_schannel_close(struct connectdata *conn, int sockindex)
+{
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
@@ -937,11 +947,13 @@ void Curl_schannel_close(struct connectdata *conn, int sockindex) {
   }
 }
 
-int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) {
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
+{
   return CURLE_NOT_BUILT_IN; /* TODO: implement SSL/TLS shutdown */
 }
 
-void Curl_schannel_session_free(void *ptr) {
+void Curl_schannel_session_free(void *ptr)
+{
   curl_schannel_cred *cred = ptr;
 
   if(cred) {
@@ -950,11 +962,13 @@ void Curl_schannel_session_free(void *ptr) {
   }
 }
 
-int Curl_schannel_init() {
+int Curl_schannel_init()
+{
   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
 }
 
-void Curl_schannel_cleanup() {
+void Curl_schannel_cleanup()
+{
   Curl_sspi_global_cleanup();
 }
 
-- 
1.7.9


From 37e9572310fc1b8dc40cd3190adc1a803e5020b5 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 21 Apr 2012 18:48:52 +0200
Subject: [PATCH 52/55] curl_schannel.c: Put the pointer sign directly at
 variable name

---
 lib/curl_schannel.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 86ed252..e49b2d1 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -83,7 +83,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 {
   ssize_t write = -1;
   struct SessionHandle *data = conn->data;
-  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SecBuffer outbuf;
   SecBufferDesc outbuf_desc;
   SCHANNEL_CRED schannel_cred;
@@ -238,7 +238,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
   int i;
   ssize_t read = -1, write = -1;
   struct SessionHandle *data = conn->data;
-  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SecBuffer outbuf[2];
   SecBufferDesc outbuf_desc;
   SecBuffer inbuf[2];
@@ -974,7 +974,7 @@ void Curl_schannel_cleanup()
 
 size_t Curl_schannel_version(char *buffer, size_t size)
 {
-  char* version = Curl_sspi_version();
+  char *version = Curl_sspi_version();
   size = snprintf(buffer, size, "Schannel/%s", version);
   free(version);
   return size;
-- 
1.7.9


From 4fcce42998a08badd90637f8723bfb1d294ca307 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sat, 21 Apr 2012 18:51:40 +0200
Subject: [PATCH 53/55] curl_schannel.c: Use structs directly instead of
 typedef'ed structs

---
 lib/curl_schannel.c |   16 ++++++++--------
 lib/urldata.h       |   12 ++++++------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index e49b2d1..6991017 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -88,7 +88,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
   SecBufferDesc outbuf_desc;
   SCHANNEL_CRED schannel_cred;
   SECURITY_STATUS sspi_status = SEC_E_OK;
-  curl_schannel_cred *old_cred = NULL;
+  struct curl_schannel_cred *old_cred = NULL;
   char *sspi_msg = NULL;
   struct in_addr addr;
 #ifdef ENABLE_IPV6
@@ -144,12 +144,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
     }
 
     /* allocate memory for the re-usable credential handle */
-    connssl->cred = malloc(sizeof(curl_schannel_cred));
+    connssl->cred = malloc(sizeof(struct curl_schannel_cred));
     if (!connssl->cred) {
       failf(data, "schannel: unable to allocate memory");
       return CURLE_OUT_OF_MEMORY;
     }
-    memset(connssl->cred, 0, sizeof(curl_schannel_cred));
+    memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
 
     /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
     sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL,
@@ -186,12 +186,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
                        ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
 
   /* allocate memory for the security context handle */
-  connssl->ctxt = malloc(sizeof(curl_schannel_ctxt));
+  connssl->ctxt = malloc(sizeof(struct curl_schannel_ctxt));
   if (!connssl->ctxt) {
     failf(data, "schannel: unable to allocate memory");
     return CURLE_OUT_OF_MEMORY;
   }
-  memset(connssl->ctxt, 0, sizeof(curl_schannel_ctxt));
+  memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
   sspi_status = s_pSecFn->InitializeSecurityContext(
@@ -408,7 +408,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
   CURLcode retcode = CURLE_OK;
   struct SessionHandle *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  curl_schannel_cred *old_cred = NULL;
+  struct curl_schannel_cred *old_cred = NULL;
   int incache;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -444,7 +444,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
   }
   if(!incache) {
     retcode = Curl_ssl_addsessionid(conn, (void*)connssl->cred,
-                                    sizeof(curl_schannel_cred));
+                                    sizeof(struct curl_schannel_cred));
     if(retcode) {
       failf(data, "schannel: failed to store credential handle\n");
       return retcode;
@@ -954,7 +954,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
 
 void Curl_schannel_session_free(void *ptr)
 {
-  curl_schannel_cred *cred = ptr;
+  struct curl_schannel_cred *cred = ptr;
 
   if(cred) {
     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
diff --git a/lib/urldata.h b/lib/urldata.h
index 7327482..20e339b 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -222,15 +222,15 @@ enum protection_level {
 
 #ifdef USE_SCHANNEL
 /* Structs to store Schannel handles */
-typedef struct curl_schannel_cred {
+struct curl_schannel_cred {
   CredHandle cred_handle;
   TimeStamp time_stamp;
-} curl_schannel_cred;
+};
 
-typedef struct curl_schannel_ctxt {
+struct curl_schannel_ctxt {
   CtxtHandle ctxt_handle;
   TimeStamp time_stamp;
-} curl_schannel_ctxt;
+};
 #endif
 
 /* enum for the nonblocking SSL connection state machine */
@@ -302,8 +302,8 @@ struct ssl_connect_data {
   SSL*     ssl;
 #endif /* USE_AXTLS */
 #ifdef USE_SCHANNEL
-  curl_schannel_cred *cred;
-  curl_schannel_ctxt *ctxt;
+  struct curl_schannel_cred *cred;
+  struct curl_schannel_ctxt *ctxt;
   SecPkgContext_StreamSizes stream_sizes;
   ssl_connect_state connecting_state;
   size_t encdata_length, decdata_length;
-- 
1.7.9


From 2f53a8d8da8b4f2cdf087ae99c60e37adab4bd1f Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 22 Apr 2012 17:10:00 +0200
Subject: [PATCH 54/55] curl_schannel.c: Removed space before opening brace

---
 lib/curl_schannel.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 6991017..a8b7c0a 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -145,7 +145,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 
     /* allocate memory for the re-usable credential handle */
     connssl->cred = malloc(sizeof(struct curl_schannel_cred));
-    if (!connssl->cred) {
+    if(!connssl->cred) {
       failf(data, "schannel: unable to allocate memory");
       return CURLE_OUT_OF_MEMORY;
     }
@@ -187,7 +187,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 
   /* allocate memory for the security context handle */
   connssl->ctxt = malloc(sizeof(struct curl_schannel_ctxt));
-  if (!connssl->ctxt) {
+  if(!connssl->ctxt) {
     failf(data, "schannel: unable to allocate memory");
     return CURLE_OUT_OF_MEMORY;
   }
-- 
1.7.9


From ededf2772d505a01b52312290c3d518e0994502b Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 22 Apr 2012 17:11:23 +0200
Subject: [PATCH 55/55] curl_schannel.c: Fixed lines being longer than 80
 chars

---
 lib/curl_schannel.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index a8b7c0a..7bca903 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -111,13 +111,13 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
     if(data->set.ssl.verifypeer) {
       schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
                               SCH_CRED_REVOCATION_CHECK_CHAIN;
-      infof(data, "schannel: checking server certificate and revocation\n");
+      infof(data, "schannel: checking server certificate revocation\n");
     }
     else {
       schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
                               SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
                               SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-      infof(data, "schannel: disable server certificate and revocation checks\n");
+      infof(data, "schannel: disable server certificate revocation checks\n");
     }
 
     if(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
-- 
1.7.9

