]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/tls-gnutls.c
Drop old private APIs that are no longer used/supported.
[thirdparty/cups.git] / cups / tls-gnutls.c
1 /*
2 * "$Id$"
3 *
4 * TLS support code for CUPS using GNU TLS.
5 *
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18
19 /*
20 * Local functions...
21 */
22
23 static int make_certificate(cupsd_client_t *con);
24
25
26 /*
27 * 'http_tls_initialize()' - Initialize the TLS stack.
28 */
29
30 static void
31 http_tls_initialize(void)
32 {
33 #ifdef HAVE_GNUTLS
34 /*
35 * Initialize GNU TLS...
36 */
37
38 gnutls_global_init();
39
40 #elif defined(HAVE_LIBSSL)
41 /*
42 * Initialize OpenSSL...
43 */
44
45 SSL_load_error_strings();
46 SSL_library_init();
47
48 /*
49 * Using the current time is a dubious random seed, but on some systems
50 * it is the best we can do (on others, this seed isn't even used...)
51 */
52
53 CUPS_SRAND(time(NULL));
54
55 for (i = 0; i < sizeof(data); i ++)
56 data[i] = CUPS_RAND();
57
58 RAND_seed(data, sizeof(data));
59 #endif /* HAVE_GNUTLS */
60 }
61
62
63 #ifdef HAVE_SSL
64 /*
65 * 'http_tls_read()' - Read from a SSL/TLS connection.
66 */
67
68 static int /* O - Bytes read */
69 http_tls_read(http_t *http, /* I - Connection to server */
70 char *buf, /* I - Buffer to store data */
71 int len) /* I - Length of buffer */
72 {
73 # if defined(HAVE_LIBSSL)
74 return (SSL_read((SSL *)(http->tls), buf, len));
75
76 # elif defined(HAVE_GNUTLS)
77 ssize_t result; /* Return value */
78
79
80 result = gnutls_record_recv(http->tls, buf, len);
81
82 if (result < 0 && !errno)
83 {
84 /*
85 * Convert GNU TLS error to errno value...
86 */
87
88 switch (result)
89 {
90 case GNUTLS_E_INTERRUPTED :
91 errno = EINTR;
92 break;
93
94 case GNUTLS_E_AGAIN :
95 errno = EAGAIN;
96 break;
97
98 default :
99 errno = EPIPE;
100 break;
101 }
102
103 result = -1;
104 }
105
106 return ((int)result);
107
108 # elif defined(HAVE_CDSASSL)
109 int result; /* Return value */
110 OSStatus error; /* Error info */
111 size_t processed; /* Number of bytes processed */
112
113
114 error = SSLRead(http->tls, buf, len, &processed);
115 DEBUG_printf(("6http_tls_read: error=%d, processed=%d", (int)error,
116 (int)processed));
117 switch (error)
118 {
119 case 0 :
120 result = (int)processed;
121 break;
122
123 case errSSLWouldBlock :
124 if (processed)
125 result = (int)processed;
126 else
127 {
128 result = -1;
129 errno = EINTR;
130 }
131 break;
132
133 case errSSLClosedGraceful :
134 default :
135 if (processed)
136 result = (int)processed;
137 else
138 {
139 result = -1;
140 errno = EPIPE;
141 }
142 break;
143 }
144
145 return (result);
146
147 # elif defined(HAVE_SSPISSL)
148 return _sspiRead((_sspi_struct_t*) http->tls, buf, len);
149 # endif /* HAVE_LIBSSL */
150 }
151 #endif /* HAVE_SSL */
152
153
154 #ifdef HAVE_SSL
155 /*
156 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
157 */
158
159 static int /* O - 0 on success, -1 on failure */
160 http_setup_ssl(http_t *http) /* I - Connection to server */
161 {
162 char hostname[256], /* Hostname */
163 *hostptr; /* Pointer into hostname */
164
165 # ifdef HAVE_LIBSSL
166 SSL_CTX *context; /* Context for encryption */
167 BIO *bio; /* BIO data */
168 const char *message = NULL;/* Error message */
169 # elif defined(HAVE_GNUTLS)
170 int status; /* Status of handshake */
171 gnutls_certificate_client_credentials *credentials;
172 /* TLS credentials */
173 # elif defined(HAVE_CDSASSL)
174 _cups_globals_t *cg = _cupsGlobals();
175 /* Pointer to library globals */
176 OSStatus error; /* Error code */
177 const char *message = NULL;/* Error message */
178 cups_array_t *credentials; /* Credentials array */
179 cups_array_t *names; /* CUPS distinguished names */
180 CFArrayRef dn_array; /* CF distinguished names array */
181 CFIndex count; /* Number of credentials */
182 CFDataRef data; /* Certificate data */
183 int i; /* Looping var */
184 http_credential_t *credential; /* Credential data */
185 # elif defined(HAVE_SSPISSL)
186 TCHAR username[256]; /* Username returned from GetUserName() */
187 TCHAR commonName[256];/* Common name for certificate */
188 DWORD dwSize; /* 32 bit size */
189 # endif /* HAVE_LIBSSL */
190
191
192 DEBUG_printf(("7http_setup_ssl(http=%p)", http));
193
194 /*
195 * Get the hostname to use for SSL...
196 */
197
198 if (httpAddrLocalhost(http->hostaddr))
199 {
200 strlcpy(hostname, "localhost", sizeof(hostname));
201 }
202 else
203 {
204 /*
205 * Otherwise make sure the hostname we have does not end in a trailing dot.
206 */
207
208 strlcpy(hostname, http->hostname, sizeof(hostname));
209 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
210 *hostptr == '.')
211 *hostptr = '\0';
212 }
213
214 # ifdef HAVE_LIBSSL
215 context = SSL_CTX_new(SSLv23_client_method());
216
217 SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
218
219 bio = BIO_new(_httpBIOMethods());
220 BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http);
221
222 http->tls = SSL_new(context);
223 SSL_set_bio(http->tls, bio, bio);
224
225 # ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
226 SSL_set_tlsext_host_name(http->tls, hostname);
227 # endif /* HAVE_SSL_SET_TLSEXT_HOST_NAME */
228
229 if (SSL_connect(http->tls) != 1)
230 {
231 unsigned long error; /* Error code */
232
233 while ((error = ERR_get_error()) != 0)
234 {
235 message = ERR_error_string(error, NULL);
236 DEBUG_printf(("8http_setup_ssl: %s", message));
237 }
238
239 SSL_CTX_free(context);
240 SSL_free(http->tls);
241 http->tls = NULL;
242
243 # ifdef WIN32
244 http->error = WSAGetLastError();
245 # else
246 http->error = errno;
247 # endif /* WIN32 */
248 http->status = HTTP_STATUS_ERROR;
249
250 if (!message)
251 message = _("Unable to establish a secure connection to host.");
252
253 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
254
255 return (-1);
256 }
257
258 # elif defined(HAVE_GNUTLS)
259 credentials = (gnutls_certificate_client_credentials *)
260 malloc(sizeof(gnutls_certificate_client_credentials));
261 if (credentials == NULL)
262 {
263 DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s",
264 strerror(errno)));
265 http->error = errno;
266 http->status = HTTP_STATUS_ERROR;
267 _cupsSetHTTPError(HTTP_STATUS_ERROR);
268
269 return (-1);
270 }
271
272 gnutls_certificate_allocate_credentials(credentials);
273
274 gnutls_init(&http->tls, GNUTLS_CLIENT);
275 gnutls_set_default_priority(http->tls);
276 gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname,
277 strlen(hostname));
278 gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
279 gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr)http);
280 gnutls_transport_set_pull_function(http->tls, _httpReadGNUTLS);
281 gnutls_transport_set_push_function(http->tls, _httpWriteGNUTLS);
282
283 while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
284 {
285 DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)",
286 status, gnutls_strerror(status)));
287
288 if (gnutls_error_is_fatal(status))
289 {
290 http->error = EIO;
291 http->status = HTTP_STATUS_ERROR;
292
293 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
294
295 gnutls_deinit(http->tls);
296 gnutls_certificate_free_credentials(*credentials);
297 free(credentials);
298 http->tls = NULL;
299
300 return (-1);
301 }
302 }
303
304 http->tls_credentials = credentials;
305
306 # elif defined(HAVE_CDSASSL)
307 if ((http->tls = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide,
308 kSSLStreamType)) == NULL)
309 {
310 DEBUG_puts("4http_setup_ssl: SSLCreateContext failed.");
311 http->error = errno = ENOMEM;
312 http->status = HTTP_STATUS_ERROR;
313 _cupsSetHTTPError(HTTP_STATUS_ERROR);
314
315 return (-1);
316 }
317
318 error = SSLSetConnection(http->tls, http);
319 DEBUG_printf(("4http_setup_ssl: SSLSetConnection, error=%d", (int)error));
320
321 if (!error)
322 {
323 error = SSLSetIOFuncs(http->tls, _httpReadCDSA, _httpWriteCDSA);
324 DEBUG_printf(("4http_setup_ssl: SSLSetIOFuncs, error=%d", (int)error));
325 }
326
327 if (!error)
328 {
329 error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth,
330 true);
331 DEBUG_printf(("4http_setup_ssl: SSLSetSessionOption, error=%d",
332 (int)error));
333 }
334
335 if (!error)
336 {
337 if (cg->client_cert_cb)
338 {
339 error = SSLSetSessionOption(http->tls,
340 kSSLSessionOptionBreakOnCertRequested, true);
341 DEBUG_printf(("4http_setup_ssl: kSSLSessionOptionBreakOnCertRequested, "
342 "error=%d", (int)error));
343 }
344 else
345 {
346 error = http_set_credentials(http);
347 DEBUG_printf(("4http_setup_ssl: http_set_credentials, error=%d",
348 (int)error));
349 }
350 }
351
352 /*
353 * Let the server know which hostname/domain we are trying to connect to
354 * in case it wants to serve up a certificate with a matching common name.
355 */
356
357 if (!error)
358 {
359 error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
360
361 DEBUG_printf(("4http_setup_ssl: SSLSetPeerDomainName, error=%d",
362 (int)error));
363 }
364
365 if (!error)
366 {
367 int done = 0; /* Are we done yet? */
368
369 while (!error && !done)
370 {
371 error = SSLHandshake(http->tls);
372
373 DEBUG_printf(("4http_setup_ssl: SSLHandshake returned %d.", (int)error));
374
375 switch (error)
376 {
377 case noErr :
378 done = 1;
379 break;
380
381 case errSSLWouldBlock :
382 error = noErr; /* Force a retry */
383 usleep(1000); /* in 1 millisecond */
384 break;
385
386 case errSSLServerAuthCompleted :
387 error = 0;
388 if (cg->server_cert_cb)
389 {
390 error = httpCopyCredentials(http, &credentials);
391 if (!error)
392 {
393 error = (cg->server_cert_cb)(http, http->tls, credentials,
394 cg->server_cert_data);
395 httpFreeCredentials(credentials);
396 }
397
398 DEBUG_printf(("4http_setup_ssl: Server certificate callback "
399 "returned %d.", (int)error));
400 }
401 break;
402
403 case errSSLClientCertRequested :
404 error = 0;
405
406 if (cg->client_cert_cb)
407 {
408 names = NULL;
409 if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) &&
410 dn_array)
411 {
412 if ((names = cupsArrayNew(NULL, NULL)) != NULL)
413 {
414 for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++)
415 {
416 data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i);
417
418 if ((credential = malloc(sizeof(*credential))) != NULL)
419 {
420 credential->datalen = CFDataGetLength(data);
421 if ((credential->data = malloc(credential->datalen)))
422 {
423 memcpy((void *)credential->data, CFDataGetBytePtr(data),
424 credential->datalen);
425 cupsArrayAdd(names, credential);
426 }
427 else
428 free(credential);
429 }
430 }
431 }
432
433 CFRelease(dn_array);
434 }
435
436 if (!error)
437 {
438 error = (cg->client_cert_cb)(http, http->tls, names,
439 cg->client_cert_data);
440
441 DEBUG_printf(("4http_setup_ssl: Client certificate callback "
442 "returned %d.", (int)error));
443 }
444
445 httpFreeCredentials(names);
446 }
447 break;
448
449 case errSSLUnknownRootCert :
450 message = _("Unable to establish a secure connection to host "
451 "(untrusted certificate).");
452 break;
453
454 case errSSLNoRootCert :
455 message = _("Unable to establish a secure connection to host "
456 "(self-signed certificate).");
457 break;
458
459 case errSSLCertExpired :
460 message = _("Unable to establish a secure connection to host "
461 "(expired certificate).");
462 break;
463
464 case errSSLCertNotYetValid :
465 message = _("Unable to establish a secure connection to host "
466 "(certificate not yet valid).");
467 break;
468
469 case errSSLHostNameMismatch :
470 message = _("Unable to establish a secure connection to host "
471 "(host name mismatch).");
472 break;
473
474 case errSSLXCertChainInvalid :
475 message = _("Unable to establish a secure connection to host "
476 "(certificate chain invalid).");
477 break;
478
479 case errSSLConnectionRefused :
480 message = _("Unable to establish a secure connection to host "
481 "(peer dropped connection before responding).");
482 break;
483
484 default :
485 break;
486 }
487 }
488 }
489
490 if (error)
491 {
492 http->error = error;
493 http->status = HTTP_STATUS_ERROR;
494 errno = ECONNREFUSED;
495
496 CFRelease(http->tls);
497 http->tls = NULL;
498
499 /*
500 * If an error string wasn't set by the callbacks use a generic one...
501 */
502
503 if (!message)
504 #ifdef HAVE_CSSMERRORSTRING
505 message = cssmErrorString(error);
506 #else
507 message = _("Unable to establish a secure connection to host.");
508 #endif /* HAVE_CSSMERRORSTRING */
509
510 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
511
512 return (-1);
513 }
514
515 # elif defined(HAVE_SSPISSL)
516 http->tls = _sspiAlloc();
517
518 if (!http->tls)
519 {
520 _cupsSetHTTPError(HTTP_STATUS_ERROR);
521 return (-1);
522 }
523
524 http->tls->sock = http->fd;
525 dwSize = sizeof(username) / sizeof(TCHAR);
526 GetUserName(username, &dwSize);
527 _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
528 sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
529
530 if (!_sspiGetCredentials(http->tls_credentials, L"ClientContainer",
531 commonName, FALSE))
532 {
533 _sspiFree(http->tls_credentials);
534 http->tls_credentials = NULL;
535
536 http->error = EIO;
537 http->status = HTTP_STATUS_ERROR;
538
539 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
540 _("Unable to establish a secure connection to host."), 1);
541
542 return (-1);
543 }
544
545 _sspiSetAllowsAnyRoot(http->tls_credentials, TRUE);
546 _sspiSetAllowsExpiredCerts(http->tls_credentials, TRUE);
547
548 if (!_sspiConnect(http->tls_credentials, hostname))
549 {
550 _sspiFree(http->tls_credentials);
551 http->tls_credentials = NULL;
552
553 http->error = EIO;
554 http->status = HTTP_STATUS_ERROR;
555
556 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI,
557 _("Unable to establish a secure connection to host."), 1);
558
559 return (-1);
560 }
561 # endif /* HAVE_CDSASSL */
562
563 return (0);
564 }
565
566
567 /*
568 * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
569 */
570
571 static void
572 http_shutdown_ssl(http_t *http) /* I - Connection to server */
573 {
574 # ifdef HAVE_LIBSSL
575 SSL_CTX *context; /* Context for encryption */
576
577 context = SSL_get_SSL_CTX(http->tls);
578
579 SSL_shutdown(http->tls);
580 SSL_CTX_free(context);
581 SSL_free(http->tls);
582
583 # elif defined(HAVE_GNUTLS)
584 gnutls_certificate_client_credentials *credentials;
585 /* TLS credentials */
586
587 credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials);
588
589 gnutls_bye(http->tls, GNUTLS_SHUT_RDWR);
590 gnutls_deinit(http->tls);
591 gnutls_certificate_free_credentials(*credentials);
592 free(credentials);
593
594 # elif defined(HAVE_CDSASSL)
595 while (SSLClose(http->tls) == errSSLWouldBlock)
596 usleep(1000);
597
598 CFRelease(http->tls);
599
600 if (http->tls_credentials)
601 CFRelease(http->tls_credentials);
602
603 # elif defined(HAVE_SSPISSL)
604 _sspiFree(http->tls_credentials);
605 # endif /* HAVE_LIBSSL */
606
607 http->tls = NULL;
608 http->tls_credentials = NULL;
609 }
610 #endif /* HAVE_SSL */
611
612
613 #ifdef HAVE_SSL
614 /*
615 * 'http_write_ssl()' - Write to a SSL/TLS connection.
616 */
617
618 static int /* O - Bytes written */
619 http_write_ssl(http_t *http, /* I - Connection to server */
620 const char *buf, /* I - Buffer holding data */
621 int len) /* I - Length of buffer */
622 {
623 ssize_t result; /* Return value */
624
625
626 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
627
628 # if defined(HAVE_LIBSSL)
629 result = SSL_write((SSL *)(http->tls), buf, len);
630
631 # elif defined(HAVE_GNUTLS)
632 result = gnutls_record_send(http->tls, buf, len);
633
634 if (result < 0 && !errno)
635 {
636 /*
637 * Convert GNU TLS error to errno value...
638 */
639
640 switch (result)
641 {
642 case GNUTLS_E_INTERRUPTED :
643 errno = EINTR;
644 break;
645
646 case GNUTLS_E_AGAIN :
647 errno = EAGAIN;
648 break;
649
650 default :
651 errno = EPIPE;
652 break;
653 }
654
655 result = -1;
656 }
657
658 # elif defined(HAVE_CDSASSL)
659 OSStatus error; /* Error info */
660 size_t processed; /* Number of bytes processed */
661
662
663 error = SSLWrite(http->tls, buf, len, &processed);
664
665 switch (error)
666 {
667 case 0 :
668 result = (int)processed;
669 break;
670
671 case errSSLWouldBlock :
672 if (processed)
673 result = (int)processed;
674 else
675 {
676 result = -1;
677 errno = EINTR;
678 }
679 break;
680
681 case errSSLClosedGraceful :
682 default :
683 if (processed)
684 result = (int)processed;
685 else
686 {
687 result = -1;
688 errno = EPIPE;
689 }
690 break;
691 }
692 # elif defined(HAVE_SSPISSL)
693 return _sspiWrite((_sspi_struct_t *)http->tls, (void *)buf, len);
694 # endif /* HAVE_LIBSSL */
695
696 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
697
698 return ((int)result);
699 }
700 #endif /* HAVE_SSL */
701
702
703 /*
704 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
705 */
706
707 static size_t
708 http_tls_pending(http_t *http) /* I - HTTP connection */
709 {
710 if (http->tls && usessl)
711 {
712 # ifdef HAVE_LIBSSL
713 if (SSL_pending(http->tls))
714 {
715 DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
716 return (1);
717 }
718
719 # elif defined(HAVE_GNUTLS)
720 if (gnutls_record_check_pending(http->tls))
721 {
722 DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
723 return (1);
724 }
725
726 # elif defined(HAVE_CDSASSL)
727 size_t bytes; /* Bytes that are available */
728
729 if (!SSLGetBufferedReadSize(http->tls, &bytes) &&
730 bytes > 0)
731 {
732 DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
733 return (1);
734 }
735 # endif /* HAVE_LIBSSL */
736 }
737
738
739 #if defined(HAVE_SSL) && defined(HAVE_GNUTLS)
740 /*
741 * '_httpReadGNUTLS()' - Read function for the GNU TLS library.
742 */
743
744 ssize_t /* O - Number of bytes read or -1 on error */
745 _httpReadGNUTLS(
746 gnutls_transport_ptr ptr, /* I - Connection to server */
747 void *data, /* I - Buffer */
748 size_t length) /* I - Number of bytes to read */
749 {
750 http_t *http; /* HTTP connection */
751 ssize_t bytes; /* Bytes read */
752
753
754 DEBUG_printf(("6_httpReadGNUTLS(ptr=%p, data=%p, length=%d)", ptr, data, (int)length));
755
756 http = (http_t *)ptr;
757
758 if (!http->blocking)
759 {
760 /*
761 * Make sure we have data before we read...
762 */
763
764 while (!_httpWait(http, http->wait_value, 0))
765 {
766 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
767 continue;
768
769 http->error = ETIMEDOUT;
770 return (-1);
771 }
772 }
773
774 bytes = recv(http->fd, data, length, 0);
775 DEBUG_printf(("6_httpReadGNUTLS: bytes=%d", (int)bytes));
776 return (bytes);
777 }
778 #endif /* HAVE_SSL && HAVE_GNUTLS */
779
780
781 #if defined(HAVE_SSL) && defined(HAVE_GNUTLS)
782 /*
783 * '_httpWriteGNUTLS()' - Write function for the GNU TLS library.
784 */
785
786 ssize_t /* O - Number of bytes written or -1 on error */
787 _httpWriteGNUTLS(
788 gnutls_transport_ptr ptr, /* I - Connection to server */
789 const void *data, /* I - Data buffer */
790 size_t length) /* I - Number of bytes to write */
791 {
792 ssize_t bytes; /* Bytes written */
793
794
795 DEBUG_printf(("6_httpWriteGNUTLS(ptr=%p, data=%p, length=%d)", ptr, data,
796 (int)length));
797 #ifdef DEBUG
798 http_debug_hex("_httpWriteGNUTLS", data, (int)length);
799 #endif /* DEBUG */
800
801 bytes = send(((http_t *)ptr)->fd, data, length, 0);
802 DEBUG_printf(("_httpWriteGNUTLS: bytes=%d", (int)bytes));
803
804 return (bytes);
805 }
806 #endif /* HAVE_SSL && HAVE_GNUTLS */
807
808
809 /*
810 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
811 */
812
813 int /* O - 1 on success, 0 on error */
814 cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */
815 {
816 int error; /* Error code */
817 gnutls_certificate_server_credentials *credentials;
818 /* TLS credentials */
819
820
821 credentials = (gnutls_certificate_server_credentials *)
822 (con->http.tls_credentials);
823
824 error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR);
825 switch (error)
826 {
827 case GNUTLS_E_SUCCESS:
828 cupsdLogMessage(CUPSD_LOG_DEBUG,
829 "SSL shutdown successful!");
830 break;
831 default:
832 cupsdLogMessage(CUPSD_LOG_ERROR,
833 "SSL shutdown failed: %s", gnutls_strerror(error));
834 break;
835 }
836
837 gnutls_deinit(con->http.tls);
838 con->http.tls = NULL;
839
840 gnutls_certificate_free_credentials(*credentials);
841 free(credentials);
842
843 return (1);
844 }
845
846
847 /*
848 * 'cupsdStartTLS()' - Start a secure session with the client.
849 */
850
851 int /* O - 1 on success, 0 on error */
852 cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */
853 {
854 int status; /* Error code */
855 gnutls_certificate_server_credentials *credentials;
856 /* TLS credentials */
857
858
859 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
860 con->http.fd);
861
862 /*
863 * Verify that we have a certificate...
864 */
865
866 if (access(ServerKey, 0) || access(ServerCertificate, 0))
867 {
868 /*
869 * Nope, make a self-signed certificate...
870 */
871
872 if (!make_certificate(con))
873 return (0);
874 }
875
876 /*
877 * Create the SSL object and perform the SSL handshake...
878 */
879
880 credentials = (gnutls_certificate_server_credentials *)
881 malloc(sizeof(gnutls_certificate_server_credentials));
882 if (credentials == NULL)
883 {
884 cupsdLogMessage(CUPSD_LOG_ERROR,
885 "Unable to encrypt connection from %s - %s",
886 con->http.hostname, strerror(errno));
887
888 return (0);
889 }
890
891 gnutls_certificate_allocate_credentials(credentials);
892 gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
893 ServerKey, GNUTLS_X509_FMT_PEM);
894
895 gnutls_init(&con->http.tls, GNUTLS_SERVER);
896 gnutls_set_default_priority(con->http.tls);
897
898 gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials);
899 gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con));
900 gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS);
901 gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS);
902
903 while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS)
904 {
905 if (gnutls_error_is_fatal(status))
906 {
907 cupsdLogMessage(CUPSD_LOG_ERROR,
908 "Unable to encrypt connection from %s - %s",
909 con->http.hostname, gnutls_strerror(status));
910
911 gnutls_deinit(con->http.tls);
912 gnutls_certificate_free_credentials(*credentials);
913 con->http.tls = NULL;
914 free(credentials);
915 return (0);
916 }
917 }
918
919 cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
920 con->http.hostname);
921
922 con->http.tls_credentials = credentials;
923 return (1);
924 }
925
926
927 /*
928 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
929 */
930
931 static int /* O - 1 on success, 0 on failure */
932 make_certificate(cupsd_client_t *con) /* I - Client connection */
933 {
934 gnutls_x509_crt crt; /* Self-signed certificate */
935 gnutls_x509_privkey key; /* Encryption key */
936 cups_lang_t *language; /* Default language info */
937 cups_file_t *fp; /* Key/cert file */
938 unsigned char buffer[8192]; /* Buffer for x509 data */
939 size_t bytes; /* Number of bytes of data */
940 unsigned char serial[4]; /* Serial number buffer */
941 time_t curtime; /* Current time */
942 int result; /* Result of GNU TLS calls */
943
944
945 /*
946 * Create the encryption key...
947 */
948
949 cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key...");
950
951 gnutls_x509_privkey_init(&key);
952 gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
953
954 /*
955 * Save it...
956 */
957
958 bytes = sizeof(buffer);
959
960 if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
961 buffer, &bytes)) < 0)
962 {
963 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s",
964 gnutls_strerror(result));
965 gnutls_x509_privkey_deinit(key);
966 return (0);
967 }
968 else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL)
969 {
970 cupsFileWrite(fp, (char *)buffer, bytes);
971 cupsFileClose(fp);
972
973 cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
974 ServerKey);
975 }
976 else
977 {
978 cupsdLogMessage(CUPSD_LOG_ERROR,
979 "Unable to create SSL server key file \"%s\" - %s",
980 ServerKey, strerror(errno));
981 gnutls_x509_privkey_deinit(key);
982 return (0);
983 }
984
985 /*
986 * Create the self-signed certificate...
987 */
988
989 cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate...");
990
991 language = cupsLangDefault();
992 curtime = time(NULL);
993 serial[0] = curtime >> 24;
994 serial[1] = curtime >> 16;
995 serial[2] = curtime >> 8;
996 serial[3] = curtime;
997
998 gnutls_x509_crt_init(&crt);
999 if (strlen(language->language) == 5)
1000 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
1001 language->language + 3, 2);
1002 else
1003 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
1004 "US", 2);
1005 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
1006 ServerName, strlen(ServerName));
1007 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
1008 ServerName, strlen(ServerName));
1009 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
1010 0, "Unknown", 7);
1011 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
1012 "Unknown", 7);
1013 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
1014 "Unknown", 7);
1015 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
1016 ServerAdmin, strlen(ServerAdmin));
1017 gnutls_x509_crt_set_key(crt, key);
1018 gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
1019 gnutls_x509_crt_set_activation_time(crt, curtime);
1020 gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
1021 gnutls_x509_crt_set_ca_status(crt, 0);
1022 gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME,
1023 ServerName);
1024 gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
1025 gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
1026 gnutls_x509_crt_set_version(crt, 3);
1027
1028 bytes = sizeof(buffer);
1029 if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
1030 gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
1031
1032 gnutls_x509_crt_sign(crt, crt, key);
1033
1034 /*
1035 * Save it...
1036 */
1037
1038 bytes = sizeof(buffer);
1039 if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM,
1040 buffer, &bytes)) < 0)
1041 cupsdLogMessage(CUPSD_LOG_ERROR,
1042 "Unable to export SSL server certificate - %s",
1043 gnutls_strerror(result));
1044 else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL)
1045 {
1046 cupsFileWrite(fp, (char *)buffer, bytes);
1047 cupsFileClose(fp);
1048
1049 cupsdLogMessage(CUPSD_LOG_INFO,
1050 "Created SSL server certificate file \"%s\"...",
1051 ServerCertificate);
1052 }
1053 else
1054 cupsdLogMessage(CUPSD_LOG_ERROR,
1055 "Unable to create SSL server certificate file \"%s\" - %s",
1056 ServerCertificate, strerror(errno));
1057
1058 /*
1059 * Cleanup...
1060 */
1061
1062 gnutls_x509_crt_deinit(crt);
1063 gnutls_x509_privkey_deinit(key);
1064
1065 return (1);
1066 }
1067
1068
1069 /*
1070 * End of "$Id$".
1071 */