From 2046abeca94b77423e205ed6b50301d1c15d8e4f 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/28] http: Replaced specific SSL libraries list in
 https_getsock fallback

---
 lib/http.c |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/http.c b/lib/http.c
index a139894..2726165 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1398,8 +1398,7 @@ 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)
+#ifdef USE_SSL
 static int https_getsock(struct connectdata *conn,
                          curl_socket_t *socks,
                          int numsocks)
@@ -1409,7 +1408,7 @@ static int https_getsock(struct connectdata *conn,
   (void)numsocks;
   return GETSOCK_BLANK;
 }
-#endif /* USE_AXTLS || USE_POLARSSL || USE_QSOSSL || USE_NSS */
+#endif /* USE_SSL */
 #endif /* USE_SSLEAY || USE_GNUTLS */
 
 /*
-- 
1.7.10.msysgit.1


From ee434cad555dbc7fa5e96ed8b9207f7287c149e8 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/28] schannel: Added SSL/TLS support with Microsoft Windows
 Schannel SSPI

---
 lib/curl_schannel.c |  848 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/curl_schannel.h |   65 ++++
 lib/sslgen.c        |    2 +
 lib/urldata.h       |   17 ++
 4 files changed, 932 insertions(+)
 create mode 100644 lib/curl_schannel.c
 create mode 100644 lib/curl_schannel.h

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
new file mode 100644
index 0000000..cfac6ef
--- /dev/null
+++ b/lib/curl_schannel.c
@@ -0,0 +1,848 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  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 "curl_sspi.h"
+#include "curl_schannel.h"
+#include "sslgen.h"
+#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>
+#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;
+  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);
+
+  /* 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(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
+#ifdef ENABLE_IPV6
+     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;
+  }
+
+  /* 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,
+    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;
+
+  /* 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) {
+    if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+      failf(data, "schannel: SNI or certificate check failed\n");
+    else
+      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 {
+    if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+      failf(data, "schannel: SNI or certificate check failed\n");
+    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 100644
index 0000000..3de932b
--- /dev/null
+++ b/lib/curl_schannel.h
@@ -0,0 +1,65 @@
+#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
+
+#ifndef UNISP_NAME_A
+#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
+#endif
+
+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 14649a9..28326dd 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 20519cf..26c0581 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
@@ -282,6 +287,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.10.msysgit.1


From 149ae76ae2fdf22c8ccdb38713fcac53451b9c55 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/28] winbuild: 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 e39aa84..7ff4aea 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_sasl.c
+  curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.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	\
@@ -40,4 +40,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.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_sasl.h
+  curl_sasl.h curl_schannel.h
diff --git a/winbuild/Makefile.vc b/winbuild/Makefile.vc
index a45e4ee..a35e9be 100644
--- a/winbuild/Makefile.vc
+++ b/winbuild/Makefile.vc
@@ -73,6 +73,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 9dfd5f6..ed0523e 100644
--- a/winbuild/MakefileBuild.vc
+++ b/winbuild/MakefileBuild.vc
@@ -97,16 +97,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
 
 
-- 
1.7.10.msysgit.1


From 1f3632e2f714cce1e8aa8df3115e5db0559b4b42 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 04/28] schannel: Allow certificate and revocation checks
 being deactivated

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

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index cfac6ef..158b30c 100644
--- 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.10.msysgit.1


From b6603c77564abb94b12db5fa3828075e108bbac5 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 05/28] schannel: Check for required context attributes

---
 lib/curl_schannel.c |   22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 158b30c..2ad0e0d 100644
--- 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,
@@ -372,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.10.msysgit.1


From 15f884c5d13a845ff10c7f94314b9f3d3eb42ecf 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 06/28] schannel: Code cleanup

---
 lib/curl_schannel.c |   14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 2ad0e0d..7619338 100644
--- 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,12 +354,8 @@ 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;
@@ -376,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.10.msysgit.1


From dd4345754e65fcf6e2553c6638f697c0c8f70b76 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 07/28] schannel: Save session credential handles in session
 cache

---
 lib/curl_schannel.c |  194 +++++++++++++++++++++++++++++++++------------------
 lib/curl_schannel.h |   15 +++-
 lib/urldata.h       |    8 +--
 3 files changed, 143 insertions(+), 74 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 7619338..9157bda 100644
--- 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
@@ -49,8 +48,6 @@
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_SCHANNEL
 
-#include <schnlsp.h>
-
 #include "urldata.h"
 #include "curl_sspi.h"
 #include "curl_schannel.h"
@@ -83,6 +80,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 in_addr addr;
 #ifdef ENABLE_IPV6
   struct in6_addr addr6;
@@ -91,60 +89,75 @@ 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");
+  /* 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 {
-    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;
+    }
+
+    /* 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->cred_handle, &connssl->cred->time_stamp);
 
-  connssl->schannel = TRUE;
+    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);
+      free(connssl->cred);
+      connssl->cred = NULL;
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
 
   /* setup output buffer */
   outbuf.pvBuffer = NULL;
@@ -160,11 +173,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)
@@ -172,6 +193,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;
   }
 
@@ -280,9 +303,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);
@@ -363,11 +386,15 @@ 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];
+  curl_schannel_cred *old_cred = 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 +411,27 @@ 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, NULL));
+  if(incache) {
+    if(old_cred != connssl->cred) {
+      infof(data, "schannel: old credential handle is stale, removing\n");
+      Curl_ssl_delsessionid(conn, old_cred);
+      incache = FALSE;
+    }
+  }
+  if(!incache) {
+    retcode = Curl_ssl_addsessionid(conn, connssl->cred,
+                                    sizeof(curl_schannel_cred));
+    if(retcode) {
+      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;
 
   return CURLE_OK;
@@ -512,9 +560,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;
@@ -561,7 +609,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 */
@@ -681,7 +729,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);
 
@@ -805,7 +853,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
@@ -819,10 +867,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);
-    s_pSecFn->FreeCredentialsHandle(&connssl->cred_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 */
@@ -846,6 +895,15 @@ 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) {
+  curl_schannel_cred *cred = ptr;
+
+  if(cred) {
+    s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+    free(cred);
+  }
+}
+
 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..fa6fc90 100644
--- 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,
@@ -39,6 +51,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 +62,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
diff --git a/lib/urldata.h b/lib/urldata.h
index 26c0581..2b972d5 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
@@ -288,10 +288,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.10.msysgit.1


From 28e8994d2bbc192428534443c99892336542ac33 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 08/28] schannel: Implemented SSL/TLS renegotiation

Updated TODO information and added related MSDN articles
---
 lib/curl_schannel.c |   43 +++++++++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 9157bda..ab3c611 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -40,7 +40,15 @@
  * TODO list for TLS/SSL implementation:
  * - implement write buffering
  * - implement SSL/TLS shutdown
- * - special cases: renegotiation, certificates, algorithms
+ * - 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/aa375447.aspx
+ * - Specifying Schannel Ciphers and Cipher Strengths
+ *   http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
  */
 
 #include "setup.h"
@@ -86,7 +94,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 */
@@ -229,11 +237,9 @@ 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);
 
-  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 +255,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;
   }
@@ -394,6 +400,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))
@@ -697,15 +706,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 +796,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 +831,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.10.msysgit.1


From f00ecc740002ca32c2f71f3b24c5e03bfdf129f8 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 09/28] schannel: 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.

Connection shutdown does not mean that there is no data to read
Correctly handle incomplete message and ask curl to re-read
Fixed buffer for decrypted being to small
Re-structured read condition to be more effective
Removed obsolete verbose messages
Changed memory reduction method to keep a minimum buffer of size 4096
---
 lib/curl_schannel.c |   88 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 48 insertions(+), 40 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index ab3c611..0ad1145 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -255,20 +255,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);
@@ -643,7 +644,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;
@@ -668,7 +668,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 */
@@ -680,16 +680,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 */
@@ -744,17 +734,38 @@ 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) {
+      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) {
+    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);
 
+        /* 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);
@@ -819,37 +830,34 @@ 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);
   }
 
   /* 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;
   }
 
   /* 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;
   }
 
-  /* everything went fine */
-  infof(data, "schannel: read returns %d with error code %d\n", ret, *err);
-
   return ret;
 }
 
-- 
1.7.10.msysgit.1


From 4908614b9ceaba877ecbc7c4f7b524ce41d775b0 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 10/28] sspi: Refactored socks_sspi and 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 |   37 ++++++++-----
 lib/curl_sspi.c     |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/curl_sspi.h     |    2 +
 lib/socks_sspi.c    |   90 ++-----------------------------
 4 files changed, 180 insertions(+), 98 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 0ad1145..3de8e7c 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -89,6 +89,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;
@@ -156,11 +157,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 = Curl_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;
@@ -196,11 +200,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 = Curl_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;
@@ -236,6 +243,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);
@@ -320,8 +328,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;
   }
 
@@ -350,11 +357,14 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) {
     }
   }
   else {
+    sspi_msg = Curl_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;
   }
 
@@ -653,6 +663,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;
@@ -853,7 +864,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 = 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;
     return -1;
   }
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.10.msysgit.1


From 7e0297f7c942832356d57f3eb0af83da8ccf444c 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 11/28] schannel: Fixed critical typo in conditions and added
 buffer length checks

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

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 3de8e7c..6bc7682 100644
--- 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
@@ -789,7 +789,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.10.msysgit.1


From 2af797c08bd4d31dd4eb2cf97e4dafaf5fb409a0 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 12/28] schannel: Fixed compiler warnings about pointer type
 assignments

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

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 6bc7682..d4e3559 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -99,7 +99,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");
   }
@@ -432,16 +432,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.10.msysgit.1


From dd231a415a40a791ddf0dcc0d7417684da6102d6 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 13/28] schannel: Moved interal struct types to urldata.h

Moved type definitions in order to avoid inclusion loop
---
 lib/curl_schannel.c |    1 -
 lib/curl_schannel.h |   10 +---------
 lib/urldata.h       |   16 +++++++++++++++-
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index d4e3559..d4d7629 100644
--- 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 100644
--- 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 2b972d5..7327482 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -133,7 +133,8 @@
 
 #ifdef USE_SCHANNEL
 #include "curl_sspi.h"
-#include "curl_schannel.h"
+#include <schnlsp.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.10.msysgit.1


From 10f42c2f1fc123bd30fa6ab2c1b41e6161d1bdc0 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 14/28] schannel: Added definitions which are missing in
 mingw32

---
 lib/curl_schannel.h |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index aea47b2..3e24fad 100644
--- 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.10.msysgit.1


From 8612b31529a57223980a00fd0d598bf39e7a35c3 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 15/28] schannel: Replace ASCII specific code with general
 defines

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

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index d4d7629..c9a3906 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -151,8 +151,8 @@ 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,
-      UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
+    sspi_status = s_pSecFn->AcquireCredentialsHandle(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) {
@@ -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.10.msysgit.1


From 826b93a85392a145e8385dfc0fd6fd319fb14400 Mon Sep 17 00:00:00 2001
From: Guenter Knauf <lists@gknw.net>
Date: Fri, 13 Apr 2012 13:17:57 +0200
Subject: [PATCH 16/28] schannel: Updated mingw32 makefiles

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

diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index 988427e..abbcca3 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -115,6 +115,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
@@ -136,6 +141,9 @@ ifdef SSH2
   DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2
 endif
 ifdef SSL
+ifdef SCHANNEL
+  CFLAGS += -DUSE_SSL -DUSE_SCHANNEL
+else
   ifndef OPENSSL_INCLUDE
     ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc"
       OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc
@@ -163,6 +171,7 @@ ifdef SSL
             -DCURL_WANTS_CA_BUNDLE_ENV
   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 5aea908..9941614 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -123,6 +123,11 @@ endif
 ifeq ($(findstring -metalink,$(CFG)),-metalink)
 METALINK = 1
 endif
+ifeq ($(findstring -schannel,$(CFG)),-schannel)
+SCHANNEL = 1
+SSPI = 1
+SSL = 1
+endif
 
 INCLUDES = -I. -I.. -I../include -I../lib
 
@@ -151,6 +156,9 @@ ifdef SSH2
   curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
 endif
 ifdef SSL
+ifdef SCHANNEL
+  CFLAGS += -DUSE_SSL -DUSE_SCHANNEL
+else
   ifndef OPENSSL_LIBPATH
     OPENSSL_LIBS = -lssl -lcrypto
     ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out"
@@ -169,6 +177,7 @@ ifdef SSL
   CFLAGS += -DUSE_SSLEAY
   curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
 endif
+endif
 ifdef ZLIB
   INCLUDES += -I"$(ZLIB_PATH)"
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
-- 
1.7.10.msysgit.1


From 7aef3a13e2a25faabde7c733ab43e415f9f09e84 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 17/28] 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 abbcca3..11f6d71 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -190,6 +190,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 9941614..80fa81b 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -199,6 +199,7 @@ ifdef METALINK
 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 ed0523e..92b4bbb 100644
--- a/winbuild/MakefileBuild.vc
+++ b/winbuild/MakefileBuild.vc
@@ -152,6 +152,7 @@ USE_SSPI = yes
 
 !IF "$(USE_SSPI)"=="yes"
 CFLAGS_SSPI = /DUSE_WINDOWS_SSPI
+LFLAGS_SSPI = version.lib
 USE_SSPI    = true
 !ENDIF
 
@@ -295,6 +296,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.10.msysgit.1


From c7e524d77a571c407a46d3652bbd3a227824f9a1 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 18/28] schannel: Code cleanup and bug fixes

curl_sspi.c: Fixed mingw32-gcc compiler warnings
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)

curl_sspi.c: Fallback to security function table version number
Instead of reporting an unknown version, the interface version is used.

curl_sspi.c: Removed SSPI/ version prefix from Curl_sspi_version
curl_schannel: Replaced static buffer sizes with defined names
curl_schannel.c: First brace when declaring functions on column 0
curl_schannel.c: Put the pointer sign directly at variable name
curl_schannel.c: Use structs directly instead of typedef'ed structs
curl_schannel.c: Removed space before opening brace
curl_schannel.c: Fixed lines being longer than 80 chars
---
 lib/curl_schannel.c |  101 ++++++++++++++++++++++++++++++---------------------
 lib/curl_schannel.h |    4 ++
 lib/curl_sspi.c     |   10 +++--
 lib/urldata.h       |   12 +++---
 4 files changed, 75 insertions(+), 52 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index c7b51cb..7bca903 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -79,15 +79,16 @@ 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];
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SecBuffer outbuf;
   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
@@ -110,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) ||
@@ -143,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));
-    if (!connssl->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,
@@ -185,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));
-  if (!connssl->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(
@@ -232,11 +233,12 @@ 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;
-  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];
@@ -250,7 +252,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");
@@ -401,11 +403,12 @@ 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];
-  curl_schannel_cred *old_cred = NULL;
+  struct curl_schannel_cred *old_cred = NULL;
   int incache;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -441,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;
@@ -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;
@@ -670,7 +676,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 +685,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 +766,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 +846,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);
   }
@@ -875,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;
 
@@ -893,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 */
@@ -903,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];
 
@@ -934,12 +947,14 @@ 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) {
-  curl_schannel_cred *cred = ptr;
+void Curl_schannel_session_free(void *ptr)
+{
+  struct curl_schannel_cred *cred = ptr;
 
   if(cred) {
     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
@@ -947,18 +962,20 @@ 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();
 }
 
 size_t Curl_schannel_version(char *buffer, size_t size)
 {
-  char* version = Curl_sspi_version();
-  size = snprintf(buffer, size, "Schannel-%s", version);
+  char *version = Curl_sspi_version();
+  size = snprintf(buffer, size, "Schannel/%s", version);
   free(version);
   return size;
 }
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,
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index d3533a2..29f8a43 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,8 +144,8 @@ Curl_sspi_version()
           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",
+              if(VerQueryValue(data, "\\", (LPVOID*)&version_info, &length)) {
+                version = curl_maprintf("%d.%d.%d.%d",
                   (version_info->dwProductVersionMS>>16)&0xffff,
                   (version_info->dwProductVersionMS>>0)&0xffff,
                   (version_info->dwProductVersionLS>>16)&0xffff,
@@ -158,7 +159,7 @@ Curl_sspi_version()
       free(path);
     }
     if(!version)
-      version = strdup("SSPI/Unknown");
+      version = curl_maprintf("%d", s_pSecFn ? s_pSecFn->dwVersion : 0);
   }
 
   if(!version)
@@ -265,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);
 }
 
 
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.10.msysgit.1


From d2c8b03916ca6aedd650f1cb73665f0977a79f23 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 22 Apr 2012 18:49:27 +0100
Subject: [PATCH 19/28] Makefile.vc6: Added version.lib if built with SSPI

---
 lib/Makefile.vc6 |    5 +++--
 src/Makefile.vc6 |   30 +++++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6
index 621c6e6..205b433 100644
--- a/lib/Makefile.vc6
+++ b/lib/Makefile.vc6
@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1999 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1999 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
@@ -22,7 +22,7 @@
 
 # All files in the Makefile.vc* series are generated automatically from the
 # one made for MSVC version 6. Alas, if you want to do changes to any of the
-# fiels and send back to the project, edit the version six, make your diff and
+# files and send back to the project, edit the version six, make your diff and
 # mail curl-library.
 
 ###########################################################################
@@ -123,6 +123,7 @@ CFGSET     = FALSE
 
 !IFDEF WINDOWS_SSPI
 CFLAGS = $(CFLAGS) /DUSE_WINDOWS_SSPI /I$(WINDOWS_SDK_PATH)\include
+WINLIBS = $(WINLIBS) version.lib
 !ENDIF
 
 !IFDEF USE_IPV6
diff --git a/src/Makefile.vc6 b/src/Makefile.vc6
index f8b3066..6da0877 100644
--- a/src/Makefile.vc6
+++ b/src/Makefile.vc6
@@ -22,7 +22,7 @@
 
 # All files in the Makefile.vc* series are generated automatically from the
 # one made for MSVC version 6. Alas, if you want to do changes to any of the
-# fiels and send back to the project, edit the version six, make your diff and
+# files and send back to the project, edit the version six, make your diff and
 # mail curl-users.
 
 #############################################################
@@ -90,6 +90,7 @@ WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK"
 
 ########################################################
 ## Nothing more to do below this line!
+
 ZLIB_CFLAGS   = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ /I "$(ZLIB_PATH)"
 ZLIB_LFLAGS   = "/LIBPATH:$(ZLIB_PATH)"
 ZLIB_LIBS     = zlib.lib
@@ -100,6 +101,8 @@ SSL_LFLAGS     = /LIBPATH:"$(OPENSSL_PATH)/out32"
 SSL_IMP_LFLAGS = /LIBPATH:"$(OPENSSL_PATH)/out32dll"
 SSL_LIBS       = libeay32.lib ssleay32.lib gdi32.lib user32.lib advapi32.lib
 
+WINLIBS        = ws2_32.lib wldap32.lib
+
 # Runtime library configuration
 RTLIB   = /MD
 RTLIBD  = /MDd
@@ -226,6 +229,9 @@ DEBUG_OBJS= \
 CFLAGS         = $(CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 
 #################################################
 # release dynamic library
@@ -243,6 +249,9 @@ CFLAGS         = $(CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL) $(ZLIB_LIBS)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(ZLIB_LIBS)
 LFLAGS         = $(LFLAGS) $(ZLIB_LFLAGS)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 !ENDIF
 
 #################################################
@@ -253,6 +262,9 @@ CFLAGS         = $(CFLAGS) $(SSL_CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS)
 LFLAGS         = $(LFLAGS) $(SSL_LFLAGS)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 !ENDIF
 
 #################################################
@@ -273,6 +285,9 @@ CFLAGS         = $(CFLAGS) $(SSL_CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS) $(ZLIB_LIBS)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS) $(ZLIB_LIBS)
 LFLAGS         = $(LFLAGS) $(SSL_LFLAGS) $(ZLIB_LFLAGS)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 !ENDIF
 
 #################################################
@@ -283,6 +298,9 @@ CFLAGS         = $(CFLAGS) $(SSL_CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS)
 LFLAGS         = $(LFLAGS) $(SSL_IMP_LFLAGS)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 !ENDIF
 
 #################################################
@@ -293,6 +311,9 @@ CFLAGS         = $(CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL) $(ZLIB_IMP_LIBS)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(ZLIB_IMP_LIBS)
 LFLAGS         = $(LFLAGS) $(ZLIB_LFLAGS)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 !ENDIF
 
 #################################################
@@ -313,6 +334,9 @@ CFLAGS         = $(CFLAGS) $(SSL_CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
 LINKLIBS       = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS) $(ZLIB_IMP_LIBS)
 LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS) $(ZLIB_IMP_LIBS)
 LFLAGS         = $(LFLAGS) $(SSL_IMP_LFLAGS) $(ZLIB_LFLAGS)
+!IFDEF WINDOWS_SSPI
+WINLIBS = $(WINLIBS) version.lib
+!ENDIF
 !ENDIF
 
 #################################################
@@ -326,8 +350,8 @@ LFLAGS         = $(LFLAGS) $(SSL_IMP_LFLAGS) $(ZLIB_LFLAGS)
 !ENDIF
 
 
-LINKLIBS       = $(LINKLIBS) ws2_32.lib wldap32.lib
-LINKLIBS_DEBUG = $(LINKLIBS_DEBUG) ws2_32.lib wldap32.lib
+LINKLIBS       = $(LINKLIBS) $(WINLIBS)
+LINKLIBS_DEBUG = $(LINKLIBS_DEBUG) $(WINLIBS)
 
 all : release
 
-- 
1.7.10.msysgit.1


From e8a8670e4be3b954cabb168c6a44e55ec8bf845a Mon Sep 17 00:00:00 2001
From: Guenter Knauf <lists@gknw.net>
Date: Mon, 23 Apr 2012 01:14:32 +0100
Subject: [PATCH 20/28] configure.ac: Added -lversion if built with SSPI

---
 configure.ac |    1 +
 1 file changed, 1 insertion(+)

diff --git a/configure.ac b/configure.ac
index 8e7fe6d..f56890f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3044,6 +3044,7 @@ AC_HELP_STRING([--disable-sspi],[Disable SSPI]),
          AC_DEFINE(USE_WINDOWS_SSPI, 1, [to enable SSPI support])
          AC_SUBST(USE_WINDOWS_SSPI, [1])
          curl_sspi_msg="enabled"
+         LIBS="$LIBS -lversion"
        else
          AC_MSG_RESULT(no)
          AC_MSG_WARN([--enable-sspi Ignored. Only supported on native Windows builds.])
-- 
1.7.10.msysgit.1


From 8c24274286d0b624fe00ecc9ed29e69edeb53d53 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 10 Jun 2012 12:07:45 +0100
Subject: [PATCH 21/28] sspi: Reworked Curl_sspi_version() to return version
 components

Reworked the version function to return four version components rather
than a string that has to be freed by the caller.
---
 lib/curl_schannel.c |   11 ++++++--
 lib/curl_sspi.c     |   77 ++++++++++++++++++++++++++++++---------------------
 lib/curl_sspi.h     |    4 +--
 3 files changed, 55 insertions(+), 37 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 7bca903..511f675 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -974,9 +974,14 @@ 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);
-  free(version);
+  int sspi_major = 0, sspi_minor = 0, sspi_build = 0;
+
+  if(!Curl_sspi_version(&sspi_major, &sspi_minor, &sspi_build, NULL))
+    size = snprintf(buffer, size, "WinSSPI/%d.%d.%d", sspi_major, sspi_minor,
+                    sspi_build);
+  else
+    size = snprintf(buffer, size, "WinSSPI/unknown");
+
   return size;
 }
 
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 29f8a43..71f087b 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -122,50 +122,63 @@ 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.
+ * This function returns the SSPI library version information.
  */
-char *
-Curl_sspi_version()
+CURLcode Curl_sspi_version(int *major, int *minor, int *build, int *special)
 {
+  CURLcode result = CURLE_OK;
   VS_FIXEDFILEINFO *version_info = NULL;
-  LPTSTR version = NULL;
   LPTSTR path = NULL;
   LPVOID data = NULL;
   DWORD size, handle;
-  UINT length;
 
-  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, "\\", (LPVOID*)&version_info, &length)) {
-                version = curl_maprintf("%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);
-          }
+  if(!s_hSecDll)
+    return CURLE_FAILED_INIT;
+
+  path = (char *) malloc(MAX_PATH);
+  if(!path)
+    return CURLE_OUT_OF_MEMORY;
+
+  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))
+            result = CURLE_OUT_OF_MEMORY;
         }
+        else
+          result = CURLE_OUT_OF_MEMORY;
       }
-      free(path);
+      else
+        result = CURLE_OUT_OF_MEMORY;
     }
-    if(!version)
-      version = curl_maprintf("%d", s_pSecFn ? s_pSecFn->dwVersion : 0);
+    else
+      result = CURLE_OUT_OF_MEMORY;
+  }
+  else
+    result = CURLE_OUT_OF_MEMORY;
+
+  /* Set the out parameters */
+  if(!result) {
+    if(major)
+      *major = (version_info->dwProductVersionMS >> 16) & 0xffff;
+  
+    if(minor)
+      *minor = (version_info->dwProductVersionMS >> 0) & 0xffff;
+
+    if(build)
+      *build = (version_info->dwProductVersionLS >> 16) & 0xffff;
+
+    if(special)
+      *special = (version_info->dwProductVersionLS >> 0) & 0xffff;
   }
 
-  if(!version)
-    version = strdup("");
+  Curl_safefree(data);
+  Curl_safefree(path);
 
-  return version;
+  return result;
 }
 
 
diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h
index 1865ee4..38d3182 100644
--- a/lib/curl_sspi.h
+++ b/lib/curl_sspi.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -63,7 +63,7 @@
 
 CURLcode Curl_sspi_global_init(void);
 void Curl_sspi_global_cleanup(void);
-char* Curl_sspi_version();
+CURLcode Curl_sspi_version(int *major, int *minor, int *build, int *special);
 char* Curl_sspi_status(SECURITY_STATUS status);
 char* Curl_sspi_status_msg(SECURITY_STATUS status);
 
-- 
1.7.10.msysgit.1


From 38984c2775651c8fb675528b20fa8d54ba43e2c6 Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Sun, 10 Jun 2012 12:30:02 +0100
Subject: [PATCH 22/28] sspi.c: Post Curl_sspi_version() rework code tidy up

Removed duplicate blank lines.
Removed spaces between the not and test in various if statements.
Removed explicit test of NULL in an if statement.
Placed function returns on same line as function declarations.
Replaced the use of curl_maprintf() with aprintf() as it is the
preprocessor job to do this substitution if ENABLE_CURLX_PRINTF
is set.
---
 lib/curl_sspi.c |   40 ++++++++++++++--------------------------
 1 file changed, 14 insertions(+), 26 deletions(-)

diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 71f087b..3f41762 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -35,7 +35,6 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
-
 /* We use our own typedef here since some headers might lack these */
 typedef PSecurityFunctionTableA (APIENTRY *INITSECURITYINTERFACE_FN_A)(VOID);
 
@@ -45,7 +44,6 @@ HMODULE s_hSecDll = NULL;
 /* Pointer to SSPI dispatch table */
 PSecurityFunctionTableA s_pSecFn = NULL;
 
-
 /*
  * Curl_sspi_global_init()
  *
@@ -57,20 +55,18 @@ PSecurityFunctionTableA s_pSecFn = NULL;
  * Once this function has been executed, Windows SSPI functions can be
  * called through the Security Service Provider Interface dispatch table.
  */
-
-CURLcode
-Curl_sspi_global_init(void)
+CURLcode Curl_sspi_global_init(void)
 {
   OSVERSIONINFO osver;
   INITSECURITYINTERFACE_FN_A pInitSecurityInterface;
 
   /* If security interface is not yet initialized try to do this */
-  if(s_hSecDll == NULL) {
+  if(!s_hSecDll) {
 
     /* Find out Windows version */
     memset(&osver, 0, sizeof(osver));
     osver.dwOSVersionInfoSize = sizeof(osver);
-    if(! GetVersionEx(&osver))
+    if(!GetVersionEx(&osver))
       return CURLE_FAILED_INIT;
 
     /* Security Service Provider Interface (SSPI) functions are located in
@@ -83,33 +79,31 @@ Curl_sspi_global_init(void)
       s_hSecDll = LoadLibrary("security.dll");
     else
       s_hSecDll = LoadLibrary("secur32.dll");
-    if(! s_hSecDll)
+    if(!s_hSecDll)
       return CURLE_FAILED_INIT;
 
     /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
     pInitSecurityInterface = (INITSECURITYINTERFACE_FN_A)
       GetProcAddress(s_hSecDll, "InitSecurityInterfaceA");
-    if(! pInitSecurityInterface)
+    if(!pInitSecurityInterface)
       return CURLE_FAILED_INIT;
 
     /* Get pointer to Security Service Provider Interface dispatch table */
     s_pSecFn = pInitSecurityInterface();
-    if(! s_pSecFn)
+    if(!s_pSecFn)
       return CURLE_FAILED_INIT;
-
   }
+
   return CURLE_OK;
 }
 
-
 /*
  * Curl_sspi_global_cleanup()
  *
  * This deinitializes the Security Service Provider Interface from libcurl.
  */
 
-void
-Curl_sspi_global_cleanup(void)
+void Curl_sspi_global_cleanup(void)
 {
   if(s_hSecDll) {
     FreeLibrary(s_hSecDll);
@@ -118,7 +112,6 @@ Curl_sspi_global_cleanup(void)
   }
 }
 
-
 /*
  * Curl_sspi_version()
  *
@@ -181,15 +174,13 @@ CURLcode Curl_sspi_version(int *major, int *minor, int *build, int *special)
   return result;
 }
 
-
 /*
  * 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)
+char* Curl_sspi_status(SECURITY_STATUS status)
 {
   const char* status_const;
 
@@ -279,20 +270,17 @@ Curl_sspi_status(SECURITY_STATUS status)
       status_const = "Unknown error";
   }
 
-  return curl_maprintf("%s (0x%04X%04X)", status_const,
-                       (status>>16)&0xffff, status&0xffff);
+  return aprintf("%s (0x%04X%04X)", status_const, (status >> 16) & 0xffff,
+                 status & 0xffff);
 }
 
-
 /*
  * 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)
+char* Curl_sspi_status_msg(SECURITY_STATUS status)
 {
   LPSTR format_msg = NULL;
   char *status_msg = NULL, *status_const = NULL;
@@ -307,7 +295,7 @@ Curl_sspi_status_msg(SECURITY_STATUS status)
     status_msg = strdup(format_msg);
     LocalFree(format_msg);
 
-    /* remove trailing CR+LF */
+    /* Remove trailing CR+LF */
     if(status_len > 0) {
       if(status_msg[status_len-1] == '\n') {
         status_msg[status_len-1] = '\0';
@@ -322,7 +310,7 @@ Curl_sspi_status_msg(SECURITY_STATUS status)
 
   status_const = Curl_sspi_status(status);
   if(status_msg) {
-    status_msg = curl_maprintf("%s [%s]", status_msg, status_const);
+    status_msg = aprintf("%s [%s]", status_msg, status_const);
     free(status_const);
   }
   else {
-- 
1.7.10.msysgit.1


From 46374d141a32c21dfaff5e7a6fd5126d64a850f4 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 11 Jun 2012 08:36:48 +0200
Subject: [PATCH 23/28] version: Replaced SSPI feature information with
 version string details

Added Windows SSPI version information to the curl version string when
SCHANNEL SSL is not enabled, as the version of the library should also
be included when SSPI is used to generate security contexts.

Removed SSPI from the feature list as the features are GSS-Negotiate,
NTLM and SSL depending on the usage of the SSPI library.
---
 include/curl/curl.h |    2 +-
 lib/version.c       |   28 ++++++++++++++++++++++------
 src/tool_getparam.c |    1 -
 3 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/include/curl/curl.h b/include/curl/curl.h
index 2cad282..2c743b4 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -2144,7 +2144,7 @@ typedef struct {
 #define CURL_VERSION_SPNEGO    (1<<8)  /* SPNEGO auth */
 #define CURL_VERSION_LARGEFILE (1<<9)  /* supports files bigger than 2GB */
 #define CURL_VERSION_IDN       (1<<10) /* International Domain Names support */
-#define CURL_VERSION_SSPI      (1<<11) /* SSPI is supported */
+#define CURL_VERSION_OBSOLETE11 (1<<11) /* NOT USED - removed in 7.27.0 */
 #define CURL_VERSION_CONV      (1<<12) /* character conversions supported */
 #define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */
 #define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
diff --git a/lib/version.c b/lib/version.c
index c56ad39..2a2c5c0 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -64,10 +64,16 @@
 char *curl_version(void)
 {
   static char version[200];
-  char *ptr=version;
+  char *ptr = version;
   size_t len;
   size_t left = sizeof(version);
-  strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION );
+#ifdef USE_WINDOWS_SSPI
+#ifndef USE_SCHANNEL
+  int sspi_major = 0, sspi_minor = 0, sspi_build = 0;
+#endif
+#endif
+
+  strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION);
   len = strlen(ptr);
   left -= len;
   ptr += len;
@@ -82,6 +88,19 @@ char *curl_version(void)
     }
   }
 
+#ifdef USE_WINDOWS_SSPI
+#ifndef USE_SCHANNEL
+  if(CURLE_OK == Curl_sspi_version(&sspi_major, &sspi_minor, &sspi_build,
+                                   NULL))
+    len = snprintf(ptr, left, " WinSSPI/%d.%d.%d", sspi_major, sspi_minor,
+                 sspi_build);
+  else
+    len = snprintf(ptr, left, " WinSSPI/unknown");
+
+  left -= len;
+  ptr += len;
+#endif
+#endif
 #ifdef HAVE_LIBZ
   len = snprintf(ptr, left, " zlib/%s", zlibVersion());
   left -= len;
@@ -243,9 +262,6 @@ static curl_version_info_data version_info = {
 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
   | CURL_VERSION_NTLM_WB
 #endif
-#ifdef USE_WINDOWS_SSPI
-  | CURL_VERSION_SSPI
-#endif
 #ifdef HAVE_LIBZ
   | CURL_VERSION_LIBZ
 #endif
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index ab8ed1d..fb42d0a 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -277,7 +277,6 @@ static const struct feat feats[] = {
   {"NTLM_WB",        CURL_VERSION_NTLM_WB},
   {"SPNEGO",         CURL_VERSION_SPNEGO},
   {"SSL",            CURL_VERSION_SSL},
-  {"SSPI",           CURL_VERSION_SSPI},
   {"krb4",           CURL_VERSION_KERBEROS4},
   {"libz",           CURL_VERSION_LIBZ},
   {"CharConv",       CURL_VERSION_CONV},
-- 
1.7.10.msysgit.1


From ecceadbd68710872fbe5bd9131a809b2d9e93b5d Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Mon, 11 Jun 2012 08:37:22 +0200
Subject: [PATCH 24/28] setup.h: Automatically define USE_SSL if USE_SCHANNEL
 is defined

---
 lib/setup.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/setup.h b/lib/setup.h
index 732b1a3..a219080 100644
--- a/lib/setup.h
+++ b/lib/setup.h
@@ -579,7 +579,7 @@ int netware_init(void);
 
 #if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \
     defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \
-    defined(USE_CYASSL)
+    defined(USE_CYASSL) || defined(USE_SCHANNEL)
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 
-- 
1.7.10.msysgit.1


From a3f4abe598169acf64527ec988f872d249c610f9 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 10 Jun 2012 17:50:39 +0200
Subject: [PATCH 25/28] winbuild: Removed WITH_SSL=schannel and tie Schannel
 to SSPI

Removed specific WITH_SSL=schannel paramter that did not fit the general
schema and complicated the parameters. For now Schannel will be enabled
if SSPI is enabled and OpenSSL is disabled.
---
 winbuild/Makefile.vc      |    4 ----
 winbuild/MakefileBuild.vc |   14 +++++++-------
 2 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/winbuild/Makefile.vc b/winbuild/Makefile.vc
index a35e9be..a45e4ee 100644
--- a/winbuild/Makefile.vc
+++ b/winbuild/Makefile.vc
@@ -73,10 +73,6 @@ 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 92b4bbb..7063906 100644
--- a/winbuild/MakefileBuild.vc
+++ b/winbuild/MakefileBuild.vc
@@ -97,19 +97,16 @@ 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
-!ELSEIF "$(WITH_SSL)"=="schannel"
-USE_SSL      = true
-USE_SSPI     = yes
-SSL_CFLAGS   = /DUSE_SSL /DUSE_SCHANNEL
-SSL          = schannel
+!ENDIF
+
+!IFDEF USE_SSL
+SSL_CFLAGS   = /DUSE_SSLEAY /I"$(DEVEL_INCLUDE)/openssl"
 !ENDIF
 
 
@@ -154,6 +151,9 @@ USE_SSPI = yes
 CFLAGS_SSPI = /DUSE_WINDOWS_SSPI
 LFLAGS_SSPI = version.lib
 USE_SSPI    = true
+!IFNDEF USE_SSL
+CFLAGS_SSPI = $(CFLAGS_SSPI) /DUSE_SCHANNEL
+!ENDIF
 !ENDIF
 
 
-- 
1.7.10.msysgit.1


From 4d150571dcae29ddfc18a395616657269aeab493 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 10 Jun 2012 22:34:43 +0200
Subject: [PATCH 26/28] sspi: Updated RELEASE-NOTES, FEATURES and THANKS

---
 RELEASE-NOTES |    3 +++
 docs/FEATURES |    2 +-
 docs/THANKS   |    1 +
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 80bed04..0052ecb 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -17,6 +17,8 @@ This release includes the following changes:
  o pop3: Added support for sasl cram-md5 authentication
  o pop3: Added support for sasl digest-md5 authentication
  o pop3: Added support for apop authentication
+ o sspi: Added support for Schannel SSL/TLS encryption
+ o sspi: Changed curl version information output
 
 This release includes the following bugfixes:
 
@@ -26,6 +28,7 @@ This release includes the following bugfixes:
  o configure: Fix libcurl.pc and curl-config generation for static MingW*
    cross builds
  o ssl: fix duplicated SSL handshake with multi interface and proxy [1]
+ o winbuild: Fix Makefile.vc ignoring USE_IPV6 and USE_IDN flags
 
 This release includes the following known bugs:
 
diff --git a/docs/FEATURES b/docs/FEATURES
index 63e4f67..46d8867 100644
--- a/docs/FEATURES
+++ b/docs/FEATURES
@@ -125,7 +125,7 @@ FILE
 FOOTNOTES
 =========
 
-  *1 = requires OpenSSL, GnuTLS, NSS, yassl, axTLS or PolarSSL
+  *1 = requires OpenSSL, GnuTLS, NSS, yassl, axTLS, PolarSSL or Windows SSPI
   *2 = requires OpenLDAP
   *3 = requires a GSSAPI-compliant library, such as Heimdal or similar.
   *4 = requires FBopenssl
diff --git a/docs/THANKS b/docs/THANKS
index ffab884..1aa2d29 100644
--- a/docs/THANKS
+++ b/docs/THANKS
@@ -554,6 +554,7 @@ Mandy Wu
 Manfred Schwarb
 Manuel Massing
 Marc Boucher
+Marc Hoersken
 Marc Kleine-Budde
 Marcel Roelofs
 Marcelo Juchem
-- 
1.7.10.msysgit.1


From 32946136ede2b8b04e2f70d14a66b3ac36abefab Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 10 Jun 2012 23:31:59 +0200
Subject: [PATCH 27/28] sspi: Fixed incompatible parameter pointer type in
 Curl_sspi_version

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

diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 3f41762..80b929f 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -124,6 +124,7 @@ CURLcode Curl_sspi_version(int *major, int *minor, int *build, int *special)
   LPTSTR path = NULL;
   LPVOID data = NULL;
   DWORD size, handle;
+  UINT length;
 
   if(!s_hSecDll)
     return CURLE_FAILED_INIT;
@@ -138,7 +139,7 @@ CURLcode Curl_sspi_version(int *major, int *minor, int *build, int *special)
       data = malloc(size);
       if(data) {
         if(GetFileVersionInfo(path, handle, size, data)) {
-          if(!VerQueryValue(data, "\\", &version_info, &handle))
+          if(!VerQueryValue(data, "\\", (LPVOID*) &version_info, &length))
             result = CURLE_OUT_OF_MEMORY;
         }
         else
-- 
1.7.10.msysgit.1


From b2ab90ff10b169b998d802b028be7a82670dd767 Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Sun, 10 Jun 2012 23:40:29 +0200
Subject: [PATCH 28/28] mingw32: Fixed warning of USE_SSL being redefined

---
 lib/Makefile.m32 |    8 +++-----
 src/Makefile.m32 |    8 +++-----
 2 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index 11f6d71..fd191c1 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -118,7 +118,6 @@ endif
 ifeq ($(findstring -schannel,$(CFG)),-schannel)
 SCHANNEL = 1
 SSPI = 1
-SSL = 1
 endif
 
 INCLUDES = -I. -I../include
@@ -141,9 +140,6 @@ ifdef SSH2
   DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2
 endif
 ifdef SSL
-ifdef SCHANNEL
-  CFLAGS += -DUSE_SSL -DUSE_SCHANNEL
-else
   ifndef OPENSSL_INCLUDE
     ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc"
       OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc
@@ -171,7 +167,6 @@ else
             -DCURL_WANTS_CA_BUNDLE_ENV
   DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
 endif
-endif
 ifdef ZLIB
   INCLUDES += -I"$(ZLIB_PATH)"
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
@@ -191,6 +186,9 @@ endif
 ifdef SSPI
   CFLAGS += -DUSE_WINDOWS_SSPI
   DLL_LIBS += -lversion
+ifdef SCHANNEL
+  CFLAGS += -DUSE_SCHANNEL
+endif
 endif
 ifdef SPNEGO
   CFLAGS += -DHAVE_SPNEGO
diff --git a/src/Makefile.m32 b/src/Makefile.m32
index 80fa81b..2186326 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -126,7 +126,6 @@ endif
 ifeq ($(findstring -schannel,$(CFG)),-schannel)
 SCHANNEL = 1
 SSPI = 1
-SSL = 1
 endif
 
 INCLUDES = -I. -I.. -I../include -I../lib
@@ -156,9 +155,6 @@ ifdef SSH2
   curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
 endif
 ifdef SSL
-ifdef SCHANNEL
-  CFLAGS += -DUSE_SSL -DUSE_SCHANNEL
-else
   ifndef OPENSSL_LIBPATH
     OPENSSL_LIBS = -lssl -lcrypto
     ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out"
@@ -177,7 +173,6 @@ else
   CFLAGS += -DUSE_SSLEAY
   curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
 endif
-endif
 ifdef ZLIB
   INCLUDES += -I"$(ZLIB_PATH)"
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
@@ -200,6 +195,9 @@ endif
 ifdef SSPI
   CFLAGS += -DUSE_WINDOWS_SSPI
   curl_LDADD += -lversion
+ifdef SCHANNEL
+  CFLAGS += -DUSE_SCHANNEL
+endif
 endif
 ifdef SPNEGO
   CFLAGS += -DHAVE_SPNEGO
-- 
1.7.10.msysgit.1

