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