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 make_certificate(cupsd_client_t *con);
24 static ssize_t
http_gnutls_read(gnutls_transport_ptr_t ptr
, void *data
, size_t length
);
25 static ssize_t
http_gnutls_write(gnutls_transport_ptr_t ptr
, const void *data
, size_t length
);
29 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
30 * an encrypted connection.
32 * @since CUPS 1.5/OS X 10.7@
35 int /* O - Status of call (0 = success) */
37 http_t
*http
, /* I - Connection to server */
38 cups_array_t
**credentials
) /* O - Array of credentials */
43 if (!http
|| !http
->tls
|| !credentials
)
51 * '_httpCreateCredentials()' - Create credentials in the internal format.
54 http_tls_credentials_t
/* O - Internal credentials */
55 _httpCreateCredentials(
56 cups_array_t
*credentials
) /* I - Array of credentials */
65 * '_httpFreeCredentials()' - Free internal credentials.
70 http_tls_credentials_t credentials
) /* I - Internal credentials */
77 * 'http_gnutls_read()' - Read function for the GNU TLS library.
80 static ssize_t
/* O - Number of bytes read or -1 on error */
82 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
83 void *data
, /* I - Buffer */
84 size_t length
) /* I - Number of bytes to read */
86 http_t
*http
; /* HTTP connection */
87 ssize_t bytes
; /* Bytes read */
90 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr
, data
, (int)length
));
97 * Make sure we have data before we read...
100 while (!_httpWait(http
, http
->wait_value
, 0))
102 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
105 http
->error
= ETIMEDOUT
;
110 bytes
= recv(http
->fd
, data
, length
, 0);
111 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes
));
117 * 'http_gnutls_write()' - Write function for the GNU TLS library.
120 static ssize_t
/* O - Number of bytes written or -1 on error */
122 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
123 const void *data
, /* I - Data buffer */
124 size_t length
) /* I - Number of bytes to write */
126 ssize_t bytes
; /* Bytes written */
129 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr
, data
,
132 http_debug_hex("http_gnutls_write", data
, (int)length
);
135 bytes
= send(((http_t
*)ptr
)->fd
, data
, length
, 0);
136 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes
));
143 * 'http_tls_initialize()' - Initialize the TLS stack.
147 http_tls_initialize(void)
150 * Initialize GNU TLS...
153 gnutls_global_init();
158 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
162 http_tls_pending(http_t
*http
) /* I - HTTP connection */
164 return (gnutls_record_check_pending(http
->tls
));
169 * 'http_tls_read()' - Read from a SSL/TLS connection.
172 static int /* O - Bytes read */
173 http_tls_read(http_t
*http
, /* I - Connection to server */
174 char *buf
, /* I - Buffer to store data */
175 int len
) /* I - Length of buffer */
177 ssize_t result
; /* Return value */
180 result
= gnutls_record_recv(http
->tls
, buf
, len
);
182 if (result
< 0 && !errno
)
185 * Convert GNU TLS error to errno value...
190 case GNUTLS_E_INTERRUPTED
:
194 case GNUTLS_E_AGAIN
:
206 return ((int)result
);
211 * 'http_tls_set_credentials()' - Set the TLS credentials.
214 static int /* O - Status of connection */
215 http_tls_set_credentials(http_t
*http
) /* I - Connection to server */
224 * 'http_tls_start()' - Set up SSL/TLS support on a connection.
227 static int /* O - 0 on success, -1 on failure */
228 http_tls_start(http_t
*http
) /* I - Connection to server */
230 char hostname
[256], /* Hostname */
231 *hostptr
; /* Pointer into hostname */
232 int status
; /* Status of handshake */
233 gnutls_certificate_client_credentials
*credentials
;
234 /* TLS credentials */
237 DEBUG_printf(("7http_setup_ssl(http=%p)", http
));
240 * Get the hostname to use for SSL...
243 if (httpAddrLocalhost(http
->hostaddr
))
245 strlcpy(hostname
, "localhost", sizeof(hostname
));
250 * Otherwise make sure the hostname we have does not end in a trailing dot.
253 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
254 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
259 credentials
= (gnutls_certificate_client_credentials
*)
260 malloc(sizeof(gnutls_certificate_client_credentials
));
261 if (credentials
== NULL
)
263 DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s",
266 http
->status
= HTTP_STATUS_ERROR
;
267 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
272 gnutls_certificate_allocate_credentials(credentials
);
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
,
278 gnutls_credentials_set(http
->tls
, GNUTLS_CRD_CERTIFICATE
, *credentials
);
279 gnutls_transport_set_ptr(http
->tls
, (gnutls_transport_ptr_t
)http
);
280 gnutls_transport_set_pull_function(http
->tls
, http_gnutls_read
);
281 gnutls_transport_set_push_function(http
->tls
, http_gnutls_write
);
283 while ((status
= gnutls_handshake(http
->tls
)) != GNUTLS_E_SUCCESS
)
285 DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)",
286 status
, gnutls_strerror(status
)));
288 if (gnutls_error_is_fatal(status
))
291 http
->status
= HTTP_STATUS_ERROR
;
293 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
295 gnutls_deinit(http
->tls
);
296 gnutls_certificate_free_credentials(*credentials
);
304 http
->tls_credentials
= credentials
;
306 // TODO: Put this in the right place; no-op for now, this to get things to compile
307 http_tls_set_credentials(http
);
314 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
318 http_tls_stop(http_t
*http
) /* I - Connection to server */
320 gnutls_certificate_client_credentials
*credentials
;
321 /* TLS credentials */
323 credentials
= (gnutls_certificate_client_credentials
*)(http
->tls_credentials
);
325 gnutls_bye(http
->tls
, GNUTLS_SHUT_RDWR
);
326 gnutls_deinit(http
->tls
);
327 gnutls_certificate_free_credentials(*credentials
);
333 * 'http_tls_write()' - Write to a SSL/TLS connection.
336 static int /* O - Bytes written */
337 http_tls_write(http_t
*http
, /* I - Connection to server */
338 const char *buf
, /* I - Buffer holding data */
339 int len
) /* I - Length of buffer */
341 ssize_t result
; /* Return value */
344 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http
, buf
, len
));
346 result
= gnutls_record_send(http
->tls
, buf
, len
);
348 if (result
< 0 && !errno
)
351 * Convert GNU TLS error to errno value...
356 case GNUTLS_E_INTERRUPTED
:
360 case GNUTLS_E_AGAIN
:
372 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result
));
374 return ((int)result
);
380 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
383 int /* O - 1 on success, 0 on error */
384 cupsdEndTLS(cupsd_client_t
*con
) /* I - Client connection */
386 int error
; /* Error code */
387 gnutls_certificate_server_credentials
*credentials
;
388 /* TLS credentials */
391 credentials
= (gnutls_certificate_server_credentials
*)
392 (con
->http
.tls_credentials
);
394 error
= gnutls_bye(con
->http
.tls
, GNUTLS_SHUT_WR
);
397 case GNUTLS_E_SUCCESS
:
398 cupsdLogMessage(CUPSD_LOG_DEBUG
,
399 "SSL shutdown successful!");
402 cupsdLogMessage(CUPSD_LOG_ERROR
,
403 "SSL shutdown failed: %s", gnutls_strerror(error
));
407 gnutls_deinit(con
->http
.tls
);
408 con
->http
.tls
= NULL
;
410 gnutls_certificate_free_credentials(*credentials
);
418 * 'cupsdStartTLS()' - Start a secure session with the client.
421 int /* O - 1 on success, 0 on error */
422 cupsdStartTLS(cupsd_client_t
*con
) /* I - Client connection */
424 int status
; /* Error code */
425 gnutls_certificate_server_credentials
*credentials
;
426 /* TLS credentials */
429 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Client %d] Encrypting connection.",
433 * Verify that we have a certificate...
436 if (access(ServerKey
, 0) || access(ServerCertificate
, 0))
439 * Nope, make a self-signed certificate...
442 if (!make_certificate(con
))
447 * Create the SSL object and perform the SSL handshake...
450 credentials
= (gnutls_certificate_server_credentials
*)
451 malloc(sizeof(gnutls_certificate_server_credentials
));
452 if (credentials
== NULL
)
454 cupsdLogMessage(CUPSD_LOG_ERROR
,
455 "Unable to encrypt connection from %s - %s",
456 con
->http
.hostname
, strerror(errno
));
461 gnutls_certificate_allocate_credentials(credentials
);
462 gnutls_certificate_set_x509_key_file(*credentials
, ServerCertificate
,
463 ServerKey
, GNUTLS_X509_FMT_PEM
);
465 gnutls_init(&con
->http
.tls
, GNUTLS_SERVER
);
466 gnutls_set_default_priority(con
->http
.tls
);
468 gnutls_credentials_set(con
->http
.tls
, GNUTLS_CRD_CERTIFICATE
, *credentials
);
469 gnutls_transport_set_ptr(con
->http
.tls
, (gnutls_transport_ptr_t
)HTTP(con
));
470 gnutls_transport_set_pull_function(con
->http
.tls
, http_gnutls_read
);
471 gnutls_transport_set_push_function(con
->http
.tls
, http_gnutls_write
);
473 while ((status
= gnutls_handshake(con
->http
.tls
)) != GNUTLS_E_SUCCESS
)
475 if (gnutls_error_is_fatal(status
))
477 cupsdLogMessage(CUPSD_LOG_ERROR
,
478 "Unable to encrypt connection from %s - %s",
479 con
->http
.hostname
, gnutls_strerror(status
));
481 gnutls_deinit(con
->http
.tls
);
482 gnutls_certificate_free_credentials(*credentials
);
483 con
->http
.tls
= NULL
;
489 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Connection from %s now encrypted.",
492 con
->http
.tls_credentials
= credentials
;
498 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
501 static int /* O - 1 on success, 0 on failure */
502 make_certificate(cupsd_client_t
*con
) /* I - Client connection */
504 gnutls_x509_crt crt
; /* Self-signed certificate */
505 gnutls_x509_privkey key
; /* Encryption key */
506 cups_lang_t
*language
; /* Default language info */
507 cups_file_t
*fp
; /* Key/cert file */
508 unsigned char buffer
[8192]; /* Buffer for x509 data */
509 size_t bytes
; /* Number of bytes of data */
510 unsigned char serial
[4]; /* Serial number buffer */
511 time_t curtime
; /* Current time */
512 int result
; /* Result of GNU TLS calls */
516 * Create the encryption key...
519 cupsdLogMessage(CUPSD_LOG_INFO
, "Generating SSL server key...");
521 gnutls_x509_privkey_init(&key
);
522 gnutls_x509_privkey_generate(key
, GNUTLS_PK_RSA
, 2048, 0);
528 bytes
= sizeof(buffer
);
530 if ((result
= gnutls_x509_privkey_export(key
, GNUTLS_X509_FMT_PEM
,
531 buffer
, &bytes
)) < 0)
533 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to export SSL server key - %s",
534 gnutls_strerror(result
));
535 gnutls_x509_privkey_deinit(key
);
538 else if ((fp
= cupsFileOpen(ServerKey
, "w")) != NULL
)
540 cupsFileWrite(fp
, (char *)buffer
, bytes
);
543 cupsdLogMessage(CUPSD_LOG_INFO
, "Created SSL server key file \"%s\"...",
548 cupsdLogMessage(CUPSD_LOG_ERROR
,
549 "Unable to create SSL server key file \"%s\" - %s",
550 ServerKey
, strerror(errno
));
551 gnutls_x509_privkey_deinit(key
);
556 * Create the self-signed certificate...
559 cupsdLogMessage(CUPSD_LOG_INFO
, "Generating self-signed SSL certificate...");
561 language
= cupsLangDefault();
562 curtime
= time(NULL
);
563 serial
[0] = curtime
>> 24;
564 serial
[1] = curtime
>> 16;
565 serial
[2] = curtime
>> 8;
568 gnutls_x509_crt_init(&crt
);
569 if (strlen(language
->language
) == 5)
570 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
571 language
->language
+ 3, 2);
573 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
575 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COMMON_NAME
, 0,
576 ServerName
, strlen(ServerName
));
577 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_ORGANIZATION_NAME
, 0,
578 ServerName
, strlen(ServerName
));
579 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME
,
581 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME
, 0,
583 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_LOCALITY_NAME
, 0,
585 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_PKCS9_EMAIL
, 0,
586 ServerAdmin
, strlen(ServerAdmin
));
587 gnutls_x509_crt_set_key(crt
, key
);
588 gnutls_x509_crt_set_serial(crt
, serial
, sizeof(serial
));
589 gnutls_x509_crt_set_activation_time(crt
, curtime
);
590 gnutls_x509_crt_set_expiration_time(crt
, curtime
+ 10 * 365 * 86400);
591 gnutls_x509_crt_set_ca_status(crt
, 0);
592 gnutls_x509_crt_set_subject_alternative_name(crt
, GNUTLS_SAN_DNSNAME
,
594 gnutls_x509_crt_set_key_purpose_oid(crt
, GNUTLS_KP_TLS_WWW_SERVER
, 0);
595 gnutls_x509_crt_set_key_usage(crt
, GNUTLS_KEY_KEY_ENCIPHERMENT
);
596 gnutls_x509_crt_set_version(crt
, 3);
598 bytes
= sizeof(buffer
);
599 if (gnutls_x509_crt_get_key_id(crt
, 0, buffer
, &bytes
) >= 0)
600 gnutls_x509_crt_set_subject_key_id(crt
, buffer
, bytes
);
602 gnutls_x509_crt_sign(crt
, crt
, key
);
608 bytes
= sizeof(buffer
);
609 if ((result
= gnutls_x509_crt_export(crt
, GNUTLS_X509_FMT_PEM
,
610 buffer
, &bytes
)) < 0)
611 cupsdLogMessage(CUPSD_LOG_ERROR
,
612 "Unable to export SSL server certificate - %s",
613 gnutls_strerror(result
));
614 else if ((fp
= cupsFileOpen(ServerCertificate
, "w")) != NULL
)
616 cupsFileWrite(fp
, (char *)buffer
, bytes
);
619 cupsdLogMessage(CUPSD_LOG_INFO
,
620 "Created SSL server certificate file \"%s\"...",
624 cupsdLogMessage(CUPSD_LOG_ERROR
,
625 "Unable to create SSL server certificate file \"%s\" - %s",
626 ServerCertificate
, strerror(errno
));
632 gnutls_x509_crt_deinit(crt
);
633 gnutls_x509_privkey_deinit(key
);