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