]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/tls-darwin.c
Make sure we don't use functions that are not available.
[thirdparty/cups.git] / cups / tls-darwin.c
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
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),
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
371 http_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
411 /*
412 * 'httpCredentialsAreTrusted()' - Return whether the credentials are trusted.
413 *
414 * @since CUPS 2.0@
415 */
416
417 int /* O - 1 if trusted, 0 if not/unknown */
418 httpCredentialsAreTrusted(
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
433 time_t /* O - Expiration date of credentials */
434 httpCredentialsGetExpiration(
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
449 int /* O - 1 if valid, 0 otherwise */
450 httpCredentialsIsValidName(
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
461 /*
462 * 'httpCredentialsString()' - Return a string representing the credentials.
463 *
464 * @since CUPS 2.0@
465 */
466
467 size_t /* O - Total size of credentials string */
468 httpCredentialsString(
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
482 /*
483 * '_httpFreeCredentials()' - Free internal credentials.
484 */
485
486 void
487 _httpFreeCredentials(
488 http_tls_credentials_t credentials) /* I - Internal credentials */
489 {
490 if (!credentials)
491 return;
492
493 CFRelease(credentials);
494 }
495
496
497 /*
498 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
499 *
500 * @since CUPS 2.0@
501 */
502
503 int /* O - 0 on success, -1 on error */
504 httpLoadCredentials(
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 {
509 (void)path;
510 (void)credentials;
511 (void)common_name;
512
513 return (-1);
514
515 #if 0
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);
582 #endif /* 0 */
583 }
584
585
586 #if 0
587 /*
588 * 'cupsMakeCredentials()' - Create self-signed credentials for the given
589 * name.
590 *
591 * @since CUPS 2.0@
592 */
593
594 int /* O - 0 on success, -1 on error */
595 cupsMakeCredentials(
596 const char *path, /* I - Keychain/PKCS#12 path */
597 cups_array_t **credentials, /* O - Credentials */
598 const char *common_name) /* I - Common name for X.509 cert */
599 {
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
613
614 if (credentials)
615 *credentials = NULL;
616
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,
648 kSecCSRBasicContraintsPathLen, 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
677 cleanup:
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));
780 }
781 #endif /* 0 */
782
783
784 /*
785 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
786 *
787 * @since CUPS 2.0@
788 */
789
790 int /* O - -1 on error, 0 on success */
791 httpSaveCredentials(
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
804 #ifdef HAVE_SECKEYCHAINOPEN
805 /*
806 * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain.
807 */
808
809 static CFArrayRef /* O - Array of certificates or NULL */
810 http_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 }
873 #endif /* HAVE_SECKEYCHAINOPEN */
874
875
876 /*
877 * 'http_cdsa_read()' - Read function for the CDSA library.
878 */
879
880 static OSStatus /* O - -1 on error, 0 on success */
881 http_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
944 static OSStatus /* O - -1 on error, 0 on success */
945 http_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
990 static void
991 http_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
1003 static size_t
1004 http_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
1020 static int /* O - Bytes read */
1021 http_tls_read(http_t *http, /* I - HTTP connection */
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
1069 static int /* O - Status of connection */
1070 http_tls_set_credentials(http_t *http) /* I - HTTP connection */
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
1104 static int /* O - 0 on success, -1 on failure */
1105 http_tls_start(http_t *http) /* I - HTTP connection */
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
1124 if (http->mode == _HTTP_MODE_SERVER && !tls_keychain)
1125 {
1126 DEBUG_puts("4http_tls_start: cupsSetServerCredentials not called.");
1127 http->error = errno = EINVAL;
1128 http->status = HTTP_STATUS_ERROR;
1129 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
1130
1131 return (-1);
1132 }
1133
1134 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL)
1135 {
1136 DEBUG_puts("4http_tls_start: SSLCreateContext failed.");
1137 http->error = errno = ENOMEM;
1138 http->status = HTTP_STATUS_ERROR;
1139 _cupsSetHTTPError(HTTP_STATUS_ERROR);
1140
1141 return (-1);
1142 }
1143
1144 error = SSLSetConnection(http->tls, http);
1145 DEBUG_printf(("4http_tls_start: SSLSetConnection, error=%d", (int)error));
1146
1147 if (!error)
1148 {
1149 error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write);
1150 DEBUG_printf(("4http_tls_start: SSLSetIOFuncs, error=%d", (int)error));
1151 }
1152
1153 if (!error)
1154 {
1155 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth,
1156 true);
1157 DEBUG_printf(("4http_tls_start: SSLSetSessionOption, error=%d",
1158 (int)error));
1159 }
1160
1161 if (!error && http->mode == _HTTP_MODE_CLIENT)
1162 {
1163 /*
1164 * Client: set client-side credentials, if any...
1165 */
1166
1167 if (cg->client_cert_cb)
1168 {
1169 error = SSLSetSessionOption(http->tls,
1170 kSSLSessionOptionBreakOnCertRequested, true);
1171 DEBUG_printf(("4http_tls_start: kSSLSessionOptionBreakOnCertRequested, "
1172 "error=%d", (int)error));
1173 }
1174 else
1175 {
1176 error = http_tls_set_credentials(http);
1177 DEBUG_printf(("4http_tls_start: http_tls_set_credentials, error=%d",
1178 (int)error));
1179 }
1180 }
1181 else if (!error)
1182 {
1183 /*
1184 * Server: find/create a certificate for TLS...
1185 */
1186
1187 if (http->fields[HTTP_FIELD_HOST][0])
1188 {
1189 /*
1190 * Use hostname for TLS upgrade...
1191 */
1192
1193 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
1194 }
1195 else
1196 {
1197 /*
1198 * Resolve hostname from connection address...
1199 */
1200
1201 http_addr_t addr; /* Connection address */
1202 socklen_t addrlen; /* Length of address */
1203
1204 addrlen = sizeof(addr);
1205 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
1206 {
1207 DEBUG_printf(("4http_tls_start: Unable to get socket address: %s", strerror(errno)));
1208 hostname[0] = '\0';
1209 }
1210 else if (httpAddrLocalhost(&addr))
1211 hostname[0] = '\0';
1212 else
1213 httpAddrString(&addr, hostname, sizeof(hostname));
1214 }
1215
1216 #ifdef HAVE_SECKEYCHAINOPEN
1217 if (hostname[0])
1218 http->tls_credentials = http_cdsa_copy_server(hostname);
1219 else if (tls_common_name)
1220 http->tls_credentials = http_cdsa_copy_server(tls_common_name);
1221
1222 if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name))
1223 {
1224 DEBUG_printf(("4http_tls_start: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name));
1225
1226 if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400))
1227 {
1228 DEBUG_puts("4http_tls_start: cupsMakeServerCredentials failed.");
1229 http->error = errno = EINVAL;
1230 http->status = HTTP_STATUS_ERROR;
1231 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
1232
1233 return (-1);
1234 }
1235
1236 http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name);
1237 }
1238 #endif /* HAVE_SECKEYCHAINOPEN */
1239
1240 if (!http->tls_credentials)
1241 {
1242 DEBUG_puts("4http_tls_start: Unable to find server credentials.");
1243 http->error = errno = EINVAL;
1244 http->status = HTTP_STATUS_ERROR;
1245 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1);
1246
1247 return (-1);
1248 }
1249
1250 error = SSLSetCertificate(http->tls, http->tls_credentials);
1251
1252 DEBUG_printf(("4http_tls_start: SSLSetCertificate, error=%d", (int)error));
1253 }
1254
1255 DEBUG_printf(("4http_tls_start: tls_credentials=%p", http->tls_credentials));
1256
1257 /*
1258 * Let the server know which hostname/domain we are trying to connect to
1259 * in case it wants to serve up a certificate with a matching common name.
1260 */
1261
1262 if (!error && http->mode == _HTTP_MODE_CLIENT)
1263 {
1264 /*
1265 * Client: get the hostname to use for TLS...
1266 */
1267
1268 if (httpAddrLocalhost(http->hostaddr))
1269 {
1270 strlcpy(hostname, "localhost", sizeof(hostname));
1271 }
1272 else
1273 {
1274 /*
1275 * Otherwise make sure the hostname we have does not end in a trailing dot.
1276 */
1277
1278 strlcpy(hostname, http->hostname, sizeof(hostname));
1279 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1280 *hostptr == '.')
1281 *hostptr = '\0';
1282 }
1283
1284 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
1285
1286 DEBUG_printf(("4http_tls_start: SSLSetPeerDomainName, error=%d", (int)error));
1287 }
1288
1289 if (!error)
1290 {
1291 int done = 0; /* Are we done yet? */
1292
1293 while (!error && !done)
1294 {
1295 error = SSLHandshake(http->tls);
1296
1297 DEBUG_printf(("4http_tls_start: SSLHandshake returned %d.", (int)error));
1298
1299 switch (error)
1300 {
1301 case noErr :
1302 done = 1;
1303 break;
1304
1305 case errSSLWouldBlock :
1306 error = noErr; /* Force a retry */
1307 usleep(1000); /* in 1 millisecond */
1308 break;
1309
1310 case errSSLServerAuthCompleted :
1311 error = 0;
1312 if (cg->server_cert_cb)
1313 {
1314 error = httpCopyCredentials(http, &credentials);
1315 if (!error)
1316 {
1317 error = (cg->server_cert_cb)(http, http->tls, credentials,
1318 cg->server_cert_data);
1319 httpFreeCredentials(credentials);
1320 }
1321
1322 DEBUG_printf(("4http_tls_start: Server certificate callback "
1323 "returned %d.", (int)error));
1324 }
1325 break;
1326
1327 case errSSLClientCertRequested :
1328 error = 0;
1329
1330 if (cg->client_cert_cb)
1331 {
1332 names = NULL;
1333 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) &&
1334 dn_array)
1335 {
1336 if ((names = cupsArrayNew(NULL, NULL)) != NULL)
1337 {
1338 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++)
1339 {
1340 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i);
1341
1342 if ((credential = malloc(sizeof(*credential))) != NULL)
1343 {
1344 credential->datalen = CFDataGetLength(data);
1345 if ((credential->data = malloc(credential->datalen)))
1346 {
1347 memcpy((void *)credential->data, CFDataGetBytePtr(data),
1348 credential->datalen);
1349 cupsArrayAdd(names, credential);
1350 }
1351 else
1352 free(credential);
1353 }
1354 }
1355 }
1356
1357 CFRelease(dn_array);
1358 }
1359
1360 if (!error)
1361 {
1362 error = (cg->client_cert_cb)(http, http->tls, names,
1363 cg->client_cert_data);
1364
1365 DEBUG_printf(("4http_tls_start: Client certificate callback "
1366 "returned %d.", (int)error));
1367 }
1368
1369 httpFreeCredentials(names);
1370 }
1371 break;
1372
1373 case errSSLUnknownRootCert :
1374 message = _("Unable to establish a secure connection to host "
1375 "(untrusted certificate).");
1376 break;
1377
1378 case errSSLNoRootCert :
1379 message = _("Unable to establish a secure connection to host "
1380 "(self-signed certificate).");
1381 break;
1382
1383 case errSSLCertExpired :
1384 message = _("Unable to establish a secure connection to host "
1385 "(expired certificate).");
1386 break;
1387
1388 case errSSLCertNotYetValid :
1389 message = _("Unable to establish a secure connection to host "
1390 "(certificate not yet valid).");
1391 break;
1392
1393 case errSSLHostNameMismatch :
1394 message = _("Unable to establish a secure connection to host "
1395 "(host name mismatch).");
1396 break;
1397
1398 case errSSLXCertChainInvalid :
1399 message = _("Unable to establish a secure connection to host "
1400 "(certificate chain invalid).");
1401 break;
1402
1403 case errSSLConnectionRefused :
1404 message = _("Unable to establish a secure connection to host "
1405 "(peer dropped connection before responding).");
1406 break;
1407
1408 default :
1409 break;
1410 }
1411 }
1412 }
1413
1414 if (error)
1415 {
1416 http->error = error;
1417 http->status = HTTP_STATUS_ERROR;
1418 errno = ECONNREFUSED;
1419
1420 CFRelease(http->tls);
1421 http->tls = NULL;
1422
1423 /*
1424 * If an error string wasn't set by the callbacks use a generic one...
1425 */
1426
1427 if (!message)
1428 #ifdef HAVE_CSSMERRORSTRING
1429 message = cssmErrorString(error);
1430 #else
1431 message = _("Unable to establish a secure connection to host.");
1432 #endif /* HAVE_CSSMERRORSTRING */
1433
1434 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
1435
1436 return (-1);
1437 }
1438
1439 return (0);
1440 }
1441
1442
1443 /*
1444 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
1445 */
1446
1447 static void
1448 http_tls_stop(http_t *http) /* I - HTTP connection */
1449 {
1450 while (SSLClose(http->tls) == errSSLWouldBlock)
1451 usleep(1000);
1452
1453 CFRelease(http->tls);
1454
1455 if (http->tls_credentials)
1456 CFRelease(http->tls_credentials);
1457
1458 http->tls = NULL;
1459 http->tls_credentials = NULL;
1460 }
1461
1462
1463 /*
1464 * 'http_tls_write()' - Write to a SSL/TLS connection.
1465 */
1466
1467 static int /* O - Bytes written */
1468 http_tls_write(http_t *http, /* I - HTTP connection */
1469 const char *buf, /* I - Buffer holding data */
1470 int len) /* I - Length of buffer */
1471 {
1472 ssize_t result; /* Return value */
1473 OSStatus error; /* Error info */
1474 size_t processed; /* Number of bytes processed */
1475
1476
1477 DEBUG_printf(("2http_tls_write(http=%p, buf=%p, len=%d)", http, buf, len));
1478
1479 error = SSLWrite(http->tls, buf, len, &processed);
1480
1481 switch (error)
1482 {
1483 case 0 :
1484 result = (int)processed;
1485 break;
1486
1487 case errSSLWouldBlock :
1488 if (processed)
1489 {
1490 result = (int)processed;
1491 }
1492 else
1493 {
1494 result = -1;
1495 errno = EINTR;
1496 }
1497 break;
1498
1499 case errSSLClosedGraceful :
1500 default :
1501 if (processed)
1502 {
1503 result = (int)processed;
1504 }
1505 else
1506 {
1507 result = -1;
1508 errno = EPIPE;
1509 }
1510 break;
1511 }
1512
1513 DEBUG_printf(("3http_tls_write: Returning %d.", (int)result));
1514
1515 return ((int)result);
1516 }
1517
1518
1519 #if 0
1520 /*
1521 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
1522 */
1523
1524 int /* O - 1 on success, 0 on error */
1525 cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */
1526 {
1527 while (SSLClose(con->http.tls) == errSSLWouldBlock)
1528 usleep(1000);
1529
1530 CFRelease(con->http.tls);
1531 con->http.tls = NULL;
1532
1533 if (con->http.tls_credentials)
1534 CFRelease(con->http.tls_credentials);
1535
1536 return (1);
1537 }
1538
1539
1540 /*
1541 * 'cupsdStartTLS()' - Start a secure session with the client.
1542 */
1543
1544 int /* O - 1 on success, 0 on error */
1545 cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */
1546 {
1547 OSStatus error = 0; /* Error code */
1548 SecTrustRef peerTrust; /* Peer certificates */
1549
1550
1551 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
1552 con->http.fd);
1553
1554 con->http.tls_credentials = copy_cdsa_certificate(con);
1555
1556 if (!con->http.tls_credentials)
1557 {
1558 /*
1559 * No keychain (yet), make a self-signed certificate...
1560 */
1561
1562 if (make_certificate(con))
1563 con->http.tls_credentials = copy_cdsa_certificate(con);
1564 }
1565
1566 if (!con->http.tls_credentials)
1567 {
1568 cupsdLogMessage(CUPSD_LOG_ERROR,
1569 "Could not find signing key in keychain \"%s\"",
1570 ServerCertificate);
1571 error = errSSLBadConfiguration;
1572 }
1573
1574 if (!error)
1575 con->http.tls = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide,
1576 kSSLStreamType);
1577
1578 if (!error)
1579 error = SSLSetIOFuncs(con->http.tls, http_cdsa_read, http_cdsa_write);
1580
1581 if (!error)
1582 error = SSLSetConnection(con->http.tls, HTTP(con));
1583
1584 if (!error)
1585 error = SSLSetCertificate(con->http.tls, con->http.tls_credentials);
1586
1587 if (!error)
1588 {
1589 /*
1590 * Perform SSL/TLS handshake
1591 */
1592
1593 while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock)
1594 usleep(1000);
1595 }
1596
1597 if (error)
1598 {
1599 cupsdLogMessage(CUPSD_LOG_ERROR,
1600 "Unable to encrypt connection from %s - %s (%d)",
1601 con->http.hostname, cssmErrorString(error), (int)error);
1602
1603 con->http.error = error;
1604 con->http.status = HTTP_ERROR;
1605
1606 if (con->http.tls)
1607 {
1608 CFRelease(con->http.tls);
1609 con->http.tls = NULL;
1610 }
1611
1612 if (con->http.tls_credentials)
1613 {
1614 CFRelease(con->http.tls_credentials);
1615 con->http.tls_credentials = NULL;
1616 }
1617
1618 return (0);
1619 }
1620
1621 cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
1622 con->http.hostname);
1623
1624 if (!SSLCopyPeerTrust(con->http.tls, &peerTrust) && peerTrust)
1625 {
1626 cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates.",
1627 (int)SecTrustGetCertificateCount(peerTrust));
1628 CFRelease(peerTrust);
1629 }
1630 else
1631 cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates.");
1632
1633 return (1);
1634 }
1635 #endif /* 0 */
1636
1637
1638 /*
1639 * End of "$Id$".
1640 */