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