]> git.ipfire.org Git - thirdparty/cups.git/blob - 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
1 /*
2 * "$Id$"
3 *
4 * TLS support code for CUPS on OS X.
5 *
6 * Copyright 2007-2014 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
18 /**** This file is included from http.c ****/
19
20 /*
21 * Include necessary headers...
22 */
23
24 #include <spawn.h>
25
26 extern char **environ;
27
28
29 /*
30 * Local globals...
31 */
32
33 #ifdef HAVE_SECKEYCHAINOPEN
34 static int tls_auto_create = 0;
35 /* Auto-create self-signed certs? */
36 static char *tls_common_name = NULL;
37 /* Default common name */
38 static SecKeychainRef tls_keychain = NULL;
39 /* Server cert keychain */
40 static char *tls_keypath = NULL;
41 /* Server cert keychain path */
42 static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
43 /* Mutex for keychain/certs */
44 #endif /* HAVE_SECKEYCHAINOPEN */
45
46
47 /*
48 * Local functions...
49 */
50
51 #ifdef HAVE_SECKEYCHAINOPEN
52 static CFArrayRef http_cdsa_copy_server(const char *common_name);
53 #endif /* HAVE_SECKEYCHAINOPEN */
54 static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength);
55 static OSStatus http_cdsa_write(SSLConnectionRef connection, const void *data, size_t *dataLength);
56
57
58 /*
59 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
60 *
61 * @since CUPS 2.0@
62 */
63
64 int /* O - 1 on success, 0 on failure */
65 cupsMakeServerCredentials(
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 {
72 #if defined(HAVE_SECGENERATESELFSIGNEDCERTIFICATE) && defined(HAVE_SECKEYCHAINOPEN)
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
86 (void)num_alt_names;
87 (void)alt_names;
88 (void)expiration_date;
89
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,
121 kSecCSRBasicContraintsPathLen, 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
150 cleanup:
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
172 #else /* !(HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN) */
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);
253 #endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN */
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
266 int /* O - 1 on success, 0 on failure */
267 cupsSetServerCredentials(
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 {
272 #ifdef HAVE_SECKEYCHAINOPEN
273 SecKeychainRef keychain = NULL;/* Temporary keychain */
274
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
291 if (tls_keypath)
292 _cupsStrFree(tls_keypath);
293
294 if (tls_common_name)
295 _cupsStrFree(tls_common_name);
296
297 /*
298 * Save the new keychain...
299 */
300
301 tls_keychain = keychain;
302 tls_keypath = _cupsStrAlloc(path);
303 tls_auto_create = auto_create;
304 tls_common_name = _cupsStrAlloc(common_name);
305
306 _cupsMutexUnlock(&tls_mutex);
307
308 return (1);
309
310 #else
311 return (0);
312 #endif /* HAVE_SECKEYCHAINOPEN */
313 }
314
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
323 int /* O - Status of call (0 = success) */
324 httpCopyCredentials(
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), (size_t)CFDataGetLength(data));
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
370 http_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 {
392 if ((data = CFDataCreate(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)))
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
409 /*
410 * 'httpCredentialsAreTrusted()' - Return whether the credentials are trusted.
411 *
412 * @since CUPS 2.0@
413 */
414
415 int /* O - 1 if trusted, 0 if not/unknown */
416 httpCredentialsAreTrusted(
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
431 time_t /* O - Expiration date of credentials */
432 httpCredentialsGetExpiration(
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
447 int /* O - 1 if valid, 0 otherwise */
448 httpCredentialsIsValidName(
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
459 /*
460 * 'httpCredentialsString()' - Return a string representing the credentials.
461 *
462 * @since CUPS 2.0@
463 */
464
465 size_t /* O - Total size of credentials string */
466 httpCredentialsString(
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
480 /*
481 * '_httpFreeCredentials()' - Free internal credentials.
482 */
483
484 void
485 _httpFreeCredentials(
486 http_tls_credentials_t credentials) /* I - Internal credentials */
487 {
488 if (!credentials)
489 return;
490
491 CFRelease(credentials);
492 }
493
494
495 /*
496 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
497 *
498 * @since CUPS 2.0@
499 */
500
501 int /* O - 0 on success, -1 on error */
502 httpLoadCredentials(
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 {
507 (void)path;
508 (void)credentials;
509 (void)common_name;
510
511 return (-1);
512
513 #if 0
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);
580 #endif /* 0 */
581 }
582
583
584 #if 0
585 /*
586 * 'cupsMakeCredentials()' - Create self-signed credentials for the given
587 * name.
588 *
589 * @since CUPS 2.0@
590 */
591
592 int /* O - 0 on success, -1 on error */
593 cupsMakeCredentials(
594 const char *path, /* I - Keychain/PKCS#12 path */
595 cups_array_t **credentials, /* O - Credentials */
596 const char *common_name) /* I - Common name for X.509 cert */
597 {
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
611
612 if (credentials)
613 *credentials = NULL;
614
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,
646 kSecCSRBasicContraintsPathLen, 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
675 cleanup:
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));
778 }
779 #endif /* 0 */
780
781
782 /*
783 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
784 *
785 * @since CUPS 2.0@
786 */
787
788 int /* O - -1 on error, 0 on success */
789 httpSaveCredentials(
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
802 #ifdef HAVE_SECKEYCHAINOPEN
803 /*
804 * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain.
805 */
806
807 static CFArrayRef /* O - Array of certificates or NULL */
808 http_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 }
871 #endif /* HAVE_SECKEYCHAINOPEN */
872
873
874 /*
875 * 'http_cdsa_read()' - Read function for the CDSA library.
876 */
877
878 static OSStatus /* O - -1 on error, 0 on success */
879 http_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
913 if ((size_t)bytes == *dataLength)
914 {
915 result = 0;
916 }
917 else if (bytes > 0)
918 {
919 *dataLength = (size_t)bytes;
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
942 static OSStatus /* O - -1 on error, 0 on success */
943 http_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
961 if ((size_t)bytes == *dataLength)
962 {
963 result = 0;
964 }
965 else if (bytes >= 0)
966 {
967 *dataLength = (size_t)bytes;
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
988 static void
989 http_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
1001 static size_t
1002 http_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
1018 static int /* O - Bytes read */
1019 http_tls_read(http_t *http, /* I - HTTP connection */
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
1028 error = SSLRead(http->tls, buf, (size_t)len, &processed);
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
1067 static int /* O - Status of connection */
1068 http_tls_set_credentials(http_t *http) /* I - HTTP connection */
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
1102 static int /* O - 0 on success, -1 on failure */
1103 http_tls_start(http_t *http) /* I - HTTP connection */
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
1122 #ifdef HAVE_SECKEYCHAINOPEN
1123 if (http->mode == _HTTP_MODE_SERVER && !tls_keychain)
1124 #else
1125 if (http->mode == _HTTP_MODE_SERVER)
1126 #endif /* HAVE_SECKEYCHAINOPEN */
1127 {
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);
1132
1133 return (-1);
1134 }
1135
1136 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL)
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
1163 if (!error && http->mode == _HTTP_MODE_CLIENT)
1164 {
1165 /*
1166 * Client: set client-side credentials, if any...
1167 */
1168
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 {
1178 error = http_tls_set_credentials(http);
1179 DEBUG_printf(("4http_tls_start: http_tls_set_credentials, error=%d",
1180 (int)error));
1181 }
1182 }
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
1218 #ifdef HAVE_SECKEYCHAINOPEN
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 }
1240 #endif /* HAVE_SECKEYCHAINOPEN */
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));
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
1264 if (!error && http->mode == _HTTP_MODE_CLIENT)
1265 {
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
1286 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
1287
1288 DEBUG_printf(("4http_tls_start: SSLSetPeerDomainName, error=%d", (int)error));
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 {
1346 credential->datalen = (size_t)CFDataGetLength(data);
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
1449 static void
1450 http_tls_stop(http_t *http) /* I - HTTP connection */
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
1469 static int /* O - Bytes written */
1470 http_tls_write(http_t *http, /* I - HTTP connection */
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
1481 error = SSLWrite(http->tls, buf, (size_t)len, &processed);
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
1521 #if 0
1522 /*
1523 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
1524 */
1525
1526 int /* O - 1 on success, 0 on error */
1527 cupsdEndTLS(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
1546 int /* O - 1 on success, 0 on error */
1547 cupsdStartTLS(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 }
1637 #endif /* 0 */
1638
1639
1640 /*
1641 * End of "$Id$".
1642 */