1/* 2 * "$Id: tls-darwin.c 12104 2014-08-20 15:23:40Z msweet $" 3 * 4 * TLS support code for CUPS on OS X. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * This file is subject to the Apple OS-Developed Software exception. 16 */ 17 18/**** This file is included from http.c ****/ 19 20/* 21 * Include necessary headers... 22 */ 23 24#include <spawn.h> 25 26extern char **environ; 27 28 29/* 30 * Local globals... 31 */ 32 33#ifdef HAVE_SECKEYCHAINOPEN 34static int tls_auto_create = 0; 35 /* Auto-create self-signed certs? */ 36static char *tls_common_name = NULL; 37 /* Default common name */ 38static SecKeychainRef tls_keychain = NULL; 39 /* Server cert keychain */ 40static char *tls_keypath = NULL; 41 /* Server cert keychain path */ 42static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; 43 /* Mutex for keychain/certs */ 44#endif /* HAVE_SECKEYCHAINOPEN */ 45 46 47/* 48 * Local functions... 49 */ 50 51#ifdef HAVE_SECKEYCHAINOPEN 52static CFArrayRef http_cdsa_copy_server(const char *common_name); 53#endif /* HAVE_SECKEYCHAINOPEN */ 54static SecCertificateRef http_cdsa_create_credential(http_credential_t *credential); 55static const char *http_cdsa_default_path(char *buffer, size_t bufsize); 56static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength); 57static int http_cdsa_set_credentials(http_t *http); 58static OSStatus http_cdsa_write(SSLConnectionRef connection, const void *data, size_t *dataLength); 59 60 61/* 62 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. 63 * 64 * @since CUPS 2.0/OS 10.10@ 65 */ 66 67int /* O - 1 on success, 0 on failure */ 68cupsMakeServerCredentials( 69 const char *path, /* I - Keychain path or @code NULL@ for default */ 70 const char *common_name, /* I - Common name */ 71 int num_alt_names, /* I - Number of subject alternate names */ 72 const char **alt_names, /* I - Subject Alternate Names */ 73 time_t expiration_date) /* I - Expiration date */ 74{ 75#if defined(HAVE_SECGENERATESELFSIGNEDCERTIFICATE) && defined(HAVE_SECKEYCHAINOPEN) 76 char filename[1024]; /* Default keychain path */ 77 int status = 0; /* Return status */ 78 OSStatus err; /* Error code (if any) */ 79 CFStringRef cfcommon_name = NULL; 80 /* CF string for server name */ 81 SecIdentityRef ident = NULL; /* Identity */ 82 SecKeyRef publicKey = NULL, 83 /* Public key */ 84 privateKey = NULL; 85 /* Private key */ 86 CFMutableDictionaryRef keyParams = NULL; 87 /* Key generation parameters */ 88 89 90 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)); 91 92 (void)num_alt_names; 93 (void)alt_names; 94 (void)expiration_date; 95 96 if (!path) 97 path = http_cdsa_default_path(filename, sizeof(filename)); 98 99 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 100 if (!cfcommon_name) 101 goto cleanup; 102 103 /* 104 * Create a public/private key pair... 105 */ 106 107 keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 108 if (!keyParams) 109 goto cleanup; 110 111 CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA); 112 CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048")); 113 CFDictionaryAddValue(keyParams, kSecAttrLabel, CFSTR("CUPS Self-Signed Certificate")); 114 115 err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey); 116 if (err != noErr) 117 goto cleanup; 118 119 /* 120 * Create a self-signed certificate using the public/private key pair... 121 */ 122 123 CFIndex usageInt = kSecKeyUsageAll; 124 CFNumberRef usage = CFNumberCreate(alloc, kCFNumberCFIndexType, &usageInt); 125 CFDictionaryRef certParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 126kSecCSRBasicContraintsPathLen, CFINT(0), kSecSubjectAltName, cfcommon_name, kSecCertificateKeyUsage, usage, NULL, NULL); 127 CFRelease(usage); 128 129 const void *ca_o[] = { kSecOidOrganization, CFSTR("") }; 130 const void *ca_cn[] = { kSecOidCommonName, cfcommon_name }; 131 CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); 132 CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); 133 const void *ca_dn_array[2]; 134 135 ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL); 136 ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL); 137 138 CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL); 139 SecCertificateRef cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey); 140 CFRelease(subject); 141 CFRelease(certParams); 142 143 if (!cert) 144 goto cleanup; 145 146 ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey); 147 148 if (ident) 149 status = 1; 150 151 /* 152 * Cleanup and return... 153 */ 154 155cleanup: 156 157 if (cfcommon_name) 158 CFRelease(cfcommon_name); 159 160 if (keyParams) 161 CFRelease(keyParams); 162 163 if (ident) 164 CFRelease(ident); 165 166 if (cert) 167 CFRelease(cert); 168 169 if (publicKey) 170 CFRelease(publicKey); 171 172 if (privateKey) 173 CFRelease(publicKey); 174 175 return (status); 176 177#else /* !(HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN) */ 178 int pid, /* Process ID of command */ 179 status, /* Status of command */ 180 i; /* Looping var */ 181 char command[1024], /* Command */ 182 *argv[4], /* Command-line arguments */ 183 *envp[1000], /* Environment variables */ 184 days[32], /* CERTTOOL_EXPIRATION_DAYS env var */ 185 keychain[1024], /* Keychain argument */ 186 infofile[1024], /* Type-in information for cert */ 187 filename[1024]; /* Default keychain path */ 188 cups_file_t *fp; /* Seed/info file */ 189 190 191 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)); 192 193 (void)num_alt_names; 194 (void)alt_names; 195 196 if (!path) 197 path = http_cdsa_default_path(filename, sizeof(filename)); 198 199 /* 200 * Run the "certtool" command to generate a self-signed certificate... 201 */ 202 203 if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) 204 return (-1); 205 206 /* 207 * Create a file with the certificate information fields... 208 * 209 * Note: This assumes that the default questions are asked by the certtool 210 * command... 211 */ 212 213 if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) 214 return (-1); 215 216 cupsFilePrintf(fp, 217 "CUPS Self-Signed Certificate\n" 218 /* Enter key and certificate label */ 219 "r\n" /* Generate RSA key pair */ 220 "2048\n" /* Key size in bits */ 221 "y\n" /* OK (y = yes) */ 222 "b\n" /* Usage (b=signing/encryption) */ 223 "s\n" /* Sign with SHA1 */ 224 "y\n" /* OK (y = yes) */ 225 "%s\n" /* Common name */ 226 "\n" /* Country (default) */ 227 "\n" /* Organization (default) */ 228 "\n" /* Organizational unit (default) */ 229 "\n" /* State/Province (default) */ 230 "\n" /* Email address */ 231 "y\n", /* OK (y = yes) */ 232 common_name); 233 cupsFileClose(fp); 234 235 snprintf(keychain, sizeof(keychain), "k=%s", path); 236 237 argv[0] = "certtool"; 238 argv[1] = "c"; 239 argv[2] = keychain; 240 argv[3] = NULL; 241 242 snprintf(days, sizeof(days), "CERTTOOL_EXPIRATION_DAYS=%d", (int)((expiration_date - time(NULL) + 86399) / 86400)); 243 envp[0] = days; 244 for (i = 0; i < (int)(sizeof(envp) / sizeof(envp[0]) - 2) && environ[i]; i ++) 245 envp[i + 1] = environ[i]; 246 envp[i] = NULL; 247 248 posix_spawn_file_actions_t actions; /* File actions */ 249 250 posix_spawn_file_actions_init(&actions); 251 posix_spawn_file_actions_addclose(&actions, 0); 252 posix_spawn_file_actions_addopen(&actions, 0, infofile, O_RDONLY, 0); 253 posix_spawn_file_actions_addclose(&actions, 1); 254 posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0); 255 posix_spawn_file_actions_addclose(&actions, 2); 256 posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0); 257 258 if (posix_spawn(&pid, command, &actions, NULL, argv, envp)) 259 { 260 unlink(infofile); 261 return (-1); 262 } 263 264 posix_spawn_file_actions_destroy(&actions); 265 266 unlink(infofile); 267 268 while (waitpid(pid, &status, 0) < 0) 269 if (errno != EINTR) 270 { 271 status = -1; 272 break; 273 } 274 275 return (!status); 276#endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN */ 277} 278 279 280/* 281 * 'cupsSetServerCredentials()' - Set the default server credentials. 282 * 283 * Note: The server credentials are used by all threads in the running process. 284 * This function is threadsafe. 285 * 286 * @since CUPS 2.0/OS X 10.10@ 287 */ 288 289int /* O - 1 on success, 0 on failure */ 290cupsSetServerCredentials( 291 const char *path, /* I - Keychain path or @code NULL@ for default */ 292 const char *common_name, /* I - Default common name for server */ 293 int auto_create) /* I - 1 = automatically create self-signed certificates */ 294{ 295 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); 296 297#ifdef HAVE_SECKEYCHAINOPEN 298 char filename[1024]; /* Filename for keychain */ 299 SecKeychainRef keychain = NULL;/* Temporary keychain */ 300 301 302 if (!path) 303 path = http_cdsa_default_path(filename, sizeof(filename)); 304 305 if (SecKeychainOpen(path, &keychain) != noErr) 306 { 307 /* TODO: Set cups last error string */ 308 DEBUG_puts("1cupsSetServerCredentials: Unable to open keychain, returning 0."); 309 return (0); 310 } 311 312 _cupsMutexLock(&tls_mutex); 313 314 /* 315 * Close any keychain that is currently open... 316 */ 317 318 if (tls_keychain) 319 CFRelease(tls_keychain); 320 321 if (tls_keypath) 322 _cupsStrFree(tls_keypath); 323 324 if (tls_common_name) 325 _cupsStrFree(tls_common_name); 326 327 /* 328 * Save the new keychain... 329 */ 330 331 tls_keychain = keychain; 332 tls_keypath = _cupsStrAlloc(path); 333 tls_auto_create = auto_create; 334 tls_common_name = _cupsStrAlloc(common_name); 335 336 _cupsMutexUnlock(&tls_mutex); 337 338 DEBUG_puts("1cupsSetServerCredentials: Opened keychain, returning 1."); 339 return (1); 340 341#else 342 DEBUG_puts("1cupsSetServerCredentials: No keychain support compiled in, returning 0."); 343 return (0); 344#endif /* HAVE_SECKEYCHAINOPEN */ 345} 346 347 348/* 349 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in 350 * an encrypted connection. 351 * 352 * @since CUPS 1.5/OS X 10.7@ 353 */ 354 355int /* O - Status of call (0 = success) */ 356httpCopyCredentials( 357 http_t *http, /* I - Connection to server */ 358 cups_array_t **credentials) /* O - Array of credentials */ 359{ 360 OSStatus error; /* Error code */ 361 SecTrustRef peerTrust; /* Peer trust reference */ 362 CFIndex count; /* Number of credentials */ 363 SecCertificateRef secCert; /* Certificate reference */ 364 CFDataRef data; /* Certificate data */ 365 int i; /* Looping var */ 366 367 368 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials)); 369 370 if (credentials) 371 *credentials = NULL; 372 373 if (!http || !http->tls || !credentials) 374 return (-1); 375 376 if (!(error = SSLCopyPeerTrust(http->tls, &peerTrust)) && peerTrust) 377 { 378 DEBUG_printf(("2httpCopyCredentials: Peer provided %d certificates.", (int)SecTrustGetCertificateCount(peerTrust))); 379 380 if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL) 381 { 382 count = SecTrustGetCertificateCount(peerTrust); 383 384 for (i = 0; i < count; i ++) 385 { 386 secCert = SecTrustGetCertificateAtIndex(peerTrust, i); 387 388#ifdef DEBUG 389 CFStringRef cf_name = SecCertificateCopySubjectSummary(secCert); 390 char name[1024]; 391 if (cf_name) 392 CFStringGetCString(cf_name, name, sizeof(name), kCFStringEncodingUTF8); 393 else 394 strlcpy(name, "unknown", sizeof(name)); 395 396 DEBUG_printf(("2httpCopyCredentials: Certificate %d name is \"%s\".", i, name)); 397#endif /* DEBUG */ 398 399 if ((data = SecCertificateCopyData(secCert)) != NULL) 400 { 401 DEBUG_printf(("2httpCopyCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data))); 402 403 httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data)); 404 CFRelease(data); 405 } 406 } 407 } 408 409 CFRelease(peerTrust); 410 } 411 412 return (error); 413} 414 415 416/* 417 * '_httpCreateCredentials()' - Create credentials in the internal format. 418 */ 419 420http_tls_credentials_t /* O - Internal credentials */ 421_httpCreateCredentials( 422 cups_array_t *credentials) /* I - Array of credentials */ 423{ 424 CFMutableArrayRef peerCerts; /* Peer credentials reference */ 425 SecCertificateRef secCert; /* Certificate reference */ 426 http_credential_t *credential; /* Credential data */ 427 428 429 if (!credentials) 430 return (NULL); 431 432 if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault, 433 cupsArrayCount(credentials), 434 &kCFTypeArrayCallBacks)) == NULL) 435 return (NULL); 436 437 for (credential = (http_credential_t *)cupsArrayFirst(credentials); 438 credential; 439 credential = (http_credential_t *)cupsArrayNext(credentials)) 440 { 441 if ((secCert = http_cdsa_create_credential(credential)) != NULL) 442 { 443 CFArrayAppendValue(peerCerts, secCert); 444 CFRelease(secCert); 445 } 446 } 447 448 return (peerCerts); 449} 450 451 452/* 453 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. 454 * 455 * @since CUPS 2.0/OS X 10.10@ 456 */ 457 458int /* O - 1 if valid, 0 otherwise */ 459httpCredentialsAreValidForName( 460 cups_array_t *credentials, /* I - Credentials */ 461 const char *common_name) /* I - Name to check */ 462{ 463 SecCertificateRef secCert; /* Certificate reference */ 464 CFStringRef cfcert_name = NULL; 465 /* Certificate's common name (CF string) */ 466 char cert_name[256]; /* Certificate's common name (C string) */ 467 int valid = 1; /* Valid name? */ 468 469 470 if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 471 return (0); 472 473 /* 474 * Compare the common names... 475 */ 476 477 if ((cfcert_name = SecCertificateCopySubjectSummary(secCert)) == NULL) 478 { 479 /* 480 * Can't get common name, cannot be valid... 481 */ 482 483 valid = 0; 484 } 485 else if (CFStringGetCString(cfcert_name, cert_name, sizeof(cert_name), kCFStringEncodingUTF8) && 486 _cups_strcasecmp(common_name, cert_name)) 487 { 488 /* 489 * Not an exact match for the common name, check for wildcard certs... 490 */ 491 492 const char *domain = strchr(common_name, '.'); 493 /* Domain in common name */ 494 495 if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1)) 496 { 497 /* 498 * Not a wildcard match. 499 */ 500 501 /* TODO: Check subject alternate names */ 502 valid = 0; 503 } 504 } 505 506 if (cfcert_name) 507 CFRelease(cfcert_name); 508 509 CFRelease(secCert); 510 511 return (valid); 512} 513 514 515/* 516 * 'httpCredentialsGetTrust()' - Return the trust of credentials. 517 * 518 * @since CUPS 2.0/OS X 10.10@ 519 */ 520 521http_trust_t /* O - Level of trust */ 522httpCredentialsGetTrust( 523 cups_array_t *credentials, /* I - Credentials */ 524 const char *common_name) /* I - Common name for trust lookup */ 525{ 526 SecCertificateRef secCert; /* Certificate reference */ 527 http_trust_t trust = HTTP_TRUST_OK; 528 /* Trusted? */ 529 cups_array_t *tcreds = NULL; /* Trusted credentials */ 530 _cups_globals_t *cg = _cupsGlobals(); 531 /* Per-thread globals */ 532 533 534 if (!common_name) 535 return (HTTP_TRUST_UNKNOWN); 536 537 if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 538 return (HTTP_TRUST_UNKNOWN); 539 540 /* 541 * Look this common name up in the default keychains... 542 */ 543 544 httpLoadCredentials(NULL, &tcreds, common_name); 545 546 if (tcreds) 547 { 548 char credentials_str[1024], /* String for incoming credentials */ 549 tcreds_str[1024]; /* String for saved credentials */ 550 551 httpCredentialsString(credentials, credentials_str, sizeof(credentials_str)); 552 httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str)); 553 554 if (strcmp(credentials_str, tcreds_str)) 555 { 556 /* 557 * Credentials don't match, let's look at the expiration date of the new 558 * credentials and allow if the new ones have a later expiration... 559 */ 560 561 if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds) || 562 !httpCredentialsAreValidForName(credentials, common_name)) 563 { 564 /* 565 * Either the new credentials are not newly issued, or the common name 566 * does not match the issued certificate... 567 */ 568 569 trust = HTTP_TRUST_INVALID; 570 } 571 else if (httpCredentialsGetExpiration(tcreds) < time(NULL)) 572 { 573 /* 574 * Save the renewed credentials... 575 */ 576 577 trust = HTTP_TRUST_RENEWED; 578 579 httpSaveCredentials(NULL, credentials, common_name); 580 } 581 } 582 583 httpFreeCredentials(tcreds); 584 } 585 else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name)) 586 trust = HTTP_TRUST_INVALID; 587 588 if (!cg->expired_certs && !SecCertificateIsValid(secCert, CFAbsoluteTimeGetCurrent())) 589 trust = HTTP_TRUST_EXPIRED; 590 else if (!cg->any_root && cupsArrayCount(credentials) == 1) 591 trust = HTTP_TRUST_INVALID; 592 593 CFRelease(secCert); 594 595 return (trust); 596} 597 598 599/* 600 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. 601 * 602 * @since CUPS 2.0/OS X 10.10@ 603 */ 604 605time_t /* O - Expiration date of credentials */ 606httpCredentialsGetExpiration( 607 cups_array_t *credentials) /* I - Credentials */ 608{ 609 SecCertificateRef secCert; /* Certificate reference */ 610 time_t expiration; /* Expiration date */ 611 612 613 if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 614 return (0); 615 616 expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); 617 618 CFRelease(secCert); 619 620 return (expiration); 621} 622 623 624/* 625 * 'httpCredentialsString()' - Return a string representing the credentials. 626 * 627 * @since CUPS 2.0/OS X 10.10@ 628 */ 629 630size_t /* O - Total size of credentials string */ 631httpCredentialsString( 632 cups_array_t *credentials, /* I - Credentials */ 633 char *buffer, /* I - Buffer or @code NULL@ */ 634 size_t bufsize) /* I - Size of buffer */ 635{ 636 http_credential_t *first; /* First certificate */ 637 SecCertificateRef secCert; /* Certificate reference */ 638 639 640 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize)); 641 642 if (!buffer) 643 return (0); 644 645 if (buffer && bufsize > 0) 646 *buffer = '\0'; 647 648 if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL && 649 (secCert = http_cdsa_create_credential(first)) != NULL) 650 { 651 CFStringRef cf_name; /* CF common name string */ 652 char name[256]; /* Common name associated with cert */ 653 time_t expiration; /* Expiration date of cert */ 654 _cups_md5_state_t md5_state; /* MD5 state */ 655 unsigned char md5_digest[16]; /* MD5 result */ 656 657 if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL) 658 { 659 CFStringGetCString(cf_name, name, (CFIndex)sizeof(name), kCFStringEncodingUTF8); 660 CFRelease(cf_name); 661 } 662 else 663 strlcpy(name, "unknown", sizeof(name)); 664 665 expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); 666 667 _cupsMD5Init(&md5_state); 668 _cupsMD5Append(&md5_state, first->data, (int)first->datalen); 669 _cupsMD5Finish(&md5_state, md5_digest); 670 671 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]); 672 673 CFRelease(secCert); 674 } 675 676 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); 677 678 return (strlen(buffer)); 679} 680 681 682/* 683 * '_httpFreeCredentials()' - Free internal credentials. 684 */ 685 686void 687_httpFreeCredentials( 688 http_tls_credentials_t credentials) /* I - Internal credentials */ 689{ 690 if (!credentials) 691 return; 692 693 CFRelease(credentials); 694} 695 696 697/* 698 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. 699 * 700 * @since CUPS 2.0/OS 10.10@ 701 */ 702 703int /* O - 0 on success, -1 on error */ 704httpLoadCredentials( 705 const char *path, /* I - Keychain path or @code NULL@ for default */ 706 cups_array_t **credentials, /* IO - Credentials */ 707 const char *common_name) /* I - Common name for credentials */ 708{ 709#ifdef HAVE_SECKEYCHAINOPEN 710 OSStatus err; /* Error info */ 711 char filename[1024]; /* Filename for keychain */ 712 SecKeychainRef keychain = NULL;/* Keychain reference */ 713 SecIdentitySearchRef search = NULL; /* Search reference */ 714 SecCertificateRef cert = NULL; /* Certificate */ 715 CFDataRef data; /* Certificate data */ 716 SecPolicyRef policy = NULL; /* Policy ref */ 717 CFStringRef cfcommon_name = NULL; 718 /* Server name */ 719 CFMutableDictionaryRef query = NULL; /* Query qualifiers */ 720 CFArrayRef list = NULL; /* Keychain list */ 721 722 723 DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); 724 725 if (!credentials) 726 return (-1); 727 728 *credentials = NULL; 729 730 if (!path) 731 path = http_cdsa_default_path(filename, sizeof(filename)); 732 733 if ((err = SecKeychainOpen(path, &keychain)) != noErr) 734 goto cleanup; 735 736 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 737 738 policy = SecPolicyCreateSSL(1, cfcommon_name); 739 740 if (cfcommon_name) 741 CFRelease(cfcommon_name); 742 743 if (!policy) 744 goto cleanup; 745 746 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 747 goto cleanup; 748 749 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks); 750 751 CFDictionaryAddValue(query, kSecClass, kSecClassCertificate); 752 CFDictionaryAddValue(query, kSecMatchPolicy, policy); 753 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); 754 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); 755 CFDictionaryAddValue(query, kSecMatchSearchList, list); 756 757 CFRelease(list); 758 759 err = SecItemCopyMatching(query, (CFTypeRef *)&cert); 760 761 if (err) 762 goto cleanup; 763 764 if (CFGetTypeID(cert) != SecCertificateGetTypeID()) 765 goto cleanup; 766 767 if ((data = SecCertificateCopyData(cert)) != NULL) 768 { 769 DEBUG_printf(("1httpLoadCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data))); 770 771 *credentials = cupsArrayNew(NULL, NULL); 772 httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data)); 773 CFRelease(data); 774 } 775 776 cleanup : 777 778 if (keychain) 779 CFRelease(keychain); 780 if (search) 781 CFRelease(search); 782 if (cert) 783 CFRelease(cert); 784 if (policy) 785 CFRelease(policy); 786 if (query) 787 CFRelease(query); 788 789 DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1)); 790 791 return (*credentials ? 0 : -1); 792 793#else 794 (void)path; 795 (void)credentials; 796 (void)common_name; 797 798 return (-1); 799#endif /* HAVE_SECKEYCHAINOPEN */ 800} 801 802 803/* 804 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. 805 * 806 * @since CUPS 2.0/OS 10.10@ 807 */ 808 809int /* O - -1 on error, 0 on success */ 810httpSaveCredentials( 811 const char *path, /* I - Keychain path or @code NULL@ for default */ 812 cups_array_t *credentials, /* I - Credentials */ 813 const char *common_name) /* I - Common name for credentials */ 814{ 815#ifdef HAVE_SECKEYCHAINOPEN 816 int ret = -1; /* Return value */ 817 OSStatus err; /* Error info */ 818 char filename[1024]; /* Filename for keychain */ 819 SecKeychainRef keychain = NULL;/* Keychain reference */ 820 SecIdentitySearchRef search = NULL; /* Search reference */ 821 SecCertificateRef cert = NULL; /* Certificate */ 822 CFMutableDictionaryRef attrs = NULL; /* Attributes for add */ 823 CFArrayRef list = NULL; /* Keychain list */ 824 825 826 DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); 827 if (!credentials) 828 goto cleanup; 829 830 if (!httpCredentialsAreValidForName(credentials, common_name)) 831 { 832 DEBUG_puts("1httpSaveCredentials: Common name does not match."); 833 return (-1); 834 } 835 836 if ((cert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) 837 { 838 DEBUG_puts("1httpSaveCredentials: Unable to create certificate."); 839 goto cleanup; 840 } 841 842 if (!path) 843 path = http_cdsa_default_path(filename, sizeof(filename)); 844 845 if ((err = SecKeychainOpen(path, &keychain)) != noErr) 846 { 847 DEBUG_printf(("1httpSaveCredentials: SecKeychainOpen returned %d.", (int)err)); 848 goto cleanup; 849 } 850 851 if ((list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks)) == NULL) 852 { 853 DEBUG_puts("1httpSaveCredentials: Unable to create list of keychains."); 854 goto cleanup; 855 } 856 857 if ((attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL) 858 { 859 DEBUG_puts("1httpSaveCredentials: Unable to create dictionary."); 860 goto cleanup; 861 } 862 863 CFDictionaryAddValue(attrs, kSecClass, kSecClassCertificate); 864 CFDictionaryAddValue(attrs, kSecValueRef, cert); 865 CFDictionaryAddValue(attrs, kSecMatchSearchList, list); 866 867 /* Note: SecItemAdd consumes "attrs"... */ 868 err = SecItemAdd(attrs, NULL); 869 DEBUG_printf(("1httpSaveCredentials: SecItemAdd returned %d.", (int)err)); 870 871 cleanup : 872 873 if (list) 874 CFRelease(list); 875 if (keychain) 876 CFRelease(keychain); 877 if (search) 878 CFRelease(search); 879 if (cert) 880 CFRelease(cert); 881 882 DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret)); 883 884 return (ret); 885 886#else 887 (void)path; 888 (void)credentials; 889 (void)common_name; 890 891 return (-1); 892#endif /* HAVE_SECKEYCHAINOPEN */ 893} 894 895 896/* 897 * '_httpTLSInitialize()' - Initialize the TLS stack. 898 */ 899 900void 901_httpTLSInitialize(void) 902{ 903 /* 904 * Nothing to do... 905 */ 906} 907 908 909/* 910 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. 911 */ 912 913size_t 914_httpTLSPending(http_t *http) /* I - HTTP connection */ 915{ 916 size_t bytes; /* Bytes that are available */ 917 918 919 if (!SSLGetBufferedReadSize(http->tls, &bytes)) 920 return (bytes); 921 922 return (0); 923} 924 925 926/* 927 * '_httpTLSRead()' - Read from a SSL/TLS connection. 928 */ 929 930int /* O - Bytes read */ 931_httpTLSRead(http_t *http, /* I - HTTP connection */ 932 char *buf, /* I - Buffer to store data */ 933 int len) /* I - Length of buffer */ 934{ 935 int result; /* Return value */ 936 OSStatus error; /* Error info */ 937 size_t processed; /* Number of bytes processed */ 938 939 940 error = SSLRead(http->tls, buf, (size_t)len, &processed); 941 DEBUG_printf(("6_httpTLSRead: error=%d, processed=%d", (int)error, 942 (int)processed)); 943 switch (error) 944 { 945 case 0 : 946 result = (int)processed; 947 break; 948 949 case errSSLWouldBlock : 950 if (processed) 951 result = (int)processed; 952 else 953 { 954 result = -1; 955 errno = EINTR; 956 } 957 break; 958 959 case errSSLClosedGraceful : 960 default : 961 if (processed) 962 result = (int)processed; 963 else 964 { 965 result = -1; 966 errno = EPIPE; 967 } 968 break; 969 } 970 971 return (result); 972} 973 974 975/* 976 * '_httpTLSStart()' - Set up SSL/TLS support on a connection. 977 */ 978 979int /* O - 0 on success, -1 on failure */ 980_httpTLSStart(http_t *http) /* I - HTTP connection */ 981{ 982 char hostname[256], /* Hostname */ 983 *hostptr; /* Pointer into hostname */ 984 _cups_globals_t *cg = _cupsGlobals(); 985 /* Pointer to library globals */ 986 OSStatus error; /* Error code */ 987 const char *message = NULL;/* Error message */ 988 cups_array_t *credentials; /* Credentials array */ 989 cups_array_t *names; /* CUPS distinguished names */ 990 CFArrayRef dn_array; /* CF distinguished names array */ 991 CFIndex count; /* Number of credentials */ 992 CFDataRef data; /* Certificate data */ 993 int i; /* Looping var */ 994 http_credential_t *credential; /* Credential data */ 995 996 997 DEBUG_printf(("7_httpTLSStart(http=%p)", http)); 998 999#ifdef HAVE_SECKEYCHAINOPEN 1000 if (http->mode == _HTTP_MODE_SERVER && !tls_keychain) 1001#else 1002 if (http->mode == _HTTP_MODE_SERVER) 1003#endif /* HAVE_SECKEYCHAINOPEN */ 1004 { 1005 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); 1006 http->error = errno = EINVAL; 1007 http->status = HTTP_STATUS_ERROR; 1008 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); 1009 1010 return (-1); 1011 } 1012 1013 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL) 1014 { 1015 DEBUG_puts("4_httpTLSStart: SSLCreateContext failed."); 1016 http->error = errno = ENOMEM; 1017 http->status = HTTP_STATUS_ERROR; 1018 _cupsSetHTTPError(HTTP_STATUS_ERROR); 1019 1020 return (-1); 1021 } 1022 1023 error = SSLSetConnection(http->tls, http); 1024 DEBUG_printf(("4_httpTLSStart: SSLSetConnection, error=%d", (int)error)); 1025 1026 if (!error) 1027 { 1028 error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write); 1029 DEBUG_printf(("4_httpTLSStart: SSLSetIOFuncs, error=%d", (int)error)); 1030 } 1031 1032 if (!error) 1033 { 1034 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth, 1035 true); 1036 DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d", 1037 (int)error)); 1038 } 1039 1040 if (!error && http->mode == _HTTP_MODE_CLIENT) 1041 { 1042 /* 1043 * Client: set client-side credentials, if any... 1044 */ 1045 1046 if (cg->client_cert_cb) 1047 { 1048 error = SSLSetSessionOption(http->tls, 1049 kSSLSessionOptionBreakOnCertRequested, true); 1050 DEBUG_printf(("4_httpTLSStart: kSSLSessionOptionBreakOnCertRequested, " 1051 "error=%d", (int)error)); 1052 } 1053 else 1054 { 1055 error = http_cdsa_set_credentials(http); 1056 DEBUG_printf(("4_httpTLSStart: http_cdsa_set_credentials, error=%d", 1057 (int)error)); 1058 } 1059 } 1060 else if (!error) 1061 { 1062 /* 1063 * Server: find/create a certificate for TLS... 1064 */ 1065 1066 if (http->fields[HTTP_FIELD_HOST][0]) 1067 { 1068 /* 1069 * Use hostname for TLS upgrade... 1070 */ 1071 1072 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); 1073 } 1074 else 1075 { 1076 /* 1077 * Resolve hostname from connection address... 1078 */ 1079 1080 http_addr_t addr; /* Connection address */ 1081 socklen_t addrlen; /* Length of address */ 1082 1083 addrlen = sizeof(addr); 1084 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) 1085 { 1086 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); 1087 hostname[0] = '\0'; 1088 } 1089 else if (httpAddrLocalhost(&addr)) 1090 hostname[0] = '\0'; 1091 else 1092 { 1093 httpAddrLookup(&addr, hostname, sizeof(hostname)); 1094 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); 1095 } 1096 } 1097 1098#ifdef HAVE_SECKEYCHAINOPEN 1099 if (isdigit(hostname[0] & 255) || hostname[0] == '[') 1100 hostname[0] = '\0'; /* Don't allow numeric addresses */ 1101 1102 if (hostname[0]) 1103 http->tls_credentials = http_cdsa_copy_server(hostname); 1104 else if (tls_common_name) 1105 http->tls_credentials = http_cdsa_copy_server(tls_common_name); 1106 1107 if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name)) 1108 { 1109 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name)); 1110 1111 if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400)) 1112 { 1113 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); 1114 http->error = errno = EINVAL; 1115 http->status = HTTP_STATUS_ERROR; 1116 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); 1117 1118 return (-1); 1119 } 1120 1121 http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name); 1122 } 1123#endif /* HAVE_SECKEYCHAINOPEN */ 1124 1125 if (!http->tls_credentials) 1126 { 1127 DEBUG_puts("4_httpTLSStart: Unable to find server credentials."); 1128 http->error = errno = EINVAL; 1129 http->status = HTTP_STATUS_ERROR; 1130 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1); 1131 1132 return (-1); 1133 } 1134 1135 error = SSLSetCertificate(http->tls, http->tls_credentials); 1136 1137 DEBUG_printf(("4_httpTLSStart: SSLSetCertificate, error=%d", (int)error)); 1138 } 1139 1140 DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", http->tls_credentials)); 1141 1142 /* 1143 * Let the server know which hostname/domain we are trying to connect to 1144 * in case it wants to serve up a certificate with a matching common name. 1145 */ 1146 1147 if (!error && http->mode == _HTTP_MODE_CLIENT) 1148 { 1149 /* 1150 * Client: get the hostname to use for TLS... 1151 */ 1152 1153 if (httpAddrLocalhost(http->hostaddr)) 1154 { 1155 strlcpy(hostname, "localhost", sizeof(hostname)); 1156 } 1157 else 1158 { 1159 /* 1160 * Otherwise make sure the hostname we have does not end in a trailing dot. 1161 */ 1162 1163 strlcpy(hostname, http->hostname, sizeof(hostname)); 1164 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && 1165 *hostptr == '.') 1166 *hostptr = '\0'; 1167 } 1168 1169 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname)); 1170 1171 DEBUG_printf(("4_httpTLSStart: SSLSetPeerDomainName, error=%d", (int)error)); 1172 } 1173 1174 if (!error) 1175 { 1176 int done = 0; /* Are we done yet? */ 1177 1178 while (!error && !done) 1179 { 1180 error = SSLHandshake(http->tls); 1181 1182 DEBUG_printf(("4_httpTLSStart: SSLHandshake returned %d.", (int)error)); 1183 1184 switch (error) 1185 { 1186 case noErr : 1187 done = 1; 1188 break; 1189 1190 case errSSLWouldBlock : 1191 error = noErr; /* Force a retry */ 1192 usleep(1000); /* in 1 millisecond */ 1193 break; 1194 1195 case errSSLServerAuthCompleted : 1196 error = 0; 1197 if (cg->server_cert_cb) 1198 { 1199 error = httpCopyCredentials(http, &credentials); 1200 if (!error) 1201 { 1202 error = (cg->server_cert_cb)(http, http->tls, credentials, 1203 cg->server_cert_data); 1204 httpFreeCredentials(credentials); 1205 } 1206 1207 DEBUG_printf(("4_httpTLSStart: Server certificate callback " 1208 "returned %d.", (int)error)); 1209 } 1210 break; 1211 1212 case errSSLClientCertRequested : 1213 error = 0; 1214 1215 if (cg->client_cert_cb) 1216 { 1217 names = NULL; 1218 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) && 1219 dn_array) 1220 { 1221 if ((names = cupsArrayNew(NULL, NULL)) != NULL) 1222 { 1223 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++) 1224 { 1225 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i); 1226 1227 if ((credential = malloc(sizeof(*credential))) != NULL) 1228 { 1229 credential->datalen = (size_t)CFDataGetLength(data); 1230 if ((credential->data = malloc(credential->datalen))) 1231 { 1232 memcpy((void *)credential->data, CFDataGetBytePtr(data), 1233 credential->datalen); 1234 cupsArrayAdd(names, credential); 1235 } 1236 else 1237 free(credential); 1238 } 1239 } 1240 } 1241 1242 CFRelease(dn_array); 1243 } 1244 1245 if (!error) 1246 { 1247 error = (cg->client_cert_cb)(http, http->tls, names, 1248 cg->client_cert_data); 1249 1250 DEBUG_printf(("4_httpTLSStart: Client certificate callback " 1251 "returned %d.", (int)error)); 1252 } 1253 1254 httpFreeCredentials(names); 1255 } 1256 break; 1257 1258 case errSSLUnknownRootCert : 1259 message = _("Unable to establish a secure connection to host " 1260 "(untrusted certificate)."); 1261 break; 1262 1263 case errSSLNoRootCert : 1264 message = _("Unable to establish a secure connection to host " 1265 "(self-signed certificate)."); 1266 break; 1267 1268 case errSSLCertExpired : 1269 message = _("Unable to establish a secure connection to host " 1270 "(expired certificate)."); 1271 break; 1272 1273 case errSSLCertNotYetValid : 1274 message = _("Unable to establish a secure connection to host " 1275 "(certificate not yet valid)."); 1276 break; 1277 1278 case errSSLHostNameMismatch : 1279 message = _("Unable to establish a secure connection to host " 1280 "(host name mismatch)."); 1281 break; 1282 1283 case errSSLXCertChainInvalid : 1284 message = _("Unable to establish a secure connection to host " 1285 "(certificate chain invalid)."); 1286 break; 1287 1288 case errSSLConnectionRefused : 1289 message = _("Unable to establish a secure connection to host " 1290 "(peer dropped connection before responding)."); 1291 break; 1292 1293 default : 1294 break; 1295 } 1296 } 1297 } 1298 1299 if (error) 1300 { 1301 http->error = error; 1302 http->status = HTTP_STATUS_ERROR; 1303 errno = ECONNREFUSED; 1304 1305 CFRelease(http->tls); 1306 http->tls = NULL; 1307 1308 /* 1309 * If an error string wasn't set by the callbacks use a generic one... 1310 */ 1311 1312 if (!message) 1313#ifdef HAVE_CSSMERRORSTRING 1314 message = cssmErrorString(error); 1315#else 1316 message = _("Unable to establish a secure connection to host."); 1317#endif /* HAVE_CSSMERRORSTRING */ 1318 1319 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); 1320 1321 return (-1); 1322 } 1323 1324 return (0); 1325} 1326 1327 1328/* 1329 * '_httpTLSStop()' - Shut down SSL/TLS on a connection. 1330 */ 1331 1332void 1333_httpTLSStop(http_t *http) /* I - HTTP connection */ 1334{ 1335 while (SSLClose(http->tls) == errSSLWouldBlock) 1336 usleep(1000); 1337 1338 CFRelease(http->tls); 1339 1340 if (http->tls_credentials) 1341 CFRelease(http->tls_credentials); 1342 1343 http->tls = NULL; 1344 http->tls_credentials = NULL; 1345} 1346 1347 1348/* 1349 * '_httpTLSWrite()' - Write to a SSL/TLS connection. 1350 */ 1351 1352int /* O - Bytes written */ 1353_httpTLSWrite(http_t *http, /* I - HTTP connection */ 1354 const char *buf, /* I - Buffer holding data */ 1355 int len) /* I - Length of buffer */ 1356{ 1357 ssize_t result; /* Return value */ 1358 OSStatus error; /* Error info */ 1359 size_t processed; /* Number of bytes processed */ 1360 1361 1362 DEBUG_printf(("2_httpTLSWrite(http=%p, buf=%p, len=%d)", http, buf, len)); 1363 1364 error = SSLWrite(http->tls, buf, (size_t)len, &processed); 1365 1366 switch (error) 1367 { 1368 case 0 : 1369 result = (int)processed; 1370 break; 1371 1372 case errSSLWouldBlock : 1373 if (processed) 1374 { 1375 result = (int)processed; 1376 } 1377 else 1378 { 1379 result = -1; 1380 errno = EINTR; 1381 } 1382 break; 1383 1384 case errSSLClosedGraceful : 1385 default : 1386 if (processed) 1387 { 1388 result = (int)processed; 1389 } 1390 else 1391 { 1392 result = -1; 1393 errno = EPIPE; 1394 } 1395 break; 1396 } 1397 1398 DEBUG_printf(("3_httpTLSWrite: Returning %d.", (int)result)); 1399 1400 return ((int)result); 1401} 1402 1403 1404#ifdef HAVE_SECKEYCHAINOPEN 1405/* 1406 * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain. 1407 */ 1408 1409static CFArrayRef /* O - Array of certificates or NULL */ 1410http_cdsa_copy_server( 1411 const char *common_name) /* I - Server's hostname */ 1412{ 1413 OSStatus err; /* Error info */ 1414 SecIdentitySearchRef search = NULL; /* Search reference */ 1415 SecIdentityRef identity = NULL;/* Identity */ 1416 CFArrayRef certificates = NULL; 1417 /* Certificate array */ 1418 SecPolicyRef policy = NULL; /* Policy ref */ 1419 CFStringRef cfcommon_name = NULL; 1420 /* Server name */ 1421 CFMutableDictionaryRef query = NULL; /* Query qualifiers */ 1422 CFArrayRef list = NULL; /* Keychain list */ 1423 1424 1425 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); 1426 1427 policy = SecPolicyCreateSSL(1, cfcommon_name); 1428 1429 if (cfcommon_name) 1430 CFRelease(cfcommon_name); 1431 1432 if (!policy) 1433 goto cleanup; 1434 1435 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 1436 goto cleanup; 1437 1438 _cupsMutexLock(&tls_mutex); 1439 1440 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&tls_keychain, 1, &kCFTypeArrayCallBacks); 1441 1442 CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); 1443 CFDictionaryAddValue(query, kSecMatchPolicy, policy); 1444 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); 1445 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); 1446 CFDictionaryAddValue(query, kSecMatchSearchList, list); 1447 1448 CFRelease(list); 1449 1450 err = SecItemCopyMatching(query, (CFTypeRef *)&identity); 1451 1452 _cupsMutexUnlock(&tls_mutex); 1453 1454 if (err) 1455 goto cleanup; 1456 1457 if (CFGetTypeID(identity) != SecIdentityGetTypeID()) 1458 goto cleanup; 1459 1460 if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL) 1461 goto cleanup; 1462 1463 cleanup : 1464 1465 if (search) 1466 CFRelease(search); 1467 if (identity) 1468 CFRelease(identity); 1469 1470 if (policy) 1471 CFRelease(policy); 1472 if (query) 1473 CFRelease(query); 1474 1475 return (certificates); 1476} 1477#endif /* HAVE_SECKEYCHAINOPEN */ 1478 1479 1480/* 1481 * 'http_cdsa_create_credential()' - Create a single credential in the internal format. 1482 */ 1483 1484static SecCertificateRef /* O - Certificate */ 1485http_cdsa_create_credential( 1486 http_credential_t *credential) /* I - Credential */ 1487{ 1488 if (!credential) 1489 return (NULL); 1490 1491 return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)); 1492} 1493 1494 1495/* 1496 * 'http_cdsa_default_path()' - Get the default keychain path. 1497 */ 1498 1499static const char * /* O - Keychain path */ 1500http_cdsa_default_path(char *buffer, /* I - Path buffer */ 1501 size_t bufsize) /* I - Size of buffer */ 1502{ 1503 const char *home = getenv("HOME"); /* HOME environment variable */ 1504 1505 1506 if (getuid() && home) 1507 snprintf(buffer, bufsize, "%s/Library/Keychains/login.keychain", home); 1508 else 1509 strlcpy(buffer, "/Library/Keychains/System.keychain", bufsize); 1510 1511 DEBUG_printf(("1http_cdsa_default_path: Using default path \"%s\".", buffer)); 1512 1513 return (buffer); 1514} 1515 1516 1517/* 1518 * 'http_cdsa_read()' - Read function for the CDSA library. 1519 */ 1520 1521static OSStatus /* O - -1 on error, 0 on success */ 1522http_cdsa_read( 1523 SSLConnectionRef connection, /* I - SSL/TLS connection */ 1524 void *data, /* I - Data buffer */ 1525 size_t *dataLength) /* IO - Number of bytes */ 1526{ 1527 OSStatus result; /* Return value */ 1528 ssize_t bytes; /* Number of bytes read */ 1529 http_t *http; /* HTTP connection */ 1530 1531 1532 http = (http_t *)connection; 1533 1534 if (!http->blocking) 1535 { 1536 /* 1537 * Make sure we have data before we read... 1538 */ 1539 1540 while (!_httpWait(http, http->wait_value, 0)) 1541 { 1542 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) 1543 continue; 1544 1545 http->error = ETIMEDOUT; 1546 return (-1); 1547 } 1548 } 1549 1550 do 1551 { 1552 bytes = recv(http->fd, data, *dataLength, 0); 1553 } 1554 while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); 1555 1556 if ((size_t)bytes == *dataLength) 1557 { 1558 result = 0; 1559 } 1560 else if (bytes > 0) 1561 { 1562 *dataLength = (size_t)bytes; 1563 result = errSSLWouldBlock; 1564 } 1565 else 1566 { 1567 *dataLength = 0; 1568 1569 if (bytes == 0) 1570 result = errSSLClosedGraceful; 1571 else if (errno == EAGAIN) 1572 result = errSSLWouldBlock; 1573 else 1574 result = errSSLClosedAbort; 1575 } 1576 1577 return (result); 1578} 1579 1580 1581/* 1582 * 'http_cdsa_set_credentials()' - Set the TLS credentials. 1583 */ 1584 1585static int /* O - Status of connection */ 1586http_cdsa_set_credentials(http_t *http) /* I - HTTP connection */ 1587{ 1588 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ 1589 OSStatus error = 0; /* Error code */ 1590 http_tls_credentials_t credentials = NULL; 1591 /* TLS credentials */ 1592 1593 1594 DEBUG_printf(("7http_tls_set_credentials(%p)", http)); 1595 1596 /* 1597 * Prefer connection specific credentials... 1598 */ 1599 1600 if ((credentials = http->tls_credentials) == NULL) 1601 credentials = cg->tls_credentials; 1602 1603 if (credentials) 1604 { 1605 error = SSLSetCertificate(http->tls, credentials); 1606 DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d", 1607 (int)error)); 1608 } 1609 else 1610 DEBUG_puts("4http_tls_set_credentials: No credentials to set."); 1611 1612 return (error); 1613} 1614 1615 1616/* 1617 * 'http_cdsa_write()' - Write function for the CDSA library. 1618 */ 1619 1620static OSStatus /* O - -1 on error, 0 on success */ 1621http_cdsa_write( 1622 SSLConnectionRef connection, /* I - SSL/TLS connection */ 1623 const void *data, /* I - Data buffer */ 1624 size_t *dataLength) /* IO - Number of bytes */ 1625{ 1626 OSStatus result; /* Return value */ 1627 ssize_t bytes; /* Number of bytes read */ 1628 http_t *http; /* HTTP connection */ 1629 1630 1631 http = (http_t *)connection; 1632 1633 do 1634 { 1635 bytes = write(http->fd, data, *dataLength); 1636 } 1637 while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); 1638 1639 if ((size_t)bytes == *dataLength) 1640 { 1641 result = 0; 1642 } 1643 else if (bytes >= 0) 1644 { 1645 *dataLength = (size_t)bytes; 1646 result = errSSLWouldBlock; 1647 } 1648 else 1649 { 1650 *dataLength = 0; 1651 1652 if (errno == EAGAIN) 1653 result = errSSLWouldBlock; 1654 else 1655 result = errSSLClosedAbort; 1656 } 1657 1658 return (result); 1659} 1660 1661 1662/* 1663 * End of "$Id: tls-darwin.c 12104 2014-08-20 15:23:40Z msweet $". 1664 */ 1665