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