From 2ece34a9f86695f0a0a60813f1dae57ad4acd2f0 Mon Sep 17 00:00:00 2001 From: msweet Date: Tue, 15 Jul 2014 18:59:26 +0000 Subject: [PATCH] Initial work on SSPI support in 2.0. git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@12029 a1ca3aef-8c08-0410-bb20-df032aa958be --- cups/http-private.h | 27 +- cups/tls-darwin.c | 31 +- cups/tls-sspi.c | 2886 ++++++++++++-------------- scheduler/tls-darwin.c | 570 ----- scheduler/tls-gnutls.c | 292 --- xcode/CUPS.xcodeproj/project.pbxproj | 4 - 6 files changed, 1340 insertions(+), 2470 deletions(-) delete mode 100644 scheduler/tls-darwin.c delete mode 100644 scheduler/tls-gnutls.c diff --git a/cups/http-private.h b/cups/http-private.h index 693e4cf81..e1b5d4a19 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -117,7 +117,12 @@ extern CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) # include # endif /* HAVE_SECPOLICYPRIV_H */ # elif defined(HAVE_SSPISSL) -# include "sspi-private.h" +# include +# include +# include +# define SECURITY_WIN32 +# include +# include # endif /* HAVE_GNUTLS */ # ifndef WIN32 @@ -203,7 +208,25 @@ typedef CFArrayRef http_tls_credentials_t; * Windows' SSPI library gets a CUPS wrapper... */ -typedef _sspi_struct_t * http_tls_t; +typedef struct _http_sspi_s /**** SSPI/SSL data structure ****/ +{ + CredHandle creds; /* Credentials */ + CtxtHandle context; /* SSL context */ + BOOL contextInitialized; /* Is context init'd? */ + SecPkgContext_StreamSizes streamSizes;/* SSL data stream sizes */ + BYTE *decryptBuffer; /* Data pre-decryption*/ + size_t decryptBufferLength; /* Length of decrypt buffer */ + size_t decryptBufferUsed; /* Bytes used in buffer */ + BYTE *readBuffer; /* Data post-decryption */ + int readBufferLength; /* Length of read buffer */ + int readBufferUsed; /* Bytes used in buffer */ + BYTE *writeBuffer; /* Data pre-encryption */ + int writeBufferLength; /* Length of write buffer */ + DWORD certFlags; /* Cert verification flags */ + PCCERT_CONTEXT localCert, /* Local certificate */ + remoteCert; /* Remote (peer's) certificate */ +} _http_sspi_t; +typedef _http_sspi_t *http_tls_t; typedef void *http_tls_credentials_t; # else diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c index 7daa291d2..fc2028523 100644 --- a/cups/tls-darwin.c +++ b/cups/tls-darwin.c @@ -51,6 +51,7 @@ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; #ifdef HAVE_SECKEYCHAINOPEN static CFArrayRef http_cdsa_copy_server(const char *common_name); #endif /* HAVE_SECKEYCHAINOPEN */ +static SecCertificateRef http_cdsa_create_credential(http_credential_t *credential); static const char *http_cdsa_default_path(char *buffer, size_t bufsize); static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength); static int http_cdsa_set_credentials(http_t *http); @@ -412,21 +413,6 @@ httpCopyCredentials( } -/* - * 'http_cdsa_create_credential()' - Create a single credential in the internal format. - */ - -static SecCertificateRef /* O - Certificate */ -http_cdsa_create_credential( - http_credential_t *credential) /* I - Credential */ -{ - if (!credential) - return (NULL); - - return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)); -} - - /* * '_httpCreateCredentials()' - Create credentials in the internal format. */ @@ -1491,6 +1477,21 @@ http_cdsa_copy_server( #endif /* HAVE_SECKEYCHAINOPEN */ +/* + * 'http_cdsa_create_credential()' - Create a single credential in the internal format. + */ + +static SecCertificateRef /* O - Certificate */ +http_cdsa_create_credential( + http_credential_t *credential) /* I - Credential */ +{ + if (!credential) + return (NULL); + + return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)); +} + + /* * 'http_cdsa_default_path()' - Get the default keychain path. */ diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c index 00242f9e9..0f08c5a86 100644 --- a/cups/tls-sspi.c +++ b/cups/tls-sspi.c @@ -3,7 +3,7 @@ * * TLS support for CUPS on Windows using SSPI. * - * Copyright 2010-2013 by Apple Inc. + * Copyright 2010-2014 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -18,1060 +18,1013 @@ * Include necessary headers... */ -#include "sspi-private.h" #include "debug-private.h" -/* required to link this library for certificate functions */ +/* + * Include necessary libraries... + */ + #pragma comment(lib, "Crypt32.lib") #pragma comment(lib, "Secur32.lib") #pragma comment(lib, "Ws2_32.lib") -#if !defined(SECURITY_FLAG_IGNORE_UNKNOWN_CA) +/* + * Constants... + */ + +#ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA # define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */ -#endif +#endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */ -#if !defined(SECURITY_FLAG_IGNORE_CERT_DATE_INVALID) +#ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID # define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */ -#endif +#endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */ + +/* + * Local functions... + */ -static DWORD sspi_verify_certificate(PCCERT_CONTEXT serverCert, - const CHAR *serverName, - DWORD dwCertFlags); +static _http_sspi_t *http_sspi_alloc(void); +static int http_sspi_client(http_t *http, const char *hostname); +static void http_sspi_free(_http_sspi_t *conn); +static BOOL http_sspi_get_credentials(_http_sspi_t *conn, const LPWSTR containerName, const TCHAR *commonName, BOOL server); +static int http_sspi_server(http_t *http, const char *hostname); +static void http_sspi_set_allows_any_root(_http_sspi_t *conn, BOOL allow); +static void http_sspi_set_allows_expired_certs(_http_sspi_t *conn, BOOL allow); +static DWORD http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags); /* - * 'http_tls_initialize()' - Initialize the TLS stack. + * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. + * + * @since CUPS 2.0@ */ -static void -http_tls_initialize(void) +int /* O - 1 on success, 0 on failure */ +cupsMakeServerCredentials( + const char *path, /* I - Keychain path or @code NULL@ for default */ + 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 */ { -#ifdef HAVE_GNUTLS - /* - * Initialize GNU TLS... - */ + 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)); - gnutls_global_init(); + (void)path; + (void)common_name; + (void)num_alt_names; + (void)alt_names; + (void)expiration_date; -#elif defined(HAVE_LIBSSL) - /* - * Initialize OpenSSL... - */ + return (0); +} - 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...) - */ +/* + * 'cupsSetServerCredentials()' - Set the default server credentials. + * + * Note: The server credentials are used by all threads in the running process. + * This function is threadsafe. + * + * @since CUPS 2.0@ + */ - CUPS_SRAND(time(NULL)); +int /* O - 1 on success, 0 on failure */ +cupsSetServerCredentials( + const char *path, /* I - Keychain path or @code NULL@ for default */ + const char *common_name, /* I - Default common name for server */ + int auto_create) /* I - 1 = automatically create self-signed certificates */ +{ + DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); - for (i = 0; i < sizeof(data); i ++) - data[i] = CUPS_RAND(); + (void)path; + (void)common_name; + (void)auto_create; - RAND_seed(data, sizeof(data)); -#endif /* HAVE_GNUTLS */ + return (0); } -#ifdef HAVE_SSL /* - * 'http_tls_read()' - Read from a SSL/TLS connection. + * 'httpCopyCredentials()' - Copy the credentials associated with the peer in + * an encrypted connection. + * + * @since CUPS 1.5/OS X 10.7@ */ -static int /* O - Bytes read */ -http_tls_read(http_t *http, /* I - Connection to server */ - char *buf, /* I - Buffer to store data */ - int len) /* I - Length of buffer */ +int /* O - Status of call (0 = success) */ +httpCopyCredentials( + http_t *http, /* I - Connection to server */ + cups_array_t **credentials) /* O - Array of credentials */ { -# if defined(HAVE_LIBSSL) - return (SSL_read((SSL *)(http->tls), buf, len)); - -# elif defined(HAVE_GNUTLS) - ssize_t result; /* Return value */ - - - result = gnutls_record_recv(http->tls, buf, len); - - if (result < 0 && !errno) - { - /* - * Convert GNU TLS error to errno value... - */ + DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials)); - switch (result) - { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; + (void)http; - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; + if (credentials) + *credentials = NULL; - default : - errno = EPIPE; - break; - } + return (-1); +} - result = -1; - } - return ((int)result); +/* + * '_httpCreateCredentials()' - Create credentials in the internal format. + */ -# elif defined(HAVE_CDSASSL) - int result; /* Return value */ - OSStatus error; /* Error info */ - size_t processed; /* Number of bytes processed */ +http_tls_credentials_t /* O - Internal credentials */ +_httpCreateCredentials( + cups_array_t *credentials) /* I - Array of credentials */ +{ + (void)credentials; + return (NULL); +} - error = SSLRead(http->tls, buf, len, &processed); - DEBUG_printf(("6http_tls_read: error=%d, processed=%d", (int)error, - (int)processed)); - switch (error) - { - case 0 : - result = (int)processed; - break; - - case errSSLWouldBlock : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EINTR; - } - break; - case errSSLClosedGraceful : - default : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EPIPE; - } - break; - } +/* + * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. + * + * @since CUPS 2.0@ + */ - return (result); +int /* O - 1 if valid, 0 otherwise */ +httpCredentialsAreValidForName( + cups_array_t *credentials, /* I - Credentials */ + const char *common_name) /* I - Name to check */ +{ + (void)credentials; + (void)common_name; -# elif defined(HAVE_SSPISSL) - return _sspiRead((_sspi_struct_t*) http->tls, buf, len); -# endif /* HAVE_LIBSSL */ + return (1); } -#endif /* HAVE_SSL */ -#ifdef HAVE_SSL /* - * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. + * 'httpCredentialsGetTrust()' - Return the trust of credentials. + * + * @since CUPS 2.0@ */ -static int /* O - 0 on success, -1 on failure */ -http_setup_ssl(http_t *http) /* I - Connection to server */ +http_trust_t /* O - Level of trust */ +httpCredentialsGetTrust( + cups_array_t *credentials, /* I - Credentials */ + const char *common_name) /* I - Common name for trust lookup */ { - char hostname[256], /* Hostname */ - *hostptr; /* Pointer into hostname */ - -# ifdef HAVE_LIBSSL - SSL_CTX *context; /* Context for encryption */ - BIO *bio; /* BIO data */ - const char *message = NULL;/* Error message */ -# elif defined(HAVE_GNUTLS) - int status; /* Status of handshake */ - gnutls_certificate_client_credentials *credentials; - /* TLS credentials */ -# elif defined(HAVE_CDSASSL) + http_trust_t trust = HTTP_TRUST_OK; + /* Trusted? */ + cups_array_t *tcreds = NULL; /* Trusted credentials */ _cups_globals_t *cg = _cupsGlobals(); - /* Pointer to library globals */ - OSStatus error; /* Error code */ - const char *message = NULL;/* Error message */ - cups_array_t *credentials; /* Credentials array */ - cups_array_t *names; /* CUPS distinguished names */ - CFArrayRef dn_array; /* CF distinguished names array */ - CFIndex count; /* Number of credentials */ - CFDataRef data; /* Certificate data */ - int i; /* Looping var */ - http_credential_t *credential; /* Credential data */ -# elif defined(HAVE_SSPISSL) - TCHAR username[256]; /* Username returned from GetUserName() */ - TCHAR commonName[256];/* Common name for certificate */ - DWORD dwSize; /* 32 bit size */ -# endif /* HAVE_LIBSSL */ + /* Per-thread globals */ - DEBUG_printf(("7http_setup_ssl(http=%p)", http)); + if (!common_name) + return (HTTP_TRUST_UNKNOWN); /* - * Get the hostname to use for SSL... + * Look this common name up in the default keychains... */ - 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_LIBSSL - context = SSL_CTX_new(SSLv23_client_method()); - - SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */ + httpLoadCredentials(NULL, &tcreds, common_name); - 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); - -# ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME - SSL_set_tlsext_host_name(http->tls, hostname); -# endif /* HAVE_SSL_SET_TLSEXT_HOST_NAME */ - - if (SSL_connect(http->tls) != 1) + if (tcreds) { - unsigned long error; /* Error code */ + char credentials_str[1024], /* String for incoming credentials */ + tcreds_str[1024]; /* String for saved credentials */ + + httpCredentialsString(credentials, credentials_str, sizeof(credentials_str)); + httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str)); - while ((error = ERR_get_error()) != 0) + if (strcmp(credentials_str, tcreds_str)) { - message = ERR_error_string(error, NULL); - DEBUG_printf(("8http_setup_ssl: %s", message)); - } + /* + * Credentials don't match, let's look at the expiration date of the new + * credentials and allow if the new ones have a later expiration... + */ - SSL_CTX_free(context); - SSL_free(http->tls); - http->tls = NULL; + if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds) || + !httpCredentialsAreValidForName(credentials, common_name)) + { + /* + * Either the new credentials are not newly issued, or the common name + * does not match the issued certificate... + */ -# ifdef WIN32 - http->error = WSAGetLastError(); -# else - http->error = errno; -# endif /* WIN32 */ - http->status = HTTP_STATUS_ERROR; + trust = HTTP_TRUST_INVALID; + } + else if (httpCredentialsGetExpiration(tcreds) < time(NULL)) + { + /* + * Save the renewed credentials... + */ - if (!message) - message = _("Unable to establish a secure connection to host."); + trust = HTTP_TRUST_RENEWED; - _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); + httpSaveCredentials(NULL, credentials, common_name); + } + } - return (-1); + httpFreeCredentials(tcreds); } + else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name)) + trust = HTTP_TRUST_INVALID; -# elif defined(HAVE_GNUTLS) - credentials = (gnutls_certificate_client_credentials *) - malloc(sizeof(gnutls_certificate_client_credentials)); - if (credentials == NULL) - { - DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s", - strerror(errno))); - http->error = errno; - http->status = HTTP_STATUS_ERROR; - _cupsSetHTTPError(HTTP_STATUS_ERROR); - - return (-1); - } + if (!cg->expired_certs && time(NULL) > httpCredentialsGetExpiration(credentials)) + trust = HTTP_TRUST_EXPIRED; + else if (!cg->any_root && cupsArrayCount(credentials) == 1) + trust = HTTP_TRUST_INVALID; - gnutls_certificate_allocate_credentials(credentials); + return (trust); +} - gnutls_init(&http->tls, GNUTLS_CLIENT); - gnutls_set_default_priority(http->tls); - gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, - strlen(hostname)); - gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials); - gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr)http); - gnutls_transport_set_pull_function(http->tls, _httpReadGNUTLS); - gnutls_transport_set_push_function(http->tls, _httpWriteGNUTLS); - while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS) - { - DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)", - status, gnutls_strerror(status))); +/* + * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. + * + * @since CUPS 2.0@ + */ - if (gnutls_error_is_fatal(status)) - { - http->error = EIO; - http->status = HTTP_STATUS_ERROR; +time_t /* O - Expiration date of credentials */ +httpCredentialsGetExpiration( + cups_array_t *credentials) /* I - Credentials */ +{ + (void)credentials; - _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); + return (INT_MAX); +} - gnutls_deinit(http->tls); - gnutls_certificate_free_credentials(*credentials); - free(credentials); - http->tls = NULL; - return (-1); - } - } +/* + * 'httpCredentialsString()' - Return a string representing the credentials. + * + * @since CUPS 2.0@ + */ - http->tls_credentials = credentials; +size_t /* O - Total size of credentials string */ +httpCredentialsString( + cups_array_t *credentials, /* I - Credentials */ + char *buffer, /* I - Buffer or @code NULL@ */ + size_t bufsize) /* I - Size of buffer */ +{ + DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize)); -# elif defined(HAVE_CDSASSL) - if ((http->tls = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, - kSSLStreamType)) == NULL) - { - DEBUG_puts("4http_setup_ssl: SSLCreateContext failed."); - http->error = errno = ENOMEM; - http->status = HTTP_STATUS_ERROR; - _cupsSetHTTPError(HTTP_STATUS_ERROR); + if (!buffer) + return (0); - return (-1); - } + if (buffer && bufsize > 0) + *buffer = '\0'; - error = SSLSetConnection(http->tls, http); - DEBUG_printf(("4http_setup_ssl: SSLSetConnection, error=%d", (int)error)); +#if 0 + http_credential_t *first; /* First certificate */ + SecCertificateRef secCert; /* Certificate reference */ - if (!error) - { - error = SSLSetIOFuncs(http->tls, _httpReadCDSA, _httpWriteCDSA); - DEBUG_printf(("4http_setup_ssl: SSLSetIOFuncs, error=%d", (int)error)); - } - if (!error) + if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL && + (secCert = http_cdsa_create_credential(first)) != NULL) { - error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth, - true); - DEBUG_printf(("4http_setup_ssl: SSLSetSessionOption, error=%d", - (int)error)); - } + CFStringRef cf_name; /* CF common name string */ + char name[256]; /* Common name associated with cert */ + time_t expiration; /* Expiration date of cert */ + _cups_md5_state_t md5_state; /* MD5 state */ + unsigned char md5_digest[16]; /* MD5 result */ - if (!error) - { - if (cg->client_cert_cb) + if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL) { - error = SSLSetSessionOption(http->tls, - kSSLSessionOptionBreakOnCertRequested, true); - DEBUG_printf(("4http_setup_ssl: kSSLSessionOptionBreakOnCertRequested, " - "error=%d", (int)error)); + CFStringGetCString(cf_name, name, (CFIndex)sizeof(name), kCFStringEncodingUTF8); + CFRelease(cf_name); } else - { - error = http_set_credentials(http); - DEBUG_printf(("4http_setup_ssl: http_set_credentials, error=%d", - (int)error)); - } - } - - /* - * Let the server know which hostname/domain we are trying to connect to - * in case it wants to serve up a certificate with a matching common name. - */ - - if (!error) - { - error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname)); + strlcpy(name, "unknown", sizeof(name)); - DEBUG_printf(("4http_setup_ssl: SSLSetPeerDomainName, error=%d", - (int)error)); - } - - if (!error) - { - int done = 0; /* Are we done yet? */ + expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); - while (!error && !done) - { - error = SSLHandshake(http->tls); + _cupsMD5Init(&md5_state); + _cupsMD5Append(&md5_state, first->data, (int)first->datalen); + _cupsMD5Finish(&md5_state, md5_digest); - DEBUG_printf(("4http_setup_ssl: SSLHandshake returned %d.", (int)error)); + snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); - switch (error) - { - case noErr : - done = 1; - break; - - case errSSLWouldBlock : - error = noErr; /* Force a retry */ - usleep(1000); /* in 1 millisecond */ - break; - - case errSSLServerAuthCompleted : - error = 0; - if (cg->server_cert_cb) - { - error = httpCopyCredentials(http, &credentials); - if (!error) - { - error = (cg->server_cert_cb)(http, http->tls, credentials, - cg->server_cert_data); - httpFreeCredentials(credentials); - } - - DEBUG_printf(("4http_setup_ssl: Server certificate callback " - "returned %d.", (int)error)); - } - break; - - case errSSLClientCertRequested : - error = 0; - - if (cg->client_cert_cb) - { - names = NULL; - if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) && - dn_array) - { - if ((names = cupsArrayNew(NULL, NULL)) != NULL) - { - for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++) - { - data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i); - - if ((credential = malloc(sizeof(*credential))) != NULL) - { - credential->datalen = CFDataGetLength(data); - if ((credential->data = malloc(credential->datalen))) - { - memcpy((void *)credential->data, CFDataGetBytePtr(data), - credential->datalen); - cupsArrayAdd(names, credential); - } - else - free(credential); - } - } - } - - CFRelease(dn_array); - } - - if (!error) - { - error = (cg->client_cert_cb)(http, http->tls, names, - cg->client_cert_data); - - DEBUG_printf(("4http_setup_ssl: Client certificate callback " - "returned %d.", (int)error)); - } - - httpFreeCredentials(names); - } - break; - - case errSSLUnknownRootCert : - message = _("Unable to establish a secure connection to host " - "(untrusted certificate)."); - break; - - case errSSLNoRootCert : - message = _("Unable to establish a secure connection to host " - "(self-signed certificate)."); - break; - - case errSSLCertExpired : - message = _("Unable to establish a secure connection to host " - "(expired certificate)."); - break; - - case errSSLCertNotYetValid : - message = _("Unable to establish a secure connection to host " - "(certificate not yet valid)."); - break; - - case errSSLHostNameMismatch : - message = _("Unable to establish a secure connection to host " - "(host name mismatch)."); - break; - - case errSSLXCertChainInvalid : - message = _("Unable to establish a secure connection to host " - "(certificate chain invalid)."); - break; - - case errSSLConnectionRefused : - message = _("Unable to establish a secure connection to host " - "(peer dropped connection before responding)."); - break; - - default : - break; - } - } + CFRelease(secCert); } +#endif /* 0 */ - if (error) - { - http->error = error; - http->status = HTTP_STATUS_ERROR; - errno = ECONNREFUSED; - - CFRelease(http->tls); - http->tls = NULL; - - /* - * If an error string wasn't set by the callbacks use a generic one... - */ + DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); - if (!message) -#ifdef HAVE_CSSMERRORSTRING - message = cssmErrorString(error); -#else - message = _("Unable to establish a secure connection to host."); -#endif /* HAVE_CSSMERRORSTRING */ + return (strlen(buffer)); +} - _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); - return (-1); - } +/* + * '_httpFreeCredentials()' - Free internal credentials. + */ -# elif defined(HAVE_SSPISSL) - http->tls = _sspiAlloc(); +void +_httpFreeCredentials( + http_tls_credentials_t credentials) /* I - Internal credentials */ +{ + if (!credentials) + return; +} - if (!http->tls) - { - _cupsSetHTTPError(HTTP_STATUS_ERROR); - return (-1); - } - http->tls->sock = http->fd; - dwSize = sizeof(username) / sizeof(TCHAR); - GetUserName(username, &dwSize); - _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR), - sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username); +/* + * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. + * + * @since CUPS 2.0@ + */ - if (!_sspiGetCredentials(http->tls, L"ClientContainer", - commonName, FALSE)) - { - _sspiFree(http->tls); - http->tls = NULL; +int /* O - 0 on success, -1 on error */ +httpLoadCredentials( + const char *path, /* I - Keychain path or @code NULL@ for default */ + cups_array_t **credentials, /* IO - Credentials */ + const char *common_name) /* I - Common name for credentials */ +{ + DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); - http->error = EIO; - http->status = HTTP_STATUS_ERROR; + (void)path; + (void)common_name; - _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, - _("Unable to establish a secure connection to host."), 1); + if (credentials) + *credentials = NULL; - return (-1); - } + DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1)); - _sspiSetAllowsAnyRoot(http->tls, TRUE); - _sspiSetAllowsExpiredCerts(http->tls, TRUE); + return (*credentials ? 0 : -1); +} - if (!_sspiConnect(http->tls, hostname)) - { - _sspiFree(http->tls); - http->tls = NULL; - http->error = EIO; - http->status = HTTP_STATUS_ERROR; +/* + * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. + * + * @since CUPS 2.0@ + */ - _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, - _("Unable to establish a secure connection to host."), 1); +int /* O - -1 on error, 0 on success */ +httpSaveCredentials( + const char *path, /* I - Keychain path or @code NULL@ for default */ + cups_array_t *credentials, /* I - Credentials */ + const char *common_name) /* I - Common name for credentials */ +{ + DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); - return (-1); - } -# endif /* HAVE_CDSASSL */ + (void)path; + (void)credentials; + (void)common_name; - return (0); + DEBUG_printf(("1httpSaveCredentials: Returning %d.", -1)); + return (-1); } /* - * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection. + * '_httpTLSInitialize()' - Initialize the TLS stack. */ -static void -http_shutdown_ssl(http_t *http) /* I - Connection to server */ +void +_httpTLSInitialize(void) { -# ifdef HAVE_LIBSSL - SSL_CTX *context; /* Context for encryption */ - - context = SSL_get_SSL_CTX(http->tls); - - SSL_shutdown(http->tls); - SSL_CTX_free(context); - SSL_free(http->tls); + /* + * Nothing to do... + */ +} -# elif defined(HAVE_GNUTLS) - gnutls_certificate_client_credentials *credentials; - /* TLS credentials */ - credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials); +/* + * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. + */ - gnutls_bye(http->tls, GNUTLS_SHUT_RDWR); - gnutls_deinit(http->tls); - gnutls_certificate_free_credentials(*credentials); - free(credentials); +size_t /* O - Bytes available */ +_httpTLSPending(http_t *http) /* I - HTTP connection */ +{ + if (http->tls) + return (http->tls->readBufferUsed); + else + return (0); +} -# elif defined(HAVE_CDSASSL) - while (SSLClose(http->tls) == errSSLWouldBlock) - usleep(1000); - CFRelease(http->tls); +/* + * '_httpTLSRead()' - Read from a SSL/TLS connection. + */ - if (http->tls_credentials) - CFRelease(http->tls_credentials); +int /* O - Bytes read */ +_httpTLSRead(http_t *http, /* I - HTTP connection */ + char *buf, /* I - Buffer to store data */ + int len) /* I - Length of buffer */ +{ + int i; /* Looping var */ + _http_sspi_t *conn = http->tls; /* SSPI data */ + SecBufferDesc message; /* Array of SecBuffer struct */ + SecBuffer buffers[4] = { 0 }; /* Security package buffer */ + int num = 0; /* Return value */ + PSecBuffer pDataBuffer; /* Data buffer */ + PSecBuffer pExtraBuffer; /* Excess data buffer */ + SECURITY_STATUS scRet; /* SSPI status */ -# elif defined(HAVE_SSPISSL) - _sspiFree(http->tls); -# endif /* HAVE_LIBSSL */ - http->tls = NULL; - http->tls_credentials = NULL; -} -#endif /* HAVE_SSL */ + if (!conn) + { + WSASetLastError(WSAEINVAL); + return (-1); + } + /* + * If there are bytes that have already been decrypted and have not yet been + * read, return those... + */ -#ifdef HAVE_SSL -/* - * 'http_write_ssl()' - Write to a SSL/TLS connection. - */ + if (conn->readBufferUsed > 0) + { + int bytesToCopy = min(conn->readBufferUsed, len); + /* Number of bytes to copy */ -static int /* O - Bytes written */ -http_write_ssl(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 */ + memcpy(buf, conn->readBuffer, bytesToCopy); + conn->readBufferUsed -= bytesToCopy; + if (conn->readBufferUsed > 0) + memmove(conn->readBuffer, conn->readBuffer + bytesToCopy, conn->readBufferUsed); - DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len)); + return (bytesToCopy); + } -# if defined(HAVE_LIBSSL) - result = SSL_write((SSL *)(http->tls), buf, len); + /* + * Initialize security buffer structs + */ -# elif defined(HAVE_GNUTLS) - result = gnutls_record_send(http->tls, buf, len); + message.ulVersion = SECBUFFER_VERSION; + message.cBuffers = 4; + message.pBuffers = buffers; - if (result < 0 && !errno) + do { /* - * Convert GNU TLS error to errno value... + * If there is not enough space in the buffer, then increase its size... */ - switch (result) + if (conn->decryptBufferLength <= conn->decryptBufferUsed) { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; + BYTE *temp; /* New buffer */ - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; - - default : - errno = EPIPE; - break; - } + if (conn->decryptBufferLength >= 262144) + { + WSASetLastError(E_OUTOFMEMORY); + DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)"); + return (-1); + } - result = -1; - } + if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL) + { + DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096)); + WSASetLastError(E_OUTOFMEMORY); + return (-1); + } -# elif defined(HAVE_CDSASSL) - OSStatus error; /* Error info */ - size_t processed; /* Number of bytes processed */ + conn->decryptBufferLength += 4096; + conn->decryptBuffer = temp; + } + buffers[0].pvBuffer = conn->decryptBuffer; + buffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; + buffers[0].BufferType = SECBUFFER_DATA; + buffers[1].BufferType = SECBUFFER_EMPTY; + buffers[2].BufferType = SECBUFFER_EMPTY; + buffers[3].BufferType = SECBUFFER_EMPTY; - error = SSLWrite(http->tls, buf, len, &processed); + scRet = DecryptMessage(&conn->context, &message, 0, NULL); - switch (error) - { - case 0 : - result = (int)processed; - break; - - case errSSLWouldBlock : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EINTR; - } - break; + if (scRet == SEC_E_INCOMPLETE_MESSAGE) + { + num = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0); + if (num < 0) + { + DEBUG_printf(("_httpTLSRead: recv failed: %d", WSAGetLastError())); + return (-1); + } + else if (num == 0) + { + DEBUG_puts("_httpTLSRead: Server disconnected."); + return (0); + } - case errSSLClosedGraceful : - default : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EPIPE; - } - break; + conn->decryptBufferUsed += num; + } } -# elif defined(HAVE_SSPISSL) - return _sspiWrite((_sspi_struct_t *)http->tls, (void *)buf, len); -# endif /* HAVE_LIBSSL */ - - DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); - - return ((int)result); -} -#endif /* HAVE_SSL */ + while (scRet == SEC_E_INCOMPLETE_MESSAGE); + if (scRet == SEC_I_CONTEXT_EXPIRED) + { + DEBUG_puts("_httpTLSRead: Context expired."); + WSASetLastError(WSAECONNRESET); + return (-1); + } + else if (scRet != SEC_E_OK) + { + DEBUG_printf(("_httpTLSRead: DecryptMessage failed: %lx", scRet)); + WSASetLastError(WSASYSCALLFAILURE); + return (-1); + } -#ifdef HAVE_SSL -/* - * 'http_write_ssl()' - Write to a SSL/TLS connection. - */ + /* + * The decryption worked. Now, locate data buffer. + */ -static int /* O - Bytes written */ -http_write_ssl(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 */ + pDataBuffer = NULL; + pExtraBuffer = NULL; + for (i = 1; i < 4; i++) + { + if (buffers[i].BufferType == SECBUFFER_DATA) + pDataBuffer = &buffers[i]; + else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA)) + pExtraBuffer = &buffers[i]; + } - DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len)); + /* + * If a data buffer is found, then copy the decrypted bytes to the passed-in + * buffer... + */ -# if defined(HAVE_LIBSSL) - result = SSL_write((SSL *)(http->tls), buf, len); + if (pDataBuffer) + { + int bytesToCopy = min(pDataBuffer->cbBuffer, len); + /* Number of bytes to copy into buf */ + int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy; + /* Number of bytes to save in our read buffer */ -# elif defined(HAVE_GNUTLS) - result = gnutls_record_send(http->tls, buf, len); + if (bytesToCopy) + memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy); - if (result < 0 && !errno) - { /* - * Convert GNU TLS error to errno value... + * If there are more decrypted bytes than can be copied to the passed in + * buffer, then save them... */ - switch (result) + if (bytesToSave) { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; + if ((conn->readBufferLength - conn->readBufferUsed) < bytesToSave) + { + BYTE *temp; /* New buffer pointer */ - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; + if ((temp = realloc(conn->readBuffer, conn->readBufferUsed + bytesToSave)) == NULL) + { + DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", conn->readBufferUsed + bytesToSave)); + WSASetLastError(E_OUTOFMEMORY); + return (-1); + } - default : - errno = EPIPE; - break; - } + conn->readBufferLength = conn->readBufferUsed + bytesToSave; + conn->readBuffer = temp; + } - result = -1; - } + memcpy(((BYTE *)conn->readBuffer) + conn->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave); -# elif defined(HAVE_CDSASSL) - OSStatus error; /* Error info */ - size_t processed; /* Number of bytes processed */ + conn->readBufferUsed += bytesToSave; + } + return (bytesToCopy); + } + else + { + DEBUG_puts("_httpTLSRead: Unable to find data buffer.")); + WSASetLastError(WSASYSCALLFAILURE); + return (-1); + } - error = SSLWrite(http->tls, buf, len, &processed); + /* + * If the decryption process left extra bytes, then save those back in + * decryptBuffer. They will be processed the next time through the loop. + */ - switch (error) + if (pExtraBuffer) { - case 0 : - result = (int)processed; - break; - - case errSSLWouldBlock : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EINTR; - } - break; - - case errSSLClosedGraceful : - default : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EPIPE; - } - break; + memmove(conn->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer); + conn->decryptBufferUsed = pExtraBuffer->cbBuffer; + } + else + { + conn->decryptBufferUsed = 0; } -# elif defined(HAVE_SSPISSL) - return _sspiWrite((_sspi_struct_t *)http->tls, (void *)buf, len); -# endif /* HAVE_LIBSSL */ - - DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); - return ((int)result); + return (0); } -#endif /* HAVE_SSL */ /* - * 'sspi_alloc()' - Allocate SSPI ssl object + * '_httpTLSStart()' - Set up SSL/TLS support on a connection. */ -_sspi_struct_t* /* O - New SSPI/SSL object */ -_sspiAlloc(void) + +int /* O - 0 on success, -1 on failure */ +_httpTLSStart(http_t *http) /* I - HTTP connection */ { - _sspi_struct_t *conn = calloc(sizeof(_sspi_struct_t), 1); + char hostname[256], /* Hostname */ + *hostptr; /* Pointer into hostname */ - if (conn) - conn->sock = INVALID_SOCKET; - return (conn); -} + DEBUG_printf(("7_httpTLSStart(http=%p)", http)); + + if ((http->tls = http_sspi_alloc()) == NULL) + return (-1); + if (http->mode == _HTTP_MODE_CLIENT) + { + /* + * Client: determine hostname... + */ -/* - * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store - * If one cannot be found, one is created. - */ -BOOL /* O - 1 on success, 0 on failure */ -_sspiGetCredentials(_sspi_struct_t *conn, - /* I - Client connection */ - const LPWSTR container, - /* I - Cert container name */ - const TCHAR *cn, /* I - Common name of certificate */ - BOOL isServer) - /* I - Is caller a server? */ -{ - HCERTSTORE store = NULL; /* Certificate store */ - PCCERT_CONTEXT storedContext = NULL; - /* Context created from the store */ - PCCERT_CONTEXT createdContext = NULL; - /* Context created by us */ - DWORD dwSize = 0; /* 32 bit size */ - PBYTE p = NULL; /* Temporary storage */ - HCRYPTPROV hProv = (HCRYPTPROV) NULL; - /* Handle to a CSP */ - CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ - SCHANNEL_CRED SchannelCred; /* Schannel credential data */ - TimeStamp tsExpiry; /* Time stamp */ - SECURITY_STATUS Status; /* Status */ - HCRYPTKEY hKey = (HCRYPTKEY) NULL; - /* Handle to crypto key */ - CRYPT_KEY_PROV_INFO kpi; /* Key container info */ - SYSTEMTIME et; /* System time */ - CERT_EXTENSIONS exts; /* Array of cert extensions */ - CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ - BOOL ok = TRUE; /* Return value */ + if (httpAddrLocalhost(http->hostaddr)) + { + strlcpy(hostname, "localhost", sizeof(hostname)); + } + else + { + /* + * Otherwise make sure the hostname we have does not end in a trailing dot. + */ - if (!conn) - return (FALSE); - if (!cn) - return (FALSE); + strlcpy(hostname, http->hostname, sizeof(hostname)); + if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && + *hostptr == '.') + *hostptr = '\0'; + } - if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W, - PROV_RSA_FULL, - CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) + return (http_sspi_client(http, hostname)); + } + else { - if (GetLastError() == NTE_EXISTS) + /* + * Server: determine hostname to use... + */ + + if (http->fields[HTTP_FIELD_HOST][0]) { - if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W, - PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) + /* + * Use hostname for TLS upgrade... + */ + + strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); + } + else + { + /* + * Resolve hostname from connection address... + */ + + http_addr_t addr; /* Connection address */ + socklen_t addrlen; /* Length of address */ + + addrlen = sizeof(addr); + if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) { - DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n", - GetLastError())); - ok = FALSE; - goto cleanup; + DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); + hostname[0] = '\0'; + } + else if (httpAddrLocalhost(&addr)) + hostname[0] = '\0'; + else + { + httpAddrLookup(&addr, hostname, sizeof(hostname)); + DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); } } - } - - store = CertOpenStore(CERT_STORE_PROV_SYSTEM, - X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, - hProv, - CERT_SYSTEM_STORE_LOCAL_MACHINE | - CERT_STORE_NO_CRYPT_RELEASE_FLAG | - CERT_STORE_OPEN_EXISTING_FLAG, - L"MY"); - if (!store) - { - DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n", - GetLastError())); - ok = FALSE; - goto cleanup; + return (http_sspi_server(http, hostname)); } +} - dwSize = 0; - if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, - NULL, NULL, &dwSize, NULL)) - { - DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n", - GetLastError())); - ok = FALSE; - goto cleanup; - } +/* + * '_httpTLSStop()' - Shut down SSL/TLS on a connection. + */ - p = (PBYTE) malloc(dwSize); +void +_httpTLSStop(http_t *http) /* I - HTTP connection */ +{ + _http_sspi_t *conn = http->tls; /* SSPI data */ - if (!p) - { - DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize)); - ok = FALSE; - goto cleanup; - } - if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL, - p, &dwSize, NULL)) + if (conn->contextInitialized && http->fd >= 0) { - DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x", - GetLastError())); - ok = FALSE; - goto cleanup; - } + SecBufferDesc message; /* Array of SecBuffer struct */ + SecBuffer buffers[1] = { 0 }; + /* Security package buffer */ + DWORD dwType; /* Type */ + DWORD status; /* Status */ - sib.cbData = dwSize; - sib.pbData = p; + /* + * Notify schannel that we are about to close the connection. + */ - storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, - 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); + dwType = SCHANNEL_SHUTDOWN; - if (!storedContext) - { - /* - * If we couldn't find the context, then we'll - * create a new one - */ - if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) - { - DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x", - GetLastError())); - ok = FALSE; - goto cleanup; - } + buffers[0].pvBuffer = &dwType; + buffers[0].BufferType = SECBUFFER_TOKEN; + buffers[0].cbBuffer = sizeof(dwType); - ZeroMemory(&kpi, sizeof(kpi)); - kpi.pwszContainerName = (LPWSTR) container; - kpi.pwszProvName = MS_DEF_PROV_W; - kpi.dwProvType = PROV_RSA_FULL; - kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; - kpi.dwKeySpec = AT_KEYEXCHANGE; + message.cBuffers = 1; + message.pBuffers = buffers; + message.ulVersion = SECBUFFER_VERSION; - GetSystemTime(&et); - et.wYear += 10; + status = ApplyControlToken(&conn->context, &message); - ZeroMemory(&exts, sizeof(exts)); + if (SUCCEEDED(status)) + { + PBYTE pbMessage; /* Message buffer */ + DWORD cbMessage; /* Message buffer count */ + DWORD cbData; /* Data count */ + DWORD dwSSPIFlags; /* SSL attributes we requested */ + DWORD dwSSPIOutFlags; /* SSL attributes we received */ + TimeStamp tsExpiry; /* Time stamp */ - createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, - &et, &exts); + dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | + ASC_REQ_REPLAY_DETECT | + ASC_REQ_CONFIDENTIALITY | + ASC_REQ_EXTENDED_ERROR | + ASC_REQ_ALLOCATE_MEMORY | + ASC_REQ_STREAM; - if (!createdContext) - { - DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x", - GetLastError())); - ok = FALSE; - goto cleanup; - } + buffers[0].pvBuffer = NULL; + buffers[0].BufferType = SECBUFFER_TOKEN; + buffers[0].cbBuffer = 0; - if (!CertAddCertificateContextToStore(store, createdContext, - CERT_STORE_ADD_REPLACE_EXISTING, - &storedContext)) - { - DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x", - GetLastError())); - ok = FALSE; - goto cleanup; + message.cBuffers = 1; + message.pBuffers = buffers; + message.ulVersion = SECBUFFER_VERSION; + + status = AcceptSecurityContext(&conn->creds, &conn->context, NULL, + dwSSPIFlags, SECURITY_NATIVE_DREP, NULL, + &message, &dwSSPIOutFlags, &tsExpiry); + + if (SUCCEEDED(status)) + { + pbMessage = buffers[0].pvBuffer; + cbMessage = buffers[0].cbBuffer; + + /* + * Send the close notify message to the client. + */ + + if (pbMessage && cbMessage) + { + cbData = send(http->fd, pbMessage, cbMessage, 0); + if ((cbData == SOCKET_ERROR) || (cbData == 0)) + { + status = WSAGetLastError(); + DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status)); + } + else + { + FreeContextBuffer(pbMessage); + } + } + } + else + { + DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %x", status)); + } + } + else + { + DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %x", status)); } + } - ZeroMemory(&ckp, sizeof(ckp)); - ckp.pwszContainerName = (LPWSTR) container; - ckp.pwszProvName = MS_DEF_PROV_W; - ckp.dwProvType = PROV_RSA_FULL; - ckp.dwFlags = CRYPT_MACHINE_KEYSET; - ckp.dwKeySpec = AT_KEYEXCHANGE; + http_sspi_free(conn); - if (!CertSetCertificateContextProperty(storedContext, - CERT_KEY_PROV_INFO_PROP_ID, - 0, &ckp)) + http->tls = NULL; +} + + +/* + * '_httpTLSWrite()' - Write to a SSL/TLS connection. + */ + +int /* O - Bytes written */ +_httpTLSWrite(http_t *http, /* I - HTTP connection */ + const char *buf, /* I - Buffer holding data */ + int len) /* I - Length of buffer */ +{ + _http_sspi_t *conn = http->tls; /* SSPI data */ + SecBufferDesc message; /* Array of SecBuffer struct */ + SecBuffer buffers[4] = { 0 }; /* Security package buffer */ + int bufferLen; /* Buffer length */ + int bytesLeft; /* Bytes left to write */ + const char *bufptr; /* Pointer into buffer */ + int num = 0; /* Return value */ + + + bufferLen = conn->streamSizes.cbMaximumMessage + conn->streamSizes.cbHeader + conn->streamSizes.cbTrailer; + + if (bufferLen > conn->writeBufferLen) + { + BYTE *temp; /* New buffer pointer */ + + if ((temp = (BYTE *)realloc(conn->writeBuffer, bufferLen)) == NULL) { - DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x", - GetLastError())); - ok = FALSE; - goto cleanup; + DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen)); + WSASetLastError(E_OUTOFMEMORY); + return (-1); } + + conn->writeBuffer = temp; + conn->writeBufferLen = bufferLen; } - ZeroMemory(&SchannelCred, sizeof(SchannelCred)); + bytesLeft = len; + bufptr = buf; - SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; - SchannelCred.cCreds = 1; - SchannelCred.paCred = &storedContext; + while (bytesLeft) + { + int chunk = min(conn->streamSizes.cbMaximumMessage, bytesLeft); + /* Size of data to write */ + SECURITY_STATUS scRet; /* SSPI status */ + + /* + * Copy user data into the buffer, starting just past the header... + */ + + memcpy(conn->writeBuffer + conn->streamSizes.cbHeader, bufptr, chunk); + + /* + * Setup the SSPI buffers + */ + + message.ulVersion = SECBUFFER_VERSION; + message.cBuffers = 4; + message.pBuffers = buffers; + + buffers[0].pvBuffer = conn->writeBuffer; + buffers[0].cbBuffer = conn->streamSizes.cbHeader; + buffers[0].BufferType = SECBUFFER_STREAM_HEADER; + buffers[1].pvBuffer = conn->writeBuffer + conn->streamSizes.cbHeader; + buffers[1].cbBuffer = (unsigned long) chunk; + buffers[1].BufferType = SECBUFFER_DATA; + buffers[2].pvBuffer = conn->writeBuffer + conn->streamSizes.cbHeader + chunk; + buffers[2].cbBuffer = conn->streamSizes.cbTrailer; + buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; + buffers[3].BufferType = SECBUFFER_EMPTY; + + /* + * Encrypt the data + */ + + scRet = EncryptMessage(&conn->context, 0, &message, 0); + + if (FAILED(scRet)) + { + DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %x", scRet)); + WSASetLastError(WSASYSCALLFAILURE); + return (-1); + } + + /* + * Send the data. Remember the size of the total data to send is the size + * of the header, the size of the data the caller passed in and the size + * of the trailer... + */ + + num = send(http->fd, conn->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0); + + if (num <= 0) + { + DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError())); + return (num); + } + + bytesLeft -= chunk; + bufptr += chunk; + } + + return (len); +} + + +#ifdef HAVE_SSL +/* + * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. + */ + +static int /* O - 0 on success, -1 on failure */ +http_setup_ssl(http_t *http) /* I - Connection to server */ +{ + char hostname[256], /* Hostname */ + *hostptr; /* Pointer into hostname */ + + TCHAR username[256]; /* Username returned from GetUserName() */ + TCHAR commonName[256];/* Common name for certificate */ + DWORD dwSize; /* 32 bit size */ - /* - * SSPI doesn't seem to like it if grbitEnabledProtocols - * is set for a client - */ - if (isServer) - SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1; + + DEBUG_printf(("7http_setup_ssl(http=%p)", http)); /* - * Create an SSPI credential. + * Get the hostname to use for SSL... */ - Status = AcquireCredentialsHandle(NULL, UNISP_NAME, - isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND, - NULL, &SchannelCred, NULL, NULL, &conn->creds, - &tsExpiry); - if (Status != SEC_E_OK) + + if (httpAddrLocalhost(http->hostaddr)) { - DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status)); - ok = FALSE; - goto cleanup; + strlcpy(hostname, "localhost", sizeof(hostname)); } + else + { + /* + * Otherwise make sure the hostname we have does not end in a trailing dot. + */ -cleanup: + strlcpy(hostname, http->hostname, sizeof(hostname)); + if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && + *hostptr == '.') + *hostptr = '\0'; + } - /* - * Cleanup - */ - if (hKey) - CryptDestroyKey(hKey); + http->tls = _sspiAlloc(); - if (createdContext) - CertFreeCertificateContext(createdContext); + if (!http->tls) + { + _cupsSetHTTPError(HTTP_STATUS_ERROR); + return (-1); + } - if (storedContext) - CertFreeCertificateContext(storedContext); + http->tls->sock = http->fd; + dwSize = sizeof(username) / sizeof(TCHAR); + GetUserName(username, &dwSize); + _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR), + sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username); - if (p) - free(p); + if (!_sspiGetCredentials(http->tls, L"ClientContainer", + commonName, FALSE)) + { + _sspiFree(http->tls); + http->tls = NULL; - if (store) - CertCloseStore(store, 0); + http->error = EIO; + http->status = HTTP_STATUS_ERROR; - if (hProv) - CryptReleaseContext(hProv, 0); + _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, + _("Unable to establish a secure connection to host."), 1); - return (ok); + return (-1); + } + + _sspiSetAllowsAnyRoot(http->tls, TRUE); + _sspiSetAllowsExpiredCerts(http->tls, TRUE); + + if (!_sspiConnect(http->tls, hostname)) + { + _sspiFree(http->tls); + http->tls = NULL; + + http->error = EIO; + http->status = HTTP_STATUS_ERROR; + + _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, + _("Unable to establish a secure connection to host."), 1); + + return (-1); + } + + return (0); } /* - * '_sspiConnect()' - Make an SSL connection. This function - * assumes a TCP/IP connection has already - * been successfully made + * 'http_sspi_alloc()' - Allocate SSPI object. */ -BOOL /* O - 1 on success, 0 on failure */ -_sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ - const CHAR *hostname) /* I - Server hostname */ + +static _http_sspi_t * /* O - New SSPI/SSL object */ +http_sspi_alloc(void) +{ + _http_sspi_t *conn = calloc(sizeof(_http_sspi_t), 1); + + return (conn); +} + + +/* + * 'http_sspi_client()' - Negotiate a TLS connection as a client. + */ + +static int /* O - 0 on success, -1 on failure */ +http_sspi_client(http_t *http, /* I - Client connection */ + const char *hostname) /* I - Server hostname */ { - PCCERT_CONTEXT serverCert; /* Server certificate */ + _http_sspi_t *conn; /* SSPI data */ DWORD dwSSPIFlags; /* SSL connection attributes we want */ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS scRet; /* Status */ - DWORD cbData; /* Data count */ + int cbData; /* Data count */ SecBufferDesc inBuffer; /* Array of SecBuffer structs */ SecBuffer inBuffers[2]; /* Security package buffer */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ - BOOL ok = TRUE; /* Return value */ + int ret = 0; /* Return value */ - serverCert = NULL; + DEBUG_printf(("http_sspi_client(http=%p, hostname=\"%s\")", http, hostname)); + + serverCert = NULL; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | @@ -1082,52 +1035,45 @@ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ /* * Initiate a ClientHello message and generate a token. */ + outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; - outBuffer.cBuffers = 1; - outBuffer.pBuffers = outBuffers; + outBuffer.cBuffers = 1; + outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; - scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags, - 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, - &outBuffer, &dwSSPIOutFlags, &tsExpiry); + scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry); if (scRet != SEC_I_CONTINUE_NEEDED) { - DEBUG_printf(("_sspiConnect: InitializeSecurityContext(1) failed: %x", scRet)); - ok = FALSE; - goto cleanup; + DEBUG_printf(("http_sspi_client: InitializeSecurityContext(1) failed: %x", scRet)); + return (-1); } /* * Send response to server if there is one. */ + if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { - cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); - - if ((cbData == SOCKET_ERROR) || !cbData) + if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0) { - DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError())); + DEBUG_printf(("http_sspi_client: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&conn->context); - ok = FALSE; - goto cleanup; + return (-1); } - DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData)); + DEBUG_printf(("http_sspi_client: %d bytes of handshake data sent.", cbData)); - /* - * Free output buffer. - */ FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION | - ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | @@ -1139,59 +1085,64 @@ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ /* * Loop until the handshake is finished or an error occurs. */ + scRet = SEC_I_CONTINUE_NEEDED; while(scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { - if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE)) + if (conn->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) { if (conn->decryptBufferLength <= conn->decryptBufferUsed) { - conn->decryptBufferLength += 4096; - conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength); + BYTE *temp; /* New buffer */ - if (!conn->decryptBuffer) - { - DEBUG_printf(("_sspiConnect: unable to allocate %d byte decrypt buffer", - conn->decryptBufferLength)); - SetLastError(E_OUTOFMEMORY); - ok = FALSE; - goto cleanup; - } + if (conn->decryptBufferLength >= 262144) + { + WSASetLastError(E_OUTOFMEMORY); + DEBUG_puts("http_sspi_client: Decryption buffer too large (>256k)"); + return (-1); + } + + if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL) + { + DEBUG_printf(("http_sspi_client: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096)); + WSASetLastError(E_OUTOFMEMORY); + return (-1); + } + + conn->decryptBufferLength += 4096; + conn->decryptBuffer = temp; } - cbData = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed, - (int) (conn->decryptBufferLength - conn->decryptBufferUsed), 0); + cbData = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0); - if (cbData == SOCKET_ERROR) + if (cbData < 0) { - DEBUG_printf(("_sspiConnect: recv failed: %d", WSAGetLastError())); - ok = FALSE; - goto cleanup; + DEBUG_printf(("http_sspi_client: recv failed: %d", WSAGetLastError())); + return (-1); } else if (cbData == 0) { - DEBUG_printf(("_sspiConnect: server unexpectedly disconnected")); - ok = FALSE; - goto cleanup; + DEBUG_printf(("http_sspi_client: Server unexpectedly disconnected.")); + return (-1); } - DEBUG_printf(("_sspiConnect: %d bytes of handshake data received", - cbData)); + DEBUG_printf(("http_sspi_client: %d bytes of handshake data received", cbData)); conn->decryptBufferUsed += cbData; } /* - * Set up the input buffers. Buffer 0 is used to pass in data - * received from the server. Schannel will consume some or all - * of this. Leftover data (if any) will be placed in buffer 1 and - * given a buffer type of SECBUFFER_EXTRA. + * Set up the input buffers. Buffer 0 is used to pass in data received from + * the server. Schannel will consume some or all of this. Leftover data + * (if any) will be placed in buffer 1 and given a buffer type of + * SECBUFFER_EXTRA. */ + inBuffers[0].pvBuffer = conn->decryptBuffer; - inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; + inBuffers[0].cbBuffer = (unsigned long)conn->decryptBufferUsed; inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; @@ -1203,101 +1154,87 @@ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ inBuffer.ulVersion = SECBUFFER_VERSION; /* - * Set up the output buffers. These are initialized to NULL - * so as to make it less likely we'll attempt to free random - * garbage later. + * Set up the output buffers. These are initialized to NULL so as to make it + * less likely we'll attempt to free random garbage later. */ - outBuffers[0].pvBuffer = NULL; - outBuffers[0].BufferType= SECBUFFER_TOKEN; - outBuffers[0].cbBuffer = 0; - outBuffer.cBuffers = 1; - outBuffer.pBuffers = outBuffers; - outBuffer.ulVersion = SECBUFFER_VERSION; + outBuffers[0].pvBuffer = NULL; + outBuffers[0].BufferType = SECBUFFER_TOKEN; + outBuffers[0].cbBuffer = 0; + + outBuffer.cBuffers = 1; + outBuffer.pBuffers = outBuffers; + outBuffer.ulVersion = SECBUFFER_VERSION; /* * Call InitializeSecurityContext. */ - scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags, - 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, - &outBuffer, &dwSSPIOutFlags, &tsExpiry); + + scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry); /* - * If InitializeSecurityContext was successful (or if the error was - * one of the special extended ones), send the contends of the output - * buffer to the server. + * If InitializeSecurityContext was successful (or if the error was one of + * the special extended ones), send the contents of the output buffer to the + * server. */ + if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) { if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { - cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); + cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); - if ((cbData == SOCKET_ERROR) || !cbData) + if (cbData <= 0) { - DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError())); + DEBUG_printf(("http_sspi_client: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&conn->context); - ok = FALSE; - goto cleanup; + return (-1); } - DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData)); + DEBUG_printf(("http_sspi_client: %d bytes of handshake data sent.", cbData)); /* * Free output buffer. */ + FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } } /* - * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, - * then we need to read more data from the server and try again. + * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we + * need to read more data from the server and try again. */ + if (scRet == SEC_E_INCOMPLETE_MESSAGE) continue; /* - * If InitializeSecurityContext returned SEC_E_OK, then the - * handshake completed successfully. + * If InitializeSecurityContext returned SEC_E_OK, then the handshake + * completed successfully. */ + if (scRet == SEC_E_OK) { /* * If the "extra" buffer contains data, this is encrypted application - * protocol layer stuff. It needs to be saved. The application layer - * will later decrypt it with DecryptMessage. + * protocol layer stuff. It needs to be saved. The application layer will + * later decrypt it with DecryptMessage. */ - DEBUG_printf(("_sspiConnect: Handshake was successful")); + + DEBUG_puts("http_sspi_client: Handshake was successful."); if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { - if (conn->decryptBufferLength < inBuffers[1].cbBuffer) - { - conn->decryptBuffer = realloc(conn->decryptBuffer, inBuffers[1].cbBuffer); - - if (!conn->decryptBuffer) - { - DEBUG_printf(("_sspiConnect: unable to allocate %d bytes for decrypt buffer", - inBuffers[1].cbBuffer)); - SetLastError(E_OUTOFMEMORY); - ok = FALSE; - goto cleanup; - } - } - - memmove(conn->decryptBuffer, - conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer), - inBuffers[1].cbBuffer); + memmove(conn->decryptBuffer, conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; - DEBUG_printf(("_sspiConnect: %d bytes of app data was bundled with handshake data", - conn->decryptBufferUsed)); + DEBUG_printf(("http_sspi_client: %d bytes of app data was bundled with handshake data", conn->decryptBufferUsed)); } else conn->decryptBufferUsed = 0; @@ -1305,16 +1242,18 @@ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ /* * Bail out to quit */ + break; } /* * Check for fatal error. */ + if (FAILED(scRet)) { - DEBUG_printf(("_sspiConnect: InitializeSecurityContext(2) failed: %x", scRet)); - ok = FALSE; + DEBUG_printf(("http_sspi_client: InitializeSecurityContext(2) failed: %x", scRet)); + ret = -1; break; } @@ -1322,25 +1261,25 @@ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, * then the server just requested client authentication. */ + if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) { /* * Unimplemented */ - DEBUG_printf(("_sspiConnect: server requested client credentials")); - ok = FALSE; + + DEBUG_printf(("http_sspi_client: server requested client credentials.")); + ret = -1; break; } /* - * Copy any leftover data from the "extra" buffer, and go around - * again. + * Copy any leftover data from the "extra" buffer, and go around again. */ + if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { - memmove(conn->decryptBuffer, - conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer), - inBuffers[1].cbBuffer); + memmove(conn->decryptBuffer, conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; } @@ -1350,849 +1289,629 @@ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ } } - if (ok) + if (!ret) { - conn->contextInitialized = TRUE; - /* - * Get the server cert + * Success! Get the server cert */ - scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID*) &serverCert ); + + conn->contextInitialized = TRUE; + + scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(conn->remoteCert)); if (scRet != SEC_E_OK) { - DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet)); - ok = FALSE; - goto cleanup; + DEBUG_printf(("http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet)); + return (-1); } - scRet = sspi_verify_certificate(serverCert, hostname, conn->certFlags); +#if 0 + /* TODO: Move this out for opt-in server cert validation, like other platforms. */ + scRet = http_sspi_verify(conn->remoteCert, hostname, conn->certFlags); if (scRet != SEC_E_OK) { - DEBUG_printf(("_sspiConnect: sspi_verify_certificate failed: %x", scRet)); - ok = FALSE; + DEBUG_printf(("http_sspi_client: sspi_verify_certificate failed: %x", scRet)); + ret = -1; goto cleanup; } +#endif // 0 /* * Find out how big the header/trailer will be: */ + scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes); if (scRet != SEC_E_OK) { - DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet)); - ok = FALSE; + DEBUG_printf(("http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet)); + ret = -1; } } -cleanup: + return (ret); +} - if (serverCert) - CertFreeCertificateContext(serverCert); - return (ok); +/* + * 'http_sspi_free()' - Close a connection and free resources. + */ + +static void +http_sspi_free(_http_sspi_t *conn) /* I - Client connection */ +{ + if (!conn) + return; + + if (conn->contextInitialized) + DeleteSecurityContext(&conn->context); + + if (conn->decryptBuffer) + free(conn->decryptBuffer); + + if (conn->readBuffer) + free(conn->readBuffer); + + if (conn->writeBuffer) + free(conn->writeBuffer); + + if (conn->localCert.pbCertEncoded) + CertFreeCertificateContext(conn->localCert); + + if (conn->remoteCert.pbCertEncoded) + CertFreeCertificateContext(conn->remoteCert); + + free(conn); } +#if 0 /* - * '_sspiAccept()' - Accept an SSL/TLS connection + * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store + * If one cannot be found, one is created. */ BOOL /* O - 1 on success, 0 on failure */ -_sspiAccept(_sspi_struct_t *conn) /* I - Client connection */ +_sspiGetCredentials(_http_sspi_t *conn, + /* I - Client connection */ + const LPWSTR container, + /* I - Cert container name */ + const TCHAR *cn, /* I - Common name of certificate */ + BOOL isServer) + /* I - Is caller a server? */ { - DWORD dwSSPIFlags; /* SSL connection attributes we want */ - DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ + HCERTSTORE store = NULL; /* Certificate store */ + PCCERT_CONTEXT storedContext = NULL; + /* Context created from the store */ + PCCERT_CONTEXT createdContext = NULL; + /* Context created by us */ + DWORD dwSize = 0; /* 32 bit size */ + PBYTE p = NULL; /* Temporary storage */ + HCRYPTPROV hProv = (HCRYPTPROV) NULL; + /* Handle to a CSP */ + CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ + SCHANNEL_CRED SchannelCred; /* Schannel credential data */ TimeStamp tsExpiry; /* Time stamp */ - SECURITY_STATUS scRet; /* SSPI Status */ - SecBufferDesc inBuffer; /* Array of SecBuffer structs */ - SecBuffer inBuffers[2]; /* Security package buffer */ - SecBufferDesc outBuffer; /* Array of SecBuffer structs */ - SecBuffer outBuffers[1]; /* Security package buffer */ - DWORD num = 0; /* 32 bit status value */ - BOOL fInitContext = TRUE; - /* Has the context been init'd? */ + SECURITY_STATUS Status; /* Status */ + HCRYPTKEY hKey = (HCRYPTKEY) NULL; + /* Handle to crypto key */ + CRYPT_KEY_PROV_INFO kpi; /* Key container info */ + SYSTEMTIME et; /* System time */ + CERT_EXTENSIONS exts; /* Array of cert extensions */ + CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ BOOL ok = TRUE; /* Return value */ if (!conn) return (FALSE); + if (!cn) + return (FALSE); - dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | - ASC_REQ_REPLAY_DETECT | - ASC_REQ_CONFIDENTIALITY | - ASC_REQ_EXTENDED_ERROR | - ASC_REQ_ALLOCATE_MEMORY | - ASC_REQ_STREAM; - - conn->decryptBufferUsed = 0; - - /* - * Set OutBuffer for AcceptSecurityContext call - */ - outBuffer.cBuffers = 1; - outBuffer.pBuffers = outBuffers; - outBuffer.ulVersion = SECBUFFER_VERSION; - - scRet = SEC_I_CONTINUE_NEEDED; - - while (scRet == SEC_I_CONTINUE_NEEDED || - scRet == SEC_E_INCOMPLETE_MESSAGE || - scRet == SEC_I_INCOMPLETE_CREDENTIALS) + if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W, + PROV_RSA_FULL, + CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) { - if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE)) + if (GetLastError() == NTE_EXISTS) { - if (conn->decryptBufferLength <= conn->decryptBufferUsed) - { - conn->decryptBufferLength += 4096; - conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, - conn->decryptBufferLength); - - if (!conn->decryptBuffer) - { - DEBUG_printf(("_sspiAccept: unable to allocate %d byte decrypt buffer", - conn->decryptBufferLength)); - ok = FALSE; - goto cleanup; - } - } - - for (;;) - { - num = recv(conn->sock, - conn->decryptBuffer + conn->decryptBufferUsed, - (int)(conn->decryptBufferLength - conn->decryptBufferUsed), - 0); - - if ((num == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK)) - Sleep(1); - else - break; - } - - if (num == SOCKET_ERROR) - { - DEBUG_printf(("_sspiAccept: recv failed: %d", WSAGetLastError())); - ok = FALSE; - goto cleanup; - } - else if (num == 0) + if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W, + PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { - DEBUG_printf(("_sspiAccept: client disconnected")); + DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n", + GetLastError())); ok = FALSE; goto cleanup; } - - DEBUG_printf(("_sspiAccept: received %d (handshake) bytes from client", - num)); - conn->decryptBufferUsed += num; } + } - /* - * InBuffers[1] is for getting extra data that - * SSPI/SCHANNEL doesn't proccess on this - * run around the loop. - */ - inBuffers[0].pvBuffer = conn->decryptBuffer; - inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; - inBuffers[0].BufferType = SECBUFFER_TOKEN; + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, + X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, + hProv, + CERT_SYSTEM_STORE_LOCAL_MACHINE | + CERT_STORE_NO_CRYPT_RELEASE_FLAG | + CERT_STORE_OPEN_EXISTING_FLAG, + L"MY"); - inBuffers[1].pvBuffer = NULL; - inBuffers[1].cbBuffer = 0; - inBuffers[1].BufferType = SECBUFFER_EMPTY; + if (!store) + { + DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n", + GetLastError())); + ok = FALSE; + goto cleanup; + } - inBuffer.cBuffers = 2; - inBuffer.pBuffers = inBuffers; - inBuffer.ulVersion = SECBUFFER_VERSION; + dwSize = 0; - /* - * Initialize these so if we fail, pvBuffer contains NULL, - * so we don't try to free random garbage at the quit - */ - outBuffers[0].pvBuffer = NULL; - outBuffers[0].BufferType = SECBUFFER_TOKEN; - outBuffers[0].cbBuffer = 0; + if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, + NULL, NULL, &dwSize, NULL)) + { + DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n", + GetLastError())); + ok = FALSE; + goto cleanup; + } - scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context), - &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, - (fInitContext?&conn->context:NULL), &outBuffer, - &dwSSPIOutFlags, &tsExpiry); + p = (PBYTE) malloc(dwSize); - fInitContext = FALSE; + if (!p) + { + DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize)); + ok = FALSE; + goto cleanup; + } - if (scRet == SEC_E_OK || - scRet == SEC_I_CONTINUE_NEEDED || - (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0))) - { - if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) - { - /* - * Send response to server if there is one - */ - num = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); + if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL, + p, &dwSize, NULL)) + { + DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x", + GetLastError())); + ok = FALSE; + goto cleanup; + } - if ((num == SOCKET_ERROR) || (num == 0)) - { - DEBUG_printf(("_sspiAccept: handshake send failed: %d", WSAGetLastError())); - ok = FALSE; - goto cleanup; - } + sib.cbData = dwSize; + sib.pbData = p; - DEBUG_printf(("_sspiAccept: send %d handshake bytes to client", - outBuffers[0].cbBuffer)); + storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); - FreeContextBuffer(outBuffers[0].pvBuffer); - outBuffers[0].pvBuffer = NULL; - } + if (!storedContext) + { + /* + * If we couldn't find the context, then we'll + * create a new one + */ + if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) + { + DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x", + GetLastError())); + ok = FALSE; + goto cleanup; } - if (scRet == SEC_E_OK) - { - /* - * If there's extra data then save it for - * next time we go to decrypt - */ - if (inBuffers[1].BufferType == SECBUFFER_EXTRA) - { - memcpy(conn->decryptBuffer, - (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)), - inBuffers[1].cbBuffer); - conn->decryptBufferUsed = inBuffers[1].cbBuffer; - } - else - { - conn->decryptBufferUsed = 0; - } + ZeroMemory(&kpi, sizeof(kpi)); + kpi.pwszContainerName = (LPWSTR) container; + kpi.pwszProvName = MS_DEF_PROV_W; + kpi.dwProvType = PROV_RSA_FULL; + kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; + kpi.dwKeySpec = AT_KEYEXCHANGE; - ok = TRUE; - break; - } - else if (FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE)) + GetSystemTime(&et); + et.wYear += 10; + + ZeroMemory(&exts, sizeof(exts)); + + createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, + &et, &exts); + + if (!createdContext) { - DEBUG_printf(("_sspiAccept: AcceptSecurityContext failed: %x", scRet)); + DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x", + GetLastError())); ok = FALSE; - break; + goto cleanup; } - if (scRet != SEC_E_INCOMPLETE_MESSAGE && - scRet != SEC_I_INCOMPLETE_CREDENTIALS) + if (!CertAddCertificateContextToStore(store, createdContext, + CERT_STORE_ADD_REPLACE_EXISTING, + &storedContext)) { - if (inBuffers[1].BufferType == SECBUFFER_EXTRA) - { - memcpy(conn->decryptBuffer, - (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)), - inBuffers[1].cbBuffer); - conn->decryptBufferUsed = inBuffers[1].cbBuffer; - } - else - { - conn->decryptBufferUsed = 0; - } + DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x", + GetLastError())); + ok = FALSE; + goto cleanup; } - } - if (ok) - { - conn->contextInitialized = TRUE; - - /* - * Find out how big the header will be: - */ - scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes); + ZeroMemory(&ckp, sizeof(ckp)); + ckp.pwszContainerName = (LPWSTR) container; + ckp.pwszProvName = MS_DEF_PROV_W; + ckp.dwProvType = PROV_RSA_FULL; + ckp.dwFlags = CRYPT_MACHINE_KEYSET; + ckp.dwKeySpec = AT_KEYEXCHANGE; - if (scRet != SEC_E_OK) + if (!CertSetCertificateContextProperty(storedContext, + CERT_KEY_PROV_INFO_PROP_ID, + 0, &ckp)) { - DEBUG_printf(("_sspiAccept: QueryContextAttributes failed: %x", scRet)); + DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x", + GetLastError())); ok = FALSE; + goto cleanup; } } -cleanup: - - return (ok); -} - - -/* - * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs - */ -void -_sspiSetAllowsAnyRoot(_sspi_struct_t *conn, - /* I - Client connection */ - BOOL allow) - /* I - Allow any root */ -{ - conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA : - conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA; -} - - -/* - * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs - */ -void -_sspiSetAllowsExpiredCerts(_sspi_struct_t *conn, - /* I - Client connection */ - BOOL allow) - /* I - Allow expired certs */ -{ - conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID : - conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; -} - - -/* - * '_sspiWrite()' - Write a buffer to an ssl socket - */ -int /* O - Bytes written or SOCKET_ERROR */ -_sspiWrite(_sspi_struct_t *conn, /* I - Client connection */ - void *buf, /* I - Buffer */ - size_t len) /* I - Buffer length */ -{ - SecBufferDesc message; /* Array of SecBuffer struct */ - SecBuffer buffers[4] = { 0 }; /* Security package buffer */ - BYTE *buffer = NULL; /* Scratch buffer */ - int bufferLen; /* Buffer length */ - size_t bytesLeft; /* Bytes left to write */ - int index = 0; /* Index into buffer */ - int num = 0; /* Return value */ - - if (!conn || !buf || !len) - { - WSASetLastError(WSAEINVAL); - num = SOCKET_ERROR; - goto cleanup; - } + ZeroMemory(&SchannelCred, sizeof(SchannelCred)); - bufferLen = conn->streamSizes.cbMaximumMessage + - conn->streamSizes.cbHeader + - conn->streamSizes.cbTrailer; + SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; + SchannelCred.cCreds = 1; + SchannelCred.paCred = &storedContext; - buffer = (BYTE*) malloc(bufferLen); + /* + * SSPI doesn't seem to like it if grbitEnabledProtocols + * is set for a client + */ + if (isServer) + SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1; - if (!buffer) + /* + * Create an SSPI credential. + */ + Status = AcquireCredentialsHandle(NULL, UNISP_NAME, + isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND, + NULL, &SchannelCred, NULL, NULL, &conn->creds, + &tsExpiry); + if (Status != SEC_E_OK) { - DEBUG_printf(("_sspiWrite: buffer alloc of %d bytes failed", bufferLen)); - WSASetLastError(E_OUTOFMEMORY); - num = SOCKET_ERROR; + DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status)); + ok = FALSE; goto cleanup; } - bytesLeft = len; - - while (bytesLeft) - { - size_t chunk = min(conn->streamSizes.cbMaximumMessage, /* Size of data to write */ - bytesLeft); - SECURITY_STATUS scRet; /* SSPI status */ - - /* - * Copy user data into the buffer, starting - * just past the header - */ - memcpy(buffer + conn->streamSizes.cbHeader, - ((BYTE*) buf) + index, - chunk); - - /* - * Setup the SSPI buffers - */ - message.ulVersion = SECBUFFER_VERSION; - message.cBuffers = 4; - message.pBuffers = buffers; - buffers[0].pvBuffer = buffer; - buffers[0].cbBuffer = conn->streamSizes.cbHeader; - buffers[0].BufferType = SECBUFFER_STREAM_HEADER; - buffers[1].pvBuffer = buffer + conn->streamSizes.cbHeader; - buffers[1].cbBuffer = (unsigned long) chunk; - buffers[1].BufferType = SECBUFFER_DATA; - buffers[2].pvBuffer = buffer + conn->streamSizes.cbHeader + chunk; - buffers[2].cbBuffer = conn->streamSizes.cbTrailer; - buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; - buffers[3].BufferType = SECBUFFER_EMPTY; - - /* - * Encrypt the data - */ - scRet = EncryptMessage(&conn->context, 0, &message, 0); - - if (FAILED(scRet)) - { - DEBUG_printf(("_sspiWrite: EncryptMessage failed: %x", scRet)); - WSASetLastError(WSASYSCALLFAILURE); - num = SOCKET_ERROR; - goto cleanup; - } +cleanup: - /* - * Send the data. Remember the size of - * the total data to send is the size - * of the header, the size of the data - * the caller passed in and the size - * of the trailer - */ - num = send(conn->sock, - buffer, - buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, - 0); + /* + * Cleanup + */ + if (hKey) + CryptDestroyKey(hKey); - if ((num == SOCKET_ERROR) || (num == 0)) - { - DEBUG_printf(("_sspiWrite: send failed: %ld", WSAGetLastError())); - goto cleanup; - } + if (createdContext) + CertFreeCertificateContext(createdContext); - bytesLeft -= (int) chunk; - index += (int) chunk; - } + if (storedContext) + CertFreeCertificateContext(storedContext); - num = (int) len; + if (p) + free(p); -cleanup: + if (store) + CertCloseStore(store, 0); - if (buffer) - free(buffer); + if (hProv) + CryptReleaseContext(hProv, 0); - return (num); + return (ok); } +#endif // 0 /* - * '_sspiRead()' - Read a buffer from an ssl socket + * 'http_sspi_server()' - Negotiate a TLS connection as a server. */ -int /* O - Bytes read or SOCKET_ERROR */ -_sspiRead(_sspi_struct_t *conn, /* I - Client connection */ - void *buf, /* I - Buffer */ - size_t len) /* I - Buffer length */ + +static int /* O - 0 on success, -1 on failure */ +http_sspi_server(http_t *http, /* I - HTTP connection */ + const char *hostname) /* I - Hostname of server */ { - SecBufferDesc message; /* Array of SecBuffer struct */ - SecBuffer buffers[4] = { 0 }; /* Security package buffer */ - int num = 0; /* Return value */ + _http_sspi_t *conn = http->tls; /* I - SSPI data */ + DWORD dwSSPIFlags; /* SSL connection attributes we want */ + DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ + TimeStamp tsExpiry; /* Time stamp */ + SECURITY_STATUS scRet; /* SSPI Status */ + SecBufferDesc inBuffer; /* Array of SecBuffer structs */ + SecBuffer inBuffers[2]; /* Security package buffer */ + SecBufferDesc outBuffer; /* Array of SecBuffer structs */ + SecBuffer outBuffers[1]; /* Security package buffer */ + int num = 0; /* 32 bit status value */ + BOOL fInitContext = TRUE; /* Has the context been init'd? */ + int ret = 0; /* Return value */ + + + DEBUG_printf(("http_sspi_server(http=%p, hostname=\"%s\")", http, hostname)); - if (!conn) - { - WSASetLastError(WSAEINVAL); - num = SOCKET_ERROR; - goto cleanup; - } + dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | + ASC_REQ_REPLAY_DETECT | + ASC_REQ_CONFIDENTIALITY | + ASC_REQ_EXTENDED_ERROR | + ASC_REQ_ALLOCATE_MEMORY | + ASC_REQ_STREAM; + + conn->decryptBufferUsed = 0; /* - * If there are bytes that have already been - * decrypted and have not yet been read, return - * those + * Set OutBuffer for AcceptSecurityContext call */ - if (buf && (conn->readBufferUsed > 0)) - { - int bytesToCopy = (int) min(conn->readBufferUsed, len); /* Amount of bytes to copy */ - /* from read buffer */ - memcpy(buf, conn->readBuffer, bytesToCopy); - conn->readBufferUsed -= bytesToCopy; + outBuffer.cBuffers = 1; + outBuffer.pBuffers = outBuffers; + outBuffer.ulVersion = SECBUFFER_VERSION; - if (conn->readBufferUsed > 0) - /* - * If the caller didn't request all the bytes - * we have in the buffer, then move the unread - * bytes down - */ - memmove(conn->readBuffer, - conn->readBuffer + bytesToCopy, - conn->readBufferUsed); + scRet = SEC_I_CONTINUE_NEEDED; - num = bytesToCopy; - } - else + while (scRet == SEC_I_CONTINUE_NEEDED || + scRet == SEC_E_INCOMPLETE_MESSAGE || + scRet == SEC_I_INCOMPLETE_CREDENTIALS) { - PSecBuffer pDataBuffer; /* Data buffer */ - PSecBuffer pExtraBuffer; /* Excess data buffer */ - SECURITY_STATUS scRet; /* SSPI status */ - int i; /* Loop control variable */ - - /* - * Initialize security buffer structs - */ - message.ulVersion = SECBUFFER_VERSION; - message.cBuffers = 4; - message.pBuffers = buffers; - - do + if (conn->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) { - /* - * If there is not enough space in the - * buffer, then increase it's size - */ if (conn->decryptBufferLength <= conn->decryptBufferUsed) { - conn->decryptBufferLength += 4096; - conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, - conn->decryptBufferLength); + BYTE *temp; /* New buffer */ - if (!conn->decryptBuffer) - { - DEBUG_printf(("_sspiRead: unable to allocate %d byte buffer", - conn->decryptBufferLength)); - WSASetLastError(E_OUTOFMEMORY); - num = SOCKET_ERROR; - goto cleanup; - } - } + if (conn->decryptBufferLength >= 262144) + { + WSASetLastError(E_OUTOFMEMORY); + DEBUG_puts("http_sspi_server: Decryption buffer too large (>256k)"); + return (-1); + } - buffers[0].pvBuffer = conn->decryptBuffer; - buffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; - buffers[0].BufferType = SECBUFFER_DATA; - buffers[1].BufferType = SECBUFFER_EMPTY; - buffers[2].BufferType = SECBUFFER_EMPTY; - buffers[3].BufferType = SECBUFFER_EMPTY; + if ((temp = realloc(conn->decryptBuffer, conn->decryptBufferLength + 4096)) == NULL) + { + DEBUG_printf(("http_sspi_server: Unable to allocate %d byte buffer.", conn->decryptBufferLength + 4096)); + WSASetLastError(E_OUTOFMEMORY); + return (-1); + } - scRet = DecryptMessage(&conn->context, &message, 0, NULL); + conn->decryptBufferLength += 4096; + conn->decryptBuffer = temp; + } - if (scRet == SEC_E_INCOMPLETE_MESSAGE) + for (;;) { - if (buf) - { - num = recv(conn->sock, - conn->decryptBuffer + conn->decryptBufferUsed, - (int)(conn->decryptBufferLength - conn->decryptBufferUsed), - 0); - if (num == SOCKET_ERROR) - { - DEBUG_printf(("_sspiRead: recv failed: %d", WSAGetLastError())); - goto cleanup; - } - else if (num == 0) - { - DEBUG_printf(("_sspiRead: server disconnected")); - goto cleanup; - } + num = recv(http->fd, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0); - conn->decryptBufferUsed += num; - } + if (num == -1 WSAGetLastError() == WSAEWOULDBLOCK) + Sleep(1); else - { - num = (int) conn->readBufferUsed; - goto cleanup; - } + break; } - } - while (scRet == SEC_E_INCOMPLETE_MESSAGE); - if (scRet == SEC_I_CONTEXT_EXPIRED) - { - DEBUG_printf(("_sspiRead: context expired")); - WSASetLastError(WSAECONNRESET); - num = SOCKET_ERROR; - goto cleanup; - } - else if (scRet != SEC_E_OK) - { - DEBUG_printf(("_sspiRead: DecryptMessage failed: %lx", scRet)); - WSASetLastError(WSASYSCALLFAILURE); - num = SOCKET_ERROR; - goto cleanup; + if (num < 0) + { + DEBUG_printf(("http_sspi_server: recv failed: %d", WSAGetLastError())); + return (-1); + } + else if (num == 0) + { + DEBUG_puts("http_sspi_server: client disconnected"); + return (-1); + } + + DEBUG_printf(("http_sspi_server: received %d (handshake) bytes from client.", num)); + conn->decryptBufferUsed += num; } /* - * The decryption worked. Now, locate data buffer. + * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process + * on this run around the loop. */ - pDataBuffer = NULL; - pExtraBuffer = NULL; - for (i = 1; i < 4; i++) - { - if (buffers[i].BufferType == SECBUFFER_DATA) - pDataBuffer = &buffers[i]; - else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA)) - pExtraBuffer = &buffers[i]; - } + + inBuffers[0].pvBuffer = conn->decryptBuffer; + inBuffers[0].cbBuffer = (unsigned long)conn->decryptBufferUsed; + inBuffers[0].BufferType = SECBUFFER_TOKEN; + + inBuffers[1].pvBuffer = NULL; + inBuffers[1].cbBuffer = 0; + inBuffers[1].BufferType = SECBUFFER_EMPTY; + + inBuffer.cBuffers = 2; + inBuffer.pBuffers = inBuffers; + inBuffer.ulVersion = SECBUFFER_VERSION; /* - * If a data buffer is found, then copy - * the decrypted bytes to the passed-in - * buffer + * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to + * free random garbage at the quit. */ - if (pDataBuffer) - { - int bytesToCopy = min(pDataBuffer->cbBuffer, (int) len); - /* Number of bytes to copy into buf */ - int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy; - /* Number of bytes to save in our read buffer */ - if (bytesToCopy) - memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy); + outBuffers[0].pvBuffer = NULL; + outBuffers[0].BufferType = SECBUFFER_TOKEN; + outBuffers[0].cbBuffer = 0; + + scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&conn->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry); - /* - * If there are more decrypted bytes than can be - * copied to the passed in buffer, then save them - */ - if (bytesToSave) + fInitContext = FALSE; + + if (scRet == SEC_E_OK || + scRet == SEC_I_CONTINUE_NEEDED || + (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0))) + { + if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { - if ((int)(conn->readBufferLength - conn->readBufferUsed) < bytesToSave) - { - conn->readBufferLength = conn->readBufferUsed + bytesToSave; - conn->readBuffer = realloc(conn->readBuffer, - conn->readBufferLength); + /* + * Send response to server if there is one. + */ - if (!conn->readBuffer) - { - DEBUG_printf(("_sspiRead: unable to allocate %d bytes", conn->readBufferLength)); - WSASetLastError(E_OUTOFMEMORY); - num = SOCKET_ERROR; - goto cleanup; - } + num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); + + if (num <= 0) + { + DEBUG_printf(("http_sspi_server: handshake send failed: %d", WSAGetLastError())); + return (-1); } - memcpy(((BYTE*) conn->readBuffer) + conn->readBufferUsed, - ((BYTE*) pDataBuffer->pvBuffer) + bytesToCopy, - bytesToSave); + DEBUG_printf(("http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer)); - conn->readBufferUsed += bytesToSave; + FreeContextBuffer(outBuffers[0].pvBuffer); + outBuffers[0].pvBuffer = NULL; } + } + + if (scRet == SEC_E_OK) + { + /* + * If there's extra data then save it for next time we go to decrypt. + */ - num = (buf) ? bytesToCopy : (int) conn->readBufferUsed; + if (inBuffers[1].BufferType == SECBUFFER_EXTRA) + { + memcpy(conn->decryptBuffer, (LPBYTE)(conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); + conn->decryptBufferUsed = inBuffers[1].cbBuffer; + } + else + { + conn->decryptBufferUsed = 0; + } + break; } - else + else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE) { - DEBUG_printf(("_sspiRead: unable to find data buffer")); - WSASetLastError(WSASYSCALLFAILURE); - num = SOCKET_ERROR; - goto cleanup; + DEBUG_printf(("http_sspi_server: AcceptSecurityContext failed: %x", scRet)); + ret = -1; + break; } - /* - * If the decryption process left extra bytes, - * then save those back in decryptBuffer. They will - * be processed the next time through the loop. - */ - if (pExtraBuffer) + if (scRet != SEC_E_INCOMPLETE_MESSAGE && + scRet != SEC_I_INCOMPLETE_CREDENTIALS) { - memmove(conn->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer); - conn->decryptBufferUsed = pExtraBuffer->cbBuffer; + if (inBuffers[1].BufferType == SECBUFFER_EXTRA) + { + memcpy(conn->decryptBuffer, (LPBYTE)(conn->decryptBuffer + conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); + conn->decryptBufferUsed = inBuffers[1].cbBuffer; + } + else + { + conn->decryptBufferUsed = 0; + } } - else + } + + if (!ret) + { + conn->contextInitialized = TRUE; + + /* + * Find out how big the header will be: + */ + + scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes); + + if (scRet != SEC_E_OK) { - conn->decryptBufferUsed = 0; + DEBUG_printf(("http_sspi_server: QueryContextAttributes failed: %x", scRet)); + ret = -1; } } -cleanup: - - return (num); + return (ret); } +#if 0 /* - * '_sspiPending()' - Returns the number of available bytes + * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs */ -int /* O - Number of available bytes */ -_sspiPending(_sspi_struct_t *conn) /* I - Client connection */ +void +_sspiSetAllowsAnyRoot(_http_sspi_t *conn, + /* I - Client connection */ + BOOL allow) + /* I - Allow any root */ { - return (_sspiRead(conn, NULL, 0)); + conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA : + conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA; } /* - * '_sspiFree()' - Close a connection and free resources + * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs */ void -_sspiFree(_sspi_struct_t *conn) /* I - Client connection */ +_sspiSetAllowsExpiredCerts(_http_sspi_t *conn, + /* I - Client connection */ + BOOL allow) + /* I - Allow expired certs */ { - if (!conn) - return; - - if (conn->contextInitialized) - { - SecBufferDesc message; /* Array of SecBuffer struct */ - SecBuffer buffers[1] = { 0 }; - /* Security package buffer */ - DWORD dwType; /* Type */ - DWORD status; /* Status */ - - /* - * Notify schannel that we are about to close the connection. - */ - dwType = SCHANNEL_SHUTDOWN; - - buffers[0].pvBuffer = &dwType; - buffers[0].BufferType = SECBUFFER_TOKEN; - buffers[0].cbBuffer = sizeof(dwType); - - message.cBuffers = 1; - message.pBuffers = buffers; - message.ulVersion = SECBUFFER_VERSION; - - status = ApplyControlToken(&conn->context, &message); - - if (SUCCEEDED(status)) - { - PBYTE pbMessage; /* Message buffer */ - DWORD cbMessage; /* Message buffer count */ - DWORD cbData; /* Data count */ - DWORD dwSSPIFlags; /* SSL attributes we requested */ - DWORD dwSSPIOutFlags; /* SSL attributes we received */ - TimeStamp tsExpiry; /* Time stamp */ - - dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | - ASC_REQ_REPLAY_DETECT | - ASC_REQ_CONFIDENTIALITY | - ASC_REQ_EXTENDED_ERROR | - ASC_REQ_ALLOCATE_MEMORY | - ASC_REQ_STREAM; - - buffers[0].pvBuffer = NULL; - buffers[0].BufferType = SECBUFFER_TOKEN; - buffers[0].cbBuffer = 0; - - message.cBuffers = 1; - message.pBuffers = buffers; - message.ulVersion = SECBUFFER_VERSION; - - status = AcceptSecurityContext(&conn->creds, &conn->context, NULL, - dwSSPIFlags, SECURITY_NATIVE_DREP, NULL, - &message, &dwSSPIOutFlags, &tsExpiry); - - if (SUCCEEDED(status)) - { - pbMessage = buffers[0].pvBuffer; - cbMessage = buffers[0].cbBuffer; - - /* - * Send the close notify message to the client. - */ - if (pbMessage && cbMessage) - { - cbData = send(conn->sock, pbMessage, cbMessage, 0); - if ((cbData == SOCKET_ERROR) || (cbData == 0)) - { - status = WSAGetLastError(); - DEBUG_printf(("_sspiFree: sending close notify failed: %d", status)); - } - else - { - FreeContextBuffer(pbMessage); - } - } - } - else - { - DEBUG_printf(("_sspiFree: AcceptSecurityContext failed: %x", status)); - } - } - else - { - DEBUG_printf(("_sspiFree: ApplyControlToken failed: %x", status)); - } - - DeleteSecurityContext(&conn->context); - conn->contextInitialized = FALSE; - } - - if (conn->decryptBuffer) - { - free(conn->decryptBuffer); - conn->decryptBuffer = NULL; - } - - if (conn->readBuffer) - { - free(conn->readBuffer); - conn->readBuffer = NULL; - } - - if (conn->sock != INVALID_SOCKET) - { - closesocket(conn->sock); - conn->sock = INVALID_SOCKET; - } - - free(conn); + conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID : + conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; } /* - * 'sspi_verify_certificate()' - Verify a server certificate + * 'http_sspi_verify()' - Verify a certificate. */ -static DWORD /* 0 - Error code (0 == No error) */ -sspi_verify_certificate(PCCERT_CONTEXT serverCert, - /* I - Server certificate */ - const CHAR *serverName, - /* I - Server name */ - DWORD dwCertFlags) - /* I - Verification flags */ + +static DWORD /* O - Error code (0 == No error) */ +http_sspi_verify( + PCCERT_CONTEXT cert, /* I - Server certificate */ + const char *common_name, /* I - Common name */ + DWORD dwCertFlags) /* I - Verification flags */ { - HTTPSPolicyCallbackData httpsPolicy; - /* HTTPS Policy Struct */ - CERT_CHAIN_POLICY_PARA policyPara; - /* Cert chain policy parameters */ - CERT_CHAIN_POLICY_STATUS policyStatus; - /* Cert chain policy status */ - CERT_CHAIN_PARA chainPara; - /* Used for searching and matching criteria */ - PCCERT_CHAIN_CONTEXT chainContext = NULL; + HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */ + CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */ + CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */ + CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */ + PCCERT_CHAIN_CONTEXT chainContext = NULL; /* Certificate chain */ - PWSTR serverNameUnicode = NULL; - /* Unicode server name */ - LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, - szOID_SERVER_GATED_CRYPTO, - szOID_SGC_NETSCAPE }; + PWSTR commonNameUnicode = NULL; + /* Unicode common name */ + LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, + szOID_SERVER_GATED_CRYPTO, + szOID_SGC_NETSCAPE }; /* How are we using this certificate? */ - DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); + DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); /* Number of ites in rgszUsages */ - DWORD count; /* 32 bit count variable */ - DWORD status; /* Return value */ + DWORD count; /* 32 bit count variable */ + DWORD status; /* Return value */ - if (!serverCert) - { - status = SEC_E_WRONG_PRINCIPAL; - goto cleanup; - } + + if (!cert) + return (SEC_E_WRONG_PRINCIPAL); /* - * Convert server name to unicode. + * Convert common name to Unicode. */ - if (!serverName || (strlen(serverName) == 0)) - { - status = SEC_E_WRONG_PRINCIPAL; - goto cleanup; - } - count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, NULL, 0); - serverNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR)); - if (!serverNameUnicode) - { - status = SEC_E_INSUFFICIENT_MEMORY; - goto cleanup; - } - count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, serverNameUnicode, count); - if (count == 0) + if (!common_name || !*common_name) + return (SEC_E_WRONG_PRINCIPAL); + + count = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0); + commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR)); + if (!commonNameUnicode) + return (SEC_E_INSUFFICIENT_MEMORY); + + if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count)) { - status = SEC_E_WRONG_PRINCIPAL; - goto cleanup; + LocalFree(commonNameUnicode); + return (SEC_E_WRONG_PRINCIPAL); } /* * Build certificate chain. */ + ZeroMemory(&chainPara, sizeof(chainPara)); + chainPara.cbSize = sizeof(chainPara); chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; - if (!CertGetCertificateChain(NULL, serverCert, NULL, serverCert->hCertStore, - &chainPara, 0, NULL, &chainContext)) + if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext)) { status = GetLastError(); DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status)); - goto cleanup; + + LocalFree(commonNameUnicode); + return (status); } /* * Validate certificate chain. */ + ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData)); httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData); httpsPolicy.dwAuthType = AUTHTYPE_SERVER; httpsPolicy.fdwChecks = dwCertFlags; - httpsPolicy.pwszServerName = serverNameUnicode; + httpsPolicy.pwszServerName = commonNameUnicode; memset(&policyPara, 0, sizeof(policyPara)); policyPara.cbSize = sizeof(policyPara); @@ -2201,32 +1920,25 @@ sspi_verify_certificate(PCCERT_CONTEXT serverCert, memset(&policyStatus, 0, sizeof(policyStatus)); policyStatus.cbSize = sizeof(policyStatus); - if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, - &policyPara, &policyStatus)) + if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus)) { status = GetLastError(); DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status)); - goto cleanup; } - - if (policyStatus.dwError) - { + else if (policyStatus.dwError) status = policyStatus.dwError; - goto cleanup; - } - - status = SEC_E_OK; - -cleanup: + else + status = SEC_E_OK; if (chainContext) CertFreeCertificateChain(chainContext); - if (serverNameUnicode) - LocalFree(serverNameUnicode); + if (commonNameUnicode) + LocalFree(commonNameUnicode); return (status); } +#endif // 0 /* diff --git a/scheduler/tls-darwin.c b/scheduler/tls-darwin.c deleted file mode 100644 index 9d62498f5..000000000 --- a/scheduler/tls-darwin.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * "$Id$" - * - * TLS support code for the CUPS scheduler on OS X. - * - * Copyright 2007-2013 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/". - * - * Contents: - * - * cupsdEndTLS() - Shutdown a secure session with the client. - * cupsdStartTLS() - Start a secure session with the client. - * copy_cdsa_certificate() - Copy a SSL/TLS certificate from the System - * keychain. - * make_certificate() - Make a self-signed SSL/TLS certificate. - */ - - -/* - * Local functions... - */ - -static CFArrayRef copy_cdsa_certificate(cupsd_client_t *con); -static int make_certificate(cupsd_client_t *con); - - -/* - * 'cupsdEndTLS()' - Shutdown a secure session with the client. - */ - -int /* O - 1 on success, 0 on error */ -cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ -{ - while (SSLClose(con->http->tls) == errSSLWouldBlock) - usleep(1000); - - CFRelease(con->http->tls); - con->http->tls = NULL; - - if (con->http->tls_credentials) - CFRelease(con->http->tls_credentials); - - return (1); -} - - -/* - * 'cupsdStartTLS()' - Start a secure session with the client. - */ - -int /* O - 1 on success, 0 on error */ -cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ -{ - OSStatus error = 0; /* Error code */ - SecTrustRef peerTrust; /* Peer certificates */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", - con->number); - - con->http->encryption = HTTP_ENCRYPTION_ALWAYS; - - con->http->tls_credentials = copy_cdsa_certificate(con); - - if (!con->http->tls_credentials) - { - /* - * No keychain (yet), make a self-signed certificate... - */ - - if (make_certificate(con)) - con->http->tls_credentials = copy_cdsa_certificate(con); - } - - if (!con->http->tls_credentials) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Could not find signing key in keychain \"%s\"", - ServerCertificate); - error = errSSLBadConfiguration; - } - - if (!error) - con->http->tls = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, - kSSLStreamType); - - if (!error) - error = SSLSetIOFuncs(con->http->tls, _httpReadCDSA, _httpWriteCDSA); - - if (!error) - error = SSLSetConnection(con->http->tls, HTTP(con)); - - if (!error) - error = SSLSetCertificate(con->http->tls, con->http->tls_credentials); - - if (!error) - { - /* - * Perform SSL/TLS handshake - */ - - while ((error = SSLHandshake(con->http->tls)) == errSSLWouldBlock) - usleep(1000); - } - - if (error) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to encrypt connection from %s - %s (%d)", - con->http->hostname, cssmErrorString(error), (int)error); - - con->http->error = error; - con->http->status = HTTP_ERROR; - - if (con->http->tls) - { - CFRelease(con->http->tls); - con->http->tls = NULL; - } - - if (con->http->tls_credentials) - { - CFRelease(con->http->tls_credentials); - con->http->tls_credentials = NULL; - } - - return (0); - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", - con->http->hostname); - - if (!SSLCopyPeerTrust(con->http->tls, &peerTrust) && peerTrust) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates.", - (int)SecTrustGetCertificateCount(peerTrust)); - CFRelease(peerTrust); - } - else - cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates."); - - return (1); -} - - -/* - * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System - * keychain. - */ - -static CFArrayRef /* O - Array of certificates */ -copy_cdsa_certificate( - cupsd_client_t *con) /* I - Client connection */ -{ - OSStatus err; /* Error info */ - SecKeychainRef keychain = NULL;/* Keychain reference */ - SecIdentitySearchRef search = NULL; /* Search reference */ - SecIdentityRef identity = NULL;/* Identity */ - CFArrayRef certificates = NULL; - /* Certificate array */ - SecPolicyRef policy = NULL; /* Policy ref */ - CFStringRef servername = NULL; - /* Server name */ - CFMutableDictionaryRef query = NULL; /* Query qualifiers */ - CFArrayRef list = NULL; /* Keychain list */ -# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - char localname[1024];/* Local hostname */ -# endif /* HAVE_DNSSD || HAVE_AVAHI */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "copy_cdsa_certificate: Looking for certs for \"%s\".", - con->servername); - - if ((err = SecKeychainOpen(ServerCertificate, &keychain))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)", - ServerCertificate, cssmErrorString(err), (int)err); - goto cleanup; - } - - servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername, - kCFStringEncodingUTF8); - - policy = SecPolicyCreateSSL(1, servername); - - if (servername) - CFRelease(servername); - - if (!policy) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); - goto cleanup; - } - - if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary"); - goto cleanup; - } - - list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, - &kCFTypeArrayCallBacks); - - CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); - CFDictionaryAddValue(query, kSecMatchPolicy, policy); - CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); - CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); - CFDictionaryAddValue(query, kSecMatchSearchList, list); - - CFRelease(list); - - err = SecItemCopyMatching(query, (CFTypeRef *)&identity); - -# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - if (err && DNSSDHostName) - { - /* - * Search for the connection server name failed; try the DNS-SD .local - * hostname instead... - */ - - snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "copy_cdsa_certificate: Looking for certs for \"%s\".", - localname); - - servername = CFStringCreateWithCString(kCFAllocatorDefault, localname, - kCFStringEncodingUTF8); - - CFRelease(policy); - - policy = SecPolicyCreateSSL(1, servername); - - if (servername) - CFRelease(servername); - - if (!policy) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); - goto cleanup; - } - - CFDictionarySetValue(query, kSecMatchPolicy, policy); - - err = SecItemCopyMatching(query, (CFTypeRef *)&identity); - } -# endif /* HAVE_DNSSD || HAVE_AVAHI */ - - if (err) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Cannot find signing key in keychain \"%s\": %s (%d)", - ServerCertificate, cssmErrorString(err), (int)err); - goto cleanup; - } - - if (CFGetTypeID(identity) != SecIdentityGetTypeID()) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure."); - goto cleanup; - } - - if ((certificates = CFArrayCreate(NULL, (const void **)&identity, - 1, &kCFTypeArrayCallBacks)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array"); - goto cleanup; - } - - cleanup : - - if (keychain) - CFRelease(keychain); - if (search) - CFRelease(search); - if (identity) - CFRelease(identity); - - if (policy) - CFRelease(policy); - if (query) - CFRelease(query); - - return (certificates); -} - - -/* - * 'make_certificate()' - Make a self-signed SSL/TLS certificate. - */ - -static int /* O - 1 on success, 0 on failure */ -make_certificate(cupsd_client_t *con) /* I - Client connection */ -{ -# ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE - int status = 0; /* Return status */ - OSStatus err; /* Error code (if any) */ -# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - char localname[1024];/* Local hostname */ -# endif /* HAVE_DNSSD || HAVE_AVAHI */ - const char *servername; /* Name of server in cert */ - CFStringRef cfservername = NULL; - /* CF string for server name */ - SecIdentityRef ident = NULL; /* Identity */ - SecKeyRef publicKey = NULL, - /* Public key */ - privateKey = NULL; - /* Private key */ - CFMutableDictionaryRef keyParams = NULL; - /* Key generation parameters */ - - - cupsdLogMessage(CUPSD_LOG_INFO, - "Generating SSL server key and certificate."); - -# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) - { - snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); - servername = localname; - } - else -# endif /* HAVE_DNSSD || HAVE_AVAHI */ - servername = con->servername; - - cfservername = CFStringCreateWithCString(kCFAllocatorDefault, servername, - kCFStringEncodingUTF8); - if (!cfservername) - goto cleanup; - - /* - * Create a public/private key pair... - */ - - keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!keyParams) - goto cleanup; - - CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA); - CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048")); - CFDictionaryAddValue(keyParams, kSecAttrLabel, - CFSTR("CUPS Self-Signed Certificate")); - - err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey); - if (err != noErr) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "SecKeyGeneratePair returned %ld.", - (long)err); - goto cleanup; - } - - /* - * Create a self-signed certificate using the public/private key pair... - */ - - CFIndex usageInt = kSecKeyUsageAll; - CFNumberRef usage = CFNumberCreate(alloc, kCFNumberCFIndexType, &usageInt); - CFDictionaryRef certParams = CFDictionaryCreateMutable(kCFAllocatorDefault, - kSecCSRBasicContraintsPathLen, CFINT(0), - kSecSubjectAltName, cfservername, - kSecCertificateKeyUsage, usage, - NULL, NULL); - CFRelease(usage); - - const void *ca_o[] = { kSecOidOrganization, CFSTR("") }; - const void *ca_cn[] = { kSecOidCommonName, cfservername }; - CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); - CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); - const void *ca_dn_array[2]; - - ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, - 1, NULL); - ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, - 1, NULL); - - CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, - NULL); - SecCertificateRef cert = SecGenerateSelfSignedCertificate(subject, certParams, - publicKey, - privateKey); - CFRelease(subject); - CFRelease(certParams); - - if (!cert) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "SecGenerateSelfSignedCertificate failed."); - goto cleanup; - } - - ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey); - - if (ident) - cupsdLogMessage(CUPSD_LOG_INFO, - "Created SSL server certificate file \"%s\".", - ServerCertificate); - - /* - * Cleanup and return... - */ - -cleanup: - - if (cfservername) - CFRelease(cfservername); - - if (keyParams) - CFRelease(keyParams); - - if (ident) - CFRelease(ident); - - if (cert) - CFRelease(cert); - - if (publicKey) - CFRelease(publicKey); - - if (privateKey) - CFRelease(publicKey); - - if (!status) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate."); - - return (status); - -# else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ - int pid, /* Process ID of command */ - status; /* Status of command */ - char command[1024], /* Command */ - *argv[4], /* Command-line arguments */ - *envp[MAX_ENV + 1], /* Environment variables */ - keychain[1024], /* Keychain argument */ - infofile[1024], /* Type-in information for cert */ -# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - localname[1024], /* Local hostname */ -# endif /* HAVE_DNSSD || HAVE_AVAHI */ - *servername; /* Name of server in cert */ - cups_file_t *fp; /* Seed/info file */ - int infofd; /* Info file descriptor */ - - -# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) - { - snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); - servername = localname; - } - else -# endif /* HAVE_DNSSD || HAVE_AVAHI */ - servername = con->servername; - - /* - * Run the "certtool" command to generate a self-signed certificate... - */ - - if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "No SSL certificate and certtool command not found."); - return (0); - } - - /* - * Create a file with the certificate information fields... - * - * Note: This assumes that the default questions are asked by the certtool - * command... - */ - - if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create certificate information file %s - %s", - infofile, strerror(errno)); - return (0); - } - - cupsFilePrintf(fp, - "%s\n" /* Enter key and certificate label */ - "r\n" /* Generate RSA key pair */ - "2048\n" /* Key size in bits */ - "y\n" /* OK (y = yes) */ - "b\n" /* Usage (b=signing/encryption) */ - "s\n" /* Sign with SHA1 */ - "y\n" /* OK (y = yes) */ - "%s\n" /* Common name */ - "\n" /* Country (default) */ - "\n" /* Organization (default) */ - "\n" /* Organizational unit (default) */ - "\n" /* State/Province (default) */ - "%s\n" /* Email address */ - "y\n", /* OK (y = yes) */ - servername, servername, ServerAdmin); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, - "Generating SSL server key and certificate."); - - snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate); - - argv[0] = "certtool"; - argv[1] = "c"; - argv[2] = keychain; - argv[3] = NULL; - - cupsdLoadEnv(envp, MAX_ENV); - - infofd = open(infofile, O_RDONLY); - - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, - NULL, &pid)) - { - close(infofd); - unlink(infofile); - return (0); - } - - close(infofd); - unlink(infofile); - - while (waitpid(pid, &status, 0) < 0) - if (errno != EINTR) - { - status = 1; - break; - } - - cupsdFinishProcess(pid, command, sizeof(command), NULL); - - if (status) - { - if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate - " - "the certtool command stopped with status %d.", - WEXITSTATUS(status)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate - " - "the certtool command crashed on signal %d.", - WTERMSIG(status)); - } - else - { - cupsdLogMessage(CUPSD_LOG_INFO, - "Created SSL server certificate file \"%s\".", - ServerCertificate); - } - - return (!status); -# endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ -} - - -/* - * End of "$Id$". - */ diff --git a/scheduler/tls-gnutls.c b/scheduler/tls-gnutls.c deleted file mode 100644 index 36518cd0e..000000000 --- a/scheduler/tls-gnutls.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * "$Id$" - * - * TLS support code for the CUPS scheduler using GNU TLS. - * - * Copyright 2007-2012 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/". - * - * Contents: - * - * cupsdEndTLS() - Shutdown a secure session with the client. - * cupsdStartTLS() - Start a secure session with the client. - * make_certificate() - Make a self-signed SSL/TLS certificate. - */ - - -/* - * Local functions... - */ - -static int make_certificate(cupsd_client_t *con); - - -/* - * 'cupsdEndTLS()' - Shutdown a secure session with the client. - */ - -int /* O - 1 on success, 0 on error */ -cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ -{ - int error; /* Error code */ - gnutls_certificate_server_credentials *credentials; - /* TLS credentials */ - - - credentials = (gnutls_certificate_server_credentials *) - (con->http.tls_credentials); - - error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR); - switch (error) - { - case GNUTLS_E_SUCCESS: - cupsdLogMessage(CUPSD_LOG_DEBUG, - "SSL shutdown successful!"); - break; - default: - cupsdLogMessage(CUPSD_LOG_ERROR, - "SSL shutdown failed: %s", gnutls_strerror(error)); - break; - } - - gnutls_deinit(con->http.tls); - con->http.tls = NULL; - - gnutls_certificate_free_credentials(*credentials); - free(credentials); - - return (1); -} - - -/* - * 'cupsdStartTLS()' - Start a secure session with the client. - */ - -int /* O - 1 on success, 0 on error */ -cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ -{ - int status; /* Error code */ - gnutls_certificate_server_credentials *credentials; - /* TLS credentials */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", - con->http.fd); - - /* - * Verify that we have a certificate... - */ - - if (access(ServerKey, 0) || access(ServerCertificate, 0)) - { - /* - * Nope, make a self-signed certificate... - */ - - if (!make_certificate(con)) - return (0); - } - - /* - * Create the SSL object and perform the SSL handshake... - */ - - credentials = (gnutls_certificate_server_credentials *) - malloc(sizeof(gnutls_certificate_server_credentials)); - if (credentials == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to encrypt connection from %s - %s", - con->http.hostname, strerror(errno)); - - return (0); - } - - gnutls_certificate_allocate_credentials(credentials); - gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, - ServerKey, GNUTLS_X509_FMT_PEM); - - gnutls_init(&con->http.tls, GNUTLS_SERVER); - gnutls_set_default_priority(con->http.tls); - - gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials); - gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con)); - gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS); - gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS); - - while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS) - { - if (gnutls_error_is_fatal(status)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to encrypt connection from %s - %s", - con->http.hostname, gnutls_strerror(status)); - - gnutls_deinit(con->http.tls); - gnutls_certificate_free_credentials(*credentials); - con->http.tls = NULL; - free(credentials); - return (0); - } - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", - con->http.hostname); - - con->http.tls_credentials = credentials; - return (1); -} - - -/* - * 'make_certificate()' - Make a self-signed SSL/TLS certificate. - */ - -static int /* O - 1 on success, 0 on failure */ -make_certificate(cupsd_client_t *con) /* I - Client connection */ -{ - gnutls_x509_crt crt; /* Self-signed certificate */ - gnutls_x509_privkey key; /* Encryption key */ - cups_lang_t *language; /* Default language info */ - cups_file_t *fp; /* Key/cert file */ - unsigned char buffer[8192]; /* Buffer for x509 data */ - size_t bytes; /* Number of bytes of data */ - unsigned char serial[4]; /* Serial number buffer */ - time_t curtime; /* Current time */ - int result; /* Result of GNU TLS calls */ - - - /* - * Create the encryption key... - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key..."); - - gnutls_x509_privkey_init(&key); - gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); - - /* - * Save it... - */ - - bytes = sizeof(buffer); - - if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, - buffer, &bytes)) < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s", - gnutls_strerror(result)); - gnutls_x509_privkey_deinit(key); - return (0); - } - else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL) - { - cupsFileWrite(fp, (char *)buffer, bytes); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", - ServerKey); - } - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key file \"%s\" - %s", - ServerKey, strerror(errno)); - gnutls_x509_privkey_deinit(key); - return (0); - } - - /* - * Create the self-signed certificate... - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate..."); - - language = cupsLangDefault(); - curtime = time(NULL); - serial[0] = curtime >> 24; - serial[1] = curtime >> 16; - serial[2] = curtime >> 8; - serial[3] = curtime; - - gnutls_x509_crt_init(&crt); - if (strlen(language->language) == 5) - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, - language->language + 3, 2); - else - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, - "US", 2); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, - ServerName, strlen(ServerName)); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, - ServerName, strlen(ServerName)); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, - 0, "Unknown", 7); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, - "Unknown", 7); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, - "Unknown", 7); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, - ServerAdmin, strlen(ServerAdmin)); - gnutls_x509_crt_set_key(crt, key); - gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); - gnutls_x509_crt_set_activation_time(crt, curtime); - gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); - gnutls_x509_crt_set_ca_status(crt, 0); - gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, - ServerName); - gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); - gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); - gnutls_x509_crt_set_version(crt, 3); - - bytes = sizeof(buffer); - if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) - gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); - - gnutls_x509_crt_sign(crt, crt, key); - - /* - * Save it... - */ - - bytes = sizeof(buffer); - if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, - buffer, &bytes)) < 0) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to export SSL server certificate - %s", - gnutls_strerror(result)); - else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL) - { - cupsFileWrite(fp, (char *)buffer, bytes); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, - "Created SSL server certificate file \"%s\"...", - ServerCertificate); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server certificate file \"%s\" - %s", - ServerCertificate, strerror(errno)); - - /* - * Cleanup... - */ - - gnutls_x509_crt_deinit(crt); - gnutls_x509_privkey_deinit(key); - - return (1); -} - - -/* - * End of "$Id$". - */ diff --git a/xcode/CUPS.xcodeproj/project.pbxproj b/xcode/CUPS.xcodeproj/project.pbxproj index 9ad83ae1e..6914ff670 100644 --- a/xcode/CUPS.xcodeproj/project.pbxproj +++ b/xcode/CUPS.xcodeproj/project.pbxproj @@ -1451,8 +1451,6 @@ 727EF04D192E3602001EF690 /* testlpd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testlpd.c; path = ../scheduler/testlpd.c; sourceTree = ""; }; 727EF04E192E3602001EF690 /* testspeed.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testspeed.c; path = ../scheduler/testspeed.c; sourceTree = ""; }; 727EF04F192E3602001EF690 /* testsub.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testsub.c; path = ../scheduler/testsub.c; sourceTree = ""; }; - 728FB7E0153600FA005426E1 /* tls-darwin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tls-darwin.c"; path = "../scheduler/tls-darwin.c"; sourceTree = ""; }; - 728FB7E1153600FA005426E1 /* tls-gnutls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tls-gnutls.c"; path = "../scheduler/tls-gnutls.c"; sourceTree = ""; }; 728FB7EC1536161C005426E1 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = ""; }; 728FB7EF1536167A005426E1 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = ""; }; 728FB7F01536167A005426E1 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = /usr/lib/libresolv.dylib; sourceTree = ""; }; @@ -2179,8 +2177,6 @@ 72220F8D13330B0C00FCA411 /* subscriptions.h */, 72220F8E13330B0C00FCA411 /* sysman.c */, 72220F8F13330B0C00FCA411 /* sysman.h */, - 728FB7E0153600FA005426E1 /* tls-darwin.c */, - 728FB7E1153600FA005426E1 /* tls-gnutls.c */, ); name = cupsd; path = .; -- 2.39.2