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