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