1 /* 2 * TLS support code for CUPS on macOS. 3 * 4 * Copyright 2007-2016 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; 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 tls_options = options; 1145 } 1146 1147 1148 /* 1149 * '_httpTLSStart()' - Set up SSL/TLS support on a connection. 1150 */ 1151 1152 int /* O - 0 on success, -1 on failure */ 1153 _httpTLSStart(http_t *http) /* I - HTTP connection */ 1154 { 1155 char hostname[256], /* Hostname */ 1156 *hostptr; /* Pointer into hostname */ 1157 _cups_globals_t *cg = _cupsGlobals(); 1158 /* Pointer to library globals */ 1159 OSStatus error; /* Error code */ 1160 const char *message = NULL;/* Error message */ 1161 cups_array_t *credentials; /* Credentials array */ 1162 cups_array_t *names; /* CUPS distinguished names */ 1163 CFArrayRef dn_array; /* CF distinguished names array */ 1164 CFIndex count; /* Number of credentials */ 1165 CFDataRef data; /* Certificate data */ 1166 int i; /* Looping var */ 1167 http_credential_t *credential; /* Credential data */ 1168 1169 1170 DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http)); 1171 1172 if (tls_options < 0) 1173 { 1174 DEBUG_puts("4_httpTLSStart: Setting defaults."); 1175 _cupsSetDefaults(); 1176 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); 1177 } 1178 1179 #ifdef HAVE_SECKEYCHAINOPEN 1180 if (http->mode == _HTTP_MODE_SERVER && !tls_keychain) 1181 { 1182 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); 1183 http->error = errno = EINVAL; 1184 http->status = HTTP_STATUS_ERROR; 1185 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); 1186 1187 return (-1); 1188 } 1189 #endif /* HAVE_SECKEYCHAINOPEN */ 1190 1191 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL) 1192 { 1193 DEBUG_puts("4_httpTLSStart: SSLCreateContext failed."); 1194 http->error = errno = ENOMEM; 1195 http->status = HTTP_STATUS_ERROR; 1196 _cupsSetHTTPError(HTTP_STATUS_ERROR); 1197 1198 return (-1); 1199 } 1200 1201 error = SSLSetConnection(http->tls, http); 1202 DEBUG_printf(("4_httpTLSStart: SSLSetConnection, error=%d", (int)error)); 1203 1204 if (!error) 1205 { 1206 error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write); 1207 DEBUG_printf(("4_httpTLSStart: SSLSetIOFuncs, error=%d", (int)error)); 1208 } 1209 1210 if (!error) 1211 { 1212 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth, 1213 true); 1214 DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d", (int)error)); 1215 } 1216 1217 if (!error) 1218 { 1219 SSLProtocol minProtocol; 1220 1221 if (tls_options & _HTTP_TLS_DENY_TLS10) 1222 minProtocol = kTLSProtocol11; 1223 else if (tls_options & _HTTP_TLS_ALLOW_SSL3) 1224 minProtocol = kSSLProtocol3; 1225 else 1226 minProtocol = kTLSProtocol1; 1227 1228 error = SSLSetProtocolVersionMin(http->tls, minProtocol); 1229 DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error)); 1230 } 1231 1232 # if HAVE_SSLSETENABLEDCIPHERS 1233 if (!error) 1234 { 1235 SSLCipherSuite supported[100]; /* Supported cipher suites */ 1236 size_t num_supported; /* Number of supported cipher suites */ 1237 SSLCipherSuite enabled[100]; /* Cipher suites to enable */ 1238 size_t num_enabled; /* Number of cipher suites to enable */ 1239 1240 num_supported = sizeof(supported) / sizeof(supported[0]); 1241 error = SSLGetSupportedCiphers(http->tls, supported, &num_supported); 1242 1243 if (!error) 1244 { 1245 DEBUG_printf(("4_httpTLSStart: %d cipher suites supported.", (int)num_supported)); 1246 1247 for (i = 0, num_enabled = 0; i < (int)num_supported && num_enabled < (sizeof(enabled) / sizeof(enabled[0])); i ++) 1248 { 1249 switch (supported[i]) 1250 { 1251 /* Obviously insecure cipher suites that we never want to use */ 1252 case SSL_NULL_WITH_NULL_NULL : 1253 case SSL_RSA_WITH_NULL_MD5 : 1254 case SSL_RSA_WITH_NULL_SHA : 1255 case SSL_RSA_EXPORT_WITH_RC4_40_MD5 : 1256 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 : 1257 case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA : 1258 case SSL_RSA_WITH_DES_CBC_SHA : 1259 case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA : 1260 case SSL_DH_DSS_WITH_DES_CBC_SHA : 1261 case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA : 1262 case SSL_DH_RSA_WITH_DES_CBC_SHA : 1263 case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA : 1264 case SSL_DHE_DSS_WITH_DES_CBC_SHA : 1265 case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA : 1266 case SSL_DHE_RSA_WITH_DES_CBC_SHA : 1267 case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 : 1268 case SSL_DH_anon_WITH_RC4_128_MD5 : 1269 case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA : 1270 case SSL_DH_anon_WITH_DES_CBC_SHA : 1271 case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA : 1272 case SSL_FORTEZZA_DMS_WITH_NULL_SHA : 1273 case TLS_DH_anon_WITH_AES_128_CBC_SHA : 1274 case TLS_DH_anon_WITH_AES_256_CBC_SHA : 1275 case TLS_ECDH_ECDSA_WITH_NULL_SHA : 1276 case TLS_ECDHE_RSA_WITH_NULL_SHA : 1277 case TLS_ECDH_anon_WITH_NULL_SHA : 1278 case TLS_ECDH_anon_WITH_RC4_128_SHA : 1279 case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA : 1280 case TLS_ECDH_anon_WITH_AES_128_CBC_SHA : 1281 case TLS_ECDH_anon_WITH_AES_256_CBC_SHA : 1282 case TLS_RSA_WITH_NULL_SHA256 : 1283 case TLS_DH_anon_WITH_AES_128_CBC_SHA256 : 1284 case TLS_DH_anon_WITH_AES_256_CBC_SHA256 : 1285 case TLS_PSK_WITH_NULL_SHA : 1286 case TLS_DHE_PSK_WITH_NULL_SHA : 1287 case TLS_RSA_PSK_WITH_NULL_SHA : 1288 case TLS_DH_anon_WITH_AES_128_GCM_SHA256 : 1289 case TLS_DH_anon_WITH_AES_256_GCM_SHA384 : 1290 case TLS_PSK_WITH_NULL_SHA256 : 1291 case TLS_PSK_WITH_NULL_SHA384 : 1292 case TLS_DHE_PSK_WITH_NULL_SHA256 : 1293 case TLS_DHE_PSK_WITH_NULL_SHA384 : 1294 case TLS_RSA_PSK_WITH_NULL_SHA256 : 1295 case TLS_RSA_PSK_WITH_NULL_SHA384 : 1296 case SSL_RSA_WITH_DES_CBC_MD5 : 1297 DEBUG_printf(("4_httpTLSStart: Excluding insecure cipher suite %d", supported[i])); 1298 break; 1299 1300 /* RC4 cipher suites that should only be used as a last resort */ 1301 case SSL_RSA_WITH_RC4_128_MD5 : 1302 case SSL_RSA_WITH_RC4_128_SHA : 1303 case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : 1304 case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : 1305 case TLS_ECDH_RSA_WITH_RC4_128_SHA : 1306 case TLS_ECDHE_RSA_WITH_RC4_128_SHA : 1307 case TLS_PSK_WITH_RC4_128_SHA : 1308 case TLS_DHE_PSK_WITH_RC4_128_SHA : 1309 case TLS_RSA_PSK_WITH_RC4_128_SHA : 1310 if (tls_options & _HTTP_TLS_ALLOW_RC4) 1311 enabled[num_enabled ++] = supported[i]; 1312 else 1313 DEBUG_printf(("4_httpTLSStart: Excluding RC4 cipher suite %d", supported[i])); 1314 break; 1315 1316 /* DH/DHE cipher suites that are problematic with parameters < 1024 bits */ 1317 case TLS_DH_DSS_WITH_AES_128_CBC_SHA : 1318 case TLS_DH_RSA_WITH_AES_128_CBC_SHA : 1319 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA : 1320 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : 1321 case TLS_DH_DSS_WITH_AES_256_CBC_SHA : 1322 case TLS_DH_RSA_WITH_AES_256_CBC_SHA : 1323 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA : 1324 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : 1325 case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA : 1326 case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA : 1327 // case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA : 1328 case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA : 1329 case TLS_DH_DSS_WITH_AES_128_CBC_SHA256 : 1330 case TLS_DH_RSA_WITH_AES_128_CBC_SHA256 : 1331 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 : 1332 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : 1333 case TLS_DH_DSS_WITH_AES_256_CBC_SHA256 : 1334 case TLS_DH_RSA_WITH_AES_256_CBC_SHA256 : 1335 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 : 1336 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : 1337 case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA : 1338 case TLS_DHE_PSK_WITH_AES_128_CBC_SHA : 1339 case TLS_DHE_PSK_WITH_AES_256_CBC_SHA : 1340 // case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : 1341 // case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : 1342 case TLS_DH_RSA_WITH_AES_128_GCM_SHA256 : 1343 case TLS_DH_RSA_WITH_AES_256_GCM_SHA384 : 1344 // case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 : 1345 // case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 : 1346 case TLS_DH_DSS_WITH_AES_128_GCM_SHA256 : 1347 case TLS_DH_DSS_WITH_AES_256_GCM_SHA384 : 1348 case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 : 1349 case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 : 1350 case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 : 1351 case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 : 1352 if (tls_options & _HTTP_TLS_ALLOW_DH) 1353 enabled[num_enabled ++] = supported[i]; 1354 else 1355 DEBUG_printf(("4_httpTLSStart: Excluding DH/DHE cipher suite %d", supported[i])); 1356 break; 1357 1358 /* Anything else we'll assume is secure */ 1359 default : 1360 enabled[num_enabled ++] = supported[i]; 1361 break; 1362 } 1363 } 1364 1365 DEBUG_printf(("4_httpTLSStart: %d cipher suites enabled.", (int)num_enabled)); 1366 error = SSLSetEnabledCiphers(http->tls, enabled, num_enabled); 1367 } 1368 } 1369 #endif /* HAVE_SSLSETENABLEDCIPHERS */ 1370 1371 if (!error && http->mode == _HTTP_MODE_CLIENT) 1372 { 1373 /* 1374 * Client: set client-side credentials, if any... 1375 */ 1376 1377 if (cg->client_cert_cb) 1378 { 1379 error = SSLSetSessionOption(http->tls, 1380 kSSLSessionOptionBreakOnCertRequested, true); 1381 DEBUG_printf(("4_httpTLSStart: kSSLSessionOptionBreakOnCertRequested, " 1382 "error=%d", (int)error)); 1383 } 1384 else 1385 { 1386 error = http_cdsa_set_credentials(http); 1387 DEBUG_printf(("4_httpTLSStart: http_cdsa_set_credentials, error=%d", 1388 (int)error)); 1389 } 1390 } 1391 else if (!error) 1392 { 1393 /* 1394 * Server: find/create a certificate for TLS... 1395 */ 1396 1397 if (http->fields[HTTP_FIELD_HOST][0]) 1398 { 1399 /* 1400 * Use hostname for TLS upgrade... 1401 */ 1402 1403 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); 1404 } 1405 else 1406 { 1407 /* 1408 * Resolve hostname from connection address... 1409 */ 1410 1411 http_addr_t addr; /* Connection address */ 1412 socklen_t addrlen; /* Length of address */ 1413 1414 addrlen = sizeof(addr); 1415 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) 1416 { 1417 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); 1418 hostname[0] = '\0'; 1419 } 1420 else if (httpAddrLocalhost(&addr)) 1421 hostname[0] = '\0'; 1422 else 1423 { 1424 httpAddrLookup(&addr, hostname, sizeof(hostname)); 1425 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); 1426 } 1427 } 1428 1429 if (isdigit(hostname[0] & 255) || hostname[0] == '[') 1430 hostname[0] = '\0'; /* Don't allow numeric addresses */ 1431 1432 if (hostname[0]) 1433 http->tls_credentials = http_cdsa_copy_server(hostname); 1434 else if (tls_common_name) 1435 http->tls_credentials = http_cdsa_copy_server(tls_common_name); 1436 1437 if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name)) 1438 { 1439 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name)); 1440 1441 if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400)) 1442 { 1443 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); 1444 http->error = errno = EINVAL; 1445 http->status = HTTP_STATUS_ERROR; 1446 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); 1447 1448 return (-1); 1449 } 1450 1451 http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name); 1452 } 1453 1454 if (!http->tls_credentials) 1455 { 1456 DEBUG_puts("4_httpTLSStart: Unable to find server credentials."); 1457 http->error = errno = EINVAL; 1458 http->status = HTTP_STATUS_ERROR; 1459 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1); 1460 1461 return (-1); 1462 } 1463 1464 error = SSLSetCertificate(http->tls, http->tls_credentials); 1465 1466 DEBUG_printf(("4_httpTLSStart: SSLSetCertificate, error=%d", (int)error)); 1467 } 1468 1469 DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", (void *)http->tls_credentials)); 1470 1471 /* 1472 * Let the server know which hostname/domain we are trying to connect to 1473 * in case it wants to serve up a certificate with a matching common name. 1474 */ 1475 1476 if (!error && http->mode == _HTTP_MODE_CLIENT) 1477 { 1478 /* 1479 * Client: get the hostname to use for TLS... 1480 */ 1481 1482 if (httpAddrLocalhost(http->hostaddr)) 1483 { 1484 strlcpy(hostname, "localhost", sizeof(hostname)); 1485 } 1486 else 1487 { 1488 /* 1489 * Otherwise make sure the hostname we have does not end in a trailing dot. 1490 */ 1491 1492 strlcpy(hostname, http->hostname, sizeof(hostname)); 1493 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 1494 *hostptr == '.') 1495 *hostptr = '\0'; 1496 } 1497 1498 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname)); 1499 1500 DEBUG_printf(("4_httpTLSStart: SSLSetPeerDomainName, error=%d", (int)error)); 1501 } 1502 1503 if (!error) 1504 { 1505 int done = 0; /* Are we done yet? */ 1506 1507 while (!error && !done) 1508 { 1509 error = SSLHandshake(http->tls); 1510 1511 DEBUG_printf(("4_httpTLSStart: SSLHandshake returned %d.", (int)error)); 1512 1513 switch (error) 1514 { 1515 case noErr : 1516 done = 1; 1517 break; 1518 1519 case errSSLWouldBlock : 1520 error = noErr; /* Force a retry */ 1521 usleep(1000); /* in 1 millisecond */ 1522 break; 1523 1524 case errSSLServerAuthCompleted : 1525 error = 0; 1526 if (cg->server_cert_cb) 1527 { 1528 error = httpCopyCredentials(http, &credentials); 1529 if (!error) 1530 { 1531 error = (cg->server_cert_cb)(http, http->tls, credentials, 1532 cg->server_cert_data); 1533 httpFreeCredentials(credentials); 1534 } 1535 1536 DEBUG_printf(("4_httpTLSStart: Server certificate callback " 1537 "returned %d.", (int)error)); 1538 } 1539 break; 1540 1541 case errSSLClientCertRequested : 1542 error = 0; 1543 1544 if (cg->client_cert_cb) 1545 { 1546 names = NULL; 1547 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) && 1548 dn_array) 1549 { 1550 if ((names = cupsArrayNew(NULL, NULL)) != NULL) 1551 { 1552 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++) 1553 { 1554 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i); 1555 1556 if ((credential = malloc(sizeof(*credential))) != NULL) 1557 { 1558 credential->datalen = (size_t)CFDataGetLength(data); 1559 if ((credential->data = malloc(credential->datalen))) 1560 { 1561 memcpy((void *)credential->data, CFDataGetBytePtr(data), 1562 credential->datalen); 1563 cupsArrayAdd(names, credential); 1564 } 1565 else 1566 free(credential); 1567 } 1568 } 1569 } 1570 1571 CFRelease(dn_array); 1572 } 1573 1574 if (!error) 1575 { 1576 error = (cg->client_cert_cb)(http, http->tls, names, 1577 cg->client_cert_data); 1578 1579 DEBUG_printf(("4_httpTLSStart: Client certificate callback " 1580 "returned %d.", (int)error)); 1581 } 1582 1583 httpFreeCredentials(names); 1584 } 1585 break; 1586 1587 case errSSLUnknownRootCert : 1588 message = _("Unable to establish a secure connection to host " 1589 "(untrusted certificate)."); 1590 break; 1591 1592 case errSSLNoRootCert : 1593 message = _("Unable to establish a secure connection to host " 1594 "(self-signed certificate)."); 1595 break; 1596 1597 case errSSLCertExpired : 1598 message = _("Unable to establish a secure connection to host " 1599 "(expired certificate)."); 1600 break; 1601 1602 case errSSLCertNotYetValid : 1603 message = _("Unable to establish a secure connection to host " 1604 "(certificate not yet valid)."); 1605 break; 1606 1607 case errSSLHostNameMismatch : 1608 message = _("Unable to establish a secure connection to host " 1609 "(host name mismatch)."); 1610 break; 1611 1612 case errSSLXCertChainInvalid : 1613 message = _("Unable to establish a secure connection to host " 1614 "(certificate chain invalid)."); 1615 break; 1616 1617 case errSSLConnectionRefused : 1618 message = _("Unable to establish a secure connection to host " 1619 "(peer dropped connection before responding)."); 1620 break; 1621 1622 default : 1623 break; 1624 } 1625 } 1626 } 1627 1628 if (error) 1629 { 1630 http->error = error; 1631 http->status = HTTP_STATUS_ERROR; 1632 errno = ECONNREFUSED; 1633 1634 CFRelease(http->tls); 1635 http->tls = NULL; 1636 1637 /* 1638 * If an error string wasn't set by the callbacks use a generic one... 1639 */ 1640 1641 if (!message) 1642 #ifdef HAVE_CSSMERRORSTRING 1643 message = cssmErrorString(error); 1644 #else 1645 message = _("Unable to establish a secure connection to host."); 1646 #endif /* HAVE_CSSMERRORSTRING */ 1647 1648 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); 1649 1650 return (-1); 1651 } 1652 1653 return (0); 1654 } 1655 1656 1657 /* 1658 * '_httpTLSStop()' - Shut down SSL/TLS on a connection. 1659 */ 1660 1661 void 1662 _httpTLSStop(http_t *http) /* I - HTTP connection */ 1663 { 1664 while (SSLClose(http->tls) == errSSLWouldBlock) 1665 usleep(1000); 1666 1667 CFRelease(http->tls); 1668 1669 if (http->tls_credentials) 1670 CFRelease(http->tls_credentials); 1671 1672 http->tls = NULL; 1673 http->tls_credentials = NULL; 1674 } 1675 1676 1677 /* 1678 * '_httpTLSWrite()' - Write to a SSL/TLS connection. 1679 */ 1680 1681 int /* O - Bytes written */ 1682 _httpTLSWrite(http_t *http, /* I - HTTP connection */ 1683 const char *buf, /* I - Buffer holding data */ 1684 int len) /* I - Length of buffer */ 1685 { 1686 ssize_t result; /* Return value */ 1687 OSStatus error; /* Error info */ 1688 size_t processed; /* Number of bytes processed */ 1689 1690 1691 DEBUG_printf(("2_httpTLSWrite(http=%p, buf=%p, len=%d)", (void *)http, (void *)buf, len)); 1692 1693 error = SSLWrite(http->tls, buf, (size_t)len, &processed); 1694 1695 switch (error) 1696 { 1697 case 0 : 1698 result = (int)processed; 1699 break; 1700 1701 case errSSLWouldBlock : 1702 if (processed) 1703 { 1704 result = (int)processed; 1705 } 1706 else 1707 { 1708 result = -1; 1709 errno = EINTR; 1710 } 1711 break; 1712 1713 case errSSLClosedGraceful : 1714 default : 1715 if (processed) 1716 { 1717 result = (int)processed; 1718 } 1719 else 1720 { 1721 result = -1; 1722 errno = EPIPE; 1723 } 1724 break; 1725 } 1726 1727 DEBUG_printf(("3_httpTLSWrite: Returning %d.", (int)result)); 1728 1729 return ((int)result); 1730 } 1731 1732 1733 /* 1734 * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain. 1735 */ 1736 1737 static CFArrayRef /* O - Array of certificates or NULL */ 1738 http_cdsa_copy_server( 1739 const char *common_name) /* I - Server's hostname */ 1740 { 1741 #ifdef HAVE_SECKEYCHAINOPEN 1742 OSStatus err; /* Error info */ 1743 SecIdentityRef identity = NULL;/* Identity */ 1744 CFArrayRef certificates = NULL; 1745 /* Certificate array */ 1746 SecPolicyRef policy = NULL; /* Policy ref */ 1747 CFStringRef cfcommon_name = NULL; 1748 /* Server name */ 1749 CFMutableDictionaryRef query = NULL; /* Query qualifiers */ 1750 CFArrayRef list = NULL; /* Keychain list */ 1751 SecKeychainRef syschain = NULL;/* System keychain */ 1752 SecKeychainStatus status = 0; /* Keychain status */ 1753 1754 1755 DEBUG_printf(("3http_cdsa_copy_server(common_name=\"%s\")", common_name)); 1756 1757 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 1758 1759 policy = SecPolicyCreateSSL(1, cfcommon_name); 1760 1761 if (!policy) 1762 { 1763 DEBUG_puts("4http_cdsa_copy_server: Unable to create SSL policy."); 1764 goto cleanup; 1765 } 1766 1767 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 1768 { 1769 DEBUG_puts("4http_cdsa_copy_server: Unable to create query dictionary."); 1770 goto cleanup; 1771 } 1772 1773 _cupsMutexLock(&tls_mutex); 1774 1775 err = SecKeychainGetStatus(tls_keychain, &status); 1776 1777 if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain) 1778 SecKeychainUnlock(tls_keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE); 1779 1780 CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); 1781 CFDictionaryAddValue(query, kSecMatchPolicy, policy); 1782 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); 1783 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); 1784 1785 syschain = http_cdsa_open_system_keychain(); 1786 1787 if (syschain) 1788 { 1789 const void *values[2] = { syschain, tls_keychain }; 1790 1791 list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks); 1792 } 1793 else 1794 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&tls_keychain, 1, &kCFTypeArrayCallBacks); 1795 1796 CFDictionaryAddValue(query, kSecMatchSearchList, list); 1797 CFRelease(list); 1798 1799 err = SecItemCopyMatching(query, (CFTypeRef *)&identity); 1800 1801 _cupsMutexUnlock(&tls_mutex); 1802 1803 if (err != noErr) 1804 { 1805 DEBUG_printf(("4http_cdsa_copy_server: SecItemCopyMatching failed with status %d.", (int)err)); 1806 goto cleanup; 1807 } 1808 1809 if (CFGetTypeID(identity) != SecIdentityGetTypeID()) 1810 { 1811 DEBUG_puts("4http_cdsa_copy_server: Search returned something that is not an identity."); 1812 goto cleanup; 1813 } 1814 1815 if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL) 1816 { 1817 DEBUG_puts("4http_cdsa_copy_server: Unable to create array of certificates."); 1818 goto cleanup; 1819 } 1820 1821 cleanup : 1822 1823 if (syschain) 1824 CFRelease(syschain); 1825 if (identity) 1826 CFRelease(identity); 1827 if (policy) 1828 CFRelease(policy); 1829 if (cfcommon_name) 1830 CFRelease(cfcommon_name); 1831 if (query) 1832 CFRelease(query); 1833 1834 DEBUG_printf(("4http_cdsa_copy_server: Returning %p.", (void *)certificates)); 1835 1836 return (certificates); 1837 #else 1838 1839 if (!tls_selfsigned) 1840 return (NULL); 1841 1842 return (CFArrayCreate(NULL, (const void **)&tls_selfsigned, 1, &kCFTypeArrayCallBacks)); 1843 #endif /* HAVE_SECKEYCHAINOPEN */ 1844 } 1845 1846 1847 /* 1848 * 'http_cdsa_create_credential()' - Create a single credential in the internal format. 1849 */ 1850 1851 static SecCertificateRef /* O - Certificate */ 1852 http_cdsa_create_credential( 1853 http_credential_t *credential) /* I - Credential */ 1854 { 1855 if (!credential) 1856 return (NULL); 1857 1858 return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)); 1859 } 1860 1861 1862 #ifdef HAVE_SECKEYCHAINOPEN 1863 /* 1864 * 'http_cdsa_default_path()' - Get the default keychain path. 1865 */ 1866 1867 static const char * /* O - Keychain path */ 1868 http_cdsa_default_path(char *buffer, /* I - Path buffer */ 1869 size_t bufsize) /* I - Size of buffer */ 1870 { 1871 const char *home = getenv("HOME"); /* HOME environment variable */ 1872 1873 1874 /* 1875 * Determine the default keychain path. Note that the login and system 1876 * keychains are no longer accessible to user applications starting in macOS 1877 * 10.11.4 (!), so we need to create our own keychain just for CUPS. 1878 */ 1879 1880 if (getuid() && home) 1881 snprintf(buffer, bufsize, "%s/.cups/ssl.keychain", home); 1882 else 1883 strlcpy(buffer, "/etc/cups/ssl.keychain", bufsize); 1884 1885 DEBUG_printf(("1http_cdsa_default_path: Using default path \"%s\".", buffer)); 1886 1887 return (buffer); 1888 } 1889 1890 1891 /* 1892 * 'http_cdsa_open_keychain()' - Open (or create) a keychain. 1893 */ 1894 1895 static SecKeychainRef /* O - Keychain or NULL */ 1896 http_cdsa_open_keychain( 1897 const char *path, /* I - Path to keychain */ 1898 char *filename, /* I - Keychain filename */ 1899 size_t filesize) /* I - Size of filename buffer */ 1900 { 1901 SecKeychainRef keychain = NULL;/* Temporary keychain */ 1902 OSStatus err; /* Error code */ 1903 Boolean interaction; /* Interaction allowed? */ 1904 SecKeychainStatus status = 0; /* Keychain status */ 1905 1906 1907 /* 1908 * Get the keychain filename... 1909 */ 1910 1911 if (!path) 1912 { 1913 path = http_cdsa_default_path(filename, filesize); 1914 tls_cups_keychain = 1; 1915 } 1916 else 1917 { 1918 strlcpy(filename, path, filesize); 1919 tls_cups_keychain = 0; 1920 } 1921 1922 /* 1923 * Save the interaction setting and disable while we open the keychain... 1924 */ 1925 1926 SecKeychainGetUserInteractionAllowed(&interaction); 1927 SecKeychainSetUserInteractionAllowed(FALSE); 1928 1929 if (access(path, R_OK) && tls_cups_keychain) 1930 { 1931 /* 1932 * Create a new keychain at the given path... 1933 */ 1934 1935 err = SecKeychainCreate(path, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, FALSE, NULL, &keychain); 1936 } 1937 else 1938 { 1939 /* 1940 * Open the existing keychain and unlock as needed... 1941 */ 1942 1943 err = SecKeychainOpen(path, &keychain); 1944 1945 if (err == noErr) 1946 err = SecKeychainGetStatus(keychain, &status); 1947 1948 if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain) 1949 err = SecKeychainUnlock(keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE); 1950 } 1951 1952 /* 1953 * Restore interaction setting... 1954 */ 1955 1956 SecKeychainSetUserInteractionAllowed(interaction); 1957 1958 /* 1959 * Release the keychain if we had any errors... 1960 */ 1961 1962 if (err != noErr) 1963 { 1964 /* TODO: Set cups last error string */ 1965 DEBUG_printf(("4http_cdsa_open_keychain: Unable to open keychain (%d), returning NULL.", (int)err)); 1966 1967 if (keychain) 1968 { 1969 CFRelease(keychain); 1970 keychain = NULL; 1971 } 1972 } 1973 1974 /* 1975 * Return the keychain or NULL... 1976 */ 1977 1978 return (keychain); 1979 } 1980 1981 1982 /* 1983 * 'http_cdsa_open_system_keychain()' - Open the System keychain. 1984 */ 1985 1986 static SecKeychainRef 1987 http_cdsa_open_system_keychain(void) 1988 { 1989 SecKeychainRef keychain = NULL;/* Temporary keychain */ 1990 OSStatus err; /* Error code */ 1991 Boolean interaction; /* Interaction allowed? */ 1992 SecKeychainStatus status = 0; /* Keychain status */ 1993 1994 1995 /* 1996 * Save the interaction setting and disable while we open the keychain... 1997 */ 1998 1999 SecKeychainGetUserInteractionAllowed(&interaction); 2000 SecKeychainSetUserInteractionAllowed(TRUE); 2001 2002 err = SecKeychainOpen("/Library/Keychains/System.keychain", &keychain); 2003 2004 if (err == noErr) 2005 err = SecKeychainGetStatus(keychain, &status); 2006 2007 if (err == noErr && !(status & kSecUnlockStateStatus)) 2008 err = errSecInteractionNotAllowed; 2009 2010 /* 2011 * Restore interaction setting... 2012 */ 2013 2014 SecKeychainSetUserInteractionAllowed(interaction); 2015 2016 /* 2017 * Release the keychain if we had any errors... 2018 */ 2019 2020 if (err != noErr) 2021 { 2022 /* TODO: Set cups last error string */ 2023 DEBUG_printf(("4http_cdsa_open_system_keychain: Unable to open keychain (%d), returning NULL.", (int)err)); 2024 2025 if (keychain) 2026 { 2027 CFRelease(keychain); 2028 keychain = NULL; 2029 } 2030 } 2031 2032 /* 2033 * Return the keychain or NULL... 2034 */ 2035 2036 return (keychain); 2037 } 2038 #endif /* HAVE_SECKEYCHAINOPEN */ 2039 2040 2041 /* 2042 * 'http_cdsa_read()' - Read function for the CDSA library. 2043 */ 2044 2045 static OSStatus /* O - -1 on error, 0 on success */ 2046 http_cdsa_read( 2047 SSLConnectionRef connection, /* I - SSL/TLS connection */ 2048 void *data, /* I - Data buffer */ 2049 size_t *dataLength) /* IO - Number of bytes */ 2050 { 2051 OSStatus result; /* Return value */ 2052 ssize_t bytes; /* Number of bytes read */ 2053 http_t *http; /* HTTP connection */ 2054 2055 2056 http = (http_t *)connection; 2057 2058 if (!http->blocking) 2059 { 2060 /* 2061 * Make sure we have data before we read... 2062 */ 2063 2064 while (!_httpWait(http, http->wait_value, 0)) 2065 { 2066 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) 2067 continue; 2068 2069 http->error = ETIMEDOUT; 2070 return (-1); 2071 } 2072 } 2073 2074 do 2075 { 2076 bytes = recv(http->fd, data, *dataLength, 0); 2077 } 2078 while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); 2079 2080 if ((size_t)bytes == *dataLength) 2081 { 2082 result = 0; 2083 } 2084 else if (bytes > 0) 2085 { 2086 *dataLength = (size_t)bytes; 2087 result = errSSLWouldBlock; 2088 } 2089 else 2090 { 2091 *dataLength = 0; 2092 2093 if (bytes == 0) 2094 result = errSSLClosedGraceful; 2095 else if (errno == EAGAIN) 2096 result = errSSLWouldBlock; 2097 else 2098 result = errSSLClosedAbort; 2099 } 2100 2101 return (result); 2102 } 2103 2104 2105 /* 2106 * 'http_cdsa_set_credentials()' - Set the TLS credentials. 2107 */ 2108 2109 static int /* O - Status of connection */ 2110 http_cdsa_set_credentials(http_t *http) /* I - HTTP connection */ 2111 { 2112 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ 2113 OSStatus error = 0; /* Error code */ 2114 http_tls_credentials_t credentials = NULL; 2115 /* TLS credentials */ 2116 2117 2118 DEBUG_printf(("7http_tls_set_credentials(%p)", (void *)http)); 2119 2120 /* 2121 * Prefer connection specific credentials... 2122 */ 2123 2124 if ((credentials = http->tls_credentials) == NULL) 2125 credentials = cg->tls_credentials; 2126 2127 if (credentials) 2128 { 2129 error = SSLSetCertificate(http->tls, credentials); 2130 DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d", 2131 (int)error)); 2132 } 2133 else 2134 DEBUG_puts("4http_tls_set_credentials: No credentials to set."); 2135 2136 return (error); 2137 } 2138 2139 2140 /* 2141 * 'http_cdsa_write()' - Write function for the CDSA library. 2142 */ 2143 2144 static OSStatus /* O - -1 on error, 0 on success */ 2145 http_cdsa_write( 2146 SSLConnectionRef connection, /* I - SSL/TLS connection */ 2147 const void *data, /* I - Data buffer */ 2148 size_t *dataLength) /* IO - Number of bytes */ 2149 { 2150 OSStatus result; /* Return value */ 2151 ssize_t bytes; /* Number of bytes read */ 2152 http_t *http; /* HTTP connection */ 2153 2154 2155 http = (http_t *)connection; 2156 2157 do 2158 { 2159 bytes = write(http->fd, data, *dataLength); 2160 } 2161 while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); 2162 2163 if ((size_t)bytes == *dataLength) 2164 { 2165 result = 0; 2166 } 2167 else if (bytes >= 0) 2168 { 2169 *dataLength = (size_t)bytes; 2170 result = errSSLWouldBlock; 2171 } 2172 else 2173 { 2174 *dataLength = 0; 2175 2176 if (errno == EAGAIN) 2177 result = errSSLWouldBlock; 2178 else 2179 result = errSSLClosedAbort; 2180 } 2181 2182 return (result); 2183 } 2184