Home | History | Annotate | Download | only in cups
      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