00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "curl_setup.h"
00042
00043 #ifdef USE_SCHANNEL
00044
00045 #ifndef USE_WINDOWS_SSPI
00046 # error "Can't compile SCHANNEL support without SSPI."
00047 #endif
00048
00049 #include "curl_sspi.h"
00050 #include "schannel.h"
00051 #include "vtls.h"
00052 #include "sendf.h"
00053 #include "connect.h"
00054 #include "strerror.h"
00055 #include "select.h"
00056 #include "inet_pton.h"
00057 #include "curl_multibyte.h"
00058 #include "warnless.h"
00059 #include "x509asn1.h"
00060 #include "curl_printf.h"
00061 #include "system_win32.h"
00062 #include "hostcheck.h"
00063
00064
00065 #include "curl_memory.h"
00066 #include "memdebug.h"
00067
00068
00069
00070
00071
00072
00073 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
00074 # define HAS_ALPN 1
00075 #endif
00076
00077
00078
00079
00080
00081
00082 static Curl_recv schannel_recv;
00083 static Curl_send schannel_send;
00084
00085 #ifdef _WIN32_WCE
00086 static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
00087 #endif
00088
00089 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
00090 void *BufDataPtr, unsigned long BufByteSize)
00091 {
00092 buffer->cbBuffer = BufByteSize;
00093 buffer->BufferType = BufType;
00094 buffer->pvBuffer = BufDataPtr;
00095 }
00096
00097 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
00098 unsigned long NumArrElem)
00099 {
00100 desc->ulVersion = SECBUFFER_VERSION;
00101 desc->pBuffers = BufArr;
00102 desc->cBuffers = NumArrElem;
00103 }
00104
00105 static CURLcode
00106 schannel_connect_step1(struct connectdata *conn, int sockindex)
00107 {
00108 ssize_t written = -1;
00109 struct Curl_easy *data = conn->data;
00110 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00111 SecBuffer outbuf;
00112 SecBufferDesc outbuf_desc;
00113 SecBuffer inbuf;
00114 SecBufferDesc inbuf_desc;
00115 #ifdef HAS_ALPN
00116 unsigned char alpn_buffer[128];
00117 #endif
00118 SCHANNEL_CRED schannel_cred;
00119 SECURITY_STATUS sspi_status = SEC_E_OK;
00120 struct curl_schannel_cred *old_cred = NULL;
00121 struct in_addr addr;
00122 #ifdef ENABLE_IPV6
00123 struct in6_addr addr6;
00124 #endif
00125 TCHAR *host_name;
00126 CURLcode result;
00127 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00128 conn->host.name;
00129
00130 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
00131 hostname, conn->remote_port);
00132
00133 #ifdef HAS_ALPN
00134
00135
00136 connssl->use_alpn = conn->bits.tls_enable_alpn &&
00137 !GetProcAddress(GetModuleHandleA("ntdll"),
00138 "wine_get_version") &&
00139 Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
00140 VERSION_GREATER_THAN_EQUAL);
00141 #else
00142 connssl->use_alpn = false;
00143 #endif
00144
00145 connssl->cred = NULL;
00146
00147
00148 if(data->set.general_ssl.sessionid) {
00149 Curl_ssl_sessionid_lock(conn);
00150 if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
00151 connssl->cred = old_cred;
00152 infof(data, "schannel: re-using existing credential handle\n");
00153
00154
00155 connssl->cred->refcount++;
00156 infof(data, "schannel: incremented credential handle refcount = %d\n",
00157 connssl->cred->refcount);
00158 }
00159 Curl_ssl_sessionid_unlock(conn);
00160 }
00161
00162 if(!connssl->cred) {
00163
00164 memset(&schannel_cred, 0, sizeof(schannel_cred));
00165 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
00166
00167 if(conn->ssl_config.verifypeer) {
00168 #ifdef _WIN32_WCE
00169
00170
00171 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
00172 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
00173 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
00174 #else
00175 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
00176
00177 if(data->set.ssl.no_revoke)
00178 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
00179 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
00180 else
00181 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
00182 #endif
00183 if(data->set.ssl.no_revoke)
00184 infof(data, "schannel: disabled server certificate revocation "
00185 "checks\n");
00186 else
00187 infof(data, "schannel: checking server certificate revocation\n");
00188 }
00189 else {
00190 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
00191 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
00192 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
00193 infof(data, "schannel: disabled server certificate revocation checks\n");
00194 }
00195
00196 if(!conn->ssl_config.verifyhost) {
00197 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
00198 infof(data, "schannel: verifyhost setting prevents Schannel from "
00199 "comparing the supplied target name with the subject "
00200 "names in server certificates. Also disables SNI.\n");
00201 }
00202
00203 switch(conn->ssl_config.version) {
00204 case CURL_SSLVERSION_DEFAULT:
00205 case CURL_SSLVERSION_TLSv1:
00206 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
00207 SP_PROT_TLS1_1_CLIENT |
00208 SP_PROT_TLS1_2_CLIENT;
00209 break;
00210 case CURL_SSLVERSION_TLSv1_0:
00211 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT;
00212 break;
00213 case CURL_SSLVERSION_TLSv1_1:
00214 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT;
00215 break;
00216 case CURL_SSLVERSION_TLSv1_2:
00217 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
00218 break;
00219 case CURL_SSLVERSION_TLSv1_3:
00220 failf(data, "Schannel: TLS 1.3 is not yet supported");
00221 return CURLE_SSL_CONNECT_ERROR;
00222 case CURL_SSLVERSION_SSLv3:
00223 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
00224 break;
00225 case CURL_SSLVERSION_SSLv2:
00226 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
00227 break;
00228 default:
00229 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
00230 return CURLE_SSL_CONNECT_ERROR;
00231 }
00232
00233
00234 connssl->cred = (struct curl_schannel_cred *)
00235 malloc(sizeof(struct curl_schannel_cred));
00236 if(!connssl->cred) {
00237 failf(data, "schannel: unable to allocate memory");
00238 return CURLE_OUT_OF_MEMORY;
00239 }
00240 memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
00241 connssl->cred->refcount = 1;
00242
00243
00244
00245 sspi_status =
00246 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
00247 SECPKG_CRED_OUTBOUND, NULL,
00248 &schannel_cred, NULL, NULL,
00249 &connssl->cred->cred_handle,
00250 &connssl->cred->time_stamp);
00251
00252 if(sspi_status != SEC_E_OK) {
00253 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
00254 failf(data, "schannel: SNI or certificate check failed: %s",
00255 Curl_sspi_strerror(conn, sspi_status));
00256 else
00257 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
00258 Curl_sspi_strerror(conn, sspi_status));
00259 Curl_safefree(connssl->cred);
00260 return CURLE_SSL_CONNECT_ERROR;
00261 }
00262 }
00263
00264
00265 if(Curl_inet_pton(AF_INET, hostname, &addr)
00266 #ifdef ENABLE_IPV6
00267 || Curl_inet_pton(AF_INET6, hostname, &addr6)
00268 #endif
00269 ) {
00270 infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
00271 }
00272
00273 #ifdef HAS_ALPN
00274 if(connssl->use_alpn) {
00275 int cur = 0;
00276 int list_start_index = 0;
00277 unsigned int *extension_len = NULL;
00278 unsigned short* list_len = NULL;
00279
00280
00281
00282 extension_len = (unsigned int *)(&alpn_buffer[cur]);
00283 cur += sizeof(unsigned int);
00284
00285
00286
00287 *(unsigned int *)&alpn_buffer[cur] =
00288 SecApplicationProtocolNegotiationExt_ALPN;
00289 cur += sizeof(unsigned int);
00290
00291
00292
00293 list_len = (unsigned short*)(&alpn_buffer[cur]);
00294 cur += sizeof(unsigned short);
00295
00296 list_start_index = cur;
00297
00298 #ifdef USE_NGHTTP2
00299 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
00300 memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
00301 cur += NGHTTP2_PROTO_ALPN_LEN;
00302 infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
00303 }
00304 #endif
00305
00306 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
00307 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
00308 cur += ALPN_HTTP_1_1_LENGTH;
00309 infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
00310
00311 *list_len = curlx_uitous(cur - list_start_index);
00312 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
00313
00314 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
00315 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
00316 }
00317 else
00318 {
00319 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
00320 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
00321 }
00322 #else
00323 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
00324 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
00325 #endif
00326
00327
00328 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
00329 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
00330
00331
00332 connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
00333 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
00334 ISC_REQ_STREAM;
00335
00336
00337 connssl->ctxt = (struct curl_schannel_ctxt *)
00338 malloc(sizeof(struct curl_schannel_ctxt));
00339 if(!connssl->ctxt) {
00340 failf(data, "schannel: unable to allocate memory");
00341 return CURLE_OUT_OF_MEMORY;
00342 }
00343 memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
00344
00345 host_name = Curl_convert_UTF8_to_tchar(hostname);
00346 if(!host_name)
00347 return CURLE_OUT_OF_MEMORY;
00348
00349
00350
00351
00352
00353
00354
00355
00356 sspi_status = s_pSecFn->InitializeSecurityContext(
00357 &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0,
00358 (connssl->use_alpn ? &inbuf_desc : NULL),
00359 0, &connssl->ctxt->ctxt_handle,
00360 &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
00361
00362 Curl_unicodefree(host_name);
00363
00364 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
00365 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
00366 failf(data, "schannel: SNI or certificate check failed: %s",
00367 Curl_sspi_strerror(conn, sspi_status));
00368 else
00369 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
00370 Curl_sspi_strerror(conn, sspi_status));
00371 Curl_safefree(connssl->ctxt);
00372 return CURLE_SSL_CONNECT_ERROR;
00373 }
00374
00375 infof(data, "schannel: sending initial handshake data: "
00376 "sending %lu bytes...\n", outbuf.cbBuffer);
00377
00378
00379 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
00380 outbuf.cbBuffer, &written);
00381 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
00382 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
00383 failf(data, "schannel: failed to send initial handshake data: "
00384 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
00385 return CURLE_SSL_CONNECT_ERROR;
00386 }
00387
00388 infof(data, "schannel: sent initial handshake data: "
00389 "sent %zd bytes\n", written);
00390
00391 connssl->recv_unrecoverable_err = CURLE_OK;
00392 connssl->recv_sspi_close_notify = false;
00393 connssl->recv_connection_closed = false;
00394
00395
00396 connssl->connecting_state = ssl_connect_2;
00397
00398 return CURLE_OK;
00399 }
00400
00401 static CURLcode
00402 schannel_connect_step2(struct connectdata *conn, int sockindex)
00403 {
00404 int i;
00405 ssize_t nread = -1, written = -1;
00406 struct Curl_easy *data = conn->data;
00407 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00408 unsigned char *reallocated_buffer;
00409 size_t reallocated_length;
00410 SecBuffer outbuf[3];
00411 SecBufferDesc outbuf_desc;
00412 SecBuffer inbuf[2];
00413 SecBufferDesc inbuf_desc;
00414 SECURITY_STATUS sspi_status = SEC_E_OK;
00415 TCHAR *host_name;
00416 CURLcode result;
00417 bool doread;
00418 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00419 conn->host.name;
00420
00421 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
00422
00423 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
00424 hostname, conn->remote_port);
00425
00426 if(!connssl->cred || !connssl->ctxt)
00427 return CURLE_SSL_CONNECT_ERROR;
00428
00429
00430 if(connssl->decdata_buffer == NULL) {
00431 connssl->decdata_offset = 0;
00432 connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
00433 connssl->decdata_buffer = malloc(connssl->decdata_length);
00434 if(connssl->decdata_buffer == NULL) {
00435 failf(data, "schannel: unable to allocate memory");
00436 return CURLE_OUT_OF_MEMORY;
00437 }
00438 }
00439
00440
00441 if(connssl->encdata_buffer == NULL) {
00442 connssl->encdata_offset = 0;
00443 connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
00444 connssl->encdata_buffer = malloc(connssl->encdata_length);
00445 if(connssl->encdata_buffer == NULL) {
00446 failf(data, "schannel: unable to allocate memory");
00447 return CURLE_OUT_OF_MEMORY;
00448 }
00449 }
00450
00451
00452 if(connssl->encdata_length - connssl->encdata_offset <
00453 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
00454
00455 reallocated_length = connssl->encdata_offset +
00456 CURL_SCHANNEL_BUFFER_FREE_SIZE;
00457 reallocated_buffer = realloc(connssl->encdata_buffer,
00458 reallocated_length);
00459
00460 if(reallocated_buffer == NULL) {
00461 failf(data, "schannel: unable to re-allocate memory");
00462 return CURLE_OUT_OF_MEMORY;
00463 }
00464 else {
00465 connssl->encdata_buffer = reallocated_buffer;
00466 connssl->encdata_length = reallocated_length;
00467 }
00468 }
00469
00470 for(;;) {
00471 if(doread) {
00472
00473 result = Curl_read_plain(conn->sock[sockindex],
00474 (char *) (connssl->encdata_buffer +
00475 connssl->encdata_offset),
00476 connssl->encdata_length -
00477 connssl->encdata_offset,
00478 &nread);
00479 if(result == CURLE_AGAIN) {
00480 if(connssl->connecting_state != ssl_connect_2_writing)
00481 connssl->connecting_state = ssl_connect_2_reading;
00482 infof(data, "schannel: failed to receive handshake, "
00483 "need more data\n");
00484 return CURLE_OK;
00485 }
00486 else if((result != CURLE_OK) || (nread == 0)) {
00487 failf(data, "schannel: failed to receive handshake, "
00488 "SSL/TLS connection failed");
00489 return CURLE_SSL_CONNECT_ERROR;
00490 }
00491
00492
00493 connssl->encdata_offset += nread;
00494 }
00495
00496 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
00497 connssl->encdata_offset, connssl->encdata_length);
00498
00499
00500 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
00501 curlx_uztoul(connssl->encdata_offset));
00502 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
00503 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
00504
00505
00506 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
00507 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
00508 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
00509 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
00510
00511 if(inbuf[0].pvBuffer == NULL) {
00512 failf(data, "schannel: unable to allocate memory");
00513 return CURLE_OUT_OF_MEMORY;
00514 }
00515
00516
00517 memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
00518 connssl->encdata_offset);
00519
00520 host_name = Curl_convert_UTF8_to_tchar(hostname);
00521 if(!host_name)
00522 return CURLE_OUT_OF_MEMORY;
00523
00524
00525
00526 sspi_status = s_pSecFn->InitializeSecurityContext(
00527 &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
00528 host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
00529 &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
00530
00531 Curl_unicodefree(host_name);
00532
00533
00534 Curl_safefree(inbuf[0].pvBuffer);
00535
00536
00537 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
00538 connssl->connecting_state = ssl_connect_2_reading;
00539 infof(data, "schannel: received incomplete message, need more data\n");
00540 return CURLE_OK;
00541 }
00542
00543
00544
00545
00546 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
00547 !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
00548 connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
00549 connssl->connecting_state = ssl_connect_2_writing;
00550 infof(data, "schannel: a client certificate has been requested\n");
00551 return CURLE_OK;
00552 }
00553
00554
00555 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
00556 for(i = 0; i < 3; i++) {
00557
00558 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
00559 infof(data, "schannel: sending next handshake data: "
00560 "sending %lu bytes...\n", outbuf[i].cbBuffer);
00561
00562
00563 result = Curl_write_plain(conn, conn->sock[sockindex],
00564 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
00565 &written);
00566 if((result != CURLE_OK) ||
00567 (outbuf[i].cbBuffer != (size_t) written)) {
00568 failf(data, "schannel: failed to send next handshake data: "
00569 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
00570 return CURLE_SSL_CONNECT_ERROR;
00571 }
00572 }
00573
00574
00575 if(outbuf[i].pvBuffer != NULL) {
00576 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
00577 }
00578 }
00579 }
00580 else {
00581 if(sspi_status == SEC_E_WRONG_PRINCIPAL)
00582 failf(data, "schannel: SNI or certificate check failed: %s",
00583 Curl_sspi_strerror(conn, sspi_status));
00584 else
00585 failf(data, "schannel: next InitializeSecurityContext failed: %s",
00586 Curl_sspi_strerror(conn, sspi_status));
00587 return CURLE_SSL_CONNECT_ERROR;
00588 }
00589
00590
00591 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
00592 infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 if(connssl->encdata_offset > inbuf[1].cbBuffer) {
00606 memmove(connssl->encdata_buffer,
00607 (connssl->encdata_buffer + connssl->encdata_offset) -
00608 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
00609 connssl->encdata_offset = inbuf[1].cbBuffer;
00610 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
00611 doread = FALSE;
00612 continue;
00613 }
00614 }
00615 }
00616 else {
00617 connssl->encdata_offset = 0;
00618 }
00619 break;
00620 }
00621
00622
00623 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
00624 connssl->connecting_state = ssl_connect_2_reading;
00625 return CURLE_OK;
00626 }
00627
00628
00629 if(sspi_status == SEC_E_OK) {
00630 connssl->connecting_state = ssl_connect_3;
00631 infof(data, "schannel: SSL/TLS handshake complete\n");
00632 }
00633
00634 #ifdef _WIN32_WCE
00635
00636
00637 if(conn->ssl_config.verifypeer)
00638 return verify_certificate(conn, sockindex);
00639 #endif
00640
00641 return CURLE_OK;
00642 }
00643
00644 static CURLcode
00645 schannel_connect_step3(struct connectdata *conn, int sockindex)
00646 {
00647 CURLcode result = CURLE_OK;
00648 struct Curl_easy *data = conn->data;
00649 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00650 SECURITY_STATUS sspi_status = SEC_E_OK;
00651 CERT_CONTEXT *ccert_context = NULL;
00652 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00653 conn->host.name;
00654 #ifdef HAS_ALPN
00655 SecPkgContext_ApplicationProtocol alpn_result;
00656 #endif
00657
00658 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
00659
00660 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
00661 hostname, conn->remote_port);
00662
00663 if(!connssl->cred)
00664 return CURLE_SSL_CONNECT_ERROR;
00665
00666
00667 if(connssl->ret_flags != connssl->req_flags) {
00668 if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
00669 failf(data, "schannel: failed to setup sequence detection");
00670 if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
00671 failf(data, "schannel: failed to setup replay detection");
00672 if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
00673 failf(data, "schannel: failed to setup confidentiality");
00674 if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
00675 failf(data, "schannel: failed to setup memory allocation");
00676 if(!(connssl->ret_flags & ISC_RET_STREAM))
00677 failf(data, "schannel: failed to setup stream orientation");
00678 return CURLE_SSL_CONNECT_ERROR;
00679 }
00680
00681 #ifdef HAS_ALPN
00682 if(connssl->use_alpn) {
00683 sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
00684 SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
00685
00686 if(sspi_status != SEC_E_OK) {
00687 failf(data, "schannel: failed to retrieve ALPN result");
00688 return CURLE_SSL_CONNECT_ERROR;
00689 }
00690
00691 if(alpn_result.ProtoNegoStatus ==
00692 SecApplicationProtocolNegotiationStatus_Success) {
00693
00694 infof(data, "schannel: ALPN, server accepted to use %.*s\n",
00695 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
00696
00697 #ifdef USE_NGHTTP2
00698 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
00699 !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
00700 NGHTTP2_PROTO_VERSION_ID_LEN)) {
00701 conn->negnpn = CURL_HTTP_VERSION_2;
00702 }
00703 else
00704 #endif
00705 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
00706 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
00707 ALPN_HTTP_1_1_LENGTH)) {
00708 conn->negnpn = CURL_HTTP_VERSION_1_1;
00709 }
00710 }
00711 else
00712 infof(data, "ALPN, server did not agree to a protocol\n");
00713 }
00714 #endif
00715
00716
00717 if(data->set.general_ssl.sessionid) {
00718 bool incache;
00719 struct curl_schannel_cred *old_cred = NULL;
00720
00721 Curl_ssl_sessionid_lock(conn);
00722 incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
00723 sockindex));
00724 if(incache) {
00725 if(old_cred != connssl->cred) {
00726 infof(data, "schannel: old credential handle is stale, removing\n");
00727
00728 Curl_ssl_delsessionid(conn, (void *)old_cred);
00729 incache = FALSE;
00730 }
00731 }
00732 if(!incache) {
00733 result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
00734 sizeof(struct curl_schannel_cred),
00735 sockindex);
00736 if(result) {
00737 Curl_ssl_sessionid_unlock(conn);
00738 failf(data, "schannel: failed to store credential handle");
00739 return result;
00740 }
00741 else {
00742
00743 connssl->cred->refcount++;
00744 infof(data, "schannel: stored credential handle in session cache\n");
00745 }
00746 }
00747 Curl_ssl_sessionid_unlock(conn);
00748 }
00749
00750 if(data->set.ssl.certinfo) {
00751 sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
00752 SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
00753
00754 if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
00755 failf(data, "schannel: failed to retrieve remote cert context");
00756 return CURLE_SSL_CONNECT_ERROR;
00757 }
00758
00759 result = Curl_ssl_init_certinfo(data, 1);
00760 if(!result) {
00761 if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
00762 (ccert_context->cbCertEncoded > 0)) {
00763
00764 const char *beg = (const char *) ccert_context->pbCertEncoded;
00765 const char *end = beg + ccert_context->cbCertEncoded;
00766 result = Curl_extract_certinfo(conn, 0, beg, end);
00767 }
00768 }
00769 CertFreeCertificateContext(ccert_context);
00770 if(result)
00771 return result;
00772 }
00773
00774 connssl->connecting_state = ssl_connect_done;
00775
00776 return CURLE_OK;
00777 }
00778
00779 static CURLcode
00780 schannel_connect_common(struct connectdata *conn, int sockindex,
00781 bool nonblocking, bool *done)
00782 {
00783 CURLcode result;
00784 struct Curl_easy *data = conn->data;
00785 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00786 curl_socket_t sockfd = conn->sock[sockindex];
00787 time_t timeout_ms;
00788 int what;
00789
00790
00791 if(ssl_connection_complete == connssl->state) {
00792 *done = TRUE;
00793 return CURLE_OK;
00794 }
00795
00796 if(ssl_connect_1 == connssl->connecting_state) {
00797
00798 timeout_ms = Curl_timeleft(data, NULL, TRUE);
00799
00800 if(timeout_ms < 0) {
00801
00802 failf(data, "SSL/TLS connection timeout");
00803 return CURLE_OPERATION_TIMEDOUT;
00804 }
00805
00806 result = schannel_connect_step1(conn, sockindex);
00807 if(result)
00808 return result;
00809 }
00810
00811 while(ssl_connect_2 == connssl->connecting_state ||
00812 ssl_connect_2_reading == connssl->connecting_state ||
00813 ssl_connect_2_writing == connssl->connecting_state) {
00814
00815
00816 timeout_ms = Curl_timeleft(data, NULL, TRUE);
00817
00818 if(timeout_ms < 0) {
00819
00820 failf(data, "SSL/TLS connection timeout");
00821 return CURLE_OPERATION_TIMEDOUT;
00822 }
00823
00824
00825 if(connssl->connecting_state == ssl_connect_2_reading
00826 || connssl->connecting_state == ssl_connect_2_writing) {
00827
00828 curl_socket_t writefd = ssl_connect_2_writing ==
00829 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
00830 curl_socket_t readfd = ssl_connect_2_reading ==
00831 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
00832
00833 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
00834 nonblocking ? 0 : timeout_ms);
00835 if(what < 0) {
00836
00837 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
00838 return CURLE_SSL_CONNECT_ERROR;
00839 }
00840 else if(0 == what) {
00841 if(nonblocking) {
00842 *done = FALSE;
00843 return CURLE_OK;
00844 }
00845 else {
00846
00847 failf(data, "SSL/TLS connection timeout");
00848 return CURLE_OPERATION_TIMEDOUT;
00849 }
00850 }
00851
00852 }
00853
00854
00855
00856
00857
00858
00859
00860
00861 result = schannel_connect_step2(conn, sockindex);
00862 if(result || (nonblocking &&
00863 (ssl_connect_2 == connssl->connecting_state ||
00864 ssl_connect_2_reading == connssl->connecting_state ||
00865 ssl_connect_2_writing == connssl->connecting_state)))
00866 return result;
00867
00868 }
00869
00870 if(ssl_connect_3 == connssl->connecting_state) {
00871 result = schannel_connect_step3(conn, sockindex);
00872 if(result)
00873 return result;
00874 }
00875
00876 if(ssl_connect_done == connssl->connecting_state) {
00877 connssl->state = ssl_connection_complete;
00878 conn->recv[sockindex] = schannel_recv;
00879 conn->send[sockindex] = schannel_send;
00880 *done = TRUE;
00881 }
00882 else
00883 *done = FALSE;
00884
00885
00886 connssl->connecting_state = ssl_connect_1;
00887
00888 return CURLE_OK;
00889 }
00890
00891 static ssize_t
00892 schannel_send(struct connectdata *conn, int sockindex,
00893 const void *buf, size_t len, CURLcode *err)
00894 {
00895 ssize_t written = -1;
00896 size_t data_len = 0;
00897 unsigned char *data = NULL;
00898 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00899 SecBuffer outbuf[4];
00900 SecBufferDesc outbuf_desc;
00901 SECURITY_STATUS sspi_status = SEC_E_OK;
00902 CURLcode result;
00903
00904
00905 if(connssl->stream_sizes.cbMaximumMessage == 0) {
00906 sspi_status = s_pSecFn->QueryContextAttributes(
00907 &connssl->ctxt->ctxt_handle,
00908 SECPKG_ATTR_STREAM_SIZES,
00909 &connssl->stream_sizes);
00910 if(sspi_status != SEC_E_OK) {
00911 *err = CURLE_SEND_ERROR;
00912 return -1;
00913 }
00914 }
00915
00916
00917 if(len > connssl->stream_sizes.cbMaximumMessage) {
00918 *err = CURLE_SEND_ERROR;
00919 return -1;
00920 }
00921
00922
00923 data_len = connssl->stream_sizes.cbHeader + len +
00924 connssl->stream_sizes.cbTrailer;
00925 data = (unsigned char *) malloc(data_len);
00926 if(data == NULL) {
00927 *err = CURLE_OUT_OF_MEMORY;
00928 return -1;
00929 }
00930
00931
00932 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
00933 data, connssl->stream_sizes.cbHeader);
00934 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
00935 data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
00936 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
00937 data + connssl->stream_sizes.cbHeader + len,
00938 connssl->stream_sizes.cbTrailer);
00939 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
00940 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
00941
00942
00943 memcpy(outbuf[1].pvBuffer, buf, len);
00944
00945
00946 sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
00947 &outbuf_desc, 0);
00948
00949
00950 if(sspi_status == SEC_E_OK) {
00951 written = 0;
00952
00953
00954 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973 while(len > (size_t)written) {
00974 ssize_t this_write;
00975 time_t timeleft;
00976 int what;
00977
00978 this_write = 0;
00979
00980 timeleft = Curl_timeleft(conn->data, NULL, FALSE);
00981 if(timeleft < 0) {
00982
00983 failf(conn->data, "schannel: timed out sending data "
00984 "(bytes sent: %zd)", written);
00985 *err = CURLE_OPERATION_TIMEDOUT;
00986 written = -1;
00987 break;
00988 }
00989
00990 what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
00991 if(what < 0) {
00992
00993 failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
00994 *err = CURLE_SEND_ERROR;
00995 written = -1;
00996 break;
00997 }
00998 else if(0 == what) {
00999 failf(conn->data, "schannel: timed out sending data "
01000 "(bytes sent: %zd)", written);
01001 *err = CURLE_OPERATION_TIMEDOUT;
01002 written = -1;
01003 break;
01004 }
01005
01006
01007 result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
01008 len - written, &this_write);
01009 if(result == CURLE_AGAIN)
01010 continue;
01011 else if(result != CURLE_OK) {
01012 *err = result;
01013 written = -1;
01014 break;
01015 }
01016
01017 written += this_write;
01018 }
01019 }
01020 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
01021 *err = CURLE_OUT_OF_MEMORY;
01022 }
01023 else{
01024 *err = CURLE_SEND_ERROR;
01025 }
01026
01027 Curl_safefree(data);
01028
01029 if(len == (size_t)written)
01030
01031
01032 written = outbuf[1].cbBuffer;
01033
01034 return written;
01035 }
01036
01037 static ssize_t
01038 schannel_recv(struct connectdata *conn, int sockindex,
01039 char *buf, size_t len, CURLcode *err)
01040 {
01041 size_t size = 0;
01042 ssize_t nread = -1;
01043 struct Curl_easy *data = conn->data;
01044 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
01045 unsigned char *reallocated_buffer;
01046 size_t reallocated_length;
01047 bool done = FALSE;
01048 SecBuffer inbuf[4];
01049 SecBufferDesc inbuf_desc;
01050 SECURITY_STATUS sspi_status = SEC_E_OK;
01051
01052
01053 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 infof(data, "schannel: client wants to read %zu bytes\n", len);
01066 *err = CURLE_OK;
01067
01068 if(len && len <= connssl->decdata_offset) {
01069 infof(data, "schannel: enough decrypted data is already available\n");
01070 goto cleanup;
01071 }
01072 else if(connssl->recv_unrecoverable_err) {
01073 *err = connssl->recv_unrecoverable_err;
01074 infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
01075 goto cleanup;
01076 }
01077 else if(connssl->recv_sspi_close_notify) {
01078
01079 infof(data, "schannel: server indicated shutdown in a prior call\n");
01080 goto cleanup;
01081 }
01082 else if(!len) {
01083
01084
01085
01086
01087 ;
01088 }
01089 else if(!connssl->recv_connection_closed) {
01090
01091 size = connssl->encdata_length - connssl->encdata_offset;
01092 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
01093 connssl->encdata_length < min_encdata_length) {
01094 reallocated_length = connssl->encdata_offset +
01095 CURL_SCHANNEL_BUFFER_FREE_SIZE;
01096 if(reallocated_length < min_encdata_length) {
01097 reallocated_length = min_encdata_length;
01098 }
01099 reallocated_buffer = realloc(connssl->encdata_buffer,
01100 reallocated_length);
01101 if(reallocated_buffer == NULL) {
01102 *err = CURLE_OUT_OF_MEMORY;
01103 failf(data, "schannel: unable to re-allocate memory");
01104 goto cleanup;
01105 }
01106
01107 connssl->encdata_buffer = reallocated_buffer;
01108 connssl->encdata_length = reallocated_length;
01109 size = connssl->encdata_length - connssl->encdata_offset;
01110 infof(data, "schannel: encdata_buffer resized %zu\n",
01111 connssl->encdata_length);
01112 }
01113
01114 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
01115 connssl->encdata_offset, connssl->encdata_length);
01116
01117
01118 *err = Curl_read_plain(conn->sock[sockindex],
01119 (char *)(connssl->encdata_buffer +
01120 connssl->encdata_offset),
01121 size, &nread);
01122 if(*err) {
01123 nread = -1;
01124 if(*err == CURLE_AGAIN)
01125 infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
01126 else if(*err == CURLE_RECV_ERROR)
01127 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
01128 else
01129 infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
01130 }
01131 else if(nread == 0) {
01132 connssl->recv_connection_closed = true;
01133 infof(data, "schannel: server closed the connection\n");
01134 }
01135 else if(nread > 0) {
01136 connssl->encdata_offset += (size_t)nread;
01137 infof(data, "schannel: encrypted data got %zd\n", nread);
01138 }
01139 }
01140
01141 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
01142 connssl->encdata_offset, connssl->encdata_length);
01143
01144
01145 while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
01146 (!len || connssl->decdata_offset < len ||
01147 connssl->recv_connection_closed)) {
01148
01149 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
01150 curlx_uztoul(connssl->encdata_offset));
01151
01152
01153 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
01154 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
01155 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
01156 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
01157
01158
01159
01160 sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
01161 &inbuf_desc, 0, NULL);
01162
01163
01164
01165 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
01166 sspi_status == SEC_I_CONTEXT_EXPIRED) {
01167
01168
01169 if(inbuf[1].BufferType == SECBUFFER_DATA) {
01170 infof(data, "schannel: decrypted data length: %lu\n",
01171 inbuf[1].cbBuffer);
01172
01173
01174 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
01175 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
01176 if(connssl->decdata_length - connssl->decdata_offset < size ||
01177 connssl->decdata_length < len) {
01178
01179 reallocated_length = connssl->decdata_offset + size;
01180
01181 if(reallocated_length < len) {
01182 reallocated_length = len;
01183 }
01184 reallocated_buffer = realloc(connssl->decdata_buffer,
01185 reallocated_length);
01186 if(reallocated_buffer == NULL) {
01187 *err = CURLE_OUT_OF_MEMORY;
01188 failf(data, "schannel: unable to re-allocate memory");
01189 goto cleanup;
01190 }
01191 connssl->decdata_buffer = reallocated_buffer;
01192 connssl->decdata_length = reallocated_length;
01193 }
01194
01195
01196 size = inbuf[1].cbBuffer;
01197 if(size) {
01198 memcpy(connssl->decdata_buffer + connssl->decdata_offset,
01199 inbuf[1].pvBuffer, size);
01200 connssl->decdata_offset += size;
01201 }
01202
01203 infof(data, "schannel: decrypted data added: %zu\n", size);
01204 infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
01205 connssl->decdata_offset, connssl->decdata_length);
01206 }
01207
01208
01209 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
01210 infof(data, "schannel: encrypted data length: %lu\n",
01211 inbuf[3].cbBuffer);
01212
01213
01214
01215
01216 if(connssl->encdata_offset > inbuf[3].cbBuffer) {
01217
01218
01219 memmove(connssl->encdata_buffer,
01220 (connssl->encdata_buffer + connssl->encdata_offset) -
01221 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
01222 connssl->encdata_offset = inbuf[3].cbBuffer;
01223 }
01224
01225 infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
01226 connssl->encdata_offset, connssl->encdata_length);
01227 }
01228 else {
01229
01230 connssl->encdata_offset = 0;
01231 }
01232
01233
01234 if(sspi_status == SEC_I_RENEGOTIATE) {
01235 infof(data, "schannel: remote party requests renegotiation\n");
01236 if(*err && *err != CURLE_AGAIN) {
01237 infof(data, "schannel: can't renogotiate, an error is pending\n");
01238 goto cleanup;
01239 }
01240 if(connssl->encdata_offset) {
01241 *err = CURLE_RECV_ERROR;
01242 infof(data, "schannel: can't renogotiate, "
01243 "encrypted data available\n");
01244 goto cleanup;
01245 }
01246
01247 infof(data, "schannel: renegotiating SSL/TLS connection\n");
01248 connssl->state = ssl_connection_negotiating;
01249 connssl->connecting_state = ssl_connect_2_writing;
01250 *err = schannel_connect_common(conn, sockindex, FALSE, &done);
01251 if(*err) {
01252 infof(data, "schannel: renegotiation failed\n");
01253 goto cleanup;
01254 }
01255
01256 sspi_status = SEC_E_OK;
01257 infof(data, "schannel: SSL/TLS connection renegotiated\n");
01258 continue;
01259 }
01260
01261 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
01262
01263
01264 connssl->recv_sspi_close_notify = true;
01265 if(!connssl->recv_connection_closed) {
01266 connssl->recv_connection_closed = true;
01267 infof(data, "schannel: server closed the connection\n");
01268 }
01269 goto cleanup;
01270 }
01271 }
01272 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
01273 if(!*err)
01274 *err = CURLE_AGAIN;
01275 infof(data, "schannel: failed to decrypt data, need more data\n");
01276 goto cleanup;
01277 }
01278 else {
01279 *err = CURLE_RECV_ERROR;
01280 infof(data, "schannel: failed to read data from server: %s\n",
01281 Curl_sspi_strerror(conn, sspi_status));
01282 goto cleanup;
01283 }
01284 }
01285
01286 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
01287 connssl->encdata_offset, connssl->encdata_length);
01288
01289 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
01290 connssl->decdata_offset, connssl->decdata_length);
01291
01292 cleanup:
01293
01294 infof(data, "schannel: schannel_recv cleanup\n");
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304 if(len && !connssl->decdata_offset && connssl->recv_connection_closed &&
01305 !connssl->recv_sspi_close_notify) {
01306 bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
01307 VERSION_EQUAL);
01308
01309 if(isWin2k && sspi_status == SEC_E_OK)
01310 connssl->recv_sspi_close_notify = true;
01311 else {
01312 *err = CURLE_RECV_ERROR;
01313 infof(data, "schannel: server closed abruptly (missing close_notify)\n");
01314 }
01315 }
01316
01317
01318 if(*err && *err != CURLE_AGAIN)
01319 connssl->recv_unrecoverable_err = *err;
01320
01321 size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
01322 if(size) {
01323 memcpy(buf, connssl->decdata_buffer, size);
01324 memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
01325 connssl->decdata_offset - size);
01326 connssl->decdata_offset -= size;
01327
01328 infof(data, "schannel: decrypted data returned %zu\n", size);
01329 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
01330 connssl->decdata_offset, connssl->decdata_length);
01331 *err = CURLE_OK;
01332 return (ssize_t)size;
01333 }
01334
01335 if(!*err && !connssl->recv_connection_closed)
01336 *err = CURLE_AGAIN;
01337
01338
01339
01340
01341 if(!len)
01342 *err = CURLE_OK;
01343
01344 return *err ? -1 : 0;
01345 }
01346
01347 CURLcode
01348 Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
01349 bool *done)
01350 {
01351 return schannel_connect_common(conn, sockindex, TRUE, done);
01352 }
01353
01354 CURLcode
01355 Curl_schannel_connect(struct connectdata *conn, int sockindex)
01356 {
01357 CURLcode result;
01358 bool done = FALSE;
01359
01360 result = schannel_connect_common(conn, sockindex, FALSE, &done);
01361 if(result)
01362 return result;
01363
01364 DEBUGASSERT(done);
01365
01366 return CURLE_OK;
01367 }
01368
01369 bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
01370 {
01371 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
01372
01373 if(connssl->use)
01374 return (connssl->encdata_offset > 0 ||
01375 connssl->decdata_offset > 0) ? TRUE : FALSE;
01376 else
01377 return FALSE;
01378 }
01379
01380 void Curl_schannel_close(struct connectdata *conn, int sockindex)
01381 {
01382 if(conn->ssl[sockindex].use)
01383
01384 Curl_ssl_shutdown(conn, sockindex);
01385 }
01386
01387 int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
01388 {
01389
01390
01391
01392 struct Curl_easy *data = conn->data;
01393 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
01394 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
01395 conn->host.name;
01396
01397 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
01398 hostname, conn->remote_port);
01399
01400 if(connssl->cred && connssl->ctxt) {
01401 SecBufferDesc BuffDesc;
01402 SecBuffer Buffer;
01403 SECURITY_STATUS sspi_status;
01404 SecBuffer outbuf;
01405 SecBufferDesc outbuf_desc;
01406 CURLcode result;
01407 TCHAR *host_name;
01408 DWORD dwshut = SCHANNEL_SHUTDOWN;
01409
01410 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
01411 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
01412
01413 sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
01414 &BuffDesc);
01415
01416 if(sspi_status != SEC_E_OK)
01417 failf(data, "schannel: ApplyControlToken failure: %s",
01418 Curl_sspi_strerror(conn, sspi_status));
01419
01420 host_name = Curl_convert_UTF8_to_tchar(hostname);
01421 if(!host_name)
01422 return CURLE_OUT_OF_MEMORY;
01423
01424
01425 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
01426 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
01427
01428 sspi_status = s_pSecFn->InitializeSecurityContext(
01429 &connssl->cred->cred_handle,
01430 &connssl->ctxt->ctxt_handle,
01431 host_name,
01432 connssl->req_flags,
01433 0,
01434 0,
01435 NULL,
01436 0,
01437 &connssl->ctxt->ctxt_handle,
01438 &outbuf_desc,
01439 &connssl->ret_flags,
01440 &connssl->ctxt->time_stamp);
01441
01442 Curl_unicodefree(host_name);
01443
01444 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
01445
01446 ssize_t written;
01447 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
01448 outbuf.cbBuffer, &written);
01449
01450 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
01451 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
01452 infof(data, "schannel: failed to send close msg: %s"
01453 " (bytes written: %zd)\n", curl_easy_strerror(result), written);
01454 }
01455 }
01456 }
01457
01458
01459 if(connssl->ctxt) {
01460 infof(data, "schannel: clear security context handle\n");
01461 s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
01462 Curl_safefree(connssl->ctxt);
01463 }
01464
01465
01466 if(connssl->cred) {
01467 Curl_ssl_sessionid_lock(conn);
01468 Curl_schannel_session_free(connssl->cred);
01469 Curl_ssl_sessionid_unlock(conn);
01470 connssl->cred = NULL;
01471 }
01472
01473
01474 if(connssl->encdata_buffer != NULL) {
01475 Curl_safefree(connssl->encdata_buffer);
01476 connssl->encdata_length = 0;
01477 connssl->encdata_offset = 0;
01478 }
01479
01480
01481 if(connssl->decdata_buffer != NULL) {
01482 Curl_safefree(connssl->decdata_buffer);
01483 connssl->decdata_length = 0;
01484 connssl->decdata_offset = 0;
01485 }
01486
01487 return CURLE_OK;
01488 }
01489
01490 void Curl_schannel_session_free(void *ptr)
01491 {
01492
01493 struct curl_schannel_cred *cred = ptr;
01494
01495 cred->refcount--;
01496 if(cred->refcount == 0) {
01497 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
01498 Curl_safefree(cred);
01499 }
01500 }
01501
01502 int Curl_schannel_init(void)
01503 {
01504 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
01505 }
01506
01507 void Curl_schannel_cleanup(void)
01508 {
01509 Curl_sspi_global_cleanup();
01510 }
01511
01512 size_t Curl_schannel_version(char *buffer, size_t size)
01513 {
01514 size = snprintf(buffer, size, "WinSSL");
01515
01516 return size;
01517 }
01518
01519 int Curl_schannel_random(unsigned char *entropy, size_t length)
01520 {
01521 HCRYPTPROV hCryptProv = 0;
01522
01523 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
01524 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
01525 return 1;
01526
01527 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
01528 CryptReleaseContext(hCryptProv, 0UL);
01529 return 1;
01530 }
01531
01532 CryptReleaseContext(hCryptProv, 0UL);
01533 return 0;
01534 }
01535
01536 #ifdef _WIN32_WCE
01537 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
01538 {
01539 SECURITY_STATUS status;
01540 struct Curl_easy *data = conn->data;
01541 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
01542 CURLcode result = CURLE_OK;
01543 CERT_CONTEXT *pCertContextServer = NULL;
01544 const CERT_CHAIN_CONTEXT *pChainContext = NULL;
01545 const char * const conn_hostname = SSL_IS_PROXY() ?
01546 conn->http_proxy.host.name :
01547 conn->host.name;
01548
01549 status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
01550 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
01551 &pCertContextServer);
01552
01553 if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
01554 failf(data, "schannel: Failed to read remote certificate context: %s",
01555 Curl_sspi_strerror(conn, status));
01556 result = CURLE_PEER_FAILED_VERIFICATION;
01557 }
01558
01559 if(result == CURLE_OK) {
01560 CERT_CHAIN_PARA ChainPara;
01561 memset(&ChainPara, 0, sizeof(ChainPara));
01562 ChainPara.cbSize = sizeof(ChainPara);
01563
01564 if(!CertGetCertificateChain(NULL,
01565 pCertContextServer,
01566 NULL,
01567 pCertContextServer->hCertStore,
01568 &ChainPara,
01569 (data->set.ssl.no_revoke ? 0 :
01570 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
01571 NULL,
01572 &pChainContext)) {
01573 failf(data, "schannel: CertGetCertificateChain failed: %s",
01574 Curl_sspi_strerror(conn, GetLastError()));
01575 pChainContext = NULL;
01576 result = CURLE_PEER_FAILED_VERIFICATION;
01577 }
01578
01579 if(result == CURLE_OK) {
01580 CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
01581 DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
01582 dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
01583 if(dwTrustErrorMask) {
01584 if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
01585 failf(data, "schannel: CertGetCertificateChain trust error"
01586 " CERT_TRUST_IS_REVOKED");
01587 else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
01588 failf(data, "schannel: CertGetCertificateChain trust error"
01589 " CERT_TRUST_IS_PARTIAL_CHAIN");
01590 else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
01591 failf(data, "schannel: CertGetCertificateChain trust error"
01592 " CERT_TRUST_IS_UNTRUSTED_ROOT");
01593 else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
01594 failf(data, "schannel: CertGetCertificateChain trust error"
01595 " CERT_TRUST_IS_NOT_TIME_VALID");
01596 else
01597 failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
01598 dwTrustErrorMask);
01599 result = CURLE_PEER_FAILED_VERIFICATION;
01600 }
01601 }
01602 }
01603
01604 if(result == CURLE_OK) {
01605 if(conn->ssl_config.verifyhost) {
01606 TCHAR cert_hostname_buff[256];
01607 DWORD len;
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617 len = CertGetNameString(pCertContextServer,
01618 CERT_NAME_DNS_TYPE,
01619 CERT_NAME_DISABLE_IE4_UTF8_FLAG,
01620 NULL,
01621 cert_hostname_buff,
01622 256);
01623 if(len > 0) {
01624 const char *cert_hostname;
01625
01626
01627
01628
01629
01630 cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
01631 if(!cert_hostname) {
01632 result = CURLE_OUT_OF_MEMORY;
01633 }
01634 else{
01635 int match_result;
01636
01637 match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
01638 if(match_result == CURL_HOST_MATCH) {
01639 infof(data,
01640 "schannel: connection hostname (%s) validated "
01641 "against certificate name (%s)\n",
01642 conn->host.name,
01643 cert_hostname);
01644 result = CURLE_OK;
01645 }
01646 else{
01647 failf(data,
01648 "schannel: connection hostname (%s) "
01649 "does not match certificate name (%s)",
01650 conn->host.name,
01651 cert_hostname);
01652 result = CURLE_PEER_FAILED_VERIFICATION;
01653 }
01654 Curl_unicodefree(cert_hostname);
01655 }
01656 }
01657 else {
01658 failf(data,
01659 "schannel: CertGetNameString did not provide any "
01660 "certificate name information");
01661 result = CURLE_PEER_FAILED_VERIFICATION;
01662 }
01663 }
01664 }
01665
01666 if(pChainContext)
01667 CertFreeCertificateChain(pChainContext);
01668
01669 if(pCertContextServer)
01670 CertFreeCertificateContext(pCertContextServer);
01671
01672 return result;
01673 }
01674 #endif
01675
01676 #endif