4 * TLS support code for CUPS using GNU TLS.
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
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 */
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
);
43 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
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 */
60 (void)expiration_date
;
67 * 'cupsSetServerCredentials()' - Set the default server credentials.
69 * Note: The server credentials are used by all threads in the running process.
70 * This function is threadsafe.
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 */
81 _cupsMutexLock(&tls_mutex
);
88 _cupsStrFree(tls_keypath
);
91 _cupsStrFree(tls_common_name
);
94 * Save the new values...
97 tls_keypath
= _cupsStrAlloc(path
);
98 tls_auto_create
= auto_create
;
99 tls_common_name
= _cupsStrAlloc(common_name
);
101 _cupsMutexUnlock(&tls_mutex
);
108 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
109 * an encrypted connection.
111 * @since CUPS 1.5/OS X 10.7@
114 int /* O - Status of call (0 = success) */
116 http_t
*http
, /* I - Connection to server */
117 cups_array_t
**credentials
) /* O - Array of credentials */
122 if (!http
|| !http
->tls
|| !credentials
)
130 * '_httpCreateCredentials()' - Create credentials in the internal format.
133 http_tls_credentials_t
/* O - Internal credentials */
134 _httpCreateCredentials(
135 cups_array_t
*credentials
) /* I - Array of credentials */
144 * '_httpFreeCredentials()' - Free internal credentials.
148 _httpFreeCredentials(
149 http_tls_credentials_t credentials
) /* I - Internal credentials */
156 * 'http_gnutls_read()' - Read function for the GNU TLS library.
159 static ssize_t
/* O - Number of bytes read or -1 on error */
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 */
165 http_t
*http
; /* HTTP connection */
166 ssize_t bytes
; /* Bytes read */
169 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr
, data
, (int)length
));
171 http
= (http_t
*)ptr
;
176 * Make sure we have data before we read...
179 while (!_httpWait(http
, http
->wait_value
, 0))
181 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
184 http
->error
= ETIMEDOUT
;
189 bytes
= recv(http
->fd
, data
, length
, 0);
190 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes
));
196 * 'http_gnutls_write()' - Write function for the GNU TLS library.
199 static ssize_t
/* O - Number of bytes written or -1 on error */
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 */
205 ssize_t bytes
; /* Bytes written */
208 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr
, data
,
211 http_debug_hex("http_gnutls_write", data
, (int)length
);
214 bytes
= send(((http_t
*)ptr
)->fd
, data
, length
, 0);
215 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes
));
222 * 'http_tls_initialize()' - Initialize the TLS stack.
226 http_tls_initialize(void)
229 * Initialize GNU TLS...
232 gnutls_global_init();
237 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
241 http_tls_pending(http_t
*http
) /* I - HTTP connection */
243 return (gnutls_record_check_pending(http
->tls
));
248 * 'http_tls_read()' - Read from a SSL/TLS connection.
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 */
256 ssize_t result
; /* Return value */
259 result
= gnutls_record_recv(http
->tls
, buf
, (size_t)len
);
261 if (result
< 0 && !errno
)
264 * Convert GNU TLS error to errno value...
269 case GNUTLS_E_INTERRUPTED
:
273 case GNUTLS_E_AGAIN
:
285 return ((int)result
);
290 * 'http_tls_set_credentials()' - Set the TLS credentials.
293 static int /* O - Status of connection */
294 http_tls_set_credentials(http_t
*http
) /* I - Connection to server */
303 * 'http_tls_start()' - Set up SSL/TLS support on a connection.
306 static int /* O - 0 on success, -1 on failure */
307 http_tls_start(http_t
*http
) /* I - Connection to server */
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 */
316 DEBUG_printf(("7http_setup_ssl(http=%p)", http
));
319 * Get the hostname to use for SSL...
322 if (httpAddrLocalhost(http
->hostaddr
))
324 strlcpy(hostname
, "localhost", sizeof(hostname
));
329 * Otherwise make sure the hostname we have does not end in a trailing dot.
332 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
333 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
338 credentials
= (gnutls_certificate_client_credentials
*)
339 malloc(sizeof(gnutls_certificate_client_credentials
));
340 if (credentials
== NULL
)
342 DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s",
345 http
->status
= HTTP_STATUS_ERROR
;
346 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
351 gnutls_certificate_allocate_credentials(credentials
);
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
,
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
);
362 while ((status
= gnutls_handshake(http
->tls
)) != GNUTLS_E_SUCCESS
)
364 DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)",
365 status
, gnutls_strerror(status
)));
367 if (gnutls_error_is_fatal(status
))
370 http
->status
= HTTP_STATUS_ERROR
;
372 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
374 gnutls_deinit(http
->tls
);
375 gnutls_certificate_free_credentials(*credentials
);
383 http
->tls_credentials
= credentials
;
385 // TODO: Put this in the right place; no-op for now, this to get things to compile
386 http_tls_set_credentials(http
);
393 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
397 http_tls_stop(http_t
*http
) /* I - Connection to server */
399 gnutls_certificate_client_credentials
*credentials
;
400 /* TLS credentials */
402 credentials
= (gnutls_certificate_client_credentials
*)(http
->tls_credentials
);
404 gnutls_bye(http
->tls
, GNUTLS_SHUT_RDWR
);
405 gnutls_deinit(http
->tls
);
406 gnutls_certificate_free_credentials(*credentials
);
412 * 'http_tls_write()' - Write to a SSL/TLS connection.
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 */
420 ssize_t result
; /* Return value */
423 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http
, buf
, len
));
425 result
= gnutls_record_send(http
->tls
, buf
, (size_t)len
);
427 if (result
< 0 && !errno
)
430 * Convert GNU TLS error to errno value...
435 case GNUTLS_E_INTERRUPTED
:
439 case GNUTLS_E_AGAIN
:
451 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result
));
453 return ((int)result
);
459 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
462 int /* O - 1 on success, 0 on error */
463 cupsdEndTLS(cupsd_client_t
*con
) /* I - Client connection */
465 int error
; /* Error code */
466 gnutls_certificate_server_credentials
*credentials
;
467 /* TLS credentials */
470 credentials
= (gnutls_certificate_server_credentials
*)
471 (con
->http
.tls_credentials
);
473 error
= gnutls_bye(con
->http
.tls
, GNUTLS_SHUT_WR
);
476 case GNUTLS_E_SUCCESS
:
477 cupsdLogMessage(CUPSD_LOG_DEBUG
,
478 "SSL shutdown successful!");
481 cupsdLogMessage(CUPSD_LOG_ERROR
,
482 "SSL shutdown failed: %s", gnutls_strerror(error
));
486 gnutls_deinit(con
->http
.tls
);
487 con
->http
.tls
= NULL
;
489 gnutls_certificate_free_credentials(*credentials
);
497 * 'cupsdStartTLS()' - Start a secure session with the client.
500 int /* O - 1 on success, 0 on error */
501 cupsdStartTLS(cupsd_client_t
*con
) /* I - Client connection */
503 int status
; /* Error code */
504 gnutls_certificate_server_credentials
*credentials
;
505 /* TLS credentials */
508 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Client %d] Encrypting connection.",
512 * Verify that we have a certificate...
515 if (access(ServerKey
, 0) || access(ServerCertificate
, 0))
518 * Nope, make a self-signed certificate...
521 if (!make_certificate(con
))
526 * Create the SSL object and perform the SSL handshake...
529 credentials
= (gnutls_certificate_server_credentials
*)
530 malloc(sizeof(gnutls_certificate_server_credentials
));
531 if (credentials
== NULL
)
533 cupsdLogMessage(CUPSD_LOG_ERROR
,
534 "Unable to encrypt connection from %s - %s",
535 con
->http
.hostname
, strerror(errno
));
540 gnutls_certificate_allocate_credentials(credentials
);
541 gnutls_certificate_set_x509_key_file(*credentials
, ServerCertificate
,
542 ServerKey
, GNUTLS_X509_FMT_PEM
);
544 gnutls_init(&con
->http
.tls
, GNUTLS_SERVER
);
545 gnutls_set_default_priority(con
->http
.tls
);
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
);
552 while ((status
= gnutls_handshake(con
->http
.tls
)) != GNUTLS_E_SUCCESS
)
554 if (gnutls_error_is_fatal(status
))
556 cupsdLogMessage(CUPSD_LOG_ERROR
,
557 "Unable to encrypt connection from %s - %s",
558 con
->http
.hostname
, gnutls_strerror(status
));
560 gnutls_deinit(con
->http
.tls
);
561 gnutls_certificate_free_credentials(*credentials
);
562 con
->http
.tls
= NULL
;
568 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Connection from %s now encrypted.",
571 con
->http
.tls_credentials
= credentials
;
577 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
580 static int /* O - 1 on success, 0 on failure */
581 make_certificate(cupsd_client_t
*con
) /* I - Client connection */
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 */
595 * Create the encryption key...
598 cupsdLogMessage(CUPSD_LOG_INFO
, "Generating SSL server key...");
600 gnutls_x509_privkey_init(&key
);
601 gnutls_x509_privkey_generate(key
, GNUTLS_PK_RSA
, 2048, 0);
607 bytes
= sizeof(buffer
);
609 if ((result
= gnutls_x509_privkey_export(key
, GNUTLS_X509_FMT_PEM
,
610 buffer
, &bytes
)) < 0)
612 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to export SSL server key - %s",
613 gnutls_strerror(result
));
614 gnutls_x509_privkey_deinit(key
);
617 else if ((fp
= cupsFileOpen(ServerKey
, "w")) != NULL
)
619 cupsFileWrite(fp
, (char *)buffer
, bytes
);
622 cupsdLogMessage(CUPSD_LOG_INFO
, "Created SSL server key file \"%s\"...",
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
);
635 * Create the self-signed certificate...
638 cupsdLogMessage(CUPSD_LOG_INFO
, "Generating self-signed SSL certificate...");
640 language
= cupsLangDefault();
641 curtime
= time(NULL
);
642 serial
[0] = curtime
>> 24;
643 serial
[1] = curtime
>> 16;
644 serial
[2] = curtime
>> 8;
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);
652 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
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
,
660 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME
, 0,
662 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_LOCALITY_NAME
, 0,
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
,
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);
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
);
681 gnutls_x509_crt_sign(crt
, crt
, key
);
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
)
695 cupsFileWrite(fp
, (char *)buffer
, bytes
);
698 cupsdLogMessage(CUPSD_LOG_INFO
,
699 "Created SSL server certificate file \"%s\"...",
703 cupsdLogMessage(CUPSD_LOG_ERROR
,
704 "Unable to create SSL server certificate file \"%s\" - %s",
705 ServerCertificate
, strerror(errno
));
711 gnutls_x509_crt_deinit(crt
);
712 gnutls_x509_privkey_deinit(key
);