aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Hoersken <info@marc-hoersken.de>2012-04-10 21:21:31 +0200
committerDaniel Stenberg <daniel@haxx.se>2012-06-11 19:00:34 +0200
commitec9e9f38b1a4a5020b41aabd11a1fbd71967c6c5 (patch)
tree2b3a750a49b250b7ac33c5bda71930e49fd412a8
parent46792af73355a3961216f0af351a2e4508c1c389 (diff)
schannel: Implemented SSL/TLS renegotiation
Updated TODO information and added related MSDN articles
-rw-r--r--lib/curl_schannel.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 9157bda56..ab3c6119c 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)