From ec9e9f38b1a4a5020b41aabd11a1fbd71967c6c5 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Tue, 10 Apr 2012 21:21:31 +0200 Subject: 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(-) (limited to 'lib') 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) -- cgit v1.2.3