Commit 72a58131 authored by Mark Salisbury's avatar Mark Salisbury Committed by Yang Tse
Browse files

schannel SSL: changes in schannel_connect_step2

Process extra data buffer before returning from schannel_connect_step2.
Without this change I've seen WinCE hang when schannel_connect_step2
returns and calls Curl_socket_ready.

If the encrypted handshake does not fit in the intial buffer (seen with
large certificate chain), increasing the encrypted data buffer is necessary.

Fixed warning in curl_schannel.c line 1215.
parent 99b13f27
Loading
Loading
Loading
Loading
+128 −95
Original line number Diff line number Diff line
@@ -290,6 +290,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
  SECURITY_STATUS sspi_status = SEC_E_OK;
  TCHAR *host_name;
  CURLcode code;
  bool doread = TRUE;

  infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
        conn->host.name, conn->remote_port);
@@ -305,6 +306,22 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
    }
  }

  /* if we need a bigger buffer to read a full message, increase buffer now */
  if(connssl->encdata_offset == connssl->encdata_length) {
    if(connssl->encdata_length >= CURL_SCHANNEL_BUFFER_INIT_SIZE * 16)
      return CURLE_OUT_OF_MEMORY;
    /* increase internal encrypted data buffer */
    connssl->encdata_length *= 2;
    connssl->encdata_buffer = realloc(connssl->encdata_buffer,
                                      connssl->encdata_length);
    if(connssl->encdata_buffer == NULL) {
      failf(data, "schannel: unable to re-allocate memory");
      return CURLE_OUT_OF_MEMORY;
    }
  }

  for (;;) {
    if(doread) {
      /* read encrypted handshake data from socket */
      code = Curl_read_plain(conn->sock[sockindex],
                (char *) (connssl->encdata_buffer + connssl->encdata_offset),
@@ -325,6 +342,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)

      /* increase encrypted data buffer offset */
      connssl->encdata_offset += nread;
    }

    infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
        connssl->encdata_offset, connssl->encdata_length);
@@ -346,7 +364,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
    }

    /* copy received handshake data into input buffer */
  memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, connssl->encdata_offset);
    memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
           connssl->encdata_offset);

#ifdef UNICODE
    host_name = Curl_convert_UTF8_to_wchar(conn->host.name);
@@ -415,20 +434,34 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
    /* check if there was additional remaining encrypted data */
    if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
      infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);

    /* check if the remaining data is less than the total amount
     * and therefore begins after the already processed data
      /*
         There are two cases where we could be getting extra data here:
         1) If we're renegotiating a connection and the handshake is already
            complete (from the server perspective), it can encrypted app data
            (not handshake data) in an extra buffer at this point.
         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
            connection and this extra data is part of the handshake.
            We should process the data immediately; waiting for the socket to
            be ready may fail since the server is done sending handshake data.
       */
      /* 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;
        if(sspi_status == SEC_I_CONTINUE_NEEDED) {
          doread = FALSE;
          continue;
        }
      }
    }
    else {
      connssl->encdata_offset = 0;
    }
    break;
  }

  /* check if the handshake needs to be continued */
  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
@@ -1229,7 +1262,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
        failf(data, "schannel: CertGetNameString() certificate hostname "
              "(%s) did not match connection (%s)",
              _cert_hostname, conn->host.name);
        free(_cert_hostname);
        free((void *)_cert_hostname);
      }
      free(hostname);
    }