]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/tls-openssl.c
<rdar://problem/15313228> "Canceling stuck job after XXX seconds" message should...
[thirdparty/cups.git] / cups / tls-openssl.c
CommitLineData
2c85b752
MS
1/*
2 * "$Id$"
3 *
4 * TLS support code for CUPS using OpenSSL.
5 *
6 * Copyright 2007-2012 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
19/*
20 * Local functions...
21 */
22
23static int make_certificate(cupsd_client_t *con);
24#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
25/*
26 * BIO methods for OpenSSL...
27 */
28
29static int http_bio_write(BIO *h, const char *buf, int num);
30static int http_bio_read(BIO *h, char *buf, int size);
31static int http_bio_puts(BIO *h, const char *str);
32static long http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
33static int http_bio_new(BIO *h);
34static int http_bio_free(BIO *data);
35
36static BIO_METHOD http_bio_methods =
37 {
38 BIO_TYPE_SOCKET,
39 "http",
40 http_bio_write,
41 http_bio_read,
42 http_bio_puts,
43 NULL, /* http_bio_gets, */
44 http_bio_ctrl,
45 http_bio_new,
46 http_bio_free,
47 NULL,
48 };
49#endif /* HAVE_SSL && HAVE_LIBSSL */
50
51
52
53
54/*
55 * 'http_tls_initialize()' - Initialize the TLS stack.
56 */
57
58static void
59http_tls_initialize(void)
60{
61#ifdef HAVE_GNUTLS
62 /*
63 * Initialize GNU TLS...
64 */
65
66 gnutls_global_init();
67
68#elif defined(HAVE_LIBSSL)
69 /*
70 * Initialize OpenSSL...
71 */
72
73 SSL_load_error_strings();
74 SSL_library_init();
75
76 /*
77 * Using the current time is a dubious random seed, but on some systems
78 * it is the best we can do (on others, this seed isn't even used...)
79 */
80
81 CUPS_SRAND(time(NULL));
82
83 for (i = 0; i < sizeof(data); i ++)
84 data[i] = CUPS_RAND();
85
86 RAND_seed(data, sizeof(data));
87#endif /* HAVE_GNUTLS */
88}
89
90
91#ifdef HAVE_SSL
92/*
93 * 'http_tls_read()' - Read from a SSL/TLS connection.
94 */
95
96static int /* O - Bytes read */
97http_tls_read(http_t *http, /* I - Connection to server */
98 char *buf, /* I - Buffer to store data */
99 int len) /* I - Length of buffer */
100{
101# if defined(HAVE_LIBSSL)
102 return (SSL_read((SSL *)(http->tls), buf, len));
103
104# elif defined(HAVE_GNUTLS)
105 ssize_t result; /* Return value */
106
107
108 result = gnutls_record_recv(http->tls, buf, len);
109
110 if (result < 0 && !errno)
111 {
112 /*
113 * Convert GNU TLS error to errno value...
114 */
115
116 switch (result)
117 {
118 case GNUTLS_E_INTERRUPTED :
119 errno = EINTR;
120 break;
121
122 case GNUTLS_E_AGAIN :
123 errno = EAGAIN;
124 break;
125
126 default :
127 errno = EPIPE;
128 break;
129 }
130
131 result = -1;
132 }
133
134 return ((int)result);
135
136# elif defined(HAVE_CDSASSL)
137 int result; /* Return value */
138 OSStatus error; /* Error info */
139 size_t processed; /* Number of bytes processed */
140
141
142 error = SSLRead(http->tls, buf, len, &processed);
143 DEBUG_printf(("6http_tls_read: error=%d, processed=%d", (int)error,
144 (int)processed));
145 switch (error)
146 {
147 case 0 :
148 result = (int)processed;
149 break;
150
151 case errSSLWouldBlock :
152 if (processed)
153 result = (int)processed;
154 else
155 {
156 result = -1;
157 errno = EINTR;
158 }
159 break;
160
161 case errSSLClosedGraceful :
162 default :
163 if (processed)
164 result = (int)processed;
165 else
166 {
167 result = -1;
168 errno = EPIPE;
169 }
170 break;
171 }
172
173 return (result);
174
175# elif defined(HAVE_SSPISSL)
176 return _sspiRead((_sspi_struct_t*) http->tls, buf, len);
177# endif /* HAVE_LIBSSL */
178}
179#endif /* HAVE_SSL */
180
181
182#ifdef HAVE_SSL
183/*
184 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
185 */
186
187static int /* O - 0 on success, -1 on failure */
188http_setup_ssl(http_t *http) /* I - Connection to server */
189{
190 char hostname[256], /* Hostname */
191 *hostptr; /* Pointer into hostname */
192
193# ifdef HAVE_LIBSSL
194 SSL_CTX *context; /* Context for encryption */
195 BIO *bio; /* BIO data */
196 const char *message = NULL;/* Error message */
197# elif defined(HAVE_GNUTLS)
198 int status; /* Status of handshake */
199 gnutls_certificate_client_credentials *credentials;
200 /* TLS credentials */
201# elif defined(HAVE_CDSASSL)
202 _cups_globals_t *cg = _cupsGlobals();
203 /* Pointer to library globals */
204 OSStatus error; /* Error code */
205 const char *message = NULL;/* Error message */
206 cups_array_t *credentials; /* Credentials array */
207 cups_array_t *names; /* CUPS distinguished names */
208 CFArrayRef dn_array; /* CF distinguished names array */
209 CFIndex count; /* Number of credentials */
210 CFDataRef data; /* Certificate data */
211 int i; /* Looping var */
212 http_credential_t *credential; /* Credential data */
213# elif defined(HAVE_SSPISSL)
214 TCHAR username[256]; /* Username returned from GetUserName() */
215 TCHAR commonName[256];/* Common name for certificate */
216 DWORD dwSize; /* 32 bit size */
217# endif /* HAVE_LIBSSL */
218
219
220 DEBUG_printf(("7http_setup_ssl(http=%p)", http));
221
222 /*
223 * Get the hostname to use for SSL...
224 */
225
226 if (httpAddrLocalhost(http->hostaddr))
227 {
228 strlcpy(hostname, "localhost", sizeof(hostname));
229 }
230 else
231 {
232 /*
233 * Otherwise make sure the hostname we have does not end in a trailing dot.
234 */
235
236 strlcpy(hostname, http->hostname, sizeof(hostname));
237 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
238 *hostptr == '.')
239 *hostptr = '\0';
240 }
241
242# ifdef HAVE_LIBSSL
243 context = SSL_CTX_new(SSLv23_client_method());
244
245 SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
246
247 bio = BIO_new(_httpBIOMethods());
248 BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http);
249
250 http->tls = SSL_new(context);
251 SSL_set_bio(http->tls, bio, bio);
252
253# ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
254 SSL_set_tlsext_host_name(http->tls, hostname);
255# endif /* HAVE_SSL_SET_TLSEXT_HOST_NAME */
256
257 if (SSL_connect(http->tls) != 1)
258 {
259 unsigned long error; /* Error code */
260
261 while ((error = ERR_get_error()) != 0)
262 {
263 message = ERR_error_string(error, NULL);
264 DEBUG_printf(("8http_setup_ssl: %s", message));
265 }
266
267 SSL_CTX_free(context);
268 SSL_free(http->tls);
269 http->tls = NULL;
270
271# ifdef WIN32
272 http->error = WSAGetLastError();
273# else
274 http->error = errno;
275# endif /* WIN32 */
276 http->status = HTTP_STATUS_ERROR;
277
278 if (!message)
279 message = _("Unable to establish a secure connection to host.");
280
281 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
282
283 return (-1);
284 }
285
286# elif defined(HAVE_GNUTLS)
287 credentials = (gnutls_certificate_client_credentials *)
288 malloc(sizeof(gnutls_certificate_client_credentials));
289 if (credentials == NULL)
290 {
291 DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s",
292 strerror(errno)));
293 http->error = errno;
294 http->status = HTTP_STATUS_ERROR;
295 _cupsSetHTTPError(HTTP_STATUS_ERROR);
296
297 return (-1);
298 }
299
300 gnutls_certificate_allocate_credentials(credentials);
301
302 gnutls_init(&http->tls, GNUTLS_CLIENT);
303 gnutls_set_default_priority(http->tls);
304 gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname,
305 strlen(hostname));
306 gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
307 gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr)http);
308 gnutls_transport_set_pull_function(http->tls, _httpReadGNUTLS);
309 gnutls_transport_set_push_function(http->tls, _httpWriteGNUTLS);
310
311 while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
312 {
313 DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)",
314 status, gnutls_strerror(status)));
315
316 if (gnutls_error_is_fatal(status))
317 {
318 http->error = EIO;
319 http->status = HTTP_STATUS_ERROR;
320
321 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
322
323 gnutls_deinit(http->tls);
324 gnutls_certificate_free_credentials(*credentials);
325 free(credentials);
326 http->tls = NULL;
327
328 return (-1);
329 }
330 }
331
332 http->tls_credentials = credentials;
333
334# elif defined(HAVE_CDSASSL)
335 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide,
336 kSSLStreamType)) == NULL)
337 {
338 DEBUG_puts("4http_setup_ssl: SSLCreateContext failed.");
339 http->error = errno = ENOMEM;
340 http->status = HTTP_STATUS_ERROR;
341 _cupsSetHTTPError(HTTP_STATUS_ERROR);
342
343 return (-1);
344 }
345
346 error = SSLSetConnection(http->tls, http);
347 DEBUG_printf(("4http_setup_ssl: SSLSetConnection, error=%d", (int)error));
348
349 if (!error)
350 {
351 error = SSLSetIOFuncs(http->tls, _httpReadCDSA, _httpWriteCDSA);
352 DEBUG_printf(("4http_setup_ssl: SSLSetIOFuncs, error=%d", (int)error));
353 }
354
355 if (!error)
356 {
357 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth,
358 true);
359 DEBUG_printf(("4http_setup_ssl: SSLSetSessionOption, error=%d",
360 (int)error));
361 }
362
363 if (!error)
364 {
365 if (cg->client_cert_cb)
366 {
367 error = SSLSetSessionOption(http->tls,
368 kSSLSessionOptionBreakOnCertRequested, true);
369 DEBUG_printf(("4http_setup_ssl: kSSLSessionOptionBreakOnCertRequested, "
370 "error=%d", (int)error));
371 }
372 else
373 {
374 error = http_set_credentials(http);
375 DEBUG_printf(("4http_setup_ssl: http_set_credentials, error=%d",
376 (int)error));
377 }
378 }
379
380 /*
381 * Let the server know which hostname/domain we are trying to connect to
382 * in case it wants to serve up a certificate with a matching common name.
383 */
384
385 if (!error)
386 {
387 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
388
389 DEBUG_printf(("4http_setup_ssl: SSLSetPeerDomainName, error=%d",
390 (int)error));
391 }
392
393 if (!error)
394 {
395 int done = 0; /* Are we done yet? */
396
397 while (!error && !done)
398 {
399 error = SSLHandshake(http->tls);
400
401 DEBUG_printf(("4http_setup_ssl: SSLHandshake returned %d.", (int)error));
402
403 switch (error)
404 {
405 case noErr :
406 done = 1;
407 break;
408
409 case errSSLWouldBlock :
410 error = noErr; /* Force a retry */
411 usleep(1000); /* in 1 millisecond */
412 break;
413
414 case errSSLServerAuthCompleted :
415 error = 0;
416 if (cg->server_cert_cb)
417 {
418 error = httpCopyCredentials(http, &credentials);
419 if (!error)
420 {
421 error = (cg->server_cert_cb)(http, http->tls, credentials,
422 cg->server_cert_data);
423 httpFreeCredentials(credentials);
424 }
425
426 DEBUG_printf(("4http_setup_ssl: Server certificate callback "
427 "returned %d.", (int)error));
428 }
429 break;
430
431 case errSSLClientCertRequested :
432 error = 0;
433
434 if (cg->client_cert_cb)
435 {
436 names = NULL;
437 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) &&
438 dn_array)
439 {
440 if ((names = cupsArrayNew(NULL, NULL)) != NULL)
441 {
442 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++)
443 {
444 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i);
445
446 if ((credential = malloc(sizeof(*credential))) != NULL)
447 {
448 credential->datalen = CFDataGetLength(data);
449 if ((credential->data = malloc(credential->datalen)))
450 {
451 memcpy((void *)credential->data, CFDataGetBytePtr(data),
452 credential->datalen);
453 cupsArrayAdd(names, credential);
454 }
455 else
456 free(credential);
457 }
458 }
459 }
460
461 CFRelease(dn_array);
462 }
463
464 if (!error)
465 {
466 error = (cg->client_cert_cb)(http, http->tls, names,
467 cg->client_cert_data);
468
469 DEBUG_printf(("4http_setup_ssl: Client certificate callback "
470 "returned %d.", (int)error));
471 }
472
473 httpFreeCredentials(names);
474 }
475 break;
476
477 case errSSLUnknownRootCert :
478 message = _("Unable to establish a secure connection to host "
479 "(untrusted certificate).");
480 break;
481
482 case errSSLNoRootCert :
483 message = _("Unable to establish a secure connection to host "
484 "(self-signed certificate).");
485 break;
486
487 case errSSLCertExpired :
488 message = _("Unable to establish a secure connection to host "
489 "(expired certificate).");
490 break;
491
492 case errSSLCertNotYetValid :
493 message = _("Unable to establish a secure connection to host "
494 "(certificate not yet valid).");
495 break;
496
497 case errSSLHostNameMismatch :
498 message = _("Unable to establish a secure connection to host "
499 "(host name mismatch).");
500 break;
501
502 case errSSLXCertChainInvalid :
503 message = _("Unable to establish a secure connection to host "
504 "(certificate chain invalid).");
505 break;
506
507 case errSSLConnectionRefused :
508 message = _("Unable to establish a secure connection to host "
509 "(peer dropped connection before responding).");
510 break;
511
512 default :
513 break;
514 }
515 }
516 }
517
518 if (error)
519 {
520 http->error = error;
521 http->status = HTTP_STATUS_ERROR;
522 errno = ECONNREFUSED;
523
524 CFRelease(http->tls);
525 http->tls = NULL;
526
527 /*
528 * If an error string wasn't set by the callbacks use a generic one...
529 */
530
531 if (!message)
532#ifdef HAVE_CSSMERRORSTRING
533 message = cssmErrorString(error);
534#else
535 message = _("Unable to establish a secure connection to host.");
536#endif /* HAVE_CSSMERRORSTRING */
537
538 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
539
540 return (-1);
541 }
542
543# elif defined(HAVE_SSPISSL)
544 http->tls = _sspiAlloc();
545
546 if (!http->tls)
547 {
548 _cupsSetHTTPError(HTTP_STATUS_ERROR);
549 return (-1);
550 }
551
552 http->tls->sock = http->fd;
553 dwSize = sizeof(username) / sizeof(TCHAR);
554 GetUserName(username, &dwSize);
555 _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
556 sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
557
558 if (!_sspiGetCredentials(http->tls_credentials, L"ClientContainer",
559 commonName, FALSE))
560 {
561 _sspiFree(http->tls_credentials);
562 http->tls_credentials = NULL;
563
564 http->error = EIO;
565 http->status = HTTP_STATUS_ERROR;
566
567 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
568 _("Unable to establish a secure connection to host."), 1);
569
570 return (-1);
571 }
572
573 _sspiSetAllowsAnyRoot(http->tls_credentials, TRUE);
574 _sspiSetAllowsExpiredCerts(http->tls_credentials, TRUE);
575
576 if (!_sspiConnect(http->tls_credentials, hostname))
577 {
578 _sspiFree(http->tls_credentials);
579 http->tls_credentials = NULL;
580
581 http->error = EIO;
582 http->status = HTTP_STATUS_ERROR;
583
584 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
585 _("Unable to establish a secure connection to host."), 1);
586
587 return (-1);
588 }
589# endif /* HAVE_CDSASSL */
590
591 return (0);
592}
593
594
595/*
596 * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
597 */
598
599static void
600http_shutdown_ssl(http_t *http) /* I - Connection to server */
601{
602# ifdef HAVE_LIBSSL
603 SSL_CTX *context; /* Context for encryption */
604
605 context = SSL_get_SSL_CTX(http->tls);
606
607 SSL_shutdown(http->tls);
608 SSL_CTX_free(context);
609 SSL_free(http->tls);
610
611# elif defined(HAVE_GNUTLS)
612 gnutls_certificate_client_credentials *credentials;
613 /* TLS credentials */
614
615 credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials);
616
617 gnutls_bye(http->tls, GNUTLS_SHUT_RDWR);
618 gnutls_deinit(http->tls);
619 gnutls_certificate_free_credentials(*credentials);
620 free(credentials);
621
622# elif defined(HAVE_CDSASSL)
623 while (SSLClose(http->tls) == errSSLWouldBlock)
624 usleep(1000);
625
626 CFRelease(http->tls);
627
628 if (http->tls_credentials)
629 CFRelease(http->tls_credentials);
630
631# elif defined(HAVE_SSPISSL)
632 _sspiFree(http->tls_credentials);
633# endif /* HAVE_LIBSSL */
634
635 http->tls = NULL;
636 http->tls_credentials = NULL;
637}
638#endif /* HAVE_SSL */
639
640
641#ifdef HAVE_SSL
642/*
643 * 'http_write_ssl()' - Write to a SSL/TLS connection.
644 */
645
646static int /* O - Bytes written */
647http_write_ssl(http_t *http, /* I - Connection to server */
648 const char *buf, /* I - Buffer holding data */
649 int len) /* I - Length of buffer */
650{
651 ssize_t result; /* Return value */
652
653
654 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
655
656# if defined(HAVE_LIBSSL)
657 result = SSL_write((SSL *)(http->tls), buf, len);
658
659# elif defined(HAVE_GNUTLS)
660 result = gnutls_record_send(http->tls, buf, len);
661
662 if (result < 0 && !errno)
663 {
664 /*
665 * Convert GNU TLS error to errno value...
666 */
667
668 switch (result)
669 {
670 case GNUTLS_E_INTERRUPTED :
671 errno = EINTR;
672 break;
673
674 case GNUTLS_E_AGAIN :
675 errno = EAGAIN;
676 break;
677
678 default :
679 errno = EPIPE;
680 break;
681 }
682
683 result = -1;
684 }
685
686# elif defined(HAVE_CDSASSL)
687 OSStatus error; /* Error info */
688 size_t processed; /* Number of bytes processed */
689
690
691 error = SSLWrite(http->tls, buf, len, &processed);
692
693 switch (error)
694 {
695 case 0 :
696 result = (int)processed;
697 break;
698
699 case errSSLWouldBlock :
700 if (processed)
701 result = (int)processed;
702 else
703 {
704 result = -1;
705 errno = EINTR;
706 }
707 break;
708
709 case errSSLClosedGraceful :
710 default :
711 if (processed)
712 result = (int)processed;
713 else
714 {
715 result = -1;
716 errno = EPIPE;
717 }
718 break;
719 }
720# elif defined(HAVE_SSPISSL)
721 return _sspiWrite((_sspi_struct_t *)http->tls, (void *)buf, len);
722# endif /* HAVE_LIBSSL */
723
724 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
725
726 return ((int)result);
727}
728#endif /* HAVE_SSL */
729
730
731/*
732 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
733 */
734
735static size_t
736http_tls_pending(http_t *http) /* I - HTTP connection */
737{
738 if (http->tls && usessl)
739 {
740# ifdef HAVE_LIBSSL
741 if (SSL_pending(http->tls))
742 {
743 DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
744 return (1);
745 }
746
747# elif defined(HAVE_GNUTLS)
748 if (gnutls_record_check_pending(http->tls))
749 {
750 DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
751 return (1);
752 }
753
754# elif defined(HAVE_CDSASSL)
755 size_t bytes; /* Bytes that are available */
756
757 if (!SSLGetBufferedReadSize(http->tls, &bytes) &&
758 bytes > 0)
759 {
760 DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
761 return (1);
762 }
763# endif /* HAVE_LIBSSL */
764}
765
766
767#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
768/*
769 * 'http_bio_ctrl()' - Control the HTTP connection.
770 */
771
772static long /* O - Result/data */
773http_bio_ctrl(BIO *h, /* I - BIO data */
774 int cmd, /* I - Control command */
775 long arg1, /* I - First argument */
776 void *arg2) /* I - Second argument */
777{
778 switch (cmd)
779 {
780 default :
781 return (0);
782
783 case BIO_CTRL_RESET :
784 h->ptr = NULL;
785 return (0);
786
787 case BIO_C_SET_FILE_PTR :
788 h->ptr = arg2;
789 h->init = 1;
790 return (1);
791
792 case BIO_C_GET_FILE_PTR :
793 if (arg2)
794 {
795 *((void **)arg2) = h->ptr;
796 return (1);
797 }
798 else
799 return (0);
800
801 case BIO_CTRL_DUP :
802 case BIO_CTRL_FLUSH :
803 return (1);
804 }
805}
806
807
808/*
809 * 'http_bio_free()' - Free OpenSSL data.
810 */
811
812static int /* O - 1 on success, 0 on failure */
813http_bio_free(BIO *h) /* I - BIO data */
814{
815 if (!h)
816 return (0);
817
818 if (h->shutdown)
819 {
820 h->init = 0;
821 h->flags = 0;
822 }
823
824 return (1);
825}
826
827
828/*
829 * 'http_bio_new()' - Initialize an OpenSSL BIO structure.
830 */
831
832static int /* O - 1 on success, 0 on failure */
833http_bio_new(BIO *h) /* I - BIO data */
834{
835 if (!h)
836 return (0);
837
838 h->init = 0;
839 h->num = 0;
840 h->ptr = NULL;
841 h->flags = 0;
842
843 return (1);
844}
845
846
847/*
848 * 'http_bio_puts()' - Send a string for OpenSSL.
849 */
850
851static int /* O - Bytes written */
852http_bio_puts(BIO *h, /* I - BIO data */
853 const char *str) /* I - String to write */
854{
855#ifdef WIN32
856 return (send(((http_t *)h->ptr)->fd, str, (int)strlen(str), 0));
857#else
858 return (send(((http_t *)h->ptr)->fd, str, strlen(str), 0));
859#endif /* WIN32 */
860}
861
862
863/*
864 * 'http_bio_read()' - Read data for OpenSSL.
865 */
866
867static int /* O - Bytes read */
868http_bio_read(BIO *h, /* I - BIO data */
869 char *buf, /* I - Buffer */
870 int size) /* I - Number of bytes to read */
871{
872 http_t *http; /* HTTP connection */
873
874
875 http = (http_t *)h->ptr;
876
877 if (!http->blocking)
878 {
879 /*
880 * Make sure we have data before we read...
881 */
882
883 while (!_httpWait(http, http->wait_value, 0))
884 {
885 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
886 continue;
887
888#ifdef WIN32
889 http->error = WSAETIMEDOUT;
890#else
891 http->error = ETIMEDOUT;
892#endif /* WIN32 */
893
894 return (-1);
895 }
896 }
897
898 return (recv(http->fd, buf, size, 0));
899}
900
901
902/*
903 * 'http_bio_write()' - Write data for OpenSSL.
904 */
905
906static int /* O - Bytes written */
907http_bio_write(BIO *h, /* I - BIO data */
908 const char *buf, /* I - Buffer to write */
909 int num) /* I - Number of bytes to write */
910{
911 return (send(((http_t *)h->ptr)->fd, buf, num, 0));
912}
913#endif /* HAVE_SSL && HAVE_LIBSSL */
914
915
916/*
917 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
918 */
919
920int /* O - 1 on success, 0 on error */
921cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */
922{
923 SSL_CTX *context; /* Context for encryption */
924 unsigned long error; /* Error code */
925 int status; /* Return status */
926
927
928 context = SSL_get_SSL_CTX(con->http.tls);
929
930 switch (SSL_shutdown(con->http.tls))
931 {
932 case 1 :
933 cupsdLogMessage(CUPSD_LOG_DEBUG,
934 "SSL shutdown successful!");
935 status = 1;
936 break;
937
938 case -1 :
939 cupsdLogMessage(CUPSD_LOG_ERROR,
940 "Fatal error during SSL shutdown!");
941
942 default :
943 while ((error = ERR_get_error()) != 0)
944 cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s",
945 ERR_error_string(error, NULL));
946 status = 0;
947 break;
948 }
949
950 SSL_CTX_free(context);
951 SSL_free(con->http.tls);
952 con->http.tls = NULL;
953
954 return (status);
955}
956
957
958/*
959 * 'cupsdStartTLS()' - Start a secure session with the client.
960 */
961
962int /* O - 1 on success, 0 on error */
963cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */
964{
965 SSL_CTX *context; /* Context for encryption */
966 BIO *bio; /* BIO data */
967 unsigned long error; /* Error code */
968
969
970 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
971 con->http.fd);
972
973 /*
974 * Verify that we have a certificate...
975 */
976
977 if (access(ServerKey, 0) || access(ServerCertificate, 0))
978 {
979 /*
980 * Nope, make a self-signed certificate...
981 */
982
983 if (!make_certificate(con))
984 return (0);
985 }
986
987 /*
988 * Create the SSL context and accept the connection...
989 */
990
991 context = SSL_CTX_new(SSLv23_server_method());
992
993 SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
994 if (SSLOptions & CUPSD_SSL_NOEMPTY)
995 SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
996 SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
997 SSL_CTX_use_certificate_chain_file(context, ServerCertificate);
998
999 bio = BIO_new(_httpBIOMethods());
1000 BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
1001
1002 con->http.tls = SSL_new(context);
1003 SSL_set_bio(con->http.tls, bio, bio);
1004
1005 if (SSL_accept(con->http.tls) != 1)
1006 {
1007 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s.",
1008 con->http.hostname);
1009
1010 while ((error = ERR_get_error()) != 0)
1011 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL));
1012
1013 SSL_CTX_free(context);
1014 SSL_free(con->http.tls);
1015 con->http.tls = NULL;
1016 return (0);
1017 }
1018
1019 cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
1020 con->http.hostname);
1021
1022 return (1);
1023}
1024
1025
1026/*
1027 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
1028 */
1029
1030static int /* O - 1 on success, 0 on failure */
1031make_certificate(cupsd_client_t *con) /* I - Client connection */
1032{
1033#ifdef HAVE_WAITPID
1034 int pid, /* Process ID of command */
1035 status; /* Status of command */
1036 char command[1024], /* Command */
1037 *argv[12], /* Command-line arguments */
1038 *envp[MAX_ENV + 1], /* Environment variables */
1039 infofile[1024], /* Type-in information for cert */
1040 seedfile[1024]; /* Random number seed file */
1041 int envc, /* Number of environment variables */
1042 bytes; /* Bytes written */
1043 cups_file_t *fp; /* Seed/info file */
1044 int infofd; /* Info file descriptor */
1045
1046
1047 /*
1048 * Run the "openssl" command to seed the random number generator and
1049 * generate a self-signed certificate that is good for 10 years:
1050 *
1051 * openssl rand -rand seedfile 1
1052 *
1053 * openssl req -new -x509 -keyout ServerKey \
1054 * -out ServerCertificate -days 3650 -nodes
1055 *
1056 * The seeding step is crucial in ensuring that the openssl command
1057 * does not block on systems without sufficient entropy...
1058 */
1059
1060 if (!cupsFileFind("openssl", getenv("PATH"), 1, command, sizeof(command)))
1061 {
1062 cupsdLogMessage(CUPSD_LOG_ERROR,
1063 "No SSL certificate and openssl command not found!");
1064 return (0);
1065 }
1066
1067 if (access("/dev/urandom", 0))
1068 {
1069 /*
1070 * If the system doesn't provide /dev/urandom, then any random source
1071 * will probably be blocking-style, so generate some random data to
1072 * use as a seed for the certificate. Note that we have already
1073 * seeded the random number generator in cupsdInitCerts()...
1074 */
1075
1076 cupsdLogMessage(CUPSD_LOG_INFO,
1077 "Seeding the random number generator...");
1078
1079 /*
1080 * Write the seed file...
1081 */
1082
1083 if ((fp = cupsTempFile2(seedfile, sizeof(seedfile))) == NULL)
1084 {
1085 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create seed file %s - %s",
1086 seedfile, strerror(errno));
1087 return (0);
1088 }
1089
1090 for (bytes = 0; bytes < 262144; bytes ++)
1091 cupsFilePutChar(fp, CUPS_RAND());
1092
1093 cupsFileClose(fp);
1094
1095 /*
1096 * Run the openssl command to seed its random number generator...
1097 */
1098
1099 argv[0] = "openssl";
1100 argv[1] = "rand";
1101 argv[2] = "-rand";
1102 argv[3] = seedfile;
1103 argv[4] = "1";
1104 argv[5] = NULL;
1105
1106 envc = cupsdLoadEnv(envp, MAX_ENV);
1107 envp[envc] = NULL;
1108
1109 if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
1110 NULL, &pid))
1111 {
1112 unlink(seedfile);
1113 return (0);
1114 }
1115
1116 while (waitpid(pid, &status, 0) < 0)
1117 if (errno != EINTR)
1118 {
1119 status = 1;
1120 break;
1121 }
1122
1123 cupsdFinishProcess(pid, command, sizeof(command), NULL);
1124
1125 /*
1126 * Remove the seed file, as it is no longer needed...
1127 */
1128
1129 unlink(seedfile);
1130
1131 if (status)
1132 {
1133 if (WIFEXITED(status))
1134 cupsdLogMessage(CUPSD_LOG_ERROR,
1135 "Unable to seed random number generator - "
1136 "the openssl command stopped with status %d!",
1137 WEXITSTATUS(status));
1138 else
1139 cupsdLogMessage(CUPSD_LOG_ERROR,
1140 "Unable to seed random number generator - "
1141 "the openssl command crashed on signal %d!",
1142 WTERMSIG(status));
1143
1144 return (0);
1145 }
1146 }
1147
1148 /*
1149 * Create a file with the certificate information fields...
1150 *
1151 * Note: This assumes that the default questions are asked by the openssl
1152 * command...
1153 */
1154
1155 if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
1156 {
1157 cupsdLogMessage(CUPSD_LOG_ERROR,
1158 "Unable to create certificate information file %s - %s",
1159 infofile, strerror(errno));
1160 return (0);
1161 }
1162
1163 cupsFilePrintf(fp, ".\n.\n.\n%s\n.\n%s\n%s\n",
1164 ServerName, ServerName, ServerAdmin);
1165 cupsFileClose(fp);
1166
1167 cupsdLogMessage(CUPSD_LOG_INFO,
1168 "Generating SSL server key and certificate...");
1169
1170 argv[0] = "openssl";
1171 argv[1] = "req";
1172 argv[2] = "-new";
1173 argv[3] = "-x509";
1174 argv[4] = "-keyout";
1175 argv[5] = ServerKey;
1176 argv[6] = "-out";
1177 argv[7] = ServerCertificate;
1178 argv[8] = "-days";
1179 argv[9] = "3650";
1180 argv[10] = "-nodes";
1181 argv[11] = NULL;
1182
1183 cupsdLoadEnv(envp, MAX_ENV);
1184
1185 infofd = open(infofile, O_RDONLY);
1186
1187 if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
1188 NULL, &pid))
1189 {
1190 close(infofd);
1191 unlink(infofile);
1192 return (0);
1193 }
1194
1195 close(infofd);
1196 unlink(infofile);
1197
1198 while (waitpid(pid, &status, 0) < 0)
1199 if (errno != EINTR)
1200 {
1201 status = 1;
1202 break;
1203 }
1204
1205 cupsdFinishProcess(pid, command, sizeof(command), NULL);
1206
1207 if (status)
1208 {
1209 if (WIFEXITED(status))
1210 cupsdLogMessage(CUPSD_LOG_ERROR,
1211 "Unable to create SSL server key and certificate - "
1212 "the openssl command stopped with status %d!",
1213 WEXITSTATUS(status));
1214 else
1215 cupsdLogMessage(CUPSD_LOG_ERROR,
1216 "Unable to create SSL server key and certificate - "
1217 "the openssl command crashed on signal %d!",
1218 WTERMSIG(status));
1219 }
1220 else
1221 {
1222 cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
1223 ServerKey);
1224 cupsdLogMessage(CUPSD_LOG_INFO,
1225 "Created SSL server certificate file \"%s\"...",
1226 ServerCertificate);
1227 }
1228
1229 return (!status);
1230
1231#else
1232 return (0);
1233#endif /* HAVE_WAITPID */
1234}
1235
1236
1237/*
1238 * End of "$Id$".
1239 */