support.
Require TLS support.
#
# Common makefile definitions for CUPS.
#
-# Copyright © 2021 by OpenPrinting.
+# Copyright © 2021-2023 by OpenPrinting.
# Copyright © 2007-2019 by Apple Inc.
# Copyright © 1997-2007 by Easy Software Products, all rights reserved.
#
INSTALLSTATIC = @INSTALLSTATIC@
-#
-# IPP backend aliases...
-#
-
-IPPALIASES = @IPPALIASES@
-
-
#
# ippeveprinter commands...
#
for file in $(UBACKENDS); do \
$(INSTALL_BIN) $$file $(SERVERBIN)/backend; \
done
- for file in $(IPPALIASES); do \
- $(RM) $(SERVERBIN)/backend/$$file; \
- $(LN) ipp $(SERVERBIN)/backend/$$file; \
- done
- if test "x$(DNSSD_BACKEND)" != x -a `uname` = Darwin; then \
- $(RM) $(SERVERBIN)/backend/mdns; \
- $(LN) $(DNSSD_BACKEND) $(SERVERBIN)/backend/mdns; \
- fi
+ $(RM) $(SERVERBIN)/backend/ipps; \
+ $(LN) ipp $(SERVERBIN)/backend/ipps; \
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
for file in $(RBACKENDS) $(UBACKENDS); do \
echo Installing XPC backends in $(SERVERBIN)/apple
$(INSTALL_DIR) -m 755 $(SERVERBIN)/apple
$(INSTALL_BIN) ipp $(SERVERBIN)/apple
- for file in $(IPPALIASES); do \
- $(RM) $(SERVERBIN)/apple/$$file; \
- $(LN) ipp $(SERVERBIN)/apple/$$file; \
- done
+ $(RM) $(SERVERBIN)/apple/ipps
+ $(LN) ipp $(SERVERBIN)/apple/ipps
#
uninstall:
$(RM) $(SERVERBIN)/apple/ipp
- for file in $(IPPALIASES); do \
- $(RM) $(SERVERBIN)/apple/$$file; \
- done
+ $(RM) $(SERVERBIN)/apple/ipps
-$(RMDIR) $(SERVERBIN)/apple
for file in $(RBACKENDS) $(UBACKENDS); do \
$(RM) $(SERVERBIN)/backend/$$file; \
done
- for file in $(IPPALIASES); do \
- $(RM) $(SERVERBIN)/backend/$$file; \
- done
+ $(RM) $(SERVERBIN)/backend/ipps
-$(RMDIR) $(SERVERBIN)/backend
-$(RMDIR) $(SERVERBIN)
echo Linking $@...
$(LD_CC) $(ALL_LDFLAGS) -o ipp ipp.o libbackend.a $(LINKCUPS)
$(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@
- $(RM) http https ipps
- for file in $(IPPALIASES); do \
- $(LN) ipp $$file; \
- done
+ $(RM) ipps
+ $(LN) ipp ipps
#
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
if (http)
httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'U' : /* Username */
switch (ch = *opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'U' : /* Username */
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'P' : /* Cancel jobs on a printer */
dnl information.
dnl
-AC_ARG_WITH([tls], AS_HELP_STRING([--with-tls=...], [use cdsa (macOS), gnutls, or openssl for TLS support]))
+AC_ARG_WITH([tls], AS_HELP_STRING([--with-tls=...], [use gnutls or openssl for TLS support]))
AS_IF([test "x$with_tls" = x], [
with_tls="yes"
-], [test "$with_tls" != cdsa -a "$with_tls" != gnutls -a "$with_tls" != openssl -a "$with_tls" != no -a "$with_tls" != yes], [
+], [test "$with_tls" != gnutls -a "$with_tls" != openssl -a "$with_tls" != yes], [
AC_MSG_ERROR([Unsupported --with-tls value "$with_tls" specified.])
])
TLSLIBS="$($PKGCONFIG --libs openssl)"
TLSFLAGS="$($PKGCONFIG --cflags openssl)"
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES openssl"
- AC_DEFINE([HAVE_TLS], [1], [Do we support TLS?])
AC_DEFINE([HAVE_OPENSSL], [1], [Do we have the OpenSSL library?])
], [
AC_MSG_RESULT([no])
with_tls="openssl"
TLSLIBS="-lssl -lcrypto"
PKGCONFIG_LIBS_STATIC="$PKGCONFIG_LIBS_STATIC $TLSLIBS"
- AC_DEFINE([HAVE_TLS], [1], [Do we support TLS?])
AC_DEFINE([HAVE_OPENSSL], [1], [Do we have the OpenSSL library?])
])
])
TLSLIBS="$($PKGCONFIG --libs gnutls)"
TLSFLAGS="$($PKGCONFIG --cflags gnutls)"
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES gnutls"
- AC_DEFINE([HAVE_TLS], [1], [Do we support TLS?])
AC_DEFINE([HAVE_GNUTLS], [1], [Do we have the GNU TLS library?])
], [
AC_MSG_RESULT([no])
TLSLIBS="$($LIBGNUTLSCONFIG --libs)"
TLSFLAGS="$($LIBGNUTLSCONFIG --cflags)"
PKGCONFIG_LIBS_STATIC="$PKGCONFIG_LIBS_STATIC $TLSLIBS"
- AC_DEFINE([HAVE_TLS], [1], [Do we support TLS?])
AC_DEFINE([HAVE_GNUTLS], [1], [Do we have the GNU TLS library?])
])
])
])
-dnl Finally try using CSDA SSL (macOS)...
-AS_IF([test $with_tls = yes -o $with_tls = cdsa], [
- dnl Look for CDSA...
- AS_IF([test $host_os_name = darwin], [
- AC_CHECK_HEADER([Security/SecureTransport.h], [
- have_tls="1"
- with_tls="cdsa"
- AC_DEFINE([HAVE_TLS], [1], [Do we support TLS?])
- AC_DEFINE([HAVE_CDSASSL], [1], [Do we have the macOS SecureTransport API?])
- CUPS_SERVERKEYCHAIN="/Library/Keychains/System.keychain"
-
- dnl Check for the various security headers...
- AC_CHECK_HEADER([Security/SecCertificate.h], [
- AC_DEFINE([HAVE_SECCERTIFICATE_H], [1], [Have the <Security/SecCertificate.h> header?])
- ])
- AC_CHECK_HEADER([Security/SecItem.h], [
- AC_DEFINE([HAVE_SECITEM_H], [1], [Have the <Security/SecItem.h> header?])
- ])
- AC_CHECK_HEADER([Security/SecPolicy.h], [
- AC_DEFINE([HAVE_SECPOLICY_H], [1], [Have the <Security/SecPolicy.h header?])
- ])
- ])
- ], [test $with_tls = cdsa], [
- AC_MSG_ERROR([--with-tls=cdsa is not compatible with your host operating system.])
- ])
-])
-
-IPPALIASES="http"
AS_IF([test $have_tls = 1], [
AC_MSG_NOTICE([ Using TLSLIBS="$TLSLIBS"])
AC_MSG_NOTICE([ Using TLSFLAGS="$TLSFLAGS"])
- IPPALIASES="http https ipps"
-], [test $with_tls = yes], [
- AC_MSG_ERROR([--with-tls=yes was specified but no compatible TLS libraries could be found.])
+], [
+ AC_MSG_ERROR([No compatible TLS libraries could be found.])
])
AC_SUBST([CUPS_SERVERKEYCHAIN])
-AC_SUBST([IPPALIASES])
AC_SUBST([TLSFLAGS])
AC_SUBST([TLSLIBS])
* Which encryption libraries do we have?
*/
-#undef HAVE_TLS
-#undef HAVE_CDSASSL
#undef HAVE_OPENSSL
#undef HAVE_GNUTLS
-#undef HAVE_SSPISSL
/*
EXPORT_TLSLIBS
TLSLIBS
TLSFLAGS
-IPPALIASES
CUPS_SERVERKEYCHAIN
LIBGNUTLSCONFIG
PTHREAD_FLAGS
--with-ldarchflags set program architecture flags
--with-domainsocket set unix domain socket name
--with-gssservicename set default gss service name
- --with-tls=... use cdsa (macOS), gnutls, or openssl for TLS support
+ --with-tls=... use gnutls or openssl for TLS support
--with-pam-module set the PAM module to use
--with-dnssd=... enable DNS Service Discovery support (avahi,
mdnsresponder, no, yes)
with_tls="yes"
-elif test "$with_tls" != cdsa -a "$with_tls" != gnutls -a "$with_tls" != openssl -a "$with_tls" != no -a "$with_tls" != yes
+elif test "$with_tls" != gnutls -a "$with_tls" != openssl -a "$with_tls" != yes
then :
as_fn_error $? "Unsupported --with-tls value \"$with_tls\" specified." "$LINENO" 5
TLSFLAGS="$($PKGCONFIG --cflags openssl)"
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES openssl"
-printf "%s\n" "#define HAVE_TLS 1" >>confdefs.h
-
-
printf "%s\n" "#define HAVE_OPENSSL 1" >>confdefs.h
TLSLIBS="-lssl -lcrypto"
PKGCONFIG_LIBS_STATIC="$PKGCONFIG_LIBS_STATIC $TLSLIBS"
-printf "%s\n" "#define HAVE_TLS 1" >>confdefs.h
-
-
printf "%s\n" "#define HAVE_OPENSSL 1" >>confdefs.h
TLSFLAGS="$($PKGCONFIG --cflags gnutls)"
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES gnutls"
-printf "%s\n" "#define HAVE_TLS 1" >>confdefs.h
-
-
printf "%s\n" "#define HAVE_GNUTLS 1" >>confdefs.h
TLSFLAGS="$($LIBGNUTLSCONFIG --cflags)"
PKGCONFIG_LIBS_STATIC="$PKGCONFIG_LIBS_STATIC $TLSLIBS"
-printf "%s\n" "#define HAVE_TLS 1" >>confdefs.h
-
-
printf "%s\n" "#define HAVE_GNUTLS 1" >>confdefs.h
fi
-if test $with_tls = yes -o $with_tls = cdsa
-then :
-
- if test $host_os_name = darwin
-then :
-
- ac_fn_c_check_header_compile "$LINENO" "Security/SecureTransport.h" "ac_cv_header_Security_SecureTransport_h" "$ac_includes_default"
-if test "x$ac_cv_header_Security_SecureTransport_h" = xyes
-then :
-
- have_tls="1"
- with_tls="cdsa"
-
-printf "%s\n" "#define HAVE_TLS 1" >>confdefs.h
-
-
-printf "%s\n" "#define HAVE_CDSASSL 1" >>confdefs.h
-
- CUPS_SERVERKEYCHAIN="/Library/Keychains/System.keychain"
-
- ac_fn_c_check_header_compile "$LINENO" "Security/SecCertificate.h" "ac_cv_header_Security_SecCertificate_h" "$ac_includes_default"
-if test "x$ac_cv_header_Security_SecCertificate_h" = xyes
-then :
-
-
-printf "%s\n" "#define HAVE_SECCERTIFICATE_H 1" >>confdefs.h
-
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "Security/SecItem.h" "ac_cv_header_Security_SecItem_h" "$ac_includes_default"
-if test "x$ac_cv_header_Security_SecItem_h" = xyes
-then :
-
-
-printf "%s\n" "#define HAVE_SECITEM_H 1" >>confdefs.h
-
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "Security/SecPolicy.h" "ac_cv_header_Security_SecPolicy_h" "$ac_includes_default"
-if test "x$ac_cv_header_Security_SecPolicy_h" = xyes
-then :
-
-
-printf "%s\n" "#define HAVE_SECPOLICY_H 1" >>confdefs.h
-
-
-fi
-
-
-fi
-
-
-elif test $with_tls = cdsa
-then :
-
- as_fn_error $? "--with-tls=cdsa is not compatible with your host operating system." "$LINENO" 5
-
-fi
-
-fi
-
-IPPALIASES="http"
if test $have_tls = 1
then :
printf "%s\n" "$as_me: Using TLSLIBS=\"$TLSLIBS\"" >&6;}
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using TLSFLAGS=\"$TLSFLAGS\"" >&5
printf "%s\n" "$as_me: Using TLSFLAGS=\"$TLSFLAGS\"" >&6;}
- IPPALIASES="http https ipps"
-elif test $with_tls = yes
-then :
+else $as_nop
- as_fn_error $? "--with-tls=yes was specified but no compatible TLS libraries could be found." "$LINENO" 5
+ as_fn_error $? "No compatible TLS libraries could be found." "$LINENO" 5
fi
-
EXPORT_TLSLIBS="$TLSLIBS"
ipp-private.h ../cups/cups.h file.h ipp.h http.h array.h language.h \
pwg.h http-private.h ../cups/language.h ../cups/http.h \
language-private.h ../cups/transcode.h pwg-private.h thread-private.h \
- debug-internal.h debug-private.h tls-darwin.c tls-darwin.h
+ debug-internal.h debug-private.h
transcode.o: transcode.c cups-private.h string-private.h ../config.h \
../cups/versioning.h array-private.h ../cups/array.h versioning.h \
ipp-private.h ../cups/cups.h file.h ipp.h http.h array.h language.h \
#
include Dependencies
-tls.o: tls-darwin.c tls-gnutls.c tls-openssl.c tls-sspi.c
+tls.o: tls-gnutls.c tls-openssl.c
* Constants...
*/
-# define CUPS_VERSION 2.0403
+# define CUPS_VERSION 2.0500
# define CUPS_VERSION_MAJOR 2
-# define CUPS_VERSION_MINOR 4
-# define CUPS_VERSION_PATCH 3
+# define CUPS_VERSION_MINOR 5
+# define CUPS_VERSION_PATCH 0
# define CUPS_BC_FD 3
/* Back-channel file descriptor for
int nfds, /* Number of files responded */
main_fd; /* File descriptor for lookups */
DNSServiceRef ipp_ref = NULL; /* IPP browser */
-# ifdef HAVE_TLS
DNSServiceRef ipps_ref = NULL; /* IPPS browser */
-# endif /* HAVE_TLS */
# ifdef HAVE_POLL
struct pollfd pfd; /* Polling data */
# else
# else /* HAVE_AVAHI */
int error; /* Error value */
AvahiServiceBrowser *ipp_ref = NULL; /* IPP browser */
-# ifdef HAVE_TLS
AvahiServiceBrowser *ipps_ref = NULL; /* IPPS browser */
-# endif /* HAVE_TLS */
# endif /* HAVE_MDNSRESPONDER */
#else
_cups_getdata_t data; /* Data for callback */
return (0);
}
-# ifdef HAVE_TLS
ipps_ref = data.main_ref;
if (DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0, "_ipps._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError)
{
return (0);
}
-# endif /* HAVE_TLS */
# else /* HAVE_AVAHI */
if ((data.simple_poll = avahi_simple_poll_new()) == NULL)
return (0);
}
-# ifdef HAVE_TLS
data.browsers ++;
if ((ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL)
{
return (0);
}
-# endif /* HAVE_TLS */
# endif /* HAVE_MDNSRESPONDER */
if (msec < 0)
if (ipp_ref)
DNSServiceRefDeallocate(ipp_ref);
-# ifdef HAVE_TLS
if (ipps_ref)
DNSServiceRefDeallocate(ipps_ref);
-# endif /* HAVE_TLS */
if (data.main_ref)
DNSServiceRefDeallocate(data.main_ref);
# else /* HAVE_AVAHI */
if (ipp_ref)
avahi_service_browser_free(ipp_ref);
-# ifdef HAVE_TLS
if (ipps_ref)
avahi_service_browser_free(ipps_ref);
-# endif /* HAVE_TLS */
if (data.client)
avahi_client_free(data.client);
break;
}
}
-
-#ifdef HAVE_TLS
else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
{
/*
if (!httpReconnect2(http, 30000, NULL))
httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
}
-#endif /* HAVE_TLS */
}
}
while (status == HTTP_STATUS_UNAUTHORIZED ||
continue;
}
-#ifdef HAVE_TLS
else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
{
/* Flush any error message... */
/* Try again, this time with encryption enabled... */
continue;
}
-#endif /* HAVE_TLS */
}
while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
continue;
}
-#ifdef HAVE_TLS
else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
{
/* Flush any error message... */
/* Try again, this time with encryption enabled... */
continue;
}
-#endif /* HAVE_TLS */
}
while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED || status == HTTP_STATUS_NONE);
httpClose(cg->http);
-#ifdef HAVE_TLS
_httpFreeCredentials(cg->tls_credentials);
-#endif /* HAVE_TLS */
cupsFileClose(cg->stdio_files[0]);
cupsFileClose(cg->stdio_files[1]);
static off_t http_set_length(http_t *http);
static void http_set_timeout(int fd, double timeout);
static void http_set_wait(http_t *http);
-
-#ifdef HAVE_TLS
static int http_tls_upgrade(http_t *http);
-#endif /* HAVE_TLS */
/*
void
_httpDisconnect(http_t *http) /* I - HTTP connection */
{
-#ifdef HAVE_TLS
if (http->tls)
_httpTLSStop(http);
-#endif /* HAVE_TLS */
httpAddrClose(NULL, http->fd);
{
DEBUG_printf(("httpEncryption(http=%p, e=%d)", (void *)http, e));
-#ifdef HAVE_TLS
if (!http)
return (0);
else
return (0);
}
-#else
- if (e == HTTP_ENCRYPTION_ALWAYS || e == HTTP_ENCRYPTION_REQUIRED)
- return (-1);
- else
- return (0);
-#endif /* HAVE_TLS */
}
http->state = HTTP_STATE_WAITING;
-#ifdef HAVE_TLS
if (http->tls)
_httpTLSStop(http);
-#endif /* HAVE_TLS */
httpAddrClose(NULL, http->fd);
return (0);
else if (http->used > 0)
return ((size_t)http->used);
-#ifdef HAVE_TLS
else if (http->tls)
return (_httpTLSPending(http));
-#endif /* HAVE_TLS */
return (0);
}
# endif /* !SO_NOSIGPIPE */
#endif /* _WIN32 */
-# ifdef HAVE_TLS
_httpTLSInitialize();
-# endif /* HAVE_TLS */
initialized = 1;
_cupsGlobalUnlock();
return (-1);
}
-#ifdef HAVE_TLS
if (http->tls)
{
DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS...");
_httpTLSStop(http);
}
-#endif /* HAVE_TLS */
/*
* Close any previously open socket...
http->hostaddr = &(addr->addr);
http->error = 0;
-#ifdef HAVE_TLS
if (http->encryption == HTTP_ENCRYPTION_ALWAYS)
{
/*
}
else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade)
return (http_tls_upgrade(http));
-#endif /* HAVE_TLS */
DEBUG_printf(("1httpReconnect2: Connected to %s:%d...",
httpAddrString(http->hostaddr, temp, sizeof(temp)),
if (!http || cupsArrayCount(credentials) < 1)
return (-1);
-#ifdef HAVE_TLS
_httpFreeCredentials(http->tls_credentials);
http->tls_credentials = _httpCreateCredentials(credentials);
-#endif /* HAVE_TLS */
return (http->tls_credentials ? 0 : -1);
}
if (!http || http->fd < 0)
return;
-#ifdef HAVE_TLS
if (http->tls)
_httpTLSStop(http);
-#endif /* HAVE_TLS */
#ifdef _WIN32
shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */
if (http->status < HTTP_STATUS_BAD_REQUEST)
http->digest_tries = 0;
-#ifdef HAVE_TLS
if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
{
if (_httpTLSStart(http) != 0)
*status = HTTP_STATUS_CONTINUE;
return (0);
}
-#endif /* HAVE_TLS */
if (http_set_length(http) < 0)
{
* Check the SSL/TLS buffers for data first...
*/
-#ifdef HAVE_TLS
if (http->tls && _httpTLSPending(http))
{
DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
return (1);
}
-#endif /* HAVE_TLS */
/*
* Then try doing a select() or poll() to poll the socket...
httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
}
-#ifdef HAVE_TLS
if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
status == HTTP_STATUS_SWITCHING_PROTOCOLS)
{
if (!http->fields[HTTP_FIELD_CONTENT_LENGTH])
httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
}
-#endif /* HAVE_TLS */
if (!http->fields[HTTP_FIELD_SERVER])
httpSetField(http, HTTP_FIELD_SERVER, http->default_fields[HTTP_FIELD_SERVER] ? http->default_fields[HTTP_FIELD_SERVER] : CUPS_MINIMAL);
do
{
-#ifdef HAVE_TLS
if (http->tls)
bytes = _httpTLSRead(http, buffer, (int)length);
else
-#endif /* HAVE_TLS */
- bytes = recv(http->fd, buffer, length, 0);
+ bytes = recv(http->fd, buffer, length, 0);
if (bytes < 0)
{
http->status = HTTP_STATUS_CONTINUE;
-#ifdef HAVE_TLS
if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
{
httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
}
-#endif /* HAVE_TLS */
if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
{
}
-#ifdef HAVE_TLS
/*
* 'http_tls_upgrade()' - Force upgrade to TLS encryption.
*/
else
return (ret);
}
-#endif /* HAVE_TLS */
/*
while (nfds <= 0);
}
-#ifdef HAVE_TLS
if (http->tls)
bytes = _httpTLSWrite(http, buffer, (int)length);
else
-#endif /* HAVE_TLS */
- bytes = send(http->fd, buffer, length, 0);
+ bytes = send(http->fd, buffer, length, 0);
DEBUG_printf(("8http_write: Write of " CUPS_LLFMT " bytes returned " CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
else
http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
}
-
-#ifdef HAVE_TLS
else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
{
/*
if (!httpReconnect2(http, 30000, NULL))
httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
}
-#endif /* HAVE_TLS */
}
if (response)
return (HTTP_STATUS_ERROR);
}
-#ifdef HAVE_TLS
/*
* See if we have an auth-info attribute and are communicating over
* a non-local link. If so, encrypt the link so that we can pass
DEBUG_puts("1cupsSendRequest: Unable to encrypt connection.");
return (HTTP_STATUS_SERVICE_UNAVAILABLE);
}
-#endif /* HAVE_TLS */
/*
* Reconnect if the last response had a "Connection: close"...
}
break;
-#ifdef HAVE_TLS
case HTTP_STATUS_UPGRADE_REQUIRED :
/*
* Flush any error message, reconnect, and then upgrade with
return (HTTP_STATUS_SERVICE_UNAVAILABLE);
}
break;
-#endif /* HAVE_TLS */
case HTTP_STATUS_EXPECTATION_FAILED :
/*
continue;
}
-#ifdef HAVE_TLS
else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
{
/* Flush any error message... */
/* Try again, this time with encryption enabled... */
continue;
}
-#endif /* HAVE_TLS */
}
while (status == HTTP_STATUS_UNAUTHORIZED ||
status == HTTP_STATUS_UPGRADE_REQUIRED);
continue;
}
-#ifdef HAVE_TLS
else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
{
/* Flush any error message... */
/* Try again, this time with encryption enabled... */
continue;
}
-#endif /* HAVE_TLS */
}
while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
+++ /dev/null
-/*
- * TLS support code for CUPS on macOS.
- *
- * Copyright © 2021-2023 by OpenPrinting
- * Copyright © 2007-2021 by Apple Inc.
- * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
- *
- * Licensed under Apache License v2.0. See the file "LICENSE" for more
- * information.
- */
-
-/**** This file is included from tls.c ****/
-
-/*
- * Include necessary headers...
- */
-
-#include <spawn.h>
-#include "tls-darwin.h"
-
-/*
- * Constants, very secure stuff...
- */
-
-#define _CUPS_CDSA_PASSWORD "42" /* CUPS keychain password */
-#define _CUPS_CDSA_PASSLEN 2 /* Length of keychain password */
-
-
-/*
- * Local globals...
- */
-
-static int tls_auto_create = 0;
- /* Auto-create self-signed certs? */
-static char *tls_common_name = NULL;
- /* Default common name */
-#if TARGET_OS_OSX
-static int tls_cups_keychain = 0;
- /* Opened the CUPS keychain? */
-static SecKeychainRef tls_keychain = NULL;
- /* Server cert keychain */
-#else
-static SecIdentityRef tls_selfsigned = NULL;
- /* Temporary self-signed cert */
-#endif /* TARGET_OS_OSX */
-static char *tls_keypath = NULL;
- /* Server cert keychain path */
-static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
- /* Mutex for keychain/certs */
-static int tls_options = -1,/* Options for TLS connections */
- tls_min_version = _HTTP_TLS_1_0,
- tls_max_version = _HTTP_TLS_MAX;
-
-
-/*
- * Local functions...
- */
-
-static CFArrayRef http_cdsa_copy_server(const char *common_name);
-static SecCertificateRef http_cdsa_create_credential(http_credential_t *credential);
-#if TARGET_OS_OSX
-static const char *http_cdsa_default_path(char *buffer, size_t bufsize);
-static SecKeychainRef http_cdsa_open_keychain(const char *path, char *filename, size_t filesize);
-static SecKeychainRef http_cdsa_open_system_keychain(void);
-#endif /* TARGET_OS_OSX */
-static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength);
-static int http_cdsa_set_credentials(http_t *http);
-static OSStatus http_cdsa_write(SSLConnectionRef connection, const void *data, size_t *dataLength);
-
-
-/*
- * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
- *
- * @since CUPS 2.0/OS 10.10@
- */
-
-int /* O - 1 on success, 0 on failure */
-cupsMakeServerCredentials(
- const char *path, /* I - 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 */
-{
-#if TARGET_OS_OSX
- int pid, /* Process ID of command */
- status, /* Status of command */
- i; /* Looping var */
- char command[1024], /* Command */
- *argv[5], /* Command-line arguments */
- *envp[1000], /* Environment variables */
- days[32], /* CERTTOOL_EXPIRATION_DAYS env var */
- keychain[1024], /* Keychain argument */
- infofile[1024], /* Type-in information for cert */
- filename[1024]; /* Default keychain path */
- cups_file_t *fp; /* Seed/info file */
-
-
- DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, (void *)alt_names, (int)expiration_date));
-
- (void)num_alt_names;
- (void)alt_names;
-
- if (!path)
- path = http_cdsa_default_path(filename, sizeof(filename));
-
- /*
- * Run the "certtool" command to generate a self-signed certificate...
- */
-
- if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command)))
- 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)
- return (0);
-
- cupsFilePrintf(fp,
- "CUPS Self-Signed Certificate\n"
- /* Enter key and certificate label */
- "r\n" /* Generate RSA key pair */
- "2048\n" /* 2048 bit encryption key */
- "y\n" /* OK (y = yes) */
- "b\n" /* Usage (b=signing/encryption) */
- "2\n" /* Sign with SHA256 */
- "y\n" /* OK (y = yes) */
- "%s\n" /* Common name */
- "\n" /* Country (default) */
- "\n" /* Organization (default) */
- "\n" /* Organizational unit (default) */
- "\n" /* State/Province (default) */
- "\n" /* Email address */
- "y\n", /* OK (y = yes) */
- common_name);
- cupsFileClose(fp);
-
- snprintf(keychain, sizeof(keychain), "k=%s", path);
-
- argv[0] = "certtool";
- argv[1] = "c";
- argv[2] = keychain;
- argv[3] = NULL;
-
- snprintf(days, sizeof(days), "CERTTOOL_EXPIRATION_DAYS=%d", (int)((expiration_date - time(NULL) + 86399) / 86400));
- envp[0] = days;
- for (i = 0; i < (int)(sizeof(envp) / sizeof(envp[0]) - 2) && environ[i]; i ++)
- envp[i + 1] = environ[i];
- envp[i] = NULL;
-
- posix_spawn_file_actions_t actions; /* File actions */
-
- posix_spawn_file_actions_init(&actions);
- posix_spawn_file_actions_addclose(&actions, 0);
- posix_spawn_file_actions_addopen(&actions, 0, infofile, O_RDONLY, 0);
- posix_spawn_file_actions_addclose(&actions, 1);
- posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0);
- posix_spawn_file_actions_addclose(&actions, 2);
- posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0);
-
- if (posix_spawn(&pid, command, &actions, NULL, argv, envp))
- {
- unlink(infofile);
- return (0);
- }
-
- posix_spawn_file_actions_destroy(&actions);
-
- unlink(infofile);
-
- while (waitpid(pid, &status, 0) < 0)
- if (errno != EINTR)
- {
- return (0);
- }
-
- return (!status);
-
-#else
- int status = 0; /* Return status */
- OSStatus err; /* Error code (if any) */
- CFStringRef cfcommon_name = NULL;
- /* CF string for server name */
- SecIdentityRef ident = NULL; /* Identity */
- SecKeyRef publicKey = NULL,
- /* Public key */
- privateKey = NULL;
- /* Private key */
- SecCertificateRef cert = NULL; /* Self-signed certificate */
- CFMutableDictionaryRef keyParams = NULL;
- /* Key generation parameters */
-
-
- 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));
-
- (void)path;
- (void)num_alt_names;
- (void)alt_names;
- (void)expiration_date;
-
- if (path)
- {
- DEBUG_puts("1cupsMakeServerCredentials: No keychain support compiled in, returning 0.");
- return (0);
- }
-
- if (tls_selfsigned)
- {
- DEBUG_puts("1cupsMakeServerCredentials: Using existing self-signed cert.");
- return (1);
- }
-
- cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8);
- if (!cfcommon_name)
- {
- DEBUG_puts("1cupsMakeServerCredentials: Unable to create CF string of common name.");
- goto cleanup;
- }
-
- /*
- * Create a public/private key pair...
- */
-
- keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!keyParams)
- {
- DEBUG_puts("1cupsMakeServerCredentials: Unable to create key parameters dictionary.");
- goto cleanup;
- }
-
- CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA);
- CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048"));
- CFDictionaryAddValue(keyParams, kSecAttrLabel, cfcommon_name);
-
- err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey);
- if (err != noErr)
- {
- DEBUG_printf(("1cupsMakeServerCredentials: Unable to generate key pair: %d.", (int)err));
- goto cleanup;
- }
-
- /*
- * Create a self-signed certificate using the public/private key pair...
- */
-
- CFIndex usageInt = kSecKeyUsageAll;
- CFNumberRef usage = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &usageInt);
- CFIndex lenInt = 0;
- CFNumberRef len = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &lenInt);
- CFTypeRef certKeys[] = { kSecCSRBasicConstraintsPathLen, kSecSubjectAltName, kSecCertificateKeyUsage };
- CFTypeRef certValues[] = { len, cfcommon_name, usage };
- CFDictionaryRef certParams = CFDictionaryCreate(kCFAllocatorDefault, certKeys, certValues, sizeof(certKeys) / sizeof(certKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFRelease(usage);
- CFRelease(len);
-
- const void *ca_o[] = { kSecOidOrganization, CFSTR("") };
- const void *ca_cn[] = { kSecOidCommonName, cfcommon_name };
- 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);
-
- cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey);
-
- CFRelease(subject);
- CFRelease(certParams);
-
- if (!cert)
- {
- DEBUG_puts("1cupsMakeServerCredentials: Unable to create self-signed certificate.");
- goto cleanup;
- }
-
- ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey);
-
- if (ident)
- {
- _cupsMutexLock(&tls_mutex);
-
- if (tls_selfsigned)
- CFRelease(ident);
- else
- tls_selfsigned = ident;
-
- _cupsMutexUnlock(&tls_mutex);
-
-# if 0 /* Someday perhaps SecItemCopyMatching will work for identities, at which point */
- CFTypeRef itemKeys[] = { kSecClass, kSecAttrLabel, kSecValueRef };
- CFTypeRef itemValues[] = { kSecClassIdentity, cfcommon_name, ident };
- CFDictionaryRef itemAttrs = CFDictionaryCreate(kCFAllocatorDefault, itemKeys, itemValues, sizeof(itemKeys) / sizeof(itemKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
- err = SecItemAdd(itemAttrs, NULL);
- /* SecItemAdd consumes itemAttrs... */
-
- CFRelease(ident);
-
- if (err != noErr)
- {
- DEBUG_printf(("1cupsMakeServerCredentials: Unable to add identity to keychain: %d.", (int)err));
- goto cleanup;
- }
-# endif /* 0 */
-
- status = 1;
- }
- else
- DEBUG_puts("1cupsMakeServerCredentials: Unable to create identity from cert and keys.");
-
- /*
- * Cleanup and return...
- */
-
-cleanup:
-
- if (cfcommon_name)
- CFRelease(cfcommon_name);
-
- if (keyParams)
- CFRelease(keyParams);
-
- if (cert)
- CFRelease(cert);
-
- if (publicKey)
- CFRelease(publicKey);
-
- if (privateKey)
- CFRelease(privateKey);
-
- DEBUG_printf(("1cupsMakeServerCredentials: Returning %d.", status));
-
- return (status);
-#endif /* TARGET_OS_OSX */
-}
-
-
-/*
- * '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/macOS 10.10@
- */
-
-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));
-
-#if TARGET_OS_OSX
- char filename[1024]; /* Keychain filename */
- SecKeychainRef keychain = http_cdsa_open_keychain(path, filename, sizeof(filename));
-
- if (!keychain)
- {
- DEBUG_puts("1cupsSetServerCredentials: Unable to open keychain.");
- return (0);
- }
-
- _cupsMutexLock(&tls_mutex);
-
- /*
- * Close any keychain that is currently open...
- */
-
- if (tls_keychain)
- CFRelease(tls_keychain);
-
- if (tls_keypath)
- _cupsStrFree(tls_keypath);
-
- if (tls_common_name)
- _cupsStrFree(tls_common_name);
-
- /*
- * Save the new keychain...
- */
-
- tls_keychain = keychain;
- tls_keypath = _cupsStrAlloc(filename);
- tls_auto_create = auto_create;
- tls_common_name = _cupsStrAlloc(common_name);
-
- _cupsMutexUnlock(&tls_mutex);
-
- DEBUG_puts("1cupsSetServerCredentials: Opened keychain, returning 1.");
- return (1);
-
-#else
- if (path)
- {
- DEBUG_puts("1cupsSetServerCredentials: No keychain support compiled in, returning 0.");
- return (0);
- }
-
- tls_auto_create = auto_create;
- tls_common_name = _cupsStrAlloc(common_name);
-
- return (1);
-#endif /* TARGET_OS_OSX */
-}
-
-
-/*
- * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
- * an encrypted connection.
- *
- * @since CUPS 1.5/macOS 10.7@
- */
-
-int /* O - Status of call (0 = success) */
-httpCopyCredentials(
- http_t *http, /* I - Connection to server */
- cups_array_t **credentials) /* O - Array of credentials */
-{
- OSStatus error; /* Error code */
- SecTrustRef peerTrust; /* Peer trust reference */
- CFDataRef data; /* Certificate data */
-
-
- DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", (void *)http, (void *)credentials));
-
- if (credentials)
- *credentials = NULL;
-
- if (!http || !http->tls || !credentials)
- return (-1);
-
- if (!(error = SSLCopyPeerTrust(http->tls, &peerTrust)) && peerTrust)
- {
- if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL)
- {
- CFArrayRef secArray = SecTrustCopyCertificateChain(peerTrust);
- CFIndex i, count = CFArrayGetCount(secArray);
-
- DEBUG_printf(("2httpCopyCredentials: Peer provided %ld certificates.", (long)count));
-
- for (i = 0; i < count; i ++)
- {
- SecCertificateRef secCert = (SecCertificateRef)CFArrayGetValueAtIndex(secArray, i);
-
-#ifdef DEBUG
- CFStringRef cf_name = SecCertificateCopySubjectSummary(secCert);
- char name[1024];
- if (cf_name)
- CFStringGetCString(cf_name, name, sizeof(name), kCFStringEncodingUTF8);
- else
- strlcpy(name, "unknown", sizeof(name));
-
- DEBUG_printf(("2httpCopyCredentials: Certificate %ld name is \"%s\".", (long)i, name));
-#endif /* DEBUG */
-
- if ((data = SecCertificateCopyData(secCert)) != NULL)
- {
- DEBUG_printf(("2httpCopyCredentials: Adding %ld byte certificate blob.", (long)CFDataGetLength(data)));
-
- httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data));
- CFRelease(data);
- }
- }
- CFRelease(secArray);
- }
-
- CFRelease(peerTrust);
- }
-
- return (error);
-}
-
-
-/*
- * '_httpCreateCredentials()' - Create credentials in the internal format.
- */
-
-http_tls_credentials_t /* O - Internal credentials */
-_httpCreateCredentials(
- cups_array_t *credentials) /* I - Array of credentials */
-{
- CFMutableArrayRef peerCerts; /* Peer credentials reference */
- SecCertificateRef secCert; /* Certificate reference */
- http_credential_t *credential; /* Credential data */
-
-
- if (!credentials)
- return (NULL);
-
- if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault,
- cupsArrayCount(credentials),
- &kCFTypeArrayCallBacks)) == NULL)
- return (NULL);
-
- for (credential = (http_credential_t *)cupsArrayFirst(credentials);
- credential;
- credential = (http_credential_t *)cupsArrayNext(credentials))
- {
- if ((secCert = http_cdsa_create_credential(credential)) != NULL)
- {
- CFArrayAppendValue(peerCerts, secCert);
- CFRelease(secCert);
- }
- }
-
- return (peerCerts);
-}
-
-
-/*
- * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
- *
- * @since CUPS 2.0/macOS 10.10@
- */
-
-int /* O - 1 if valid, 0 otherwise */
-httpCredentialsAreValidForName(
- cups_array_t *credentials, /* I - Credentials */
- const char *common_name) /* I - Name to check */
-{
- SecCertificateRef secCert; /* Certificate reference */
- CFStringRef cfcert_name = NULL;
- /* Certificate's common name (CF string) */
- char cert_name[256]; /* Certificate's common name (C string) */
- int valid = 1; /* Valid name? */
-
-
- if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
- return (0);
-
- /*
- * Compare the common names...
- */
-
- if ((cfcert_name = SecCertificateCopySubjectSummary(secCert)) == NULL)
- {
- /*
- * Can't get common name, cannot be valid...
- */
-
- valid = 0;
- }
- else if (CFStringGetCString(cfcert_name, cert_name, sizeof(cert_name), kCFStringEncodingUTF8) &&
- _cups_strcasecmp(common_name, cert_name))
- {
- /*
- * Not an exact match for the common name, check for wildcard certs...
- */
-
- const char *domain = strchr(common_name, '.');
- /* Domain in common name */
-
- if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1))
- {
- /*
- * Not a wildcard match.
- */
-
- /* TODO: Check subject alternate names */
- valid = 0;
- }
- }
-
- if (cfcert_name)
- CFRelease(cfcert_name);
-
- CFRelease(secCert);
-
- return (valid);
-}
-
-
-/*
- * 'httpCredentialsGetTrust()' - Return the trust of credentials.
- *
- * @since CUPS 2.0/macOS 10.10@
- */
-
-http_trust_t /* O - Level of trust */
-httpCredentialsGetTrust(
- cups_array_t *credentials, /* I - Credentials */
- const char *common_name) /* I - Common name for trust lookup */
-{
- SecCertificateRef secCert; /* Certificate reference */
- http_trust_t trust = HTTP_TRUST_OK;
- /* Trusted? */
- cups_array_t *tcreds = NULL; /* Trusted credentials */
- _cups_globals_t *cg = _cupsGlobals();
- /* Per-thread globals */
-
-
- if (!common_name)
- {
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No common name specified."), 1);
- return (HTTP_TRUST_UNKNOWN);
- }
-
- if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
- {
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create credentials from array."), 1);
- return (HTTP_TRUST_UNKNOWN);
- }
-
- if (cg->any_root < 0)
- _cupsSetDefaults();
-
- /*
- * Look this common name up in the default keychains...
- */
-
- httpLoadCredentials(NULL, &tcreds, common_name);
-
- if (tcreds)
- {
- 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));
-
- if (strcmp(credentials_str, tcreds_str))
- {
- /*
- * 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...
- */
-
- if (!cg->trust_first)
- {
- /*
- * Do not trust certificates on first use...
- */
-
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
-
- trust = HTTP_TRUST_INVALID;
- }
- else if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds))
- {
- /*
- * The new credentials are not newly issued...
- */
-
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are older than stored credentials."), 1);
-
- trust = HTTP_TRUST_INVALID;
- }
- else if (!httpCredentialsAreValidForName(credentials, common_name))
- {
- /*
- * The common name does not match the issued certificate...
- */
-
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are not valid for name."), 1);
-
- trust = HTTP_TRUST_INVALID;
- }
- else if (httpCredentialsGetExpiration(tcreds) < time(NULL))
- {
- /*
- * Save the renewed credentials...
- */
-
- trust = HTTP_TRUST_RENEWED;
-
- httpSaveCredentials(NULL, credentials, common_name);
- }
- }
-
- httpFreeCredentials(tcreds);
- }
- else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name))
- {
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1);
- trust = HTTP_TRUST_INVALID;
- }
- else if (!cg->trust_first)
- {
- /*
- * See if we have a site CA certificate we can compare...
- */
-
- if (!httpLoadCredentials(NULL, &tcreds, "site"))
- {
- if (cupsArrayCount(credentials) != (cupsArrayCount(tcreds) + 1))
- {
- /*
- * Certificate isn't directly generated from the CA cert...
- */
-
- trust = HTTP_TRUST_INVALID;
- }
- else
- {
- /*
- * Do a tail comparison of the two certificates...
- */
-
- http_credential_t *a, *b; /* Certificates */
-
- for (a = (http_credential_t *)cupsArrayFirst(tcreds), b = (http_credential_t *)cupsArrayIndex(credentials, 1);
- a && b;
- a = (http_credential_t *)cupsArrayNext(tcreds), b = (http_credential_t *)cupsArrayNext(credentials))
- if (a->datalen != b->datalen || memcmp(a->data, b->data, a->datalen))
- break;
-
- if (a || b)
- trust = HTTP_TRUST_INVALID;
- }
-
- if (trust != HTTP_TRUST_OK)
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials do not validate against site CA certificate."), 1);
- }
- else
- {
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
- trust = HTTP_TRUST_INVALID;
- }
- }
-
- if (trust == HTTP_TRUST_OK && !cg->expired_certs && !SecCertificateIsValid(secCert, CFAbsoluteTimeGetCurrent()))
- {
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials have expired."), 1);
- trust = HTTP_TRUST_EXPIRED;
- }
-
- if (trust == HTTP_TRUST_OK && !cg->any_root && cupsArrayCount(credentials) == 1)
- {
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1);
- trust = HTTP_TRUST_INVALID;
- }
-
- CFRelease(secCert);
-
- return (trust);
-}
-
-
-/*
- * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
- *
- * @since CUPS 2.0/macOS 10.10@
- */
-
-time_t /* O - Expiration date of credentials */
-httpCredentialsGetExpiration(
- cups_array_t *credentials) /* I - Credentials */
-{
- SecCertificateRef secCert; /* Certificate reference */
- time_t expiration; /* Expiration date */
-
-
- if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
- return (0);
-
- expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970);
-
- CFRelease(secCert);
-
- return (expiration);
-}
-
-
-/*
- * 'httpCredentialsString()' - Return a string representing the credentials.
- *
- * @since CUPS 2.0/macOS 10.10@
- */
-
-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 */
-{
- http_credential_t *first; /* First certificate */
- SecCertificateRef secCert; /* Certificate reference */
-
-
- DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", (void *)credentials, (void *)buffer, CUPS_LLCAST bufsize));
-
- if (!buffer)
- return (0);
-
- if (bufsize > 0)
- *buffer = '\0';
-
- if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL &&
- (secCert = http_cdsa_create_credential(first)) != NULL)
- {
- /*
- * Copy certificate (string) values from the SecCertificateRef and produce
- * a one-line summary. The API for accessing certificate values like the
- * issuer name is, um, "interesting"...
- */
-
-# if TARGET_OS_OSX
- CFDictionaryRef cf_dict; /* Dictionary for certificate */
-# endif /* TARGET_OS_OSX */
- CFStringRef cf_string; /* CF string */
- char commonName[256],/* Common name associated with cert */
- issuer[256], /* Issuer name */
- sigalg[256]; /* Signature algorithm */
- time_t expiration; /* Expiration date of cert */
- unsigned char md5_digest[16]; /* MD5 result */
-
- if (SecCertificateCopyCommonName(secCert, &cf_string) == noErr)
- {
- CFStringGetCString(cf_string, commonName, (CFIndex)sizeof(commonName), kCFStringEncodingUTF8);
- CFRelease(cf_string);
- }
- else
- {
- strlcpy(commonName, "unknown", sizeof(commonName));
- }
-
- strlcpy(issuer, "unknown", sizeof(issuer));
- strlcpy(sigalg, "UnknownSignature", sizeof(sigalg));
-
-# if TARGET_OS_OSX
- if ((cf_dict = SecCertificateCopyValues(secCert, NULL, NULL)) != NULL)
- {
- CFDictionaryRef cf_issuer = CFDictionaryGetValue(cf_dict, kSecOIDX509V1IssuerName);
- CFDictionaryRef cf_sigalg = CFDictionaryGetValue(cf_dict, kSecOIDX509V1SignatureAlgorithm);
-
- if (cf_issuer)
- {
- CFArrayRef cf_values = CFDictionaryGetValue(cf_issuer, kSecPropertyKeyValue);
- CFIndex i, count = CFArrayGetCount(cf_values);
- CFDictionaryRef cf_value;
-
- for (i = 0; i < count; i ++)
- {
- cf_value = CFArrayGetValueAtIndex(cf_values, i);
-
- if (!CFStringCompare(CFDictionaryGetValue(cf_value, kSecPropertyKeyLabel), kSecOIDOrganizationName, kCFCompareCaseInsensitive))
- CFStringGetCString(CFDictionaryGetValue(cf_value, kSecPropertyKeyValue), issuer, (CFIndex)sizeof(issuer), kCFStringEncodingUTF8);
- }
- }
-
- if (cf_sigalg)
- {
- CFArrayRef cf_values = CFDictionaryGetValue(cf_sigalg, kSecPropertyKeyValue);
- CFIndex i, count = CFArrayGetCount(cf_values);
- CFDictionaryRef cf_value;
-
- for (i = 0; i < count; i ++)
- {
- cf_value = CFArrayGetValueAtIndex(cf_values, i);
-
- if (!CFStringCompare(CFDictionaryGetValue(cf_value, kSecPropertyKeyLabel), CFSTR("Algorithm"), kCFCompareCaseInsensitive))
- {
- CFStringRef cf_algorithm = CFDictionaryGetValue(cf_value, kSecPropertyKeyValue);
-
- if (!CFStringCompare(cf_algorithm, CFSTR("1.2.840.113549.1.1.5"), kCFCompareCaseInsensitive))
- strlcpy(sigalg, "SHA1WithRSAEncryption", sizeof(sigalg));
- else if (!CFStringCompare(cf_algorithm, CFSTR("1.2.840.113549.1.1.11"), kCFCompareCaseInsensitive))
- strlcpy(sigalg, "SHA256WithRSAEncryption", sizeof(sigalg));
- else if (!CFStringCompare(cf_algorithm, CFSTR("1.2.840.113549.1.1.4"), kCFCompareCaseInsensitive))
- strlcpy(sigalg, "MD5WithRSAEncryption", sizeof(sigalg));
- }
- }
- }
-
- CFRelease(cf_dict);
- }
-# endif /* TARGET_OS_OSX */
-
- expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970);
-
- cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
-
- snprintf(buffer, bufsize, "%s (issued by %s) / %s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", commonName, issuer, httpGetDateString(expiration), sigalg, 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]);
-
- CFRelease(secCert);
- }
-
- DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
-
- return (strlen(buffer));
-}
-
-
-/*
- * '_httpFreeCredentials()' - Free internal credentials.
- */
-
-void
-_httpFreeCredentials(
- http_tls_credentials_t credentials) /* I - Internal credentials */
-{
- if (credentials)
- CFRelease(credentials);
-}
-
-
-/*
- * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
- *
- * @since CUPS 2.0/OS 10.10@
- */
-
-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 */
-{
- OSStatus err; /* Error info */
-#if TARGET_OS_OSX
- char filename[1024]; /* Filename for keychain */
- SecKeychainRef keychain = NULL,/* Keychain reference */
- syschain = NULL;/* System keychain */
- CFArrayRef list; /* Keychain list */
-#endif /* TARGET_OS_OSX */
- SecCertificateRef cert = NULL; /* Certificate */
- CFDataRef data; /* Certificate data */
- SecPolicyRef policy = NULL; /* Policy ref */
- CFStringRef cfcommon_name = NULL;
- /* Server name */
- CFMutableDictionaryRef query = NULL; /* Query qualifiers */
-
-
- DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name));
-
- if (!credentials)
- return (-1);
-
- *credentials = NULL;
-
-#if TARGET_OS_OSX
- keychain = http_cdsa_open_keychain(path, filename, sizeof(filename));
-
- if (!keychain)
- goto cleanup;
-
- syschain = http_cdsa_open_system_keychain();
-
-#else
- if (path)
- return (-1);
-#endif /* TARGET_OS_OSX */
-
- cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8);
-
- policy = SecPolicyCreateSSL(1, cfcommon_name);
-
- if (cfcommon_name)
- CFRelease(cfcommon_name);
-
- if (!policy)
- goto cleanup;
-
- if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)))
- goto cleanup;
-
- CFDictionaryAddValue(query, kSecClass, kSecClassCertificate);
- CFDictionaryAddValue(query, kSecMatchPolicy, policy);
- CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
- CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
-
-#if TARGET_OS_OSX
- if (syschain)
- {
- const void *values[2] = { syschain, keychain };
-
- list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks);
- }
- else
- list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks);
- CFDictionaryAddValue(query, kSecMatchSearchList, list);
- CFRelease(list);
-#endif /* TARGET_OS_OSX */
-
- err = SecItemCopyMatching(query, (CFTypeRef *)&cert);
-
- if (err)
- goto cleanup;
-
- if (CFGetTypeID(cert) != SecCertificateGetTypeID())
- goto cleanup;
-
- if ((data = SecCertificateCopyData(cert)) != NULL)
- {
- DEBUG_printf(("1httpLoadCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data)));
-
- *credentials = cupsArrayNew(NULL, NULL);
- httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data));
- CFRelease(data);
- }
-
- cleanup :
-
-#if TARGET_OS_OSX
- if (keychain)
- CFRelease(keychain);
-
- if (syschain)
- CFRelease(syschain);
-#endif /* TARGET_OS_OSX */
- if (cert)
- CFRelease(cert);
- if (policy)
- CFRelease(policy);
- if (query)
- CFRelease(query);
-
- DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1));
-
- return (*credentials ? 0 : -1);
-}
-
-
-/*
- * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
- *
- * @since CUPS 2.0/OS 10.10@
- */
-
-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 */
-{
- int ret = 0; /* Return value */
- OSStatus err; /* Error info */
-#if TARGET_OS_OSX
- char filename[1024]; /* Filename for keychain */
- SecKeychainRef keychain = NULL;/* Keychain reference */
- CFArrayRef list; /* Keychain list */
-#endif /* TARGET_OS_OSX */
- SecCertificateRef cert = NULL; /* Certificate */
- CFMutableDictionaryRef attrs = NULL; /* Attributes for add */
-
-
- DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name));
- if (!credentials)
- {
- DEBUG_puts("1httpSaveCredentials: No credentials, returning -1.");
- return (-1);
- }
-
- if (!httpCredentialsAreValidForName(credentials, common_name))
- {
- DEBUG_puts("1httpSaveCredentials: Common name does not match.");
- return (-1);
- }
-
- if ((cert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
- {
- DEBUG_puts("1httpSaveCredentials: Unable to create certificate.");
- goto cleanup;
- }
-
-#if TARGET_OS_OSX
- keychain = http_cdsa_open_keychain(path, filename, sizeof(filename));
-
- if (!keychain)
- {
- DEBUG_puts("1httpSaveCredentials: No keychain, returning -1.");
- return (-1);
- }
-
-#else
- if (path)
- {
- DEBUG_puts("1httpSaveCredentials: No path, returning -1.");
- return (-1);
- }
-#endif /* TARGET_OS_OSX */
-
- if ((attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL)
- {
- DEBUG_puts("1httpSaveCredentials: Unable to create dictionary.");
- goto cleanup;
- }
-
- CFDictionaryAddValue(attrs, kSecClass, kSecClassCertificate);
- CFDictionaryAddValue(attrs, kSecValueRef, cert);
-
-#if TARGET_OS_OSX
- if ((list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks)) == NULL)
- {
- DEBUG_puts("1httpSaveCredentials: Unable to create list of keychains.");
- ret = -1;
- goto cleanup;
- }
- CFDictionaryAddValue(attrs, kSecMatchSearchList, list);
- CFRelease(list);
-#endif /* TARGET_OS_OSX */
-
- /* Note: SecItemAdd consumes "attrs"... */
- if((err = SecItemAdd(attrs, NULL)) != 0)
- {
- DEBUG_printf(("1httpSaveCredentials: SecItemAdd failed, returned %d.", (int)err));
- ret = -1;
- }
-
- cleanup :
-
-#if TARGET_OS_OSX
- CFRelease(keychain);
-#endif /* TARGET_OS_OSX */
- CFRelease(cert);
-
- DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret));
-
- return (ret);
-}
-
-
-/*
- * '_httpTLSInitialize()' - Initialize the TLS stack.
- */
-
-void
-_httpTLSInitialize(void)
-{
- /*
- * Nothing to do...
- */
-}
-
-
-/*
- * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
- */
-
-size_t
-_httpTLSPending(http_t *http) /* I - HTTP connection */
-{
- size_t bytes; /* Bytes that are available */
-
-
- if (!SSLGetBufferedReadSize(http->tls, &bytes))
- return (bytes);
-
- return (0);
-}
-
-
-/*
- * '_httpTLSRead()' - Read from a SSL/TLS connection.
- */
-
-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 result; /* Return value */
- OSStatus error; /* Error info */
- size_t processed; /* Number of bytes processed */
-
-
- error = SSLRead(http->tls, buf, (size_t)len, &processed);
- DEBUG_printf(("5_httpTLSRead: 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;
- }
-
- return (result);
-}
-
-
-/*
- * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
- */
-
-void
-_httpTLSSetOptions(int options, /* I - Options */
- int min_version, /* I - Minimum TLS version */
- int max_version) /* I - Maximum TLS version */
-{
- if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
- {
- tls_options = options;
- tls_min_version = min_version;
- tls_max_version = max_version;
- }
-}
-
-
-/*
- * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
- */
-
-int /* O - 0 on success, -1 on failure */
-_httpTLSStart(http_t *http) /* I - HTTP connection */
-{
- char hostname[256], /* Hostname */
- *hostptr; /* Pointer into hostname */
- _cups_globals_t *cg = _cupsGlobals();
- /* Pointer to library globals */
- OSStatus error; /* Error code */
- const char *message = NULL;/* Error message */
- char msgbuf[1024]; /* Error message buffer */
- 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 */
-
-
- DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http));
-
- if (tls_options < 0)
- {
- DEBUG_puts("4_httpTLSStart: Setting defaults.");
- _cupsSetDefaults();
- DEBUG_printf(("4_httpTLSStart: tls_options=%x, tls_min_version=%d, tls_max_version=%d", tls_options, tls_min_version, tls_max_version));
- }
-
-#if TARGET_OS_OSX
- if (http->mode == _HTTP_MODE_SERVER && !tls_keychain)
- {
- DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
- http->error = errno = EINVAL;
- http->status = HTTP_STATUS_ERROR;
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
-
- return (-1);
- }
-#endif /* TARGET_OS_OSX */
-
- if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL)
- {
- DEBUG_puts("4_httpTLSStart: SSLCreateContext failed.");
- http->error = errno = ENOMEM;
- http->status = HTTP_STATUS_ERROR;
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
-
- return (-1);
- }
-
- error = SSLSetConnection(http->tls, http);
- DEBUG_printf(("4_httpTLSStart: SSLSetConnection, error=%d", (int)error));
-
- if (!error)
- {
- error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write);
- DEBUG_printf(("4_httpTLSStart: SSLSetIOFuncs, error=%d", (int)error));
- }
-
- if (!error)
- {
- error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth,
- true);
- DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d", (int)error));
- }
-
- if (!error)
- {
- static const SSLProtocol protocols[] = /* Min/max protocol versions */
- {
- kSSLProtocol3,
- kTLSProtocol1,
- kTLSProtocol11,
- kTLSProtocol12,
- kTLSProtocol13
- };
-
- if (tls_min_version < _HTTP_TLS_MAX)
- {
- error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]);
- DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error));
- }
-
- if (!error && tls_max_version < _HTTP_TLS_MAX)
- {
- error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]);
- DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error));
- }
- }
-
- if (!error)
- {
- SSLCipherSuite supported[100]; /* Supported cipher suites */
- size_t num_supported; /* Number of supported cipher suites */
- SSLCipherSuite enabled[100]; /* Cipher suites to enable */
- size_t num_enabled; /* Number of cipher suites to enable */
-
- num_supported = sizeof(supported) / sizeof(supported[0]);
- error = SSLGetSupportedCiphers(http->tls, supported, &num_supported);
-
- if (!error)
- {
- DEBUG_printf(("4_httpTLSStart: %d cipher suites supported.", (int)num_supported));
-
- for (i = 0, num_enabled = 0; i < (int)num_supported && num_enabled < (sizeof(enabled) / sizeof(enabled[0])); i ++)
- {
- switch (supported[i])
- {
- /* Obviously insecure cipher suites that we never want to use */
- case SSL_NULL_WITH_NULL_NULL :
- case SSL_RSA_WITH_NULL_MD5 :
- case SSL_RSA_WITH_NULL_SHA :
- case SSL_RSA_EXPORT_WITH_RC4_40_MD5 :
- case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 :
- case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA :
- case SSL_RSA_WITH_DES_CBC_SHA :
- case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA :
- case SSL_DH_DSS_WITH_DES_CBC_SHA :
- case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA :
- case SSL_DH_RSA_WITH_DES_CBC_SHA :
- case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA :
- case SSL_DHE_DSS_WITH_DES_CBC_SHA :
- case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA :
- case SSL_DHE_RSA_WITH_DES_CBC_SHA :
- case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 :
- case SSL_DH_anon_WITH_RC4_128_MD5 :
- case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA :
- case SSL_DH_anon_WITH_DES_CBC_SHA :
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA :
- case SSL_FORTEZZA_DMS_WITH_NULL_SHA :
- case TLS_DH_anon_WITH_AES_128_CBC_SHA :
- case TLS_DH_anon_WITH_AES_256_CBC_SHA :
- case TLS_ECDH_ECDSA_WITH_NULL_SHA :
- case TLS_ECDHE_RSA_WITH_NULL_SHA :
- case TLS_ECDH_anon_WITH_NULL_SHA :
- case TLS_ECDH_anon_WITH_RC4_128_SHA :
- case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA :
- case TLS_ECDH_anon_WITH_AES_128_CBC_SHA :
- case TLS_ECDH_anon_WITH_AES_256_CBC_SHA :
- case TLS_RSA_WITH_NULL_SHA256 :
- case TLS_DH_anon_WITH_AES_128_CBC_SHA256 :
- case TLS_DH_anon_WITH_AES_256_CBC_SHA256 :
- case TLS_PSK_WITH_NULL_SHA :
- case TLS_DHE_PSK_WITH_NULL_SHA :
- case TLS_RSA_PSK_WITH_NULL_SHA :
- case TLS_DH_anon_WITH_AES_128_GCM_SHA256 :
- case TLS_DH_anon_WITH_AES_256_GCM_SHA384 :
- case TLS_PSK_WITH_NULL_SHA256 :
- case TLS_PSK_WITH_NULL_SHA384 :
- case TLS_DHE_PSK_WITH_NULL_SHA256 :
- case TLS_DHE_PSK_WITH_NULL_SHA384 :
- case TLS_RSA_PSK_WITH_NULL_SHA256 :
- case TLS_RSA_PSK_WITH_NULL_SHA384 :
- case SSL_RSA_WITH_DES_CBC_MD5 :
- DEBUG_printf(("4_httpTLSStart: Excluding insecure cipher suite %d", supported[i]));
- break;
-
- /* RC4 cipher suites that should only be used as a last resort */
- case SSL_RSA_WITH_RC4_128_MD5 :
- case SSL_RSA_WITH_RC4_128_SHA :
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA :
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
- case TLS_ECDH_RSA_WITH_RC4_128_SHA :
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
- case TLS_PSK_WITH_RC4_128_SHA :
- case TLS_DHE_PSK_WITH_RC4_128_SHA :
- case TLS_RSA_PSK_WITH_RC4_128_SHA :
- if (tls_options & _HTTP_TLS_ALLOW_RC4)
- enabled[num_enabled ++] = supported[i];
- else
- DEBUG_printf(("4_httpTLSStart: Excluding RC4 cipher suite %d", supported[i]));
- break;
-
- /* DH/DHE cipher suites that are problematic with parameters < 1024 bits */
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA :
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA :
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA :
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA :
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA :
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA :
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
- case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA :
- case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA :
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA :
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA256 :
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA256 :
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 :
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 :
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA256 :
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA256 :
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 :
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 :
- case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA :
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA :
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA :
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
- if (tls_options & _HTTP_TLS_DENY_CBC)
- {
- DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i]));
- break;
- }
-
-// case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
-// case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
- case TLS_DH_RSA_WITH_AES_128_GCM_SHA256 :
- case TLS_DH_RSA_WITH_AES_256_GCM_SHA384 :
-// case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 :
-// case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 :
- case TLS_DH_DSS_WITH_AES_128_GCM_SHA256 :
- case TLS_DH_DSS_WITH_AES_256_GCM_SHA384 :
- case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 :
- case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 :
- if (tls_options & _HTTP_TLS_ALLOW_DH)
- enabled[num_enabled ++] = supported[i];
- else
- DEBUG_printf(("4_httpTLSStart: Excluding DH/DHE cipher suite %d", supported[i]));
- break;
-
- case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA :
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA :
- case TLS_RSA_WITH_AES_128_CBC_SHA :
- case TLS_RSA_WITH_AES_256_CBC_SHA :
- if (tls_options & _HTTP_TLS_DENY_CBC)
- {
- DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i]));
- break;
- }
-
- /* Anything else we'll assume is "secure" */
- default :
- enabled[num_enabled ++] = supported[i];
- break;
- }
- }
-
- DEBUG_printf(("4_httpTLSStart: %d cipher suites enabled.", (int)num_enabled));
- error = SSLSetEnabledCiphers(http->tls, enabled, num_enabled);
- }
- }
-
- if (!error && http->mode == _HTTP_MODE_CLIENT)
- {
- /*
- * Client: set client-side credentials, if any...
- */
-
- if (cg->client_cert_cb)
- {
- error = SSLSetSessionOption(http->tls,
- kSSLSessionOptionBreakOnCertRequested, true);
- DEBUG_printf(("4_httpTLSStart: kSSLSessionOptionBreakOnCertRequested, error=%d", (int)error));
- }
- else
- {
- error = http_cdsa_set_credentials(http);
- DEBUG_printf(("4_httpTLSStart: http_cdsa_set_credentials, error=%d", (int)error));
- }
- }
- else if (!error)
- {
- /*
- * Server: find/create a certificate for TLS...
- */
-
- if (http->fields[HTTP_FIELD_HOST])
- {
- /*
- * 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(("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));
- }
- }
-
- if (isdigit(hostname[0] & 255) || hostname[0] == '[')
- hostname[0] = '\0'; /* Don't allow numeric addresses */
-
- _cupsMutexLock(&tls_mutex);
-
- if (hostname[0])
- http->tls_credentials = http_cdsa_copy_server(hostname);
- else if (tls_common_name)
- http->tls_credentials = http_cdsa_copy_server(tls_common_name);
-
- if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name))
- {
- DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name));
-
- if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400))
- {
- DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
- http->error = errno = EINVAL;
- http->status = HTTP_STATUS_ERROR;
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
- _cupsMutexUnlock(&tls_mutex);
-
- return (-1);
- }
-
- http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name);
- }
-
- _cupsMutexUnlock(&tls_mutex);
-
- if (!http->tls_credentials)
- {
- DEBUG_puts("4_httpTLSStart: Unable to find server credentials.");
- http->error = errno = EINVAL;
- http->status = HTTP_STATUS_ERROR;
- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1);
-
- return (-1);
- }
-
- error = SSLSetCertificate(http->tls, http->tls_credentials);
-
- DEBUG_printf(("4_httpTLSStart: SSLSetCertificate, error=%d", (int)error));
- }
-
- DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", (void *)http->tls_credentials));
-
- /*
- * 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 && http->mode == _HTTP_MODE_CLIENT)
- {
- /*
- * Client: get the hostname to use for TLS...
- */
-
- if (httpAddrLocalhost(http->hostaddr))
- {
- strlcpy(hostname, "localhost", sizeof(hostname));
- }
- else
- {
- /*
- * Otherwise make sure the hostname we have does not end in a trailing dot.
- */
-
- strlcpy(hostname, http->hostname, sizeof(hostname));
- if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
- *hostptr == '.')
- *hostptr = '\0';
- }
-
- error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
-
- DEBUG_printf(("4_httpTLSStart: SSLSetPeerDomainName, error=%d", (int)error));
- }
-
- if (!error)
- {
- int done = 0; /* Are we done yet? */
- double old_timeout; /* Old timeout value */
- http_timeout_cb_t old_cb; /* Old timeout callback */
- void *old_data; /* Old timeout data */
-
- /*
- * Enforce a minimum timeout of 10 seconds for the TLS handshake...
- */
-
- old_timeout = http->timeout_value;
- old_cb = http->timeout_cb;
- old_data = http->timeout_data;
-
- if (!old_cb || old_timeout < 10.0)
- {
- DEBUG_puts("4_httpTLSStart: Setting timeout to 10 seconds.");
- httpSetTimeout(http, 10.0, NULL, NULL);
- }
-
- /*
- * Do the TLS handshake...
- */
-
- while (!error && !done)
- {
- error = SSLHandshake(http->tls);
-
- DEBUG_printf(("4_httpTLSStart: SSLHandshake returned %d.", (int)error));
-
- 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(("4_httpTLSStart: Server certificate callback returned %d.", (int)error));
- }
- break;
-
- case errSSLClientCertRequested :
- error = 0;
-
- if (cg->client_cert_cb)
- {
- names = NULL;
- error = SSLCopyDistinguishedNames(http->tls, &dn_array);
- if (dn_array)
- {
- if (!error) {
- 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 = (size_t)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(("4_httpTLSStart: 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;
- }
- }
-
- /*
- * Restore the previous timeout settings...
- */
-
- httpSetTimeout(http, old_timeout, old_cb, old_data);
- }
-
- 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...
- */
-
- if (!message)
- {
- if (!cg->lang_default)
- cg->lang_default = cupsLangDefault();
-
- snprintf(msgbuf, sizeof(msgbuf), _cupsLangString(cg->lang_default, _("Unable to establish a secure connection to host (%d).")), error);
- message = msgbuf;
- }
-
- _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
-
- return (-1);
- }
-
- return (0);
-}
-
-
-/*
- * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
- */
-
-void
-_httpTLSStop(http_t *http) /* I - HTTP connection */
-{
- while (SSLClose(http->tls) == errSSLWouldBlock)
- usleep(1000);
-
- CFRelease(http->tls);
- http->tls = NULL;
-
- if (http->tls_credentials)
- {
- CFRelease(http->tls_credentials);
- http->tls_credentials = 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 */
-{
- ssize_t result; /* Return value */
- OSStatus error; /* Error info */
- size_t processed; /* Number of bytes processed */
-
-
- DEBUG_printf(("4_httpTLSWrite(http=%p, buf=%p, len=%d)", (void *)http, (void *)buf, len));
-
- error = SSLWrite(http->tls, buf, (size_t)len, &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;
- }
-
- DEBUG_printf(("5_httpTLSWrite: Returning %d.", (int)result));
-
- return ((int)result);
-}
-
-
-/*
- * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain.
- */
-
-static CFArrayRef /* O - Array of certificates or NULL */
-http_cdsa_copy_server(
- const char *common_name) /* I - Server's hostname */
-{
-#if TARGET_OS_OSX
- OSStatus err; /* Error info */
- SecIdentityRef identity = NULL;/* Identity */
- CFArrayRef certificates = NULL;
- /* Certificate array */
- SecPolicyRef policy = NULL; /* Policy ref */
- CFStringRef cfcommon_name = NULL;
- /* Server name */
- CFMutableDictionaryRef query = NULL; /* Query qualifiers */
- CFArrayRef list = NULL; /* Keychain list */
- SecKeychainRef syschain = NULL;/* System keychain */
- SecKeychainStatus status = 0; /* Keychain status */
-
-
- DEBUG_printf(("3http_cdsa_copy_server(common_name=\"%s\")", common_name));
-
- cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8);
-
- policy = SecPolicyCreateSSL(1, cfcommon_name);
-
- if (!policy)
- {
- DEBUG_puts("4http_cdsa_copy_server: Unable to create SSL policy.");
- goto cleanup;
- }
-
- if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)))
- {
- DEBUG_puts("4http_cdsa_copy_server: Unable to create query dictionary.");
- goto cleanup;
- }
-
- _cupsMutexLock(&tls_mutex);
-
- err = SecKeychainGetStatus(tls_keychain, &status);
-
- if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain)
- SecKeychainUnlock(tls_keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE);
-
- CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
- CFDictionaryAddValue(query, kSecMatchPolicy, policy);
- CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
- CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
-
- syschain = http_cdsa_open_system_keychain();
-
- if (syschain)
- {
- const void *values[2] = { syschain, tls_keychain };
-
- list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks);
- }
- else
- list = CFArrayCreate(kCFAllocatorDefault, (const void **)&tls_keychain, 1, &kCFTypeArrayCallBacks);
-
- CFDictionaryAddValue(query, kSecMatchSearchList, list);
- CFRelease(list);
-
- err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
-
- _cupsMutexUnlock(&tls_mutex);
-
- if (err != noErr)
- {
- DEBUG_printf(("4http_cdsa_copy_server: SecItemCopyMatching failed with status %d.", (int)err));
- goto cleanup;
- }
-
- if (CFGetTypeID(identity) != SecIdentityGetTypeID())
- {
- DEBUG_puts("4http_cdsa_copy_server: Search returned something that is not an identity.");
- goto cleanup;
- }
-
- if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL)
- {
- DEBUG_puts("4http_cdsa_copy_server: Unable to create array of certificates.");
- goto cleanup;
- }
-
- cleanup :
-
- if (syschain)
- CFRelease(syschain);
- if (identity)
- CFRelease(identity);
- if (policy)
- CFRelease(policy);
- if (cfcommon_name)
- CFRelease(cfcommon_name);
- if (query)
- CFRelease(query);
-
- DEBUG_printf(("4http_cdsa_copy_server: Returning %p.", (void *)certificates));
-
- return (certificates);
-#else
-
- (void)common_name;
-
- if (!tls_selfsigned)
- return (NULL);
-
- return (CFArrayCreate(NULL, (const void **)&tls_selfsigned, 1, &kCFTypeArrayCallBacks));
-#endif /* TARGET_OS_OSX */
-}
-
-
-/*
- * '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 */
-{
- SecCertificateRef cert; /* Certificate */
- CFDataRef data; /* Data object */
-
-
- if (!credential)
- return (NULL);
-
- data = CFDataCreate(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen);
- cert = SecCertificateCreateWithData(kCFAllocatorDefault, data);
- CFRelease(data);
-
- return (cert);
-}
-
-
-#if TARGET_OS_OSX
-/*
- * 'http_cdsa_default_path()' - Get the default keychain path.
- */
-
-static const char * /* O - Keychain path */
-http_cdsa_default_path(char *buffer, /* I - Path buffer */
- size_t bufsize) /* I - Size of buffer */
-{
- _cups_globals_t *cg = _cupsGlobals();
- /* Pointer to library globals */
-
-
- /*
- * Determine the default keychain path. Note that the login and system
- * keychains are no longer accessible to user applications starting in macOS
- * 10.11.4 (!), so we need to create our own keychain just for CUPS.
- */
-
- if (cg->home)
- snprintf(buffer, bufsize, "%s/.cups/ssl.keychain", cg->home);
- else
- strlcpy(buffer, "/etc/cups/ssl.keychain", bufsize);
-
- DEBUG_printf(("1http_cdsa_default_path: Using default path \"%s\".", buffer));
-
- return (buffer);
-}
-
-
-/*
- * 'http_cdsa_open_keychain()' - Open (or create) a keychain.
- */
-
-static SecKeychainRef /* O - Keychain or NULL */
-http_cdsa_open_keychain(
- const char *path, /* I - Path to keychain */
- char *filename, /* I - Keychain filename */
- size_t filesize) /* I - Size of filename buffer */
-{
- SecKeychainRef keychain = NULL;/* Temporary keychain */
- OSStatus err; /* Error code */
- Boolean interaction; /* Interaction allowed? */
- SecKeychainStatus status = 0; /* Keychain status */
-
-
- /*
- * Get the keychain filename...
- */
-
- if (!path)
- {
- path = http_cdsa_default_path(filename, filesize);
- tls_cups_keychain = 1;
- }
- else
- {
- strlcpy(filename, path, filesize);
- tls_cups_keychain = 0;
- }
-
- /*
- * Save the interaction setting and disable while we open the keychain...
- */
-
- SecKeychainGetUserInteractionAllowed(&interaction);
- SecKeychainSetUserInteractionAllowed(FALSE);
-
- if (access(path, R_OK) && tls_cups_keychain)
- {
- /*
- * Create a new keychain at the given path...
- */
-
- err = SecKeychainCreate(path, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, FALSE, NULL, &keychain);
- }
- else
- {
- /*
- * Open the existing keychain and unlock as needed...
- */
-
- err = SecKeychainOpen(path, &keychain);
-
- if (err == noErr)
- err = SecKeychainGetStatus(keychain, &status);
-
- if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain)
- err = SecKeychainUnlock(keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE);
- }
-
- /*
- * Restore interaction setting...
- */
-
- SecKeychainSetUserInteractionAllowed(interaction);
-
- /*
- * Release the keychain if we had any errors...
- */
-
- if (err != noErr)
- {
- /* TODO: Set cups last error string */
- DEBUG_printf(("4http_cdsa_open_keychain: Unable to open keychain (%d), returning NULL.", (int)err));
-
- if (keychain)
- {
- CFRelease(keychain);
- keychain = NULL;
- }
- }
-
- /*
- * Return the keychain or NULL...
- */
-
- return (keychain);
-}
-
-
-/*
- * 'http_cdsa_open_system_keychain()' - Open the System keychain.
- */
-
-static SecKeychainRef
-http_cdsa_open_system_keychain(void)
-{
- SecKeychainRef keychain = NULL;/* Temporary keychain */
- OSStatus err; /* Error code */
- Boolean interaction; /* Interaction allowed? */
- SecKeychainStatus status = 0; /* Keychain status */
-
-
- /*
- * Save the interaction setting and disable while we open the keychain...
- */
-
- SecKeychainGetUserInteractionAllowed(&interaction);
- SecKeychainSetUserInteractionAllowed(TRUE);
-
- err = SecKeychainOpen("/Library/Keychains/System.keychain", &keychain);
-
- if (err == noErr)
- err = SecKeychainGetStatus(keychain, &status);
-
- if (err == noErr && !(status & kSecUnlockStateStatus))
- err = errSecInteractionNotAllowed;
-
- /*
- * Restore interaction setting...
- */
-
- SecKeychainSetUserInteractionAllowed(interaction);
-
- /*
- * Release the keychain if we had any errors...
- */
-
- if (err != noErr)
- {
- /* TODO: Set cups last error string */
- DEBUG_printf(("4http_cdsa_open_system_keychain: Unable to open keychain (%d), returning NULL.", (int)err));
-
- if (keychain)
- {
- CFRelease(keychain);
- keychain = NULL;
- }
- }
-
- /*
- * Return the keychain or NULL...
- */
-
- return (keychain);
-}
-#endif /* TARGET_OS_OSX */
-
-
-/*
- * 'http_cdsa_read()' - Read function for the CDSA library.
- */
-
-static OSStatus /* O - -1 on error, 0 on success */
-http_cdsa_read(
- SSLConnectionRef connection, /* I - SSL/TLS connection */
- void *data, /* I - Data buffer */
- size_t *dataLength) /* IO - Number of bytes */
-{
- OSStatus result; /* Return value */
- ssize_t bytes; /* Number of bytes read */
- http_t *http; /* HTTP connection */
-
-
- http = (http_t *)connection;
-
- if (!http->blocking || http->timeout_value > 0.0)
- {
- /*
- * Make sure we have data before we read...
- */
-
- while (!_httpWait(http, http->wait_value, 0))
- {
- if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
- continue;
-
- http->error = ETIMEDOUT;
- return (-1);
- }
- }
-
- do
- {
- bytes = recv(http->fd, data, *dataLength, 0);
- }
- while (bytes == -1 && (errno == EINTR || errno == EAGAIN));
-
- if ((size_t)bytes == *dataLength)
- {
- result = 0;
- }
- else if (bytes > 0)
- {
- *dataLength = (size_t)bytes;
- result = errSSLWouldBlock;
- }
- else
- {
- *dataLength = 0;
-
- if (bytes == 0)
- result = errSSLClosedGraceful;
- else if (errno == EAGAIN)
- result = errSSLWouldBlock;
- else
- result = errSSLClosedAbort;
- }
-
- return (result);
-}
-
-
-/*
- * 'http_cdsa_set_credentials()' - Set the TLS credentials.
- */
-
-static int /* O - Status of connection */
-http_cdsa_set_credentials(http_t *http) /* I - HTTP connection */
-{
- _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- OSStatus error = 0; /* Error code */
- http_tls_credentials_t credentials = NULL;
- /* TLS credentials */
-
-
- DEBUG_printf(("7http_tls_set_credentials(%p)", (void *)http));
-
- /*
- * Prefer connection specific credentials...
- */
-
- if ((credentials = http->tls_credentials) == NULL)
- credentials = cg->tls_credentials;
-
- if (credentials)
- {
- error = SSLSetCertificate(http->tls, credentials);
- DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d",
- (int)error));
- }
- else
- DEBUG_puts("4http_tls_set_credentials: No credentials to set.");
-
- return (error);
-}
-
-
-/*
- * 'http_cdsa_write()' - Write function for the CDSA library.
- */
-
-static OSStatus /* O - -1 on error, 0 on success */
-http_cdsa_write(
- SSLConnectionRef connection, /* I - SSL/TLS connection */
- const void *data, /* I - Data buffer */
- size_t *dataLength) /* IO - Number of bytes */
-{
- OSStatus result; /* Return value */
- ssize_t bytes; /* Number of bytes read */
- http_t *http; /* HTTP connection */
-
-
- http = (http_t *)connection;
-
- do
- {
- bytes = write(http->fd, data, *dataLength);
- }
- while (bytes == -1 && (errno == EINTR || errno == EAGAIN));
-
- if ((size_t)bytes == *dataLength)
- {
- result = 0;
- }
- else if (bytes >= 0)
- {
- *dataLength = (size_t)bytes;
- result = errSSLWouldBlock;
- }
- else
- {
- *dataLength = 0;
-
- if (errno == EAGAIN)
- result = errSSLWouldBlock;
- else
- result = errSSLClosedAbort;
- }
-
- return (result);
-}
+++ /dev/null
-/*
- * TLS support header for CUPS on macOS.
- *
- * Copyright © 2007-2019 by Apple Inc.
- * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
- *
- * Licensed under Apache License v2.0. See the file "LICENSE" for more
- * information.
- */
-
-/**** This file is included from tls-darwin.c ****/
-
-extern char **environ;
-
-#ifndef _SECURITY_VERSION_GREATER_THAN_57610_
-typedef CF_OPTIONS(uint32_t, SecKeyUsage) {
- kSecKeyUsageAll = 0x7FFFFFFF
-};
-#endif /* !_SECURITY_VERSION_GREATER_THAN_57610_ */
-extern const void * kSecCSRChallengePassword;
-extern const void * kSecSubjectAltName;
-extern const void * kSecCertificateKeyUsage;
-extern const void * kSecCSRBasicConstraintsPathLen;
-extern const void * kSecCertificateExtensions;
-extern const void * kSecCertificateExtensionsEncoded;
-extern const void * kSecOidCommonName;
-extern const void * kSecOidCountryName;
-extern const void * kSecOidStateProvinceName;
-extern const void * kSecOidLocalityName;
-extern const void * kSecOidOrganization;
-extern const void * kSecOidOrganizationalUnit;
-extern bool SecCertificateIsValid(SecCertificateRef certificate, CFAbsoluteTime verifyTime);
-extern CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate);
-extern SecCertificateRef SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey);
-extern SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey);
+++ /dev/null
-/*
- * TLS support for CUPS on Windows using the Security Support Provider
- * Interface (SSPI).
- *
- * Copyright © 2020-2023 by OpenPrinting.
- * Copyright © 2010-2018 by Apple Inc.
- *
- * Licensed under Apache License v2.0. See the file "LICENSE" for more
- * information.
- */
-
-/**** This file is included from tls.c ****/
-
-/*
- * Include necessary headers...
- */
-
-#include "debug-private.h"
-#include <string.h>
-
-
-/*
- * Include necessary libraries...
- */
-
-#pragma comment(lib, "Crypt32.lib")
-#pragma comment(lib, "Secur32.lib")
-#pragma comment(lib, "Ws2_32.lib")
-
-
-/*
- * Constants...
- */
-
-#ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA
-# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
-#endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */
-
-#ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID
-# define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 /* Common name does not match */
-#endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */
-
-#ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
-# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
-#endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
-
-
-/*
- * Local globals...
- */
-
-static int tls_options = -1,/* Options for TLS connections */
- tls_min_version = _HTTP_TLS_1_0,
- tls_max_version = _HTTP_TLS_MAX;
-
-
-/*
- * Local functions...
- */
-
-static _http_sspi_t *http_sspi_alloc(void);
-static int http_sspi_client(http_t *http, const char *hostname);
-static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred);
-static BOOL http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name);
-static void http_sspi_free(_http_sspi_t *sspi);
-static BOOL http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years);
-static int http_sspi_server(http_t *http, const char *hostname);
-static void http_sspi_set_error(const char *title);
-static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code);
-static DWORD http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags);
-
-
-/*
- * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
- */
-
-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 */
-{
- _http_sspi_t *sspi; /* SSPI data */
- int ret; /* Return value */
-
-
- 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));
-
- (void)path;
- (void)num_alt_names;
- (void)alt_names;
-
- sspi = http_sspi_alloc();
- ret = http_sspi_make_credentials(sspi, L"ServerContainer", common_name, _HTTP_MODE_SERVER, (int)((expiration_date - time(NULL) + 86399) / 86400 / 365));
-
- http_sspi_free(sspi);
-
- return (ret);
-}
-
-
-/*
- * 'cupsSetServerCredentials()' - Set the default server credentials.
- *
- * Note: The server credentials are used by all threads in the running process.
- * This function is threadsafe.
- */
-
-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));
-
- (void)path;
- (void)common_name;
- (void)auto_create;
-
- return (0);
-}
-
-
-/*
- * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
- * an encrypted connection.
- */
-
-int /* O - Status of call (0 = success) */
-httpCopyCredentials(
- http_t *http, /* I - Connection to server */
- cups_array_t **credentials) /* O - Array of credentials */
-{
- DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
-
- if (!http || !http->tls || !http->tls->remoteCert || !credentials)
- {
- if (credentials)
- *credentials = NULL;
-
- return (-1);
- }
-
- *credentials = cupsArrayNew(NULL, NULL);
- httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded);
-
- return (0);
-}
-
-
-/*
- * '_httpCreateCredentials()' - Create credentials in the internal format.
- */
-
-http_tls_credentials_t /* O - Internal credentials */
-_httpCreateCredentials(
- cups_array_t *credentials) /* I - Array of credentials */
-{
- return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)));
-}
-
-
-/*
- * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
- */
-
-int /* O - 1 if valid, 0 otherwise */
-httpCredentialsAreValidForName(
- cups_array_t *credentials, /* I - Credentials */
- const char *common_name) /* I - Name to check */
-{
- int valid = 1; /* Valid name? */
- PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
- /* Certificate */
- char cert_name[1024]; /* Name from certificate */
-
-
- if (cert)
- {
- if (CertNameToStrA(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
- {
- /*
- * Extract common name at end...
- */
-
- char *ptr = strrchr(cert_name, ',');
- if (ptr && ptr[1])
- _cups_strcpy(cert_name, ptr + 2);
- }
- else
- strlcpy(cert_name, "unknown", sizeof(cert_name));
-
- CertFreeCertificateContext(cert);
- }
- else
- strlcpy(cert_name, "unknown", sizeof(cert_name));
-
- /*
- * Compare the common names...
- */
-
- if (_cups_strcasecmp(common_name, cert_name))
- {
- /*
- * Not an exact match for the common name, check for wildcard certs...
- */
-
- const char *domain = strchr(common_name, '.');
- /* Domain in common name */
-
- if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1))
- {
- /*
- * Not a wildcard match.
- */
-
- /* TODO: Check subject alternate names */
- valid = 0;
- }
- }
-
- return (valid);
-}
-
-
-/*
- * 'httpCredentialsGetTrust()' - Return the trust of credentials.
- */
-
-http_trust_t /* O - Level of trust */
-httpCredentialsGetTrust(
- cups_array_t *credentials, /* I - Credentials */
- const char *common_name) /* I - Common name for trust lookup */
-{
- http_trust_t trust = HTTP_TRUST_OK; /* Level of trust */
- PCCERT_CONTEXT cert = NULL; /* Certificate to validate */
- DWORD certFlags = 0; /* Cert verification flags */
- _cups_globals_t *cg = _cupsGlobals(); /* Per-thread global data */
-
-
- if (!common_name)
- return (HTTP_TRUST_UNKNOWN);
-
- cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
- if (!cert)
- return (HTTP_TRUST_UNKNOWN);
-
- if (cg->any_root < 0)
- _cupsSetDefaults();
-
- if (cg->any_root)
- certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
-
- if (cg->expired_certs)
- certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
-
- if (!cg->validate_certs)
- certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
-
- if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK)
- trust = HTTP_TRUST_INVALID;
-
- CertFreeCertificateContext(cert);
-
- return (trust);
-}
-
-
-/*
- * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
- */
-
-time_t /* O - Expiration date of credentials */
-httpCredentialsGetExpiration(
- cups_array_t *credentials) /* I - Credentials */
-{
- time_t expiration_date = 0; /* Expiration data of credentials */
- PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
- /* Certificate */
-
- if (cert)
- {
- SYSTEMTIME systime; /* System time */
- struct tm tm; /* UNIX date/time */
-
- FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
-
- tm.tm_year = systime.wYear - 1900;
- tm.tm_mon = systime.wMonth - 1;
- tm.tm_mday = systime.wDay;
- tm.tm_hour = systime.wHour;
- tm.tm_min = systime.wMinute;
- tm.tm_sec = systime.wSecond;
-
- expiration_date = mktime(&tm);
-
- CertFreeCertificateContext(cert);
- }
-
- return (expiration_date);
-}
-
-
-/*
- * 'httpCredentialsString()' - Return a string representing the 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 */
-{
- http_credential_t *first = (http_credential_t *)cupsArrayFirst(credentials);
- /* First certificate */
- PCCERT_CONTEXT cert; /* Certificate */
-
-
- DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
-
- if (!buffer)
- return (0);
-
- if (bufsize > 0)
- *buffer = '\0';
-
- cert = http_sspi_create_credential(first);
-
- if (cert)
- {
- char cert_name[256]; /* Common name */
- SYSTEMTIME systime; /* System time */
- struct tm tm; /* UNIX date/time */
- time_t expiration; /* Expiration date of cert */
- unsigned char md5_digest[16]; /* MD5 result */
-
- FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
-
- tm.tm_year = systime.wYear - 1900;
- tm.tm_mon = systime.wMonth - 1;
- tm.tm_mday = systime.wDay;
- tm.tm_hour = systime.wHour;
- tm.tm_min = systime.wMinute;
- tm.tm_sec = systime.wSecond;
-
- expiration = mktime(&tm);
-
- if (CertNameToStrA(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name)))
- {
- /*
- * Extract common name at end...
- */
-
- char *ptr = strrchr(cert_name, ',');
- if (ptr && ptr[1])
- _cups_strcpy(cert_name, ptr + 2);
- }
- else
- strlcpy(cert_name, "unknown", sizeof(cert_name));
-
- cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
-
- snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_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]);
-
- CertFreeCertificateContext(cert);
- }
-
- DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
-
- return (strlen(buffer));
-}
-
-
-/*
- * '_httpFreeCredentials()' - Free internal credentials.
- */
-
-void
-_httpFreeCredentials(
- http_tls_credentials_t credentials) /* I - Internal credentials */
-{
- if (!credentials)
- return;
-
- CertFreeCertificateContext(credentials);
-}
-
-
-/*
- * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
- */
-
-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 */
-{
- HCERTSTORE store = NULL; /* Certificate store */
- PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
- 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 */
-#ifdef DEBUG
- char error[1024]; /* Error message buffer */
-#endif /* DEBUG */
-
-
- DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
-
- (void)path;
-
- if (credentials)
- {
- *credentials = NULL;
- }
- else
- {
- DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1.");
- return (-1);
- }
-
- if (!common_name)
- {
- DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1.");
- return (-1);
- }
-
- if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET /*| CRYPT_MACHINE_KEYSET*/))
- {
- if (GetLastError() == NTE_EXISTS)
- {
- if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, 0 /*CRYPT_MACHINE_KEYSET*/))
- {
- DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CryptAquireContext");
- goto cleanup;
- }
- }
- }
-
- 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(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertOpenSystemStore");
- goto cleanup;
- }
-
- dwSize = 0;
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
- {
- DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertStrToName");
- goto cleanup;
- }
-
- p = (PBYTE)malloc(dwSize);
-
- if (!p)
- {
- DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize));
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- goto cleanup;
- }
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
- {
- DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertStrToName");
- goto cleanup;
- }
-
- sib.cbData = dwSize;
- sib.pbData = p;
-
- storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
-
- if (!storedContext)
- {
- DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name));
- goto cleanup;
- }
-
- *credentials = cupsArrayNew(NULL, NULL);
- httpAddCredential(*credentials, storedContext->pbCertEncoded, storedContext->cbCertEncoded);
-
-cleanup:
-
- /*
- * Cleanup
- */
-
- if (storedContext)
- CertFreeCertificateContext(storedContext);
-
- if (p)
- free(p);
-
- if (store)
- CertCloseStore(store, 0);
-
- if (hProv)
- CryptReleaseContext(hProv, 0);
-
- DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1));
-
- return (*credentials ? 0 : -1);
-}
-
-
-/*
- * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
- */
-
-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 */
-{
- 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 */
- CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
- int ret = -1; /* Return value */
-#ifdef DEBUG
- char error[1024]; /* Error message buffer */
-#endif /* DEBUG */
-
-
- DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
-
- (void)path;
-
- if (!common_name)
- {
- DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1.");
- return (-1);
- }
-
- createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
- if (!createdContext)
- {
- DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
- return (-1);
- }
-
- if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET /*| CRYPT_MACHINE_KEYSET*/))
- {
- if (GetLastError() == NTE_EXISTS)
- {
- if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, 0 /*CRYPT_MACHINE_KEYSET*/))
- {
- DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CryptAquireContext");
- goto cleanup;
- }
- }
- }
-
- 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(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertOpenSystemStore");
- goto cleanup;
- }
-
- dwSize = 0;
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
- {
- DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertStrToName");
- goto cleanup;
- }
-
- p = (PBYTE)malloc(dwSize);
-
- if (!p)
- {
- DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize));
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- goto cleanup;
- }
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
- {
- DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertToToName");
- goto cleanup;
- }
-
- /*
- * Add the created context to the named store, and associate it with the named
- * container...
- */
-
- if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
- {
- DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertAddCertificateContextToStore");
- goto cleanup;
- }
-
- ZeroMemory(&ckp, sizeof(ckp));
- ckp.pwszContainerName = L"RememberedContainer";
- ckp.pwszProvName = MS_DEF_PROV_W;
- ckp.dwProvType = PROV_RSA_FULL;
- ckp.dwFlags = 0 /*CRYPT_MACHINE_KEYSET*/;
- ckp.dwKeySpec = AT_KEYEXCHANGE;
-
- if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
- {
- DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError())));
- http_sspi_set_error("CertSetCertificateContextProperty");
- goto cleanup;
- }
-
- ret = 0;
-
-cleanup:
-
- /*
- * Cleanup
- */
-
- if (createdContext)
- CertFreeCertificateContext(createdContext);
-
- if (storedContext)
- CertFreeCertificateContext(storedContext);
-
- if (p)
- free(p);
-
- if (store)
- CertCloseStore(store, 0);
-
- if (hProv)
- CryptReleaseContext(hProv, 0);
-
- DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret));
- return (ret);
-}
-
-
-/*
- * '_httpTLSInitialize()' - Initialize the TLS stack.
- */
-
-void
-_httpTLSInitialize(void)
-{
- /*
- * Nothing to do...
- */
-}
-
-
-/*
- * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
- */
-
-size_t /* O - Bytes available */
-_httpTLSPending(http_t *http) /* I - HTTP connection */
-{
- if (http->tls)
- {
- DEBUG_printf(("4_httpTLSPending: Returning %d.", http->tls->readBufferUsed + http->tls->decryptBufferUsed));
- return (http->tls->readBufferUsed + http->tls->decryptBufferUsed);
- }
- else
- {
- DEBUG_puts("4_httpTLSPending: Returning 0.");
- return (0);
- }
-}
-
-
-/*
- * '_httpTLSRead()' - Read from a SSL/TLS connection.
- */
-
-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 *sspi = 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 */
-
-
- DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len));
-
- /*
- * If there are bytes that have already been decrypted and have not yet been
- * read, return those...
- */
-
- if (sspi->readBufferUsed > 0)
- {
- int bytesToCopy = min(sspi->readBufferUsed, len);
- /* Number of bytes to copy */
-
- memcpy(buf, sspi->readBuffer, bytesToCopy);
- sspi->readBufferUsed -= bytesToCopy;
-
- if (sspi->readBufferUsed > 0)
- memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed);
-
- DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy));
-
- return (bytesToCopy);
- }
-
- /*
- * Initialize security buffer structs
- */
-
- message.ulVersion = SECBUFFER_VERSION;
- message.cBuffers = 4;
- message.pBuffers = buffers;
-
- do
- {
- /*
- * If there is not enough space in the buffer, then increase its size...
- */
-
- if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
- {
- BYTE *temp; /* New buffer */
-
- if (sspi->decryptBufferLength >= 262144)
- {
- WSASetLastError(E_OUTOFMEMORY);
- DEBUG_puts("5_httpTLSRead: Decryption buffer too large (>256k)");
- return (-1);
- }
-
- if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
- {
- DEBUG_printf(("5_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096));
- WSASetLastError(E_OUTOFMEMORY);
- return (-1);
- }
-
- sspi->decryptBufferLength += 4096;
- sspi->decryptBuffer = temp;
-
- DEBUG_printf(("5_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength));
- }
-
- buffers[0].pvBuffer = sspi->decryptBuffer;
- buffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed;
- buffers[0].BufferType = SECBUFFER_DATA;
- buffers[1].BufferType = SECBUFFER_EMPTY;
- buffers[2].BufferType = SECBUFFER_EMPTY;
- buffers[3].BufferType = SECBUFFER_EMPTY;
-
- DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed));
-
- scRet = DecryptMessage(&sspi->context, &message, 0, NULL);
-
- if (scRet == SEC_E_INCOMPLETE_MESSAGE)
- {
- num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
- if (num < 0)
- {
- DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError()));
- return (-1);
- }
- else if (num == 0)
- {
- DEBUG_puts("5_httpTLSRead: Server disconnected.");
- return (0);
- }
-
- DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num));
-
- sspi->decryptBufferUsed += num;
- }
- }
- while (scRet == SEC_E_INCOMPLETE_MESSAGE);
-
- if (scRet == SEC_I_CONTEXT_EXPIRED)
- {
- http_sspi_set_error("DecryptMessage");
- DEBUG_puts("5_httpTLSRead: Context expired.");
- WSASetLastError(WSAECONNRESET);
- return (-1);
- }
- else if (scRet != SEC_E_OK)
- {
- http_sspi_set_error("DecryptMessage");
- DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- WSASetLastError(WSASYSCALLFAILURE);
- return (-1);
- }
-
- /*
- * The decryption worked. Now, locate data buffer.
- */
-
- 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];
- }
-
- /*
- * If a data buffer is found, then copy the decrypted bytes to the passed-in
- * buffer...
- */
-
- if (pDataBuffer)
- {
- int bytesToCopy = min((int)pDataBuffer->cbBuffer, 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);
-
- /*
- * If there are more decrypted bytes than can be copied to the passed in
- * buffer, then save them...
- */
-
- if (bytesToSave)
- {
- if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave)
- {
- BYTE *temp; /* New buffer pointer */
-
- if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL)
- {
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- DEBUG_printf(("5_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave));
- WSASetLastError(E_OUTOFMEMORY);
- return (-1);
- }
-
- sspi->readBufferLength = sspi->readBufferUsed + bytesToSave;
- sspi->readBuffer = temp;
- }
-
- memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave);
-
- sspi->readBufferUsed += bytesToSave;
- }
-
- num = bytesToCopy;
- }
- else
- {
- DEBUG_puts("5_httpTLSRead: Unable to find data buffer.");
- _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, "Unable to find data buffer.", 0);
- WSASetLastError(WSASYSCALLFAILURE);
- return (-1);
- }
-
- /*
- * 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)
- {
- memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
- sspi->decryptBufferUsed = pExtraBuffer->cbBuffer;
- }
- else
- {
- sspi->decryptBufferUsed = 0;
- }
-
- return (num);
-}
-
-
-/*
- * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
- */
-
-void
-_httpTLSSetOptions(int options, /* I - Options */
- int min_version, /* I - Minimum TLS version */
- int max_version) /* I - Maximum TLS version */
-{
- if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
- {
- tls_options = options;
- tls_min_version = min_version;
- tls_max_version = max_version;
- }
-}
-
-
-/*
- * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
- */
-
-int /* O - 0 on success, -1 on failure */
-_httpTLSStart(http_t *http) /* I - HTTP connection */
-{
- char hostname[256], /* Hostname */
- *hostptr; /* Pointer into hostname */
-
-
- DEBUG_printf(("3_httpTLSStart(http=%p)", http));
-
- if (tls_options < 0)
- {
- DEBUG_puts("4_httpTLSStart: Setting defaults.");
- _cupsSetDefaults();
- DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
- }
-
- if ((http->tls = http_sspi_alloc()) == NULL)
- return (-1);
-
- if (http->mode == _HTTP_MODE_CLIENT)
- {
- /*
- * Client: determine hostname...
- */
-
- 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';
- }
-
- return (http_sspi_client(http, hostname));
- }
- else
- {
- /*
- * Server: determine hostname to use...
- */
-
- if (http->fields[HTTP_FIELD_HOST])
- {
- /*
- * 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(("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));
- }
- }
-
-// fprintf(stderr, "_httpTLSStart: Using hostname '%s'.\n", hostname);
-
- return (http_sspi_server(http, hostname));
- }
-}
-
-
-/*
- * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
- */
-
-void
-_httpTLSStop(http_t *http) /* I - HTTP connection */
-{
- _http_sspi_t *sspi = http->tls; /* SSPI data */
-
-
- if (sspi->contextInitialized && http->fd >= 0)
- {
- 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(&sspi->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(&sspi->creds, &sspi->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(("4_httpTLSStop: sending close notify failed: %d", status));
- }
- else
- {
- FreeContextBuffer(pbMessage);
- }
- }
- }
- else
- {
- http_sspi_set_error("AcceptSecurityContext");
- DEBUG_printf(("4_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
- }
- }
- else
- {
- http_sspi_set_error("ApplyControlToken");
- DEBUG_printf(("4_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status)));
- }
- }
-
- http_sspi_free(sspi);
-
- 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 *sspi = 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 = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer;
-
- if (bufferLen > sspi->writeBufferLength)
- {
- BYTE *temp; /* New buffer pointer */
-
- if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL)
- {
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- DEBUG_printf(("5_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen));
- WSASetLastError(E_OUTOFMEMORY);
- return (-1);
- }
-
- sspi->writeBuffer = temp;
- sspi->writeBufferLength = bufferLen;
- }
-
- bytesLeft = len;
- bufptr = buf;
-
- while (bytesLeft)
- {
- int chunk = min((int)sspi->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(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk);
-
- /*
- * Setup the SSPI buffers
- */
-
- message.ulVersion = SECBUFFER_VERSION;
- message.cBuffers = 4;
- message.pBuffers = buffers;
-
- buffers[0].pvBuffer = sspi->writeBuffer;
- buffers[0].cbBuffer = sspi->streamSizes.cbHeader;
- buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
- buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader;
- buffers[1].cbBuffer = (unsigned long) chunk;
- buffers[1].BufferType = SECBUFFER_DATA;
- buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk;
- buffers[2].cbBuffer = sspi->streamSizes.cbTrailer;
- buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
- buffers[3].BufferType = SECBUFFER_EMPTY;
-
- /*
- * Encrypt the data
- */
-
- scRet = EncryptMessage(&sspi->context, 0, &message, 0);
-
- if (FAILED(scRet))
- {
- http_sspi_set_error("EncryptMessage");
- DEBUG_printf(("5_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), 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, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0);
-
- if (num <= 0)
- {
- DEBUG_printf(("5_httpTLSWrite: send failed: %ld", WSAGetLastError()));
- return (num);
- }
-
- bytesLeft -= chunk;
- bufptr += chunk;
- }
-
- return (len);
-}
-
-
-/*
- * 'http_sspi_alloc()' - Allocate SSPI object.
- */
-
-static _http_sspi_t * /* O - New SSPI/SSL object */
-http_sspi_alloc(void)
-{
- return ((_http_sspi_t *)calloc(1, sizeof(_http_sspi_t)));
-}
-
-
-/*
- * '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 */
-{
- _http_sspi_t *sspi = http->tls; /* SSPI data */
- DWORD dwSSPIFlags; /* SSL connection attributes we want */
- DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
- TimeStamp tsExpiry; /* Time stamp */
- SECURITY_STATUS scRet; /* Status */
- 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 */
- int ret = 0; /* Return value */
-
-
- DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname));
-
- dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
- ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_STREAM;
-
- /*
- * Lookup the client certificate...
- */
-
- if (!http_sspi_find_credentials(http, L"ClientContainer", NULL))
- {
- DEBUG_puts("5http_sspi_client: Unable to get client credentials.");
- return (-1);
- }
-
- /*
- * 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.ulVersion = SECBUFFER_VERSION;
-
- scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry);
-
- if (scRet != SEC_I_CONTINUE_NEEDED)
- {
- http_sspi_set_error("InitializeSecurityContext");
- DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- return (-1);
- }
-
- /*
- * Send response to server if there is one.
- */
-
- if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
- {
- if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0)
- {
- DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
- FreeContextBuffer(outBuffers[0].pvBuffer);
- DeleteSecurityContext(&sspi->context);
- return (-1);
- }
-
- DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData));
-
- FreeContextBuffer(outBuffers[0].pvBuffer);
- outBuffers[0].pvBuffer = NULL;
- }
-
- dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
- ISC_REQ_SEQUENCE_DETECT |
- ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_STREAM;
-
- sspi->decryptBufferUsed = 0;
-
- /*
- * 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 (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
- {
- if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
- {
- BYTE *temp; /* New buffer */
-
- if (sspi->decryptBufferLength >= 262144)
- {
- WSASetLastError(E_OUTOFMEMORY);
- DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)");
- return (-1);
- }
-
- if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
- {
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
- WSASetLastError(E_OUTOFMEMORY);
- return (-1);
- }
-
- sspi->decryptBufferLength += 4096;
- sspi->decryptBuffer = temp;
- }
-
- cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
-
- if (cbData < 0)
- {
- DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError()));
- return (-1);
- }
- else if (cbData == 0)
- {
- DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected."));
- return (-1);
- }
-
- DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData));
-
- sspi->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.
- */
-
- inBuffers[0].pvBuffer = sspi->decryptBuffer;
- inBuffers[0].cbBuffer = (unsigned long)sspi->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;
-
- /*
- * 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;
-
- /*
- * Call InitializeSecurityContext.
- */
-
- scRet = InitializeSecurityContext(&sspi->creds, &sspi->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 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(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
-
- if (cbData <= 0)
- {
- DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError()));
- FreeContextBuffer(outBuffers[0].pvBuffer);
- DeleteSecurityContext(&sspi->context);
- return (-1);
- }
-
- DEBUG_printf(("5http_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 (scRet == SEC_E_INCOMPLETE_MESSAGE)
- continue;
-
- /*
- * 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.
- */
-
- DEBUG_puts("5http_sspi_client: Handshake was successful.");
-
- if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
- {
- memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
-
- sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
-
- DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed));
- }
- else
- sspi->decryptBufferUsed = 0;
-
- /*
- * Bail out to quit
- */
-
- break;
- }
-
- /*
- * Check for fatal error.
- */
-
- if (FAILED(scRet))
- {
- http_sspi_set_error("InitializeSecurityContext");
- DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- ret = -1;
- break;
- }
-
- /*
- * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
- * then the server just requested client authentication.
- */
-
- if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
- {
- /*
- * Unimplemented
- */
-
- _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, "Need client credentials.", 0);
- DEBUG_printf(("5http_sspi_client: server requested client credentials."));
- ret = -1;
- break;
- }
-
- /*
- * Copy any leftover data from the "extra" buffer, and go around again.
- */
-
- if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
- {
- memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer);
-
- sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
- }
- else
- {
- sspi->decryptBufferUsed = 0;
- }
- }
-
- if (!ret)
- {
- /*
- * Success! Get the server cert
- */
-
- sspi->contextInitialized = TRUE;
-
- scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert));
-
- if (scRet != SEC_E_OK)
- {
- http_sspi_set_error("QueryContextAttributes");
- DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- return (-1);
- }
-
- /*
- * Find out how big the header/trailer will be:
- */
-
- scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
-
- if (scRet != SEC_E_OK)
- {
- http_sspi_set_error("QueryContextAttributes");
- DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- ret = -1;
- }
- }
-
- return (ret);
-}
-
-
-/*
- * 'http_sspi_create_credential()' - Create an SSPI certificate context.
- */
-
-static PCCERT_CONTEXT /* O - Certificate context */
-http_sspi_create_credential(
- http_credential_t *cred) /* I - Credential */
-{
- if (cred)
- return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, (DWORD)cred->datalen));
- else
- return (NULL);
-}
-
-
-/*
- * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store.
- */
-
-static BOOL /* O - 1 on success, 0 on failure */
-http_sspi_find_credentials(
- http_t *http, /* I - HTTP connection */
- const LPWSTR container, /* I - Cert container name */
- const char *common_name) /* I - Common name of certificate */
-{
- _http_sspi_t *sspi = http->tls; /* SSPI data */
- HCERTSTORE store = NULL; /* Certificate store */
- PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
- 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 */
- BOOL ok = TRUE; /* Return value */
-
-
- if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET /*| CRYPT_MACHINE_KEYSET*/))
- {
- if (GetLastError() == NTE_EXISTS)
- {
- if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, 0 /*CRYPT_MACHINE_KEYSET*/))
- {
- http_sspi_set_error("CryptAquireContext");
- DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
- ok = FALSE;
- goto cleanup;
- }
- }
- }
-
- store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
-
- if (!store)
- {
- http_sspi_set_error("CertOpenSystemStore");
- DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
- ok = FALSE;
- goto cleanup;
- }
-
- if (common_name)
- {
- dwSize = 0;
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
- {
- http_sspi_set_error("CertStrToName");
- DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
- ok = FALSE;
- goto cleanup;
- }
-
- p = (PBYTE)malloc(dwSize);
-
- if (!p)
- {
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize));
- ok = FALSE;
- goto cleanup;
- }
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
- {
- http_sspi_set_error("CertStrToName");
- DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
- ok = FALSE;
- goto cleanup;
- }
-
- sib.cbData = dwSize;
- sib.pbData = p;
-
- storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
-
- if (!storedContext)
- {
- http_sspi_set_error("CertFindCertificateInStore");
- DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name));
- ok = FALSE;
- goto cleanup;
- }
- }
-
- ZeroMemory(&SchannelCred, sizeof(SchannelCred));
-
- SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
-
- if (common_name)
- {
- SchannelCred.cCreds = 1;
- SchannelCred.paCred = &storedContext;
- }
-
- /*
- * Set supported protocols (can also be overridden in the registry...)
- */
-
-#ifdef SP_PROT_TLS1_2_SERVER
- if (http->mode == _HTTP_MODE_SERVER)
- {
- if (tls_min_version > _HTTP_TLS_1_1)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER;
- else if (tls_min_version > _HTTP_TLS_1_0)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER;
- else if (tls_min_version == _HTTP_TLS_SSL3)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER;
- else
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER;
- }
- else
- {
- if (tls_min_version > _HTTP_TLS_1_1)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
- else if (tls_min_version > _HTTP_TLS_1_0)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT;
- else if (tls_min_version == _HTTP_TLS_SSL3)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT;
- else
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT;
- }
-
-#else
- if (http->mode == _HTTP_MODE_SERVER)
- {
- if (tls_min_version == _HTTP_TLS_SSL3)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
- else
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
- }
- else
- {
- if (tls_min_version == _HTTP_TLS_SSL3)
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
- else
- SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
- }
-#endif /* SP_PROT_TLS1_2_SERVER */
-
- /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */
-
- /*
- * Create an SSPI credential.
- */
-
- Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
- if (Status != SEC_E_OK)
- {
- http_sspi_set_error("AcquireCredentialsHandle");
- DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
- ok = FALSE;
- goto cleanup;
- }
-
-cleanup:
-
- /*
- * Cleanup
- */
-
- if (storedContext)
- CertFreeCertificateContext(storedContext);
-
- if (p)
- free(p);
-
- if (store)
- CertCloseStore(store, 0);
-
- if (hProv)
- CryptReleaseContext(hProv, 0);
-
- return (ok);
-}
-
-
-/*
- * 'http_sspi_free()' - Close a connection and free resources.
- */
-
-static void
-http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */
-{
- if (!sspi)
- return;
-
- if (sspi->contextInitialized)
- DeleteSecurityContext(&sspi->context);
-
- if (sspi->decryptBuffer)
- free(sspi->decryptBuffer);
-
- if (sspi->readBuffer)
- free(sspi->readBuffer);
-
- if (sspi->writeBuffer)
- free(sspi->writeBuffer);
-
- if (sspi->localCert)
- CertFreeCertificateContext(sspi->localCert);
-
- if (sspi->remoteCert)
- CertFreeCertificateContext(sspi->remoteCert);
-
- free(sspi);
-}
-
-
-/*
- * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store.
- */
-
-static BOOL /* O - 1 on success, 0 on failure */
-http_sspi_make_credentials(
- _http_sspi_t *sspi, /* I - SSPI data */
- const LPWSTR container, /* I - Cert container name */
- const char *common_name, /* I - Common name of certificate */
- _http_mode_t mode, /* I - Client or server? */
- int years) /* I - Years until expiration */
-{
- 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 */
-
-
- DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years));
-
- if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET /* | CRYPT_MACHINE_KEYSET*/))
- {
- if (GetLastError() == NTE_EXISTS)
- {
- if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, 0 /*CRYPT_MACHINE_KEYSET*/))
- {
- http_sspi_set_error("CryptAquireContext");
- DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
-// fprintf(stderr, "5http_sspi_make_credentials: CryptAcquireContext failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
- }
- }
-
- store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY");
-
- if (!store)
- {
- http_sspi_set_error("CertOpenSystemStore");
- DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
-// fprintf(stderr, "5http_sspi_make_credentials: CertOpenSystemStore failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
-
- dwSize = 0;
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL))
- {
- http_sspi_set_error("CertStrToName");
- DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
-// fprintf(stderr, "5http_sspi_make_credentials: CertStrToName failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
-
- p = (PBYTE)malloc(dwSize);
-
- if (!p)
- {
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize));
-// fprintf(stderr, "5http_sspi_make_credentials: malloc failed for %d bytes\n", dwSize);
- ok = FALSE;
- goto cleanup;
- }
-
- if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL))
- {
- http_sspi_set_error("CertStrToName");
- DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
-// fprintf(stderr, "5http_sspi_make_credentials: CertStrToName failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
-
- sib.cbData = dwSize;
- sib.pbData = p;
-
- /*
- * Create a private key and self-signed certificate...
- */
-
- if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE | RSA1024BIT_KEY, &hKey))
- {
- http_sspi_set_error("CryptGenKey");
- DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
-// fprintf(stderr, "5http_sspi_make_credentials: CryptGenKey failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
-
- 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;
-
- GetSystemTime(&et);
- et.wYear += years;
- if (et.wMonth == 2 && et.wDay == 29)
- et.wDay = 28; /* Avoid Feb 29th due to leap years */
-
- ZeroMemory(&exts, sizeof(exts));
-
- createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts);
-
- if (!createdContext)
- {
- http_sspi_set_error("CertCreateSelfSignCertificate");
- DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
-// fprintf(stderr, "5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()));
- ok = FALSE;
- goto cleanup;
- }
-
- /*
- * Add the created context to the named store, and associate it with the named
- * container...
- */
-
- if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext))
- {
- http_sspi_set_error("CertAddCertificateContextToStore");
- DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
- ok = FALSE;
- goto cleanup;
- }
-
- ZeroMemory(&ckp, sizeof(ckp));
- ckp.pwszContainerName = (LPWSTR) container;
- ckp.pwszProvName = MS_DEF_PROV_W;
- ckp.dwProvType = PROV_RSA_FULL;
- ckp.dwFlags = 0 /*CRYPT_MACHINE_KEYSET*/;
- ckp.dwKeySpec = AT_KEYEXCHANGE;
-
- if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp))
- {
- http_sspi_set_error("CertSetCertificateContextProperty");
- DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError())));
- ok = FALSE;
- goto cleanup;
- }
-
- /*
- * Get a handle to use the certificate...
- */
-
- ZeroMemory(&SchannelCred, sizeof(SchannelCred));
-
- SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
- SchannelCred.cCreds = 1;
- SchannelCred.paCred = &storedContext;
-
- /*
- * Create an SSPI credential.
- */
-
- Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry);
- if (Status != SEC_E_OK)
- {
- http_sspi_set_error("AcquireCredentialsHandle");
- DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status)));
-// fprintf(stderr, "5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s\n", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status));
- ok = FALSE;
- goto cleanup;
- }
-
-cleanup:
-
- /*
- * Cleanup
- */
-
- if (hKey)
- CryptDestroyKey(hKey);
-
- if (createdContext)
- CertFreeCertificateContext(createdContext);
-
- if (storedContext)
- CertFreeCertificateContext(storedContext);
-
- if (p)
- free(p);
-
- if (store)
- CertCloseStore(store, 0);
-
- if (hProv)
- CryptReleaseContext(hProv, 0);
-
- return (ok);
-}
-
-
-/*
- * 'http_sspi_server()' - Negotiate a TLS connection as a server.
- */
-
-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 */
-{
- _http_sspi_t *sspi = http->tls; /* SSPI data */
- char common_name[512]; /* Common name for cert */
- 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(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname));
-
- dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
- ASC_REQ_REPLAY_DETECT |
- ASC_REQ_CONFIDENTIALITY |
- ASC_REQ_EXTENDED_ERROR |
- ASC_REQ_ALLOCATE_MEMORY |
- ASC_REQ_STREAM;
-
- sspi->decryptBufferUsed = 0;
-
- /*
- * Lookup the server certificate...
- */
-
- snprintf(common_name, sizeof(common_name), "CN=%s", hostname);
-
- if (!http_sspi_find_credentials(http, L"ServerContainer", common_name))
- if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10))
- {
- DEBUG_puts("5http_sspi_server: Unable to get server credentials.");
- return (-1);
- }
-
- /*
- * 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 (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
- {
- if (sspi->decryptBufferLength <= sspi->decryptBufferUsed)
- {
- BYTE *temp; /* New buffer */
-
- if (sspi->decryptBufferLength >= 262144)
- {
- WSASetLastError(E_OUTOFMEMORY);
- DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)");
- return (-1);
- }
-
- if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL)
- {
- _cupsSetHTTPError(HTTP_STATUS_ERROR);
- DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096));
- WSASetLastError(E_OUTOFMEMORY);
- return (-1);
- }
-
- sspi->decryptBufferLength += 4096;
- sspi->decryptBuffer = temp;
- }
-
- for (;;)
- {
- num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0);
-
- if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
- Sleep(1);
- else
- break;
- }
-
- if (num < 0)
- {
- DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError()));
- return (-1);
- }
- else if (num == 0)
- {
- DEBUG_puts("5http_sspi_server: client disconnected");
- return (-1);
- }
-
- DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num));
- sspi->decryptBufferUsed += num;
- }
-
- /*
- * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process
- * on this run around the loop.
- */
-
- inBuffers[0].pvBuffer = sspi->decryptBuffer;
- inBuffers[0].cbBuffer = (unsigned long)sspi->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;
-
- /*
- * 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;
-
- scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry);
-
- 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)
- {
- /*
- * Send response to server if there is one.
- */
-
- num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
-
- if (num <= 0)
- {
- DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError()));
- return (-1);
- }
-
- DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer));
-
- 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.
- */
-
- if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
- {
- memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
- sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
- }
- else
- {
- sspi->decryptBufferUsed = 0;
- }
- break;
- }
- else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE)
- {
- http_sspi_set_error("AcceptSecurityContext");
- DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- ret = -1;
- break;
- }
-
- if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
- scRet != SEC_I_INCOMPLETE_CREDENTIALS)
- {
- if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
- {
- memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer);
- sspi->decryptBufferUsed = inBuffers[1].cbBuffer;
- }
- else
- {
- sspi->decryptBufferUsed = 0;
- }
- }
- }
-
- if (!ret)
- {
- sspi->contextInitialized = TRUE;
-
- /*
- * Find out how big the header will be:
- */
-
- scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes);
-
- if (scRet != SEC_E_OK)
- {
- http_sspi_set_error("QueryContextAttributes");
- DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet)));
- ret = -1;
- }
- }
-
- return (ret);
-}
-
-
-//
-// 'http_sspi_set_error()' - Copy the Windows error string to the CUPS error string.
-//
-
-static void
-http_sspi_set_error(const char *title) // I - Prefix/title for error
-{
- char temp[8192]; // Error string
- size_t templen; // Length of prefix
-
-
- snprintf(temp, sizeof(temp), "%s (%08x): ", title, GetLastError());
- templen = strlen(temp);
- http_sspi_strerror(temp + templen, sizeof(temp) - templen, GetLastError());
- _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, temp, 0);
-}
-
-
-/*
- * 'http_sspi_strerror()' - Return a string for the specified error code.
- */
-
-static const char * /* O - String for error */
-http_sspi_strerror(char *buffer, /* I - Error message buffer */
- size_t bufsize, /* I - Size of buffer */
- DWORD code) /* I - Error code */
-{
- if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, (DWORD)bufsize, NULL))
- {
- /*
- * Strip trailing CR + LF...
- */
-
- char *ptr; /* Pointer into error message */
-
- for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --)
- if (*ptr == '\n' || *ptr == '\r')
- *ptr = '\0';
- else
- break;
- }
- else
- snprintf(buffer, bufsize, "Unknown error %x", code);
-
- return (buffer);
-}
-
-
-/*
- * 'http_sspi_verify()' - Verify a certificate.
- */
-
-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;
- /* Certificate chain */
- 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);
- /* Number of ites in rgszUsages */
- DWORD count; /* 32 bit count variable */
- DWORD status; /* Return value */
-#ifdef DEBUG
- char error[1024]; /* Error message string */
-#endif /* DEBUG */
-
-
- if (!cert)
- return (SEC_E_WRONG_PRINCIPAL);
-
- /*
- * Convert common name to Unicode.
- */
-
- 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))
- {
- 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, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext))
- {
- status = GetLastError();
-
- http_sspi_set_error("CertGetCertificateChain");
- DEBUG_printf(("5http_sspi_verify: CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
-
- LocalFree(commonNameUnicode);
- return (status);
- }
-
- /*
- * Validate certificate chain.
- */
-
- ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
- httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
- httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
- httpsPolicy.fdwChecks = dwCertFlags;
- httpsPolicy.pwszServerName = commonNameUnicode;
-
- memset(&policyPara, 0, sizeof(policyPara));
- policyPara.cbSize = sizeof(policyPara);
- policyPara.pvExtraPolicyPara = &httpsPolicy;
-
- memset(&policyStatus, 0, sizeof(policyStatus));
- policyStatus.cbSize = sizeof(policyStatus);
-
- if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus))
- {
- status = GetLastError();
-
- http_sspi_set_error("CertVerifyCertificateChainPolicy");
- DEBUG_printf(("5http_sspi_verify: CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
- }
- else if (policyStatus.dwError)
- status = policyStatus.dwError;
- else
- status = SEC_E_OK;
-
- if (chainContext)
- CertFreeCertificateChain(chainContext);
-
- if (commonNameUnicode)
- LocalFree(commonNameUnicode);
-
- return (status);
-}
* Include platform-specific TLS code...
*/
-#ifdef HAVE_TLS
-# ifdef HAVE_OPENSSL
-# include "tls-openssl.c"
-# elif defined(HAVE_GNUTLS)
-# include "tls-gnutls.c"
-# elif defined(HAVE_CDSASSL)
-# include "tls-darwin.c"
-# elif defined(HAVE_SSPISSL)
-# include "tls-sspi.c"
-# endif /* HAVE_GNUTLS */
-#else
-/* Stubs for when TLS is not supported/available */
-int
-httpCopyCredentials(http_t *http, cups_array_t **credentials)
-{
- (void)http;
- if (credentials)
- *credentials = NULL;
- return (-1);
-}
-int
-httpCredentialsAreValidForName(cups_array_t *credentials, const char *common_name)
-{
- (void)credentials;
- (void)common_name;
- return (1);
-}
-time_t
-httpCredentialsGetExpiration(cups_array_t *credentials)
-{
- (void)credentials;
- return (INT_MAX);
-}
-http_trust_t
-httpCredentialsGetTrust(cups_array_t *credentials, const char *common_name)
-{
- (void)credentials;
- (void)common_name;
- return (HTTP_TRUST_OK);
-}
-size_t
-httpCredentialsString(cups_array_t *credentials, char *buffer, size_t bufsize)
-{
- (void)credentials;
- (void)bufsize;
- if (buffer)
- *buffer = '\0';
- return (0);
-}
-int
-httpLoadCredentials(const char *path, cups_array_t **credentials, const char *common_name)
-{
- (void)path;
- (void)credentials;
- (void)common_name;
- return (-1);
-}
-int
-httpSaveCredentials(const char *path, cups_array_t *credentials, const char *common_name)
-{
- (void)path;
- (void)credentials;
- (void)common_name;
- return (-1);
-}
-#endif /* HAVE_TLS */
+#ifdef HAVE_OPENSSL
+# include "tls-openssl.c"
+#else /* HAVE_GNUTLS */
+# include "tls-gnutls.c"
+#endif /* HAVE_OPENSSL */
#include "cups-private.h"
-#ifndef HAVE_TLS
-int main(void) { puts("Sorry, no TLS support compiled in."); return (1); }
-#else
-
/*
* Local functions...
*/
exit(1);
}
-#endif /* !HAVE_TLS */
{
_cups_digestoptions_t digestoptions; /* DigestOptions values */
_cups_uatokens_t uatokens; /* UserAgentTokens values */
-#ifdef HAVE_TLS
int ssl_options, /* SSLOptions values */
ssl_min_version,/* Minimum SSL/TLS version */
ssl_max_version;/* Maximum SSL/TLS version */
-#endif /* HAVE_TLS */
int trust_first, /* Trust on first use? */
any_root, /* Allow any (e.g., self-signed) root */
expired_certs, /* Allow expired certs */
*/
#ifdef __APPLE__
-# ifdef HAVE_TLS
static int cups_apple_get_boolean(CFStringRef key, int *value);
-# endif /* HAVE_TLS */
static int cups_apple_get_string(CFStringRef key, char *value, size_t valsize);
#endif /* __APPLE__ */
static int cups_boolean_value(const char *value);
static void cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
#endif /* HAVE_GSSAPI */
static void cups_set_server_name(_cups_client_conf_t *cc, const char *value);
-#ifdef HAVE_TLS
static void cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
-#endif /* HAVE_TLS */
static void cups_set_uatokens(_cups_client_conf_t *cc, const char *value);
static void cups_set_user(_cups_client_conf_t *cc, const char *value);
if (cupsArrayCount(credentials) < 1)
return (-1);
-#ifdef HAVE_TLS
_httpFreeCredentials(cg->tls_credentials);
cg->tls_credentials = _httpCreateCredentials(credentials);
-#endif /* HAVE_TLS */
return (cg->tls_credentials ? 0 : -1);
}
if (cg->validate_certs < 0)
cg->validate_certs = cc.validate_certs;
-#ifdef HAVE_TLS
_httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version);
-#endif /* HAVE_TLS */
}
#ifdef __APPLE__
-# ifdef HAVE_TLS
/*
* 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
*/
return ((int)bval_set);
}
-# endif /* HAVE_TLS */
/*
cups_set_user(cc, "mobile");
#endif /* __APPLE__ && !TARGET_OS_OSX */
-#ifdef HAVE_TLS
cc->ssl_min_version = _HTTP_TLS_1_0;
cc->ssl_max_version = _HTTP_TLS_MAX;
-#endif /* HAVE_TLS */
cc->encryption = (http_encryption_t)-1;
cc->trust_first = -1;
cc->any_root = -1;
#if defined(__APPLE__)
char sval[1024]; /* String value */
-# ifdef HAVE_TLS
int bval; /* Boolean value */
if (cups_apple_get_boolean(kAllowAnyRootKey, &bval))
if (cups_apple_get_boolean(kValidateCertsKey, &bval))
cc->validate_certs = bval;
-# endif /* HAVE_TLS */
if (cups_apple_get_string(kDigestOptionsKey, sval, sizeof(sval)))
cups_set_digestoptions(cc, sval);
else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
cups_set_gss_service_name(cc, value);
#endif /* HAVE_GSSAPI */
-#ifdef HAVE_TLS
else if (!_cups_strcasecmp(line, "SSLOptions") && value)
cups_set_ssl_options(cc, value);
-#endif /* HAVE_TLS */
}
}
* 'cups_set_ssl_options()' - Set the SSLOptions value.
*/
-#ifdef HAVE_TLS
static void
cups_set_ssl_options(
_cups_client_conf_t *cc, /* I - client.conf values */
DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version));
}
-#endif /* HAVE_TLS */
/*
if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
return (HTTP_FORBIDDEN);
-#ifdef HAVE_TLS
/*
* See if encryption is required...
*/
"cupsdIsAuthorized: Need upgrade to TLS...");
return (HTTP_UPGRADE_REQUIRED);
}
-#endif /* HAVE_TLS */
/*
* Now see what access level is required...
VAR cups_array_t *Locations VALUE(NULL);
/* Authorization locations */
-#ifdef HAVE_TLS
VAR http_encryption_t DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED);
/* Default encryption for authentication */
-#endif /* HAVE_TLS */
/*
struct stat *filestats);
static int compare_clients(cupsd_client_t *a, cupsd_client_t *b,
void *data);
-#ifdef HAVE_TLS
static int cupsd_start_tls(cupsd_client_t *con, http_encryption_t e);
-#endif /* HAVE_TLS */
static char *get_file(cupsd_client_t *con, struct stat *filestats,
char *filename, size_t len);
static http_status_t install_cupsd_conf(cupsd_client_t *con);
if (cupsArrayCount(Clients) == MaxClients)
cupsdPauseListening();
-#ifdef HAVE_TLS
/*
* See if we are connecting on a secure port...
*/
}
else
con->auto_ssl = 1;
-#endif /* HAVE_TLS */
}
cupsArrayRemove(ActiveClients, con);
cupsdSetBusyState(0);
-#ifdef HAVE_TLS
/*
* Shutdown encryption as needed...
*/
if (httpIsEncrypted(con->http))
partial = 1;
-#endif /* HAVE_TLS */
if (partial)
{
return;
}
-#ifdef HAVE_TLS
if (con->auto_ssl)
{
/*
return;
}
}
-#endif /* HAVE_TLS */
switch (httpGetState(con->http))
{
if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), "Upgrade") && strstr(httpGetField(con->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(con->http))
{
-#ifdef HAVE_TLS
/*
* Do encryption stuff...
*/
cupsdCloseClient(con);
return;
}
-#else
- if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
- {
- cupsdCloseClient(con);
- return;
- }
-#endif /* HAVE_TLS */
}
httpClearFields(con->http);
if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION),
"Upgrade") && !httpIsEncrypted(con->http))
{
-#ifdef HAVE_TLS
/*
* Do encryption stuff...
*/
cupsdCloseClient(con);
return;
}
-#else
- if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
- {
- cupsdCloseClient(con);
- return;
- }
-#endif /* HAVE_TLS */
}
if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_STATUS_OK)
cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cupsdSendError code=%d, auth_type=%d", code, auth_type);
-#ifdef HAVE_TLS
/*
* Force client to upgrade for authentication if that is how the
* server is configured...
{
code = HTTP_STATUS_UPGRADE_REQUIRED;
}
-#endif /* HAVE_TLS */
/*
* Put the request in the access_log file...
}
-#ifdef HAVE_TLS
/*
* 'cupsd_start_tls()' - Start encryption on a connection.
*/
cupsdLogClient(con, CUPSD_LOG_DEBUG, "Connection now encrypted.");
return (0);
}
-#endif /* HAVE_TLS */
/*
header_used; /* Number of header bytes used */
char header[2048]; /* Header from CGI program */
cups_lang_t *language; /* Language to use */
-#ifdef HAVE_TLS
int auto_ssl; /* Automatic test for SSL/TLS */
-#endif /* HAVE_TLS */
http_addr_t clientaddr; /* Client's server address */
char clientname[256];/* Client's server name for connection */
int clientport; /* Client's server port for connection */
extern void cupsdUpdateCGI(void);
extern void cupsdWriteClient(cupsd_client_t *con);
-#ifdef HAVE_TLS
extern int cupsdEndTLS(cupsd_client_t *con);
extern int cupsdStartTLS(cupsd_client_t *con);
-#endif /* HAVE_TLS */
{ "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING },
{ "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING },
{ "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_PERM },
-#ifdef HAVE_TLS
{ "CreateSelfSignedCerts", &CreateSelfSignedCerts, CUPSD_VARTYPE_BOOLEAN },
-#endif /* HAVE_TLS */
{ "DataDir", &DataDir, CUPSD_VARTYPE_STRING },
{ "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING },
{ "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING },
{ "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING },
{ "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING },
{ "ServerBin", &ServerBin, CUPSD_VARTYPE_PATHNAME },
-#ifdef HAVE_TLS
{ "ServerKeychain", &ServerKeychain, CUPSD_VARTYPE_PATHNAME },
-#endif /* HAVE_TLS */
{ "ServerRoot", &ServerRoot, CUPSD_VARTYPE_PATHNAME },
{ "StateDir", &StateDir, CUPSD_VARTYPE_STRING },
{ "SyncOnClose", &SyncOnClose, CUPSD_VARTYPE_BOOLEAN },
cupsdClearString(&Classification);
ClassifyOverride = 0;
-#ifdef HAVE_TLS
-# if defined HAVE_GNUTLS || defined HAVE_OPENSSL
cupsdSetString(&ServerKeychain, "ssl");
-# else
- cupsdSetString(&ServerKeychain, "/Library/Keychains/System.keychain");
-# endif /* HAVE_GNUTLS || HAVE_OPENSSL */
_httpTLSSetOptions(_HTTP_TLS_NONE, _HTTP_TLS_1_0, _HTTP_TLS_MAX);
-#endif /* HAVE_TLS */
language = cupsLangDefault();
ConfigFilePerm = CUPS_DEFAULT_CONFIG_FILE_PERM;
FatalErrors = parse_fatal_errors(CUPS_DEFAULT_FATAL_ERRORS);
default_auth_type = CUPSD_AUTH_BASIC;
-#ifdef HAVE_TLS
CreateSelfSignedCerts = TRUE;
DefaultEncryption = HTTP_ENCRYPT_REQUIRED;
-#endif /* HAVE_TLS */
DirtyCleanInterval = DEFAULT_KEEPALIVE;
JobKillDelay = DEFAULT_TIMEOUT;
JobRetryLimit = 5;
if (CacheDir[0] != '/')
cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir);
-#ifdef HAVE_TLS
if (!_cups_strcasecmp(ServerKeychain, "internal"))
cupsdClearString(&ServerKeychain);
else if (ServerKeychain[0] != '/')
if (!CreateSelfSignedCerts)
cupsdLogMessage(CUPSD_LOG_DEBUG, "Self-signed TLS certificate generation is disabled.");
cupsSetServerCredentials(ServerKeychain, ServerName, CreateSelfSignedCerts);
-#endif /* HAVE_TLS */
/*
* Make sure that directories and config files are owned and
"FaxRetryLimit is deprecated; use "
"JobRetryLimit on line %d of %s.", linenum, ConfigurationFile);
}
-#ifdef HAVE_TLS
else if (!_cups_strcasecmp(line, "SSLOptions"))
{
/*
_httpTLSSetOptions(options, min_version, max_version);
}
-#endif /* HAVE_TLS */
- else if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")
-#ifdef HAVE_TLS
- || !_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen")
-#endif /* HAVE_TLS */
- ) && value)
+ else if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen") || !_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen")) && value)
{
/*
* Add listening address(es) to the list...
memcpy(&(lis->address), &(addr->addr), sizeof(lis->address));
lis->fd = -1;
-#ifdef HAVE_TLS
if (!_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen"))
lis->encryption = HTTP_ENCRYPT_ALWAYS;
-#endif /* HAVE_TLS */
httpAddrString(&lis->address, temp, sizeof(temp));
return (0);
}
}
-#ifdef HAVE_TLS
else if (!_cups_strcasecmp(line, "DefaultEncryption"))
{
/*
return (0);
}
}
-#endif /* HAVE_TLS */
else if (!_cups_strcasecmp(line, "HostNameLookups") && value)
{
/*
VAR const char **MimeTypes VALUE(NULL);
/* Array of MIME types */
-#ifdef HAVE_TLS
VAR int CreateSelfSignedCerts VALUE(TRUE);
/* Automatically create self-signed certs? */
VAR char *ServerKeychain VALUE(NULL);
/* Keychain holding cert + key */
-#endif /* HAVE_TLS */
#ifdef HAVE_ONDEMAND
VAR int IdleExitTimeout VALUE(60);
* Get the URL scheme for the admin page...
*/
-# ifdef HAVE_TLS
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
if (lis->encryption != HTTP_ENCRYPTION_NEVER)
break;
}
}
-# endif /* HAVE_TLS */
httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), admin_scheme, NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
keyvalue[count ][0] = "adminurl";
keyvalue[count ][0] = "UUID";
keyvalue[count++][1] = p->uuid + 9;
-#ifdef HAVE_TLS
keyvalue[count ][0] = "TLS";
- keyvalue[count++][1] = "1.2";
-#endif /* HAVE_TLS */
+ keyvalue[count++][1] = "1.3";
if ((urf_supported = ippFindAttribute(p->ppd_attrs, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
{
dnssdDeregisterInstance(&p->ipp_srv, from_callback);
# ifdef HAVE_MDNSRESPONDER
-# ifdef HAVE_TLS
dnssdDeregisterInstance(&p->ipps_srv, from_callback);
-# endif /* HAVE_TLS */
dnssdDeregisterInstance(&p->printer_srv, from_callback);
# endif /* HAVE_MDNSRESPONDER */
}
# ifdef HAVE_MDNSRESPONDER
if (!strcmp(type, "_printer._tcp"))
srv = &p->printer_srv; /* Target LPD service */
-# ifdef HAVE_TLS
else if (!strcmp(type, "_ipps._tcp"))
srv = &p->ipps_srv; /* Target IPPS service */
-# endif /* HAVE_TLS */
else
srv = &p->ipp_srv; /* Target IPP service */
status = dnssdRegisterInstance(NULL, p, name, "_printer._tcp", NULL, 0, NULL, 0, from_callback);
-# ifdef HAVE_TLS
if (status)
dnssdRegisterInstance(NULL, p, name, "_ipps._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 0, from_callback);
-# endif /* HAVE_TLS */
if (status)
{
dnssdDeregisterInstance(&p->ipp_srv, from_callback);
# ifdef HAVE_MDNSRESPONDER
-# ifdef HAVE_TLS
dnssdDeregisterInstance(&p->ipps_srv, from_callback);
-# endif /* HAVE_TLS */
dnssdDeregisterInstance(&p->printer_srv, from_callback);
# endif /* HAVE_MDNSRESPONDER */
}
send_http_error(con, HTTP_UNAUTHORIZED, printer);
return (NULL);
}
-#ifdef HAVE_TLS
else if (auth_info && !con->http->tls &&
!httpAddrLocalhost(con->http->hostaddr))
{
send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
return (NULL);
}
-#endif /* HAVE_TLS */
/*
* See if the printer is accepting jobs...
{
http_status_t status; /* Policy status */
ipp_attribute_t *attr; /* Current attribute */
-#ifdef HAVE_TLS
ipp_attribute_t *auth_info; /* auth-info attribute */
-#endif /* HAVE_TLS */
ipp_attribute_t *format, /* Document-format attribute */
*name; /* Job-name attribute */
cups_ptype_t dtype; /* Destination type (printer/class) */
* Check policy...
*/
-#ifdef HAVE_TLS
auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
-#endif /* HAVE_TLS */
if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
{
send_http_error(con, HTTP_UNAUTHORIZED, printer);
return;
}
-#ifdef HAVE_TLS
else if (auth_info && !con->http->tls &&
!httpAddrLocalhost(con->http->hostaddr))
{
send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
return;
}
-#endif /* HAVE_TLS */
/*
* Everything was ok, so return OK status...
lis->fd = fd;
lis->on_demand = 1;
-# ifdef HAVE_TLS
if (httpAddrPort(&(lis->address)) == 443)
lis->encryption = HTTP_ENCRYPT_ALWAYS;
-# endif /* HAVE_TLS */
}
#endif /* HAVE_ONDEMAND */
*pdl; /* pdl value for TXT record */
cupsd_srv_t ipp_srv; /* IPP service(s) */
# ifdef HAVE_MDNSRESPONDER
-# ifdef HAVE_TLS
cupsd_srv_t ipps_srv; /* IPPS service(s) */
-# endif /* HAVE_TLS */
cupsd_srv_t printer_srv; /* LPD service */
# endif /* HAVE_MDNSRESPONDER */
#endif /* HAVE_DNSSD */
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
if (http)
httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'U' : /* Username */
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), command);
-#endif /* HAVE_TLS */
break;
case 'U' : /* Username */
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'U' : /* Username */
case 'E' : /* Enable the printer/enable encryption */
if (printer == NULL)
{
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED);
if (http)
httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
}
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'h' : /* Connect to host */
switch (*opt)
{
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
-#endif /* HAVE_TLS */
break;
case 'h' : /* Connect to host */
break;
case 'E' : /* Encrypt */
-#ifdef HAVE_TLS
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-#else
- _cupsLangPrintf(stderr,
- _("%s: Sorry, no encryption support."),
- argv[0]);
-#endif /* HAVE_TLS */
break;
case 'H' : /* Show server and port */
* URL scheme for web resources...
*/
-#ifdef HAVE_TLS
-# define WEB_SCHEME "https"
-#else
-# define WEB_SCHEME "http"
-#endif /* HAVE_TLS */
+#define WEB_SCHEME "https"
/*
*device_uri = NULL, /* Device URI */
*output_format = NULL, /* Output format */
*icon = NULL, /* Icon file */
-#ifdef HAVE_TLS
*keypath = NULL, /* Keychain path */
-#endif /* HAVE_TLS */
*location = "", /* Location of printer */
*make = "Example", /* Manufacturer */
*model = "Printer", /* Model */
output_format = argv[i];
break;
-#ifdef HAVE_TLS
case 'K' : /* -K keypath */
i ++;
if (i >= argc)
keypath = argv[i];
break;
-#endif /* HAVE_TLS */
case 'M' : /* -M manufacturer */
i ++;
printer->ppdfile = strdup(ppdfile);
#endif /* !CUPS_LITE */
-#ifdef HAVE_TLS
cupsSetServerCredentials(keypath, printer->hostname, 1);
-#endif /* HAVE_TLS */
/*
* Run the print service...
{ /* reference-uri-schemes-supported */
"file",
"ftp",
- "http"
-#ifdef HAVE_TLS
- , "https"
-#endif /* HAVE_TLS */
+ "http",
+ "https"
};
-#ifdef HAVE_TLS
static const char * const uri_authentication_supported[] =
{ /* uri-authentication-supported values */
"none",
"none",
"tls"
};
-#endif /* HAVE_TLS */
static const char * const which_jobs[] =
{ /* which-jobs-supported values */
"completed",
if (Verbosity)
{
-#ifdef HAVE_TLS
fprintf(stderr, "printer-uri-supported=\"ipp://%s:%d/ipp/print\",\"ipps://%s:%d/ipp/print\"\n", printer->hostname, printer->port, printer->hostname, printer->port);
-#else
- fprintf(stderr, "printer-uri-supported=\"ipp://%s:%d/ipp/print\"\n", printer->hostname, printer->port);
-#endif /* HAVE_TLS */
fprintf(stderr, "printer-uuid=\"%s\"\n", uuid);
}
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_URISCHEME), "reference-uri-schemes-supported", (int)(sizeof(reference_uri_schemes_supported) / sizeof(reference_uri_schemes_supported[0])), NULL, reference_uri_schemes_supported);
/* uri-authentication-supported */
-#ifdef HAVE_TLS
if (PAMService)
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", 2, NULL, uri_authentication_basic);
else
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", 2, NULL, uri_authentication_supported);
-#else
- if (PAMService)
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", NULL, "basic");
- else
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", NULL, "none");
-#endif /* HAVE_TLS */
/* uri-security-supported */
-#ifdef HAVE_TLS
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", 2, NULL, uri_security_supported);
-#else
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", NULL, "none");
-#endif /* HAVE_TLS */
/* which-jobs-supported */
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "which-jobs-supported", sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs);
goto abort_job;
}
- if (strcmp(scheme, "file") &&
-#ifdef HAVE_TLS
- strcmp(scheme, "https") &&
-#endif /* HAVE_TLS */
- strcmp(scheme, "http"))
+ if (strcmp(scheme, "file") && strcmp(scheme, "https") && strcmp(scheme, "http"))
{
respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme \"%s\" not supported.", scheme);
}
else
{
-#ifdef HAVE_TLS
if (port == 443 || !strcmp(scheme, "https"))
encryption = HTTP_ENCRYPTION_ALWAYS;
else
-#endif /* HAVE_TLS */
- encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+ encryption = HTTP_ENCRYPTION_IF_REQUESTED;
if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL)
{
httpAssembleURI(HTTP_URI_CODING_ALL, uris[0], sizeof(uris[0]), "ipp", NULL, client->host_field, client->host_port, "/ipp/print");
values[num_values ++] = uris[0];
-#ifdef HAVE_TLS
httpAssembleURI(HTTP_URI_CODING_ALL, uris[1], sizeof(uris[1]), "ipps", NULL, client->host_field, client->host_port, "/ipp/print");
values[num_values ++] = uris[1];
-#endif /* HAVE_TLS */
ippAddStrings(client->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", num_values, NULL, values);
}
* Loop until we are out of requests or timeout (30 seconds)...
*/
-#ifdef HAVE_TLS
int first_time = 1; /* First time request? */
-#endif /* HAVE_TLS */
+
while (httpWait(client->http, 30000))
{
-#ifdef HAVE_TLS
if (first_time)
{
/*
first_time = 0;
}
-#endif /* HAVE_TLS */
if (!process_http(client))
break;
if (!strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION), "Upgrade"))
{
-#ifdef HAVE_TLS
if (strstr(httpGetField(client->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(client->http))
{
if (!respond_http(client, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, NULL, 0))
fprintf(stderr, "%s Connection now encrypted.\n", client->hostname);
}
- else
-#endif /* HAVE_TLS */
-
- if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0))
+ else if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0))
return (0);
}
TXTRecordSetValue(&ipp_txt, "Duplex", 1, ippGetCount(sides_supported) > 1 ? "T" : "F");
if ((value = ippGetString(printer_uuid, 0, NULL)) != NULL)
TXTRecordSetValue(&ipp_txt, "UUID", (uint8_t)strlen(value) - 9, value + 9);
-# ifdef HAVE_TLS
- TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.2");
-# endif /* HAVE_TLS */
+ TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.3");
if (urf[0])
TXTRecordSetValue(&ipp_txt, "URF", (uint8_t)strlen(urf), urf);
TXTRecordSetValue(&ipp_txt, "txtvers", 1, "1");
return (0);
}
-# ifdef HAVE_TLS
/*
* Then register the _ipps._tcp (IPP) service type with the real port number to
* advertise our IPPS printer...
_cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, regtype, error);
return (0);
}
-# endif /* HAVE_TLS */
/*
* Similarly, register the _http._tcp,_printer (HTTP) service type with the
ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=%s", ippGetCount(sides_supported) > 1 ? "T" : "F");
if ((value = ippGetString(printer_uuid, 0, NULL)) != NULL)
ipp_txt = avahi_string_list_add_printf(ipp_txt, "UUID=%s", value + 9);
-# ifdef HAVE_TLS
ipp_txt = avahi_string_list_add_printf(ipp_txt, "TLS=1.2");
-# endif /* HAVE_TLS */
if (urf[0])
ipp_txt = avahi_string_list_add_printf(ipp_txt, "URF=%s", urf);
ipp_txt = avahi_string_list_add_printf(ipp_txt, "txtvers=1");
free(temptypes);
}
-#ifdef HAVE_TLS
/*
* _ipps._tcp (IPPS) for secure printing...
*/
free(temptypes);
}
-#endif /* HAVE_TLS */
/*
* Finally _http.tcp (HTTP) for the web interface...
/*
* Make sure the number of trays is consistent.
*/
-
+
if (num_sources != ippGetCount(input_tray))
{
html_printf(client, "<p>Error: Different number of trays in media-source-supported and printer-input-tray defined for printer.</p>\n");
_cupsLangPuts(stdout, _("-A Enable authentication"));
_cupsLangPuts(stdout, _("-D device-uri Set the device URI for the printer"));
_cupsLangPuts(stdout, _("-F output-type/subtype Set the output format for the printer"));
-#ifdef HAVE_TLS
_cupsLangPuts(stdout, _("-K keypath Set location of server X.509 certificates and keys."));
-#endif /* HAVE_TLS */
_cupsLangPuts(stdout, _("-M manufacturer Set manufacturer name (default=Test)"));
#if !CUPS_LITE
_cupsLangPuts(stdout, _("-P filename.ppd Load printer attributes from PPD file"));
break;
case 'E' : /* Encrypt with TLS */
-#ifdef HAVE_TLS
data.encryption = HTTP_ENCRYPT_REQUIRED;
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
- argv[0]);
-#endif /* HAVE_TLS */
break;
case 'I' : /* Ignore errors */
break;
case 'S' : /* Encrypt with SSL */
-#ifdef HAVE_TLS
data.encryption = HTTP_ENCRYPT_ALWAYS;
-#else
- _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), "ipptool");
-#endif /* HAVE_TLS */
break;
case 'T' : /* Set timeout */
}
}
}
- else if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "http://", 7)
-#ifdef HAVE_TLS
- || !strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8)
-#endif /* HAVE_TLS */
- )
+ else if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "http://", 7) || !strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8))
{
/*
* Set URI...
usage();
}
-#ifdef HAVE_TLS
if (!strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8))
data.encryption = HTTP_ENCRYPT_ALWAYS;
-#endif /* HAVE_TLS */
if (!_ippVarsSet(data.vars, "uri", argv[i]))
{
}
-/*
+/*
* 'print_json_string()' - Print a string in JSON format.
*/
* Which encryption libraries do we have?
*/
-#define HAVE_TLS 1
#define HAVE_OPENSSL 1
/* #undef HAVE_GNUTLS */
/* Begin PBXFileReference section */
2706965A1CADF3E200FFE5FB /* libcups_ios.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups_ios.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 270B267D17F5C06700C8A3A9 /* tls-darwin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-darwin.c"; path = "../cups/tls-darwin.c"; sourceTree = "<group>"; };
270B267E17F5C06700C8A3A9 /* tls-gnutls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-gnutls.c"; path = "../cups/tls-gnutls.c"; sourceTree = "<group>"; };
270B268117F5C5D600C8A3A9 /* tls-sspi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-sspi.c"; path = "../cups/tls-sspi.c"; sourceTree = "<group>"; };
270CCDA7135E3C9E00007BE2 /* testmime */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testmime; sourceTree = BUILT_PRODUCTS_DIR; };
27D3037D134148CB00F022B1 /* libcups2.def */ = {isa = PBXFileReference; lastKnownFileType = text; name = libcups2.def; path = ../cups/libcups2.def; sourceTree = "<group>"; };
27F89DA21B3AC43B00E5A4B7 /* testraster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testraster.c; path = ../cups/testraster.c; sourceTree = "<group>"; };
27F9A76D28CBFC03002CCEE0 /* tls-openssl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-openssl.c"; path = "../cups/tls-openssl.c"; sourceTree = "<group>"; };
- 27F9A76E28CBFC03002CCEE0 /* tls-darwin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "tls-darwin.h"; path = "../cups/tls-darwin.h"; sourceTree = "<group>"; };
720DD6C21358FD5F0064AA82 /* snmp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = snmp; sourceTree = BUILT_PRODUCTS_DIR; };
720DD6D21358FDDE0064AA82 /* snmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snmp.c; path = ../backend/snmp.c; sourceTree = "<group>"; };
720E854120164E7A00C6C411 /* ipp-file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-file.c"; path = "../cups/ipp-file.c"; sourceTree = "<group>"; };
72220F02133305BB00FCA411 /* string.c */,
72220F03133305BB00FCA411 /* tempfile.c */,
72220F05133305BB00FCA411 /* thread.c */,
- 27F9A76E28CBFC03002CCEE0 /* tls-darwin.h */,
- 270B267D17F5C06700C8A3A9 /* tls-darwin.c */,
270B267E17F5C06700C8A3A9 /* tls-gnutls.c */,
27F9A76D28CBFC03002CCEE0 /* tls-openssl.c */,
270B268117F5C5D600C8A3A9 /* tls-sspi.c */,
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = c99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = c99;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
* Which encryption libraries do we have?
*/
-#define HAVE_TLS 1
#define HAVE_OPENSSL 1
/* #undef HAVE_GNUTLS */