1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 2012 - 2015, Marc Hoersken, <info (at) marc-hoersken.de> 9 * Copyright (C) 2012, Mark Salisbury, <mark.salisbury (at) hp.com> 10 * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel (at) haxx.se>, et al. 11 * 12 * This software is licensed as described in the file COPYING, which 13 * you should have received as part of this distribution. The terms 14 * are also available at http://curl.haxx.se/docs/copyright.html. 15 * 16 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 * copies of the Software, and permit persons to whom the Software is 18 * furnished to do so, under the terms of the COPYING file. 19 * 20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 * KIND, either express or implied. 22 * 23 ***************************************************************************/ 24 25 /* 26 * Source file for all SChannel-specific code for the TLS/SSL layer. No code 27 * but vtls.c should ever call or use these functions. 28 * 29 */ 30 31 /* 32 * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: 33 * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan (at) gmail.com> 34 * 35 * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: 36 * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel (at) haxx.se>, et al. 37 * 38 * Thanks for code and inspiration! 39 */ 40 41 #include "curl_setup.h" 42 43 #ifdef USE_SCHANNEL 44 45 #ifndef USE_WINDOWS_SSPI 46 # error "Can't compile SCHANNEL support without SSPI." 47 #endif 48 49 #include "curl_sspi.h" 50 #include "schannel.h" 51 #include "vtls.h" 52 #include "sendf.h" 53 #include "connect.h" /* for the connect timeout */ 54 #include "strerror.h" 55 #include "select.h" /* for the socket readyness */ 56 #include "inet_pton.h" /* for IP addr SNI check */ 57 #include "curl_multibyte.h" 58 #include "warnless.h" 59 #include "curl_printf.h" 60 #include "curl_memory.h" 61 /* The last #include file should be: */ 62 #include "memdebug.h" 63 64 /* Uncomment to force verbose output 65 * #define infof(x, y, ...) printf(y, __VA_ARGS__) 66 * #define failf(x, y, ...) printf(y, __VA_ARGS__) 67 */ 68 69 static Curl_recv schannel_recv; 70 static Curl_send schannel_send; 71 72 #ifdef _WIN32_WCE 73 static CURLcode verify_certificate(struct connectdata *conn, int sockindex); 74 #endif 75 76 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType, 77 void *BufDataPtr, unsigned long BufByteSize) 78 { 79 buffer->cbBuffer = BufByteSize; 80 buffer->BufferType = BufType; 81 buffer->pvBuffer = BufDataPtr; 82 } 83 84 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, 85 unsigned long NumArrElem) 86 { 87 desc->ulVersion = SECBUFFER_VERSION; 88 desc->pBuffers = BufArr; 89 desc->cBuffers = NumArrElem; 90 } 91 92 static CURLcode 93 schannel_connect_step1(struct connectdata *conn, int sockindex) 94 { 95 ssize_t written = -1; 96 struct SessionHandle *data = conn->data; 97 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 98 SecBuffer outbuf; 99 SecBufferDesc outbuf_desc; 100 SCHANNEL_CRED schannel_cred; 101 SECURITY_STATUS sspi_status = SEC_E_OK; 102 struct curl_schannel_cred *old_cred = NULL; 103 struct in_addr addr; 104 #ifdef ENABLE_IPV6 105 struct in6_addr addr6; 106 #endif 107 TCHAR *host_name; 108 CURLcode result; 109 110 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", 111 conn->host.name, conn->remote_port); 112 113 /* check for an existing re-usable credential handle */ 114 if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { 115 connssl->cred = old_cred; 116 infof(data, "schannel: re-using existing credential handle\n"); 117 } 118 else { 119 /* setup Schannel API options */ 120 memset(&schannel_cred, 0, sizeof(schannel_cred)); 121 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; 122 123 if(data->set.ssl.verifypeer) { 124 #ifdef _WIN32_WCE 125 /* certificate validation on CE doesn't seem to work right; we'll 126 do it following a more manual process. */ 127 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | 128 SCH_CRED_IGNORE_NO_REVOCATION_CHECK | 129 SCH_CRED_IGNORE_REVOCATION_OFFLINE; 130 #else 131 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | 132 SCH_CRED_REVOCATION_CHECK_CHAIN; 133 #endif 134 infof(data, "schannel: checking server certificate revocation\n"); 135 } 136 else { 137 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | 138 SCH_CRED_IGNORE_NO_REVOCATION_CHECK | 139 SCH_CRED_IGNORE_REVOCATION_OFFLINE; 140 infof(data, "schannel: disable server certificate revocation checks\n"); 141 } 142 143 if(!data->set.ssl.verifyhost) { 144 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; 145 infof(data, "schannel: verifyhost setting prevents Schannel from " 146 "comparing the supplied target name with the subject " 147 "names in server certificates. Also disables SNI.\n"); 148 } 149 150 switch(data->set.ssl.version) { 151 default: 152 case CURL_SSLVERSION_DEFAULT: 153 case CURL_SSLVERSION_TLSv1: 154 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | 155 SP_PROT_TLS1_1_CLIENT | 156 SP_PROT_TLS1_2_CLIENT; 157 break; 158 case CURL_SSLVERSION_TLSv1_0: 159 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT; 160 break; 161 case CURL_SSLVERSION_TLSv1_1: 162 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT; 163 break; 164 case CURL_SSLVERSION_TLSv1_2: 165 schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; 166 break; 167 case CURL_SSLVERSION_SSLv3: 168 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; 169 break; 170 case CURL_SSLVERSION_SSLv2: 171 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; 172 break; 173 } 174 175 /* allocate memory for the re-usable credential handle */ 176 connssl->cred = (struct curl_schannel_cred *) 177 malloc(sizeof(struct curl_schannel_cred)); 178 if(!connssl->cred) { 179 failf(data, "schannel: unable to allocate memory"); 180 return CURLE_OUT_OF_MEMORY; 181 } 182 memset(connssl->cred, 0, sizeof(struct curl_schannel_cred)); 183 184 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ 185 sspi_status = 186 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, 187 SECPKG_CRED_OUTBOUND, NULL, 188 &schannel_cred, NULL, NULL, 189 &connssl->cred->cred_handle, 190 &connssl->cred->time_stamp); 191 192 if(sspi_status != SEC_E_OK) { 193 if(sspi_status == SEC_E_WRONG_PRINCIPAL) 194 failf(data, "schannel: SNI or certificate check failed: %s", 195 Curl_sspi_strerror(conn, sspi_status)); 196 else 197 failf(data, "schannel: AcquireCredentialsHandle failed: %s", 198 Curl_sspi_strerror(conn, sspi_status)); 199 Curl_safefree(connssl->cred); 200 return CURLE_SSL_CONNECT_ERROR; 201 } 202 } 203 204 /* Warn if SNI is disabled due to use of an IP address */ 205 if(Curl_inet_pton(AF_INET, conn->host.name, &addr) 206 #ifdef ENABLE_IPV6 207 || Curl_inet_pton(AF_INET6, conn->host.name, &addr6) 208 #endif 209 ) { 210 infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); 211 } 212 213 /* setup output buffer */ 214 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); 215 InitSecBufferDesc(&outbuf_desc, &outbuf, 1); 216 217 /* setup request flags */ 218 connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | 219 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | 220 ISC_REQ_STREAM; 221 222 /* allocate memory for the security context handle */ 223 connssl->ctxt = (struct curl_schannel_ctxt *) 224 malloc(sizeof(struct curl_schannel_ctxt)); 225 if(!connssl->ctxt) { 226 failf(data, "schannel: unable to allocate memory"); 227 return CURLE_OUT_OF_MEMORY; 228 } 229 memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt)); 230 231 host_name = Curl_convert_UTF8_to_tchar(conn->host.name); 232 if(!host_name) 233 return CURLE_OUT_OF_MEMORY; 234 235 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ 236 237 sspi_status = s_pSecFn->InitializeSecurityContext( 238 &connssl->cred->cred_handle, NULL, host_name, 239 connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle, 240 &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); 241 242 Curl_unicodefree(host_name); 243 244 if(sspi_status != SEC_I_CONTINUE_NEEDED) { 245 if(sspi_status == SEC_E_WRONG_PRINCIPAL) 246 failf(data, "schannel: SNI or certificate check failed: %s", 247 Curl_sspi_strerror(conn, sspi_status)); 248 else 249 failf(data, "schannel: initial InitializeSecurityContext failed: %s", 250 Curl_sspi_strerror(conn, sspi_status)); 251 Curl_safefree(connssl->ctxt); 252 return CURLE_SSL_CONNECT_ERROR; 253 } 254 255 infof(data, "schannel: sending initial handshake data: " 256 "sending %lu bytes...\n", outbuf.cbBuffer); 257 258 /* send initial handshake data which is now stored in output buffer */ 259 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, 260 outbuf.cbBuffer, &written); 261 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); 262 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { 263 failf(data, "schannel: failed to send initial handshake data: " 264 "sent %zd of %lu bytes", written, outbuf.cbBuffer); 265 return CURLE_SSL_CONNECT_ERROR; 266 } 267 268 infof(data, "schannel: sent initial handshake data: " 269 "sent %zd bytes\n", written); 270 271 connssl->recv_unrecoverable_err = CURLE_OK; 272 connssl->recv_sspi_close_notify = false; 273 connssl->recv_connection_closed = false; 274 275 /* continue to second handshake step */ 276 connssl->connecting_state = ssl_connect_2; 277 278 return CURLE_OK; 279 } 280 281 static CURLcode 282 schannel_connect_step2(struct connectdata *conn, int sockindex) 283 { 284 int i; 285 ssize_t nread = -1, written = -1; 286 struct SessionHandle *data = conn->data; 287 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 288 unsigned char *reallocated_buffer; 289 size_t reallocated_length; 290 SecBuffer outbuf[3]; 291 SecBufferDesc outbuf_desc; 292 SecBuffer inbuf[2]; 293 SecBufferDesc inbuf_desc; 294 SECURITY_STATUS sspi_status = SEC_E_OK; 295 TCHAR *host_name; 296 CURLcode result; 297 bool doread; 298 299 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; 300 301 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", 302 conn->host.name, conn->remote_port); 303 304 if(!connssl->cred || !connssl->ctxt) 305 return CURLE_SSL_CONNECT_ERROR; 306 307 /* buffer to store previously received and decrypted data */ 308 if(connssl->decdata_buffer == NULL) { 309 connssl->decdata_offset = 0; 310 connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; 311 connssl->decdata_buffer = malloc(connssl->decdata_length); 312 if(connssl->decdata_buffer == NULL) { 313 failf(data, "schannel: unable to allocate memory"); 314 return CURLE_OUT_OF_MEMORY; 315 } 316 } 317 318 /* buffer to store previously received and encrypted data */ 319 if(connssl->encdata_buffer == NULL) { 320 connssl->encdata_offset = 0; 321 connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; 322 connssl->encdata_buffer = malloc(connssl->encdata_length); 323 if(connssl->encdata_buffer == NULL) { 324 failf(data, "schannel: unable to allocate memory"); 325 return CURLE_OUT_OF_MEMORY; 326 } 327 } 328 329 /* if we need a bigger buffer to read a full message, increase buffer now */ 330 if(connssl->encdata_length - connssl->encdata_offset < 331 CURL_SCHANNEL_BUFFER_FREE_SIZE) { 332 /* increase internal encrypted data buffer */ 333 reallocated_length = connssl->encdata_offset + 334 CURL_SCHANNEL_BUFFER_FREE_SIZE; 335 reallocated_buffer = realloc(connssl->encdata_buffer, 336 reallocated_length); 337 338 if(reallocated_buffer == NULL) { 339 failf(data, "schannel: unable to re-allocate memory"); 340 return CURLE_OUT_OF_MEMORY; 341 } 342 else { 343 connssl->encdata_buffer = reallocated_buffer; 344 connssl->encdata_length = reallocated_length; 345 } 346 } 347 348 for(;;) { 349 if(doread) { 350 /* read encrypted handshake data from socket */ 351 result = Curl_read_plain(conn->sock[sockindex], 352 (char *) (connssl->encdata_buffer + 353 connssl->encdata_offset), 354 connssl->encdata_length - 355 connssl->encdata_offset, 356 &nread); 357 if(result == CURLE_AGAIN) { 358 if(connssl->connecting_state != ssl_connect_2_writing) 359 connssl->connecting_state = ssl_connect_2_reading; 360 infof(data, "schannel: failed to receive handshake, " 361 "need more data\n"); 362 return CURLE_OK; 363 } 364 else if((result != CURLE_OK) || (nread == 0)) { 365 failf(data, "schannel: failed to receive handshake, " 366 "SSL/TLS connection failed"); 367 return CURLE_SSL_CONNECT_ERROR; 368 } 369 370 /* increase encrypted data buffer offset */ 371 connssl->encdata_offset += nread; 372 } 373 374 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", 375 connssl->encdata_offset, connssl->encdata_length); 376 377 /* setup input buffers */ 378 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset), 379 curlx_uztoul(connssl->encdata_offset)); 380 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); 381 InitSecBufferDesc(&inbuf_desc, inbuf, 2); 382 383 /* setup output buffers */ 384 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); 385 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); 386 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); 387 InitSecBufferDesc(&outbuf_desc, outbuf, 3); 388 389 if(inbuf[0].pvBuffer == NULL) { 390 failf(data, "schannel: unable to allocate memory"); 391 return CURLE_OUT_OF_MEMORY; 392 } 393 394 /* copy received handshake data into input buffer */ 395 memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, 396 connssl->encdata_offset); 397 398 host_name = Curl_convert_UTF8_to_tchar(conn->host.name); 399 if(!host_name) 400 return CURLE_OUT_OF_MEMORY; 401 402 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ 403 404 sspi_status = s_pSecFn->InitializeSecurityContext( 405 &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle, 406 host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL, 407 &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); 408 409 Curl_unicodefree(host_name); 410 411 /* free buffer for received handshake data */ 412 Curl_safefree(inbuf[0].pvBuffer); 413 414 /* check if the handshake was incomplete */ 415 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { 416 connssl->connecting_state = ssl_connect_2_reading; 417 infof(data, "schannel: received incomplete message, need more data\n"); 418 return CURLE_OK; 419 } 420 421 /* If the server has requested a client certificate, attempt to continue 422 the handshake without one. This will allow connections to servers which 423 request a client certificate but do not require it. */ 424 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && 425 !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { 426 connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; 427 connssl->connecting_state = ssl_connect_2_writing; 428 infof(data, "schannel: a client certificate has been requested\n"); 429 return CURLE_OK; 430 } 431 432 /* check if the handshake needs to be continued */ 433 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { 434 for(i = 0; i < 3; i++) { 435 /* search for handshake tokens that need to be send */ 436 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { 437 infof(data, "schannel: sending next handshake data: " 438 "sending %lu bytes...\n", outbuf[i].cbBuffer); 439 440 /* send handshake token to server */ 441 result = Curl_write_plain(conn, conn->sock[sockindex], 442 outbuf[i].pvBuffer, outbuf[i].cbBuffer, 443 &written); 444 if((result != CURLE_OK) || 445 (outbuf[i].cbBuffer != (size_t) written)) { 446 failf(data, "schannel: failed to send next handshake data: " 447 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); 448 return CURLE_SSL_CONNECT_ERROR; 449 } 450 } 451 452 /* free obsolete buffer */ 453 if(outbuf[i].pvBuffer != NULL) { 454 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); 455 } 456 } 457 } 458 else { 459 if(sspi_status == SEC_E_WRONG_PRINCIPAL) 460 failf(data, "schannel: SNI or certificate check failed: %s", 461 Curl_sspi_strerror(conn, sspi_status)); 462 else 463 failf(data, "schannel: next InitializeSecurityContext failed: %s", 464 Curl_sspi_strerror(conn, sspi_status)); 465 return CURLE_SSL_CONNECT_ERROR; 466 } 467 468 /* check if there was additional remaining encrypted data */ 469 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { 470 infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer); 471 /* 472 There are two cases where we could be getting extra data here: 473 1) If we're renegotiating a connection and the handshake is already 474 complete (from the server perspective), it can encrypted app data 475 (not handshake data) in an extra buffer at this point. 476 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a 477 connection and this extra data is part of the handshake. 478 We should process the data immediately; waiting for the socket to 479 be ready may fail since the server is done sending handshake data. 480 */ 481 /* check if the remaining data is less than the total amount 482 and therefore begins after the already processed data */ 483 if(connssl->encdata_offset > inbuf[1].cbBuffer) { 484 memmove(connssl->encdata_buffer, 485 (connssl->encdata_buffer + connssl->encdata_offset) - 486 inbuf[1].cbBuffer, inbuf[1].cbBuffer); 487 connssl->encdata_offset = inbuf[1].cbBuffer; 488 if(sspi_status == SEC_I_CONTINUE_NEEDED) { 489 doread = FALSE; 490 continue; 491 } 492 } 493 } 494 else { 495 connssl->encdata_offset = 0; 496 } 497 break; 498 } 499 500 /* check if the handshake needs to be continued */ 501 if(sspi_status == SEC_I_CONTINUE_NEEDED) { 502 connssl->connecting_state = ssl_connect_2_reading; 503 return CURLE_OK; 504 } 505 506 /* check if the handshake is complete */ 507 if(sspi_status == SEC_E_OK) { 508 connssl->connecting_state = ssl_connect_3; 509 infof(data, "schannel: SSL/TLS handshake complete\n"); 510 } 511 512 #ifdef _WIN32_WCE 513 /* Windows CE doesn't do any server certificate validation. 514 We have to do it manually. */ 515 if(data->set.ssl.verifypeer) 516 return verify_certificate(conn, sockindex); 517 #endif 518 519 return CURLE_OK; 520 } 521 522 static CURLcode 523 schannel_connect_step3(struct connectdata *conn, int sockindex) 524 { 525 CURLcode result = CURLE_OK; 526 struct SessionHandle *data = conn->data; 527 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 528 struct curl_schannel_cred *old_cred = NULL; 529 bool incache; 530 531 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); 532 533 infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", 534 conn->host.name, conn->remote_port); 535 536 if(!connssl->cred) 537 return CURLE_SSL_CONNECT_ERROR; 538 539 /* check if the required context attributes are met */ 540 if(connssl->ret_flags != connssl->req_flags) { 541 if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT)) 542 failf(data, "schannel: failed to setup sequence detection"); 543 if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT)) 544 failf(data, "schannel: failed to setup replay detection"); 545 if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY)) 546 failf(data, "schannel: failed to setup confidentiality"); 547 if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY)) 548 failf(data, "schannel: failed to setup memory allocation"); 549 if(!(connssl->ret_flags & ISC_RET_STREAM)) 550 failf(data, "schannel: failed to setup stream orientation"); 551 return CURLE_SSL_CONNECT_ERROR; 552 } 553 554 /* increment the reference counter of the credential/session handle */ 555 if(connssl->cred && connssl->ctxt) { 556 connssl->cred->refcount++; 557 infof(data, "schannel: incremented credential handle refcount = %d\n", 558 connssl->cred->refcount); 559 } 560 561 /* save the current session data for possible re-use */ 562 incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); 563 if(incache) { 564 if(old_cred != connssl->cred) { 565 infof(data, "schannel: old credential handle is stale, removing\n"); 566 Curl_ssl_delsessionid(conn, (void *)old_cred); 567 incache = FALSE; 568 } 569 } 570 571 if(!incache) { 572 result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, 573 sizeof(struct curl_schannel_cred)); 574 if(result) { 575 failf(data, "schannel: failed to store credential handle"); 576 return result; 577 } 578 else { 579 connssl->cred->cached = TRUE; 580 infof(data, "schannel: stored credential handle in session cache\n"); 581 } 582 } 583 584 connssl->connecting_state = ssl_connect_done; 585 586 return CURLE_OK; 587 } 588 589 static CURLcode 590 schannel_connect_common(struct connectdata *conn, int sockindex, 591 bool nonblocking, bool *done) 592 { 593 CURLcode result; 594 struct SessionHandle *data = conn->data; 595 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 596 curl_socket_t sockfd = conn->sock[sockindex]; 597 long timeout_ms; 598 int what; 599 600 /* check if the connection has already been established */ 601 if(ssl_connection_complete == connssl->state) { 602 *done = TRUE; 603 return CURLE_OK; 604 } 605 606 if(ssl_connect_1 == connssl->connecting_state) { 607 /* check out how much more time we're allowed */ 608 timeout_ms = Curl_timeleft(data, NULL, TRUE); 609 610 if(timeout_ms < 0) { 611 /* no need to continue if time already is up */ 612 failf(data, "SSL/TLS connection timeout"); 613 return CURLE_OPERATION_TIMEDOUT; 614 } 615 616 result = schannel_connect_step1(conn, sockindex); 617 if(result) 618 return result; 619 } 620 621 while(ssl_connect_2 == connssl->connecting_state || 622 ssl_connect_2_reading == connssl->connecting_state || 623 ssl_connect_2_writing == connssl->connecting_state) { 624 625 /* check out how much more time we're allowed */ 626 timeout_ms = Curl_timeleft(data, NULL, TRUE); 627 628 if(timeout_ms < 0) { 629 /* no need to continue if time already is up */ 630 failf(data, "SSL/TLS connection timeout"); 631 return CURLE_OPERATION_TIMEDOUT; 632 } 633 634 /* if ssl is expecting something, check if it's available. */ 635 if(connssl->connecting_state == ssl_connect_2_reading 636 || connssl->connecting_state == ssl_connect_2_writing) { 637 638 curl_socket_t writefd = ssl_connect_2_writing == 639 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; 640 curl_socket_t readfd = ssl_connect_2_reading == 641 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; 642 643 what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); 644 if(what < 0) { 645 /* fatal error */ 646 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); 647 return CURLE_SSL_CONNECT_ERROR; 648 } 649 else if(0 == what) { 650 if(nonblocking) { 651 *done = FALSE; 652 return CURLE_OK; 653 } 654 else { 655 /* timeout */ 656 failf(data, "SSL/TLS connection timeout"); 657 return CURLE_OPERATION_TIMEDOUT; 658 } 659 } 660 /* socket is readable or writable */ 661 } 662 663 /* Run transaction, and return to the caller if it failed or if 664 * this connection is part of a multi handle and this loop would 665 * execute again. This permits the owner of a multi handle to 666 * abort a connection attempt before step2 has completed while 667 * ensuring that a client using select() or epoll() will always 668 * have a valid fdset to wait on. 669 */ 670 result = schannel_connect_step2(conn, sockindex); 671 if(result || (nonblocking && 672 (ssl_connect_2 == connssl->connecting_state || 673 ssl_connect_2_reading == connssl->connecting_state || 674 ssl_connect_2_writing == connssl->connecting_state))) 675 return result; 676 677 } /* repeat step2 until all transactions are done. */ 678 679 if(ssl_connect_3 == connssl->connecting_state) { 680 result = schannel_connect_step3(conn, sockindex); 681 if(result) 682 return result; 683 } 684 685 if(ssl_connect_done == connssl->connecting_state) { 686 connssl->state = ssl_connection_complete; 687 conn->recv[sockindex] = schannel_recv; 688 conn->send[sockindex] = schannel_send; 689 *done = TRUE; 690 } 691 else 692 *done = FALSE; 693 694 /* reset our connection state machine */ 695 connssl->connecting_state = ssl_connect_1; 696 697 return CURLE_OK; 698 } 699 700 static ssize_t 701 schannel_send(struct connectdata *conn, int sockindex, 702 const void *buf, size_t len, CURLcode *err) 703 { 704 ssize_t written = -1; 705 size_t data_len = 0; 706 unsigned char *data = NULL; 707 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 708 SecBuffer outbuf[4]; 709 SecBufferDesc outbuf_desc; 710 SECURITY_STATUS sspi_status = SEC_E_OK; 711 CURLcode result; 712 713 /* check if the maximum stream sizes were queried */ 714 if(connssl->stream_sizes.cbMaximumMessage == 0) { 715 sspi_status = s_pSecFn->QueryContextAttributes( 716 &connssl->ctxt->ctxt_handle, 717 SECPKG_ATTR_STREAM_SIZES, 718 &connssl->stream_sizes); 719 if(sspi_status != SEC_E_OK) { 720 *err = CURLE_SEND_ERROR; 721 return -1; 722 } 723 } 724 725 /* check if the buffer is longer than the maximum message length */ 726 if(len > connssl->stream_sizes.cbMaximumMessage) { 727 *err = CURLE_SEND_ERROR; 728 return -1; 729 } 730 731 /* calculate the complete message length and allocate a buffer for it */ 732 data_len = connssl->stream_sizes.cbHeader + len + 733 connssl->stream_sizes.cbTrailer; 734 data = (unsigned char *) malloc(data_len); 735 if(data == NULL) { 736 *err = CURLE_OUT_OF_MEMORY; 737 return -1; 738 } 739 740 /* setup output buffers (header, data, trailer, empty) */ 741 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, 742 data, connssl->stream_sizes.cbHeader); 743 InitSecBuffer(&outbuf[1], SECBUFFER_DATA, 744 data + connssl->stream_sizes.cbHeader, curlx_uztoul(len)); 745 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, 746 data + connssl->stream_sizes.cbHeader + len, 747 connssl->stream_sizes.cbTrailer); 748 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); 749 InitSecBufferDesc(&outbuf_desc, outbuf, 4); 750 751 /* copy data into output buffer */ 752 memcpy(outbuf[1].pvBuffer, buf, len); 753 754 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ 755 sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0, 756 &outbuf_desc, 0); 757 758 /* check if the message was encrypted */ 759 if(sspi_status == SEC_E_OK) { 760 written = 0; 761 762 /* send the encrypted message including header, data and trailer */ 763 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; 764 765 /* 766 It's important to send the full message which includes the header, 767 encrypted payload, and trailer. Until the client receives all the 768 data a coherent message has not been delivered and the client 769 can't read any of it. 770 771 If we wanted to buffer the unwritten encrypted bytes, we would 772 tell the client that all data it has requested to be sent has been 773 sent. The unwritten encrypted bytes would be the first bytes to 774 send on the next invocation. 775 Here's the catch with this - if we tell the client that all the 776 bytes have been sent, will the client call this method again to 777 send the buffered data? Looking at who calls this function, it 778 seems the answer is NO. 779 */ 780 781 /* send entire message or fail */ 782 while(len > (size_t)written) { 783 ssize_t this_write; 784 long timeleft; 785 int what; 786 787 this_write = 0; 788 789 timeleft = Curl_timeleft(conn->data, NULL, FALSE); 790 if(timeleft < 0) { 791 /* we already got the timeout */ 792 failf(conn->data, "schannel: timed out sending data " 793 "(bytes sent: %zd)", written); 794 *err = CURLE_OPERATION_TIMEDOUT; 795 written = -1; 796 break; 797 } 798 799 what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex], 800 timeleft); 801 if(what < 0) { 802 /* fatal error */ 803 failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); 804 *err = CURLE_SEND_ERROR; 805 written = -1; 806 break; 807 } 808 else if(0 == what) { 809 failf(conn->data, "schannel: timed out sending data " 810 "(bytes sent: %zd)", written); 811 *err = CURLE_OPERATION_TIMEDOUT; 812 written = -1; 813 break; 814 } 815 /* socket is writable */ 816 817 result = Curl_write_plain(conn, conn->sock[sockindex], data + written, 818 len - written, &this_write); 819 if(result == CURLE_AGAIN) 820 continue; 821 else if(result != CURLE_OK) { 822 *err = result; 823 written = -1; 824 break; 825 } 826 827 written += this_write; 828 } 829 } 830 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) { 831 *err = CURLE_OUT_OF_MEMORY; 832 } 833 else{ 834 *err = CURLE_SEND_ERROR; 835 } 836 837 Curl_safefree(data); 838 839 if(len == (size_t)written) 840 /* Encrypted message including header, data and trailer entirely sent. 841 The return value is the number of unencrypted bytes that were sent. */ 842 written = outbuf[1].cbBuffer; 843 844 return written; 845 } 846 847 static ssize_t 848 schannel_recv(struct connectdata *conn, int sockindex, 849 char *buf, size_t len, CURLcode *err) 850 { 851 size_t size = 0; 852 ssize_t nread = -1; 853 struct SessionHandle *data = conn->data; 854 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 855 unsigned char *reallocated_buffer; 856 size_t reallocated_length; 857 bool done = FALSE; 858 SecBuffer inbuf[4]; 859 SecBufferDesc inbuf_desc; 860 SECURITY_STATUS sspi_status = SEC_E_OK; 861 /* we want the length of the encrypted buffer to be at least large enough 862 that it can hold all the bytes requested and some TLS record overhead. */ 863 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; 864 865 /**************************************************************************** 866 * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup. 867 * The pattern for return error is set *err, optional infof, goto cleanup. 868 * 869 * Our priority is to always return as much decrypted data to the caller as 870 * possible, even if an error occurs. The state of the decrypted buffer must 871 * always be valid. Transfer of decrypted data to the caller's buffer is 872 * handled in the cleanup. 873 */ 874 875 infof(data, "schannel: client wants to read %zu bytes\n", len); 876 *err = CURLE_OK; 877 878 if(len && len <= connssl->decdata_offset) { 879 infof(data, "schannel: enough decrypted data is already available\n"); 880 goto cleanup; 881 } 882 else if(connssl->recv_unrecoverable_err) { 883 *err = connssl->recv_unrecoverable_err; 884 infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); 885 goto cleanup; 886 } 887 else if(connssl->recv_sspi_close_notify) { 888 /* once a server has indicated shutdown there is no more encrypted data */ 889 infof(data, "schannel: server indicated shutdown in a prior call\n"); 890 goto cleanup; 891 } 892 else if(!len) { 893 /* It's debatable what to return when !len. Regardless we can't return 894 immediately because there may be data to decrypt (in the case we want to 895 decrypt all encrypted cached data) so handle !len later in cleanup. 896 */ 897 ; /* do nothing */ 898 } 899 else if(!connssl->recv_connection_closed) { 900 /* increase enc buffer in order to fit the requested amount of data */ 901 size = connssl->encdata_length - connssl->encdata_offset; 902 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || 903 connssl->encdata_length < min_encdata_length) { 904 reallocated_length = connssl->encdata_offset + 905 CURL_SCHANNEL_BUFFER_FREE_SIZE; 906 if(reallocated_length < min_encdata_length) { 907 reallocated_length = min_encdata_length; 908 } 909 reallocated_buffer = realloc(connssl->encdata_buffer, 910 reallocated_length); 911 if(reallocated_buffer == NULL) { 912 *err = CURLE_OUT_OF_MEMORY; 913 failf(data, "schannel: unable to re-allocate memory"); 914 goto cleanup; 915 } 916 917 connssl->encdata_buffer = reallocated_buffer; 918 connssl->encdata_length = reallocated_length; 919 size = connssl->encdata_length - connssl->encdata_offset; 920 infof(data, "schannel: encdata_buffer resized %zu\n", 921 connssl->encdata_length); 922 } 923 924 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", 925 connssl->encdata_offset, connssl->encdata_length); 926 927 /* read encrypted data from socket */ 928 *err = Curl_read_plain(conn->sock[sockindex], 929 (char *)(connssl->encdata_buffer + 930 connssl->encdata_offset), 931 size, &nread); 932 if(*err) { 933 nread = -1; 934 if(*err == CURLE_AGAIN) 935 infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n"); 936 else if(*err == CURLE_RECV_ERROR) 937 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); 938 else 939 infof(data, "schannel: Curl_read_plain returned error %d\n", *err); 940 } 941 else if(nread == 0) { 942 connssl->recv_connection_closed = true; 943 infof(data, "schannel: server closed the connection\n"); 944 } 945 else if(nread > 0) { 946 connssl->encdata_offset += (size_t)nread; 947 infof(data, "schannel: encrypted data got %zd\n", nread); 948 } 949 } 950 951 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", 952 connssl->encdata_offset, connssl->encdata_length); 953 954 /* decrypt loop */ 955 while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK && 956 (!len || connssl->decdata_offset < len || 957 connssl->recv_connection_closed)) { 958 /* prepare data buffer for DecryptMessage call */ 959 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer, 960 curlx_uztoul(connssl->encdata_offset)); 961 962 /* we need 3 more empty input buffers for possible output */ 963 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); 964 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); 965 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); 966 InitSecBufferDesc(&inbuf_desc, inbuf, 4); 967 968 /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ 969 sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle, 970 &inbuf_desc, 0, NULL); 971 972 /* check if everything went fine (server may want to renegotiate 973 or shutdown the connection context) */ 974 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || 975 sspi_status == SEC_I_CONTEXT_EXPIRED) { 976 /* check for successfully decrypted data, even before actual 977 renegotiation or shutdown of the connection context */ 978 if(inbuf[1].BufferType == SECBUFFER_DATA) { 979 infof(data, "schannel: decrypted data length: %lu\n", 980 inbuf[1].cbBuffer); 981 982 /* increase buffer in order to fit the received amount of data */ 983 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? 984 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; 985 if(connssl->decdata_length - connssl->decdata_offset < size || 986 connssl->decdata_length < len) { 987 /* increase internal decrypted data buffer */ 988 reallocated_length = connssl->decdata_offset + size; 989 /* make sure that the requested amount of data fits */ 990 if(reallocated_length < len) { 991 reallocated_length = len; 992 } 993 reallocated_buffer = realloc(connssl->decdata_buffer, 994 reallocated_length); 995 if(reallocated_buffer == NULL) { 996 *err = CURLE_OUT_OF_MEMORY; 997 failf(data, "schannel: unable to re-allocate memory"); 998 goto cleanup; 999 } 1000 connssl->decdata_buffer = reallocated_buffer; 1001 connssl->decdata_length = reallocated_length; 1002 } 1003 1004 /* copy decrypted data to internal buffer */ 1005 size = inbuf[1].cbBuffer; 1006 if(size) { 1007 memcpy(connssl->decdata_buffer + connssl->decdata_offset, 1008 inbuf[1].pvBuffer, size); 1009 connssl->decdata_offset += size; 1010 } 1011 1012 infof(data, "schannel: decrypted data added: %zu\n", size); 1013 infof(data, "schannel: decrypted data cached: offset %zu length %zu\n", 1014 connssl->decdata_offset, connssl->decdata_length); 1015 } 1016 1017 /* check for remaining encrypted data */ 1018 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { 1019 infof(data, "schannel: encrypted data length: %lu\n", 1020 inbuf[3].cbBuffer); 1021 1022 /* check if the remaining data is less than the total amount 1023 * and therefore begins after the already processed data 1024 */ 1025 if(connssl->encdata_offset > inbuf[3].cbBuffer) { 1026 /* move remaining encrypted data forward to the beginning of 1027 buffer */ 1028 memmove(connssl->encdata_buffer, 1029 (connssl->encdata_buffer + connssl->encdata_offset) - 1030 inbuf[3].cbBuffer, inbuf[3].cbBuffer); 1031 connssl->encdata_offset = inbuf[3].cbBuffer; 1032 } 1033 1034 infof(data, "schannel: encrypted data cached: offset %zu length %zu\n", 1035 connssl->encdata_offset, connssl->encdata_length); 1036 } 1037 else { 1038 /* reset encrypted buffer offset, because there is no data remaining */ 1039 connssl->encdata_offset = 0; 1040 } 1041 1042 /* check if server wants to renegotiate the connection context */ 1043 if(sspi_status == SEC_I_RENEGOTIATE) { 1044 infof(data, "schannel: remote party requests renegotiation\n"); 1045 if(*err && *err != CURLE_AGAIN) { 1046 infof(data, "schannel: can't renogotiate, an error is pending\n"); 1047 goto cleanup; 1048 } 1049 if(connssl->encdata_offset) { 1050 *err = CURLE_RECV_ERROR; 1051 infof(data, "schannel: can't renogotiate, " 1052 "encrypted data available\n"); 1053 goto cleanup; 1054 } 1055 /* begin renegotiation */ 1056 infof(data, "schannel: renegotiating SSL/TLS connection\n"); 1057 connssl->state = ssl_connection_negotiating; 1058 connssl->connecting_state = ssl_connect_2_writing; 1059 *err = schannel_connect_common(conn, sockindex, FALSE, &done); 1060 if(*err) { 1061 infof(data, "schannel: renegotiation failed\n"); 1062 goto cleanup; 1063 } 1064 /* now retry receiving data */ 1065 sspi_status = SEC_E_OK; 1066 infof(data, "schannel: SSL/TLS connection renegotiated\n"); 1067 continue; 1068 } 1069 /* check if the server closed the connection */ 1070 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { 1071 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not 1072 returned so we have to work around that in cleanup. */ 1073 connssl->recv_sspi_close_notify = true; 1074 if(!connssl->recv_connection_closed) { 1075 connssl->recv_connection_closed = true; 1076 infof(data, "schannel: server closed the connection\n"); 1077 } 1078 goto cleanup; 1079 } 1080 } 1081 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { 1082 if(!*err) 1083 *err = CURLE_AGAIN; 1084 infof(data, "schannel: failed to decrypt data, need more data\n"); 1085 goto cleanup; 1086 } 1087 else { 1088 *err = CURLE_RECV_ERROR; 1089 infof(data, "schannel: failed to read data from server: %s\n", 1090 Curl_sspi_strerror(conn, sspi_status)); 1091 goto cleanup; 1092 } 1093 } 1094 1095 infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", 1096 connssl->encdata_offset, connssl->encdata_length); 1097 1098 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", 1099 connssl->decdata_offset, connssl->decdata_length); 1100 1101 cleanup: 1102 /* Warning- there is no guarantee the encdata state is valid at this point */ 1103 infof(data, "schannel: schannel_recv cleanup\n"); 1104 1105 /* Error if the connection has closed without a close_notify. 1106 Behavior here is a matter of debate. We don't want to be vulnerable to a 1107 truncation attack however there's some browser precedent for ignoring the 1108 close_notify for compatibility reasons. 1109 Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't 1110 return close_notify. In that case if the connection was closed we assume it 1111 was graceful (close_notify) since there doesn't seem to be a way to tell. 1112 */ 1113 if(len && !connssl->decdata_offset && connssl->recv_connection_closed && 1114 !connssl->recv_sspi_close_notify) { 1115 DWORD winver_full, winver_major, winver_minor; 1116 winver_full = GetVersion(); 1117 winver_major = (DWORD)(LOBYTE(LOWORD(winver_full))); 1118 winver_minor = (DWORD)(HIBYTE(LOWORD(winver_full))); 1119 1120 if(winver_major == 5 && winver_minor == 0 && sspi_status == SEC_E_OK) 1121 connssl->recv_sspi_close_notify = true; 1122 else { 1123 *err = CURLE_RECV_ERROR; 1124 infof(data, "schannel: server closed abruptly (missing close_notify)\n"); 1125 } 1126 } 1127 1128 /* Any error other than CURLE_AGAIN is an unrecoverable error. */ 1129 if(*err && *err != CURLE_AGAIN) 1130 connssl->recv_unrecoverable_err = *err; 1131 1132 size = len < connssl->decdata_offset ? len : connssl->decdata_offset; 1133 if(size) { 1134 memcpy(buf, connssl->decdata_buffer, size); 1135 memmove(connssl->decdata_buffer, connssl->decdata_buffer + size, 1136 connssl->decdata_offset - size); 1137 connssl->decdata_offset -= size; 1138 1139 infof(data, "schannel: decrypted data returned %zu\n", size); 1140 infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", 1141 connssl->decdata_offset, connssl->decdata_length); 1142 *err = CURLE_OK; 1143 return (ssize_t)size; 1144 } 1145 1146 if(!*err && !connssl->recv_connection_closed) 1147 *err = CURLE_AGAIN; 1148 1149 /* It's debatable what to return when !len. We could return whatever error we 1150 got from decryption but instead we override here so the return is consistent. 1151 */ 1152 if(!len) 1153 *err = CURLE_OK; 1154 1155 return *err ? -1 : 0; 1156 } 1157 1158 CURLcode 1159 Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex, 1160 bool *done) 1161 { 1162 return schannel_connect_common(conn, sockindex, TRUE, done); 1163 } 1164 1165 CURLcode 1166 Curl_schannel_connect(struct connectdata *conn, int sockindex) 1167 { 1168 CURLcode result; 1169 bool done = FALSE; 1170 1171 result = schannel_connect_common(conn, sockindex, FALSE, &done); 1172 if(result) 1173 return result; 1174 1175 DEBUGASSERT(done); 1176 1177 return CURLE_OK; 1178 } 1179 1180 bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) 1181 { 1182 const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 1183 1184 if(connssl->use) /* SSL/TLS is in use */ 1185 return (connssl->encdata_offset > 0 || 1186 connssl->decdata_offset > 0 ) ? TRUE : FALSE; 1187 else 1188 return FALSE; 1189 } 1190 1191 void Curl_schannel_close(struct connectdata *conn, int sockindex) 1192 { 1193 if(conn->ssl[sockindex].use) 1194 /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ 1195 Curl_ssl_shutdown(conn, sockindex); 1196 } 1197 1198 int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) 1199 { 1200 /* See http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx 1201 * Shutting Down an Schannel Connection 1202 */ 1203 struct SessionHandle *data = conn->data; 1204 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 1205 1206 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", 1207 conn->host.name, conn->remote_port); 1208 1209 if(connssl->cred && connssl->ctxt) { 1210 SecBufferDesc BuffDesc; 1211 SecBuffer Buffer; 1212 SECURITY_STATUS sspi_status; 1213 SecBuffer outbuf; 1214 SecBufferDesc outbuf_desc; 1215 CURLcode result; 1216 TCHAR *host_name; 1217 DWORD dwshut = SCHANNEL_SHUTDOWN; 1218 1219 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); 1220 InitSecBufferDesc(&BuffDesc, &Buffer, 1); 1221 1222 sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle, 1223 &BuffDesc); 1224 1225 if(sspi_status != SEC_E_OK) 1226 failf(data, "schannel: ApplyControlToken failure: %s", 1227 Curl_sspi_strerror(conn, sspi_status)); 1228 1229 host_name = Curl_convert_UTF8_to_tchar(conn->host.name); 1230 if(!host_name) 1231 return CURLE_OUT_OF_MEMORY; 1232 1233 /* setup output buffer */ 1234 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); 1235 InitSecBufferDesc(&outbuf_desc, &outbuf, 1); 1236 1237 sspi_status = s_pSecFn->InitializeSecurityContext( 1238 &connssl->cred->cred_handle, 1239 &connssl->ctxt->ctxt_handle, 1240 host_name, 1241 connssl->req_flags, 1242 0, 1243 0, 1244 NULL, 1245 0, 1246 &connssl->ctxt->ctxt_handle, 1247 &outbuf_desc, 1248 &connssl->ret_flags, 1249 &connssl->ctxt->time_stamp); 1250 1251 Curl_unicodefree(host_name); 1252 1253 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { 1254 /* send close message which is in output buffer */ 1255 ssize_t written; 1256 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, 1257 outbuf.cbBuffer, &written); 1258 1259 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); 1260 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { 1261 infof(data, "schannel: failed to send close msg: %s" 1262 " (bytes written: %zd)\n", curl_easy_strerror(result), written); 1263 } 1264 } 1265 } 1266 1267 /* free SSPI Schannel API security context handle */ 1268 if(connssl->ctxt) { 1269 infof(data, "schannel: clear security context handle\n"); 1270 s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); 1271 Curl_safefree(connssl->ctxt); 1272 } 1273 1274 /* free SSPI Schannel API credential handle */ 1275 if(connssl->cred) { 1276 /* decrement the reference counter of the credential/session handle */ 1277 if(connssl->cred->refcount > 0) { 1278 connssl->cred->refcount--; 1279 infof(data, "schannel: decremented credential handle refcount = %d\n", 1280 connssl->cred->refcount); 1281 } 1282 1283 /* if the handle was not cached and the refcount is zero */ 1284 if(!connssl->cred->cached && connssl->cred->refcount == 0) { 1285 infof(data, "schannel: clear credential handle\n"); 1286 s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); 1287 Curl_safefree(connssl->cred); 1288 } 1289 } 1290 1291 /* free internal buffer for received encrypted data */ 1292 if(connssl->encdata_buffer != NULL) { 1293 Curl_safefree(connssl->encdata_buffer); 1294 connssl->encdata_length = 0; 1295 connssl->encdata_offset = 0; 1296 } 1297 1298 /* free internal buffer for received decrypted data */ 1299 if(connssl->decdata_buffer != NULL) { 1300 Curl_safefree(connssl->decdata_buffer); 1301 connssl->decdata_length = 0; 1302 connssl->decdata_offset = 0; 1303 } 1304 1305 return CURLE_OK; 1306 } 1307 1308 void Curl_schannel_session_free(void *ptr) 1309 { 1310 struct curl_schannel_cred *cred = ptr; 1311 1312 if(cred && cred->cached) { 1313 if(cred->refcount == 0) { 1314 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); 1315 Curl_safefree(cred); 1316 } 1317 else { 1318 cred->cached = FALSE; 1319 } 1320 } 1321 } 1322 1323 int Curl_schannel_init(void) 1324 { 1325 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); 1326 } 1327 1328 void Curl_schannel_cleanup(void) 1329 { 1330 Curl_sspi_global_cleanup(); 1331 } 1332 1333 size_t Curl_schannel_version(char *buffer, size_t size) 1334 { 1335 size = snprintf(buffer, size, "WinSSL"); 1336 1337 return size; 1338 } 1339 1340 int Curl_schannel_random(unsigned char *entropy, size_t length) 1341 { 1342 HCRYPTPROV hCryptProv = 0; 1343 1344 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 1345 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) 1346 return 1; 1347 1348 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { 1349 CryptReleaseContext(hCryptProv, 0UL); 1350 return 1; 1351 } 1352 1353 CryptReleaseContext(hCryptProv, 0UL); 1354 return 0; 1355 } 1356 1357 #ifdef _WIN32_WCE 1358 static CURLcode verify_certificate(struct connectdata *conn, int sockindex) 1359 { 1360 SECURITY_STATUS status; 1361 struct SessionHandle *data = conn->data; 1362 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 1363 CURLcode result = CURLE_OK; 1364 CERT_CONTEXT *pCertContextServer = NULL; 1365 const CERT_CHAIN_CONTEXT *pChainContext = NULL; 1366 1367 status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, 1368 SECPKG_ATTR_REMOTE_CERT_CONTEXT, 1369 &pCertContextServer); 1370 1371 if((status != SEC_E_OK) || (pCertContextServer == NULL)) { 1372 failf(data, "schannel: Failed to read remote certificate context: %s", 1373 Curl_sspi_strerror(conn, status)); 1374 result = CURLE_PEER_FAILED_VERIFICATION; 1375 } 1376 1377 if(result == CURLE_OK) { 1378 CERT_CHAIN_PARA ChainPara; 1379 memset(&ChainPara, 0, sizeof(ChainPara)); 1380 ChainPara.cbSize = sizeof(ChainPara); 1381 1382 if(!CertGetCertificateChain(NULL, 1383 pCertContextServer, 1384 NULL, 1385 pCertContextServer->hCertStore, 1386 &ChainPara, 1387 0, 1388 NULL, 1389 &pChainContext)) { 1390 failf(data, "schannel: CertGetCertificateChain failed: %s", 1391 Curl_sspi_strerror(conn, GetLastError())); 1392 pChainContext = NULL; 1393 result = CURLE_PEER_FAILED_VERIFICATION; 1394 } 1395 1396 if(result == CURLE_OK) { 1397 CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; 1398 DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED| 1399 CERT_TRUST_REVOCATION_STATUS_UNKNOWN); 1400 dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; 1401 if(dwTrustErrorMask) { 1402 if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) 1403 failf(data, "schannel: CertGetCertificateChain trust error" 1404 " CERT_TRUST_IS_PARTIAL_CHAIN"); 1405 if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) 1406 failf(data, "schannel: CertGetCertificateChain trust error" 1407 " CERT_TRUST_IS_UNTRUSTED_ROOT"); 1408 if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) 1409 failf(data, "schannel: CertGetCertificateChain trust error" 1410 " CERT_TRUST_IS_NOT_TIME_VALID"); 1411 failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", 1412 dwTrustErrorMask); 1413 result = CURLE_PEER_FAILED_VERIFICATION; 1414 } 1415 } 1416 } 1417 1418 if(result == CURLE_OK) { 1419 if(data->set.ssl.verifyhost) { 1420 TCHAR cert_hostname_buff[128]; 1421 xcharp_u hostname; 1422 xcharp_u cert_hostname; 1423 DWORD len; 1424 1425 cert_hostname.const_tchar_ptr = cert_hostname_buff; 1426 hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name); 1427 1428 len = CertGetNameString(pCertContextServer, 1429 CERT_NAME_DNS_TYPE, 1430 0, 1431 NULL, 1432 cert_hostname.tchar_ptr, 1433 128); 1434 if(len > 0 && *cert_hostname.tchar_ptr == '*') { 1435 /* this is a wildcard cert. try matching the last len - 1 chars */ 1436 int hostname_len = strlen(conn->host.name); 1437 cert_hostname.tchar_ptr++; 1438 if(_tcsicmp(cert_hostname.const_tchar_ptr, 1439 hostname.const_tchar_ptr + hostname_len - len + 2) != 0) 1440 result = CURLE_PEER_FAILED_VERIFICATION; 1441 } 1442 else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr, 1443 cert_hostname.const_tchar_ptr) != 0) { 1444 result = CURLE_PEER_FAILED_VERIFICATION; 1445 } 1446 if(result == CURLE_PEER_FAILED_VERIFICATION) { 1447 char *_cert_hostname; 1448 _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr); 1449 failf(data, "schannel: CertGetNameString() certificate hostname " 1450 "(%s) did not match connection (%s)", 1451 _cert_hostname, conn->host.name); 1452 Curl_unicodefree(_cert_hostname); 1453 } 1454 Curl_unicodefree(hostname.tchar_ptr); 1455 } 1456 } 1457 1458 if(pChainContext) 1459 CertFreeCertificateChain(pChainContext); 1460 1461 if(pCertContextServer) 1462 CertFreeCertificateContext(pCertContextServer); 1463 1464 return result; 1465 } 1466 #endif /* _WIN32_WCE */ 1467 1468 #endif /* USE_SCHANNEL */ 1469