1 /* 2 * Wininet - networking layer 3 * 4 * Copyright 2002 TransGaming Technologies Inc. 5 * Copyright 2013 Jacek Caban for CodeWeavers 6 * 7 * David Hammerton 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 #define NONAMELESSUNION 25 26 #include "ws2tcpip.h" 27 28 #include <time.h> 29 #include <stdarg.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdio.h> 33 #include <assert.h> 34 35 #include "wine/library.h" 36 #include "windef.h" 37 #include "winbase.h" 38 #include "wininet.h" 39 #include "winerror.h" 40 41 #include "wine/debug.h" 42 #include "internet.h" 43 44 WINE_DEFAULT_DEBUG_CHANNEL(wininet); 45 46 static DWORD netconn_verify_cert(netconn_t *conn, PCCERT_CONTEXT cert, HCERTSTORE store) 47 { 48 BOOL ret; 49 CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; 50 PCCERT_CHAIN_CONTEXT chain; 51 char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; 52 char *server_auth[] = { oid_server_auth }; 53 DWORD err = ERROR_SUCCESS, errors; 54 55 static const DWORD supportedErrors = 56 CERT_TRUST_IS_NOT_TIME_VALID | 57 CERT_TRUST_IS_UNTRUSTED_ROOT | 58 CERT_TRUST_IS_PARTIAL_CHAIN | 59 CERT_TRUST_IS_NOT_SIGNATURE_VALID | 60 CERT_TRUST_IS_NOT_VALID_FOR_USAGE; 61 62 TRACE("verifying %s\n", debugstr_w(conn->server->name)); 63 64 chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; 65 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; 66 if (!(ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0, NULL, &chain))) { 67 TRACE("failed\n"); 68 return GetLastError(); 69 } 70 71 errors = chain->TrustStatus.dwErrorStatus; 72 73 do { 74 /* This seems strange, but that's what tests show */ 75 if(errors & CERT_TRUST_IS_PARTIAL_CHAIN) { 76 WARN("ERROR_INTERNET_SEC_CERT_REV_FAILED\n"); 77 err = ERROR_INTERNET_SEC_CERT_REV_FAILED; 78 if(conn->mask_errors) 79 conn->security_flags |= _SECURITY_FLAG_CERT_REV_FAILED; 80 if(!(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION)) 81 break; 82 } 83 84 if (chain->TrustStatus.dwErrorStatus & ~supportedErrors) { 85 WARN("error status %x\n", chain->TrustStatus.dwErrorStatus & ~supportedErrors); 86 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; 87 errors &= supportedErrors; 88 if(!conn->mask_errors) 89 break; 90 WARN("unknown error flags\n"); 91 } 92 93 if(errors & CERT_TRUST_IS_NOT_TIME_VALID) { 94 WARN("CERT_TRUST_IS_NOT_TIME_VALID\n"); 95 if(!(conn->security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) { 96 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_DATE_INVALID; 97 if(!conn->mask_errors) 98 break; 99 conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_DATE; 100 } 101 errors &= ~CERT_TRUST_IS_NOT_TIME_VALID; 102 } 103 104 if(errors & CERT_TRUST_IS_UNTRUSTED_ROOT) { 105 WARN("CERT_TRUST_IS_UNTRUSTED_ROOT\n"); 106 if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) { 107 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; 108 if(!conn->mask_errors) 109 break; 110 conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CA; 111 } 112 errors &= ~CERT_TRUST_IS_UNTRUSTED_ROOT; 113 } 114 115 if(errors & CERT_TRUST_IS_PARTIAL_CHAIN) { 116 WARN("CERT_TRUST_IS_PARTIAL_CHAIN\n"); 117 if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) { 118 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; 119 if(!conn->mask_errors) 120 break; 121 conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CA; 122 } 123 errors &= ~CERT_TRUST_IS_PARTIAL_CHAIN; 124 } 125 126 if(errors & CERT_TRUST_IS_NOT_SIGNATURE_VALID) { 127 WARN("CERT_TRUST_IS_NOT_SIGNATURE_VALID\n"); 128 if(!(conn->security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) { 129 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_INVALID_CA; 130 if(!conn->mask_errors) 131 break; 132 conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CA; 133 } 134 errors &= ~CERT_TRUST_IS_NOT_SIGNATURE_VALID; 135 } 136 137 if(errors & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { 138 WARN("CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); 139 if(!(conn->security_flags & SECURITY_FLAG_IGNORE_WRONG_USAGE)) { 140 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; 141 if(!conn->mask_errors) 142 break; 143 WARN("CERT_TRUST_IS_NOT_VALID_FOR_USAGE, unknown error flags\n"); 144 } 145 errors &= ~CERT_TRUST_IS_NOT_VALID_FOR_USAGE; 146 } 147 148 if(err == ERROR_INTERNET_SEC_CERT_REV_FAILED) { 149 assert(conn->security_flags & SECURITY_FLAG_IGNORE_REVOCATION); 150 err = ERROR_SUCCESS; 151 } 152 }while(0); 153 154 if(!err || conn->mask_errors) { 155 CERT_CHAIN_POLICY_PARA policyPara; 156 SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; 157 CERT_CHAIN_POLICY_STATUS policyStatus; 158 CERT_CHAIN_CONTEXT chainCopy; 159 160 /* Clear chain->TrustStatus.dwErrorStatus so 161 * CertVerifyCertificateChainPolicy will verify additional checks 162 * rather than stopping with an existing, ignored error. 163 */ 164 memcpy(&chainCopy, chain, sizeof(chainCopy)); 165 chainCopy.TrustStatus.dwErrorStatus = 0; 166 sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); 167 sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; 168 sslExtraPolicyPara.pwszServerName = conn->server->name; 169 sslExtraPolicyPara.fdwChecks = conn->security_flags; 170 policyPara.cbSize = sizeof(policyPara); 171 policyPara.dwFlags = 0; 172 policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; 173 ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, 174 &chainCopy, &policyPara, &policyStatus); 175 /* Any error in the policy status indicates that the 176 * policy couldn't be verified. 177 */ 178 if(ret) { 179 if(policyStatus.dwError == CERT_E_CN_NO_MATCH) { 180 WARN("CERT_E_CN_NO_MATCH\n"); 181 if(conn->mask_errors) 182 conn->security_flags |= _SECURITY_FLAG_CERT_INVALID_CN; 183 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_CERT_CN_INVALID; 184 }else if(policyStatus.dwError) { 185 WARN("policyStatus.dwError %x\n", policyStatus.dwError); 186 if(conn->mask_errors) 187 WARN("unknown error flags for policy status %x\n", policyStatus.dwError); 188 err = conn->mask_errors && err ? ERROR_INTERNET_SEC_CERT_ERRORS : ERROR_INTERNET_SEC_INVALID_CERT; 189 } 190 }else { 191 err = GetLastError(); 192 } 193 } 194 195 if(err) { 196 WARN("failed %u\n", err); 197 CertFreeCertificateChain(chain); 198 if(conn->server->cert_chain) { 199 CertFreeCertificateChain(conn->server->cert_chain); 200 conn->server->cert_chain = NULL; 201 } 202 if(conn->mask_errors) 203 conn->server->security_flags |= conn->security_flags & _SECURITY_ERROR_FLAGS_MASK; 204 return err; 205 } 206 207 /* FIXME: Reuse cached chain */ 208 if(conn->server->cert_chain) 209 CertFreeCertificateChain(chain); 210 else 211 conn->server->cert_chain = chain; 212 return ERROR_SUCCESS; 213 } 214 215 static SecHandle cred_handle, compat_cred_handle; 216 static BOOL cred_handle_initialized, have_compat_cred_handle; 217 218 static CRITICAL_SECTION init_sechandle_cs; 219 static CRITICAL_SECTION_DEBUG init_sechandle_cs_debug = { 220 0, 0, &init_sechandle_cs, 221 { &init_sechandle_cs_debug.ProcessLocksList, 222 &init_sechandle_cs_debug.ProcessLocksList }, 223 0, 0, { (DWORD_PTR)(__FILE__ ": init_sechandle_cs") } 224 }; 225 static CRITICAL_SECTION init_sechandle_cs = { &init_sechandle_cs_debug, -1, 0, 0, 0, 0 }; 226 227 static BOOL ensure_cred_handle(void) 228 { 229 SECURITY_STATUS res = SEC_E_OK; 230 231 EnterCriticalSection(&init_sechandle_cs); 232 233 if(!cred_handle_initialized) { 234 SCHANNEL_CRED cred = {SCHANNEL_CRED_VERSION}; 235 SecPkgCred_SupportedProtocols prots; 236 237 res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, &cred, 238 NULL, NULL, &cred_handle, NULL); 239 if(res == SEC_E_OK) { 240 res = QueryCredentialsAttributesA(&cred_handle, SECPKG_ATTR_SUPPORTED_PROTOCOLS, &prots); 241 if(res != SEC_E_OK || (prots.grbitProtocol & SP_PROT_TLS1_1PLUS_CLIENT)) { 242 cred.grbitEnabledProtocols = prots.grbitProtocol & ~SP_PROT_TLS1_1PLUS_CLIENT; 243 res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, &cred, 244 NULL, NULL, &compat_cred_handle, NULL); 245 have_compat_cred_handle = res == SEC_E_OK; 246 } 247 } 248 249 cred_handle_initialized = res == SEC_E_OK; 250 } 251 252 LeaveCriticalSection(&init_sechandle_cs); 253 254 if(res != SEC_E_OK) { 255 WARN("Failed: %08x\n", res); 256 return FALSE; 257 } 258 259 return TRUE; 260 } 261 262 static BOOL winsock_loaded = FALSE; 263 264 static BOOL WINAPI winsock_startup(INIT_ONCE *once, void *param, void **context) 265 { 266 WSADATA wsa_data; 267 DWORD res; 268 269 res = WSAStartup(MAKEWORD(2,2), &wsa_data); 270 if(res == ERROR_SUCCESS) 271 winsock_loaded = TRUE; 272 else 273 ERR("WSAStartup failed: %u\n", res); 274 return TRUE; 275 } 276 277 void init_winsock(void) 278 { 279 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; 280 InitOnceExecuteOnce(&init_once, winsock_startup, NULL, NULL); 281 } 282 283 static void set_socket_blocking(netconn_t *conn, BOOL is_blocking) 284 { 285 if(conn->is_blocking != is_blocking) { 286 ULONG arg = !is_blocking; 287 ioctlsocket(conn->socket, FIONBIO, &arg); 288 } 289 conn->is_blocking = is_blocking; 290 } 291 292 static DWORD create_netconn_socket(server_t *server, netconn_t *netconn, DWORD timeout) 293 { 294 int result; 295 ULONG flag; 296 DWORD res; 297 298 init_winsock(); 299 300 assert(server->addr_len); 301 result = netconn->socket = socket(server->addr.ss_family, SOCK_STREAM, 0); 302 if(result != -1) { 303 set_socket_blocking(netconn, FALSE); 304 result = connect(netconn->socket, (struct sockaddr*)&server->addr, server->addr_len); 305 if(result == -1) 306 { 307 res = WSAGetLastError(); 308 if (res == WSAEINPROGRESS || res == WSAEWOULDBLOCK) { 309 FD_SET set; 310 int res; 311 socklen_t len = sizeof(res); 312 TIMEVAL timeout_timeval = {0, timeout*1000}; 313 314 FD_ZERO(&set); 315 FD_SET(netconn->socket, &set); 316 res = select(netconn->socket+1, NULL, &set, NULL, &timeout_timeval); 317 if(!res || res == SOCKET_ERROR) { 318 closesocket(netconn->socket); 319 netconn->socket = -1; 320 return ERROR_INTERNET_CANNOT_CONNECT; 321 } 322 if (!getsockopt(netconn->socket, SOL_SOCKET, SO_ERROR, (void *)&res, &len) && !res) 323 result = 0; 324 } 325 } 326 if(result == -1) 327 { 328 closesocket(netconn->socket); 329 netconn->socket = -1; 330 } 331 } 332 if(result == -1) 333 return ERROR_INTERNET_CANNOT_CONNECT; 334 335 flag = 1; 336 result = setsockopt(netconn->socket, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof(flag)); 337 if(result < 0) 338 WARN("setsockopt(TCP_NODELAY) failed\n"); 339 340 return ERROR_SUCCESS; 341 } 342 343 DWORD create_netconn(BOOL useSSL, server_t *server, DWORD security_flags, BOOL mask_errors, DWORD timeout, netconn_t **ret) 344 { 345 netconn_t *netconn; 346 int result; 347 348 netconn = heap_alloc_zero(sizeof(*netconn)); 349 if(!netconn) 350 return ERROR_OUTOFMEMORY; 351 352 netconn->socket = -1; 353 netconn->security_flags = security_flags | server->security_flags; 354 netconn->mask_errors = mask_errors; 355 list_init(&netconn->pool_entry); 356 SecInvalidateHandle(&netconn->ssl_ctx); 357 358 result = create_netconn_socket(server, netconn, timeout); 359 if (result != ERROR_SUCCESS) { 360 heap_free(netconn); 361 return result; 362 } 363 364 server_addref(server); 365 netconn->server = server; 366 *ret = netconn; 367 return result; 368 } 369 370 BOOL is_valid_netconn(netconn_t *netconn) 371 { 372 return netconn && netconn->socket != -1; 373 } 374 375 void close_netconn(netconn_t *netconn) 376 { 377 closesocket(netconn->socket); 378 netconn->socket = -1; 379 } 380 381 void free_netconn(netconn_t *netconn) 382 { 383 server_release(netconn->server); 384 385 if (netconn->secure) { 386 heap_free(netconn->peek_msg_mem); 387 netconn->peek_msg_mem = NULL; 388 netconn->peek_msg = NULL; 389 netconn->peek_len = 0; 390 heap_free(netconn->ssl_buf); 391 netconn->ssl_buf = NULL; 392 heap_free(netconn->extra_buf); 393 netconn->extra_buf = NULL; 394 netconn->extra_len = 0; 395 if (SecIsValidHandle(&netconn->ssl_ctx)) 396 DeleteSecurityContext(&netconn->ssl_ctx); 397 } 398 399 close_netconn(netconn); 400 heap_free(netconn); 401 } 402 403 void NETCON_unload(void) 404 { 405 if(cred_handle_initialized) 406 FreeCredentialsHandle(&cred_handle); 407 if(have_compat_cred_handle) 408 FreeCredentialsHandle(&compat_cred_handle); 409 DeleteCriticalSection(&init_sechandle_cs); 410 if(winsock_loaded) 411 WSACleanup(); 412 } 413 414 int sock_send(int fd, const void *msg, size_t len, int flags) 415 { 416 int ret; 417 do 418 { 419 ret = send(fd, msg, len, flags); 420 } 421 while(ret == -1 && WSAGetLastError() == WSAEINTR); 422 return ret; 423 } 424 425 int sock_recv(int fd, void *msg, size_t len, int flags) 426 { 427 int ret; 428 do 429 { 430 ret = recv(fd, msg, len, flags); 431 } 432 while(ret == -1 && WSAGetLastError() == WSAEINTR); 433 return ret; 434 } 435 436 static DWORD netcon_secure_connect_setup(netconn_t *connection, BOOL compat_mode) 437 { 438 SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; 439 SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; 440 SecHandle *cred = &cred_handle; 441 BYTE *read_buf; 442 SIZE_T read_buf_size = 2048; 443 ULONG attrs = 0; 444 CtxtHandle ctx; 445 SSIZE_T size; 446 int bits; 447 const CERT_CONTEXT *cert; 448 SECURITY_STATUS status; 449 DWORD res = ERROR_SUCCESS; 450 451 const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY 452 |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; 453 454 if(!ensure_cred_handle()) 455 return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; 456 457 if(compat_mode) { 458 if(!have_compat_cred_handle) 459 return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; 460 cred = &compat_cred_handle; 461 } 462 463 read_buf = heap_alloc(read_buf_size); 464 if(!read_buf) 465 return ERROR_OUTOFMEMORY; 466 467 status = InitializeSecurityContextW(cred, NULL, connection->server->name, isc_req_flags, 0, 0, NULL, 0, 468 &ctx, &out_desc, &attrs, NULL); 469 470 assert(status != SEC_E_OK); 471 472 set_socket_blocking(connection, TRUE); 473 474 while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { 475 if(out_buf.cbBuffer) { 476 assert(status == SEC_I_CONTINUE_NEEDED); 477 478 TRACE("sending %u bytes\n", out_buf.cbBuffer); 479 480 size = sock_send(connection->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); 481 if(size != out_buf.cbBuffer) { 482 ERR("send failed\n"); 483 status = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; 484 break; 485 } 486 487 FreeContextBuffer(out_buf.pvBuffer); 488 out_buf.pvBuffer = NULL; 489 out_buf.cbBuffer = 0; 490 } 491 492 if(status == SEC_I_CONTINUE_NEEDED) { 493 assert(in_bufs[1].cbBuffer < read_buf_size); 494 495 memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); 496 in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; 497 498 in_bufs[1].BufferType = SECBUFFER_EMPTY; 499 in_bufs[1].cbBuffer = 0; 500 in_bufs[1].pvBuffer = NULL; 501 } 502 503 assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); 504 assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); 505 506 if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { 507 BYTE *new_read_buf; 508 509 new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); 510 if(!new_read_buf) { 511 status = E_OUTOFMEMORY; 512 break; 513 } 514 515 in_bufs[0].pvBuffer = read_buf = new_read_buf; 516 read_buf_size += 1024; 517 } 518 519 size = sock_recv(connection->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); 520 if(size < 1) { 521 WARN("recv error\n"); 522 res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; 523 break; 524 } 525 526 TRACE("recv %lu bytes\n", size); 527 528 in_bufs[0].cbBuffer += size; 529 in_bufs[0].pvBuffer = read_buf; 530 status = InitializeSecurityContextW(cred, &ctx, connection->server->name, isc_req_flags, 0, 0, &in_desc, 531 0, NULL, &out_desc, &attrs, NULL); 532 TRACE("InitializeSecurityContext ret %08x\n", status); 533 534 if(status == SEC_E_OK) { 535 if(SecIsValidHandle(&connection->ssl_ctx)) 536 DeleteSecurityContext(&connection->ssl_ctx); 537 connection->ssl_ctx = ctx; 538 539 if(in_bufs[1].BufferType == SECBUFFER_EXTRA) 540 FIXME("SECBUFFER_EXTRA not supported\n"); 541 542 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &connection->ssl_sizes); 543 if(status != SEC_E_OK) { 544 WARN("Could not get sizes\n"); 545 break; 546 } 547 548 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); 549 if(status == SEC_E_OK) { 550 res = netconn_verify_cert(connection, cert, cert->hCertStore); 551 CertFreeCertificateContext(cert); 552 if(res != ERROR_SUCCESS) { 553 WARN("cert verify failed: %u\n", res); 554 break; 555 } 556 }else { 557 WARN("Could not get cert\n"); 558 break; 559 } 560 561 connection->ssl_buf = heap_alloc(connection->ssl_sizes.cbHeader + connection->ssl_sizes.cbMaximumMessage 562 + connection->ssl_sizes.cbTrailer); 563 if(!connection->ssl_buf) { 564 res = GetLastError(); 565 break; 566 } 567 } 568 } 569 570 heap_free(read_buf); 571 572 if(status != SEC_E_OK || res != ERROR_SUCCESS) { 573 WARN("Failed to establish SSL connection: %08x (%u)\n", status, res); 574 heap_free(connection->ssl_buf); 575 connection->ssl_buf = NULL; 576 return res ? res : ERROR_INTERNET_SECURITY_CHANNEL_ERROR; 577 } 578 579 TRACE("established SSL connection\n"); 580 connection->secure = TRUE; 581 connection->security_flags |= SECURITY_FLAG_SECURE; 582 583 bits = NETCON_GetCipherStrength(connection); 584 if (bits >= 128) 585 connection->security_flags |= SECURITY_FLAG_STRENGTH_STRONG; 586 else if (bits >= 56) 587 connection->security_flags |= SECURITY_FLAG_STRENGTH_MEDIUM; 588 else 589 connection->security_flags |= SECURITY_FLAG_STRENGTH_WEAK; 590 591 if(connection->mask_errors) 592 connection->server->security_flags = connection->security_flags; 593 return ERROR_SUCCESS; 594 } 595 596 /****************************************************************************** 597 * NETCON_secure_connect 598 * Initiates a secure connection over an existing plaintext connection. 599 */ 600 DWORD NETCON_secure_connect(netconn_t *connection, server_t *server) 601 { 602 DWORD res; 603 604 /* can't connect if we are already connected */ 605 if(connection->secure) { 606 ERR("already connected\n"); 607 return ERROR_INTERNET_CANNOT_CONNECT; 608 } 609 610 if(server != connection->server) { 611 server_release(connection->server); 612 server_addref(server); 613 connection->server = server; 614 } 615 616 /* connect with given TLS options */ 617 res = netcon_secure_connect_setup(connection, FALSE); 618 if (res == ERROR_SUCCESS) 619 return res; 620 621 /* FIXME: when got version alert and FIN from server */ 622 /* fallback to connect without TLSv1.1/TLSv1.2 */ 623 if (res == ERROR_INTERNET_SECURITY_CHANNEL_ERROR && have_compat_cred_handle) 624 { 625 closesocket(connection->socket); 626 res = create_netconn_socket(connection->server, connection, 500); 627 if (res != ERROR_SUCCESS) 628 return res; 629 res = netcon_secure_connect_setup(connection, TRUE); 630 } 631 return res; 632 } 633 634 static BOOL send_ssl_chunk(netconn_t *conn, const void *msg, size_t size) 635 { 636 SecBuffer bufs[4] = { 637 {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf}, 638 {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader}, 639 {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size}, 640 {0, SECBUFFER_EMPTY, NULL} 641 }; 642 SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs}; 643 SECURITY_STATUS res; 644 645 memcpy(bufs[1].pvBuffer, msg, size); 646 res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0); 647 if(res != SEC_E_OK) { 648 WARN("EncryptMessage failed\n"); 649 return FALSE; 650 } 651 652 if(sock_send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) { 653 WARN("send failed\n"); 654 return FALSE; 655 } 656 657 return TRUE; 658 } 659 660 /****************************************************************************** 661 * NETCON_send 662 * Basically calls 'send()' unless we should use SSL 663 * number of chars send is put in *sent 664 */ 665 DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags, 666 int *sent /* out */) 667 { 668 /* send is always blocking. */ 669 set_socket_blocking(connection, TRUE); 670 671 if(!connection->secure) 672 { 673 *sent = sock_send(connection->socket, msg, len, flags); 674 return *sent == -1 ? WSAGetLastError() : ERROR_SUCCESS; 675 } 676 else 677 { 678 const BYTE *ptr = msg; 679 size_t chunk_size; 680 681 *sent = 0; 682 683 while(len) { 684 chunk_size = min(len, connection->ssl_sizes.cbMaximumMessage); 685 if(!send_ssl_chunk(connection, ptr, chunk_size)) 686 return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; 687 688 *sent += chunk_size; 689 ptr += chunk_size; 690 len -= chunk_size; 691 } 692 693 return ERROR_SUCCESS; 694 } 695 } 696 697 static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, BOOL blocking, SIZE_T *ret_size, BOOL *eof) 698 { 699 const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer; 700 SecBuffer bufs[4]; 701 SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs}; 702 SSIZE_T size, buf_len = 0; 703 int i; 704 SECURITY_STATUS res; 705 706 assert(conn->extra_len < ssl_buf_size); 707 708 if(conn->extra_len) { 709 memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len); 710 buf_len = conn->extra_len; 711 conn->extra_len = 0; 712 heap_free(conn->extra_buf); 713 conn->extra_buf = NULL; 714 } 715 716 set_socket_blocking(conn, blocking && !buf_len); 717 size = sock_recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0); 718 if(size < 0) { 719 if(!buf_len) { 720 if(WSAGetLastError() == WSAEWOULDBLOCK) { 721 TRACE("would block\n"); 722 return WSAEWOULDBLOCK; 723 } 724 WARN("recv failed\n"); 725 return ERROR_INTERNET_CONNECTION_ABORTED; 726 } 727 }else { 728 buf_len += size; 729 } 730 731 if(!buf_len) { 732 TRACE("EOF\n"); 733 *eof = TRUE; 734 *ret_size = 0; 735 return ERROR_SUCCESS; 736 } 737 738 *eof = FALSE; 739 740 do { 741 memset(bufs, 0, sizeof(bufs)); 742 bufs[0].BufferType = SECBUFFER_DATA; 743 bufs[0].cbBuffer = buf_len; 744 bufs[0].pvBuffer = conn->ssl_buf; 745 746 res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL); 747 switch(res) { 748 case SEC_E_OK: 749 break; 750 case SEC_I_CONTEXT_EXPIRED: 751 TRACE("context expired\n"); 752 *eof = TRUE; 753 return ERROR_SUCCESS; 754 case SEC_E_INCOMPLETE_MESSAGE: 755 assert(buf_len < ssl_buf_size); 756 757 set_socket_blocking(conn, blocking); 758 size = sock_recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0); 759 if(size < 1) { 760 if(size < 0 && WSAGetLastError() == WSAEWOULDBLOCK) { 761 TRACE("would block\n"); 762 763 /* FIXME: Optimize extra_buf usage. */ 764 conn->extra_buf = heap_alloc(buf_len); 765 if(!conn->extra_buf) 766 return ERROR_NOT_ENOUGH_MEMORY; 767 768 conn->extra_len = buf_len; 769 memcpy(conn->extra_buf, conn->ssl_buf, conn->extra_len); 770 return WSAEWOULDBLOCK; 771 } 772 773 return ERROR_INTERNET_CONNECTION_ABORTED; 774 } 775 776 buf_len += size; 777 continue; 778 default: 779 WARN("failed: %08x\n", res); 780 return ERROR_INTERNET_CONNECTION_ABORTED; 781 } 782 } while(res != SEC_E_OK); 783 784 for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) { 785 if(bufs[i].BufferType == SECBUFFER_DATA) { 786 size = min(buf_size, bufs[i].cbBuffer); 787 memcpy(buf, bufs[i].pvBuffer, size); 788 if(size < bufs[i].cbBuffer) { 789 assert(!conn->peek_len); 790 conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size); 791 if(!conn->peek_msg) 792 return ERROR_NOT_ENOUGH_MEMORY; 793 conn->peek_len = bufs[i].cbBuffer-size; 794 memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len); 795 } 796 797 *ret_size = size; 798 } 799 } 800 801 for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) { 802 if(bufs[i].BufferType == SECBUFFER_EXTRA) { 803 conn->extra_buf = heap_alloc(bufs[i].cbBuffer); 804 if(!conn->extra_buf) 805 return ERROR_NOT_ENOUGH_MEMORY; 806 807 conn->extra_len = bufs[i].cbBuffer; 808 memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len); 809 } 810 } 811 812 return ERROR_SUCCESS; 813 } 814 815 /****************************************************************************** 816 * NETCON_recv 817 * Basically calls 'recv()' unless we should use SSL 818 * number of chars received is put in *recvd 819 */ 820 DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, BOOL blocking, int *recvd) 821 { 822 *recvd = 0; 823 if (!len) 824 return ERROR_SUCCESS; 825 826 if (!connection->secure) 827 { 828 set_socket_blocking(connection, blocking); 829 *recvd = sock_recv(connection->socket, buf, len, 0); 830 return *recvd == -1 ? WSAGetLastError() : ERROR_SUCCESS; 831 } 832 else 833 { 834 SIZE_T size = 0; 835 BOOL eof; 836 DWORD res; 837 838 if(connection->peek_msg) { 839 size = min(len, connection->peek_len); 840 memcpy(buf, connection->peek_msg, size); 841 connection->peek_len -= size; 842 connection->peek_msg += size; 843 844 if(!connection->peek_len) { 845 heap_free(connection->peek_msg_mem); 846 connection->peek_msg_mem = connection->peek_msg = NULL; 847 } 848 849 *recvd = size; 850 return ERROR_SUCCESS; 851 } 852 853 do { 854 res = read_ssl_chunk(connection, (BYTE*)buf, len, blocking, &size, &eof); 855 if(res != ERROR_SUCCESS) { 856 if(res == WSAEWOULDBLOCK) { 857 if(size) 858 res = ERROR_SUCCESS; 859 }else { 860 WARN("read_ssl_chunk failed\n"); 861 } 862 break; 863 } 864 }while(!size && !eof); 865 866 TRACE("received %ld bytes\n", size); 867 *recvd = size; 868 return res; 869 } 870 } 871 872 BOOL NETCON_is_alive(netconn_t *netconn) 873 { 874 int len; 875 char b; 876 877 set_socket_blocking(netconn, FALSE); 878 len = sock_recv(netconn->socket, &b, 1, MSG_PEEK); 879 880 return len == 1 || (len == -1 && WSAGetLastError() == WSAEWOULDBLOCK); 881 } 882 883 LPCVOID NETCON_GetCert(netconn_t *connection) 884 { 885 const CERT_CONTEXT *ret; 886 SECURITY_STATUS res; 887 888 res = QueryContextAttributesW(&connection->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret); 889 return res == SEC_E_OK ? ret : NULL; 890 } 891 892 int NETCON_GetCipherStrength(netconn_t *connection) 893 { 894 SecPkgContext_ConnectionInfo conn_info; 895 SECURITY_STATUS res; 896 897 if (!connection->secure) 898 return 0; 899 900 res = QueryContextAttributesW(&connection->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info); 901 if(res != SEC_E_OK) 902 WARN("QueryContextAttributesW failed: %08x\n", res); 903 return res == SEC_E_OK ? conn_info.dwCipherStrength : 0; 904 } 905 906 DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, DWORD value) 907 { 908 int result; 909 910 result = setsockopt(connection->socket, SOL_SOCKET, 911 send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&value, 912 sizeof(value)); 913 if (result == -1) 914 { 915 WARN("setsockopt failed\n"); 916 return WSAGetLastError(); 917 } 918 return ERROR_SUCCESS; 919 } 920