1 /* 2 * TLS support for CUPS on Windows using the Security Support Provider 3 * Interface (SSPI). 4 * 5 * Copyright 2010-2017 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 55 static int tls_options = -1;/* Options for TLS connections */ 56 57 58 /* 59 * Local functions... 60 */ 61 62 static _http_sspi_t *http_sspi_alloc(void); 63 static int http_sspi_client(http_t *http, const char *hostname); 64 static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred); 65 static BOOL http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name); 66 static void http_sspi_free(_http_sspi_t *sspi); 67 static BOOL http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years); 68 static int http_sspi_server(http_t *http, const char *hostname); 69 static void http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow); 70 static void http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow); 71 static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code); 72 static 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 81 int /* O - 1 on success, 0 on failure */ 82 cupsMakeServerCredentials( 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 117 int /* O - 1 on success, 0 on failure */ 118 cupsSetServerCredentials( 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 140 int /* O - Status of call (0 = success) */ 141 httpCopyCredentials( 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 166 http_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 180 int /* O - 1 if valid, 0 otherwise */ 181 httpCredentialsAreValidForName( 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 245 http_trust_t /* O - Level of trust */ 246 httpCredentialsGetTrust( 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 290 time_t /* O - Expiration date of credentials */ 291 httpCredentialsGetExpiration( 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 327 size_t /* O - Total size of credentials string */ 328 httpCredentialsString( 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 400 void 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 417 int /* O - 0 on success, -1 on error */ 418 httpLoadCredentials( 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 511 cleanup: 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 541 int /* O - -1 on error, 0 on success */ 542 httpSaveCredentials( 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 646 cleanup: 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 676 void 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 689 size_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 703 int /* 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 913 void 914 _httpTLSSetOptions(int options) /* I - Options */ 915 { 916 if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) 917 tls_options = options; 918 } 919 920 921 /* 922 * '_httpTLSStart()' - Set up SSL/TLS support on a connection. 923 */ 924 925 int /* O - 0 on success, -1 on failure */ 926 _httpTLSStart(http_t *http) /* I - HTTP connection */ 927 { 928 char hostname[256], /* Hostname */ 929 *hostptr; /* Pointer into hostname */ 930 931 932 DEBUG_printf(("3_httpTLSStart(http=%p)", http)); 933 934 if (tls_options < 0) 935 { 936 DEBUG_puts("4_httpTLSStart: Setting defaults."); 937 _cupsSetDefaults(); 938 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); 939 } 940 941 if ((http->tls = http_sspi_alloc()) == NULL) 942 return (-1); 943 944 if (http->mode == _HTTP_MODE_CLIENT) 945 { 946 /* 947 * Client: determine hostname... 948 */ 949 950 if (httpAddrLocalhost(http->hostaddr)) 951 { 952 strlcpy(hostname, "localhost", sizeof(hostname)); 953 } 954 else 955 { 956 /* 957 * Otherwise make sure the hostname we have does not end in a trailing dot. 958 */ 959 960 strlcpy(hostname, http->hostname, sizeof(hostname)); 961 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 962 *hostptr == '.') 963 *hostptr = '\0'; 964 } 965 966 return (http_sspi_client(http, hostname)); 967 } 968 else 969 { 970 /* 971 * Server: determine hostname to use... 972 */ 973 974 if (http->fields[HTTP_FIELD_HOST][0]) 975 { 976 /* 977 * Use hostname for TLS upgrade... 978 */ 979 980 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); 981 } 982 else 983 { 984 /* 985 * Resolve hostname from connection address... 986 */ 987 988 http_addr_t addr; /* Connection address */ 989 socklen_t addrlen; /* Length of address */ 990 991 addrlen = sizeof(addr); 992 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) 993 { 994 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); 995 hostname[0] = '\0'; 996 } 997 else if (httpAddrLocalhost(&addr)) 998 hostname[0] = '\0'; 999 else 1000 { 1001 httpAddrLookup(&addr, hostname, sizeof(hostname)); 1002 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); 1003 } 1004 } 1005 1006 return (http_sspi_server(http, hostname)); 1007 } 1008 } 1009 1010 1011 /* 1012 * '_httpTLSStop()' - Shut down SSL/TLS on a connection. 1013 */ 1014 1015 void 1016 _httpTLSStop(http_t *http) /* I - HTTP connection */ 1017 { 1018 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1019 1020 1021 if (sspi->contextInitialized && http->fd >= 0) 1022 { 1023 SecBufferDesc message; /* Array of SecBuffer struct */ 1024 SecBuffer buffers[1] = { 0 }; 1025 /* Security package buffer */ 1026 DWORD dwType; /* Type */ 1027 DWORD status; /* Status */ 1028 1029 /* 1030 * Notify schannel that we are about to close the connection. 1031 */ 1032 1033 dwType = SCHANNEL_SHUTDOWN; 1034 1035 buffers[0].pvBuffer = &dwType; 1036 buffers[0].BufferType = SECBUFFER_TOKEN; 1037 buffers[0].cbBuffer = sizeof(dwType); 1038 1039 message.cBuffers = 1; 1040 message.pBuffers = buffers; 1041 message.ulVersion = SECBUFFER_VERSION; 1042 1043 status = ApplyControlToken(&sspi->context, &message); 1044 1045 if (SUCCEEDED(status)) 1046 { 1047 PBYTE pbMessage; /* Message buffer */ 1048 DWORD cbMessage; /* Message buffer count */ 1049 DWORD cbData; /* Data count */ 1050 DWORD dwSSPIFlags; /* SSL attributes we requested */ 1051 DWORD dwSSPIOutFlags; /* SSL attributes we received */ 1052 TimeStamp tsExpiry; /* Time stamp */ 1053 1054 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | 1055 ASC_REQ_REPLAY_DETECT | 1056 ASC_REQ_CONFIDENTIALITY | 1057 ASC_REQ_EXTENDED_ERROR | 1058 ASC_REQ_ALLOCATE_MEMORY | 1059 ASC_REQ_STREAM; 1060 1061 buffers[0].pvBuffer = NULL; 1062 buffers[0].BufferType = SECBUFFER_TOKEN; 1063 buffers[0].cbBuffer = 0; 1064 1065 message.cBuffers = 1; 1066 message.pBuffers = buffers; 1067 message.ulVersion = SECBUFFER_VERSION; 1068 1069 status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL, 1070 dwSSPIFlags, SECURITY_NATIVE_DREP, NULL, 1071 &message, &dwSSPIOutFlags, &tsExpiry); 1072 1073 if (SUCCEEDED(status)) 1074 { 1075 pbMessage = buffers[0].pvBuffer; 1076 cbMessage = buffers[0].cbBuffer; 1077 1078 /* 1079 * Send the close notify message to the client. 1080 */ 1081 1082 if (pbMessage && cbMessage) 1083 { 1084 cbData = send(http->fd, pbMessage, cbMessage, 0); 1085 if ((cbData == SOCKET_ERROR) || (cbData == 0)) 1086 { 1087 status = WSAGetLastError(); 1088 DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status)); 1089 } 1090 else 1091 { 1092 FreeContextBuffer(pbMessage); 1093 } 1094 } 1095 } 1096 else 1097 { 1098 DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status))); 1099 } 1100 } 1101 else 1102 { 1103 DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status))); 1104 } 1105 } 1106 1107 http_sspi_free(sspi); 1108 1109 http->tls = NULL; 1110 } 1111 1112 1113 /* 1114 * '_httpTLSWrite()' - Write to a SSL/TLS connection. 1115 */ 1116 1117 int /* O - Bytes written */ 1118 _httpTLSWrite(http_t *http, /* I - HTTP connection */ 1119 const char *buf, /* I - Buffer holding data */ 1120 int len) /* I - Length of buffer */ 1121 { 1122 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1123 SecBufferDesc message; /* Array of SecBuffer struct */ 1124 SecBuffer buffers[4] = { 0 }; /* Security package buffer */ 1125 int bufferLen; /* Buffer length */ 1126 int bytesLeft; /* Bytes left to write */ 1127 const char *bufptr; /* Pointer into buffer */ 1128 int num = 0; /* Return value */ 1129 1130 1131 bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer; 1132 1133 if (bufferLen > sspi->writeBufferLength) 1134 { 1135 BYTE *temp; /* New buffer pointer */ 1136 1137 if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL) 1138 { 1139 DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen)); 1140 WSASetLastError(E_OUTOFMEMORY); 1141 return (-1); 1142 } 1143 1144 sspi->writeBuffer = temp; 1145 sspi->writeBufferLength = bufferLen; 1146 } 1147 1148 bytesLeft = len; 1149 bufptr = buf; 1150 1151 while (bytesLeft) 1152 { 1153 int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft); 1154 /* Size of data to write */ 1155 SECURITY_STATUS scRet; /* SSPI status */ 1156 1157 /* 1158 * Copy user data into the buffer, starting just past the header... 1159 */ 1160 1161 memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk); 1162 1163 /* 1164 * Setup the SSPI buffers 1165 */ 1166 1167 message.ulVersion = SECBUFFER_VERSION; 1168 message.cBuffers = 4; 1169 message.pBuffers = buffers; 1170 1171 buffers[0].pvBuffer = sspi->writeBuffer; 1172 buffers[0].cbBuffer = sspi->streamSizes.cbHeader; 1173 buffers[0].BufferType = SECBUFFER_STREAM_HEADER; 1174 buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader; 1175 buffers[1].cbBuffer = (unsigned long) chunk; 1176 buffers[1].BufferType = SECBUFFER_DATA; 1177 buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk; 1178 buffers[2].cbBuffer = sspi->streamSizes.cbTrailer; 1179 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; 1180 buffers[3].BufferType = SECBUFFER_EMPTY; 1181 1182 /* 1183 * Encrypt the data 1184 */ 1185 1186 scRet = EncryptMessage(&sspi->context, 0, &message, 0); 1187 1188 if (FAILED(scRet)) 1189 { 1190 DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1191 WSASetLastError(WSASYSCALLFAILURE); 1192 return (-1); 1193 } 1194 1195 /* 1196 * Send the data. Remember the size of the total data to send is the size 1197 * of the header, the size of the data the caller passed in and the size 1198 * of the trailer... 1199 */ 1200 1201 num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0); 1202 1203 if (num <= 0) 1204 { 1205 DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError())); 1206 return (num); 1207 } 1208 1209 bytesLeft -= chunk; 1210 bufptr += chunk; 1211 } 1212 1213 return (len); 1214 } 1215 1216 1217 #if 0 1218 /* 1219 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. 1220 */ 1221 1222 static int /* O - 0 on success, -1 on failure */ 1223 http_setup_ssl(http_t *http) /* I - Connection to server */ 1224 { 1225 char hostname[256], /* Hostname */ 1226 *hostptr; /* Pointer into hostname */ 1227 1228 TCHAR username[256]; /* Username returned from GetUserName() */ 1229 TCHAR commonName[256];/* Common name for certificate */ 1230 DWORD dwSize; /* 32 bit size */ 1231 1232 1233 DEBUG_printf(("7http_setup_ssl(http=%p)", http)); 1234 1235 /* 1236 * Get the hostname to use for SSL... 1237 */ 1238 1239 if (httpAddrLocalhost(http->hostaddr)) 1240 { 1241 strlcpy(hostname, "localhost", sizeof(hostname)); 1242 } 1243 else 1244 { 1245 /* 1246 * Otherwise make sure the hostname we have does not end in a trailing dot. 1247 */ 1248 1249 strlcpy(hostname, http->hostname, sizeof(hostname)); 1250 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 1251 *hostptr == '.') 1252 *hostptr = '\0'; 1253 } 1254 1255 http->tls = http_sspi_alloc(); 1256 1257 if (!http->tls) 1258 { 1259 _cupsSetHTTPError(HTTP_STATUS_ERROR); 1260 return (-1); 1261 } 1262 1263 dwSize = sizeof(username) / sizeof(TCHAR); 1264 GetUserName(username, &dwSize); 1265 _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR), 1266 sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username); 1267 1268 if (!_sspiGetCredentials(http->tls, L"ClientContainer", 1269 commonName, FALSE)) 1270 { 1271 _sspiFree(http->tls); 1272 http->tls = NULL; 1273 1274 http->error = EIO; 1275 http->status = HTTP_STATUS_ERROR; 1276 1277 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, 1278 _("Unable to establish a secure connection to host."), 1); 1279 1280 return (-1); 1281 } 1282 1283 _sspiSetAllowsAnyRoot(http->tls, TRUE); 1284 _sspiSetAllowsExpiredCerts(http->tls, TRUE); 1285 1286 if (!_sspiConnect(http->tls, hostname)) 1287 { 1288 _sspiFree(http->tls); 1289 http->tls = NULL; 1290 1291 http->error = EIO; 1292 http->status = HTTP_STATUS_ERROR; 1293 1294 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, 1295 _("Unable to establish a secure connection to host."), 1); 1296 1297 return (-1); 1298 } 1299 1300 return (0); 1301 } 1302 #endif // 0 1303 1304 1305 /* 1306 * 'http_sspi_alloc()' - Allocate SSPI object. 1307 */ 1308 1309 static _http_sspi_t * /* O - New SSPI/SSL object */ 1310 http_sspi_alloc(void) 1311 { 1312 return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1)); 1313 } 1314 1315 1316 /* 1317 * 'http_sspi_client()' - Negotiate a TLS connection as a client. 1318 */ 1319 1320 static int /* O - 0 on success, -1 on failure */ 1321 http_sspi_client(http_t *http, /* I - Client connection */ 1322 const char *hostname) /* I - Server hostname */ 1323 { 1324 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1325 DWORD dwSize; /* Size for buffer */ 1326 DWORD dwSSPIFlags; /* SSL connection attributes we want */ 1327 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ 1328 TimeStamp tsExpiry; /* Time stamp */ 1329 SECURITY_STATUS scRet; /* Status */ 1330 int cbData; /* Data count */ 1331 SecBufferDesc inBuffer; /* Array of SecBuffer structs */ 1332 SecBuffer inBuffers[2]; /* Security package buffer */ 1333 SecBufferDesc outBuffer; /* Array of SecBuffer structs */ 1334 SecBuffer outBuffers[1]; /* Security package buffer */ 1335 int ret = 0; /* Return value */ 1336 char username[1024], /* Current username */ 1337 common_name[1024]; /* CN=username */ 1338 1339 1340 DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname)); 1341 1342 dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | 1343 ISC_REQ_REPLAY_DETECT | 1344 ISC_REQ_CONFIDENTIALITY | 1345 ISC_RET_EXTENDED_ERROR | 1346 ISC_REQ_ALLOCATE_MEMORY | 1347 ISC_REQ_STREAM; 1348 1349 /* 1350 * Lookup the client certificate... 1351 */ 1352 1353 dwSize = sizeof(username); 1354 GetUserName(username, &dwSize); 1355 snprintf(common_name, sizeof(common_name), "CN=%s", username); 1356 1357 if (!http_sspi_find_credentials(http, L"ClientContainer", common_name)) 1358 if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10)) 1359 { 1360 DEBUG_puts("5http_sspi_client: Unable to get client credentials."); 1361 return (-1); 1362 } 1363 1364 /* 1365 * Initiate a ClientHello message and generate a token. 1366 */ 1367 1368 outBuffers[0].pvBuffer = NULL; 1369 outBuffers[0].BufferType = SECBUFFER_TOKEN; 1370 outBuffers[0].cbBuffer = 0; 1371 1372 outBuffer.cBuffers = 1; 1373 outBuffer.pBuffers = outBuffers; 1374 outBuffer.ulVersion = SECBUFFER_VERSION; 1375 1376 scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry); 1377 1378 if (scRet != SEC_I_CONTINUE_NEEDED) 1379 { 1380 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1381 return (-1); 1382 } 1383 1384 /* 1385 * Send response to server if there is one. 1386 */ 1387 1388 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) 1389 { 1390 if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0) 1391 { 1392 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError())); 1393 FreeContextBuffer(outBuffers[0].pvBuffer); 1394 DeleteSecurityContext(&sspi->context); 1395 return (-1); 1396 } 1397 1398 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData)); 1399 1400 FreeContextBuffer(outBuffers[0].pvBuffer); 1401 outBuffers[0].pvBuffer = NULL; 1402 } 1403 1404 dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION | 1405 ISC_REQ_SEQUENCE_DETECT | 1406 ISC_REQ_REPLAY_DETECT | 1407 ISC_REQ_CONFIDENTIALITY | 1408 ISC_RET_EXTENDED_ERROR | 1409 ISC_REQ_ALLOCATE_MEMORY | 1410 ISC_REQ_STREAM; 1411 1412 sspi->decryptBufferUsed = 0; 1413 1414 /* 1415 * Loop until the handshake is finished or an error occurs. 1416 */ 1417 1418 scRet = SEC_I_CONTINUE_NEEDED; 1419 1420 while(scRet == SEC_I_CONTINUE_NEEDED || 1421 scRet == SEC_E_INCOMPLETE_MESSAGE || 1422 scRet == SEC_I_INCOMPLETE_CREDENTIALS) 1423 { 1424 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) 1425 { 1426 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) 1427 { 1428 BYTE *temp; /* New buffer */ 1429 1430 if (sspi->decryptBufferLength >= 262144) 1431 { 1432 WSASetLastError(E_OUTOFMEMORY); 1433 DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)"); 1434 return (-1); 1435 } 1436 1437 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) 1438 { 1439 DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096)); 1440 WSASetLastError(E_OUTOFMEMORY); 1441 return (-1); 1442 } 1443 1444 sspi->decryptBufferLength += 4096; 1445 sspi->decryptBuffer = temp; 1446 } 1447 1448 cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); 1449 1450 if (cbData < 0) 1451 { 1452 DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError())); 1453 return (-1); 1454 } 1455 else if (cbData == 0) 1456 { 1457 DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected.")); 1458 return (-1); 1459 } 1460 1461 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData)); 1462 1463 sspi->decryptBufferUsed += cbData; 1464 } 1465 1466 /* 1467 * Set up the input buffers. Buffer 0 is used to pass in data received from 1468 * the server. Schannel will consume some or all of this. Leftover data 1469 * (if any) will be placed in buffer 1 and given a buffer type of 1470 * SECBUFFER_EXTRA. 1471 */ 1472 1473 inBuffers[0].pvBuffer = sspi->decryptBuffer; 1474 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; 1475 inBuffers[0].BufferType = SECBUFFER_TOKEN; 1476 1477 inBuffers[1].pvBuffer = NULL; 1478 inBuffers[1].cbBuffer = 0; 1479 inBuffers[1].BufferType = SECBUFFER_EMPTY; 1480 1481 inBuffer.cBuffers = 2; 1482 inBuffer.pBuffers = inBuffers; 1483 inBuffer.ulVersion = SECBUFFER_VERSION; 1484 1485 /* 1486 * Set up the output buffers. These are initialized to NULL so as to make it 1487 * less likely we'll attempt to free random garbage later. 1488 */ 1489 1490 outBuffers[0].pvBuffer = NULL; 1491 outBuffers[0].BufferType = SECBUFFER_TOKEN; 1492 outBuffers[0].cbBuffer = 0; 1493 1494 outBuffer.cBuffers = 1; 1495 outBuffer.pBuffers = outBuffers; 1496 outBuffer.ulVersion = SECBUFFER_VERSION; 1497 1498 /* 1499 * Call InitializeSecurityContext. 1500 */ 1501 1502 scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry); 1503 1504 /* 1505 * If InitializeSecurityContext was successful (or if the error was one of 1506 * the special extended ones), send the contents of the output buffer to the 1507 * server. 1508 */ 1509 1510 if (scRet == SEC_E_OK || 1511 scRet == SEC_I_CONTINUE_NEEDED || 1512 FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) 1513 { 1514 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) 1515 { 1516 cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); 1517 1518 if (cbData <= 0) 1519 { 1520 DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError())); 1521 FreeContextBuffer(outBuffers[0].pvBuffer); 1522 DeleteSecurityContext(&sspi->context); 1523 return (-1); 1524 } 1525 1526 DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData)); 1527 1528 /* 1529 * Free output buffer. 1530 */ 1531 1532 FreeContextBuffer(outBuffers[0].pvBuffer); 1533 outBuffers[0].pvBuffer = NULL; 1534 } 1535 } 1536 1537 /* 1538 * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we 1539 * need to read more data from the server and try again. 1540 */ 1541 1542 if (scRet == SEC_E_INCOMPLETE_MESSAGE) 1543 continue; 1544 1545 /* 1546 * If InitializeSecurityContext returned SEC_E_OK, then the handshake 1547 * completed successfully. 1548 */ 1549 1550 if (scRet == SEC_E_OK) 1551 { 1552 /* 1553 * If the "extra" buffer contains data, this is encrypted application 1554 * protocol layer stuff. It needs to be saved. The application layer will 1555 * later decrypt it with DecryptMessage. 1556 */ 1557 1558 DEBUG_puts("5http_sspi_client: Handshake was successful."); 1559 1560 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 1561 { 1562 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); 1563 1564 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 1565 1566 DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed)); 1567 } 1568 else 1569 sspi->decryptBufferUsed = 0; 1570 1571 /* 1572 * Bail out to quit 1573 */ 1574 1575 break; 1576 } 1577 1578 /* 1579 * Check for fatal error. 1580 */ 1581 1582 if (FAILED(scRet)) 1583 { 1584 DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1585 ret = -1; 1586 break; 1587 } 1588 1589 /* 1590 * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, 1591 * then the server just requested client authentication. 1592 */ 1593 1594 if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) 1595 { 1596 /* 1597 * Unimplemented 1598 */ 1599 1600 DEBUG_printf(("5http_sspi_client: server requested client credentials.")); 1601 ret = -1; 1602 break; 1603 } 1604 1605 /* 1606 * Copy any leftover data from the "extra" buffer, and go around again. 1607 */ 1608 1609 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 1610 { 1611 memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); 1612 1613 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 1614 } 1615 else 1616 { 1617 sspi->decryptBufferUsed = 0; 1618 } 1619 } 1620 1621 if (!ret) 1622 { 1623 /* 1624 * Success! Get the server cert 1625 */ 1626 1627 sspi->contextInitialized = TRUE; 1628 1629 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert)); 1630 1631 if (scRet != SEC_E_OK) 1632 { 1633 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1634 return (-1); 1635 } 1636 1637 /* 1638 * Find out how big the header/trailer will be: 1639 */ 1640 1641 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes); 1642 1643 if (scRet != SEC_E_OK) 1644 { 1645 DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 1646 ret = -1; 1647 } 1648 } 1649 1650 return (ret); 1651 } 1652 1653 1654 /* 1655 * 'http_sspi_create_credential()' - Create an SSPI certificate context. 1656 */ 1657 1658 static PCCERT_CONTEXT /* O - Certificate context */ 1659 http_sspi_create_credential( 1660 http_credential_t *cred) /* I - Credential */ 1661 { 1662 if (cred) 1663 return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen)); 1664 else 1665 return (NULL); 1666 } 1667 1668 1669 /* 1670 * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store. 1671 */ 1672 1673 static BOOL /* O - 1 on success, 0 on failure */ 1674 http_sspi_find_credentials( 1675 http_t *http, /* I - HTTP connection */ 1676 const LPWSTR container, /* I - Cert container name */ 1677 const char *common_name) /* I - Common name of certificate */ 1678 { 1679 _http_sspi_t *sspi = http->tls; /* SSPI data */ 1680 HCERTSTORE store = NULL; /* Certificate store */ 1681 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ 1682 DWORD dwSize = 0; /* 32 bit size */ 1683 PBYTE p = NULL; /* Temporary storage */ 1684 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 1685 /* Handle to a CSP */ 1686 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ 1687 SCHANNEL_CRED SchannelCred; /* Schannel credential data */ 1688 TimeStamp tsExpiry; /* Time stamp */ 1689 SECURITY_STATUS Status; /* Status */ 1690 BOOL ok = TRUE; /* Return value */ 1691 1692 1693 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 1694 { 1695 if (GetLastError() == NTE_EXISTS) 1696 { 1697 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 1698 { 1699 DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1700 ok = FALSE; 1701 goto cleanup; 1702 } 1703 } 1704 } 1705 1706 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"); 1707 1708 if (!store) 1709 { 1710 DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1711 ok = FALSE; 1712 goto cleanup; 1713 } 1714 1715 dwSize = 0; 1716 1717 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) 1718 { 1719 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1720 ok = FALSE; 1721 goto cleanup; 1722 } 1723 1724 p = (PBYTE)malloc(dwSize); 1725 1726 if (!p) 1727 { 1728 DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize)); 1729 ok = FALSE; 1730 goto cleanup; 1731 } 1732 1733 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) 1734 { 1735 DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1736 ok = FALSE; 1737 goto cleanup; 1738 } 1739 1740 sib.cbData = dwSize; 1741 sib.pbData = p; 1742 1743 storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); 1744 1745 if (!storedContext) 1746 { 1747 DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name)); 1748 ok = FALSE; 1749 goto cleanup; 1750 } 1751 1752 ZeroMemory(&SchannelCred, sizeof(SchannelCred)); 1753 1754 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; 1755 SchannelCred.cCreds = 1; 1756 SchannelCred.paCred = &storedContext; 1757 1758 /* 1759 * Set supported protocols (can also be overriden in the registry...) 1760 */ 1761 1762 #ifdef SP_PROT_TLS1_2_SERVER 1763 if (http->mode == _HTTP_MODE_SERVER) 1764 { 1765 if (tls_options & _HTTP_TLS_DENY_TLS10) 1766 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER; 1767 else if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1768 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER; 1769 else 1770 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER; 1771 } 1772 else 1773 { 1774 if (tls_options & _HTTP_TLS_DENY_TLS10) 1775 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT; 1776 else if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1777 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT; 1778 else 1779 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT; 1780 } 1781 1782 #else 1783 if (http->mode == _HTTP_MODE_SERVER) 1784 { 1785 if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1786 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER; 1787 else 1788 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; 1789 } 1790 else 1791 { 1792 if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1793 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT; 1794 else 1795 SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT; 1796 } 1797 #endif /* SP_PROT_TLS1_2_SERVER */ 1798 1799 /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */ 1800 1801 /* 1802 * Create an SSPI credential. 1803 */ 1804 1805 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry); 1806 if (Status != SEC_E_OK) 1807 { 1808 DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status))); 1809 ok = FALSE; 1810 goto cleanup; 1811 } 1812 1813 cleanup: 1814 1815 /* 1816 * Cleanup 1817 */ 1818 1819 if (storedContext) 1820 CertFreeCertificateContext(storedContext); 1821 1822 if (p) 1823 free(p); 1824 1825 if (store) 1826 CertCloseStore(store, 0); 1827 1828 if (hProv) 1829 CryptReleaseContext(hProv, 0); 1830 1831 return (ok); 1832 } 1833 1834 1835 /* 1836 * 'http_sspi_free()' - Close a connection and free resources. 1837 */ 1838 1839 static void 1840 http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */ 1841 { 1842 if (!sspi) 1843 return; 1844 1845 if (sspi->contextInitialized) 1846 DeleteSecurityContext(&sspi->context); 1847 1848 if (sspi->decryptBuffer) 1849 free(sspi->decryptBuffer); 1850 1851 if (sspi->readBuffer) 1852 free(sspi->readBuffer); 1853 1854 if (sspi->writeBuffer) 1855 free(sspi->writeBuffer); 1856 1857 if (sspi->localCert) 1858 CertFreeCertificateContext(sspi->localCert); 1859 1860 if (sspi->remoteCert) 1861 CertFreeCertificateContext(sspi->remoteCert); 1862 1863 free(sspi); 1864 } 1865 1866 1867 /* 1868 * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store. 1869 */ 1870 1871 static BOOL /* O - 1 on success, 0 on failure */ 1872 http_sspi_make_credentials( 1873 _http_sspi_t *sspi, /* I - SSPI data */ 1874 const LPWSTR container, /* I - Cert container name */ 1875 const char *common_name, /* I - Common name of certificate */ 1876 _http_mode_t mode, /* I - Client or server? */ 1877 int years) /* I - Years until expiration */ 1878 { 1879 HCERTSTORE store = NULL; /* Certificate store */ 1880 PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ 1881 PCCERT_CONTEXT createdContext = NULL; /* Context created by us */ 1882 DWORD dwSize = 0; /* 32 bit size */ 1883 PBYTE p = NULL; /* Temporary storage */ 1884 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 1885 /* Handle to a CSP */ 1886 CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ 1887 SCHANNEL_CRED SchannelCred; /* Schannel credential data */ 1888 TimeStamp tsExpiry; /* Time stamp */ 1889 SECURITY_STATUS Status; /* Status */ 1890 HCRYPTKEY hKey = (HCRYPTKEY)NULL; /* Handle to crypto key */ 1891 CRYPT_KEY_PROV_INFO kpi; /* Key container info */ 1892 SYSTEMTIME et; /* System time */ 1893 CERT_EXTENSIONS exts; /* Array of cert extensions */ 1894 CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ 1895 BOOL ok = TRUE; /* Return value */ 1896 1897 1898 DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years)); 1899 1900 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) 1901 { 1902 if (GetLastError() == NTE_EXISTS) 1903 { 1904 if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 1905 { 1906 DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1907 ok = FALSE; 1908 goto cleanup; 1909 } 1910 } 1911 } 1912 1913 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"); 1914 1915 if (!store) 1916 { 1917 DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1918 ok = FALSE; 1919 goto cleanup; 1920 } 1921 1922 dwSize = 0; 1923 1924 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) 1925 { 1926 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1927 ok = FALSE; 1928 goto cleanup; 1929 } 1930 1931 p = (PBYTE)malloc(dwSize); 1932 1933 if (!p) 1934 { 1935 DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize)); 1936 ok = FALSE; 1937 goto cleanup; 1938 } 1939 1940 if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) 1941 { 1942 DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1943 ok = FALSE; 1944 goto cleanup; 1945 } 1946 1947 /* 1948 * Create a private key and self-signed certificate... 1949 */ 1950 1951 if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) 1952 { 1953 DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1954 ok = FALSE; 1955 goto cleanup; 1956 } 1957 1958 ZeroMemory(&kpi, sizeof(kpi)); 1959 kpi.pwszContainerName = (LPWSTR)container; 1960 kpi.pwszProvName = MS_DEF_PROV_W; 1961 kpi.dwProvType = PROV_RSA_FULL; 1962 kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; 1963 kpi.dwKeySpec = AT_KEYEXCHANGE; 1964 1965 GetSystemTime(&et); 1966 et.wYear += years; 1967 1968 ZeroMemory(&exts, sizeof(exts)); 1969 1970 createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts); 1971 1972 if (!createdContext) 1973 { 1974 DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1975 ok = FALSE; 1976 goto cleanup; 1977 } 1978 1979 /* 1980 * Add the created context to the named store, and associate it with the named 1981 * container... 1982 */ 1983 1984 if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext)) 1985 { 1986 DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 1987 ok = FALSE; 1988 goto cleanup; 1989 } 1990 1991 ZeroMemory(&ckp, sizeof(ckp)); 1992 ckp.pwszContainerName = (LPWSTR) container; 1993 ckp.pwszProvName = MS_DEF_PROV_W; 1994 ckp.dwProvType = PROV_RSA_FULL; 1995 ckp.dwFlags = CRYPT_MACHINE_KEYSET; 1996 ckp.dwKeySpec = AT_KEYEXCHANGE; 1997 1998 if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp)) 1999 { 2000 DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); 2001 ok = FALSE; 2002 goto cleanup; 2003 } 2004 2005 /* 2006 * Get a handle to use the certificate... 2007 */ 2008 2009 ZeroMemory(&SchannelCred, sizeof(SchannelCred)); 2010 2011 SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; 2012 SchannelCred.cCreds = 1; 2013 SchannelCred.paCred = &storedContext; 2014 2015 /* 2016 * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client. 2017 */ 2018 2019 if (mode == _HTTP_MODE_SERVER) 2020 SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1; 2021 2022 /* 2023 * Create an SSPI credential. 2024 */ 2025 2026 Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry); 2027 if (Status != SEC_E_OK) 2028 { 2029 DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status))); 2030 ok = FALSE; 2031 goto cleanup; 2032 } 2033 2034 cleanup: 2035 2036 /* 2037 * Cleanup 2038 */ 2039 2040 if (hKey) 2041 CryptDestroyKey(hKey); 2042 2043 if (createdContext) 2044 CertFreeCertificateContext(createdContext); 2045 2046 if (storedContext) 2047 CertFreeCertificateContext(storedContext); 2048 2049 if (p) 2050 free(p); 2051 2052 if (store) 2053 CertCloseStore(store, 0); 2054 2055 if (hProv) 2056 CryptReleaseContext(hProv, 0); 2057 2058 return (ok); 2059 } 2060 2061 2062 /* 2063 * 'http_sspi_server()' - Negotiate a TLS connection as a server. 2064 */ 2065 2066 static int /* O - 0 on success, -1 on failure */ 2067 http_sspi_server(http_t *http, /* I - HTTP connection */ 2068 const char *hostname) /* I - Hostname of server */ 2069 { 2070 _http_sspi_t *sspi = http->tls; /* I - SSPI data */ 2071 char common_name[512]; /* Common name for cert */ 2072 DWORD dwSSPIFlags; /* SSL connection attributes we want */ 2073 DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ 2074 TimeStamp tsExpiry; /* Time stamp */ 2075 SECURITY_STATUS scRet; /* SSPI Status */ 2076 SecBufferDesc inBuffer; /* Array of SecBuffer structs */ 2077 SecBuffer inBuffers[2]; /* Security package buffer */ 2078 SecBufferDesc outBuffer; /* Array of SecBuffer structs */ 2079 SecBuffer outBuffers[1]; /* Security package buffer */ 2080 int num = 0; /* 32 bit status value */ 2081 BOOL fInitContext = TRUE; /* Has the context been init'd? */ 2082 int ret = 0; /* Return value */ 2083 2084 2085 DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname)); 2086 2087 dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | 2088 ASC_REQ_REPLAY_DETECT | 2089 ASC_REQ_CONFIDENTIALITY | 2090 ASC_REQ_EXTENDED_ERROR | 2091 ASC_REQ_ALLOCATE_MEMORY | 2092 ASC_REQ_STREAM; 2093 2094 sspi->decryptBufferUsed = 0; 2095 2096 /* 2097 * Lookup the server certificate... 2098 */ 2099 2100 snprintf(common_name, sizeof(common_name), "CN=%s", hostname); 2101 2102 if (!http_sspi_find_credentials(http, L"ServerContainer", common_name)) 2103 if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10)) 2104 { 2105 DEBUG_puts("5http_sspi_server: Unable to get server credentials."); 2106 return (-1); 2107 } 2108 2109 /* 2110 * Set OutBuffer for AcceptSecurityContext call 2111 */ 2112 2113 outBuffer.cBuffers = 1; 2114 outBuffer.pBuffers = outBuffers; 2115 outBuffer.ulVersion = SECBUFFER_VERSION; 2116 2117 scRet = SEC_I_CONTINUE_NEEDED; 2118 2119 while (scRet == SEC_I_CONTINUE_NEEDED || 2120 scRet == SEC_E_INCOMPLETE_MESSAGE || 2121 scRet == SEC_I_INCOMPLETE_CREDENTIALS) 2122 { 2123 if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) 2124 { 2125 if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) 2126 { 2127 BYTE *temp; /* New buffer */ 2128 2129 if (sspi->decryptBufferLength >= 262144) 2130 { 2131 WSASetLastError(E_OUTOFMEMORY); 2132 DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)"); 2133 return (-1); 2134 } 2135 2136 if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) 2137 { 2138 DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096)); 2139 WSASetLastError(E_OUTOFMEMORY); 2140 return (-1); 2141 } 2142 2143 sspi->decryptBufferLength += 4096; 2144 sspi->decryptBuffer = temp; 2145 } 2146 2147 for (;;) 2148 { 2149 num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); 2150 2151 if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK) 2152 Sleep(1); 2153 else 2154 break; 2155 } 2156 2157 if (num < 0) 2158 { 2159 DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError())); 2160 return (-1); 2161 } 2162 else if (num == 0) 2163 { 2164 DEBUG_puts("5http_sspi_server: client disconnected"); 2165 return (-1); 2166 } 2167 2168 DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num)); 2169 sspi->decryptBufferUsed += num; 2170 } 2171 2172 /* 2173 * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process 2174 * on this run around the loop. 2175 */ 2176 2177 inBuffers[0].pvBuffer = sspi->decryptBuffer; 2178 inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; 2179 inBuffers[0].BufferType = SECBUFFER_TOKEN; 2180 2181 inBuffers[1].pvBuffer = NULL; 2182 inBuffers[1].cbBuffer = 0; 2183 inBuffers[1].BufferType = SECBUFFER_EMPTY; 2184 2185 inBuffer.cBuffers = 2; 2186 inBuffer.pBuffers = inBuffers; 2187 inBuffer.ulVersion = SECBUFFER_VERSION; 2188 2189 /* 2190 * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to 2191 * free random garbage at the quit. 2192 */ 2193 2194 outBuffers[0].pvBuffer = NULL; 2195 outBuffers[0].BufferType = SECBUFFER_TOKEN; 2196 outBuffers[0].cbBuffer = 0; 2197 2198 scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry); 2199 2200 fInitContext = FALSE; 2201 2202 if (scRet == SEC_E_OK || 2203 scRet == SEC_I_CONTINUE_NEEDED || 2204 (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0))) 2205 { 2206 if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) 2207 { 2208 /* 2209 * Send response to server if there is one. 2210 */ 2211 2212 num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); 2213 2214 if (num <= 0) 2215 { 2216 DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError())); 2217 return (-1); 2218 } 2219 2220 DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer)); 2221 2222 FreeContextBuffer(outBuffers[0].pvBuffer); 2223 outBuffers[0].pvBuffer = NULL; 2224 } 2225 } 2226 2227 if (scRet == SEC_E_OK) 2228 { 2229 /* 2230 * If there's extra data then save it for next time we go to decrypt. 2231 */ 2232 2233 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 2234 { 2235 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); 2236 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 2237 } 2238 else 2239 { 2240 sspi->decryptBufferUsed = 0; 2241 } 2242 break; 2243 } 2244 else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE) 2245 { 2246 DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 2247 ret = -1; 2248 break; 2249 } 2250 2251 if (scRet != SEC_E_INCOMPLETE_MESSAGE && 2252 scRet != SEC_I_INCOMPLETE_CREDENTIALS) 2253 { 2254 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) 2255 { 2256 memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); 2257 sspi->decryptBufferUsed = inBuffers[1].cbBuffer; 2258 } 2259 else 2260 { 2261 sspi->decryptBufferUsed = 0; 2262 } 2263 } 2264 } 2265 2266 if (!ret) 2267 { 2268 sspi->contextInitialized = TRUE; 2269 2270 /* 2271 * Find out how big the header will be: 2272 */ 2273 2274 scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes); 2275 2276 if (scRet != SEC_E_OK) 2277 { 2278 DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); 2279 ret = -1; 2280 } 2281 } 2282 2283 return (ret); 2284 } 2285 2286 2287 /* 2288 * 'http_sspi_strerror()' - Return a string for the specified error code. 2289 */ 2290 2291 static const char * /* O - String for error */ 2292 http_sspi_strerror(char *buffer, /* I - Error message buffer */ 2293 size_t bufsize, /* I - Size of buffer */ 2294 DWORD code) /* I - Error code */ 2295 { 2296 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL)) 2297 { 2298 /* 2299 * Strip trailing CR + LF... 2300 */ 2301 2302 char *ptr; /* Pointer into error message */ 2303 2304 for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --) 2305 if (*ptr == '\n' || *ptr == '\r') 2306 *ptr = '\0'; 2307 else 2308 break; 2309 } 2310 else 2311 snprintf(buffer, bufsize, "Unknown error %x", code); 2312 2313 return (buffer); 2314 } 2315 2316 2317 /* 2318 * 'http_sspi_verify()' - Verify a certificate. 2319 */ 2320 2321 static DWORD /* O - Error code (0 == No error) */ 2322 http_sspi_verify( 2323 PCCERT_CONTEXT cert, /* I - Server certificate */ 2324 const char *common_name, /* I - Common name */ 2325 DWORD dwCertFlags) /* I - Verification flags */ 2326 { 2327 HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */ 2328 CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */ 2329 CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */ 2330 CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */ 2331 PCCERT_CHAIN_CONTEXT chainContext = NULL; 2332 /* Certificate chain */ 2333 PWSTR commonNameUnicode = NULL; 2334 /* Unicode common name */ 2335 LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, 2336 szOID_SERVER_GATED_CRYPTO, 2337 szOID_SGC_NETSCAPE }; 2338 /* How are we using this certificate? */ 2339 DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); 2340 /* Number of ites in rgszUsages */ 2341 DWORD count; /* 32 bit count variable */ 2342 DWORD status; /* Return value */ 2343 #ifdef DEBUG 2344 char error[1024]; /* Error message string */ 2345 #endif /* DEBUG */ 2346 2347 2348 if (!cert) 2349 return (SEC_E_WRONG_PRINCIPAL); 2350 2351 /* 2352 * Convert common name to Unicode. 2353 */ 2354 2355 if (!common_name || !*common_name) 2356 return (SEC_E_WRONG_PRINCIPAL); 2357 2358 count = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0); 2359 commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR)); 2360 if (!commonNameUnicode) 2361 return (SEC_E_INSUFFICIENT_MEMORY); 2362 2363 if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count)) 2364 { 2365 LocalFree(commonNameUnicode); 2366 return (SEC_E_WRONG_PRINCIPAL); 2367 } 2368 2369 /* 2370 * Build certificate chain. 2371 */ 2372 2373 ZeroMemory(&chainPara, sizeof(chainPara)); 2374 2375 chainPara.cbSize = sizeof(chainPara); 2376 chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; 2377 chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; 2378 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; 2379 2380 if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext)) 2381 { 2382 status = GetLastError(); 2383 2384 DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status))); 2385 2386 LocalFree(commonNameUnicode); 2387 return (status); 2388 } 2389 2390 /* 2391 * Validate certificate chain. 2392 */ 2393 2394 ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData)); 2395 httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData); 2396 httpsPolicy.dwAuthType = AUTHTYPE_SERVER; 2397 httpsPolicy.fdwChecks = dwCertFlags; 2398 httpsPolicy.pwszServerName = commonNameUnicode; 2399 2400 memset(&policyPara, 0, sizeof(policyPara)); 2401 policyPara.cbSize = sizeof(policyPara); 2402 policyPara.pvExtraPolicyPara = &httpsPolicy; 2403 2404 memset(&policyStatus, 0, sizeof(policyStatus)); 2405 policyStatus.cbSize = sizeof(policyStatus); 2406 2407 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus)) 2408 { 2409 status = GetLastError(); 2410 2411 DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status))); 2412 } 2413 else if (policyStatus.dwError) 2414 status = policyStatus.dwError; 2415 else 2416 status = SEC_E_OK; 2417 2418 if (chainContext) 2419 CertFreeCertificateChain(chainContext); 2420 2421 if (commonNameUnicode) 2422 LocalFree(commonNameUnicode); 2423 2424 return (status); 2425 } 2426