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