Commit ec9e9f38 authored by Marc Hoersken's avatar Marc Hoersken Committed by Daniel Stenberg
Browse files

schannel: Implemented SSL/TLS renegotiation

Updated TODO information and added related MSDN articles
parent 46792af7
Loading
Loading
Loading
Loading
+33 −10
Original line number Diff line number Diff line
@@ -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)