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