]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/tls-gnutls.c
Fix build errors on Fedora.
[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 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 (void)path;
57 (void)common_name;
58 (void)num_alt_names;
59 (void)alt_names;
60 (void)expiration_date;
61
62 return (0);
63 }
64
65
66 /*
67 * 'cupsSetServerCredentials()' - Set the default server credentials.
68 *
69 * Note: The server credentials are used by all threads in the running process.
70 * This function is threadsafe.
71 *
72 * @since CUPS 2.0@
73 */
74
75 int /* O - 1 on success, 0 on failure */
76 cupsSetServerCredentials(
77 const char *path, /* I - Path to keychain/directory */
78 const char *common_name, /* I - Default common name for server */
79 int auto_create) /* I - 1 = automatically create self-signed certificates */
80 {
81 _cupsMutexLock(&tls_mutex);
82
83 /*
84 * Free old values...
85 */
86
87 if (tls_keypath)
88 _cupsStrFree(tls_keypath);
89
90 if (tls_common_name)
91 _cupsStrFree(tls_common_name);
92
93 /*
94 * Save the new values...
95 */
96
97 tls_keypath = _cupsStrAlloc(path);
98 tls_auto_create = auto_create;
99 tls_common_name = _cupsStrAlloc(common_name);
100
101 _cupsMutexUnlock(&tls_mutex);
102
103 return (1);
104 }
105
106
107 /*
108 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
109 * an encrypted connection.
110 *
111 * @since CUPS 1.5/OS X 10.7@
112 */
113
114 int /* O - Status of call (0 = success) */
115 httpCopyCredentials(
116 http_t *http, /* I - Connection to server */
117 cups_array_t **credentials) /* O - Array of credentials */
118 {
119 if (credentials)
120 *credentials = NULL;
121
122 if (!http || !http->tls || !credentials)
123 return (-1);
124
125 return (0);
126 }
127
128
129 /*
130 * '_httpCreateCredentials()' - Create credentials in the internal format.
131 */
132
133 http_tls_credentials_t /* O - Internal credentials */
134 _httpCreateCredentials(
135 cups_array_t *credentials) /* I - Array of credentials */
136 {
137 (void)credentials;
138
139 return (NULL);
140 }
141
142
143 /*
144 * '_httpFreeCredentials()' - Free internal credentials.
145 */
146
147 void
148 _httpFreeCredentials(
149 http_tls_credentials_t credentials) /* I - Internal credentials */
150 {
151 (void)credentials;
152 }
153
154
155 /*
156 * 'http_gnutls_read()' - Read function for the GNU TLS library.
157 */
158
159 static ssize_t /* O - Number of bytes read or -1 on error */
160 http_gnutls_read(
161 gnutls_transport_ptr_t ptr, /* I - Connection to server */
162 void *data, /* I - Buffer */
163 size_t length) /* I - Number of bytes to read */
164 {
165 http_t *http; /* HTTP connection */
166 ssize_t bytes; /* Bytes read */
167
168
169 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr, data, (int)length));
170
171 http = (http_t *)ptr;
172
173 if (!http->blocking)
174 {
175 /*
176 * Make sure we have data before we read...
177 */
178
179 while (!_httpWait(http, http->wait_value, 0))
180 {
181 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
182 continue;
183
184 http->error = ETIMEDOUT;
185 return (-1);
186 }
187 }
188
189 bytes = recv(http->fd, data, length, 0);
190 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes));
191 return (bytes);
192 }
193
194
195 /*
196 * 'http_gnutls_write()' - Write function for the GNU TLS library.
197 */
198
199 static ssize_t /* O - Number of bytes written or -1 on error */
200 http_gnutls_write(
201 gnutls_transport_ptr_t ptr, /* I - Connection to server */
202 const void *data, /* I - Data buffer */
203 size_t length) /* I - Number of bytes to write */
204 {
205 ssize_t bytes; /* Bytes written */
206
207
208 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr, data,
209 (int)length));
210 #ifdef DEBUG
211 http_debug_hex("http_gnutls_write", data, (int)length);
212 #endif /* DEBUG */
213
214 bytes = send(((http_t *)ptr)->fd, data, length, 0);
215 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes));
216
217 return (bytes);
218 }
219
220
221 /*
222 * 'http_tls_initialize()' - Initialize the TLS stack.
223 */
224
225 static void
226 http_tls_initialize(void)
227 {
228 /*
229 * Initialize GNU TLS...
230 */
231
232 gnutls_global_init();
233 }
234
235
236 /*
237 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
238 */
239
240 static size_t
241 http_tls_pending(http_t *http) /* I - HTTP connection */
242 {
243 return (gnutls_record_check_pending(http->tls));
244 }
245
246
247 /*
248 * 'http_tls_read()' - Read from a SSL/TLS connection.
249 */
250
251 static int /* O - Bytes read */
252 http_tls_read(http_t *http, /* I - Connection to server */
253 char *buf, /* I - Buffer to store data */
254 int len) /* I - Length of buffer */
255 {
256 ssize_t result; /* Return value */
257
258
259 result = gnutls_record_recv(http->tls, buf, (size_t)len);
260
261 if (result < 0 && !errno)
262 {
263 /*
264 * Convert GNU TLS error to errno value...
265 */
266
267 switch (result)
268 {
269 case GNUTLS_E_INTERRUPTED :
270 errno = EINTR;
271 break;
272
273 case GNUTLS_E_AGAIN :
274 errno = EAGAIN;
275 break;
276
277 default :
278 errno = EPIPE;
279 break;
280 }
281
282 result = -1;
283 }
284
285 return ((int)result);
286 }
287
288
289 /*
290 * 'http_tls_set_credentials()' - Set the TLS credentials.
291 */
292
293 static int /* O - Status of connection */
294 http_tls_set_credentials(http_t *http) /* I - Connection to server */
295 {
296 (void)http;
297
298 return (0);
299 }
300
301
302 /*
303 * 'http_tls_start()' - Set up SSL/TLS support on a connection.
304 */
305
306 static int /* O - 0 on success, -1 on failure */
307 http_tls_start(http_t *http) /* I - Connection to server */
308 {
309 char hostname[256], /* Hostname */
310 *hostptr; /* Pointer into hostname */
311 int status; /* Status of handshake */
312 gnutls_certificate_client_credentials *credentials;
313 /* TLS credentials */
314
315
316 DEBUG_printf(("7http_setup_ssl(http=%p)", http));
317
318 /*
319 * Get the hostname to use for SSL...
320 */
321
322 if (httpAddrLocalhost(http->hostaddr))
323 {
324 strlcpy(hostname, "localhost", sizeof(hostname));
325 }
326 else
327 {
328 /*
329 * Otherwise make sure the hostname we have does not end in a trailing dot.
330 */
331
332 strlcpy(hostname, http->hostname, sizeof(hostname));
333 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
334 *hostptr == '.')
335 *hostptr = '\0';
336 }
337
338 credentials = (gnutls_certificate_client_credentials *)
339 malloc(sizeof(gnutls_certificate_client_credentials));
340 if (credentials == NULL)
341 {
342 DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s",
343 strerror(errno)));
344 http->error = errno;
345 http->status = HTTP_STATUS_ERROR;
346 _cupsSetHTTPError(HTTP_STATUS_ERROR);
347
348 return (-1);
349 }
350
351 gnutls_certificate_allocate_credentials(credentials);
352
353 gnutls_init(&http->tls, GNUTLS_CLIENT);
354 gnutls_set_default_priority(http->tls);
355 gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname,
356 strlen(hostname));
357 gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
358 gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http);
359 gnutls_transport_set_pull_function(http->tls, http_gnutls_read);
360 gnutls_transport_set_push_function(http->tls, http_gnutls_write);
361
362 while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
363 {
364 DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)",
365 status, gnutls_strerror(status)));
366
367 if (gnutls_error_is_fatal(status))
368 {
369 http->error = EIO;
370 http->status = HTTP_STATUS_ERROR;
371
372 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
373
374 gnutls_deinit(http->tls);
375 gnutls_certificate_free_credentials(*credentials);
376 free(credentials);
377 http->tls = NULL;
378
379 return (-1);
380 }
381 }
382
383 http->tls_credentials = credentials;
384
385 // TODO: Put this in the right place; no-op for now, this to get things to compile
386 http_tls_set_credentials(http);
387
388 return (0);
389 }
390
391
392 /*
393 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
394 */
395
396 static void
397 http_tls_stop(http_t *http) /* I - Connection to server */
398 {
399 gnutls_certificate_client_credentials *credentials;
400 /* TLS credentials */
401
402 credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials);
403
404 gnutls_bye(http->tls, GNUTLS_SHUT_RDWR);
405 gnutls_deinit(http->tls);
406 gnutls_certificate_free_credentials(*credentials);
407 free(credentials);
408 }
409
410
411 /*
412 * 'http_tls_write()' - Write to a SSL/TLS connection.
413 */
414
415 static int /* O - Bytes written */
416 http_tls_write(http_t *http, /* I - Connection to server */
417 const char *buf, /* I - Buffer holding data */
418 int len) /* I - Length of buffer */
419 {
420 ssize_t result; /* Return value */
421
422
423 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
424
425 result = gnutls_record_send(http->tls, buf, (size_t)len);
426
427 if (result < 0 && !errno)
428 {
429 /*
430 * Convert GNU TLS error to errno value...
431 */
432
433 switch (result)
434 {
435 case GNUTLS_E_INTERRUPTED :
436 errno = EINTR;
437 break;
438
439 case GNUTLS_E_AGAIN :
440 errno = EAGAIN;
441 break;
442
443 default :
444 errno = EPIPE;
445 break;
446 }
447
448 result = -1;
449 }
450
451 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
452
453 return ((int)result);
454 }
455
456
457 #if 0
458 /*
459 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
460 */
461
462 int /* O - 1 on success, 0 on error */
463 cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */
464 {
465 int error; /* Error code */
466 gnutls_certificate_server_credentials *credentials;
467 /* TLS credentials */
468
469
470 credentials = (gnutls_certificate_server_credentials *)
471 (con->http.tls_credentials);
472
473 error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR);
474 switch (error)
475 {
476 case GNUTLS_E_SUCCESS:
477 cupsdLogMessage(CUPSD_LOG_DEBUG,
478 "SSL shutdown successful!");
479 break;
480 default:
481 cupsdLogMessage(CUPSD_LOG_ERROR,
482 "SSL shutdown failed: %s", gnutls_strerror(error));
483 break;
484 }
485
486 gnutls_deinit(con->http.tls);
487 con->http.tls = NULL;
488
489 gnutls_certificate_free_credentials(*credentials);
490 free(credentials);
491
492 return (1);
493 }
494
495
496 /*
497 * 'cupsdStartTLS()' - Start a secure session with the client.
498 */
499
500 int /* O - 1 on success, 0 on error */
501 cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */
502 {
503 int status; /* Error code */
504 gnutls_certificate_server_credentials *credentials;
505 /* TLS credentials */
506
507
508 cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
509 con->http.fd);
510
511 /*
512 * Verify that we have a certificate...
513 */
514
515 if (access(ServerKey, 0) || access(ServerCertificate, 0))
516 {
517 /*
518 * Nope, make a self-signed certificate...
519 */
520
521 if (!make_certificate(con))
522 return (0);
523 }
524
525 /*
526 * Create the SSL object and perform the SSL handshake...
527 */
528
529 credentials = (gnutls_certificate_server_credentials *)
530 malloc(sizeof(gnutls_certificate_server_credentials));
531 if (credentials == NULL)
532 {
533 cupsdLogMessage(CUPSD_LOG_ERROR,
534 "Unable to encrypt connection from %s - %s",
535 con->http.hostname, strerror(errno));
536
537 return (0);
538 }
539
540 gnutls_certificate_allocate_credentials(credentials);
541 gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
542 ServerKey, GNUTLS_X509_FMT_PEM);
543
544 gnutls_init(&con->http.tls, GNUTLS_SERVER);
545 gnutls_set_default_priority(con->http.tls);
546
547 gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials);
548 gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr_t)HTTP(con));
549 gnutls_transport_set_pull_function(con->http.tls, http_gnutls_read);
550 gnutls_transport_set_push_function(con->http.tls, http_gnutls_write);
551
552 while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS)
553 {
554 if (gnutls_error_is_fatal(status))
555 {
556 cupsdLogMessage(CUPSD_LOG_ERROR,
557 "Unable to encrypt connection from %s - %s",
558 con->http.hostname, gnutls_strerror(status));
559
560 gnutls_deinit(con->http.tls);
561 gnutls_certificate_free_credentials(*credentials);
562 con->http.tls = NULL;
563 free(credentials);
564 return (0);
565 }
566 }
567
568 cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
569 con->http.hostname);
570
571 con->http.tls_credentials = credentials;
572 return (1);
573 }
574
575
576 /*
577 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
578 */
579
580 static int /* O - 1 on success, 0 on failure */
581 make_certificate(cupsd_client_t *con) /* I - Client connection */
582 {
583 gnutls_x509_crt crt; /* Self-signed certificate */
584 gnutls_x509_privkey key; /* Encryption key */
585 cups_lang_t *language; /* Default language info */
586 cups_file_t *fp; /* Key/cert file */
587 unsigned char buffer[8192]; /* Buffer for x509 data */
588 size_t bytes; /* Number of bytes of data */
589 unsigned char serial[4]; /* Serial number buffer */
590 time_t curtime; /* Current time */
591 int result; /* Result of GNU TLS calls */
592
593
594 /*
595 * Create the encryption key...
596 */
597
598 cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key...");
599
600 gnutls_x509_privkey_init(&key);
601 gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
602
603 /*
604 * Save it...
605 */
606
607 bytes = sizeof(buffer);
608
609 if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
610 buffer, &bytes)) < 0)
611 {
612 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s",
613 gnutls_strerror(result));
614 gnutls_x509_privkey_deinit(key);
615 return (0);
616 }
617 else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL)
618 {
619 cupsFileWrite(fp, (char *)buffer, bytes);
620 cupsFileClose(fp);
621
622 cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
623 ServerKey);
624 }
625 else
626 {
627 cupsdLogMessage(CUPSD_LOG_ERROR,
628 "Unable to create SSL server key file \"%s\" - %s",
629 ServerKey, strerror(errno));
630 gnutls_x509_privkey_deinit(key);
631 return (0);
632 }
633
634 /*
635 * Create the self-signed certificate...
636 */
637
638 cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate...");
639
640 language = cupsLangDefault();
641 curtime = time(NULL);
642 serial[0] = curtime >> 24;
643 serial[1] = curtime >> 16;
644 serial[2] = curtime >> 8;
645 serial[3] = curtime;
646
647 gnutls_x509_crt_init(&crt);
648 if (strlen(language->language) == 5)
649 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
650 language->language + 3, 2);
651 else
652 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
653 "US", 2);
654 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
655 ServerName, strlen(ServerName));
656 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
657 ServerName, strlen(ServerName));
658 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
659 0, "Unknown", 7);
660 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
661 "Unknown", 7);
662 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
663 "Unknown", 7);
664 gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
665 ServerAdmin, strlen(ServerAdmin));
666 gnutls_x509_crt_set_key(crt, key);
667 gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
668 gnutls_x509_crt_set_activation_time(crt, curtime);
669 gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
670 gnutls_x509_crt_set_ca_status(crt, 0);
671 gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME,
672 ServerName);
673 gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
674 gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
675 gnutls_x509_crt_set_version(crt, 3);
676
677 bytes = sizeof(buffer);
678 if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
679 gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
680
681 gnutls_x509_crt_sign(crt, crt, key);
682
683 /*
684 * Save it...
685 */
686
687 bytes = sizeof(buffer);
688 if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM,
689 buffer, &bytes)) < 0)
690 cupsdLogMessage(CUPSD_LOG_ERROR,
691 "Unable to export SSL server certificate - %s",
692 gnutls_strerror(result));
693 else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL)
694 {
695 cupsFileWrite(fp, (char *)buffer, bytes);
696 cupsFileClose(fp);
697
698 cupsdLogMessage(CUPSD_LOG_INFO,
699 "Created SSL server certificate file \"%s\"...",
700 ServerCertificate);
701 }
702 else
703 cupsdLogMessage(CUPSD_LOG_ERROR,
704 "Unable to create SSL server certificate file \"%s\" - %s",
705 ServerCertificate, strerror(errno));
706
707 /*
708 * Cleanup...
709 */
710
711 gnutls_x509_crt_deinit(crt);
712 gnutls_x509_privkey_deinit(key);
713
714 return (1);
715 }
716 #endif /* 0 */
717
718
719 /*
720 * End of "$Id$".
721 */