1 /* Copyright (C) 2005 Juan Lang 2 * Copyright 2008 Henri Verbeet 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 * 18 * This file implements the schannel provider, or, the SSL/TLS implementations. 19 */ 20 21 #include "precomp.h" 22 23 #include <wine/config.h> 24 25 WINE_DEFAULT_DEBUG_CHANNEL(schannel); 26 27 #if defined(SONAME_LIBGNUTLS) || defined (HAVE_SECURITY_SECURITY_H) || defined (SONAME_LIBMBEDTLS) 28 29 #define SCHAN_INVALID_HANDLE ~0UL 30 31 enum schan_handle_type 32 { 33 SCHAN_HANDLE_CRED, 34 SCHAN_HANDLE_CTX, 35 SCHAN_HANDLE_FREE 36 }; 37 38 struct schan_handle 39 { 40 void *object; 41 enum schan_handle_type type; 42 }; 43 44 struct schan_context 45 { 46 schan_imp_session session; 47 ULONG req_ctx_attr; 48 const CERT_CONTEXT *cert; 49 }; 50 51 static struct schan_handle *schan_handle_table; 52 static struct schan_handle *schan_free_handles; 53 static SIZE_T schan_handle_table_size; 54 static SIZE_T schan_handle_count; 55 56 /* Protocols enabled, only those may be used for the connection. */ 57 static DWORD config_enabled_protocols; 58 59 /* Protocols disabled by default. They are enabled for using, but disabled when caller asks for default settings. */ 60 static DWORD config_default_disabled_protocols; 61 62 static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type) 63 { 64 struct schan_handle *handle; 65 66 if (schan_free_handles) 67 { 68 DWORD index = schan_free_handles - schan_handle_table; 69 /* Use a free handle */ 70 handle = schan_free_handles; 71 if (handle->type != SCHAN_HANDLE_FREE) 72 { 73 ERR("Handle %d(%p) is in the free list, but has type %#x.\n", index, handle, handle->type); 74 return SCHAN_INVALID_HANDLE; 75 } 76 schan_free_handles = handle->object; 77 handle->object = object; 78 handle->type = type; 79 80 return index; 81 } 82 if (!(schan_handle_count < schan_handle_table_size)) 83 { 84 /* Grow the table */ 85 SIZE_T new_size = schan_handle_table_size + (schan_handle_table_size >> 1); 86 struct schan_handle *new_table = HeapReAlloc(GetProcessHeap(), 0, schan_handle_table, new_size * sizeof(*schan_handle_table)); 87 if (!new_table) 88 { 89 ERR("Failed to grow the handle table\n"); 90 return SCHAN_INVALID_HANDLE; 91 } 92 schan_handle_table = new_table; 93 schan_handle_table_size = new_size; 94 } 95 96 handle = &schan_handle_table[schan_handle_count++]; 97 handle->object = object; 98 handle->type = type; 99 100 return handle - schan_handle_table; 101 } 102 103 static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type) 104 { 105 struct schan_handle *handle; 106 void *object; 107 108 if (handle_idx == SCHAN_INVALID_HANDLE) return NULL; 109 if (handle_idx >= schan_handle_count) return NULL; 110 handle = &schan_handle_table[handle_idx]; 111 if (handle->type != type) 112 { 113 ERR("Handle %ld(%p) is not of type %#x\n", handle_idx, handle, type); 114 return NULL; 115 } 116 117 object = handle->object; 118 handle->object = schan_free_handles; 119 handle->type = SCHAN_HANDLE_FREE; 120 schan_free_handles = handle; 121 122 return object; 123 } 124 125 static void *schan_get_object(ULONG_PTR handle_idx, enum schan_handle_type type) 126 { 127 struct schan_handle *handle; 128 129 if (handle_idx == SCHAN_INVALID_HANDLE) return NULL; 130 if (handle_idx >= schan_handle_count) return NULL; 131 handle = &schan_handle_table[handle_idx]; 132 if (handle->type != type) 133 { 134 ERR("Handle %ld(%p) is not of type %#x\n", handle_idx, handle, type); 135 return NULL; 136 } 137 138 return handle->object; 139 } 140 141 static void read_config(void) 142 { 143 DWORD enabled = 0, default_disabled = 0; 144 HKEY protocols_key, key; 145 WCHAR subkey_name[64]; 146 unsigned i; 147 DWORD res; 148 149 static BOOL config_read = FALSE; 150 151 static const WCHAR protocol_config_key_name[] = { 152 'S','Y','S','T','E','M','\\', 153 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 154 'C','o','n','t','r','o','l','\\', 155 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s','\\', 156 'S','C','H','A','N','N','E','L','\\', 157 'P','r','o','t','o','c','o','l','s',0 }; 158 159 static const WCHAR clientW[] = {'\\','C','l','i','e','n','t',0}; 160 static const WCHAR enabledW[] = {'e','n','a','b','l','e','d',0}; 161 static const WCHAR disabledbydefaultW[] = {'D','i','s','a','b','l','e','d','B','y','D','e','f','a','u','l','t',0}; 162 163 static const struct { 164 WCHAR key_name[20]; 165 DWORD prot_client_flag; 166 BOOL enabled; /* If no config is present, enable the protocol */ 167 BOOL disabled_by_default; /* Disable if caller asks for default protocol set */ 168 } protocol_config_keys[] = { 169 {{'S','S','L',' ','2','.','0',0}, SP_PROT_SSL2_CLIENT, FALSE, TRUE}, /* NOTE: TRUE, TRUE on Windows */ 170 {{'S','S','L',' ','3','.','0',0}, SP_PROT_SSL3_CLIENT, TRUE, FALSE}, 171 {{'T','L','S',' ','1','.','0',0}, SP_PROT_TLS1_0_CLIENT, TRUE, FALSE}, 172 {{'T','L','S',' ','1','.','1',0}, SP_PROT_TLS1_1_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }, 173 {{'T','L','S',' ','1','.','2',0}, SP_PROT_TLS1_2_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ } 174 }; 175 176 /* No need for thread safety */ 177 if(config_read) 178 return; 179 180 res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, protocol_config_key_name, 0, KEY_READ, &protocols_key); 181 if(res == ERROR_SUCCESS) { 182 DWORD type, size, value; 183 184 for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) { 185 strcpyW(subkey_name, protocol_config_keys[i].key_name); 186 strcatW(subkey_name, clientW); 187 res = RegOpenKeyExW(protocols_key, subkey_name, 0, KEY_READ, &key); 188 if(res != ERROR_SUCCESS) { 189 if(protocol_config_keys[i].enabled) 190 enabled |= protocol_config_keys[i].prot_client_flag; 191 if(protocol_config_keys[i].disabled_by_default) 192 default_disabled |= protocol_config_keys[i].prot_client_flag; 193 continue; 194 } 195 196 size = sizeof(value); 197 res = RegQueryValueExW(key, enabledW, NULL, &type, (BYTE*)&value, &size); 198 if(res == ERROR_SUCCESS) { 199 if(type == REG_DWORD && value) 200 enabled |= protocol_config_keys[i].prot_client_flag; 201 }else if(protocol_config_keys[i].enabled) { 202 enabled |= protocol_config_keys[i].prot_client_flag; 203 } 204 205 size = sizeof(value); 206 res = RegQueryValueExW(key, disabledbydefaultW, NULL, &type, (BYTE*)&value, &size); 207 if(res == ERROR_SUCCESS) { 208 if(type != REG_DWORD || value) 209 default_disabled |= protocol_config_keys[i].prot_client_flag; 210 }else if(protocol_config_keys[i].disabled_by_default) { 211 default_disabled |= protocol_config_keys[i].prot_client_flag; 212 } 213 214 RegCloseKey(key); 215 } 216 }else { 217 /* No config, enable all known protocols. */ 218 for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) { 219 if(protocol_config_keys[i].enabled) 220 enabled |= protocol_config_keys[i].prot_client_flag; 221 if(protocol_config_keys[i].disabled_by_default) 222 default_disabled |= protocol_config_keys[i].prot_client_flag; 223 } 224 } 225 226 RegCloseKey(protocols_key); 227 228 config_enabled_protocols = enabled & schan_imp_enabled_protocols(); 229 config_default_disabled_protocols = default_disabled; 230 config_read = TRUE; 231 232 TRACE("enabled %x, disabled by default %x\n", config_enabled_protocols, config_default_disabled_protocols); 233 } 234 235 static SECURITY_STATUS schan_QueryCredentialsAttributes( 236 PCredHandle phCredential, ULONG ulAttribute, VOID *pBuffer) 237 { 238 struct schan_credentials *cred; 239 SECURITY_STATUS ret; 240 241 cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED); 242 if(!cred) 243 return SEC_E_INVALID_HANDLE; 244 245 switch (ulAttribute) 246 { 247 case SECPKG_ATTR_SUPPORTED_ALGS: 248 if (pBuffer) 249 { 250 /* FIXME: get from CryptoAPI */ 251 FIXME("SECPKG_ATTR_SUPPORTED_ALGS: stub\n"); 252 ret = SEC_E_UNSUPPORTED_FUNCTION; 253 } 254 else 255 ret = SEC_E_INTERNAL_ERROR; 256 break; 257 case SECPKG_ATTR_CIPHER_STRENGTHS: 258 if (pBuffer) 259 { 260 SecPkgCred_CipherStrengths *r = pBuffer; 261 262 /* FIXME: get from CryptoAPI */ 263 FIXME("SECPKG_ATTR_CIPHER_STRENGTHS: semi-stub\n"); 264 r->dwMinimumCipherStrength = 40; 265 r->dwMaximumCipherStrength = 168; 266 ret = SEC_E_OK; 267 } 268 else 269 ret = SEC_E_INTERNAL_ERROR; 270 break; 271 case SECPKG_ATTR_SUPPORTED_PROTOCOLS: 272 if(pBuffer) { 273 /* Regardless of MSDN documentation, tests show that this attribute takes into account 274 * what protocols are enabled for given credential. */ 275 ((SecPkgCred_SupportedProtocols*)pBuffer)->grbitProtocol = cred->enabled_protocols; 276 ret = SEC_E_OK; 277 }else { 278 ret = SEC_E_INTERNAL_ERROR; 279 } 280 break; 281 default: 282 ret = SEC_E_UNSUPPORTED_FUNCTION; 283 } 284 return ret; 285 } 286 287 static SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesA( 288 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) 289 { 290 SECURITY_STATUS ret; 291 292 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); 293 294 switch (ulAttribute) 295 { 296 case SECPKG_CRED_ATTR_NAMES: 297 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); 298 ret = SEC_E_UNSUPPORTED_FUNCTION; 299 break; 300 default: 301 ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute, 302 pBuffer); 303 } 304 return ret; 305 } 306 307 SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesW( 308 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) 309 { 310 SECURITY_STATUS ret; 311 312 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); 313 314 switch (ulAttribute) 315 { 316 case SECPKG_CRED_ATTR_NAMES: 317 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); 318 ret = SEC_E_UNSUPPORTED_FUNCTION; 319 break; 320 default: 321 ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute, 322 pBuffer); 323 } 324 return ret; 325 } 326 327 static SECURITY_STATUS schan_CheckCreds(const SCHANNEL_CRED *schanCred) 328 { 329 SECURITY_STATUS st; 330 DWORD i; 331 332 TRACE("dwVersion = %d\n", schanCred->dwVersion); 333 TRACE("cCreds = %d\n", schanCred->cCreds); 334 TRACE("hRootStore = %p\n", schanCred->hRootStore); 335 TRACE("cMappers = %d\n", schanCred->cMappers); 336 TRACE("cSupportedAlgs = %d:\n", schanCred->cSupportedAlgs); 337 for (i = 0; i < schanCred->cSupportedAlgs; i++) 338 TRACE("%08x\n", schanCred->palgSupportedAlgs[i]); 339 TRACE("grbitEnabledProtocols = %08x\n", schanCred->grbitEnabledProtocols); 340 TRACE("dwMinimumCipherStrength = %d\n", schanCred->dwMinimumCipherStrength); 341 TRACE("dwMaximumCipherStrength = %d\n", schanCred->dwMaximumCipherStrength); 342 TRACE("dwSessionLifespan = %d\n", schanCred->dwSessionLifespan); 343 TRACE("dwFlags = %08x\n", schanCred->dwFlags); 344 TRACE("dwCredFormat = %d\n", schanCred->dwCredFormat); 345 346 switch (schanCred->dwVersion) 347 { 348 case SCH_CRED_V3: 349 case SCHANNEL_CRED_VERSION: 350 break; 351 default: 352 return SEC_E_INTERNAL_ERROR; 353 } 354 355 if (schanCred->cCreds == 0) 356 st = SEC_E_NO_CREDENTIALS; 357 else if (schanCred->cCreds > 1) 358 st = SEC_E_UNKNOWN_CREDENTIALS; 359 else 360 { 361 DWORD keySpec; 362 HCRYPTPROV csp; 363 BOOL ret, freeCSP; 364 365 ret = CryptAcquireCertificatePrivateKey(schanCred->paCred[0], 366 0, /* FIXME: what flags to use? */ NULL, 367 &csp, &keySpec, &freeCSP); 368 if (ret) 369 { 370 st = SEC_E_OK; 371 if (freeCSP) 372 CryptReleaseContext(csp, 0); 373 } 374 else 375 st = SEC_E_UNKNOWN_CREDENTIALS; 376 } 377 return st; 378 } 379 380 static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred, 381 PCredHandle phCredential, PTimeStamp ptsExpiry) 382 { 383 struct schan_credentials *creds; 384 unsigned enabled_protocols; 385 ULONG_PTR handle; 386 SECURITY_STATUS st = SEC_E_OK; 387 388 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry); 389 390 if (schanCred) 391 { 392 st = schan_CheckCreds(schanCred); 393 if (st != SEC_E_OK && st != SEC_E_NO_CREDENTIALS) 394 return st; 395 396 st = SEC_E_OK; 397 } 398 399 read_config(); 400 if(schanCred && schanCred->grbitEnabledProtocols) 401 enabled_protocols = schanCred->grbitEnabledProtocols & config_enabled_protocols; 402 else 403 enabled_protocols = config_enabled_protocols & ~config_default_disabled_protocols; 404 if(!enabled_protocols) { 405 ERR("Could not find matching protocol\n"); 406 return SEC_E_NO_AUTHENTICATING_AUTHORITY; 407 } 408 409 /* For now, the only thing I'm interested in is the direction of the 410 * connection, so just store it. 411 */ 412 creds = HeapAlloc(GetProcessHeap(), 0, sizeof(*creds)); 413 if (!creds) return SEC_E_INSUFFICIENT_MEMORY; 414 415 handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED); 416 if (handle == SCHAN_INVALID_HANDLE) goto fail; 417 418 creds->credential_use = SECPKG_CRED_OUTBOUND; 419 if (!schan_imp_allocate_certificate_credentials(creds)) 420 { 421 schan_free_handle(handle, SCHAN_HANDLE_CRED); 422 goto fail; 423 } 424 425 creds->enabled_protocols = enabled_protocols; 426 phCredential->dwLower = handle; 427 phCredential->dwUpper = 0; 428 429 /* Outbound credentials have no expiry */ 430 if (ptsExpiry) 431 { 432 ptsExpiry->LowPart = 0; 433 ptsExpiry->HighPart = 0; 434 } 435 436 return st; 437 438 fail: 439 HeapFree(GetProcessHeap(), 0, creds); 440 return SEC_E_INTERNAL_ERROR; 441 } 442 443 static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schanCred, 444 PCredHandle phCredential, PTimeStamp ptsExpiry) 445 { 446 SECURITY_STATUS st; 447 448 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry); 449 450 if (!schanCred) return SEC_E_NO_CREDENTIALS; 451 452 st = schan_CheckCreds(schanCred); 453 if (st == SEC_E_OK) 454 { 455 ULONG_PTR handle; 456 struct schan_credentials *creds; 457 458 creds = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*creds)); 459 if (!creds) return SEC_E_INSUFFICIENT_MEMORY; 460 creds->credential_use = SECPKG_CRED_INBOUND; 461 462 handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED); 463 if (handle == SCHAN_INVALID_HANDLE) 464 { 465 HeapFree(GetProcessHeap(), 0, creds); 466 return SEC_E_INTERNAL_ERROR; 467 } 468 469 phCredential->dwLower = handle; 470 phCredential->dwUpper = 0; 471 472 /* FIXME: get expiry from cert */ 473 } 474 return st; 475 } 476 477 static SECURITY_STATUS schan_AcquireCredentialsHandle(ULONG fCredentialUse, 478 const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry) 479 { 480 SECURITY_STATUS ret; 481 482 if (fCredentialUse == SECPKG_CRED_OUTBOUND) 483 ret = schan_AcquireClientCredentials(schanCred, phCredential, 484 ptsExpiry); 485 else 486 ret = schan_AcquireServerCredentials(schanCred, phCredential, 487 ptsExpiry); 488 return ret; 489 } 490 491 SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleA( 492 SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, 493 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, 494 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) 495 { 496 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", 497 debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, 498 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); 499 return schan_AcquireCredentialsHandle(fCredentialUse, 500 pAuthData, phCredential, ptsExpiry); 501 } 502 503 SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleW( 504 SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, 505 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, 506 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) 507 { 508 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", 509 debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, 510 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); 511 return schan_AcquireCredentialsHandle(fCredentialUse, 512 pAuthData, phCredential, ptsExpiry); 513 } 514 515 SECURITY_STATUS SEC_ENTRY schan_FreeCredentialsHandle( 516 PCredHandle phCredential) 517 { 518 struct schan_credentials *creds; 519 520 TRACE("phCredential %p\n", phCredential); 521 522 if (!phCredential) return SEC_E_INVALID_HANDLE; 523 524 creds = schan_free_handle(phCredential->dwLower, SCHAN_HANDLE_CRED); 525 if (!creds) return SEC_E_INVALID_HANDLE; 526 527 if (creds->credential_use == SECPKG_CRED_OUTBOUND) 528 schan_imp_free_certificate_credentials(creds); 529 HeapFree(GetProcessHeap(), 0, creds); 530 531 return SEC_E_OK; 532 } 533 534 static void init_schan_buffers(struct schan_buffers *s, const PSecBufferDesc desc, 535 int (*get_next_buffer)(const struct schan_transport *, struct schan_buffers *)) 536 { 537 s->offset = 0; 538 s->limit = ~0UL; 539 s->desc = desc; 540 s->current_buffer_idx = -1; 541 s->allow_buffer_resize = FALSE; 542 s->get_next_buffer = get_next_buffer; 543 } 544 545 static int schan_find_sec_buffer_idx(const SecBufferDesc *desc, unsigned int start_idx, ULONG buffer_type) 546 { 547 unsigned int i; 548 PSecBuffer buffer; 549 550 for (i = start_idx; i < desc->cBuffers; ++i) 551 { 552 buffer = &desc->pBuffers[i]; 553 if (buffer->BufferType == buffer_type) return i; 554 } 555 556 return -1; 557 } 558 559 static void schan_resize_current_buffer(const struct schan_buffers *s, SIZE_T min_size) 560 { 561 SecBuffer *b = &s->desc->pBuffers[s->current_buffer_idx]; 562 SIZE_T new_size = b->cbBuffer ? b->cbBuffer * 2 : 128; 563 void *new_data; 564 565 if (b->cbBuffer >= min_size || !s->allow_buffer_resize || min_size > UINT_MAX / 2) return; 566 567 while (new_size < min_size) new_size *= 2; 568 569 if (b->pvBuffer) 570 new_data = HeapReAlloc(GetProcessHeap(), 0, b->pvBuffer, new_size); 571 else 572 new_data = HeapAlloc(GetProcessHeap(), 0, new_size); 573 574 if (!new_data) 575 { 576 TRACE("Failed to resize %p from %d to %ld\n", b->pvBuffer, b->cbBuffer, new_size); 577 return; 578 } 579 580 b->cbBuffer = new_size; 581 b->pvBuffer = new_data; 582 } 583 584 char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) 585 { 586 SIZE_T max_count; 587 PSecBuffer buffer; 588 589 if (!s->desc) 590 { 591 TRACE("No desc\n"); 592 return NULL; 593 } 594 595 if (s->current_buffer_idx == -1) 596 { 597 /* Initial buffer */ 598 int buffer_idx = s->get_next_buffer(t, s); 599 if (buffer_idx == -1) 600 { 601 TRACE("No next buffer\n"); 602 return NULL; 603 } 604 s->current_buffer_idx = buffer_idx; 605 } 606 607 buffer = &s->desc->pBuffers[s->current_buffer_idx]; 608 TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n", s->current_buffer_idx, buffer->cbBuffer, buffer->BufferType, buffer->pvBuffer); 609 610 schan_resize_current_buffer(s, s->offset + *count); 611 max_count = buffer->cbBuffer - s->offset; 612 if (s->limit != ~0UL && s->limit < max_count) 613 max_count = s->limit; 614 if (!max_count) 615 { 616 int buffer_idx; 617 618 s->allow_buffer_resize = FALSE; 619 buffer_idx = s->get_next_buffer(t, s); 620 if (buffer_idx == -1) 621 { 622 TRACE("No next buffer\n"); 623 return NULL; 624 } 625 s->current_buffer_idx = buffer_idx; 626 s->offset = 0; 627 return schan_get_buffer(t, s, count); 628 } 629 630 if (*count > max_count) 631 *count = max_count; 632 if (s->limit != ~0UL) 633 s->limit -= *count; 634 635 return (char *)buffer->pvBuffer + s->offset; 636 } 637 638 /* schan_pull 639 * Read data from the transport input buffer. 640 * 641 * t - The session transport object. 642 * buff - The buffer into which to store the read data. Must be at least 643 * *buff_len bytes in length. 644 * buff_len - On input, *buff_len is the desired length to read. On successful 645 * return, *buff_len is the number of bytes actually read. 646 * 647 * Returns: 648 * 0 on success, in which case: 649 * *buff_len == 0 indicates end of file. 650 * *buff_len > 0 indicates that some data was read. May be less than 651 * what was requested, in which case the caller should call again if/ 652 * when they want more. 653 * EAGAIN when no data could be read without blocking 654 * another errno-style error value on failure 655 * 656 */ 657 int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) 658 { 659 char *b; 660 SIZE_T local_len = *buff_len; 661 662 TRACE("Pull %lu bytes\n", local_len); 663 664 *buff_len = 0; 665 666 b = schan_get_buffer(t, &t->in, &local_len); 667 if (!b) 668 return EAGAIN; 669 670 memcpy(buff, b, local_len); 671 t->in.offset += local_len; 672 673 TRACE("Read %lu bytes\n", local_len); 674 675 *buff_len = local_len; 676 return 0; 677 } 678 679 /* schan_push 680 * Write data to the transport output buffer. 681 * 682 * t - The session transport object. 683 * buff - The buffer of data to write. Must be at least *buff_len bytes in length. 684 * buff_len - On input, *buff_len is the desired length to write. On successful 685 * return, *buff_len is the number of bytes actually written. 686 * 687 * Returns: 688 * 0 on success 689 * *buff_len will be > 0 indicating how much data was written. May be less 690 * than what was requested, in which case the caller should call again 691 if/when they want to write more. 692 * EAGAIN when no data could be written without blocking 693 * another errno-style error value on failure 694 * 695 */ 696 int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) 697 { 698 char *b; 699 SIZE_T local_len = *buff_len; 700 701 TRACE("Push %lu bytes\n", local_len); 702 703 *buff_len = 0; 704 705 b = schan_get_buffer(t, &t->out, &local_len); 706 if (!b) 707 return EAGAIN; 708 709 memcpy(b, buff, local_len); 710 t->out.offset += local_len; 711 712 TRACE("Wrote %lu bytes\n", local_len); 713 714 *buff_len = local_len; 715 return 0; 716 } 717 718 schan_imp_session schan_session_for_transport(struct schan_transport* t) 719 { 720 return t->ctx->session; 721 } 722 723 static int schan_init_sec_ctx_get_next_input_buffer(const struct schan_transport *t, struct schan_buffers *s) 724 { 725 if (s->current_buffer_idx != -1) 726 return -1; 727 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN); 728 } 729 730 static int schan_init_sec_ctx_get_next_output_buffer(const struct schan_transport *t, struct schan_buffers *s) 731 { 732 if (s->current_buffer_idx == -1) 733 { 734 int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN); 735 if (t->ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY) 736 { 737 if (idx == -1) 738 { 739 idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_EMPTY); 740 if (idx != -1) s->desc->pBuffers[idx].BufferType = SECBUFFER_TOKEN; 741 } 742 if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer) 743 { 744 s->desc->pBuffers[idx].cbBuffer = 0; 745 s->allow_buffer_resize = TRUE; 746 } 747 } 748 return idx; 749 } 750 751 return -1; 752 } 753 754 static void dump_buffer_desc(SecBufferDesc *desc) 755 { 756 unsigned int i; 757 758 if (!desc) return; 759 TRACE("Buffer desc %p:\n", desc); 760 for (i = 0; i < desc->cBuffers; ++i) 761 { 762 SecBuffer *b = &desc->pBuffers[i]; 763 TRACE("\tbuffer %u: cbBuffer %d, BufferType %#x pvBuffer %p\n", i, b->cbBuffer, b->BufferType, b->pvBuffer); 764 } 765 } 766 767 /*********************************************************************** 768 * InitializeSecurityContextW 769 */ 770 SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( 771 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, 772 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 773 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, 774 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) 775 { 776 struct schan_context *ctx; 777 struct schan_buffers *out_buffers; 778 struct schan_credentials *cred; 779 struct schan_transport transport; 780 SIZE_T expected_size = ~0UL; 781 SECURITY_STATUS ret; 782 783 TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext, 784 debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, 785 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); 786 787 dump_buffer_desc(pInput); 788 dump_buffer_desc(pOutput); 789 790 if (!phContext) 791 { 792 ULONG_PTR handle; 793 794 if (!phCredential) return SEC_E_INVALID_HANDLE; 795 796 cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED); 797 if (!cred) return SEC_E_INVALID_HANDLE; 798 799 if (!(cred->credential_use & SECPKG_CRED_OUTBOUND)) 800 { 801 WARN("Invalid credential use %#x\n", cred->credential_use); 802 return SEC_E_INVALID_HANDLE; 803 } 804 805 ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(*ctx)); 806 if (!ctx) return SEC_E_INSUFFICIENT_MEMORY; 807 808 ctx->cert = NULL; 809 handle = schan_alloc_handle(ctx, SCHAN_HANDLE_CTX); 810 if (handle == SCHAN_INVALID_HANDLE) 811 { 812 HeapFree(GetProcessHeap(), 0, ctx); 813 return SEC_E_INTERNAL_ERROR; 814 } 815 816 if (!schan_imp_create_session(&ctx->session, cred)) 817 { 818 schan_free_handle(handle, SCHAN_HANDLE_CTX); 819 HeapFree(GetProcessHeap(), 0, ctx); 820 return SEC_E_INTERNAL_ERROR; 821 } 822 823 if (pszTargetName) 824 { 825 UINT len = WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, NULL, 0, NULL, NULL ); 826 char *target = HeapAlloc( GetProcessHeap(), 0, len ); 827 828 if (target) 829 { 830 WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL ); 831 schan_imp_set_session_target( ctx->session, target ); 832 HeapFree( GetProcessHeap(), 0, target ); 833 } 834 } 835 phNewContext->dwLower = handle; 836 phNewContext->dwUpper = 0; 837 } 838 else 839 { 840 SIZE_T record_size = 0; 841 unsigned char *ptr; 842 SecBuffer *buffer; 843 int idx; 844 845 if (!pInput) 846 return SEC_E_INCOMPLETE_MESSAGE; 847 848 idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_TOKEN); 849 if (idx == -1) 850 return SEC_E_INCOMPLETE_MESSAGE; 851 852 buffer = &pInput->pBuffers[idx]; 853 ptr = buffer->pvBuffer; 854 expected_size = 0; 855 856 while (buffer->cbBuffer > expected_size + 5) 857 { 858 record_size = 5 + ((ptr[3] << 8) | ptr[4]); 859 860 if (buffer->cbBuffer < expected_size + record_size) 861 break; 862 863 expected_size += record_size; 864 ptr += record_size; 865 } 866 867 if (!expected_size) 868 { 869 TRACE("Expected at least %lu bytes, but buffer only contains %u bytes.\n", 870 max(6, record_size), buffer->cbBuffer); 871 return SEC_E_INCOMPLETE_MESSAGE; 872 } 873 874 TRACE("Using expected_size %lu.\n", expected_size); 875 876 ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX); 877 } 878 879 ctx->req_ctx_attr = fContextReq; 880 881 transport.ctx = ctx; 882 init_schan_buffers(&transport.in, pInput, schan_init_sec_ctx_get_next_input_buffer); 883 transport.in.limit = expected_size; 884 init_schan_buffers(&transport.out, pOutput, schan_init_sec_ctx_get_next_output_buffer); 885 schan_imp_set_session_transport(ctx->session, &transport); 886 887 /* Perform the TLS handshake */ 888 ret = schan_imp_handshake(ctx->session); 889 890 if(transport.in.offset && transport.in.offset != pInput->pBuffers[0].cbBuffer) { 891 if(pInput->cBuffers<2 || pInput->pBuffers[1].BufferType!=SECBUFFER_EMPTY) 892 return SEC_E_INVALID_TOKEN; 893 894 pInput->pBuffers[1].BufferType = SECBUFFER_EXTRA; 895 pInput->pBuffers[1].cbBuffer = pInput->pBuffers[0].cbBuffer-transport.in.offset; 896 } 897 898 out_buffers = &transport.out; 899 if (out_buffers->current_buffer_idx != -1) 900 { 901 SecBuffer *buffer = &out_buffers->desc->pBuffers[out_buffers->current_buffer_idx]; 902 buffer->cbBuffer = out_buffers->offset; 903 } 904 905 *pfContextAttr = 0; 906 if (ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY) 907 *pfContextAttr |= ISC_RET_ALLOCATED_MEMORY; 908 909 return ret; 910 } 911 912 /*********************************************************************** 913 * InitializeSecurityContextA 914 */ 915 SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextA( 916 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, 917 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 918 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, 919 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) 920 { 921 SECURITY_STATUS ret; 922 SEC_WCHAR *target_name = NULL; 923 924 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext, 925 debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, 926 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); 927 928 if (pszTargetName) 929 { 930 INT len = MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, NULL, 0); 931 target_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*target_name)); 932 MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, target_name, len); 933 } 934 935 ret = schan_InitializeSecurityContextW(phCredential, phContext, target_name, 936 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, 937 phNewContext, pOutput, pfContextAttr, ptsExpiry); 938 939 HeapFree(GetProcessHeap(), 0, target_name); 940 941 return ret; 942 } 943 944 static 945 SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( 946 PCtxtHandle context_handle, ULONG attribute, PVOID buffer) 947 { 948 struct schan_context *ctx; 949 950 TRACE("context_handle %p, attribute %#x, buffer %p\n", 951 context_handle, attribute, buffer); 952 953 if (!context_handle) return SEC_E_INVALID_HANDLE; 954 ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX); 955 956 switch(attribute) 957 { 958 case SECPKG_ATTR_STREAM_SIZES: 959 { 960 SecPkgContext_ConnectionInfo info; 961 SECURITY_STATUS status = schan_imp_get_connection_info(ctx->session, &info); 962 if (status == SEC_E_OK) 963 { 964 SecPkgContext_StreamSizes *stream_sizes = buffer; 965 SIZE_T mac_size = info.dwHashStrength; 966 unsigned int block_size = schan_imp_get_session_cipher_block_size(ctx->session); 967 unsigned int message_size = schan_imp_get_max_message_size(ctx->session); 968 969 TRACE("Using %lu mac bytes, message size %u, block size %u\n", 970 mac_size, message_size, block_size); 971 972 /* These are defined by the TLS RFC */ 973 stream_sizes->cbHeader = 5; 974 stream_sizes->cbTrailer = mac_size + 256; /* Max 255 bytes padding + 1 for padding size */ 975 stream_sizes->cbMaximumMessage = message_size; 976 stream_sizes->cbBuffers = 4; 977 stream_sizes->cbBlockSize = block_size; 978 } 979 980 return status; 981 } 982 case SECPKG_ATTR_REMOTE_CERT_CONTEXT: 983 { 984 PCCERT_CONTEXT *cert = buffer; 985 986 if (!ctx->cert) { 987 HCERTSTORE cert_store; 988 SECURITY_STATUS status; 989 990 cert_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); 991 if(!cert_store) 992 return GetLastError(); 993 994 status = schan_imp_get_session_peer_certificate(ctx->session, cert_store, &ctx->cert); 995 CertCloseStore(cert_store, 0); 996 if(status != SEC_E_OK) 997 return status; 998 } 999 1000 *cert = CertDuplicateCertificateContext(ctx->cert); 1001 return SEC_E_OK; 1002 } 1003 case SECPKG_ATTR_CONNECTION_INFO: 1004 { 1005 SecPkgContext_ConnectionInfo *info = buffer; 1006 return schan_imp_get_connection_info(ctx->session, info); 1007 } 1008 1009 default: 1010 FIXME("Unhandled attribute %#x\n", attribute); 1011 return SEC_E_UNSUPPORTED_FUNCTION; 1012 } 1013 } 1014 1015 static 1016 SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA( 1017 PCtxtHandle context_handle, ULONG attribute, PVOID buffer) 1018 { 1019 TRACE("context_handle %p, attribute %#x, buffer %p\n", 1020 context_handle, attribute, buffer); 1021 1022 switch(attribute) 1023 { 1024 case SECPKG_ATTR_STREAM_SIZES: 1025 return schan_QueryContextAttributesW(context_handle, attribute, buffer); 1026 case SECPKG_ATTR_REMOTE_CERT_CONTEXT: 1027 return schan_QueryContextAttributesW(context_handle, attribute, buffer); 1028 case SECPKG_ATTR_CONNECTION_INFO: 1029 return schan_QueryContextAttributesW(context_handle, attribute, buffer); 1030 1031 default: 1032 FIXME("Unhandled attribute %#x\n", attribute); 1033 return SEC_E_UNSUPPORTED_FUNCTION; 1034 } 1035 } 1036 1037 static int schan_encrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s) 1038 { 1039 SecBuffer *b; 1040 1041 if (s->current_buffer_idx == -1) 1042 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_HEADER); 1043 1044 b = &s->desc->pBuffers[s->current_buffer_idx]; 1045 1046 if (b->BufferType == SECBUFFER_STREAM_HEADER) 1047 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA); 1048 1049 if (b->BufferType == SECBUFFER_DATA) 1050 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_TRAILER); 1051 1052 return -1; 1053 } 1054 1055 static int schan_encrypt_message_get_next_buffer_token(const struct schan_transport *t, struct schan_buffers *s) 1056 { 1057 SecBuffer *b; 1058 1059 if (s->current_buffer_idx == -1) 1060 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN); 1061 1062 b = &s->desc->pBuffers[s->current_buffer_idx]; 1063 1064 if (b->BufferType == SECBUFFER_TOKEN) 1065 { 1066 int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN); 1067 if (idx != s->current_buffer_idx) return -1; 1068 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA); 1069 } 1070 1071 if (b->BufferType == SECBUFFER_DATA) 1072 { 1073 int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN); 1074 if (idx != -1) 1075 idx = schan_find_sec_buffer_idx(s->desc, idx + 1, SECBUFFER_TOKEN); 1076 return idx; 1077 } 1078 1079 return -1; 1080 } 1081 1082 static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle, 1083 ULONG quality, PSecBufferDesc message, ULONG message_seq_no) 1084 { 1085 struct schan_transport transport; 1086 struct schan_context *ctx; 1087 struct schan_buffers *b; 1088 SECURITY_STATUS status; 1089 SecBuffer *buffer; 1090 SIZE_T data_size; 1091 SIZE_T length; 1092 char *data; 1093 int idx; 1094 1095 TRACE("context_handle %p, quality %d, message %p, message_seq_no %d\n", 1096 context_handle, quality, message, message_seq_no); 1097 1098 if (!context_handle) return SEC_E_INVALID_HANDLE; 1099 ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX); 1100 1101 dump_buffer_desc(message); 1102 1103 idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_DATA); 1104 if (idx == -1) 1105 { 1106 WARN("No data buffer passed\n"); 1107 return SEC_E_INTERNAL_ERROR; 1108 } 1109 buffer = &message->pBuffers[idx]; 1110 1111 data_size = buffer->cbBuffer; 1112 data = HeapAlloc(GetProcessHeap(), 0, data_size); 1113 memcpy(data, buffer->pvBuffer, data_size); 1114 1115 transport.ctx = ctx; 1116 init_schan_buffers(&transport.in, NULL, NULL); 1117 if (schan_find_sec_buffer_idx(message, 0, SECBUFFER_STREAM_HEADER) != -1) 1118 init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer); 1119 else 1120 init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer_token); 1121 schan_imp_set_session_transport(ctx->session, &transport); 1122 1123 length = data_size; 1124 status = schan_imp_send(ctx->session, data, &length); 1125 1126 TRACE("Sent %ld bytes.\n", length); 1127 1128 if (length != data_size) 1129 status = SEC_E_INTERNAL_ERROR; 1130 1131 b = &transport.out; 1132 b->desc->pBuffers[b->current_buffer_idx].cbBuffer = b->offset; 1133 HeapFree(GetProcessHeap(), 0, data); 1134 1135 TRACE("Returning %#x.\n", status); 1136 1137 return status; 1138 } 1139 1140 static int schan_decrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s) 1141 { 1142 if (s->current_buffer_idx == -1) 1143 return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA); 1144 1145 return -1; 1146 } 1147 1148 static int schan_validate_decrypt_buffer_desc(PSecBufferDesc message) 1149 { 1150 int data_idx = -1; 1151 unsigned int empty_count = 0; 1152 unsigned int i; 1153 1154 if (message->cBuffers < 4) 1155 { 1156 WARN("Less than four buffers passed\n"); 1157 return -1; 1158 } 1159 1160 for (i = 0; i < message->cBuffers; ++i) 1161 { 1162 SecBuffer *b = &message->pBuffers[i]; 1163 if (b->BufferType == SECBUFFER_DATA) 1164 { 1165 if (data_idx != -1) 1166 { 1167 WARN("More than one data buffer passed\n"); 1168 return -1; 1169 } 1170 data_idx = i; 1171 } 1172 else if (b->BufferType == SECBUFFER_EMPTY) 1173 ++empty_count; 1174 } 1175 1176 if (data_idx == -1) 1177 { 1178 WARN("No data buffer passed\n"); 1179 return -1; 1180 } 1181 1182 if (empty_count < 3) 1183 { 1184 WARN("Less than three empty buffers passed\n"); 1185 return -1; 1186 } 1187 1188 return data_idx; 1189 } 1190 1191 static void schan_decrypt_fill_buffer(PSecBufferDesc message, ULONG buffer_type, void *data, ULONG size) 1192 { 1193 int idx; 1194 SecBuffer *buffer; 1195 1196 idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY); 1197 buffer = &message->pBuffers[idx]; 1198 1199 buffer->BufferType = buffer_type; 1200 buffer->pvBuffer = data; 1201 buffer->cbBuffer = size; 1202 } 1203 1204 static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle, 1205 PSecBufferDesc message, ULONG message_seq_no, PULONG quality) 1206 { 1207 struct schan_transport transport; 1208 struct schan_context *ctx; 1209 SecBuffer *buffer; 1210 SIZE_T data_size; 1211 char *data; 1212 unsigned expected_size; 1213 SSIZE_T received = 0; 1214 int idx; 1215 unsigned char *buf_ptr; 1216 1217 TRACE("context_handle %p, message %p, message_seq_no %d, quality %p\n", 1218 context_handle, message, message_seq_no, quality); 1219 1220 if (!context_handle) return SEC_E_INVALID_HANDLE; 1221 ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX); 1222 1223 dump_buffer_desc(message); 1224 1225 idx = schan_validate_decrypt_buffer_desc(message); 1226 if (idx == -1) 1227 return SEC_E_INVALID_TOKEN; 1228 buffer = &message->pBuffers[idx]; 1229 buf_ptr = buffer->pvBuffer; 1230 1231 expected_size = 5 + ((buf_ptr[3] << 8) | buf_ptr[4]); 1232 if(buffer->cbBuffer < expected_size) 1233 { 1234 TRACE("Expected %u bytes, but buffer only contains %u bytes\n", expected_size, buffer->cbBuffer); 1235 buffer->BufferType = SECBUFFER_MISSING; 1236 buffer->cbBuffer = expected_size - buffer->cbBuffer; 1237 1238 /* This is a bit weird, but windows does it too */ 1239 idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY); 1240 buffer = &message->pBuffers[idx]; 1241 buffer->BufferType = SECBUFFER_MISSING; 1242 buffer->cbBuffer = expected_size - buffer->cbBuffer; 1243 1244 TRACE("Returning SEC_E_INCOMPLETE_MESSAGE\n"); 1245 return SEC_E_INCOMPLETE_MESSAGE; 1246 } 1247 1248 data_size = expected_size - 5; 1249 data = HeapAlloc(GetProcessHeap(), 0, data_size); 1250 1251 transport.ctx = ctx; 1252 init_schan_buffers(&transport.in, message, schan_decrypt_message_get_next_buffer); 1253 transport.in.limit = expected_size; 1254 init_schan_buffers(&transport.out, NULL, NULL); 1255 schan_imp_set_session_transport(ctx->session, &transport); 1256 1257 while (received < data_size) 1258 { 1259 SIZE_T length = data_size - received; 1260 SECURITY_STATUS status = schan_imp_recv(ctx->session, data + received, &length); 1261 1262 if (status == SEC_I_CONTINUE_NEEDED) 1263 break; 1264 1265 if (status != SEC_E_OK) 1266 { 1267 HeapFree(GetProcessHeap(), 0, data); 1268 ERR("Returning %x\n", status); 1269 return status; 1270 } 1271 1272 if (!length) 1273 break; 1274 1275 received += length; 1276 } 1277 1278 TRACE("Received %ld bytes\n", received); 1279 1280 memcpy(buf_ptr + 5, data, received); 1281 HeapFree(GetProcessHeap(), 0, data); 1282 1283 schan_decrypt_fill_buffer(message, SECBUFFER_DATA, 1284 buf_ptr + 5, received); 1285 1286 schan_decrypt_fill_buffer(message, SECBUFFER_STREAM_TRAILER, 1287 buf_ptr + 5 + received, buffer->cbBuffer - 5 - received); 1288 1289 if(buffer->cbBuffer > expected_size) 1290 schan_decrypt_fill_buffer(message, SECBUFFER_EXTRA, 1291 buf_ptr + expected_size, buffer->cbBuffer - expected_size); 1292 1293 buffer->BufferType = SECBUFFER_STREAM_HEADER; 1294 buffer->cbBuffer = 5; 1295 1296 return SEC_E_OK; 1297 } 1298 1299 SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context_handle) 1300 { 1301 struct schan_context *ctx; 1302 1303 TRACE("context_handle %p\n", context_handle); 1304 1305 if (!context_handle) return SEC_E_INVALID_HANDLE; 1306 1307 ctx = schan_free_handle(context_handle->dwLower, SCHAN_HANDLE_CTX); 1308 if (!ctx) return SEC_E_INVALID_HANDLE; 1309 1310 if (ctx->cert) 1311 CertFreeCertificateContext(ctx->cert); 1312 schan_imp_dispose_session(ctx->session); 1313 HeapFree(GetProcessHeap(), 0, ctx); 1314 1315 return SEC_E_OK; 1316 } 1317 1318 SecurityFunctionTableA schanTableA = { 1319 1, 1320 schan_EnumerateSecurityPackagesA, 1321 schan_QueryCredentialsAttributesA, 1322 schan_AcquireCredentialsHandleA, 1323 schan_FreeCredentialsHandle, 1324 NULL, /* Reserved2 */ 1325 schan_InitializeSecurityContextA, 1326 NULL, /* AcceptSecurityContext */ 1327 NULL, /* CompleteAuthToken */ 1328 schan_DeleteSecurityContext, 1329 NULL, /* ApplyControlToken */ 1330 schan_QueryContextAttributesA, 1331 NULL, /* ImpersonateSecurityContext */ 1332 NULL, /* RevertSecurityContext */ 1333 NULL, /* MakeSignature */ 1334 NULL, /* VerifySignature */ 1335 schan_FreeContextBuffer, 1336 NULL, /* QuerySecurityPackageInfoA */ 1337 NULL, /* Reserved3 */ 1338 NULL, /* Reserved4 */ 1339 NULL, /* ExportSecurityContext */ 1340 NULL, /* ImportSecurityContextA */ 1341 NULL, /* AddCredentialsA */ 1342 NULL, /* Reserved8 */ 1343 NULL, /* QuerySecurityContextToken */ 1344 schan_EncryptMessage, 1345 schan_DecryptMessage, 1346 NULL, /* SetContextAttributesA */ 1347 }; 1348 1349 SecurityFunctionTableW schanTableW = { 1350 1, 1351 schan_EnumerateSecurityPackagesW, 1352 schan_QueryCredentialsAttributesW, 1353 schan_AcquireCredentialsHandleW, 1354 schan_FreeCredentialsHandle, 1355 NULL, /* Reserved2 */ 1356 schan_InitializeSecurityContextW, 1357 NULL, /* AcceptSecurityContext */ 1358 NULL, /* CompleteAuthToken */ 1359 schan_DeleteSecurityContext, 1360 NULL, /* ApplyControlToken */ 1361 schan_QueryContextAttributesW, 1362 NULL, /* ImpersonateSecurityContext */ 1363 NULL, /* RevertSecurityContext */ 1364 NULL, /* MakeSignature */ 1365 NULL, /* VerifySignature */ 1366 schan_FreeContextBuffer, 1367 NULL, /* QuerySecurityPackageInfoW */ 1368 NULL, /* Reserved3 */ 1369 NULL, /* Reserved4 */ 1370 NULL, /* ExportSecurityContext */ 1371 NULL, /* ImportSecurityContextW */ 1372 NULL, /* AddCredentialsW */ 1373 NULL, /* Reserved8 */ 1374 NULL, /* QuerySecurityContextToken */ 1375 schan_EncryptMessage, 1376 schan_DecryptMessage, 1377 NULL, /* SetContextAttributesW */ 1378 }; 1379 1380 static const WCHAR schannelComment[] = { 'S','c','h','a','n','n','e','l',' ', 1381 'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 }; 1382 static const WCHAR schannelDllName[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 }; 1383 1384 void SECUR32_initSchannelSP(void) 1385 { 1386 /* This is what Windows reports. This shouldn't break any applications 1387 * even though the functions are missing, because the wrapper will 1388 * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL. 1389 */ 1390 static const LONG caps = 1391 SECPKG_FLAG_INTEGRITY | 1392 SECPKG_FLAG_PRIVACY | 1393 SECPKG_FLAG_CONNECTION | 1394 SECPKG_FLAG_MULTI_REQUIRED | 1395 SECPKG_FLAG_EXTENDED_ERROR | 1396 SECPKG_FLAG_IMPERSONATION | 1397 SECPKG_FLAG_ACCEPT_WIN32_NAME | 1398 SECPKG_FLAG_STREAM; 1399 static const short version = 1; 1400 static const LONG maxToken = 16384; 1401 SEC_WCHAR *uniSPName = (SEC_WCHAR *)UNISP_NAME_W, 1402 *schannel = (SEC_WCHAR *)SCHANNEL_NAME_W; 1403 const SecPkgInfoW info[] = { 1404 { caps, version, UNISP_RPC_ID, maxToken, uniSPName, uniSPName }, 1405 { caps, version, UNISP_RPC_ID, maxToken, schannel, 1406 (SEC_WCHAR *)schannelComment }, 1407 }; 1408 SecureProvider *provider; 1409 1410 if (!schan_imp_init()) 1411 return; 1412 1413 schan_handle_table = HeapAlloc(GetProcessHeap(), 0, 64 * sizeof(*schan_handle_table)); 1414 if (!schan_handle_table) 1415 { 1416 ERR("Failed to allocate schannel handle table.\n"); 1417 goto fail; 1418 } 1419 schan_handle_table_size = 64; 1420 1421 provider = SECUR32_addProvider(&schanTableA, &schanTableW, schannelDllName); 1422 if (!provider) 1423 { 1424 ERR("Failed to add schannel provider.\n"); 1425 goto fail; 1426 } 1427 1428 SECUR32_addPackages(provider, sizeof(info) / sizeof(info[0]), NULL, info); 1429 1430 return; 1431 1432 fail: 1433 HeapFree(GetProcessHeap(), 0, schan_handle_table); 1434 schan_handle_table = NULL; 1435 schan_imp_deinit(); 1436 return; 1437 } 1438 1439 void SECUR32_deinitSchannelSP(void) 1440 { 1441 SIZE_T i = schan_handle_count; 1442 1443 if (!schan_handle_table) return; 1444 1445 /* deinitialized sessions first because a pointer to the credentials 1446 * may be stored for the session. */ 1447 while (i--) 1448 { 1449 if (schan_handle_table[i].type == SCHAN_HANDLE_CTX) 1450 { 1451 struct schan_context *ctx = schan_free_handle(i, SCHAN_HANDLE_CTX); 1452 schan_imp_dispose_session(ctx->session); 1453 HeapFree(GetProcessHeap(), 0, ctx); 1454 } 1455 } 1456 i = schan_handle_count; 1457 while (i--) 1458 { 1459 if (schan_handle_table[i].type != SCHAN_HANDLE_FREE) 1460 { 1461 struct schan_credentials *cred; 1462 cred = schan_free_handle(i, SCHAN_HANDLE_CRED); 1463 schan_imp_free_certificate_credentials(cred); 1464 HeapFree(GetProcessHeap(), 0, cred); 1465 } 1466 } 1467 HeapFree(GetProcessHeap(), 0, schan_handle_table); 1468 schan_imp_deinit(); 1469 } 1470 1471 #else /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H || SONAME_LIBMBEDTLS */ 1472 1473 void SECUR32_initSchannelSP(void) 1474 { 1475 ERR("TLS library not found, SSL connections will fail\n"); 1476 } 1477 1478 void SECUR32_deinitSchannelSP(void) {} 1479 1480 #endif /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H || SONAME_LIBMBEDTLS */ 1481