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