]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/tls-gnutls.c
0c57fd33d8018a836c8cc625284978489f6ddc01
[thirdparty/cups.git] / cups / tls-gnutls.c
1 /*
2 * "$Id$"
3 *
4 * TLS support code for CUPS using GNU TLS.
5 *
6 * Copyright 2007-2014 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 globals...
21 */
22
23 static int tls_auto_create = 0;
24 /* Auto-create self-signed certs? */
25 static char *tls_common_name = NULL;
26 /* Default common name */
27 static char *tls_keypath = NULL;
28 /* Server cert keychain path */
29 static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
30 /* Mutex for keychain/certs */
31
32
33 /*
34 * Local functions...
35 */
36
37 //static int make_certificate(cupsd_client_t *con);
38 static ssize_t http_gnutls_read(gnutls_transport_ptr_t ptr, void *data, size_t length);
39 static ssize_t http_gnutls_write(gnutls_transport_ptr_t ptr, const void *data, size_t length);
40
41
42 /*
43 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
44 *
45 * @since CUPS 2.0@
46 */
47
48 int /* O - 1 on success, 0 on failure */
49 cupsMakeServerCredentials(
50 const char *path, /* I - Path to keychain/directory */
51 const char *common_name, /* I - Common name */
52 int num_alt_names, /* I - Number of subject alternate names */
53 const char **alt_names, /* I - Subject Alternate Names */
54 time_t expiration_date) /* I - Expiration date */
55 {
56 gnutls_x509_crt_t crt; /* Self-signed certificate */
57 gnutls_x509_privkey_t key; /* Encryption private key */
58 char temp[1024], /* Temporary directory name */
59 crtfile[1024], /* Certificate filename */
60 keyfile[1024]; /* Private key filename */
61 cups_lang_t *language; /* Default language info */
62 cups_file_t *fp; /* Key/cert file */
63 unsigned char buffer[8192]; /* Buffer for x509 data */
64 size_t bytes; /* Number of bytes of data */
65 unsigned char serial[4]; /* Serial number buffer */
66 time_t curtime; /* Current time */
67 int result; /* Result of GNU TLS calls */
68
69
70 DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date));
71
72 /*
73 * Filenames...
74 */
75
76 if (!path)
77 {
78 const char *home = getenv("HOME"); /* HOME environment variable */
79
80 if (getuid() && home)
81 snprintf(temp, sizeof(temp), "%s/.cups/ssl", home);
82 else
83 snprintf(temp, sizeof(temp), "%s/ssl", CUPS_SERVERROOT);
84
85 path = temp;
86
87 DEBUG_printf(("1cupsMakeServerCredentials: Using default path \"%s\".", path));
88 }
89
90 snprintf(crtfile, sizeof(crtfile), "%s/%s.crt", path, common_name);
91 snprintf(keyfile, sizeof(keyfile), "%s/%s.key", path, common_name);
92
93 /*
94 * Create the encryption key...
95 */
96
97 gnutls_x509_privkey_init(&key);
98 gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
99
100 /*
101 * Save it...
102 */
103
104 bytes = sizeof(buffer);
105
106 if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
107 buffer, &bytes)) < 0)
108 {
109 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0);
110 gnutls_x509_privkey_deinit(key);
111 return (0);
112 }
113 else if ((fp = cupsFileOpen(keyfile, "w")) != NULL)
114 {
115 cupsFileWrite(fp, (char *)buffer, bytes);
116 cupsFileClose(fp);
117 }
118 else
119 {
120 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
121 gnutls_x509_privkey_deinit(key);
122 return (0);
123 }
124
125 /*
126 * Create the self-signed certificate...
127 */
128
129 DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed SSL certificate.");
130
131 language = cupsLangDefault();
132 curtime = time(NULL);
133 serial[0] = curtime >> 24;
134 serial[1] = curtime >> 16;
135 serial[2] = curtime >> 8;
136 serial[3] = curtime;
137
138 gnutls_x509_crt_init(&crt);
139 if (strlen(language->language) == 5)
140 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
141 language->language + 3, 2);
142 else
143 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
144 "US", 2);
145 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
146 common_name, strlen(common_name));
147 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
148 common_name, strlen(common_name));
149 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
150 0, "Unknown", 7);
151 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
152 "Unknown", 7);
153 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
154 "Unknown", 7);
155 /* gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
156 ServerAdmin, strlen(ServerAdmin));*/
157 gnutls_x509_crt_set_key(crt, key);
158 gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
159 gnutls_x509_crt_set_activation_time(crt, curtime);
160 gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
161 gnutls_x509_crt_set_ca_status(crt, 0);
162 if (num_alt_names > 0)
163 gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, alt_names[0]);
164 gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
165 gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
166 gnutls_x509_crt_set_version(crt, 3);
167
168 bytes = sizeof(buffer);
169 if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
170 gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
171
172 gnutls_x509_crt_sign(crt, crt, key);
173
174 /*
175 * Save it...
176 */
177
178 bytes = sizeof(buffer);
179 if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
180 {
181 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0);
182 gnutls_x509_crt_deinit(crt);
183 gnutls_x509_privkey_deinit(key);
184 return (0);
185 }
186 else if ((fp = cupsFileOpen(crtfile, "w")) != NULL)
187 {
188 cupsFileWrite(fp, (char *)buffer, bytes);
189 cupsFileClose(fp);
190 }
191 else
192 {
193 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
194 gnutls_x509_crt_deinit(crt);
195 gnutls_x509_privkey_deinit(key);
196 return (0);
197 }
198
199 /*
200 * Cleanup...
201 */
202
203 gnutls_x509_crt_deinit(crt);
204 gnutls_x509_privkey_deinit(key);
205
206 return (1);
207 }
208
209
210 /*
211 * 'cupsSetServerCredentials()' - Set the default server credentials.
212 *
213 * Note: The server credentials are used by all threads in the running process.
214 * This function is threadsafe.
215 *
216 * @since CUPS 2.0@
217 */
218
219 int /* O - 1 on success, 0 on failure */
220 cupsSetServerCredentials(
221 const char *path, /* I - Path to keychain/directory */
222 const char *common_name, /* I - Default common name for server */
223 int auto_create) /* I - 1 = automatically create self-signed certificates */
224 {
225 char temp[1024]; /* Default path buffer */
226
227
228 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create));
229
230 _cupsMutexLock(&tls_mutex);
231
232 /*
233 * Free old values...
234 */
235
236 if (tls_keypath)
237 _cupsStrFree(tls_keypath);
238
239 if (tls_common_name)
240 _cupsStrFree(tls_common_name);
241
242 /*
243 * Use defaults as needed...
244 */
245
246 if (!path)
247 {
248 const char *home = getenv("HOME"); /* HOME environment variable */
249
250 if (getuid() && home)
251 snprintf(temp, sizeof(temp), "%s/.cups/ssl", home);
252 else
253 snprintf(temp, sizeof(temp), "%s/ssl", CUPS_SERVERROOT);
254
255 path = temp;
256
257 DEBUG_printf(("1cupsSetServerCredentials: Using default path \"%s\".", path));
258 }
259
260 /*
261 * Save the new values...
262 */
263
264 tls_keypath = _cupsStrAlloc(path);
265 tls_auto_create = auto_create;
266 tls_common_name = _cupsStrAlloc(common_name);
267
268 _cupsMutexUnlock(&tls_mutex);
269
270 return (1);
271 }
272
273
274 /*
275 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
276 * an encrypted connection.
277 *
278 * @since CUPS 1.5/OS X 10.7@
279 */
280
281 int /* O - Status of call (0 = success) */
282 httpCopyCredentials(
283 http_t *http, /* I - Connection to server */
284 cups_array_t **credentials) /* O - Array of credentials */
285 {
286 if (credentials)
287 *credentials = NULL;
288
289 if (!http || !http->tls || !credentials)
290 return (-1);
291
292 return (0);
293 }
294
295
296 /*
297 * '_httpCreateCredentials()' - Create credentials in the internal format.
298 */
299
300 http_tls_credentials_t /* O - Internal credentials */
301 _httpCreateCredentials(
302 cups_array_t *credentials) /* I - Array of credentials */
303 {
304 (void)credentials;
305
306 return (NULL);
307 }
308
309
310 /*
311 * '_httpFreeCredentials()' - Free internal credentials.
312 */
313
314 void
315 _httpFreeCredentials(
316 http_tls_credentials_t credentials) /* I - Internal credentials */
317 {
318 (void)credentials;
319 }
320
321
322 /*
323 * 'http_gnutls_read()' - Read function for the GNU TLS library.
324 */
325
326 static ssize_t /* O - Number of bytes read or -1 on error */
327 http_gnutls_read(
328 gnutls_transport_ptr_t ptr, /* I - Connection to server */
329 void *data, /* I - Buffer */
330 size_t length) /* I - Number of bytes to read */
331 {
332 http_t *http; /* HTTP connection */
333 ssize_t bytes; /* Bytes read */
334
335
336 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr, data, (int)length));
337
338 http = (http_t *)ptr;
339
340 if (!http->blocking)
341 {
342 /*
343 * Make sure we have data before we read...
344 */
345
346 while (!_httpWait(http, http->wait_value, 0))
347 {
348 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
349 continue;
350
351 http->error = ETIMEDOUT;
352 return (-1);
353 }
354 }
355
356 bytes = recv(http->fd, data, length, 0);
357 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes));
358 return (bytes);
359 }
360
361
362 /*
363 * 'http_gnutls_write()' - Write function for the GNU TLS library.
364 */
365
366 static ssize_t /* O - Number of bytes written or -1 on error */
367 http_gnutls_write(
368 gnutls_transport_ptr_t ptr, /* I - Connection to server */
369 const void *data, /* I - Data buffer */
370 size_t length) /* I - Number of bytes to write */
371 {
372 ssize_t bytes; /* Bytes written */
373
374
375 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr, data,
376 (int)length));
377 bytes = send(((http_t *)ptr)->fd, data, length, 0);
378 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes));
379
380 return (bytes);
381 }
382
383
384 /*
385 * '_httpTLSInitialize()' - Initialize the TLS stack.
386 */
387
388 void
389 _httpTLSInitialize(void)
390 {
391 /*
392 * Initialize GNU TLS...
393 */
394
395 gnutls_global_init();
396 }
397
398
399 /*
400 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
401 */
402
403 size_t /* O - Bytes available */
404 _httpTLSPending(http_t *http) /* I - HTTP connection */
405 {
406 return (gnutls_record_check_pending(http->tls));
407 }
408
409
410 /*
411 * '_httpTLSRead()' - Read from a SSL/TLS connection.
412 */
413
414 int /* O - Bytes read */
415 _httpTLSRead(http_t *http, /* I - Connection to server */
416 char *buf, /* I - Buffer to store data */
417 int len) /* I - Length of buffer */
418 {
419 ssize_t result; /* Return value */
420
421
422 result = gnutls_record_recv(http->tls, buf, (size_t)len);
423
424 if (result < 0 && !errno)
425 {
426 /*
427 * Convert GNU TLS error to errno value...
428 */
429
430 switch (result)
431 {
432 case GNUTLS_E_INTERRUPTED :
433 errno = EINTR;
434 break;
435
436 case GNUTLS_E_AGAIN :
437 errno = EAGAIN;
438 break;
439
440 default :
441 errno = EPIPE;
442 break;
443 }
444
445 result = -1;
446 }
447
448 return ((int)result);
449 }
450
451
452 /*
453 * '_httpTLSSetCredentials()' - Set the TLS credentials.
454 */
455
456 int /* O - Status of connection */
457 _httpTLSSetCredentials(http_t *http) /* I - Connection to server */
458 {
459 (void)http;
460
461 return (0);
462 }
463
464
465 /*
466 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
467 */
468
469 int /* O - 0 on success, -1 on failure */
470 _httpTLSStart(http_t *http) /* I - Connection to server */
471 {
472 char hostname[256], /* Hostname */
473 *hostptr; /* Pointer into hostname */
474 int status; /* Status of handshake */
475 gnutls_certificate_credentials_t *credentials;
476 /* TLS credentials */
477
478
479 DEBUG_printf(("7_httpTLSStart(http=%p)", http));
480
481 if (http->mode == _HTTP_MODE_SERVER && !tls_keypath)
482 {
483 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
484 http->error = errno = EINVAL;
485 http->status = HTTP_STATUS_ERROR;
486 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
487
488 return (-1);
489 }
490
491 credentials = (gnutls_certificate_credentials_t *)
492 malloc(sizeof(gnutls_certificate_credentials_t));
493 if (credentials == NULL)
494 {
495 DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
496 strerror(errno)));
497 http->error = errno;
498 http->status = HTTP_STATUS_ERROR;
499 _cupsSetHTTPError(HTTP_STATUS_ERROR);
500
501 return (-1);
502 }
503
504 gnutls_certificate_allocate_credentials(credentials);
505 gnutls_init(&http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_CLIENT : GNUTLS_SERVER);
506 gnutls_set_default_priority(http->tls);
507 gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http);
508 gnutls_transport_set_pull_function(http->tls, http_gnutls_read);
509 gnutls_transport_set_push_function(http->tls, http_gnutls_write);
510
511 if (http->mode == _HTTP_MODE_CLIENT)
512 {
513 /*
514 * Client: get the hostname to use for TLS...
515 */
516
517 if (httpAddrLocalhost(http->hostaddr))
518 {
519 strlcpy(hostname, "localhost", sizeof(hostname));
520 }
521 else
522 {
523 /*
524 * Otherwise make sure the hostname we have does not end in a trailing dot.
525 */
526
527 strlcpy(hostname, http->hostname, sizeof(hostname));
528 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
529 *hostptr == '.')
530 *hostptr = '\0';
531 }
532
533 gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, strlen(hostname));
534 gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
535 }
536 else
537 {
538 /*
539 * Server: get certificate and private key...
540 */
541
542 char crtfile[1024], /* Certificate file */
543 keyfile[1024]; /* Private key file */
544 int have_creds = 0; /* Have credentials? */
545
546
547 if (http->fields[HTTP_FIELD_HOST][0])
548 {
549 /*
550 * Use hostname for TLS upgrade...
551 */
552
553 strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
554 }
555 else
556 {
557 /*
558 * Resolve hostname from connection address...
559 */
560
561 http_addr_t addr; /* Connection address */
562 socklen_t addrlen; /* Length of address */
563
564 addrlen = sizeof(addr);
565 if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
566 {
567 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
568 hostname[0] = '\0';
569 }
570 else if (httpAddrLocalhost(&addr))
571 hostname[0] = '\0';
572 else
573 {
574 httpAddrLookup(&addr, hostname, sizeof(hostname));
575 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
576 }
577 }
578
579 if (isdigit(hostname[0] & 255) || hostname[0] == '[')
580 hostname[0] = '\0'; /* Don't allow numeric addresses */
581
582 if (hostname[0])
583 {
584 snprintf(crtfile, sizeof(crtfile), "%s/%s.crt", tls_keypath, hostname);
585 snprintf(keyfile, sizeof(keyfile), "%s/%s.key", tls_keypath, hostname);
586
587 have_creds = !access(crtfile, 0) && !access(keyfile, 0);
588 }
589 else if (tls_common_name)
590 {
591 snprintf(crtfile, sizeof(crtfile), "%s/%s.crt", tls_keypath, tls_common_name);
592 snprintf(keyfile, sizeof(keyfile), "%s/%s.key", tls_keypath, tls_common_name);
593
594 have_creds = !access(crtfile, 0) && !access(keyfile, 0);
595 }
596
597 if (!have_creds && tls_auto_create && (hostname[0] || tls_common_name))
598 {
599 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name));
600
601 if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400))
602 {
603 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
604 http->error = errno = EINVAL;
605 http->status = HTTP_STATUS_ERROR;
606 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
607
608 return (-1);
609 }
610 }
611
612 gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM);
613 }
614
615 while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
616 {
617 DEBUG_printf(("8_httpStartTLS: gnutls_handshake returned %d (%s)",
618 status, gnutls_strerror(status)));
619
620 if (gnutls_error_is_fatal(status))
621 {
622 http->error = EIO;
623 http->status = HTTP_STATUS_ERROR;
624
625 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
626
627 gnutls_deinit(http->tls);
628 gnutls_certificate_free_credentials(*credentials);
629 free(credentials);
630 http->tls = NULL;
631
632 return (-1);
633 }
634 }
635
636 http->tls_credentials = credentials;
637
638 // TODO: Put this in the right place; no-op for now, this to get things to compile
639 // http_tls_set_credentials(http);
640
641 return (0);
642 }
643
644
645 /*
646 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
647 */
648
649 void
650 _httpTLSStop(http_t *http) /* I - Connection to server */
651 {
652 int error; /* Error code */
653
654
655 error = gnutls_bye(http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
656 if (error != GNUTLS_E_SUCCESS)
657 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(errno), 0);
658
659 gnutls_deinit(http->tls);
660 http->tls = NULL;
661
662 gnutls_certificate_free_credentials(*(http->tls_credentials));
663 free(http->tls_credentials);
664 http->tls_credentials = NULL;
665 }
666
667
668 /*
669 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
670 */
671
672 int /* O - Bytes written */
673 _httpTLSWrite(http_t *http, /* I - Connection to server */
674 const char *buf, /* I - Buffer holding data */
675 int len) /* I - Length of buffer */
676 {
677 ssize_t result; /* Return value */
678
679
680 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
681
682 result = gnutls_record_send(http->tls, buf, (size_t)len);
683
684 if (result < 0 && !errno)
685 {
686 /*
687 * Convert GNU TLS error to errno value...
688 */
689
690 switch (result)
691 {
692 case GNUTLS_E_INTERRUPTED :
693 errno = EINTR;
694 break;
695
696 case GNUTLS_E_AGAIN :
697 errno = EAGAIN;
698 break;
699
700 default :
701 errno = EPIPE;
702 break;
703 }
704
705 result = -1;
706 }
707
708 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
709
710 return ((int)result);
711 }
712
713
714 #if 0
715 /*
716 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
717 */
718
719 int /* O - 1 on success, 0 on error */
720 cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */
721 {
722 int error; /* Error code */
723 gnutls_certificate_server_credentials *credentials;
724 /* TLS credentials */
725
726
727 credentials = (gnutls_certificate_server_credentials *)
728 (con->http.tls_credentials);
729
730 error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR);
731 switch (error)
732 {
733 case GNUTLS_E_SUCCESS:
734 cupsdLogMessage(CUPSD_LOG_DEBUG,
735 "SSL shutdown successful!");
736 break;
737 default:
738 cupsdLogMessage(CUPSD_LOG_ERROR,
739 "SSL shutdown failed: %s", gnutls_strerror(error));
740 break;
741 }
742
743 gnutls_deinit(con->http.tls);
744 con->http.tls = NULL;
745
746 gnutls_certificate_free_credentials(*credentials);
747 free(credentials);
748
749 return (1);
750 }
751
752
753 /*
754 * 'cupsdStartTLS()' - Start a secure session with the client.
755 */
756
757 int /* O - 1 on success, 0 on error */
758 cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */
759 {
760 int status; /* Error code */
761 gnutls_certificate_credentials_t *credentials;
762 /* TLS credentials */
763
764
765 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
766 con->http.fd);
767
768 /*
769 * Verify that we have a certificate...
770 */
771
772 if (access(ServerKey, 0) || access(ServerCertificate, 0))
773 {
774 /*
775 * Nope, make a self-signed certificate...
776 */
777
778 if (!make_certificate(con))
779 return (0);
780 }
781
782 /*
783 * Create the SSL object and perform the SSL handshake...
784 */
785
786 credentials = (gnutls_certificate_credentials_t *)
787 malloc(sizeof(gnutls_certificate_credentials_t));
788 if (credentials == NULL)
789 {
790 cupsdLogMessage(CUPSD_LOG_ERROR,
791 "Unable to encrypt connection from %s - %s",
792 con->http.hostname, strerror(errno));
793
794 return (0);
795 }
796
797 gnutls_certificate_allocate_credentials(credentials);
798 gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
799 ServerKey, GNUTLS_X509_FMT_PEM);
800
801 gnutls_init(&con->http.tls, GNUTLS_SERVER);
802 gnutls_set_default_priority(con->http.tls);
803
804 gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials);
805 gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr_t)HTTP(con));
806 gnutls_transport_set_pull_function(con->http.tls, http_gnutls_read);
807 gnutls_transport_set_push_function(con->http.tls, http_gnutls_write);
808
809 while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS)
810 {
811 if (gnutls_error_is_fatal(status))
812 {
813 cupsdLogMessage(CUPSD_LOG_ERROR,
814 "Unable to encrypt connection from %s - %s",
815 con->http.hostname, gnutls_strerror(status));
816
817 gnutls_deinit(con->http.tls);
818 gnutls_certificate_free_credentials(*credentials);
819 con->http.tls = NULL;
820 free(credentials);
821 return (0);
822 }
823 }
824
825 cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
826 con->http.hostname);
827
828 con->http.tls_credentials = credentials;
829 return (1);
830 }
831
832
833 /*
834 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
835 */
836
837 static int /* O - 1 on success, 0 on failure */
838 make_certificate(cupsd_client_t *con) /* I - Client connection */
839 {
840 gnutls_x509_crt crt; /* Self-signed certificate */
841 gnutls_x509_privkey key; /* Encryption key */
842 cups_lang_t *language; /* Default language info */
843 cups_file_t *fp; /* Key/cert file */
844 unsigned char buffer[8192]; /* Buffer for x509 data */
845 size_t bytes; /* Number of bytes of data */
846 unsigned char serial[4]; /* Serial number buffer */
847 time_t curtime; /* Current time */
848 int result; /* Result of GNU TLS calls */
849
850
851 /*
852 * Create the encryption key...
853 */
854
855 cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key...");
856
857 gnutls_x509_privkey_init(&key);
858 gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
859
860 /*
861 * Save it...
862 */
863
864 bytes = sizeof(buffer);
865
866 if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
867 buffer, &bytes)) < 0)
868 {
869 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s",
870 gnutls_strerror(result));
871 gnutls_x509_privkey_deinit(key);
872 return (0);
873 }
874 else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL)
875 {
876 cupsFileWrite(fp, (char *)buffer, bytes);
877 cupsFileClose(fp);
878
879 cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
880 ServerKey);
881 }
882 else
883 {
884 cupsdLogMessage(CUPSD_LOG_ERROR,
885 "Unable to create SSL server key file \"%s\" - %s",
886 ServerKey, strerror(errno));
887 gnutls_x509_privkey_deinit(key);
888 return (0);
889 }
890
891 /*
892 * Create the self-signed certificate...
893 */
894
895 cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate...");
896
897 language = cupsLangDefault();
898 curtime = time(NULL);
899 serial[0] = curtime >> 24;
900 serial[1] = curtime >> 16;
901 serial[2] = curtime >> 8;
902 serial[3] = curtime;
903
904 gnutls_x509_crt_init(&crt);
905 if (strlen(language->language) == 5)
906 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
907 language->language + 3, 2);
908 else
909 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
910 "US", 2);
911 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
912 ServerName, strlen(ServerName));
913 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
914 ServerName, strlen(ServerName));
915 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
916 0, "Unknown", 7);
917 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
918 "Unknown", 7);
919 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
920 "Unknown", 7);
921 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
922 ServerAdmin, strlen(ServerAdmin));
923 gnutls_x509_crt_set_key(crt, key);
924 gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
925 gnutls_x509_crt_set_activation_time(crt, curtime);
926 gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
927 gnutls_x509_crt_set_ca_status(crt, 0);
928 gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME,
929 ServerName);
930 gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
931 gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
932 gnutls_x509_crt_set_version(crt, 3);
933
934 bytes = sizeof(buffer);
935 if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
936 gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
937
938 gnutls_x509_crt_sign(crt, crt, key);
939
940 /*
941 * Save it...
942 */
943
944 bytes = sizeof(buffer);
945 if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM,
946 buffer, &bytes)) < 0)
947 cupsdLogMessage(CUPSD_LOG_ERROR,
948 "Unable to export SSL server certificate - %s",
949 gnutls_strerror(result));
950 else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL)
951 {
952 cupsFileWrite(fp, (char *)buffer, bytes);
953 cupsFileClose(fp);
954
955 cupsdLogMessage(CUPSD_LOG_INFO,
956 "Created SSL server certificate file \"%s\"...",
957 ServerCertificate);
958 }
959 else
960 cupsdLogMessage(CUPSD_LOG_ERROR,
961 "Unable to create SSL server certificate file \"%s\" - %s",
962 ServerCertificate, strerror(errno));
963
964 /*
965 * Cleanup...
966 */
967
968 gnutls_x509_crt_deinit(crt);
969 gnutls_x509_privkey_deinit(key);
970
971 return (1);
972 }
973 #endif /* 0 */
974
975
976 /*
977 * End of "$Id$".
978 */