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