1 /* 2 * TLS support code for CUPS on macOS. 3 * 4 * Copyright 2007-2017 by Apple Inc. 5 * Copyright 1997-2007 by Easy Software Products, all rights reserved. 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 <spawn.h> 23 24 extern char **environ; /* @private@ */ 25 26 27 /* 28 * Constants, very secure stuff... 29 */ 30 31 #define _CUPS_CDSA_PASSWORD "42" /* CUPS keychain password */ 32 #define _CUPS_CDSA_PASSLEN 2 /* Length of keychain password */ 33 34 35 /* 36 * Local globals... 37 */ 38 39 static int tls_auto_create = 0; 40 /* Auto-create self-signed certs? */ 41 static char *tls_common_name = NULL; 42 /* Default common name */ 43 #ifdef HAVE_SECKEYCHAINOPEN 44 static int tls_cups_keychain = 0; 45 /* Opened the CUPS keychain? */ 46 static SecKeychainRef tls_keychain = NULL; 47 /* Server cert keychain */ 48 #else 49 static SecIdentityRef tls_selfsigned = NULL; 50 /* Temporary self-signed cert */ 51 #endif /* HAVE_SECKEYCHAINOPEN */ 52 static char *tls_keypath = NULL; 53 /* Server cert keychain path */ 54 static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; 55 /* Mutex for keychain/certs */ 56 static int tls_options = -1;/* Options for TLS connections */ 57 58 59 /* 60 * Local functions... 61 */ 62 63 static CFArrayRef http_cdsa_copy_server(const char *common_name); 64 static SecCertificateRef http_cdsa_create_credential(http_credential_t *credential); 65 #ifdef HAVE_SECKEYCHAINOPEN 66 static const char *http_cdsa_default_path(char *buffer, size_t bufsize); 67 static SecKeychainRef http_cdsa_open_keychain(const char *path, char *filename, size_t filesize); 68 static SecKeychainRef http_cdsa_open_system_keychain(void); 69 #endif /* HAVE_SECKEYCHAINOPEN */ 70 static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength); 71 static int http_cdsa_set_credentials(http_t *http); 72 static OSStatus http_cdsa_write(SSLConnectionRef connection, const void *data, size_t *dataLength); 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 #if defined(HAVE_SECGENERATESELFSIGNEDCERTIFICATE) 90 int status = 0; /* Return status */ 91 OSStatus err; /* Error code (if any) */ 92 CFStringRef cfcommon_name = NULL; 93 /* CF string for server name */ 94 SecIdentityRef ident = NULL; /* Identity */ 95 SecKeyRef publicKey = NULL, 96 /* Public key */ 97 privateKey = NULL; 98 /* Private key */ 99 SecCertificateRef cert = NULL; /* Self-signed certificate */ 100 CFMutableDictionaryRef keyParams = NULL; 101 /* Key generation parameters */ 102 103 104 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)); 105 106 (void)path; 107 (void)num_alt_names; 108 (void)alt_names; 109 (void)expiration_date; 110 111 if (path) 112 { 113 DEBUG_puts("1cupsMakeServerCredentials: No keychain support compiled in, returning 0."); 114 return (0); 115 } 116 117 if (tls_selfsigned) 118 { 119 DEBUG_puts("1cupsMakeServerCredentials: Using existing self-signed cert."); 120 return (1); 121 } 122 123 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 124 if (!cfcommon_name) 125 { 126 DEBUG_puts("1cupsMakeServerCredentials: Unable to create CF string of common name."); 127 goto cleanup; 128 } 129 130 /* 131 * Create a public/private key pair... 132 */ 133 134 keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 135 if (!keyParams) 136 { 137 DEBUG_puts("1cupsMakeServerCredentials: Unable to create key parameters dictionary."); 138 goto cleanup; 139 } 140 141 CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA); 142 CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048")); 143 CFDictionaryAddValue(keyParams, kSecAttrLabel, cfcommon_name); 144 145 err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey); 146 if (err != noErr) 147 { 148 DEBUG_printf(("1cupsMakeServerCredentials: Unable to generate key pair: %d.", (int)err)); 149 goto cleanup; 150 } 151 152 /* 153 * Create a self-signed certificate using the public/private key pair... 154 */ 155 156 CFIndex usageInt = kSecKeyUsageAll; 157 CFNumberRef usage = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &usageInt); 158 CFIndex lenInt = 0; 159 CFNumberRef len = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &lenInt); 160 CFTypeRef certKeys[] = { kSecCSRBasicContraintsPathLen, kSecSubjectAltName, kSecCertificateKeyUsage }; 161 CFTypeRef certValues[] = { len, cfcommon_name, usage }; 162 CFDictionaryRef certParams = CFDictionaryCreate(kCFAllocatorDefault, certKeys, certValues, sizeof(certKeys) / sizeof(certKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 163 CFRelease(usage); 164 CFRelease(len); 165 166 const void *ca_o[] = { kSecOidOrganization, CFSTR("") }; 167 const void *ca_cn[] = { kSecOidCommonName, cfcommon_name }; 168 CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); 169 CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); 170 const void *ca_dn_array[2]; 171 172 ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL); 173 ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL); 174 175 CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL); 176 177 cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey); 178 179 CFRelease(subject); 180 CFRelease(certParams); 181 182 if (!cert) 183 { 184 DEBUG_puts("1cupsMakeServerCredentials: Unable to create self-signed certificate."); 185 goto cleanup; 186 } 187 188 ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey); 189 190 if (ident) 191 { 192 _cupsMutexLock(&tls_mutex); 193 194 if (tls_selfsigned) 195 CFRelease(ident); 196 else 197 tls_selfsigned = ident; 198 199 _cupsMutexLock(&tls_mutex); 200 201 # if 0 /* Someday perhaps SecItemCopyMatching will work for identities, at which point */ 202 CFTypeRef itemKeys[] = { kSecClass, kSecAttrLabel, kSecValueRef }; 203 CFTypeRef itemValues[] = { kSecClassIdentity, cfcommon_name, ident }; 204 CFDictionaryRef itemAttrs = CFDictionaryCreate(kCFAllocatorDefault, itemKeys, itemValues, sizeof(itemKeys) / sizeof(itemKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 205 206 err = SecItemAdd(itemAttrs, NULL); 207 /* SecItemAdd consumes itemAttrs... */ 208 209 CFRelease(ident); 210 211 if (err != noErr) 212 { 213 DEBUG_printf(("1cupsMakeServerCredentials: Unable to add identity to keychain: %d.", (int)err)); 214 goto cleanup; 215 } 216 # endif /* 0 */ 217 218 status = 1; 219 } 220 else 221 DEBUG_puts("1cupsMakeServerCredentials: Unable to create identity from cert and keys."); 222 223 /* 224 * Cleanup and return... 225 */ 226 227 cleanup: 228 229 if (cfcommon_name) 230 CFRelease(cfcommon_name); 231 232 if (keyParams) 233 CFRelease(keyParams); 234 235 if (cert) 236 CFRelease(cert); 237 238 if (publicKey) 239 CFRelease(publicKey); 240 241 if (privateKey) 242 CFRelease(privateKey); 243 244 DEBUG_printf(("1cupsMakeServerCredentials: Returning %d.", status)); 245 246 return (status); 247 248 #else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ 249 int pid, /* Process ID of command */ 250 status, /* Status of command */ 251 i; /* Looping var */ 252 char command[1024], /* Command */ 253 *argv[5], /* Command-line arguments */ 254 *envp[1000], /* Environment variables */ 255 days[32], /* CERTTOOL_EXPIRATION_DAYS env var */ 256 keychain[1024], /* Keychain argument */ 257 infofile[1024], /* Type-in information for cert */ 258 filename[1024]; /* Default keychain path */ 259 cups_file_t *fp; /* Seed/info file */ 260 261 262 DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, (void *)alt_names, (int)expiration_date)); 263 264 (void)num_alt_names; 265 (void)alt_names; 266 267 if (!path) 268 path = http_cdsa_default_path(filename, sizeof(filename)); 269 270 /* 271 * Run the "certtool" command to generate a self-signed certificate... 272 */ 273 274 if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) 275 return (-1); 276 277 /* 278 * Create a file with the certificate information fields... 279 * 280 * Note: This assumes that the default questions are asked by the certtool 281 * command... 282 */ 283 284 if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) 285 return (-1); 286 287 cupsFilePrintf(fp, 288 "CUPS Self-Signed Certificate\n" 289 /* Enter key and certificate label */ 290 "r\n" /* Generate RSA key pair */ 291 "2048\n" /* 2048 bit encryption key */ 292 "y\n" /* OK (y = yes) */ 293 "b\n" /* Usage (b=signing/encryption) */ 294 "2\n" /* Sign with SHA256 */ 295 "y\n" /* OK (y = yes) */ 296 "%s\n" /* Common name */ 297 "\n" /* Country (default) */ 298 "\n" /* Organization (default) */ 299 "\n" /* Organizational unit (default) */ 300 "\n" /* State/Province (default) */ 301 "\n" /* Email address */ 302 "y\n", /* OK (y = yes) */ 303 common_name); 304 cupsFileClose(fp); 305 306 snprintf(keychain, sizeof(keychain), "k=%s", path); 307 308 argv[0] = "certtool"; 309 argv[1] = "c"; 310 argv[2] = keychain; 311 argv[3] = NULL; 312 313 snprintf(days, sizeof(days), "CERTTOOL_EXPIRATION_DAYS=%d", (int)((expiration_date - time(NULL) + 86399) / 86400)); 314 envp[0] = days; 315 for (i = 0; i < (int)(sizeof(envp) / sizeof(envp[0]) - 2) && environ[i]; i ++) 316 envp[i + 1] = environ[i]; 317 envp[i] = NULL; 318 319 posix_spawn_file_actions_t actions; /* File actions */ 320 321 posix_spawn_file_actions_init(&actions); 322 posix_spawn_file_actions_addclose(&actions, 0); 323 posix_spawn_file_actions_addopen(&actions, 0, infofile, O_RDONLY, 0); 324 posix_spawn_file_actions_addclose(&actions, 1); 325 posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0); 326 posix_spawn_file_actions_addclose(&actions, 2); 327 posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0); 328 329 if (posix_spawn(&pid, command, &actions, NULL, argv, envp)) 330 { 331 unlink(infofile); 332 return (-1); 333 } 334 335 posix_spawn_file_actions_destroy(&actions); 336 337 unlink(infofile); 338 339 while (waitpid(pid, &status, 0) < 0) 340 if (errno != EINTR) 341 { 342 status = -1; 343 break; 344 } 345 346 return (!status); 347 #endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN */ 348 } 349 350 351 /* 352 * 'cupsSetServerCredentials()' - Set the default server credentials. 353 * 354 * Note: The server credentials are used by all threads in the running process. 355 * This function is threadsafe. 356 * 357 * @since CUPS 2.0/macOS 10.10@ 358 */ 359 360 int /* O - 1 on success, 0 on failure */ 361 cupsSetServerCredentials( 362 const char *path, /* I - Keychain path or @code NULL@ for default */ 363 const char *common_name, /* I - Default common name for server */ 364 int auto_create) /* I - 1 = automatically create self-signed certificates */ 365 { 366 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); 367 368 #ifdef HAVE_SECKEYCHAINOPEN 369 char filename[1024]; /* Keychain filename */ 370 SecKeychainRef keychain = http_cdsa_open_keychain(path, filename, sizeof(filename)); 371 372 if (!keychain) 373 { 374 DEBUG_puts("1cupsSetServerCredentials: Unable to open keychain."); 375 return (0); 376 } 377 378 _cupsMutexLock(&tls_mutex); 379 380 /* 381 * Close any keychain that is currently open... 382 */ 383 384 if (tls_keychain) 385 CFRelease(tls_keychain); 386 387 if (tls_keypath) 388 _cupsStrFree(tls_keypath); 389 390 if (tls_common_name) 391 _cupsStrFree(tls_common_name); 392 393 /* 394 * Save the new keychain... 395 */ 396 397 tls_keychain = keychain; 398 tls_keypath = _cupsStrAlloc(filename); 399 tls_auto_create = auto_create; 400 tls_common_name = _cupsStrAlloc(common_name); 401 402 _cupsMutexUnlock(&tls_mutex); 403 404 DEBUG_puts("1cupsSetServerCredentials: Opened keychain, returning 1."); 405 return (1); 406 407 #else 408 if (path) 409 { 410 DEBUG_puts("1cupsSetServerCredentials: No keychain support compiled in, returning 0."); 411 return (0); 412 } 413 414 tls_auto_create = auto_create; 415 tls_common_name = _cupsStrAlloc(common_name); 416 417 return (1); 418 #endif /* HAVE_SECKEYCHAINOPEN */ 419 } 420 421 422 /* 423 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in 424 * an encrypted connection. 425 * 426 * @since CUPS 1.5/macOS 10.7@ 427 */ 428 429 int /* O - Status of call (0 = success) */ 430 httpCopyCredentials( 431 http_t *http, /* I - Connection to server */ 432 cups_array_t **credentials) /* O - Array of credentials */ 433 { 434 OSStatus error; /* Error code */ 435 SecTrustRef peerTrust; /* Peer trust reference */ 436 CFIndex count; /* Number of credentials */ 437 SecCertificateRef secCert; /* Certificate reference */ 438 CFDataRef data; /* Certificate data */ 439 int i; /* Looping var */ 440 441 442 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", (void *)http, (void *)credentials)); 443 444 if (credentials) 445 *credentials = NULL; 446 447 if (!http || !http->tls || !credentials) 448 return (-1); 449 450 if (!(error = SSLCopyPeerTrust(http->tls, &peerTrust)) && peerTrust) 451 { 452 DEBUG_printf(("2httpCopyCredentials: Peer provided %d certificates.", (int)SecTrustGetCertificateCount(peerTrust))); 453 454 if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL) 455 { 456 count = SecTrustGetCertificateCount(peerTrust); 457 458 for (i = 0; i < count; i ++) 459 { 460 secCert = SecTrustGetCertificateAtIndex(peerTrust, i); 461 462 #ifdef DEBUG 463 CFStringRef cf_name = SecCertificateCopySubjectSummary(secCert); 464 char name[1024]; 465 if (cf_name) 466 CFStringGetCString(cf_name, name, sizeof(name), kCFStringEncodingUTF8); 467 else 468 strlcpy(name, "unknown", sizeof(name)); 469 470 DEBUG_printf(("2httpCopyCredentials: Certificate %d name is \"%s\".", i, name)); 471 #endif /* DEBUG */ 472 473 if ((data = SecCertificateCopyData(secCert)) != NULL) 474 { 475 DEBUG_printf(("2httpCopyCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data))); 476 477 httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data)); 478 CFRelease(data); 479 } 480 } 481 } 482 483 CFRelease(peerTrust); 484 } 485 486 return (error); 487 } 488 489 490 /* 491 * '_httpCreateCredentials()' - Create credentials in the internal format. 492 */ 493 494 http_tls_credentials_t /* O - Internal credentials */ 495 _httpCreateCredentials( 496 cups_array_t *credentials) /* I - Array of credentials */ 497 { 498 CFMutableArrayRef peerCerts; /* Peer credentials reference */ 499 SecCertificateRef secCert; /* Certificate reference */ 500 http_credential_t *credential; /* Credential data */ 501 502 503 if (!credentials) 504 return (NULL); 505 506 if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault, 507 cupsArrayCount(credentials), 508 &kCFTypeArrayCallBacks)) == NULL) 509 return (NULL); 510 511 for (credential = (http_credential_t *)cupsArrayFirst(credentials); 512 credential; 513 credential = (http_credential_t *)cupsArrayNext(credentials)) 514 { 515 if ((secCert = http_cdsa_create_credential(credential)) != NULL) 516 { 517 CFArrayAppendValue(peerCerts, secCert); 518 CFRelease(secCert); 519 } 520 } 521 522 return (peerCerts); 523 } 524 525 526 /* 527 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. 528 * 529 * @since CUPS 2.0/macOS 10.10@ 530 */ 531 532 int /* O - 1 if valid, 0 otherwise */ 533 httpCredentialsAreValidForName( 534 cups_array_t *credentials, /* I - Credentials */ 535 const char *common_name) /* I - Name to check */ 536 { 537 SecCertificateRef secCert; /* Certificate reference */ 538 CFStringRef cfcert_name = NULL; 539 /* Certificate's common name (CF string) */ 540 char cert_name[256]; /* Certificate's common name (C string) */ 541 int valid = 1; /* Valid name? */ 542 543 544 if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 545 return (0); 546 547 /* 548 * Compare the common names... 549 */ 550 551 if ((cfcert_name = SecCertificateCopySubjectSummary(secCert)) == NULL) 552 { 553 /* 554 * Can't get common name, cannot be valid... 555 */ 556 557 valid = 0; 558 } 559 else if (CFStringGetCString(cfcert_name, cert_name, sizeof(cert_name), kCFStringEncodingUTF8) && 560 _cups_strcasecmp(common_name, cert_name)) 561 { 562 /* 563 * Not an exact match for the common name, check for wildcard certs... 564 */ 565 566 const char *domain = strchr(common_name, '.'); 567 /* Domain in common name */ 568 569 if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1)) 570 { 571 /* 572 * Not a wildcard match. 573 */ 574 575 /* TODO: Check subject alternate names */ 576 valid = 0; 577 } 578 } 579 580 if (cfcert_name) 581 CFRelease(cfcert_name); 582 583 CFRelease(secCert); 584 585 return (valid); 586 } 587 588 589 /* 590 * 'httpCredentialsGetTrust()' - Return the trust of credentials. 591 * 592 * @since CUPS 2.0/macOS 10.10@ 593 */ 594 595 http_trust_t /* O - Level of trust */ 596 httpCredentialsGetTrust( 597 cups_array_t *credentials, /* I - Credentials */ 598 const char *common_name) /* I - Common name for trust lookup */ 599 { 600 SecCertificateRef secCert; /* Certificate reference */ 601 http_trust_t trust = HTTP_TRUST_OK; 602 /* Trusted? */ 603 cups_array_t *tcreds = NULL; /* Trusted credentials */ 604 _cups_globals_t *cg = _cupsGlobals(); 605 /* Per-thread globals */ 606 607 608 if (!common_name) 609 { 610 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No common name specified."), 1); 611 return (HTTP_TRUST_UNKNOWN); 612 } 613 614 if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 615 { 616 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create credentials from array."), 1); 617 return (HTTP_TRUST_UNKNOWN); 618 } 619 620 if (cg->any_root < 0) 621 _cupsSetDefaults(); 622 623 /* 624 * Look this common name up in the default keychains... 625 */ 626 627 httpLoadCredentials(NULL, &tcreds, common_name); 628 629 if (tcreds) 630 { 631 char credentials_str[1024], /* String for incoming credentials */ 632 tcreds_str[1024]; /* String for saved credentials */ 633 634 httpCredentialsString(credentials, credentials_str, sizeof(credentials_str)); 635 httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str)); 636 637 if (strcmp(credentials_str, tcreds_str)) 638 { 639 /* 640 * Credentials don't match, let's look at the expiration date of the new 641 * credentials and allow if the new ones have a later expiration... 642 */ 643 644 if (!cg->trust_first) 645 { 646 /* 647 * Do not trust certificates on first use... 648 */ 649 650 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1); 651 652 trust = HTTP_TRUST_INVALID; 653 } 654 else if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds)) 655 { 656 /* 657 * The new credentials are not newly issued... 658 */ 659 660 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are older than stored credentials."), 1); 661 662 trust = HTTP_TRUST_INVALID; 663 } 664 else if (!httpCredentialsAreValidForName(credentials, common_name)) 665 { 666 /* 667 * The common name does not match the issued certificate... 668 */ 669 670 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are not valid for name."), 1); 671 672 trust = HTTP_TRUST_INVALID; 673 } 674 else if (httpCredentialsGetExpiration(tcreds) < time(NULL)) 675 { 676 /* 677 * Save the renewed credentials... 678 */ 679 680 trust = HTTP_TRUST_RENEWED; 681 682 httpSaveCredentials(NULL, credentials, common_name); 683 } 684 } 685 686 httpFreeCredentials(tcreds); 687 } 688 else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name)) 689 { 690 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1); 691 trust = HTTP_TRUST_INVALID; 692 } 693 else if (!cg->trust_first) 694 { 695 /* 696 * See if we have a site CA certificate we can compare... 697 */ 698 699 if (!httpLoadCredentials(NULL, &tcreds, "site")) 700 { 701 if (cupsArrayCount(credentials) != (cupsArrayCount(tcreds) + 1)) 702 { 703 /* 704 * Certificate isn't directly generated from the CA cert... 705 */ 706 707 trust = HTTP_TRUST_INVALID; 708 } 709 else 710 { 711 /* 712 * Do a tail comparison of the two certificates... 713 */ 714 715 http_credential_t *a, *b; /* Certificates */ 716 717 for (a = (http_credential_t *)cupsArrayFirst(tcreds), b = (http_credential_t *)cupsArrayIndex(credentials, 1); 718 a && b; 719 a = (http_credential_t *)cupsArrayNext(tcreds), b = (http_credential_t *)cupsArrayNext(credentials)) 720 if (a->datalen != b->datalen || memcmp(a->data, b->data, a->datalen)) 721 break; 722 723 if (a || b) 724 trust = HTTP_TRUST_INVALID; 725 } 726 727 if (trust != HTTP_TRUST_OK) 728 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials do not validate against site CA certificate."), 1); 729 } 730 else 731 { 732 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1); 733 trust = HTTP_TRUST_INVALID; 734 } 735 } 736 737 if (trust == HTTP_TRUST_OK && !cg->expired_certs && !SecCertificateIsValid(secCert, CFAbsoluteTimeGetCurrent())) 738 { 739 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials have expired."), 1); 740 trust = HTTP_TRUST_EXPIRED; 741 } 742 743 if (trust == HTTP_TRUST_OK && !cg->any_root && cupsArrayCount(credentials) == 1) 744 { 745 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1); 746 trust = HTTP_TRUST_INVALID; 747 } 748 749 CFRelease(secCert); 750 751 return (trust); 752 } 753 754 755 /* 756 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. 757 * 758 * @since CUPS 2.0/macOS 10.10@ 759 */ 760 761 time_t /* O - Expiration date of credentials */ 762 httpCredentialsGetExpiration( 763 cups_array_t *credentials) /* I - Credentials */ 764 { 765 SecCertificateRef secCert; /* Certificate reference */ 766 time_t expiration; /* Expiration date */ 767 768 769 if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 770 return (0); 771 772 expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); 773 774 CFRelease(secCert); 775 776 return (expiration); 777 } 778 779 780 /* 781 * 'httpCredentialsString()' - Return a string representing the credentials. 782 * 783 * @since CUPS 2.0/macOS 10.10@ 784 */ 785 786 size_t /* O - Total size of credentials string */ 787 httpCredentialsString( 788 cups_array_t *credentials, /* I - Credentials */ 789 char *buffer, /* I - Buffer or @code NULL@ */ 790 size_t bufsize) /* I - Size of buffer */ 791 { 792 http_credential_t *first; /* First certificate */ 793 SecCertificateRef secCert; /* Certificate reference */ 794 795 796 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", (void *)credentials, (void *)buffer, CUPS_LLCAST bufsize)); 797 798 if (!buffer) 799 return (0); 800 801 if (buffer && bufsize > 0) 802 *buffer = '\0'; 803 804 if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL && 805 (secCert = http_cdsa_create_credential(first)) != NULL) 806 { 807 CFStringRef cf_name; /* CF common name string */ 808 char name[256]; /* Common name associated with cert */ 809 time_t expiration; /* Expiration date of cert */ 810 _cups_md5_state_t md5_state; /* MD5 state */ 811 unsigned char md5_digest[16]; /* MD5 result */ 812 813 if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL) 814 { 815 CFStringGetCString(cf_name, name, (CFIndex)sizeof(name), kCFStringEncodingUTF8); 816 CFRelease(cf_name); 817 } 818 else 819 strlcpy(name, "unknown", sizeof(name)); 820 821 expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); 822 823 _cupsMD5Init(&md5_state); 824 _cupsMD5Append(&md5_state, first->data, (int)first->datalen); 825 _cupsMD5Finish(&md5_state, md5_digest); 826 827 snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", 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]); 828 829 CFRelease(secCert); 830 } 831 832 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); 833 834 return (strlen(buffer)); 835 } 836 837 838 /* 839 * '_httpFreeCredentials()' - Free internal credentials. 840 */ 841 842 void 843 _httpFreeCredentials( 844 http_tls_credentials_t credentials) /* I - Internal credentials */ 845 { 846 if (!credentials) 847 return; 848 849 CFRelease(credentials); 850 } 851 852 853 /* 854 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. 855 * 856 * @since CUPS 2.0/OS 10.10@ 857 */ 858 859 int /* O - 0 on success, -1 on error */ 860 httpLoadCredentials( 861 const char *path, /* I - Keychain path or @code NULL@ for default */ 862 cups_array_t **credentials, /* IO - Credentials */ 863 const char *common_name) /* I - Common name for credentials */ 864 { 865 OSStatus err; /* Error info */ 866 #ifdef HAVE_SECKEYCHAINOPEN 867 char filename[1024]; /* Filename for keychain */ 868 SecKeychainRef keychain = NULL,/* Keychain reference */ 869 syschain = NULL;/* System keychain */ 870 CFArrayRef list; /* Keychain list */ 871 #endif /* HAVE_SECKEYCHAINOPEN */ 872 SecCertificateRef cert = NULL; /* Certificate */ 873 CFDataRef data; /* Certificate data */ 874 SecPolicyRef policy = NULL; /* Policy ref */ 875 CFStringRef cfcommon_name = NULL; 876 /* Server name */ 877 CFMutableDictionaryRef query = NULL; /* Query qualifiers */ 878 879 880 DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name)); 881 882 if (!credentials) 883 return (-1); 884 885 *credentials = NULL; 886 887 #ifdef HAVE_SECKEYCHAINOPEN 888 keychain = http_cdsa_open_keychain(path, filename, sizeof(filename)); 889 890 if (!keychain) 891 goto cleanup; 892 893 syschain = http_cdsa_open_system_keychain(); 894 895 #else 896 if (path) 897 return (-1); 898 #endif /* HAVE_SECKEYCHAINOPEN */ 899 900 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 901 902 policy = SecPolicyCreateSSL(1, cfcommon_name); 903 904 if (cfcommon_name) 905 CFRelease(cfcommon_name); 906 907 if (!policy) 908 goto cleanup; 909 910 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 911 goto cleanup; 912 913 CFDictionaryAddValue(query, kSecClass, kSecClassCertificate); 914 CFDictionaryAddValue(query, kSecMatchPolicy, policy); 915 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); 916 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); 917 918 #ifdef HAVE_SECKEYCHAINOPEN 919 if (syschain) 920 { 921 const void *values[2] = { syschain, keychain }; 922 923 list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks); 924 } 925 else 926 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks); 927 CFDictionaryAddValue(query, kSecMatchSearchList, list); 928 CFRelease(list); 929 #endif /* HAVE_SECKEYCHAINOPEN */ 930 931 err = SecItemCopyMatching(query, (CFTypeRef *)&cert); 932 933 if (err) 934 goto cleanup; 935 936 if (CFGetTypeID(cert) != SecCertificateGetTypeID()) 937 goto cleanup; 938 939 if ((data = SecCertificateCopyData(cert)) != NULL) 940 { 941 DEBUG_printf(("1httpLoadCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data))); 942 943 *credentials = cupsArrayNew(NULL, NULL); 944 httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data)); 945 CFRelease(data); 946 } 947 948 cleanup : 949 950 #ifdef HAVE_SECKEYCHAINOPEN 951 if (keychain) 952 CFRelease(keychain); 953 954 if (syschain) 955 CFRelease(syschain); 956 #endif /* HAVE_SECKEYCHAINOPEN */ 957 if (cert) 958 CFRelease(cert); 959 if (policy) 960 CFRelease(policy); 961 if (query) 962 CFRelease(query); 963 964 DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1)); 965 966 return (*credentials ? 0 : -1); 967 } 968 969 970 /* 971 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. 972 * 973 * @since CUPS 2.0/OS 10.10@ 974 */ 975 976 int /* O - -1 on error, 0 on success */ 977 httpSaveCredentials( 978 const char *path, /* I - Keychain path or @code NULL@ for default */ 979 cups_array_t *credentials, /* I - Credentials */ 980 const char *common_name) /* I - Common name for credentials */ 981 { 982 int ret = -1; /* Return value */ 983 OSStatus err; /* Error info */ 984 #ifdef HAVE_SECKEYCHAINOPEN 985 char filename[1024]; /* Filename for keychain */ 986 SecKeychainRef keychain = NULL;/* Keychain reference */ 987 CFArrayRef list; /* Keychain list */ 988 #endif /* HAVE_SECKEYCHAINOPEN */ 989 SecCertificateRef cert = NULL; /* Certificate */ 990 CFMutableDictionaryRef attrs = NULL; /* Attributes for add */ 991 992 993 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name)); 994 if (!credentials) 995 goto cleanup; 996 997 if (!httpCredentialsAreValidForName(credentials, common_name)) 998 { 999 DEBUG_puts("1httpSaveCredentials: Common name does not match."); 1000 return (-1); 1001 } 1002 1003 if ((cert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 1004 { 1005 DEBUG_puts("1httpSaveCredentials: Unable to create certificate."); 1006 goto cleanup; 1007 } 1008 1009 #ifdef HAVE_SECKEYCHAINOPEN 1010 keychain = http_cdsa_open_keychain(path, filename, sizeof(filename)); 1011 1012 if (!keychain) 1013 goto cleanup; 1014 1015 #else 1016 if (path) 1017 return (-1); 1018 #endif /* HAVE_SECKEYCHAINOPEN */ 1019 1020 if ((attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL) 1021 { 1022 DEBUG_puts("1httpSaveCredentials: Unable to create dictionary."); 1023 goto cleanup; 1024 } 1025 1026 CFDictionaryAddValue(attrs, kSecClass, kSecClassCertificate); 1027 CFDictionaryAddValue(attrs, kSecValueRef, cert); 1028 1029 #ifdef HAVE_SECKEYCHAINOPEN 1030 if ((list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks)) == NULL) 1031 { 1032 DEBUG_puts("1httpSaveCredentials: Unable to create list of keychains."); 1033 goto cleanup; 1034 } 1035 CFDictionaryAddValue(attrs, kSecMatchSearchList, list); 1036 CFRelease(list); 1037 #endif /* HAVE_SECKEYCHAINOPEN */ 1038 1039 /* Note: SecItemAdd consumes "attrs"... */ 1040 err = SecItemAdd(attrs, NULL); 1041 DEBUG_printf(("1httpSaveCredentials: SecItemAdd returned %d.", (int)err)); 1042 1043 cleanup : 1044 1045 #ifdef HAVE_SECKEYCHAINOPEN 1046 if (keychain) 1047 CFRelease(keychain); 1048 #endif /* HAVE_SECKEYCHAINOPEN */ 1049 if (cert) 1050 CFRelease(cert); 1051 1052 DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret)); 1053 1054 return (ret); 1055 } 1056 1057 1058 /* 1059 * '_httpTLSInitialize()' - Initialize the TLS stack. 1060 */ 1061 1062 void 1063 _httpTLSInitialize(void) 1064 { 1065 /* 1066 * Nothing to do... 1067 */ 1068 } 1069 1070 1071 /* 1072 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. 1073 */ 1074 1075 size_t 1076 _httpTLSPending(http_t *http) /* I - HTTP connection */ 1077 { 1078 size_t bytes; /* Bytes that are available */ 1079 1080 1081 if (!SSLGetBufferedReadSize(http->tls, &bytes)) 1082 return (bytes); 1083 1084 return (0); 1085 } 1086 1087 1088 /* 1089 * '_httpTLSRead()' - Read from a SSL/TLS connection. 1090 */ 1091 1092 int /* O - Bytes read */ 1093 _httpTLSRead(http_t *http, /* I - HTTP connection */ 1094 char *buf, /* I - Buffer to store data */ 1095 int len) /* I - Length of buffer */ 1096 { 1097 int result; /* Return value */ 1098 OSStatus error; /* Error info */ 1099 size_t processed; /* Number of bytes processed */ 1100 1101 1102 error = SSLRead(http->tls, buf, (size_t)len, &processed); 1103 DEBUG_printf(("6_httpTLSRead: error=%d, processed=%d", (int)error, 1104 (int)processed)); 1105 switch (error) 1106 { 1107 case 0 : 1108 result = (int)processed; 1109 break; 1110 1111 case errSSLWouldBlock : 1112 if (processed) 1113 result = (int)processed; 1114 else 1115 { 1116 result = -1; 1117 errno = EINTR; 1118 } 1119 break; 1120 1121 case errSSLClosedGraceful : 1122 default : 1123 if (processed) 1124 result = (int)processed; 1125 else 1126 { 1127 result = -1; 1128 errno = EPIPE; 1129 } 1130 break; 1131 } 1132 1133 return (result); 1134 } 1135 1136 1137 /* 1138 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options. 1139 */ 1140 1141 void 1142 _httpTLSSetOptions(int options) /* I - Options */ 1143 { 1144 if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) 1145 tls_options = options; 1146 } 1147 1148 1149 /* 1150 * '_httpTLSStart()' - Set up SSL/TLS support on a connection. 1151 */ 1152 1153 int /* O - 0 on success, -1 on failure */ 1154 _httpTLSStart(http_t *http) /* I - HTTP connection */ 1155 { 1156 char hostname[256], /* Hostname */ 1157 *hostptr; /* Pointer into hostname */ 1158 _cups_globals_t *cg = _cupsGlobals(); 1159 /* Pointer to library globals */ 1160 OSStatus error; /* Error code */ 1161 const char *message = NULL;/* Error message */ 1162 cups_array_t *credentials; /* Credentials array */ 1163 cups_array_t *names; /* CUPS distinguished names */ 1164 CFArrayRef dn_array; /* CF distinguished names array */ 1165 CFIndex count; /* Number of credentials */ 1166 CFDataRef data; /* Certificate data */ 1167 int i; /* Looping var */ 1168 http_credential_t *credential; /* Credential data */ 1169 1170 1171 DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http)); 1172 1173 if (tls_options < 0) 1174 { 1175 DEBUG_puts("4_httpTLSStart: Setting defaults."); 1176 _cupsSetDefaults(); 1177 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); 1178 } 1179 1180 #ifdef HAVE_SECKEYCHAINOPEN 1181 if (http->mode == _HTTP_MODE_SERVER && !tls_keychain) 1182 { 1183 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); 1184 http->error = errno = EINVAL; 1185 http->status = HTTP_STATUS_ERROR; 1186 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); 1187 1188 return (-1); 1189 } 1190 #endif /* HAVE_SECKEYCHAINOPEN */ 1191 1192 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL) 1193 { 1194 DEBUG_puts("4_httpTLSStart: SSLCreateContext failed."); 1195 http->error = errno = ENOMEM; 1196 http->status = HTTP_STATUS_ERROR; 1197 _cupsSetHTTPError(HTTP_STATUS_ERROR); 1198 1199 return (-1); 1200 } 1201 1202 error = SSLSetConnection(http->tls, http); 1203 DEBUG_printf(("4_httpTLSStart: SSLSetConnection, error=%d", (int)error)); 1204 1205 if (!error) 1206 { 1207 error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write); 1208 DEBUG_printf(("4_httpTLSStart: SSLSetIOFuncs, error=%d", (int)error)); 1209 } 1210 1211 if (!error) 1212 { 1213 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth, 1214 true); 1215 DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d", (int)error)); 1216 } 1217 1218 if (!error) 1219 { 1220 SSLProtocol minProtocol; 1221 1222 if (tls_options & _HTTP_TLS_DENY_TLS10) 1223 minProtocol = kTLSProtocol11; 1224 else if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1225 minProtocol = kSSLProtocol3; 1226 else 1227 minProtocol = kTLSProtocol1; 1228 1229 error = SSLSetProtocolVersionMin(http->tls, minProtocol); 1230 DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error)); 1231 1232 if (!error && (tls_options & _HTTP_TLS_ONLY_TLS10)) 1233 { 1234 error = SSLSetProtocolVersionMax(http->tls, kTLSProtocol1); 1235 DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(kTLSProtocol1), error=%d", (int)error)); 1236 } 1237 } 1238 1239 # if HAVE_SSLSETENABLEDCIPHERS 1240 if (!error) 1241 { 1242 SSLCipherSuite supported[100]; /* Supported cipher suites */ 1243 size_t num_supported; /* Number of supported cipher suites */ 1244 SSLCipherSuite enabled[100]; /* Cipher suites to enable */ 1245 size_t num_enabled; /* Number of cipher suites to enable */ 1246 1247 num_supported = sizeof(supported) / sizeof(supported[0]); 1248 error = SSLGetSupportedCiphers(http->tls, supported, &num_supported); 1249 1250 if (!error) 1251 { 1252 DEBUG_printf(("4_httpTLSStart: %d cipher suites supported.", (int)num_supported)); 1253 1254 for (i = 0, num_enabled = 0; i < (int)num_supported && num_enabled < (sizeof(enabled) / sizeof(enabled[0])); i ++) 1255 { 1256 switch (supported[i]) 1257 { 1258 /* Obviously insecure cipher suites that we never want to use */ 1259 case SSL_NULL_WITH_NULL_NULL : 1260 case SSL_RSA_WITH_NULL_MD5 : 1261 case SSL_RSA_WITH_NULL_SHA : 1262 case SSL_RSA_EXPORT_WITH_RC4_40_MD5 : 1263 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 : 1264 case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA : 1265 case SSL_RSA_WITH_DES_CBC_SHA : 1266 case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA : 1267 case SSL_DH_DSS_WITH_DES_CBC_SHA : 1268 case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA : 1269 case SSL_DH_RSA_WITH_DES_CBC_SHA : 1270 case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA : 1271 case SSL_DHE_DSS_WITH_DES_CBC_SHA : 1272 case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA : 1273 case SSL_DHE_RSA_WITH_DES_CBC_SHA : 1274 case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 : 1275 case SSL_DH_anon_WITH_RC4_128_MD5 : 1276 case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA : 1277 case SSL_DH_anon_WITH_DES_CBC_SHA : 1278 case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA : 1279 case SSL_FORTEZZA_DMS_WITH_NULL_SHA : 1280 case TLS_DH_anon_WITH_AES_128_CBC_SHA : 1281 case TLS_DH_anon_WITH_AES_256_CBC_SHA : 1282 case TLS_ECDH_ECDSA_WITH_NULL_SHA : 1283 case TLS_ECDHE_RSA_WITH_NULL_SHA : 1284 case TLS_ECDH_anon_WITH_NULL_SHA : 1285 case TLS_ECDH_anon_WITH_RC4_128_SHA : 1286 case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA : 1287 case TLS_ECDH_anon_WITH_AES_128_CBC_SHA : 1288 case TLS_ECDH_anon_WITH_AES_256_CBC_SHA : 1289 case TLS_RSA_WITH_NULL_SHA256 : 1290 case TLS_DH_anon_WITH_AES_128_CBC_SHA256 : 1291 case TLS_DH_anon_WITH_AES_256_CBC_SHA256 : 1292 case TLS_PSK_WITH_NULL_SHA : 1293 case TLS_DHE_PSK_WITH_NULL_SHA : 1294 case TLS_RSA_PSK_WITH_NULL_SHA : 1295 case TLS_DH_anon_WITH_AES_128_GCM_SHA256 : 1296 case TLS_DH_anon_WITH_AES_256_GCM_SHA384 : 1297 case TLS_PSK_WITH_NULL_SHA256 : 1298 case TLS_PSK_WITH_NULL_SHA384 : 1299 case TLS_DHE_PSK_WITH_NULL_SHA256 : 1300 case TLS_DHE_PSK_WITH_NULL_SHA384 : 1301 case TLS_RSA_PSK_WITH_NULL_SHA256 : 1302 case TLS_RSA_PSK_WITH_NULL_SHA384 : 1303 case SSL_RSA_WITH_DES_CBC_MD5 : 1304 DEBUG_printf(("4_httpTLSStart: Excluding insecure cipher suite %d", supported[i])); 1305 break; 1306 1307 /* RC4 cipher suites that should only be used as a last resort */ 1308 case SSL_RSA_WITH_RC4_128_MD5 : 1309 case SSL_RSA_WITH_RC4_128_SHA : 1310 case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : 1311 case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : 1312 case TLS_ECDH_RSA_WITH_RC4_128_SHA : 1313 case TLS_ECDHE_RSA_WITH_RC4_128_SHA : 1314 case TLS_PSK_WITH_RC4_128_SHA : 1315 case TLS_DHE_PSK_WITH_RC4_128_SHA : 1316 case TLS_RSA_PSK_WITH_RC4_128_SHA : 1317 if (tls_options & _HTTP_TLS_ALLOW_RC4) 1318 enabled[num_enabled ++] = supported[i]; 1319 else 1320 DEBUG_printf(("4_httpTLSStart: Excluding RC4 cipher suite %d", supported[i])); 1321 break; 1322 1323 /* DH/DHE cipher suites that are problematic with parameters < 1024 bits */ 1324 case TLS_DH_DSS_WITH_AES_128_CBC_SHA : 1325 case TLS_DH_RSA_WITH_AES_128_CBC_SHA : 1326 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA : 1327 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : 1328 case TLS_DH_DSS_WITH_AES_256_CBC_SHA : 1329 case TLS_DH_RSA_WITH_AES_256_CBC_SHA : 1330 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA : 1331 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : 1332 case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA : 1333 case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA : 1334 case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA : 1335 case TLS_DH_DSS_WITH_AES_128_CBC_SHA256 : 1336 case TLS_DH_RSA_WITH_AES_128_CBC_SHA256 : 1337 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 : 1338 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : 1339 case TLS_DH_DSS_WITH_AES_256_CBC_SHA256 : 1340 case TLS_DH_RSA_WITH_AES_256_CBC_SHA256 : 1341 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 : 1342 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : 1343 case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA : 1344 case TLS_DHE_PSK_WITH_AES_128_CBC_SHA : 1345 case TLS_DHE_PSK_WITH_AES_256_CBC_SHA : 1346 case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 : 1347 case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 : 1348 if (tls_options & _HTTP_TLS_DENY_CBC) 1349 { 1350 DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i])); 1351 break; 1352 } 1353 1354 // case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : 1355 // case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : 1356 case TLS_DH_RSA_WITH_AES_128_GCM_SHA256 : 1357 case TLS_DH_RSA_WITH_AES_256_GCM_SHA384 : 1358 // case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 : 1359 // case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 : 1360 case TLS_DH_DSS_WITH_AES_128_GCM_SHA256 : 1361 case TLS_DH_DSS_WITH_AES_256_GCM_SHA384 : 1362 case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 : 1363 case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 : 1364 if (tls_options & _HTTP_TLS_ALLOW_DH) 1365 enabled[num_enabled ++] = supported[i]; 1366 else 1367 DEBUG_printf(("4_httpTLSStart: Excluding DH/DHE cipher suite %d", supported[i])); 1368 break; 1369 1370 case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA : 1371 case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : 1372 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : 1373 case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : 1374 case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : 1375 case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : 1376 case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : 1377 case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : 1378 case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : 1379 case TLS_RSA_WITH_3DES_EDE_CBC_SHA : 1380 case TLS_RSA_WITH_AES_128_CBC_SHA : 1381 case TLS_RSA_WITH_AES_256_CBC_SHA : 1382 if (tls_options & _HTTP_TLS_DENY_CBC) 1383 { 1384 DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i])); 1385 break; 1386 } 1387 1388 /* Anything else we'll assume is "secure" */ 1389 default : 1390 enabled[num_enabled ++] = supported[i]; 1391 break; 1392 } 1393 } 1394 1395 DEBUG_printf(("4_httpTLSStart: %d cipher suites enabled.", (int)num_enabled)); 1396 error = SSLSetEnabledCiphers(http->tls, enabled, num_enabled); 1397 } 1398 } 1399 #endif /* HAVE_SSLSETENABLEDCIPHERS */ 1400 1401 if (!error && http->mode == _HTTP_MODE_CLIENT) 1402 { 1403 /* 1404 * Client: set client-side credentials, if any... 1405 */ 1406 1407 if (cg->client_cert_cb) 1408 { 1409 error = SSLSetSessionOption(http->tls, 1410 kSSLSessionOptionBreakOnCertRequested, true); 1411 DEBUG_printf(("4_httpTLSStart: kSSLSessionOptionBreakOnCertRequested, " 1412 "error=%d", (int)error)); 1413 } 1414 else 1415 { 1416 error = http_cdsa_set_credentials(http); 1417 DEBUG_printf(("4_httpTLSStart: http_cdsa_set_credentials, error=%d", 1418 (int)error)); 1419 } 1420 } 1421 else if (!error) 1422 { 1423 /* 1424 * Server: find/create a certificate for TLS... 1425 */ 1426 1427 if (http->fields[HTTP_FIELD_HOST][0]) 1428 { 1429 /* 1430 * Use hostname for TLS upgrade... 1431 */ 1432 1433 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); 1434 } 1435 else 1436 { 1437 /* 1438 * Resolve hostname from connection address... 1439 */ 1440 1441 http_addr_t addr; /* Connection address */ 1442 socklen_t addrlen; /* Length of address */ 1443 1444 addrlen = sizeof(addr); 1445 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) 1446 { 1447 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); 1448 hostname[0] = '\0'; 1449 } 1450 else if (httpAddrLocalhost(&addr)) 1451 hostname[0] = '\0'; 1452 else 1453 { 1454 httpAddrLookup(&addr, hostname, sizeof(hostname)); 1455 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); 1456 } 1457 } 1458 1459 if (isdigit(hostname[0] & 255) || hostname[0] == '[') 1460 hostname[0] = '\0'; /* Don't allow numeric addresses */ 1461 1462 if (hostname[0]) 1463 http->tls_credentials = http_cdsa_copy_server(hostname); 1464 else if (tls_common_name) 1465 http->tls_credentials = http_cdsa_copy_server(tls_common_name); 1466 1467 if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name)) 1468 { 1469 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name)); 1470 1471 if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400)) 1472 { 1473 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); 1474 http->error = errno = EINVAL; 1475 http->status = HTTP_STATUS_ERROR; 1476 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); 1477 1478 return (-1); 1479 } 1480 1481 http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name); 1482 } 1483 1484 if (!http->tls_credentials) 1485 { 1486 DEBUG_puts("4_httpTLSStart: Unable to find server credentials."); 1487 http->error = errno = EINVAL; 1488 http->status = HTTP_STATUS_ERROR; 1489 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1); 1490 1491 return (-1); 1492 } 1493 1494 error = SSLSetCertificate(http->tls, http->tls_credentials); 1495 1496 DEBUG_printf(("4_httpTLSStart: SSLSetCertificate, error=%d", (int)error)); 1497 } 1498 1499 DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", (void *)http->tls_credentials)); 1500 1501 /* 1502 * Let the server know which hostname/domain we are trying to connect to 1503 * in case it wants to serve up a certificate with a matching common name. 1504 */ 1505 1506 if (!error && http->mode == _HTTP_MODE_CLIENT) 1507 { 1508 /* 1509 * Client: get the hostname to use for TLS... 1510 */ 1511 1512 if (httpAddrLocalhost(http->hostaddr)) 1513 { 1514 strlcpy(hostname, "localhost", sizeof(hostname)); 1515 } 1516 else 1517 { 1518 /* 1519 * Otherwise make sure the hostname we have does not end in a trailing dot. 1520 */ 1521 1522 strlcpy(hostname, http->hostname, sizeof(hostname)); 1523 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 1524 *hostptr == '.') 1525 *hostptr = '\0'; 1526 } 1527 1528 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname)); 1529 1530 DEBUG_printf(("4_httpTLSStart: SSLSetPeerDomainName, error=%d", (int)error)); 1531 } 1532 1533 if (!error) 1534 { 1535 int done = 0; /* Are we done yet? */ 1536 1537 while (!error && !done) 1538 { 1539 error = SSLHandshake(http->tls); 1540 1541 DEBUG_printf(("4_httpTLSStart: SSLHandshake returned %d.", (int)error)); 1542 1543 switch (error) 1544 { 1545 case noErr : 1546 done = 1; 1547 break; 1548 1549 case errSSLWouldBlock : 1550 error = noErr; /* Force a retry */ 1551 usleep(1000); /* in 1 millisecond */ 1552 break; 1553 1554 case errSSLServerAuthCompleted : 1555 error = 0; 1556 if (cg->server_cert_cb) 1557 { 1558 error = httpCopyCredentials(http, &credentials); 1559 if (!error) 1560 { 1561 error = (cg->server_cert_cb)(http, http->tls, credentials, 1562 cg->server_cert_data); 1563 httpFreeCredentials(credentials); 1564 } 1565 1566 DEBUG_printf(("4_httpTLSStart: Server certificate callback " 1567 "returned %d.", (int)error)); 1568 } 1569 break; 1570 1571 case errSSLClientCertRequested : 1572 error = 0; 1573 1574 if (cg->client_cert_cb) 1575 { 1576 names = NULL; 1577 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) && 1578 dn_array) 1579 { 1580 if ((names = cupsArrayNew(NULL, NULL)) != NULL) 1581 { 1582 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++) 1583 { 1584 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i); 1585 1586 if ((credential = malloc(sizeof(*credential))) != NULL) 1587 { 1588 credential->datalen = (size_t)CFDataGetLength(data); 1589 if ((credential->data = malloc(credential->datalen))) 1590 { 1591 memcpy((void *)credential->data, CFDataGetBytePtr(data), 1592 credential->datalen); 1593 cupsArrayAdd(names, credential); 1594 } 1595 else 1596 free(credential); 1597 } 1598 } 1599 } 1600 1601 CFRelease(dn_array); 1602 } 1603 1604 if (!error) 1605 { 1606 error = (cg->client_cert_cb)(http, http->tls, names, 1607 cg->client_cert_data); 1608 1609 DEBUG_printf(("4_httpTLSStart: Client certificate callback " 1610 "returned %d.", (int)error)); 1611 } 1612 1613 httpFreeCredentials(names); 1614 } 1615 break; 1616 1617 case errSSLUnknownRootCert : 1618 message = _("Unable to establish a secure connection to host " 1619 "(untrusted certificate)."); 1620 break; 1621 1622 case errSSLNoRootCert : 1623 message = _("Unable to establish a secure connection to host " 1624 "(self-signed certificate)."); 1625 break; 1626 1627 case errSSLCertExpired : 1628 message = _("Unable to establish a secure connection to host " 1629 "(expired certificate)."); 1630 break; 1631 1632 case errSSLCertNotYetValid : 1633 message = _("Unable to establish a secure connection to host " 1634 "(certificate not yet valid)."); 1635 break; 1636 1637 case errSSLHostNameMismatch : 1638 message = _("Unable to establish a secure connection to host " 1639 "(host name mismatch)."); 1640 break; 1641 1642 case errSSLXCertChainInvalid : 1643 message = _("Unable to establish a secure connection to host " 1644 "(certificate chain invalid)."); 1645 break; 1646 1647 case errSSLConnectionRefused : 1648 message = _("Unable to establish a secure connection to host " 1649 "(peer dropped connection before responding)."); 1650 break; 1651 1652 default : 1653 break; 1654 } 1655 } 1656 } 1657 1658 if (error) 1659 { 1660 http->error = error; 1661 http->status = HTTP_STATUS_ERROR; 1662 errno = ECONNREFUSED; 1663 1664 CFRelease(http->tls); 1665 http->tls = NULL; 1666 1667 /* 1668 * If an error string wasn't set by the callbacks use a generic one... 1669 */ 1670 1671 if (!message) 1672 #ifdef HAVE_CSSMERRORSTRING 1673 message = cssmErrorString(error); 1674 #else 1675 message = _("Unable to establish a secure connection to host."); 1676 #endif /* HAVE_CSSMERRORSTRING */ 1677 1678 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); 1679 1680 return (-1); 1681 } 1682 1683 return (0); 1684 } 1685 1686 1687 /* 1688 * '_httpTLSStop()' - Shut down SSL/TLS on a connection. 1689 */ 1690 1691 void 1692 _httpTLSStop(http_t *http) /* I - HTTP connection */ 1693 { 1694 while (SSLClose(http->tls) == errSSLWouldBlock) 1695 usleep(1000); 1696 1697 CFRelease(http->tls); 1698 1699 if (http->tls_credentials) 1700 CFRelease(http->tls_credentials); 1701 1702 http->tls = NULL; 1703 http->tls_credentials = NULL; 1704 } 1705 1706 1707 /* 1708 * '_httpTLSWrite()' - Write to a SSL/TLS connection. 1709 */ 1710 1711 int /* O - Bytes written */ 1712 _httpTLSWrite(http_t *http, /* I - HTTP connection */ 1713 const char *buf, /* I - Buffer holding data */ 1714 int len) /* I - Length of buffer */ 1715 { 1716 ssize_t result; /* Return value */ 1717 OSStatus error; /* Error info */ 1718 size_t processed; /* Number of bytes processed */ 1719 1720 1721 DEBUG_printf(("2_httpTLSWrite(http=%p, buf=%p, len=%d)", (void *)http, (void *)buf, len)); 1722 1723 error = SSLWrite(http->tls, buf, (size_t)len, &processed); 1724 1725 switch (error) 1726 { 1727 case 0 : 1728 result = (int)processed; 1729 break; 1730 1731 case errSSLWouldBlock : 1732 if (processed) 1733 { 1734 result = (int)processed; 1735 } 1736 else 1737 { 1738 result = -1; 1739 errno = EINTR; 1740 } 1741 break; 1742 1743 case errSSLClosedGraceful : 1744 default : 1745 if (processed) 1746 { 1747 result = (int)processed; 1748 } 1749 else 1750 { 1751 result = -1; 1752 errno = EPIPE; 1753 } 1754 break; 1755 } 1756 1757 DEBUG_printf(("3_httpTLSWrite: Returning %d.", (int)result)); 1758 1759 return ((int)result); 1760 } 1761 1762 1763 /* 1764 * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain. 1765 */ 1766 1767 static CFArrayRef /* O - Array of certificates or NULL */ 1768 http_cdsa_copy_server( 1769 const char *common_name) /* I - Server's hostname */ 1770 { 1771 #ifdef HAVE_SECKEYCHAINOPEN 1772 OSStatus err; /* Error info */ 1773 SecIdentityRef identity = NULL;/* Identity */ 1774 CFArrayRef certificates = NULL; 1775 /* Certificate array */ 1776 SecPolicyRef policy = NULL; /* Policy ref */ 1777 CFStringRef cfcommon_name = NULL; 1778 /* Server name */ 1779 CFMutableDictionaryRef query = NULL; /* Query qualifiers */ 1780 CFArrayRef list = NULL; /* Keychain list */ 1781 SecKeychainRef syschain = NULL;/* System keychain */ 1782 SecKeychainStatus status = 0; /* Keychain status */ 1783 1784 1785 DEBUG_printf(("3http_cdsa_copy_server(common_name=\"%s\")", common_name)); 1786 1787 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 1788 1789 policy = SecPolicyCreateSSL(1, cfcommon_name); 1790 1791 if (!policy) 1792 { 1793 DEBUG_puts("4http_cdsa_copy_server: Unable to create SSL policy."); 1794 goto cleanup; 1795 } 1796 1797 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 1798 { 1799 DEBUG_puts("4http_cdsa_copy_server: Unable to create query dictionary."); 1800 goto cleanup; 1801 } 1802 1803 _cupsMutexLock(&tls_mutex); 1804 1805 err = SecKeychainGetStatus(tls_keychain, &status); 1806 1807 if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain) 1808 SecKeychainUnlock(tls_keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE); 1809 1810 CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); 1811 CFDictionaryAddValue(query, kSecMatchPolicy, policy); 1812 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); 1813 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); 1814 1815 syschain = http_cdsa_open_system_keychain(); 1816 1817 if (syschain) 1818 { 1819 const void *values[2] = { syschain, tls_keychain }; 1820 1821 list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks); 1822 } 1823 else 1824 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&tls_keychain, 1, &kCFTypeArrayCallBacks); 1825 1826 CFDictionaryAddValue(query, kSecMatchSearchList, list); 1827 CFRelease(list); 1828 1829 err = SecItemCopyMatching(query, (CFTypeRef *)&identity); 1830 1831 _cupsMutexUnlock(&tls_mutex); 1832 1833 if (err != noErr) 1834 { 1835 DEBUG_printf(("4http_cdsa_copy_server: SecItemCopyMatching failed with status %d.", (int)err)); 1836 goto cleanup; 1837 } 1838 1839 if (CFGetTypeID(identity) != SecIdentityGetTypeID()) 1840 { 1841 DEBUG_puts("4http_cdsa_copy_server: Search returned something that is not an identity."); 1842 goto cleanup; 1843 } 1844 1845 if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL) 1846 { 1847 DEBUG_puts("4http_cdsa_copy_server: Unable to create array of certificates."); 1848 goto cleanup; 1849 } 1850 1851 cleanup : 1852 1853 if (syschain) 1854 CFRelease(syschain); 1855 if (identity) 1856 CFRelease(identity); 1857 if (policy) 1858 CFRelease(policy); 1859 if (cfcommon_name) 1860 CFRelease(cfcommon_name); 1861 if (query) 1862 CFRelease(query); 1863 1864 DEBUG_printf(("4http_cdsa_copy_server: Returning %p.", (void *)certificates)); 1865 1866 return (certificates); 1867 #else 1868 1869 if (!tls_selfsigned) 1870 return (NULL); 1871 1872 return (CFArrayCreate(NULL, (const void **)&tls_selfsigned, 1, &kCFTypeArrayCallBacks)); 1873 #endif /* HAVE_SECKEYCHAINOPEN */ 1874 } 1875 1876 1877 /* 1878 * 'http_cdsa_create_credential()' - Create a single credential in the internal format. 1879 */ 1880 1881 static SecCertificateRef /* O - Certificate */ 1882 http_cdsa_create_credential( 1883 http_credential_t *credential) /* I - Credential */ 1884 { 1885 if (!credential) 1886 return (NULL); 1887 1888 return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)); 1889 } 1890 1891 1892 #ifdef HAVE_SECKEYCHAINOPEN 1893 /* 1894 * 'http_cdsa_default_path()' - Get the default keychain path. 1895 */ 1896 1897 static const char * /* O - Keychain path */ 1898 http_cdsa_default_path(char *buffer, /* I - Path buffer */ 1899 size_t bufsize) /* I - Size of buffer */ 1900 { 1901 const char *home = getenv("HOME"); /* HOME environment variable */ 1902 1903 1904 /* 1905 * Determine the default keychain path. Note that the login and system 1906 * keychains are no longer accessible to user applications starting in macOS 1907 * 10.11.4 (!), so we need to create our own keychain just for CUPS. 1908 */ 1909 1910 if (getuid() && home) 1911 snprintf(buffer, bufsize, "%s/.cups/ssl.keychain", home); 1912 else 1913 strlcpy(buffer, "/etc/cups/ssl.keychain", bufsize); 1914 1915 DEBUG_printf(("1http_cdsa_default_path: Using default path \"%s\".", buffer)); 1916 1917 return (buffer); 1918 } 1919 1920 1921 /* 1922 * 'http_cdsa_open_keychain()' - Open (or create) a keychain. 1923 */ 1924 1925 static SecKeychainRef /* O - Keychain or NULL */ 1926 http_cdsa_open_keychain( 1927 const char *path, /* I - Path to keychain */ 1928 char *filename, /* I - Keychain filename */ 1929 size_t filesize) /* I - Size of filename buffer */ 1930 { 1931 SecKeychainRef keychain = NULL;/* Temporary keychain */ 1932 OSStatus err; /* Error code */ 1933 Boolean interaction; /* Interaction allowed? */ 1934 SecKeychainStatus status = 0; /* Keychain status */ 1935 1936 1937 /* 1938 * Get the keychain filename... 1939 */ 1940 1941 if (!path) 1942 { 1943 path = http_cdsa_default_path(filename, filesize); 1944 tls_cups_keychain = 1; 1945 } 1946 else 1947 { 1948 strlcpy(filename, path, filesize); 1949 tls_cups_keychain = 0; 1950 } 1951 1952 /* 1953 * Save the interaction setting and disable while we open the keychain... 1954 */ 1955 1956 SecKeychainGetUserInteractionAllowed(&interaction); 1957 SecKeychainSetUserInteractionAllowed(FALSE); 1958 1959 if (access(path, R_OK) && tls_cups_keychain) 1960 { 1961 /* 1962 * Create a new keychain at the given path... 1963 */ 1964 1965 err = SecKeychainCreate(path, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, FALSE, NULL, &keychain); 1966 } 1967 else 1968 { 1969 /* 1970 * Open the existing keychain and unlock as needed... 1971 */ 1972 1973 err = SecKeychainOpen(path, &keychain); 1974 1975 if (err == noErr) 1976 err = SecKeychainGetStatus(keychain, &status); 1977 1978 if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain) 1979 err = SecKeychainUnlock(keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE); 1980 } 1981 1982 /* 1983 * Restore interaction setting... 1984 */ 1985 1986 SecKeychainSetUserInteractionAllowed(interaction); 1987 1988 /* 1989 * Release the keychain if we had any errors... 1990 */ 1991 1992 if (err != noErr) 1993 { 1994 /* TODO: Set cups last error string */ 1995 DEBUG_printf(("4http_cdsa_open_keychain: Unable to open keychain (%d), returning NULL.", (int)err)); 1996 1997 if (keychain) 1998 { 1999 CFRelease(keychain); 2000 keychain = NULL; 2001 } 2002 } 2003 2004 /* 2005 * Return the keychain or NULL... 2006 */ 2007 2008 return (keychain); 2009 } 2010 2011 2012 /* 2013 * 'http_cdsa_open_system_keychain()' - Open the System keychain. 2014 */ 2015 2016 static SecKeychainRef 2017 http_cdsa_open_system_keychain(void) 2018 { 2019 SecKeychainRef keychain = NULL;/* Temporary keychain */ 2020 OSStatus err; /* Error code */ 2021 Boolean interaction; /* Interaction allowed? */ 2022 SecKeychainStatus status = 0; /* Keychain status */ 2023 2024 2025 /* 2026 * Save the interaction setting and disable while we open the keychain... 2027 */ 2028 2029 SecKeychainGetUserInteractionAllowed(&interaction); 2030 SecKeychainSetUserInteractionAllowed(TRUE); 2031 2032 err = SecKeychainOpen("/Library/Keychains/System.keychain", &keychain); 2033 2034 if (err == noErr) 2035 err = SecKeychainGetStatus(keychain, &status); 2036 2037 if (err == noErr && !(status & kSecUnlockStateStatus)) 2038 err = errSecInteractionNotAllowed; 2039 2040 /* 2041 * Restore interaction setting... 2042 */ 2043 2044 SecKeychainSetUserInteractionAllowed(interaction); 2045 2046 /* 2047 * Release the keychain if we had any errors... 2048 */ 2049 2050 if (err != noErr) 2051 { 2052 /* TODO: Set cups last error string */ 2053 DEBUG_printf(("4http_cdsa_open_system_keychain: Unable to open keychain (%d), returning NULL.", (int)err)); 2054 2055 if (keychain) 2056 { 2057 CFRelease(keychain); 2058 keychain = NULL; 2059 } 2060 } 2061 2062 /* 2063 * Return the keychain or NULL... 2064 */ 2065 2066 return (keychain); 2067 } 2068 #endif /* HAVE_SECKEYCHAINOPEN */ 2069 2070 2071 /* 2072 * 'http_cdsa_read()' - Read function for the CDSA library. 2073 */ 2074 2075 static OSStatus /* O - -1 on error, 0 on success */ 2076 http_cdsa_read( 2077 SSLConnectionRef connection, /* I - SSL/TLS connection */ 2078 void *data, /* I - Data buffer */ 2079 size_t *dataLength) /* IO - Number of bytes */ 2080 { 2081 OSStatus result; /* Return value */ 2082 ssize_t bytes; /* Number of bytes read */ 2083 http_t *http; /* HTTP connection */ 2084 2085 2086 http = (http_t *)connection; 2087 2088 if (!http->blocking) 2089 { 2090 /* 2091 * Make sure we have data before we read... 2092 */ 2093 2094 while (!_httpWait(http, http->wait_value, 0)) 2095 { 2096 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) 2097 continue; 2098 2099 http->error = ETIMEDOUT; 2100 return (-1); 2101 } 2102 } 2103 2104 do 2105 { 2106 bytes = recv(http->fd, data, *dataLength, 0); 2107 } 2108 while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); 2109 2110 if ((size_t)bytes == *dataLength) 2111 { 2112 result = 0; 2113 } 2114 else if (bytes > 0) 2115 { 2116 *dataLength = (size_t)bytes; 2117 result = errSSLWouldBlock; 2118 } 2119 else 2120 { 2121 *dataLength = 0; 2122 2123 if (bytes == 0) 2124 result = errSSLClosedGraceful; 2125 else if (errno == EAGAIN) 2126 result = errSSLWouldBlock; 2127 else 2128 result = errSSLClosedAbort; 2129 } 2130 2131 return (result); 2132 } 2133 2134 2135 /* 2136 * 'http_cdsa_set_credentials()' - Set the TLS credentials. 2137 */ 2138 2139 static int /* O - Status of connection */ 2140 http_cdsa_set_credentials(http_t *http) /* I - HTTP connection */ 2141 { 2142 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ 2143 OSStatus error = 0; /* Error code */ 2144 http_tls_credentials_t credentials = NULL; 2145 /* TLS credentials */ 2146 2147 2148 DEBUG_printf(("7http_tls_set_credentials(%p)", (void *)http)); 2149 2150 /* 2151 * Prefer connection specific credentials... 2152 */ 2153 2154 if ((credentials = http->tls_credentials) == NULL) 2155 credentials = cg->tls_credentials; 2156 2157 if (credentials) 2158 { 2159 error = SSLSetCertificate(http->tls, credentials); 2160 DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d", 2161 (int)error)); 2162 } 2163 else 2164 DEBUG_puts("4http_tls_set_credentials: No credentials to set."); 2165 2166 return (error); 2167 } 2168 2169 2170 /* 2171 * 'http_cdsa_write()' - Write function for the CDSA library. 2172 */ 2173 2174 static OSStatus /* O - -1 on error, 0 on success */ 2175 http_cdsa_write( 2176 SSLConnectionRef connection, /* I - SSL/TLS connection */ 2177 const void *data, /* I - Data buffer */ 2178 size_t *dataLength) /* IO - Number of bytes */ 2179 { 2180 OSStatus result; /* Return value */ 2181 ssize_t bytes; /* Number of bytes read */ 2182 http_t *http; /* HTTP connection */ 2183 2184 2185 http = (http_t *)connection; 2186 2187 do 2188 { 2189 bytes = write(http->fd, data, *dataLength); 2190 } 2191 while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); 2192 2193 if ((size_t)bytes == *dataLength) 2194 { 2195 result = 0; 2196 } 2197 else if (bytes >= 0) 2198 { 2199 *dataLength = (size_t)bytes; 2200 result = errSSLWouldBlock; 2201 } 2202 else 2203 { 2204 *dataLength = 0; 2205 2206 if (errno == EAGAIN) 2207 result = errSSLWouldBlock; 2208 else 2209 result = errSSLClosedAbort; 2210 } 2211 2212 return (result); 2213 } 2214