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