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