]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/tls-darwin.c
Fix clang-reported issues (<rdar://problem/15936066>)
[thirdparty/cups.git] / cups / tls-darwin.c
CommitLineData
2c85b752
MS
1/*
2 * "$Id$"
3 *
4 * TLS support code for CUPS on OS X.
5 *
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
dafebafd 18/**** This file is included from http.c ****/
2c85b752
MS
19
20/*
dafebafd 21 * Include necessary headers...
2c85b752
MS
22 */
23
dafebafd
MS
24#include <spawn.h>
25
26extern char **environ;
27
28
c0459938
MS
29/*
30 * Local globals...
31 */
32
eb66bc71 33#ifdef HAVE_SECKEYCHAINOPEN
c0459938
MS
34static int tls_auto_create = 0;
35 /* Auto-create self-signed certs? */
36static char *tls_common_name = NULL;
37 /* Default common name */
41e0907c
MS
38static SecKeychainRef tls_keychain = NULL;
39 /* Server cert keychain */
40static char *tls_keypath = NULL;
41 /* Server cert keychain path */
42static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
43 /* Mutex for keychain/certs */
eb66bc71 44#endif /* HAVE_SECKEYCHAINOPEN */
c0459938
MS
45
46
dafebafd
MS
47/*
48 * Local functions...
49 */
2c85b752 50
eb66bc71 51#ifdef HAVE_SECKEYCHAINOPEN
41e0907c 52static CFArrayRef http_cdsa_copy_server(const char *common_name);
eb66bc71 53#endif /* HAVE_SECKEYCHAINOPEN */
41e0907c
MS
54static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength);
55static OSStatus http_cdsa_write(SSLConnectionRef connection, const void *data, size_t *dataLength);
2c85b752
MS
56
57
3af9ac9e
MS
58/*
59 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
60 *
61 * @since CUPS 2.0@
62 */
63
64int /* O - 1 on success, 0 on failure */
65cupsMakeServerCredentials(
66 const char *path, /* I - Path to keychain/directory */
67 const char *common_name, /* I - Common name */
68 int num_alt_names, /* I - Number of subject alternate names */
69 const char **alt_names, /* I - Subject Alternate Names */
70 time_t expiration_date) /* I - Expiration date */
71{
eb66bc71 72#if defined(HAVE_SECGENERATESELFSIGNEDCERTIFICATE) && defined(HAVE_SECKEYCHAINOPEN)
41e0907c
MS
73 int status = 0; /* Return status */
74 OSStatus err; /* Error code (if any) */
75 CFStringRef cfcommon_name = NULL;
76 /* CF string for server name */
77 SecIdentityRef ident = NULL; /* Identity */
78 SecKeyRef publicKey = NULL,
79 /* Public key */
80 privateKey = NULL;
81 /* Private key */
82 CFMutableDictionaryRef keyParams = NULL;
83 /* Key generation parameters */
84
85
3af9ac9e
MS
86 (void)num_alt_names;
87 (void)alt_names;
88 (void)expiration_date;
89
41e0907c
MS
90 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name,
91 kCFStringEncodingUTF8);
92 if (!cfcommon_name)
93 goto cleanup;
94
95 /*
96 * Create a public/private key pair...
97 */
98
99 keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
100 &kCFTypeDictionaryKeyCallBacks,
101 &kCFTypeDictionaryValueCallBacks);
102 if (!keyParams)
103 goto cleanup;
104
105 CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA);
106 CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048"));
107 CFDictionaryAddValue(keyParams, kSecAttrLabel,
108 CFSTR("CUPS Self-Signed Certificate"));
109
110 err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey);
111 if (err != noErr)
112 goto cleanup;
113
114 /*
115 * Create a self-signed certificate using the public/private key pair...
116 */
117
118 CFIndex usageInt = kSecKeyUsageAll;
119 CFNumberRef usage = CFNumberCreate(alloc, kCFNumberCFIndexType, &usageInt);
120 CFDictionaryRef certParams = CFDictionaryCreateMutable(kCFAllocatorDefault,
121kSecCSRBasicContraintsPathLen, CFINT(0), kSecSubjectAltName, cfcommon_name, kSecCertificateKeyUsage, usage, NULL, NULL);
122 CFRelease(usage);
123
124 const void *ca_o[] = { kSecOidOrganization, CFSTR("") };
125 const void *ca_cn[] = { kSecOidCommonName, cfcommon_name };
126 CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL);
127 CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL);
128 const void *ca_dn_array[2];
129
130 ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL);
131 ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL);
132
133 CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL);
134 SecCertificateRef cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey);
135 CFRelease(subject);
136 CFRelease(certParams);
137
138 if (!cert)
139 goto cleanup;
140
141 ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey);
142
143 if (ident)
144 status = 1;
145
146 /*
147 * Cleanup and return...
148 */
149
150cleanup:
151
152 if (cfcommon_name)
153 CFRelease(cfcommon_name);
154
155 if (keyParams)
156 CFRelease(keyParams);
157
158 if (ident)
159 CFRelease(ident);
160
161 if (cert)
162 CFRelease(cert);
163
164 if (publicKey)
165 CFRelease(publicKey);
166
167 if (privateKey)
168 CFRelease(publicKey);
169
170 return (status);
171
eb66bc71 172#else /* !(HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN) */
41e0907c
MS
173 int pid, /* Process ID of command */
174 status; /* Status of command */
175 char command[1024], /* Command */
176 *argv[4], /* Command-line arguments */
177 keychain[1024], /* Keychain argument */
178 infofile[1024]; /* Type-in information for cert */
179 cups_file_t *fp; /* Seed/info file */
180
181
182 (void)num_alt_names;
183 (void)alt_names;
184 (void)expiration_date;
185
186 /*
187 * Run the "certtool" command to generate a self-signed certificate...
188 */
189
190 if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command)))
191 return (-1);
192
193 /*
194 * Create a file with the certificate information fields...
195 *
196 * Note: This assumes that the default questions are asked by the certtool
197 * command...
198 */
199
200 if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
201 return (-1);
202
203 cupsFilePrintf(fp,
204 "CUPS Self-Signed Certificate\n"
205 /* Enter key and certificate label */
206 "r\n" /* Generate RSA key pair */
207 "2048\n" /* Key size in bits */
208 "y\n" /* OK (y = yes) */
209 "b\n" /* Usage (b=signing/encryption) */
210 "s\n" /* Sign with SHA1 */
211 "y\n" /* OK (y = yes) */
212 "%s\n" /* Common name */
213 "\n" /* Country (default) */
214 "\n" /* Organization (default) */
215 "\n" /* Organizational unit (default) */
216 "\n" /* State/Province (default) */
217 "\n" /* Email address */
218 "y\n", /* OK (y = yes) */
219 common_name);
220 cupsFileClose(fp);
221
222 snprintf(keychain, sizeof(keychain), "k=%s", path);
223
224 argv[0] = "certtool";
225 argv[1] = "c";
226 argv[2] = keychain;
227 argv[3] = NULL;
228
229 posix_spawn_file_actions_t actions; /* File actions */
230
231 posix_spawn_file_actions_init(&actions);
232 posix_spawn_file_actions_addclose(&actions, 0);
233 posix_spawn_file_actions_addopen(&actions, 0, infofile, O_RDONLY, 0);
234
235 if (posix_spawn(&pid, command, &actions, NULL, argv, environ))
236 {
237 unlink(infofile);
238 return (-1);
239 }
240
241 posix_spawn_file_actions_destroy(&actions);
242
243 unlink(infofile);
244
245 while (waitpid(pid, &status, 0) < 0)
246 if (errno != EINTR)
247 {
248 status = -1;
249 break;
250 }
251
252 return (!status);
eb66bc71 253#endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN */
3af9ac9e
MS
254}
255
256
257/*
258 * 'cupsSetServerCredentials()' - Set the default server credentials.
259 *
260 * Note: The server credentials are used by all threads in the running process.
261 * This function is threadsafe.
262 *
263 * @since CUPS 2.0@
264 */
265
266int /* O - 1 on success, 0 on failure */
267cupsSetServerCredentials(
268 const char *path, /* I - Path to keychain/directory */
269 const char *common_name, /* I - Default common name for server */
270 int auto_create) /* I - 1 = automatically create self-signed certificates */
271{
eb66bc71 272#ifdef HAVE_SECKEYCHAINOPEN
c0459938 273 SecKeychainRef keychain = NULL;/* Temporary keychain */
3af9ac9e 274
c0459938
MS
275
276 if (SecKeychainOpen(path, &keychain) != noErr)
277 {
278 /* TODO: Set cups last error string */
279 return (0);
280 }
281
282 _cupsMutexLock(&tls_mutex);
283
284 /*
285 * Close any keychain that is currently open...
286 */
287
288 if (tls_keychain)
289 CFRelease(tls_keychain);
290
41e0907c
MS
291 if (tls_keypath)
292 _cupsStrFree(tls_keypath);
293
c0459938
MS
294 if (tls_common_name)
295 _cupsStrFree(tls_common_name);
296
297 /*
298 * Save the new keychain...
299 */
300
301 tls_keychain = keychain;
41e0907c 302 tls_keypath = _cupsStrAlloc(path);
c0459938
MS
303 tls_auto_create = auto_create;
304 tls_common_name = _cupsStrAlloc(common_name);
305
306 _cupsMutexUnlock(&tls_mutex);
307
308 return (1);
eb66bc71
MS
309
310#else
311 return (0);
312#endif /* HAVE_SECKEYCHAINOPEN */
3af9ac9e
MS
313}
314
2c85b752
MS
315
316/*
317 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
318 * an encrypted connection.
319 *
320 * @since CUPS 1.5/OS X 10.7@
321 */
322
323int /* O - Status of call (0 = success) */
324httpCopyCredentials(
325 http_t *http, /* I - Connection to server */
326 cups_array_t **credentials) /* O - Array of credentials */
327{
328 OSStatus error; /* Error code */
329 SecTrustRef peerTrust; /* Peer trust reference */
330 CFIndex count; /* Number of credentials */
331 SecCertificateRef secCert; /* Certificate reference */
332 CFDataRef data; /* Certificate data */
333 int i; /* Looping var */
334
335
336 if (credentials)
337 *credentials = NULL;
338
339 if (!http || !http->tls || !credentials)
340 return (-1);
341
342 if (!(error = SSLCopyPeerTrust(http->tls, &peerTrust)) && peerTrust)
343 {
344 if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL)
345 {
346 count = SecTrustGetCertificateCount(peerTrust);
347
348 for (i = 0; i < count; i ++)
349 {
350 secCert = SecTrustGetCertificateAtIndex(peerTrust, i);
351 if ((data = SecCertificateCopyData(secCert)))
352 {
353 httpAddCredential(*credentials, CFDataGetBytePtr(data),
354 CFDataGetLength(data));
355 CFRelease(data);
356 }
357 }
358 }
359
360 CFRelease(peerTrust);
361 }
362
363 return (error);
364}
365
366
367/*
368 * '_httpCreateCredentials()' - Create credentials in the internal format.
369 */
370
371http_tls_credentials_t /* O - Internal credentials */
372_httpCreateCredentials(
373 cups_array_t *credentials) /* I - Array of credentials */
374{
375 CFMutableArrayRef peerCerts; /* Peer credentials reference */
376 SecCertificateRef secCert; /* Certificate reference */
377 CFDataRef data; /* Credential data reference */
378 http_credential_t *credential; /* Credential data */
379
380
381 if (!credentials)
382 return (NULL);
383
384 if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault,
385 cupsArrayCount(credentials),
386 &kCFTypeArrayCallBacks)) == NULL)
387 return (NULL);
388
389 for (credential = (http_credential_t *)cupsArrayFirst(credentials);
390 credential;
391 credential = (http_credential_t *)cupsArrayNext(credentials))
392 {
393 if ((data = CFDataCreate(kCFAllocatorDefault, credential->data,
394 credential->datalen)))
395 {
396 if ((secCert = SecCertificateCreateWithData(kCFAllocatorDefault, data))
397 != NULL)
398 {
399 CFArrayAppendValue(peerCerts, secCert);
400 CFRelease(secCert);
401 }
402
403 CFRelease(data);
404 }
405 }
406
407 return (peerCerts);
408}
409
410
3af9ac9e
MS
411/*
412 * 'httpCredentialsAreTrusted()' - Return whether the credentials are trusted.
413 *
414 * @since CUPS 2.0@
415 */
416
417int /* O - 1 if trusted, 0 if not/unknown */
418httpCredentialsAreTrusted(
419 cups_array_t *credentials) /* I - Credentials */
420{
421 (void)credentials;
422
423 return (0);
424}
425
426
427/*
428 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
429 *
430 * @since CUPS 2.0@
431 */
432
433time_t /* O - Expiration date of credentials */
434httpCredentialsGetExpiration(
435 cups_array_t *credentials) /* I - Credentials */
436{
437 (void)credentials;
438
439 return (0);
440}
441
442
443/*
444 * 'httpCredentialsIsValidName()' - Return whether the credentials are valid for the given name.
445 *
446 * @since CUPS 2.0@
447 */
448
449int /* O - 1 if valid, 0 otherwise */
450httpCredentialsIsValidName(
451 cups_array_t *credentials, /* I - Credentials */
452 const char *common_name) /* I - Name to check */
453{
454 (void)credentials;
455 (void)common_name;
456
457 return (0);
458}
459
460
72d05bc9
MS
461/*
462 * 'httpCredentialsString()' - Return a string representing the credentials.
463 *
464 * @since CUPS 2.0@
465 */
466
467size_t /* O - Total size of credentials string */
468httpCredentialsString(
469 cups_array_t *credentials, /* I - Credentials */
470 char *buffer, /* I - Buffer or @code NULL@ */
471 size_t bufsize) /* I - Size of buffer */
472{
473 (void)credentials;
474
475 if (buffer && bufsize > 0)
476 *buffer = '\0';
477
478 return (1);
479}
480
481
2c85b752
MS
482/*
483 * '_httpFreeCredentials()' - Free internal credentials.
484 */
485
486void
487_httpFreeCredentials(
488 http_tls_credentials_t credentials) /* I - Internal credentials */
489{
490 if (!credentials)
491 return;
492
493 CFRelease(credentials);
494}
495
496
72d05bc9
MS
497/*
498 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
499 *
500 * @since CUPS 2.0@
501 */
502
dafebafd 503int /* O - 0 on success, -1 on error */
72d05bc9
MS
504httpLoadCredentials(
505 const char *path, /* I - Keychain/PKCS#12 path */
506 cups_array_t **credentials, /* IO - Credentials */
507 const char *common_name) /* I - Common name for credentials */
508{
f4047845
MS
509 (void)path;
510 (void)credentials;
511 (void)common_name;
512
513 return (-1);
514
515#if 0
dafebafd
MS
516 OSStatus err; /* Error info */
517 SecKeychainRef keychain = NULL;/* Keychain reference */
518 SecIdentitySearchRef search = NULL; /* Search reference */
519 SecIdentityRef identity = NULL;/* Identity */
520 CFArrayRef certificates = NULL;
521 /* Certificate array */
522 SecPolicyRef policy = NULL; /* Policy ref */
523 CFStringRef cfcommon_name = NULL;
524 /* Server name */
525 CFMutableDictionaryRef query = NULL; /* Query qualifiers */
526 CFArrayRef list = NULL; /* Keychain list */
527
528
529 if ((err = SecKeychainOpen(path, &keychain)))
530 goto cleanup;
531
532 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8);
533
534 policy = SecPolicyCreateSSL(1, cfcommon_name);
535
536 if (cfcommon_name)
537 CFRelease(cfcommon_name);
538
539 if (!policy)
540 goto cleanup;
541
542 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)))
543 goto cleanup;
544
545 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1,
546 &kCFTypeArrayCallBacks);
547
548 CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
549 CFDictionaryAddValue(query, kSecMatchPolicy, policy);
550 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
551 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
552 CFDictionaryAddValue(query, kSecMatchSearchList, list);
553
554 CFRelease(list);
555
556 err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
557
558 if (err)
559 goto cleanup;
560
561 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
562 goto cleanup;
563
564 if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL)
565 goto cleanup;
566
567 cleanup :
568
569 if (keychain)
570 CFRelease(keychain);
571 if (search)
572 CFRelease(search);
573 if (identity)
574 CFRelease(identity);
575
576 if (policy)
577 CFRelease(policy);
578 if (query)
579 CFRelease(query);
580
581 return (certificates);
f4047845 582#endif /* 0 */
72d05bc9
MS
583}
584
585
f4047845 586#if 0
72d05bc9 587/*
3af9ac9e 588 * 'cupsMakeCredentials()' - Create self-signed credentials for the given
72d05bc9
MS
589 * name.
590 *
591 * @since CUPS 2.0@
592 */
593
dafebafd 594int /* O - 0 on success, -1 on error */
3af9ac9e 595cupsMakeCredentials(
dafebafd 596 const char *path, /* I - Keychain/PKCS#12 path */
72d05bc9
MS
597 cups_array_t **credentials, /* O - Credentials */
598 const char *common_name) /* I - Common name for X.509 cert */
599{
dafebafd
MS
600# ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE
601 int status = -1; /* Return status */
602 OSStatus err; /* Error code (if any) */
603 CFStringRef cfcommon_name = NULL;
604 /* CF string for server name */
605 SecIdentityRef ident = NULL; /* Identity */
606 SecKeyRef publicKey = NULL,
607 /* Public key */
608 privateKey = NULL;
609 /* Private key */
610 CFMutableDictionaryRef keyParams = NULL;
611 /* Key generation parameters */
612
72d05bc9
MS
613
614 if (credentials)
615 *credentials = NULL;
616
dafebafd
MS
617 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, servername,
618 kCFStringEncodingUTF8);
619 if (!cfcommon_name)
620 goto cleanup;
621
622 /*
623 * Create a public/private key pair...
624 */
625
626 keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
627 &kCFTypeDictionaryKeyCallBacks,
628 &kCFTypeDictionaryValueCallBacks);
629 if (!keyParams)
630 goto cleanup;
631
632 CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA);
633 CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048"));
634 CFDictionaryAddValue(keyParams, kSecAttrLabel,
635 CFSTR("CUPS Self-Signed Certificate"));
636
637 err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey);
638 if (err != noErr)
639 goto cleanup;
640
641 /*
642 * Create a self-signed certificate using the public/private key pair...
643 */
644
645 CFIndex usageInt = kSecKeyUsageAll;
646 CFNumberRef usage = CFNumberCreate(alloc, kCFNumberCFIndexType, &usageInt);
647 CFDictionaryRef certParams = CFDictionaryCreateMutable(kCFAllocatorDefault,
648kSecCSRBasicContraintsPathLen, CFINT(0), kSecSubjectAltName, cfcommon_name, kSecCertificateKeyUsage, usage, NULL, NULL);
649 CFRelease(usage);
650
651 const void *ca_o[] = { kSecOidOrganization, CFSTR("") };
652 const void *ca_cn[] = { kSecOidCommonName, cfcommon_name };
653 CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL);
654 CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL);
655 const void *ca_dn_array[2];
656
657 ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL);
658 ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL);
659
660 CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL);
661 SecCertificateRef cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey);
662 CFRelease(subject);
663 CFRelease(certParams);
664
665 if (!cert)
666 goto cleanup;
667
668 ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey);
669
670 if (ident)
671 status = 0;
672
673 /*
674 * Cleanup and return...
675 */
676
677cleanup:
678
679 if (cfcommon_name)
680 CFRelease(cfcommon_name);
681
682 if (keyParams)
683 CFRelease(keyParams);
684
685 if (ident)
686 CFRelease(ident);
687
688 if (cert)
689 CFRelease(cert);
690
691 if (publicKey)
692 CFRelease(publicKey);
693
694 if (privateKey)
695 CFRelease(publicKey);
696
697 return (status);
698
699# else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */
700 int pid, /* Process ID of command */
701 status; /* Status of command */
702 char command[1024], /* Command */
703 *argv[4], /* Command-line arguments */
704 keychain[1024], /* Keychain argument */
705 infofile[1024]; /* Type-in information for cert */
706 cups_file_t *fp; /* Seed/info file */
707
708
709 /*
710 * Run the "certtool" command to generate a self-signed certificate...
711 */
712
713 if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command)))
714 return (-1);
715
716 /*
717 * Create a file with the certificate information fields...
718 *
719 * Note: This assumes that the default questions are asked by the certtool
720 * command...
721 */
722
723 if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
724 return (-1);
725
726 cupsFilePrintf(fp,
727 "%s\n" /* Enter key and certificate label */
728 "r\n" /* Generate RSA key pair */
729 "2048\n" /* Key size in bits */
730 "y\n" /* OK (y = yes) */
731 "b\n" /* Usage (b=signing/encryption) */
732 "s\n" /* Sign with SHA1 */
733 "y\n" /* OK (y = yes) */
734 "%s\n" /* Common name */
735 "\n" /* Country (default) */
736 "\n" /* Organization (default) */
737 "\n" /* Organizational unit (default) */
738 "\n" /* State/Province (default) */
739 "%s\n" /* Email address */
740 "y\n", /* OK (y = yes) */
741 common_name, common_name, "");
742 cupsFileClose(fp);
743
744 snprintf(keychain, sizeof(keychain), "k=%s", path);
745
746 argv[0] = "certtool";
747 argv[1] = "c";
748 argv[2] = keychain;
749 argv[3] = NULL;
750
751 posix_spawn_file_actions_t actions; /* File actions */
752
753 posix_spawn_file_actions_init(&actions);
754 posix_spawn_file_actions_addclose(&actions, 0);
755 posix_spawn_file_actions_addopen(&actions, 0, infofile, O_RDONLY, 0);
756
757 if (posix_spawn(&pid, command, &actions, NULL, argv, environ))
758 {
759 unlink(infofile);
760 return (-1);
761 }
762
763 posix_spawn_file_actions_destroy(&actions);
764
765 unlink(infofile);
766
767 while (waitpid(pid, &status, 0) < 0)
768 if (errno != EINTR)
769 {
770 status = -1;
771 break;
772 }
773
774 if (status)
775 return (-1);
776
777# endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */
778
779 return (httpLoadCredentials(path, credentials, common_name));
72d05bc9 780}
f4047845 781#endif /* 0 */
72d05bc9
MS
782
783
784/*
785 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
786 *
787 * @since CUPS 2.0@
788 */
789
790int /* O - -1 on error, 0 on success */
791httpSaveCredentials(
792 const char *path, /* I - Keychain/PKCS#12 path */
793 cups_array_t *credentials, /* I - Credentials */
794 const char *common_name) /* I - Common name for credentials */
795{
796 (void)path;
797 (void)credentials;
798 (void)common_name;
799
800 return (-1);
801}
802
803
eb66bc71 804#ifdef HAVE_SECKEYCHAINOPEN
41e0907c
MS
805/*
806 * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain.
807 */
808
809static CFArrayRef /* O - Array of certificates or NULL */
810http_cdsa_copy_server(
811 const char *common_name) /* I - Server's hostname */
812{
813 OSStatus err; /* Error info */
814 SecIdentitySearchRef search = NULL; /* Search reference */
815 SecIdentityRef identity = NULL;/* Identity */
816 CFArrayRef certificates = NULL;
817 /* Certificate array */
818 SecPolicyRef policy = NULL; /* Policy ref */
819 CFStringRef cfcommon_name = NULL;
820 /* Server name */
821 CFMutableDictionaryRef query = NULL; /* Query qualifiers */
822 CFArrayRef list = NULL; /* Keychain list */
823
824
825 cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8);
826
827 policy = SecPolicyCreateSSL(1, cfcommon_name);
828
829 if (cfcommon_name)
830 CFRelease(cfcommon_name);
831
832 if (!policy)
833 goto cleanup;
834
835 if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)))
836 goto cleanup;
837
838 list = CFArrayCreate(kCFAllocatorDefault, (const void **)&tls_keychain, 1, &kCFTypeArrayCallBacks);
839
840 CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
841 CFDictionaryAddValue(query, kSecMatchPolicy, policy);
842 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
843 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
844 CFDictionaryAddValue(query, kSecMatchSearchList, list);
845
846 CFRelease(list);
847
848 err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
849
850 if (err)
851 goto cleanup;
852
853 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
854 goto cleanup;
855
856 if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL)
857 goto cleanup;
858
859 cleanup :
860
861 if (search)
862 CFRelease(search);
863 if (identity)
864 CFRelease(identity);
865
866 if (policy)
867 CFRelease(policy);
868 if (query)
869 CFRelease(query);
870
871 return (certificates);
872}
eb66bc71 873#endif /* HAVE_SECKEYCHAINOPEN */
41e0907c
MS
874
875
2c85b752
MS
876/*
877 * 'http_cdsa_read()' - Read function for the CDSA library.
878 */
879
880static OSStatus /* O - -1 on error, 0 on success */
881http_cdsa_read(
882 SSLConnectionRef connection, /* I - SSL/TLS connection */
883 void *data, /* I - Data buffer */
884 size_t *dataLength) /* IO - Number of bytes */
885{
886 OSStatus result; /* Return value */
887 ssize_t bytes; /* Number of bytes read */
888 http_t *http; /* HTTP connection */
889
890
891 http = (http_t *)connection;
892
893 if (!http->blocking)
894 {
895 /*
896 * Make sure we have data before we read...
897 */
898
899 while (!_httpWait(http, http->wait_value, 0))
900 {
901 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
902 continue;
903
904 http->error = ETIMEDOUT;
905 return (-1);
906 }
907 }
908
909 do
910 {
911 bytes = recv(http->fd, data, *dataLength, 0);
912 }
913 while (bytes == -1 && (errno == EINTR || errno == EAGAIN));
914
915 if (bytes == *dataLength)
916 {
917 result = 0;
918 }
919 else if (bytes > 0)
920 {
921 *dataLength = bytes;
922 result = errSSLWouldBlock;
923 }
924 else
925 {
926 *dataLength = 0;
927
928 if (bytes == 0)
929 result = errSSLClosedGraceful;
930 else if (errno == EAGAIN)
931 result = errSSLWouldBlock;
932 else
933 result = errSSLClosedAbort;
934 }
935
936 return (result);
937}
938
939
940/*
941 * 'http_cdsa_write()' - Write function for the CDSA library.
942 */
943
944static OSStatus /* O - -1 on error, 0 on success */
945http_cdsa_write(
946 SSLConnectionRef connection, /* I - SSL/TLS connection */
947 const void *data, /* I - Data buffer */
948 size_t *dataLength) /* IO - Number of bytes */
949{
950 OSStatus result; /* Return value */
951 ssize_t bytes; /* Number of bytes read */
952 http_t *http; /* HTTP connection */
953
954
955 http = (http_t *)connection;
956
957 do
958 {
959 bytes = write(http->fd, data, *dataLength);
960 }
961 while (bytes == -1 && (errno == EINTR || errno == EAGAIN));
962
963 if (bytes == *dataLength)
964 {
965 result = 0;
966 }
967 else if (bytes >= 0)
968 {
969 *dataLength = bytes;
970 result = errSSLWouldBlock;
971 }
972 else
973 {
974 *dataLength = 0;
975
976 if (errno == EAGAIN)
977 result = errSSLWouldBlock;
978 else
979 result = errSSLClosedAbort;
980 }
981
982 return (result);
983}
984
985
986/*
987 * 'http_tls_initialize()' - Initialize the TLS stack.
988 */
989
990static void
991http_tls_initialize(void)
992{
993 /*
994 * Nothing to do...
995 */
996}
997
998
999/*
1000 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
1001 */
1002
1003static size_t
1004http_tls_pending(http_t *http) /* I - HTTP connection */
1005{
1006 size_t bytes; /* Bytes that are available */
1007
1008
1009 if (!SSLGetBufferedReadSize(http->tls, &bytes))
1010 return (bytes);
1011
1012 return (0);
1013}
1014
1015
1016/*
1017 * 'http_tls_read()' - Read from a SSL/TLS connection.
1018 */
1019
1020static int /* O - Bytes read */
41e0907c 1021http_tls_read(http_t *http, /* I - HTTP connection */
2c85b752
MS
1022 char *buf, /* I - Buffer to store data */
1023 int len) /* I - Length of buffer */
1024{
1025 int result; /* Return value */
1026 OSStatus error; /* Error info */
1027 size_t processed; /* Number of bytes processed */
1028
1029
1030 error = SSLRead(http->tls, buf, len, &processed);
1031 DEBUG_printf(("6http_tls_read: error=%d, processed=%d", (int)error,
1032 (int)processed));
1033 switch (error)
1034 {
1035 case 0 :
1036 result = (int)processed;
1037 break;
1038
1039 case errSSLWouldBlock :
1040 if (processed)
1041 result = (int)processed;
1042 else
1043 {
1044 result = -1;
1045 errno = EINTR;
1046 }
1047 break;
1048
1049 case errSSLClosedGraceful :
1050 default :
1051 if (processed)
1052 result = (int)processed;
1053 else
1054 {
1055 result = -1;
1056 errno = EPIPE;
1057 }
1058 break;
1059 }
1060
1061 return (result);
1062}
1063
1064
1065/*
1066 * 'http_tls_set_credentials()' - Set the TLS credentials.
1067 */
1068
1069static int /* O - Status of connection */
41e0907c 1070http_tls_set_credentials(http_t *http) /* I - HTTP connection */
2c85b752
MS
1071{
1072 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1073 OSStatus error = 0; /* Error code */
1074 http_tls_credentials_t credentials = NULL;
1075 /* TLS credentials */
1076
1077
1078 DEBUG_printf(("7http_tls_set_credentials(%p)", http));
1079
1080 /*
1081 * Prefer connection specific credentials...
1082 */
1083
1084 if ((credentials = http->tls_credentials) == NULL)
1085 credentials = cg->tls_credentials;
1086
1087 if (credentials)
1088 {
1089 error = SSLSetCertificate(http->tls, credentials);
1090 DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d",
1091 (int)error));
1092 }
1093 else
1094 DEBUG_puts("4http_tls_set_credentials: No credentials to set.");
1095
1096 return (error);
1097}
1098
1099
1100/*
1101 * 'http_tls_start()' - Set up SSL/TLS support on a connection.
1102 */
1103
1104static int /* O - 0 on success, -1 on failure */
41e0907c 1105http_tls_start(http_t *http) /* I - HTTP connection */
2c85b752
MS
1106{
1107 char hostname[256], /* Hostname */
1108 *hostptr; /* Pointer into hostname */
1109 _cups_globals_t *cg = _cupsGlobals();
1110 /* Pointer to library globals */
1111 OSStatus error; /* Error code */
1112 const char *message = NULL;/* Error message */
1113 cups_array_t *credentials; /* Credentials array */
1114 cups_array_t *names; /* CUPS distinguished names */
1115 CFArrayRef dn_array; /* CF distinguished names array */
1116 CFIndex count; /* Number of credentials */
1117 CFDataRef data; /* Certificate data */
1118 int i; /* Looping var */
1119 http_credential_t *credential; /* Credential data */
1120
1121
1122 DEBUG_printf(("7http_tls_start(http=%p)", http));
1123
c913d726 1124#ifdef HAVE_SECKEYCHAINOPEN
41e0907c 1125 if (http->mode == _HTTP_MODE_SERVER && !tls_keychain)
c913d726
MS
1126#else
1127 if (http->mode == _HTTP_MODE_SERVER)
1128#endif /* HAVE_SECKEYCHAINOPEN */
2c85b752 1129 {
41e0907c
MS
1130 DEBUG_puts("4http_tls_start: cupsSetServerCredentials not called.");
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
MS
1136 }
1137
72d05bc9 1138 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL)
2c85b752
MS
1139 {
1140 DEBUG_puts("4http_tls_start: SSLCreateContext failed.");
1141 http->error = errno = ENOMEM;
1142 http->status = HTTP_STATUS_ERROR;
1143 _cupsSetHTTPError(HTTP_STATUS_ERROR);
1144
1145 return (-1);
1146 }
1147
1148 error = SSLSetConnection(http->tls, http);
1149 DEBUG_printf(("4http_tls_start: SSLSetConnection, error=%d", (int)error));
1150
1151 if (!error)
1152 {
1153 error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write);
1154 DEBUG_printf(("4http_tls_start: SSLSetIOFuncs, error=%d", (int)error));
1155 }
1156
1157 if (!error)
1158 {
1159 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth,
1160 true);
1161 DEBUG_printf(("4http_tls_start: SSLSetSessionOption, error=%d",
1162 (int)error));
1163 }
1164
41e0907c 1165 if (!error && http->mode == _HTTP_MODE_CLIENT)
2c85b752 1166 {
41e0907c
MS
1167 /*
1168 * Client: set client-side credentials, if any...
1169 */
1170
2c85b752
MS
1171 if (cg->client_cert_cb)
1172 {
1173 error = SSLSetSessionOption(http->tls,
1174 kSSLSessionOptionBreakOnCertRequested, true);
1175 DEBUG_printf(("4http_tls_start: kSSLSessionOptionBreakOnCertRequested, "
1176 "error=%d", (int)error));
1177 }
1178 else
1179 {
d3d89474
MS
1180 error = http_tls_set_credentials(http);
1181 DEBUG_printf(("4http_tls_start: http_tls_set_credentials, error=%d",
2c85b752
MS
1182 (int)error));
1183 }
1184 }
41e0907c
MS
1185 else if (!error)
1186 {
1187 /*
1188 * Server: find/create a certificate for TLS...
1189 */
1190
1191 if (http->fields[HTTP_FIELD_HOST][0])
1192 {
1193 /*
1194 * Use hostname for TLS upgrade...
1195 */
1196
1197 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
1198 }
1199 else
1200 {
1201 /*
1202 * Resolve hostname from connection address...
1203 */
1204
1205 http_addr_t addr; /* Connection address */
1206 socklen_t addrlen; /* Length of address */
1207
1208 addrlen = sizeof(addr);
1209 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
1210 {
1211 DEBUG_printf(("4http_tls_start: Unable to get socket address: %s", strerror(errno)));
1212 hostname[0] = '\0';
1213 }
1214 else if (httpAddrLocalhost(&addr))
1215 hostname[0] = '\0';
1216 else
1217 httpAddrString(&addr, hostname, sizeof(hostname));
1218 }
1219
eb66bc71 1220#ifdef HAVE_SECKEYCHAINOPEN
41e0907c
MS
1221 if (hostname[0])
1222 http->tls_credentials = http_cdsa_copy_server(hostname);
1223 else if (tls_common_name)
1224 http->tls_credentials = http_cdsa_copy_server(tls_common_name);
1225
1226 if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name))
1227 {
1228 DEBUG_printf(("4http_tls_start: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name));
1229
1230 if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400))
1231 {
1232 DEBUG_puts("4http_tls_start: cupsMakeServerCredentials failed.");
1233 http->error = errno = EINVAL;
1234 http->status = HTTP_STATUS_ERROR;
1235 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
1236
1237 return (-1);
1238 }
1239
1240 http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name);
1241 }
eb66bc71 1242#endif /* HAVE_SECKEYCHAINOPEN */
41e0907c
MS
1243
1244 if (!http->tls_credentials)
1245 {
1246 DEBUG_puts("4http_tls_start: Unable to find server credentials.");
1247 http->error = errno = EINVAL;
1248 http->status = HTTP_STATUS_ERROR;
1249 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1);
1250
1251 return (-1);
1252 }
1253
1254 error = SSLSetCertificate(http->tls, http->tls_credentials);
1255
1256 DEBUG_printf(("4http_tls_start: SSLSetCertificate, error=%d", (int)error));
1257 }
1258
1259 DEBUG_printf(("4http_tls_start: tls_credentials=%p", http->tls_credentials));
2c85b752
MS
1260
1261 /*
1262 * Let the server know which hostname/domain we are trying to connect to
1263 * in case it wants to serve up a certificate with a matching common name.
1264 */
1265
41e0907c 1266 if (!error && http->mode == _HTTP_MODE_CLIENT)
2c85b752 1267 {
41e0907c
MS
1268 /*
1269 * Client: get the hostname to use for TLS...
1270 */
1271
1272 if (httpAddrLocalhost(http->hostaddr))
1273 {
1274 strlcpy(hostname, "localhost", sizeof(hostname));
1275 }
1276 else
1277 {
1278 /*
1279 * Otherwise make sure the hostname we have does not end in a trailing dot.
1280 */
1281
1282 strlcpy(hostname, http->hostname, sizeof(hostname));
1283 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1284 *hostptr == '.')
1285 *hostptr = '\0';
1286 }
1287
2c85b752
MS
1288 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
1289
41e0907c 1290 DEBUG_printf(("4http_tls_start: SSLSetPeerDomainName, error=%d", (int)error));
2c85b752
MS
1291 }
1292
1293 if (!error)
1294 {
1295 int done = 0; /* Are we done yet? */
1296
1297 while (!error && !done)
1298 {
1299 error = SSLHandshake(http->tls);
1300
1301 DEBUG_printf(("4http_tls_start: SSLHandshake returned %d.", (int)error));
1302
1303 switch (error)
1304 {
1305 case noErr :
1306 done = 1;
1307 break;
1308
1309 case errSSLWouldBlock :
1310 error = noErr; /* Force a retry */
1311 usleep(1000); /* in 1 millisecond */
1312 break;
1313
1314 case errSSLServerAuthCompleted :
1315 error = 0;
1316 if (cg->server_cert_cb)
1317 {
1318 error = httpCopyCredentials(http, &credentials);
1319 if (!error)
1320 {
1321 error = (cg->server_cert_cb)(http, http->tls, credentials,
1322 cg->server_cert_data);
1323 httpFreeCredentials(credentials);
1324 }
1325
1326 DEBUG_printf(("4http_tls_start: Server certificate callback "
1327 "returned %d.", (int)error));
1328 }
1329 break;
1330
1331 case errSSLClientCertRequested :
1332 error = 0;
1333
1334 if (cg->client_cert_cb)
1335 {
1336 names = NULL;
1337 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) &&
1338 dn_array)
1339 {
1340 if ((names = cupsArrayNew(NULL, NULL)) != NULL)
1341 {
1342 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++)
1343 {
1344 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i);
1345
1346 if ((credential = malloc(sizeof(*credential))) != NULL)
1347 {
1348 credential->datalen = CFDataGetLength(data);
1349 if ((credential->data = malloc(credential->datalen)))
1350 {
1351 memcpy((void *)credential->data, CFDataGetBytePtr(data),
1352 credential->datalen);
1353 cupsArrayAdd(names, credential);
1354 }
1355 else
1356 free(credential);
1357 }
1358 }
1359 }
1360
1361 CFRelease(dn_array);
1362 }
1363
1364 if (!error)
1365 {
1366 error = (cg->client_cert_cb)(http, http->tls, names,
1367 cg->client_cert_data);
1368
1369 DEBUG_printf(("4http_tls_start: Client certificate callback "
1370 "returned %d.", (int)error));
1371 }
1372
1373 httpFreeCredentials(names);
1374 }
1375 break;
1376
1377 case errSSLUnknownRootCert :
1378 message = _("Unable to establish a secure connection to host "
1379 "(untrusted certificate).");
1380 break;
1381
1382 case errSSLNoRootCert :
1383 message = _("Unable to establish a secure connection to host "
1384 "(self-signed certificate).");
1385 break;
1386
1387 case errSSLCertExpired :
1388 message = _("Unable to establish a secure connection to host "
1389 "(expired certificate).");
1390 break;
1391
1392 case errSSLCertNotYetValid :
1393 message = _("Unable to establish a secure connection to host "
1394 "(certificate not yet valid).");
1395 break;
1396
1397 case errSSLHostNameMismatch :
1398 message = _("Unable to establish a secure connection to host "
1399 "(host name mismatch).");
1400 break;
1401
1402 case errSSLXCertChainInvalid :
1403 message = _("Unable to establish a secure connection to host "
1404 "(certificate chain invalid).");
1405 break;
1406
1407 case errSSLConnectionRefused :
1408 message = _("Unable to establish a secure connection to host "
1409 "(peer dropped connection before responding).");
1410 break;
1411
1412 default :
1413 break;
1414 }
1415 }
1416 }
1417
1418 if (error)
1419 {
1420 http->error = error;
1421 http->status = HTTP_STATUS_ERROR;
1422 errno = ECONNREFUSED;
1423
1424 CFRelease(http->tls);
1425 http->tls = NULL;
1426
1427 /*
1428 * If an error string wasn't set by the callbacks use a generic one...
1429 */
1430
1431 if (!message)
1432#ifdef HAVE_CSSMERRORSTRING
1433 message = cssmErrorString(error);
1434#else
1435 message = _("Unable to establish a secure connection to host.");
1436#endif /* HAVE_CSSMERRORSTRING */
1437
1438 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
1439
1440 return (-1);
1441 }
1442
1443 return (0);
1444}
1445
1446
1447/*
1448 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
1449 */
1450
1451static void
41e0907c 1452http_tls_stop(http_t *http) /* I - HTTP connection */
2c85b752
MS
1453{
1454 while (SSLClose(http->tls) == errSSLWouldBlock)
1455 usleep(1000);
1456
1457 CFRelease(http->tls);
1458
1459 if (http->tls_credentials)
1460 CFRelease(http->tls_credentials);
1461
1462 http->tls = NULL;
1463 http->tls_credentials = NULL;
1464}
1465
1466
1467/*
1468 * 'http_tls_write()' - Write to a SSL/TLS connection.
1469 */
1470
1471static int /* O - Bytes written */
41e0907c 1472http_tls_write(http_t *http, /* I - HTTP connection */
2c85b752
MS
1473 const char *buf, /* I - Buffer holding data */
1474 int len) /* I - Length of buffer */
1475{
1476 ssize_t result; /* Return value */
1477 OSStatus error; /* Error info */
1478 size_t processed; /* Number of bytes processed */
1479
1480
1481 DEBUG_printf(("2http_tls_write(http=%p, buf=%p, len=%d)", http, buf, len));
1482
1483 error = SSLWrite(http->tls, buf, len, &processed);
1484
1485 switch (error)
1486 {
1487 case 0 :
1488 result = (int)processed;
1489 break;
1490
1491 case errSSLWouldBlock :
1492 if (processed)
1493 {
1494 result = (int)processed;
1495 }
1496 else
1497 {
1498 result = -1;
1499 errno = EINTR;
1500 }
1501 break;
1502
1503 case errSSLClosedGraceful :
1504 default :
1505 if (processed)
1506 {
1507 result = (int)processed;
1508 }
1509 else
1510 {
1511 result = -1;
1512 errno = EPIPE;
1513 }
1514 break;
1515 }
1516
1517 DEBUG_printf(("3http_tls_write: Returning %d.", (int)result));
1518
1519 return ((int)result);
1520}
1521
1522
d3d89474 1523#if 0
2c85b752
MS
1524/*
1525 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
1526 */
1527
1528int /* O - 1 on success, 0 on error */
1529cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */
1530{
1531 while (SSLClose(con->http.tls) == errSSLWouldBlock)
1532 usleep(1000);
1533
1534 CFRelease(con->http.tls);
1535 con->http.tls = NULL;
1536
1537 if (con->http.tls_credentials)
1538 CFRelease(con->http.tls_credentials);
1539
1540 return (1);
1541}
1542
1543
1544/*
1545 * 'cupsdStartTLS()' - Start a secure session with the client.
1546 */
1547
1548int /* O - 1 on success, 0 on error */
1549cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */
1550{
1551 OSStatus error = 0; /* Error code */
1552 SecTrustRef peerTrust; /* Peer certificates */
1553
1554
1555 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
1556 con->http.fd);
1557
1558 con->http.tls_credentials = copy_cdsa_certificate(con);
1559
1560 if (!con->http.tls_credentials)
1561 {
1562 /*
1563 * No keychain (yet), make a self-signed certificate...
1564 */
1565
1566 if (make_certificate(con))
1567 con->http.tls_credentials = copy_cdsa_certificate(con);
1568 }
1569
1570 if (!con->http.tls_credentials)
1571 {
1572 cupsdLogMessage(CUPSD_LOG_ERROR,
1573 "Could not find signing key in keychain \"%s\"",
1574 ServerCertificate);
1575 error = errSSLBadConfiguration;
1576 }
1577
1578 if (!error)
1579 con->http.tls = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide,
1580 kSSLStreamType);
1581
1582 if (!error)
1583 error = SSLSetIOFuncs(con->http.tls, http_cdsa_read, http_cdsa_write);
1584
1585 if (!error)
1586 error = SSLSetConnection(con->http.tls, HTTP(con));
1587
1588 if (!error)
1589 error = SSLSetCertificate(con->http.tls, con->http.tls_credentials);
1590
1591 if (!error)
1592 {
1593 /*
1594 * Perform SSL/TLS handshake
1595 */
1596
1597 while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock)
1598 usleep(1000);
1599 }
1600
1601 if (error)
1602 {
1603 cupsdLogMessage(CUPSD_LOG_ERROR,
1604 "Unable to encrypt connection from %s - %s (%d)",
1605 con->http.hostname, cssmErrorString(error), (int)error);
1606
1607 con->http.error = error;
1608 con->http.status = HTTP_ERROR;
1609
1610 if (con->http.tls)
1611 {
1612 CFRelease(con->http.tls);
1613 con->http.tls = NULL;
1614 }
1615
1616 if (con->http.tls_credentials)
1617 {
1618 CFRelease(con->http.tls_credentials);
1619 con->http.tls_credentials = NULL;
1620 }
1621
1622 return (0);
1623 }
1624
1625 cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
1626 con->http.hostname);
1627
1628 if (!SSLCopyPeerTrust(con->http.tls, &peerTrust) && peerTrust)
1629 {
1630 cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates.",
1631 (int)SecTrustGetCertificateCount(peerTrust));
1632 CFRelease(peerTrust);
1633 }
1634 else
1635 cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates.");
1636
1637 return (1);
1638}
d3d89474 1639#endif /* 0 */
2c85b752
MS
1640
1641
1642/*
1643 * End of "$Id$".
1644 */