1/* 2 * TLS support for CUPS on Windows using the Security Support Provider 3 * Interface (SSPI). 4 * 5 * Copyright 2010-2015 by Apple Inc. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16/**** This file is included from tls.c ****/ 17 18/* 19 * Include necessary headers... 20 */ 21 22#include "debug-private.h" 23 24 25/* 26 * Include necessary libraries... 27 */ 28 29#pragma comment(lib, "Crypt32.lib") 30#pragma comment(lib, "Secur32.lib") 31#pragma comment(lib, "Ws2_32.lib") 32 33 34/* 35 * Constants... 36 */ 37 38#ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA 39# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */ 40#endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */ 41 42#ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID 43# define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 /* Common name does not match */ 44#endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */ 45 46#ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 47# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */ 48#endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */ 49 50 51/* 52 * Local globals... 53 */ 54 55static int tls_options = -1;/* Options for TLS connections */ 56 57 58/* 59 * Local functions... 60 */ 61 62static _http_sspi_t *http_sspi_alloc(void); 63static int http_sspi_client(http_t *http, const char *hostname); 64static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred); 65static BOOL http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name); 66static void http_sspi_free(_http_sspi_t *sspi); 67static BOOL http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years); 68static int http_sspi_server(http_t *http, const char *hostname); 69static void http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow); 70static void http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow); 71static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code); 72static DWORD http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags); 73 74 75/* 76 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. 77 * 78 * @since CUPS 2.0/OS 10.10@ 79 */ 80 81int /* O - 1 on success, 0 on failure */ 82cupsMakeServerCredentials( 83 const char *path, /* I - Keychain path or @code NULL@ for default */ 84 const char *common_name, /* I - Common name */ 85 int num_alt_names, /* I - Number of subject alternate names */ 86 const char **alt_names, /* I - Subject Alternate Names */ 87 time_t expiration_date) /* I - Expiration date */ 88{ 89 _http_sspi_t *sspi; /* SSPI data */ 90 int ret; /* Return value */ 91 92 93 DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date)); 94 95 (void)path; 96 (void)num_alt_names; 97 (void)alt_names; 98 99 sspi = http_sspi_alloc(); 100 ret = http_sspi_make_credentials(sspi, L"ServerContainer", common_name, _HTTP_MODE_SERVER, (int)((expiration_date - time(NULL) + 86399) / 86400 / 365)); 101 102 http_sspi_free(sspi); 103 104 return (ret); 105} 106 107 108/* 109 * 'cupsSetServerCredentials()' - Set the default server credentials. 110 * 111 * Note: The server credentials are used by all threads in the running process. 112 * This function is threadsafe. 113 * 114 * @since CUPS 2.0/OS 10.10@ 115 */ 116 117int /* O - 1 on success, 0 on failure */ 118cupsSetServerCredentials( 119 const char *path, /* I - Keychain path or @code NULL@ for default */ 120 const char *common_name, /* I - Default common name for server */ 121 int auto_create) /* I - 1 = automatically create self-signed certificates */ 122{ 123 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); 124 125 (void)path; 126 (void)common_name; 127 (void)auto_create; 128 129 return (0); 130} 131 132 133/* 134 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in 135 * an encrypted connection. 136 * 137 * @since CUPS 1.5/macOS 10.7@ 138 */ 139 140int /* O - Status of call (0 = success) */ 141httpCopyCredentials( 142 http_t *http, /* I - Connection to server */ 143 cups_array_t **credentials) /* O - Array of credentials */ 144{ 145 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials)); 146 147 if (!http || !http->tls || !http->tls->remoteCert || !credentials) 148 { 149 if (credentials) 150 *credentials = NULL; 151 152 return (-1); 153 } 154 155 *credentials = cupsArrayNew(NULL, NULL); 156 httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded); 157 158 return (0); 159} 160 161 162/* 163 * '_httpCreateCredentials()' - Create credentials in the internal format. 164 */ 165 166http_tls_credentials_t /* O - Internal credentials */ 167_httpCreateCredentials( 168 cups_array_t *credentials) /* I - Array of credentials */ 169{ 170 return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials))); 171} 172 173 174/* 175 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. 176 * 177 * @since CUPS 2.0/OS 10.10@ 178 */ 179 180int /* O - 1 if valid, 0 otherwise */ 181httpCredentialsAreValidForName( 182 cups_array_t *credentials, /* I - Credentials */ 183 const char *common_name) /* I - Name to check */ 184{ 185 int valid = 1; /* Valid name? */ 186 PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); 187 /* Certificate */ 188 char cert_name[1024]; /* Name from certificate */ 189 190 191 if (cert) 192 { 193 if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name))) 194 { 195 /* 196 * Extract common name at end... 197 */ 198 199 char *ptr = strrchr(cert_name, ','); 200 if (ptr && ptr[1]) 201 _cups_strcpy(cert_name, ptr + 2); 202 } 203 else 204 strlcpy(cert_name, "unknown", sizeof(cert_name)); 205 206 CertFreeCertificateContext(cert); 207 } 208 else 209 strlcpy(cert_name, "unknown", sizeof(cert_name)); 210 211 /* 212 * Compare the common names... 213 */ 214 215 if (_cups_strcasecmp(common_name, cert_name)) 216 { 217 /* 218 * Not an exact match for the common name, check for wildcard certs... 219 */ 220 221 const char *domain = strchr(common_name, '.'); 222 /* Domain in common name */ 223 224 if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1)) 225 { 226 /* 227 * Not a wildcard match. 228 */ 229 230 /* TODO: Check subject alternate names */ 231 valid = 0; 232 } 233 } 234 235 return (valid); 236} 237 238 239/* 240 * 'httpCredentialsGetTrust()' - Return the trust of credentials. 241 * 242 * @since CUPS 2.0/OS 10.10@ 243 */ 244 245http_trust_t /* O - Level of trust */ 246httpCredentialsGetTrust( 247 cups_array_t *credentials, /* I - Credentials */ 248 const char *common_name) /* I - Common name for trust lookup */ 249{ 250 http_trust_t trust = HTTP_TRUST_OK; /* Level of trust */ 251 PCCERT_CONTEXT cert = NULL; /* Certificate to validate */ 252 DWORD certFlags = 0; /* Cert verification flags */ 253 _cups_globals_t *cg = _cupsGlobals(); /* Per-thread global data */ 254 255 256 if (!common_name) 257 return (HTTP_TRUST_UNKNOWN); 258 259 cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); 260 if (!cert) 261 return (HTTP_TRUST_UNKNOWN); 262 263 if (cg->any_root < 0) 264 _cupsSetDefaults(); 265 266 if (cg->any_root) 267 certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; 268 269 if (cg->expired_certs) 270 certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 271 272 if (!cg->validate_certs) 273 certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; 274 275 if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK) 276 trust = HTTP_TRUST_INVALID; 277 278 CertFreeCertificateContext(cert); 279 280 return (trust); 281} 282 283 284/* 285 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. 286 * 287 * @since CUPS 2.0/OS 10.10@ 288 */ 289 290time_t /* O - Expiration date of credentials */ 291httpCredentialsGetExpiration( 292 cups_array_t *credentials) /* I - Credentials */ 293{ 294 time_t expiration_date = 0; /* Expiration data of credentials */ 295 PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); 296 /* Certificate */ 297 298 if (cert) 299 { 300 SYSTEMTIME systime; /* System time */ 301 struct tm tm; /* UNIX date/time */ 302 303 FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime); 304 305 tm.tm_year = systime.wYear - 1900; 306 tm.tm_mon = systime.wMonth - 1; 307 tm.tm_mday = systime.wDay; 308 tm.tm_hour = systime.wHour; 309 tm.tm_min = systime.wMinute; 310 tm.tm_sec = systime.wSecond; 311 312 expiration_date = mktime(&tm); 313 314 CertFreeCertificateContext(cert); 315 } 316 317 return (expiration_date); 318} 319 320 321/* 322 * 'httpCredentialsString()' - Return a string representing the credentials. 323 * 324 * @since CUPS 2.0/OS 10.10@ 325 */ 326 327size_t /* O - Total size of credentials string */ 328httpCredentialsString( 329 cups_array_t *credentials, /* I - Credentials */ 330 char *buffer, /* I - Buffer or @code NULL@ */ 331 size_t bufsize) /* I - Size of buffer */ 332{ 333 http_credential_t *first = (http_credential_t *)cupsArrayFirst(credentials); 334 /* First certificate */ 335 PCCERT_CONTEXT cert; /* Certificate */ 336 337 338 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize)); 339 340 if (!buffer) 341 return (0); 342 343 if (buffer && bufsize > 0) 344 *buffer = '\0'; 345 346 cert = http_sspi_create_credential(first); 347 348 if (cert) 349 { 350 char cert_name[256]; /* Common name */ 351 SYSTEMTIME systime; /* System time */ 352 struct tm tm; /* UNIX date/time */ 353 time_t expiration; /* Expiration date of cert */ 354 _cups_md5_state_t md5_state; /* MD5 state */ 355 unsigned char md5_digest[16]; /* MD5 result */ 356 357 FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime); 358 359 tm.tm_year = systime.wYear - 1900; 360 tm.tm_mon = systime.wMonth - 1; 361 tm.tm_mday = systime.wDay; 362 tm.tm_hour = systime.wHour; 363 tm.tm_min = systime.wMinute; 364 tm.tm_sec = systime.wSecond; 365 366 expiration = mktime(&tm); 367 368 if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name))) 369 { 370 /* 371 * Extract common name at end... 372 */ 373 374 char *ptr = strrchr(cert_name, ','); 375 if (ptr && ptr[1]) 376 _cups_strcpy(cert_name, ptr + 2); 377 } 378 else 379 strlcpy(cert_name, "unknown", sizeof(cert_name)); 380 381 _cupsMD5Init(&md5_state); 382 _cupsMD5Append(&md5_state, first->data, (int)first->datalen); 383 _cupsMD5Finish(&md5_state, md5_digest); 384 385 snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); 386 387 CertFreeCertificateContext(cert); 388 } 389 390 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); 391 392 return (strlen(buffer)); 393} 394 395 396/* 397 * '_httpFreeCredentials()' - Free internal credentials. 398 */ 399 400void 401_httpFreeCredentials( 402 http_tls_credentials_t credentials) /* I - Internal credentials */ 403{ 404 if (!credentials) 405 return; 406 407 CertFreeCertificateContext(credentials); 408} 409 410 411/* 412 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. 413 * 414 * @since CUPS 2.0/OS 10.10@ 415 */ 416 417int /* O - 0 on success, -1 on error */ 418httpLoadCredentials( 419 const char *path, /* I - Keychain path or @code NULL@ for default */ 420 cups_array_t **credentials, /* IO - Credentials */ 421 const char *common_name) /* I - Common name for credentials */ 422{ 423 HCERTSTORE store = NULL; /* Certificate store */ 424 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ 425 DWORD dwSize = 0; /* 32 bit size */ 426 PBYTE p = NULL; /* Temporary storage */ 427 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 428 /* Handle to a CSP */ 429 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ 430#ifdef DEBUG 431 char error[1024]; /* Error message buffer */ 432#endif /* DEBUG */ 433 434 435 DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); 436 437 (void)path; 438 439 if (credentials) 440 { 441 *credentials = NULL; 442 } 443 else 444 { 445 DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1."); 446 return (-1); 447 } 448 449 if (!common_name) 450 { 451 DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1."); 452 return (-1); 453 } 454 455 if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 456 { 457 if (GetLastError() == NTE_EXISTS) 458 { 459 if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 460 { 461 DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 462 goto cleanup; 463 } 464 } 465 } 466 467 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); 468 469 if (!store) 470 { 471 DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 472 goto cleanup; 473 } 474 475 dwSize = 0; 476 477 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) 478 { 479 DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 480 goto cleanup; 481 } 482 483 p = (PBYTE)malloc(dwSize); 484 485 if (!p) 486 { 487 DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize)); 488 goto cleanup; 489 } 490 491 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) 492 { 493 DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 494 goto cleanup; 495 } 496 497 sib.cbData = dwSize; 498 sib.pbData = p; 499 500 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); 501 502 if (!storedContext) 503 { 504 DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name)); 505 goto cleanup; 506 } 507 508 *credentials = cupsArrayNew(NULL, NULL); 509 httpAddCredential(*credentials, storedContext->pbCertEncoded, storedContext->cbCertEncoded); 510 511cleanup: 512 513 /* 514 * Cleanup 515 */ 516 517 if (storedContext) 518 CertFreeCertificateContext(storedContext); 519 520 if (p) 521 free(p); 522 523 if (store) 524 CertCloseStore(store, 0); 525 526 if (hProv) 527 CryptReleaseContext(hProv, 0); 528 529 DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1)); 530 531 return (*credentials ? 0 : -1); 532} 533 534 535/* 536 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. 537 * 538 * @since CUPS 2.0/OS 10.10@ 539 */ 540 541int /* O - -1 on error, 0 on success */ 542httpSaveCredentials( 543 const char *path, /* I - Keychain path or @code NULL@ for default */ 544 cups_array_t *credentials, /* I - Credentials */ 545 const char *common_name) /* I - Common name for credentials */ 546{ 547 HCERTSTORE store = NULL; /* Certificate store */ 548 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ 549 PCCERT_CONTEXT createdContext = NULL; /* Context created by us */ 550 DWORD dwSize = 0; /* 32 bit size */ 551 PBYTE p = NULL; /* Temporary storage */ 552 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 553 /* Handle to a CSP */ 554 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ 555 int ret = -1; /* Return value */ 556#ifdef DEBUG 557 char error[1024]; /* Error message buffer */ 558#endif /* DEBUG */ 559 560 561 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); 562 563 (void)path; 564 565 if (!common_name) 566 { 567 DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1."); 568 return (-1); 569 } 570 571 createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); 572 if (!createdContext) 573 { 574 DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1."); 575 return (-1); 576 } 577 578 if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 579 { 580 if (GetLastError() == NTE_EXISTS) 581 { 582 if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 583 { 584 DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 585 goto cleanup; 586 } 587 } 588 } 589 590 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); 591 592 if (!store) 593 { 594 DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 595 goto cleanup; 596 } 597 598 dwSize = 0; 599 600 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) 601 { 602 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 603 goto cleanup; 604 } 605 606 p = (PBYTE)malloc(dwSize); 607 608 if (!p) 609 { 610 DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize)); 611 goto cleanup; 612 } 613 614 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) 615 { 616 DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 617 goto cleanup; 618 } 619 620 /* 621 * Add the created context to the named store, and associate it with the named 622 * container... 623 */ 624 625 if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext)) 626 { 627 DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 628 goto cleanup; 629 } 630 631 ZeroMemory(&ckp, sizeof(ckp)); 632 ckp.pwszContainerName = L"RememberedContainer"; 633 ckp.pwszProvName = MS_DEF_PROV_W; 634 ckp.dwProvType = PROV_RSA_FULL; 635 ckp.dwFlags = CRYPT_MACHINE_KEYSET; 636 ckp.dwKeySpec = AT_KEYEXCHANGE; 637 638 if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp)) 639 { 640 DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); 641 goto cleanup; 642 } 643 644 ret = 0; 645 646cleanup: 647 648 /* 649 * Cleanup 650 */ 651 652 if (createdContext) 653 CertFreeCertificateContext(createdContext); 654 655 if (storedContext) 656 CertFreeCertificateContext(storedContext); 657 658 if (p) 659 free(p); 660 661 if (store) 662 CertCloseStore(store, 0); 663 664 if (hProv) 665 CryptReleaseContext(hProv, 0); 666 667 DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret)); 668 return (ret); 669} 670 671 672/* 673 * '_httpTLSInitialize()' - Initialize the TLS stack. 674 */ 675 676void 677_httpTLSInitialize(void) 678{ 679 /* 680 * Nothing to do... 681 */ 682} 683 684 685/* 686 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. 687 */ 688 689size_t /* O - Bytes available */ 690_httpTLSPending(http_t *http) /* I - HTTP connection */ 691{ 692 if (http->tls) 693 return (http->tls->readBufferUsed); 694 else 695 return (0); 696} 697 698 699/* 700 * '_httpTLSRead()' - Read from a SSL/TLS connection. 701 */ 702 703int /* O - Bytes read */ 704_httpTLSRead(http_t *http, /* I - HTTP connection */ 705 char *buf, /* I - Buffer to store data */ 706 int len) /* I - Length of buffer */ 707{ 708 int i; /* Looping var */ 709 _http_sspi_t *sspi = http->tls; /* SSPI data */ 710 SecBufferDesc message; /* Array of SecBuffer struct */ 711 SecBuffer buffers[4] = { 0 }; /* Security package buffer */ 712 int num = 0; /* Return value */ 713 PSecBuffer pDataBuffer; /* Data buffer */ 714 PSecBuffer pExtraBuffer; /* Excess data buffer */ 715 SECURITY_STATUS scRet; /* SSPI status */ 716 717 718 DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len)); 719 720 /* 721 * If there are bytes that have already been decrypted and have not yet been 722 * read, return those... 723 */ 724 725 if (sspi->readBufferUsed > 0) 726 { 727 int bytesToCopy = min(sspi->readBufferUsed, len); 728 /* Number of bytes to copy */ 729 730 memcpy(buf, sspi->readBuffer, bytesToCopy); 731 sspi->readBufferUsed -= bytesToCopy; 732 733 if (sspi->readBufferUsed > 0) 734 memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed); 735 736 DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy)); 737 738 return (bytesToCopy); 739 } 740 741 /* 742 * Initialize security buffer structs 743 */ 744 745 message.ulVersion = SECBUFFER_VERSION; 746 message.cBuffers = 4; 747 message.pBuffers = buffers; 748 749 do 750 { 751 /* 752 * If there is not enough space in the buffer, then increase its size... 753 */ 754 755 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) 756 { 757 BYTE *temp; /* New buffer */ 758 759 if (sspi->decryptBufferLength >= 262144) 760 { 761 WSASetLastError(E_OUTOFMEMORY); 762 DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)"); 763 return (-1); 764 } 765 766 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) 767 { 768 DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096)); 769 WSASetLastError(E_OUTOFMEMORY); 770 return (-1); 771 } 772 773 sspi->decryptBufferLength += 4096; 774 sspi->decryptBuffer = temp; 775 776 DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength)); 777 } 778 779 buffers[0].pvBuffer = sspi->decryptBuffer; 780 buffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; 781 buffers[0].BufferType = SECBUFFER_DATA; 782 buffers[1].BufferType = SECBUFFER_EMPTY; 783 buffers[2].BufferType = SECBUFFER_EMPTY; 784 buffers[3].BufferType = SECBUFFER_EMPTY; 785 786 DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed)); 787 788 scRet = DecryptMessage(&sspi->context, &message, 0, NULL); 789 790 if (scRet == SEC_E_INCOMPLETE_MESSAGE) 791 { 792 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); 793 if (num < 0) 794 { 795 DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError())); 796 return (-1); 797 } 798 else if (num == 0) 799 { 800 DEBUG_puts("5_httpTLSRead: Server disconnected."); 801 return (0); 802 } 803 804 DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num)); 805 806 sspi->decryptBufferUsed += num; 807 } 808 } 809 while (scRet == SEC_E_INCOMPLETE_MESSAGE); 810 811 if (scRet == SEC_I_CONTEXT_EXPIRED) 812 { 813 DEBUG_puts("5_httpTLSRead: Context expired."); 814 WSASetLastError(WSAECONNRESET); 815 return (-1); 816 } 817 else if (scRet != SEC_E_OK) 818 { 819 DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 820 WSASetLastError(WSASYSCALLFAILURE); 821 return (-1); 822 } 823 824 /* 825 * The decryption worked. Now, locate data buffer. 826 */ 827 828 pDataBuffer = NULL; 829 pExtraBuffer = NULL; 830 831 for (i = 1; i < 4; i++) 832 { 833 if (buffers[i].BufferType == SECBUFFER_DATA) 834 pDataBuffer = &buffers[i]; 835 else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA)) 836 pExtraBuffer = &buffers[i]; 837 } 838 839 /* 840 * If a data buffer is found, then copy the decrypted bytes to the passed-in 841 * buffer... 842 */ 843 844 if (pDataBuffer) 845 { 846 int bytesToCopy = min((int)pDataBuffer->cbBuffer, len); 847 /* Number of bytes to copy into buf */ 848 int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy; 849 /* Number of bytes to save in our read buffer */ 850 851 if (bytesToCopy) 852 memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy); 853 854 /* 855 * If there are more decrypted bytes than can be copied to the passed in 856 * buffer, then save them... 857 */ 858 859 if (bytesToSave) 860 { 861 if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave) 862 { 863 BYTE *temp; /* New buffer pointer */ 864 865 if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL) 866 { 867 DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave)); 868 WSASetLastError(E_OUTOFMEMORY); 869 return (-1); 870 } 871 872 sspi->readBufferLength = sspi->readBufferUsed + bytesToSave; 873 sspi->readBuffer = temp; 874 } 875 876 memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave); 877 878 sspi->readBufferUsed += bytesToSave; 879 } 880 881 num = bytesToCopy; 882 } 883 else 884 { 885 DEBUG_puts("_httpTLSRead: Unable to find data buffer."); 886 WSASetLastError(WSASYSCALLFAILURE); 887 return (-1); 888 } 889 890 /* 891 * If the decryption process left extra bytes, then save those back in 892 * decryptBuffer. They will be processed the next time through the loop. 893 */ 894 895 if (pExtraBuffer) 896 { 897 memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer); 898 sspi->decryptBufferUsed = pExtraBuffer->cbBuffer; 899 } 900 else 901 { 902 sspi->decryptBufferUsed = 0; 903 } 904 905 return (num); 906} 907 908 909/* 910 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options. 911 */ 912 913void 914_httpTLSSetOptions(int options) /* I - Options */ 915{ 916 tls_options = options; 917} 918 919 920/* 921 * '_httpTLSStart()' - Set up SSL/TLS support on a connection. 922 */ 923 924int /* O - 0 on success, -1 on failure */ 925_httpTLSStart(http_t *http) /* I - HTTP connection */ 926{ 927 char hostname[256], /* Hostname */ 928 *hostptr; /* Pointer into hostname */ 929 930 931 DEBUG_printf(("3_httpTLSStart(http=%p)", http)); 932 933 if (tls_options < 0) 934 { 935 DEBUG_puts("4_httpTLSStart: Setting defaults."); 936 _cupsSetDefaults(); 937 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); 938 } 939 940 if ((http->tls = http_sspi_alloc()) == NULL) 941 return (-1); 942 943 if (http->mode == _HTTP_MODE_CLIENT) 944 { 945 /* 946 * Client: determine hostname... 947 */ 948 949 if (httpAddrLocalhost(http->hostaddr)) 950 { 951 strlcpy(hostname, "localhost", sizeof(hostname)); 952 } 953 else 954 { 955 /* 956 * Otherwise make sure the hostname we have does not end in a trailing dot. 957 */ 958 959 strlcpy(hostname, http->hostname, sizeof(hostname)); 960 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 961 *hostptr == '.') 962 *hostptr = '\0'; 963 } 964 965 return (http_sspi_client(http, hostname)); 966 } 967 else 968 { 969 /* 970 * Server: determine hostname to use... 971 */ 972 973 if (http->fields[HTTP_FIELD_HOST][0]) 974 { 975 /* 976 * Use hostname for TLS upgrade... 977 */ 978 979 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); 980 } 981 else 982 { 983 /* 984 * Resolve hostname from connection address... 985 */ 986 987 http_addr_t addr; /* Connection address */ 988 socklen_t addrlen; /* Length of address */ 989 990 addrlen = sizeof(addr); 991 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) 992 { 993 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); 994 hostname[0] = '\0'; 995 } 996 else if (httpAddrLocalhost(&addr)) 997 hostname[0] = '\0'; 998 else 999 { 1000 httpAddrLookup(&addr, hostname, sizeof(hostname)); 1001 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); 1002 } 1003 } 1004 1005 return (http_sspi_server(http, hostname)); 1006 } 1007} 1008 1009 1010/* 1011 * '_httpTLSStop()' - Shut down SSL/TLS on a connection. 1012 */ 1013 1014void 1015_httpTLSStop(http_t *http) /* I - HTTP connection */ 1016{ 1017 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1018 1019 1020 if (sspi->contextInitialized && http->fd >= 0) 1021 { 1022 SecBufferDesc message; /* Array of SecBuffer struct */ 1023 SecBuffer buffers[1] = { 0 }; 1024 /* Security package buffer */ 1025 DWORD dwType; /* Type */ 1026 DWORD status; /* Status */ 1027 1028 /* 1029 * Notify schannel that we are about to close the connection. 1030 */ 1031 1032 dwType = SCHANNEL_SHUTDOWN; 1033 1034 buffers[0].pvBuffer = &dwType; 1035 buffers[0].BufferType = SECBUFFER_TOKEN; 1036 buffers[0].cbBuffer = sizeof(dwType); 1037 1038 message.cBuffers = 1; 1039 message.pBuffers = buffers; 1040 message.ulVersion = SECBUFFER_VERSION; 1041 1042 status = ApplyControlToken(&sspi->context, &message); 1043 1044 if (SUCCEEDED(status)) 1045 { 1046 PBYTE pbMessage; /* Message buffer */ 1047 DWORD cbMessage; /* Message buffer count */ 1048 DWORD cbData; /* Data count */ 1049 DWORD dwSSPIFlags; /* SSL attributes we requested */ 1050 DWORD dwSSPIOutFlags; /* SSL attributes we received */ 1051 TimeStamp tsExpiry; /* Time stamp */ 1052 1053 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | 1054 ASC_REQ_REPLAY_DETECT | 1055 ASC_REQ_CONFIDENTIALITY | 1056 ASC_REQ_EXTENDED_ERROR | 1057 ASC_REQ_ALLOCATE_MEMORY | 1058 ASC_REQ_STREAM; 1059 1060 buffers[0].pvBuffer = NULL; 1061 buffers[0].BufferType = SECBUFFER_TOKEN; 1062 buffers[0].cbBuffer = 0; 1063 1064 message.cBuffers = 1; 1065 message.pBuffers = buffers; 1066 message.ulVersion = SECBUFFER_VERSION; 1067 1068 status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL, 1069 dwSSPIFlags, SECURITY_NATIVE_DREP, NULL, 1070 &message, &dwSSPIOutFlags, &tsExpiry); 1071 1072 if (SUCCEEDED(status)) 1073 { 1074 pbMessage = buffers[0].pvBuffer; 1075 cbMessage = buffers[0].cbBuffer; 1076 1077 /* 1078 * Send the close notify message to the client. 1079 */ 1080 1081 if (pbMessage && cbMessage) 1082 { 1083 cbData = send(http->fd, pbMessage, cbMessage, 0); 1084 if ((cbData == SOCKET_ERROR) || (cbData == 0)) 1085 { 1086 status = WSAGetLastError(); 1087 DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status)); 1088 } 1089 else 1090 { 1091 FreeContextBuffer(pbMessage); 1092 } 1093 } 1094 } 1095 else 1096 { 1097 DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status))); 1098 } 1099 } 1100 else 1101 { 1102 DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status))); 1103 } 1104 } 1105 1106 http_sspi_free(sspi); 1107 1108 http->tls = NULL; 1109} 1110 1111 1112/* 1113 * '_httpTLSWrite()' - Write to a SSL/TLS connection. 1114 */ 1115 1116int /* O - Bytes written */ 1117_httpTLSWrite(http_t *http, /* I - HTTP connection */ 1118 const char *buf, /* I - Buffer holding data */ 1119 int len) /* I - Length of buffer */ 1120{ 1121 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1122 SecBufferDesc message; /* Array of SecBuffer struct */ 1123 SecBuffer buffers[4] = { 0 }; /* Security package buffer */ 1124 int bufferLen; /* Buffer length */ 1125 int bytesLeft; /* Bytes left to write */ 1126 const char *bufptr; /* Pointer into buffer */ 1127 int num = 0; /* Return value */ 1128 1129 1130 bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer; 1131 1132 if (bufferLen > sspi->writeBufferLength) 1133 { 1134 BYTE *temp; /* New buffer pointer */ 1135 1136 if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL) 1137 { 1138 DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen)); 1139 WSASetLastError(E_OUTOFMEMORY); 1140 return (-1); 1141 } 1142 1143 sspi->writeBuffer = temp; 1144 sspi->writeBufferLength = bufferLen; 1145 } 1146 1147 bytesLeft = len; 1148 bufptr = buf; 1149 1150 while (bytesLeft) 1151 { 1152 int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft); 1153 /* Size of data to write */ 1154 SECURITY_STATUS scRet; /* SSPI status */ 1155 1156 /* 1157 * Copy user data into the buffer, starting just past the header... 1158 */ 1159 1160 memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk); 1161 1162 /* 1163 * Setup the SSPI buffers 1164 */ 1165 1166 message.ulVersion = SECBUFFER_VERSION; 1167 message.cBuffers = 4; 1168 message.pBuffers = buffers; 1169 1170 buffers[0].pvBuffer = sspi->writeBuffer; 1171 buffers[0].cbBuffer = sspi->streamSizes.cbHeader; 1172 buffers[0].BufferType = SECBUFFER_STREAM_HEADER; 1173 buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader; 1174 buffers[1].cbBuffer = (unsigned long) chunk; 1175 buffers[1].BufferType = SECBUFFER_DATA; 1176 buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk; 1177 buffers[2].cbBuffer = sspi->streamSizes.cbTrailer; 1178 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; 1179 buffers[3].BufferType = SECBUFFER_EMPTY; 1180 1181 /* 1182 * Encrypt the data 1183 */ 1184 1185 scRet = EncryptMessage(&sspi->context, 0, &message, 0); 1186 1187 if (FAILED(scRet)) 1188 { 1189 DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1190 WSASetLastError(WSASYSCALLFAILURE); 1191 return (-1); 1192 } 1193 1194 /* 1195 * Send the data. Remember the size of the total data to send is the size 1196 * of the header, the size of the data the caller passed in and the size 1197 * of the trailer... 1198 */ 1199 1200 num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0); 1201 1202 if (num <= 0) 1203 { 1204 DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError())); 1205 return (num); 1206 } 1207 1208 bytesLeft -= chunk; 1209 bufptr += chunk; 1210 } 1211 1212 return (len); 1213} 1214 1215 1216#if 0 1217/* 1218 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. 1219 */ 1220 1221static int /* O - 0 on success, -1 on failure */ 1222http_setup_ssl(http_t *http) /* I - Connection to server */ 1223{ 1224 char hostname[256], /* Hostname */ 1225 *hostptr; /* Pointer into hostname */ 1226 1227 TCHAR username[256]; /* Username returned from GetUserName() */ 1228 TCHAR commonName[256];/* Common name for certificate */ 1229 DWORD dwSize; /* 32 bit size */ 1230 1231 1232 DEBUG_printf(("7http_setup_ssl(http=%p)", http)); 1233 1234 /* 1235 * Get the hostname to use for SSL... 1236 */ 1237 1238 if (httpAddrLocalhost(http->hostaddr)) 1239 { 1240 strlcpy(hostname, "localhost", sizeof(hostname)); 1241 } 1242 else 1243 { 1244 /* 1245 * Otherwise make sure the hostname we have does not end in a trailing dot. 1246 */ 1247 1248 strlcpy(hostname, http->hostname, sizeof(hostname)); 1249 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 1250 *hostptr == '.') 1251 *hostptr = '\0'; 1252 } 1253 1254 http->tls = http_sspi_alloc(); 1255 1256 if (!http->tls) 1257 { 1258 _cupsSetHTTPError(HTTP_STATUS_ERROR); 1259 return (-1); 1260 } 1261 1262 dwSize = sizeof(username) / sizeof(TCHAR); 1263 GetUserName(username, &dwSize); 1264 _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR), 1265 sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username); 1266 1267 if (!_sspiGetCredentials(http->tls, L"ClientContainer", 1268 commonName, FALSE)) 1269 { 1270 _sspiFree(http->tls); 1271 http->tls = NULL; 1272 1273 http->error = EIO; 1274 http->status = HTTP_STATUS_ERROR; 1275 1276 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, 1277 _("Unable to establish a secure connection to host."), 1); 1278 1279 return (-1); 1280 } 1281 1282 _sspiSetAllowsAnyRoot(http->tls, TRUE); 1283 _sspiSetAllowsExpiredCerts(http->tls, TRUE); 1284 1285 if (!_sspiConnect(http->tls, hostname)) 1286 { 1287 _sspiFree(http->tls); 1288 http->tls = NULL; 1289 1290 http->error = EIO; 1291 http->status = HTTP_STATUS_ERROR; 1292 1293 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, 1294 _("Unable to establish a secure connection to host."), 1); 1295 1296 return (-1); 1297 } 1298 1299 return (0); 1300} 1301#endif // 0 1302 1303 1304/* 1305 * 'http_sspi_alloc()' - Allocate SSPI object. 1306 */ 1307 1308static _http_sspi_t * /* O - New SSPI/SSL object */ 1309http_sspi_alloc(void) 1310{ 1311 return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1)); 1312} 1313 1314 1315/* 1316 * 'http_sspi_client()' - Negotiate a TLS connection as a client. 1317 */ 1318 1319static int /* O - 0 on success, -1 on failure */ 1320http_sspi_client(http_t *http, /* I - Client connection */ 1321 const char *hostname) /* I - Server hostname */ 1322{ 1323 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1324 DWORD dwSize; /* Size for buffer */ 1325 DWORD dwSSPIFlags; /* SSL connection attributes we want */ 1326 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ 1327 TimeStamp tsExpiry; /* Time stamp */ 1328 SECURITY_STATUS scRet; /* Status */ 1329 int cbData; /* Data count */ 1330 SecBufferDesc inBuffer; /* Array of SecBuffer structs */ 1331 SecBuffer inBuffers[2]; /* Security package buffer */ 1332 SecBufferDesc outBuffer; /* Array of SecBuffer structs */ 1333 SecBuffer outBuffers[1]; /* Security package buffer */ 1334 int ret = 0; /* Return value */ 1335 char username[1024], /* Current username */ 1336 common_name[1024]; /* CN=username */ 1337 1338 1339 DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname)); 1340 1341 dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | 1342 ISC_REQ_REPLAY_DETECT | 1343 ISC_REQ_CONFIDENTIALITY | 1344 ISC_RET_EXTENDED_ERROR | 1345 ISC_REQ_ALLOCATE_MEMORY | 1346 ISC_REQ_STREAM; 1347 1348 /* 1349 * Lookup the client certificate... 1350 */ 1351 1352 dwSize = sizeof(username); 1353 GetUserName(username, &dwSize); 1354 snprintf(common_name, sizeof(common_name), "CN=%s", username); 1355 1356 if (!http_sspi_find_credentials(http, L"ClientContainer", common_name)) 1357 if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10)) 1358 { 1359 DEBUG_puts("5http_sspi_client: Unable to get client credentials."); 1360 return (-1); 1361 } 1362 1363 /* 1364 * Initiate a ClientHello message and generate a token. 1365 */ 1366 1367 outBuffers[0].pvBuffer = NULL; 1368 outBuffers[0].BufferType = SECBUFFER_TOKEN; 1369 outBuffers[0].cbBuffer = 0; 1370 1371 outBuffer.cBuffers = 1; 1372 outBuffer.pBuffers = outBuffers; 1373 outBuffer.ulVersion = SECBUFFER_VERSION; 1374 1375 scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry); 1376 1377 if (scRet != SEC_I_CONTINUE_NEEDED) 1378 { 1379 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1380 return (-1); 1381 } 1382 1383 /* 1384 * Send response to server if there is one. 1385 */ 1386 1387 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) 1388 { 1389 if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0) 1390 { 1391 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError())); 1392 FreeContextBuffer(outBuffers[0].pvBuffer); 1393 DeleteSecurityContext(&sspi->context); 1394 return (-1); 1395 } 1396 1397 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData)); 1398 1399 FreeContextBuffer(outBuffers[0].pvBuffer); 1400 outBuffers[0].pvBuffer = NULL; 1401 } 1402 1403 dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION | 1404 ISC_REQ_SEQUENCE_DETECT | 1405 ISC_REQ_REPLAY_DETECT | 1406 ISC_REQ_CONFIDENTIALITY | 1407 ISC_RET_EXTENDED_ERROR | 1408 ISC_REQ_ALLOCATE_MEMORY | 1409 ISC_REQ_STREAM; 1410 1411 sspi->decryptBufferUsed = 0; 1412 1413 /* 1414 * Loop until the handshake is finished or an error occurs. 1415 */ 1416 1417 scRet = SEC_I_CONTINUE_NEEDED; 1418 1419 while(scRet == SEC_I_CONTINUE_NEEDED || 1420 scRet == SEC_E_INCOMPLETE_MESSAGE || 1421 scRet == SEC_I_INCOMPLETE_CREDENTIALS) 1422 { 1423 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) 1424 { 1425 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) 1426 { 1427 BYTE *temp; /* New buffer */ 1428 1429 if (sspi->decryptBufferLength >= 262144) 1430 { 1431 WSASetLastError(E_OUTOFMEMORY); 1432 DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)"); 1433 return (-1); 1434 } 1435 1436 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) 1437 { 1438 DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096)); 1439 WSASetLastError(E_OUTOFMEMORY); 1440 return (-1); 1441 } 1442 1443 sspi->decryptBufferLength += 4096; 1444 sspi->decryptBuffer = temp; 1445 } 1446 1447 cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); 1448 1449 if (cbData < 0) 1450 { 1451 DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError())); 1452 return (-1); 1453 } 1454 else if (cbData == 0) 1455 { 1456 DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected.")); 1457 return (-1); 1458 } 1459 1460 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData)); 1461 1462 sspi->decryptBufferUsed += cbData; 1463 } 1464 1465 /* 1466 * Set up the input buffers. Buffer 0 is used to pass in data received from 1467 * the server. Schannel will consume some or all of this. Leftover data 1468 * (if any) will be placed in buffer 1 and given a buffer type of 1469 * SECBUFFER_EXTRA. 1470 */ 1471 1472 inBuffers[0].pvBuffer = sspi->decryptBuffer; 1473 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; 1474 inBuffers[0].BufferType = SECBUFFER_TOKEN; 1475 1476 inBuffers[1].pvBuffer = NULL; 1477 inBuffers[1].cbBuffer = 0; 1478 inBuffers[1].BufferType = SECBUFFER_EMPTY; 1479 1480 inBuffer.cBuffers = 2; 1481 inBuffer.pBuffers = inBuffers; 1482 inBuffer.ulVersion = SECBUFFER_VERSION; 1483 1484 /* 1485 * Set up the output buffers. These are initialized to NULL so as to make it 1486 * less likely we'll attempt to free random garbage later. 1487 */ 1488 1489 outBuffers[0].pvBuffer = NULL; 1490 outBuffers[0].BufferType = SECBUFFER_TOKEN; 1491 outBuffers[0].cbBuffer = 0; 1492 1493 outBuffer.cBuffers = 1; 1494 outBuffer.pBuffers = outBuffers; 1495 outBuffer.ulVersion = SECBUFFER_VERSION; 1496 1497 /* 1498 * Call InitializeSecurityContext. 1499 */ 1500 1501 scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry); 1502 1503 /* 1504 * If InitializeSecurityContext was successful (or if the error was one of 1505 * the special extended ones), send the contents of the output buffer to the 1506 * server. 1507 */ 1508 1509 if (scRet == SEC_E_OK || 1510 scRet == SEC_I_CONTINUE_NEEDED || 1511 FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) 1512 { 1513 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) 1514 { 1515 cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); 1516 1517 if (cbData <= 0) 1518 { 1519 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError())); 1520 FreeContextBuffer(outBuffers[0].pvBuffer); 1521 DeleteSecurityContext(&sspi->context); 1522 return (-1); 1523 } 1524 1525 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData)); 1526 1527 /* 1528 * Free output buffer. 1529 */ 1530 1531 FreeContextBuffer(outBuffers[0].pvBuffer); 1532 outBuffers[0].pvBuffer = NULL; 1533 } 1534 } 1535 1536 /* 1537 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we 1538 * need to read more data from the server and try again. 1539 */ 1540 1541 if (scRet == SEC_E_INCOMPLETE_MESSAGE) 1542 continue; 1543 1544 /* 1545 * If InitializeSecurityContext returned SEC_E_OK, then the handshake 1546 * completed successfully. 1547 */ 1548 1549 if (scRet == SEC_E_OK) 1550 { 1551 /* 1552 * If the "extra" buffer contains data, this is encrypted application 1553 * protocol layer stuff. It needs to be saved. The application layer will 1554 * later decrypt it with DecryptMessage. 1555 */ 1556 1557 DEBUG_puts("5http_sspi_client: Handshake was successful."); 1558 1559 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 1560 { 1561 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); 1562 1563 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 1564 1565 DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed)); 1566 } 1567 else 1568 sspi->decryptBufferUsed = 0; 1569 1570 /* 1571 * Bail out to quit 1572 */ 1573 1574 break; 1575 } 1576 1577 /* 1578 * Check for fatal error. 1579 */ 1580 1581 if (FAILED(scRet)) 1582 { 1583 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1584 ret = -1; 1585 break; 1586 } 1587 1588 /* 1589 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, 1590 * then the server just requested client authentication. 1591 */ 1592 1593 if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) 1594 { 1595 /* 1596 * Unimplemented 1597 */ 1598 1599 DEBUG_printf(("5http_sspi_client: server requested client credentials.")); 1600 ret = -1; 1601 break; 1602 } 1603 1604 /* 1605 * Copy any leftover data from the "extra" buffer, and go around again. 1606 */ 1607 1608 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 1609 { 1610 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); 1611 1612 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 1613 } 1614 else 1615 { 1616 sspi->decryptBufferUsed = 0; 1617 } 1618 } 1619 1620 if (!ret) 1621 { 1622 /* 1623 * Success! Get the server cert 1624 */ 1625 1626 sspi->contextInitialized = TRUE; 1627 1628 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert)); 1629 1630 if (scRet != SEC_E_OK) 1631 { 1632 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1633 return (-1); 1634 } 1635 1636 /* 1637 * Find out how big the header/trailer will be: 1638 */ 1639 1640 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes); 1641 1642 if (scRet != SEC_E_OK) 1643 { 1644 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1645 ret = -1; 1646 } 1647 } 1648 1649 return (ret); 1650} 1651 1652 1653/* 1654 * 'http_sspi_create_credential()' - Create an SSPI certificate context. 1655 */ 1656 1657static PCCERT_CONTEXT /* O - Certificate context */ 1658http_sspi_create_credential( 1659 http_credential_t *cred) /* I - Credential */ 1660{ 1661 if (cred) 1662 return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen)); 1663 else 1664 return (NULL); 1665} 1666 1667 1668/* 1669 * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store. 1670 */ 1671 1672static BOOL /* O - 1 on success, 0 on failure */ 1673http_sspi_find_credentials( 1674 http_t *http, /* I - HTTP connection */ 1675 const LPWSTR container, /* I - Cert container name */ 1676 const char *common_name) /* I - Common name of certificate */ 1677{ 1678 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1679 HCERTSTORE store = NULL; /* Certificate store */ 1680 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ 1681 DWORD dwSize = 0; /* 32 bit size */ 1682 PBYTE p = NULL; /* Temporary storage */ 1683 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 1684 /* Handle to a CSP */ 1685 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ 1686 SCHANNEL_CRED SchannelCred; /* Schannel credential data */ 1687 TimeStamp tsExpiry; /* Time stamp */ 1688 SECURITY_STATUS Status; /* Status */ 1689 BOOL ok = TRUE; /* Return value */ 1690 1691 1692 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 1693 { 1694 if (GetLastError() == NTE_EXISTS) 1695 { 1696 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 1697 { 1698 DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1699 ok = FALSE; 1700 goto cleanup; 1701 } 1702 } 1703 } 1704 1705 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); 1706 1707 if (!store) 1708 { 1709 DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1710 ok = FALSE; 1711 goto cleanup; 1712 } 1713 1714 dwSize = 0; 1715 1716 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) 1717 { 1718 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1719 ok = FALSE; 1720 goto cleanup; 1721 } 1722 1723 p = (PBYTE)malloc(dwSize); 1724 1725 if (!p) 1726 { 1727 DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize)); 1728 ok = FALSE; 1729 goto cleanup; 1730 } 1731 1732 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) 1733 { 1734 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1735 ok = FALSE; 1736 goto cleanup; 1737 } 1738 1739 sib.cbData = dwSize; 1740 sib.pbData = p; 1741 1742 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); 1743 1744 if (!storedContext) 1745 { 1746 DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name)); 1747 ok = FALSE; 1748 goto cleanup; 1749 } 1750 1751 ZeroMemory(&SchannelCred, sizeof(SchannelCred)); 1752 1753 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; 1754 SchannelCred.cCreds = 1; 1755 SchannelCred.paCred = &storedContext; 1756 1757 /* 1758 * Set supported protocols (can also be overriden in the registry...) 1759 */ 1760 1761#ifdef SP_PROT_TLS1_2_SERVER 1762 if (http->mode == _HTTP_MODE_SERVER) 1763 { 1764 if (tls_options & _HTTP_TLS_DENY_TLS10) 1765 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER; 1766 else if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1767 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER; 1768 else 1769 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER; 1770 } 1771 else 1772 { 1773 if (tls_options & _HTTP_TLS_DENY_TLS10) 1774 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT; 1775 else if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1776 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT; 1777 else 1778 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT; 1779 } 1780 1781#else 1782 if (http->mode == _HTTP_MODE_SERVER) 1783 { 1784 if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1785 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER; 1786 else 1787 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; 1788 } 1789 else 1790 { 1791 if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1792 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT; 1793 else 1794 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT; 1795 } 1796#endif /* SP_PROT_TLS1_2_SERVER */ 1797 1798 /* TODO: Support _HTTP_TLS_ALLOW_RC4 and _HTTP_TLS_ALLOW_DH options; right now we'll rely on Windows registry to enable/disable RC4/DH... */ 1799 1800 /* 1801 * Create an SSPI credential. 1802 */ 1803 1804 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry); 1805 if (Status != SEC_E_OK) 1806 { 1807 DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status))); 1808 ok = FALSE; 1809 goto cleanup; 1810 } 1811 1812cleanup: 1813 1814 /* 1815 * Cleanup 1816 */ 1817 1818 if (storedContext) 1819 CertFreeCertificateContext(storedContext); 1820 1821 if (p) 1822 free(p); 1823 1824 if (store) 1825 CertCloseStore(store, 0); 1826 1827 if (hProv) 1828 CryptReleaseContext(hProv, 0); 1829 1830 return (ok); 1831} 1832 1833 1834/* 1835 * 'http_sspi_free()' - Close a connection and free resources. 1836 */ 1837 1838static void 1839http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */ 1840{ 1841 if (!sspi) 1842 return; 1843 1844 if (sspi->contextInitialized) 1845 DeleteSecurityContext(&sspi->context); 1846 1847 if (sspi->decryptBuffer) 1848 free(sspi->decryptBuffer); 1849 1850 if (sspi->readBuffer) 1851 free(sspi->readBuffer); 1852 1853 if (sspi->writeBuffer) 1854 free(sspi->writeBuffer); 1855 1856 if (sspi->localCert) 1857 CertFreeCertificateContext(sspi->localCert); 1858 1859 if (sspi->remoteCert) 1860 CertFreeCertificateContext(sspi->remoteCert); 1861 1862 free(sspi); 1863} 1864 1865 1866/* 1867 * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store. 1868 */ 1869 1870static BOOL /* O - 1 on success, 0 on failure */ 1871http_sspi_make_credentials( 1872 _http_sspi_t *sspi, /* I - SSPI data */ 1873 const LPWSTR container, /* I - Cert container name */ 1874 const char *common_name, /* I - Common name of certificate */ 1875 _http_mode_t mode, /* I - Client or server? */ 1876 int years) /* I - Years until expiration */ 1877{ 1878 HCERTSTORE store = NULL; /* Certificate store */ 1879 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ 1880 PCCERT_CONTEXT createdContext = NULL; /* Context created by us */ 1881 DWORD dwSize = 0; /* 32 bit size */ 1882 PBYTE p = NULL; /* Temporary storage */ 1883 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 1884 /* Handle to a CSP */ 1885 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ 1886 SCHANNEL_CRED SchannelCred; /* Schannel credential data */ 1887 TimeStamp tsExpiry; /* Time stamp */ 1888 SECURITY_STATUS Status; /* Status */ 1889 HCRYPTKEY hKey = (HCRYPTKEY)NULL; /* Handle to crypto key */ 1890 CRYPT_KEY_PROV_INFO kpi; /* Key container info */ 1891 SYSTEMTIME et; /* System time */ 1892 CERT_EXTENSIONS exts; /* Array of cert extensions */ 1893 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ 1894 BOOL ok = TRUE; /* Return value */ 1895 1896 1897 DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years)); 1898 1899 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 1900 { 1901 if (GetLastError() == NTE_EXISTS) 1902 { 1903 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 1904 { 1905 DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1906 ok = FALSE; 1907 goto cleanup; 1908 } 1909 } 1910 } 1911 1912 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); 1913 1914 if (!store) 1915 { 1916 DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1917 ok = FALSE; 1918 goto cleanup; 1919 } 1920 1921 dwSize = 0; 1922 1923 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) 1924 { 1925 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1926 ok = FALSE; 1927 goto cleanup; 1928 } 1929 1930 p = (PBYTE)malloc(dwSize); 1931 1932 if (!p) 1933 { 1934 DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize)); 1935 ok = FALSE; 1936 goto cleanup; 1937 } 1938 1939 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) 1940 { 1941 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1942 ok = FALSE; 1943 goto cleanup; 1944 } 1945 1946 /* 1947 * Create a private key and self-signed certificate... 1948 */ 1949 1950 if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) 1951 { 1952 DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1953 ok = FALSE; 1954 goto cleanup; 1955 } 1956 1957 ZeroMemory(&kpi, sizeof(kpi)); 1958 kpi.pwszContainerName = (LPWSTR)container; 1959 kpi.pwszProvName = MS_DEF_PROV_W; 1960 kpi.dwProvType = PROV_RSA_FULL; 1961 kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; 1962 kpi.dwKeySpec = AT_KEYEXCHANGE; 1963 1964 GetSystemTime(&et); 1965 et.wYear += years; 1966 1967 ZeroMemory(&exts, sizeof(exts)); 1968 1969 createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts); 1970 1971 if (!createdContext) 1972 { 1973 DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1974 ok = FALSE; 1975 goto cleanup; 1976 } 1977 1978 /* 1979 * Add the created context to the named store, and associate it with the named 1980 * container... 1981 */ 1982 1983 if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext)) 1984 { 1985 DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1986 ok = FALSE; 1987 goto cleanup; 1988 } 1989 1990 ZeroMemory(&ckp, sizeof(ckp)); 1991 ckp.pwszContainerName = (LPWSTR) container; 1992 ckp.pwszProvName = MS_DEF_PROV_W; 1993 ckp.dwProvType = PROV_RSA_FULL; 1994 ckp.dwFlags = CRYPT_MACHINE_KEYSET; 1995 ckp.dwKeySpec = AT_KEYEXCHANGE; 1996 1997 if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp)) 1998 { 1999 DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 2000 ok = FALSE; 2001 goto cleanup; 2002 } 2003 2004 /* 2005 * Get a handle to use the certificate... 2006 */ 2007 2008 ZeroMemory(&SchannelCred, sizeof(SchannelCred)); 2009 2010 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; 2011 SchannelCred.cCreds = 1; 2012 SchannelCred.paCred = &storedContext; 2013 2014 /* 2015 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client. 2016 */ 2017 2018 if (mode == _HTTP_MODE_SERVER) 2019 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1; 2020 2021 /* 2022 * Create an SSPI credential. 2023 */ 2024 2025 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry); 2026 if (Status != SEC_E_OK) 2027 { 2028 DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status))); 2029 ok = FALSE; 2030 goto cleanup; 2031 } 2032 2033cleanup: 2034 2035 /* 2036 * Cleanup 2037 */ 2038 2039 if (hKey) 2040 CryptDestroyKey(hKey); 2041 2042 if (createdContext) 2043 CertFreeCertificateContext(createdContext); 2044 2045 if (storedContext) 2046 CertFreeCertificateContext(storedContext); 2047 2048 if (p) 2049 free(p); 2050 2051 if (store) 2052 CertCloseStore(store, 0); 2053 2054 if (hProv) 2055 CryptReleaseContext(hProv, 0); 2056 2057 return (ok); 2058} 2059 2060 2061/* 2062 * 'http_sspi_server()' - Negotiate a TLS connection as a server. 2063 */ 2064 2065static int /* O - 0 on success, -1 on failure */ 2066http_sspi_server(http_t *http, /* I - HTTP connection */ 2067 const char *hostname) /* I - Hostname of server */ 2068{ 2069 _http_sspi_t *sspi = http->tls; /* I - SSPI data */ 2070 char common_name[512]; /* Common name for cert */ 2071 DWORD dwSSPIFlags; /* SSL connection attributes we want */ 2072 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ 2073 TimeStamp tsExpiry; /* Time stamp */ 2074 SECURITY_STATUS scRet; /* SSPI Status */ 2075 SecBufferDesc inBuffer; /* Array of SecBuffer structs */ 2076 SecBuffer inBuffers[2]; /* Security package buffer */ 2077 SecBufferDesc outBuffer; /* Array of SecBuffer structs */ 2078 SecBuffer outBuffers[1]; /* Security package buffer */ 2079 int num = 0; /* 32 bit status value */ 2080 BOOL fInitContext = TRUE; /* Has the context been init'd? */ 2081 int ret = 0; /* Return value */ 2082 2083 2084 DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname)); 2085 2086 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | 2087 ASC_REQ_REPLAY_DETECT | 2088 ASC_REQ_CONFIDENTIALITY | 2089 ASC_REQ_EXTENDED_ERROR | 2090 ASC_REQ_ALLOCATE_MEMORY | 2091 ASC_REQ_STREAM; 2092 2093 sspi->decryptBufferUsed = 0; 2094 2095 /* 2096 * Lookup the server certificate... 2097 */ 2098 2099 snprintf(common_name, sizeof(common_name), "CN=%s", hostname); 2100 2101 if (!http_sspi_find_credentials(http, L"ServerContainer", common_name)) 2102 if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10)) 2103 { 2104 DEBUG_puts("5http_sspi_server: Unable to get server credentials."); 2105 return (-1); 2106 } 2107 2108 /* 2109 * Set OutBuffer for AcceptSecurityContext call 2110 */ 2111 2112 outBuffer.cBuffers = 1; 2113 outBuffer.pBuffers = outBuffers; 2114 outBuffer.ulVersion = SECBUFFER_VERSION; 2115 2116 scRet = SEC_I_CONTINUE_NEEDED; 2117 2118 while (scRet == SEC_I_CONTINUE_NEEDED || 2119 scRet == SEC_E_INCOMPLETE_MESSAGE || 2120 scRet == SEC_I_INCOMPLETE_CREDENTIALS) 2121 { 2122 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) 2123 { 2124 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) 2125 { 2126 BYTE *temp; /* New buffer */ 2127 2128 if (sspi->decryptBufferLength >= 262144) 2129 { 2130 WSASetLastError(E_OUTOFMEMORY); 2131 DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)"); 2132 return (-1); 2133 } 2134 2135 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) 2136 { 2137 DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096)); 2138 WSASetLastError(E_OUTOFMEMORY); 2139 return (-1); 2140 } 2141 2142 sspi->decryptBufferLength += 4096; 2143 sspi->decryptBuffer = temp; 2144 } 2145 2146 for (;;) 2147 { 2148 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); 2149 2150 if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK) 2151 Sleep(1); 2152 else 2153 break; 2154 } 2155 2156 if (num < 0) 2157 { 2158 DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError())); 2159 return (-1); 2160 } 2161 else if (num == 0) 2162 { 2163 DEBUG_puts("5http_sspi_server: client disconnected"); 2164 return (-1); 2165 } 2166 2167 DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num)); 2168 sspi->decryptBufferUsed += num; 2169 } 2170 2171 /* 2172 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process 2173 * on this run around the loop. 2174 */ 2175 2176 inBuffers[0].pvBuffer = sspi->decryptBuffer; 2177 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; 2178 inBuffers[0].BufferType = SECBUFFER_TOKEN; 2179 2180 inBuffers[1].pvBuffer = NULL; 2181 inBuffers[1].cbBuffer = 0; 2182 inBuffers[1].BufferType = SECBUFFER_EMPTY; 2183 2184 inBuffer.cBuffers = 2; 2185 inBuffer.pBuffers = inBuffers; 2186 inBuffer.ulVersion = SECBUFFER_VERSION; 2187 2188 /* 2189 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to 2190 * free random garbage at the quit. 2191 */ 2192 2193 outBuffers[0].pvBuffer = NULL; 2194 outBuffers[0].BufferType = SECBUFFER_TOKEN; 2195 outBuffers[0].cbBuffer = 0; 2196 2197 scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry); 2198 2199 fInitContext = FALSE; 2200 2201 if (scRet == SEC_E_OK || 2202 scRet == SEC_I_CONTINUE_NEEDED || 2203 (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0))) 2204 { 2205 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) 2206 { 2207 /* 2208 * Send response to server if there is one. 2209 */ 2210 2211 num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); 2212 2213 if (num <= 0) 2214 { 2215 DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError())); 2216 return (-1); 2217 } 2218 2219 DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer)); 2220 2221 FreeContextBuffer(outBuffers[0].pvBuffer); 2222 outBuffers[0].pvBuffer = NULL; 2223 } 2224 } 2225 2226 if (scRet == SEC_E_OK) 2227 { 2228 /* 2229 * If there's extra data then save it for next time we go to decrypt. 2230 */ 2231 2232 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 2233 { 2234 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); 2235 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 2236 } 2237 else 2238 { 2239 sspi->decryptBufferUsed = 0; 2240 } 2241 break; 2242 } 2243 else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE) 2244 { 2245 DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 2246 ret = -1; 2247 break; 2248 } 2249 2250 if (scRet != SEC_E_INCOMPLETE_MESSAGE && 2251 scRet != SEC_I_INCOMPLETE_CREDENTIALS) 2252 { 2253 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 2254 { 2255 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); 2256 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 2257 } 2258 else 2259 { 2260 sspi->decryptBufferUsed = 0; 2261 } 2262 } 2263 } 2264 2265 if (!ret) 2266 { 2267 sspi->contextInitialized = TRUE; 2268 2269 /* 2270 * Find out how big the header will be: 2271 */ 2272 2273 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes); 2274 2275 if (scRet != SEC_E_OK) 2276 { 2277 DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 2278 ret = -1; 2279 } 2280 } 2281 2282 return (ret); 2283} 2284 2285 2286/* 2287 * 'http_sspi_strerror()' - Return a string for the specified error code. 2288 */ 2289 2290static const char * /* O - String for error */ 2291http_sspi_strerror(char *buffer, /* I - Error message buffer */ 2292 size_t bufsize, /* I - Size of buffer */ 2293 DWORD code) /* I - Error code */ 2294{ 2295 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL)) 2296 { 2297 /* 2298 * Strip trailing CR + LF... 2299 */ 2300 2301 char *ptr; /* Pointer into error message */ 2302 2303 for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --) 2304 if (*ptr == '\n' || *ptr == '\r') 2305 *ptr = '\0'; 2306 else 2307 break; 2308 } 2309 else 2310 snprintf(buffer, bufsize, "Unknown error %x", code); 2311 2312 return (buffer); 2313} 2314 2315 2316/* 2317 * 'http_sspi_verify()' - Verify a certificate. 2318 */ 2319 2320static DWORD /* O - Error code (0 == No error) */ 2321http_sspi_verify( 2322 PCCERT_CONTEXT cert, /* I - Server certificate */ 2323 const char *common_name, /* I - Common name */ 2324 DWORD dwCertFlags) /* I - Verification flags */ 2325{ 2326 HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */ 2327 CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */ 2328 CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */ 2329 CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */ 2330 PCCERT_CHAIN_CONTEXT chainContext = NULL; 2331 /* Certificate chain */ 2332 PWSTR commonNameUnicode = NULL; 2333 /* Unicode common name */ 2334 LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, 2335 szOID_SERVER_GATED_CRYPTO, 2336 szOID_SGC_NETSCAPE }; 2337 /* How are we using this certificate? */ 2338 DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); 2339 /* Number of ites in rgszUsages */ 2340 DWORD count; /* 32 bit count variable */ 2341 DWORD status; /* Return value */ 2342#ifdef DEBUG 2343 char error[1024]; /* Error message string */ 2344#endif /* DEBUG */ 2345 2346 2347 if (!cert) 2348 return (SEC_E_WRONG_PRINCIPAL); 2349 2350 /* 2351 * Convert common name to Unicode. 2352 */ 2353 2354 if (!common_name || !*common_name) 2355 return (SEC_E_WRONG_PRINCIPAL); 2356 2357 count = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0); 2358 commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR)); 2359 if (!commonNameUnicode) 2360 return (SEC_E_INSUFFICIENT_MEMORY); 2361 2362 if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count)) 2363 { 2364 LocalFree(commonNameUnicode); 2365 return (SEC_E_WRONG_PRINCIPAL); 2366 } 2367 2368 /* 2369 * Build certificate chain. 2370 */ 2371 2372 ZeroMemory(&chainPara, sizeof(chainPara)); 2373 2374 chainPara.cbSize = sizeof(chainPara); 2375 chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; 2376 chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; 2377 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; 2378 2379 if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext)) 2380 { 2381 status = GetLastError(); 2382 2383 DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status))); 2384 2385 LocalFree(commonNameUnicode); 2386 return (status); 2387 } 2388 2389 /* 2390 * Validate certificate chain. 2391 */ 2392 2393 ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData)); 2394 httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData); 2395 httpsPolicy.dwAuthType = AUTHTYPE_SERVER; 2396 httpsPolicy.fdwChecks = dwCertFlags; 2397 httpsPolicy.pwszServerName = commonNameUnicode; 2398 2399 memset(&policyPara, 0, sizeof(policyPara)); 2400 policyPara.cbSize = sizeof(policyPara); 2401 policyPara.pvExtraPolicyPara = &httpsPolicy; 2402 2403 memset(&policyStatus, 0, sizeof(policyStatus)); 2404 policyStatus.cbSize = sizeof(policyStatus); 2405 2406 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus)) 2407 { 2408 status = GetLastError(); 2409 2410 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status))); 2411 } 2412 else if (policyStatus.dwError) 2413 status = policyStatus.dwError; 2414 else 2415 status = SEC_E_OK; 2416 2417 if (chainContext) 2418 CertFreeCertificateChain(chainContext); 2419 2420 if (commonNameUnicode) 2421 LocalFree(commonNameUnicode); 2422 2423 return (status); 2424} 2425