From 9eafdc6d27c292e1beec00f95608ec4ef2cd1fef Mon Sep 17 00:00:00 2001 From: Glade Diviney Date: Thu, 5 Oct 2017 09:31:34 -0700 Subject: Add IPPS support via BoringSSL Fixes: 67460226 Test: Use Default Print Service with an IPPS-only printer Change-Id: I5794906ddf176d62c9727c98417efa2c1ceba7ff Signed-off-by: Glade Diviney --- Android.bp | 3 + config.h | 1 + cups/tls-boringssl.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 587 insertions(+) create mode 100644 cups/tls-boringssl.c diff --git a/Android.bp b/Android.bp index df8d10c3..d2471e56 100644 --- a/Android.bp +++ b/Android.bp @@ -64,6 +64,7 @@ cc_library_shared { "cups/snprintf.c", "cups/string.c", "cups/tempfile.c", + "cups/tls-boringssl.c", "cups/thread.c", "cups/transcode.c", "cups/usersys.c", @@ -97,5 +98,7 @@ cc_library_shared { shared_libs: [ "libz", "liblog", + "libcrypto", + "libssl", ], } diff --git a/config.h b/config.h index ec0f673b..2decf312 100644 --- a/config.h +++ b/config.h @@ -58,5 +58,6 @@ #define HAVE_POLL 1 #define CUPS_RAND() random() #define CUPS_SRAND(v) srandom(v) +#define HAVE_SSL 1 #endif /* !_CUPS_CONFIG_H_ */ diff --git a/cups/tls-boringssl.c b/cups/tls-boringssl.c new file mode 100644 index 00000000..6aec3146 --- /dev/null +++ b/cups/tls-boringssl.c @@ -0,0 +1,583 @@ +/* + * TLS support code for CUPS using Google BoringSSL. + * + * Copyright 2007-2016 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/**** This file is included from tls.c ****/ + +/* + * Local globals... + */ + +#include "cups-private.h" +#include "http.h" +#include "thread-private.h" +#include +#include +#include + +#include + +static char *tls_keypath = NULL; + /* Server cert keychain path */ +static int tls_options = -1;/* Options for TLS connections */ + + +/* + * Local functions... + */ + +static const char *http_bssl_default_path(char *buffer, size_t bufsize); +static const char *http_bssl_make_path(char *buffer, size_t bufsize, const char *dirname, const char *filename, const char *ext); +static BIO_METHOD * _httpBIOMethods(void); +static int http_bio_write(BIO *h, const char *buf, int num); +static int http_bio_read(BIO *h, char *buf, int size); +static int http_bio_puts(BIO *h, const char *str); +static long http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int http_bio_new(BIO *h); +static int http_bio_free(BIO *data); + +static BIO_METHOD http_bio_methods = + { + BIO_TYPE_SSL, + "http", + http_bio_write, + http_bio_read, + http_bio_puts, + NULL, /* http_bio_gets, */ + http_bio_ctrl, + http_bio_new, + http_bio_free, + NULL, + }; + +/* + * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. + * + * @since CUPS 2.0/OS 10.10@ + */ + +int /* O - 1 on success, 0 on failure */ +cupsMakeServerCredentials( + const char *path, /* I - Path to keychain/directory */ + const char *common_name, /* I - Common name */ + int num_alt_names, /* I - Number of subject alternate names */ + const char **alt_names, /* I - Subject Alternate Names */ + time_t expiration_date) /* I - Expiration date */ +{ + int pid, /* Process ID of command */ + status; /* Status of command */ + char command[1024], /* Command */ + *argv[12], /* Command-line arguments */ + *envp[1000], /* Environment variables */ + infofile[1024], /* Type-in information for cert */ + seedfile[1024]; /* Random number seed file */ + int envc, /* Number of environment variables */ + bytes; /* Bytes written */ + cups_file_t *fp; /* Seed/info file */ + int infofd; /* Info file descriptor */ + char temp[1024], /* Temporary directory name */ + crtfile[1024], /* Certificate filename */ + keyfile[1024]; /* Private key filename */ + + 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)); + + return 0; +} + + +/* + * '_httpCreateCredentials()' - Create credentials in the internal format. + */ + +http_tls_credentials_t /* O - Internal credentials */ +_httpCreateCredentials( + cups_array_t *credentials) /* I - Array of credentials */ +{ + (void)credentials; + + return (NULL); +} + + +/* + * '_httpFreeCredentials()' - Free internal credentials. + */ + +void +_httpFreeCredentials( + http_tls_credentials_t credentials) /* I - Internal credentials */ +{ + (void)credentials; +} + + +/* + * 'http_gnutls_default_path()' - Get the default credential store path. + */ + +static const char * /* O - Path or NULL on error */ +http_bssl_default_path(char *buffer,/* I - Path buffer */ + size_t bufsize)/* I - Size of path buffer */ +{ + const char *home = getenv("HOME"); /* HOME environment variable */ + + + if (getuid() && home) + { + snprintf(buffer, bufsize, "%s/.cups", home); + if (access(buffer, 0)) + { + DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer)); + if (mkdir(buffer, 0700)) + { + DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno))); + return (NULL); + } + } + + snprintf(buffer, bufsize, "%s/.cups/ssl", home); + if (access(buffer, 0)) + { + DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer)); + if (mkdir(buffer, 0700)) + { + DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno))); + return (NULL); + } + } + } + else + strlcpy(buffer, CUPS_SERVERROOT "/ssl", bufsize); + + DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer)); + + return (buffer); +} + + +/* + * 'http_gnutls_make_path()' - Format a filename for a certificate or key file. + */ + +static const char * /* O - Filename */ +http_bssl_make_path( + char *buffer, /* I - Filename buffer */ + size_t bufsize, /* I - Size of buffer */ + const char *dirname, /* I - Directory */ + const char *filename, /* I - Filename (usually hostname) */ + const char *ext) /* I - Extension */ +{ + char *bufptr, /* Pointer into buffer */ + *bufend = buffer + bufsize - 1; /* End of buffer */ + + + snprintf(buffer, bufsize, "%s/", dirname); + bufptr = buffer + strlen(buffer); + + while (*filename && bufptr < bufend) + { + if (_cups_isalnum(*filename) || *filename == '-' || *filename == '.') + *bufptr++ = *filename; + else + *bufptr++ = '_'; + + filename ++; + } + + if (bufptr < bufend) + *bufptr++ = '.'; + + strlcpy(bufptr, ext, (size_t)(bufend - bufptr + 1)); + + return (buffer); +} + + +/* + * '_httpBIOMethods()' - Get the OpenSSL BIO methods for HTTP connections. + */ + +static BIO_METHOD * /* O - BIO methods for OpenSSL */ +_httpBIOMethods(void) +{ + return (&http_bio_methods); +} + + +/* + * 'http_bio_ctrl()' - Control the HTTP connection. + */ + +static long /* O - Result/data */ +http_bio_ctrl(BIO *h, /* I - BIO data */ + int cmd, /* I - Control command */ + long arg1, /* I - First argument */ + void *arg2) /* I - Second argument */ +{ + switch (cmd) + { + default : + return (0); + + case BIO_CTRL_RESET : + h->ptr = NULL; + return (0); + + case BIO_C_SET_FILE_PTR : + h->ptr = arg2; + h->init = 1; + return (1); + + case BIO_C_GET_FILE_PTR : + if (arg2) + { + *((void **)arg2) = h->ptr; + return (1); + } + else + return (0); + + case BIO_CTRL_DUP : + case BIO_CTRL_FLUSH : + return (1); + } +} + + +/* + * 'http_bio_free()' - Free OpenSSL data. + */ + +static int /* O - 1 on success, 0 on failure */ +http_bio_free(BIO *h) /* I - BIO data */ +{ + if (!h) + return (0); + + if (h->shutdown) + { + h->init = 0; + h->flags = 0; + } + + return (1); +} + + +/* + * 'http_bio_new()' - Initialize an OpenSSL BIO structure. + */ + +static int /* O - 1 on success, 0 on failure */ +http_bio_new(BIO *h) /* I - BIO data */ +{ + if (!h) + return (0); + + h->init = 0; + h->num = 0; + h->ptr = NULL; + h->flags = 0; + + return (1); +} + + +/* + * 'http_bio_puts()' - Send a string for OpenSSL. + */ + +static int /* O - Bytes written */ +http_bio_puts(BIO *h, /* I - BIO data */ + const char *str) /* I - String to write */ +{ + return (send(((http_t *)h->ptr)->fd, str, strlen(str), 0)); +} + + +/* + * 'http_bio_read()' - Read data for OpenSSL. + */ + +static int /* O - Bytes read */ +http_bio_read(BIO *h, /* I - BIO data */ + char *buf, /* I - Buffer */ + int size) /* I - Number of bytes to read */ +{ + http_t *http; /* HTTP connection */ + + + http = (http_t *)h->ptr; + + if (!http->blocking) + { + /* + * Make sure we have data before we read... + */ + + while (!_httpWait(http, http->wait_value, 0)) + { + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) + continue; + + http->error = ETIMEDOUT; + + return (-1); + } + } + + return (recv(http->fd, buf, size, 0)); +} + + +/* + * 'http_bio_write()' - Write data for OpenSSL. + */ + +static int /* O - Bytes written */ +http_bio_write(BIO *h, /* I - BIO data */ + const char *buf, /* I - Buffer to write */ + int num) /* I - Number of bytes to write */ +{ + return (send(((http_t *)h->ptr)->fd, buf, num, 0)); +} + + +/* + * '_httpTLSInitialize()' - Initialize the TLS stack. + */ + +void +_httpTLSInitialize(void) +{ + int i; /* Looping var */ + unsigned char data[1024]; /* Seed data */ + + /* + * Initialize OpenSSL... + */ + + SSL_load_error_strings(); + SSL_library_init(); + + /* + * Using the current time is a dubious random seed, but on some systems + * it is the best we can do (on others, this seed isn't even used...) + */ + + CUPS_SRAND(time(NULL)); + + for (i = 0; i < sizeof(data); i ++) + data[i] = CUPS_RAND(); + + RAND_seed(data, sizeof(data)); +} + + +/* + * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. + */ + +size_t /* O - Bytes available */ +_httpTLSPending(http_t *http) /* I - HTTP connection */ +{ + return (SSL_pending(http->tls)); +} + + +/* + * '_httpTLSRead()' - Read from a SSL/TLS connection. + */ + +int /* O - Bytes read */ +_httpTLSRead(http_t *http, /* I - Connection to server */ + char *buf, /* I - Buffer to store data */ + int len) /* I - Length of buffer */ +{ + return (SSL_read((SSL *)(http->tls), buf, len)); +} + + +/* + * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options. + */ + +void +_httpTLSSetOptions(int options) /* I - Options */ +{ + tls_options = options; +} + + +/* + * '_httpTLSStart()' - Set up SSL/TLS support on a connection. + */ + +int /* O - 0 on success, -1 on failure */ +_httpTLSStart(http_t *http) /* I - Connection to server */ +{ + char hostname[256], /* Hostname */ + *hostptr; /* Pointer into hostname */ + + SSL_CTX *context; /* Context for encryption */ + BIO *bio; /* BIO data */ + const char *message = NULL;/* Error message */ + + DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http)); + + if (tls_options < 0) + { + DEBUG_puts("4_httpTLSStart: Setting defaults."); + _cupsSetDefaults(); + DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); + } + + if (http->mode == _HTTP_MODE_SERVER && !tls_keypath) + { + DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); + http->error = errno = EINVAL; + http->status = HTTP_STATUS_ERROR; + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); + + return (-1); + } + + if (tls_options & _HTTP_TLS_DENY_TLS10) + context = SSL_CTX_new(http->mode == _HTTP_MODE_CLIENT ? TLSv1_1_client_method() : TLSv1_1_server_method()); + else if (tls_options & _HTTP_TLS_ALLOW_SSL3) + context = SSL_CTX_new(http->mode == _HTTP_MODE_CLIENT ? SSLv3_client_method() : SSLv3_server_method()); + else + context = SSL_CTX_new(http->mode == _HTTP_MODE_CLIENT ? TLSv1_client_method() : TLSv1_server_method()); + + bio = BIO_new(_httpBIOMethods()); + BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http); + + http->tls = SSL_new(context); + SSL_set_bio(http->tls, bio, bio); + + if (http->mode == _HTTP_MODE_CLIENT) + { + /* + * Client: get the hostname to use for TLS... + */ + + if (httpAddrLocalhost(http->hostaddr)) + { + strlcpy(hostname, "localhost", sizeof(hostname)); + } + else + { + /* + * Otherwise make sure the hostname we have does not end in a trailing dot. + */ + + strlcpy(hostname, http->hostname, sizeof(hostname)); + if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && + *hostptr == '.') + *hostptr = '\0'; + } +# ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME + SSL_set_tlsext_host_name(http->tls, hostname); +# endif /* HAVE_SSL_SET_TLSEXT_HOST_NAME */ + + } + else + { +/* @@@ TODO @@@ */ +// SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM); +// SSL_CTX_use_certificate_chain_file(context, ServerCertificate); + } + + + if (http->mode == _HTTP_MODE_CLIENT ? SSL_connect(http->tls) != 1 :SSL_connect(http->tls) != 1) + { + unsigned long error; /* Error code */ + + while ((error = ERR_get_error()) != 0) + { + message = ERR_error_string(error, NULL); + DEBUG_printf(("8http_setup_ssl: %s", message)); + } + + SSL_CTX_free(context); + SSL_free(http->tls); + http->tls = NULL; + + http->error = errno; + http->status = HTTP_STATUS_ERROR; + + if (!message) + message = _("Unable to establish a secure connection to host."); + + _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); + + return (-1); + } + + return (0); +} + + +/* + * '_httpTLSStop()' - Shut down SSL/TLS on a connection. + */ + +void +_httpTLSStop(http_t *http) /* I - Connection to server */ +{ + SSL_CTX *context; /* Context for encryption */ + unsigned long error; /* Error code */ + + context = SSL_get_SSL_CTX(http->tls); + + switch (SSL_shutdown(http->tls)) + { + case 1 : + break; + + case -1 : + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, + "Fatal error during SSL shutdown!", 0); + default : + while ((error = ERR_get_error()) != 0) + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, + ERR_error_string(error, NULL), 0); + break; + } + + SSL_CTX_free(context); + SSL_free(http->tls); + http->tls = NULL; +} + +/* + * '_httpTLSWrite()' - Write to a SSL/TLS connection. + */ + +int /* O - Bytes written */ +_httpTLSWrite(http_t *http, /* I - Connection to server */ + const char *buf, /* I - Buffer holding data */ + int len) /* I - Length of buffer */ +{ + ssize_t result; /* Return value */ + + + DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len)); + + result = SSL_write((SSL *)(http->tls), buf, len); + + DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); + + return ((int)result); +} -- cgit v1.2.3