]> granicus.if.org Git - curl/commitdiff
schannel: Implemented SSL/TLS renegotiation
authorMarc Hoersken <info@marc-hoersken.de>
Tue, 10 Apr 2012 19:21:31 +0000 (21:21 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 11 Jun 2012 17:00:34 +0000 (19:00 +0200)
Updated TODO information and added related MSDN articles

lib/curl_schannel.c

index 9157bda56238f8d8a0e11d71f9dbabfe51f3f7aa..ab3c6119c0490dff59f679aac6face7b05218922 100644 (file)
  * 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)