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