/*
- * "$Id$"
- *
* TLS support code for CUPS on OS X.
*
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2016 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* This file is subject to the Apple OS-Developed Software exception.
*/
-/**** This file is included from http.c ****/
+/**** This file is included from tls.c ****/
/*
* Include necessary headers...
static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
/* Mutex for keychain/certs */
#endif /* HAVE_SECKEYCHAINOPEN */
+static int tls_options = -1;/* Options for TLS connections */
/*
#ifdef HAVE_SECKEYCHAINOPEN
static CFArrayRef http_cdsa_copy_server(const char *common_name);
#endif /* HAVE_SECKEYCHAINOPEN */
+static SecCertificateRef http_cdsa_create_credential(http_credential_t *credential);
static const char *http_cdsa_default_path(char *buffer, size_t bufsize);
static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength);
static int http_cdsa_set_credentials(http_t *http);
/*
* 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - 1 on success, 0 on failure */
if (!keyParams)
goto cleanup;
- CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA);
+ CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeECDSA);
CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048"));
CFDictionaryAddValue(keyParams, kSecAttrLabel, CFSTR("CUPS Self-Signed Certificate"));
status, /* Status of command */
i; /* Looping var */
char command[1024], /* Command */
- *argv[4], /* Command-line arguments */
+ *argv[5], /* Command-line arguments */
*envp[1000], /* Environment variables */
days[32], /* CERTTOOL_EXPIRATION_DAYS env var */
keychain[1024], /* Keychain argument */
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, alt_names, (int)expiration_date));
+ 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;
"CUPS Self-Signed Certificate\n"
/* Enter key and certificate label */
"r\n" /* Generate RSA key pair */
- "2048\n" /* Key size in bits */
+ "2048\n" /* 2048 bit encryption key */
"y\n" /* OK (y = yes) */
"b\n" /* Usage (b=signing/encryption) */
- "s\n" /* Sign with SHA1 */
+ "2\n" /* Sign with SHA256 */
"y\n" /* OK (y = yes) */
"%s\n" /* Common name */
"\n" /* Country (default) */
* Note: The server credentials are used by all threads in the running process.
* This function is threadsafe.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS X 10.10@
*/
int /* O - 1 on success, 0 on failure */
int i; /* Looping var */
- DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
+ DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", (void *)http, (void *)credentials));
if (credentials)
*credentials = NULL;
}
-/*
- * 'http_cdsa_create_credential()' - Create a single credential in the internal format.
- */
-
-static SecCertificateRef /* O - Certificate */
-http_cdsa_create_credential(
- http_credential_t *credential) /* I - Credential */
-{
- if (!credential)
- return (NULL);
-
- return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen));
-}
-
-
/*
* '_httpCreateCredentials()' - Create credentials in the internal format.
*/
/*
* 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS X 10.10@
*/
int /* O - 1 if valid, 0 otherwise */
/*
* 'httpCredentialsGetTrust()' - Return the trust of credentials.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS X 10.10@
*/
http_trust_t /* O - Level of trust */
if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
return (HTTP_TRUST_UNKNOWN);
+ if (cg->any_root < 0)
+ _cupsSetDefaults();
+
/*
* Look this common name up in the default keychains...
*/
/*
* 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS X 10.10@
*/
time_t /* O - Expiration date of credentials */
/*
* 'httpCredentialsString()' - Return a string representing the credentials.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS X 10.10@
*/
size_t /* O - Total size of credentials string */
SecCertificateRef secCert; /* Certificate reference */
- DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
+ DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", (void *)credentials, (void *)buffer, CUPS_LLCAST bufsize));
if (!buffer)
return (0);
/*
* 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - 0 on success, -1 on error */
CFArrayRef list = NULL; /* Keychain list */
- DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
+ DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name));
if (!credentials)
return (-1);
/*
* 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
*
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
*/
int /* O - -1 on error, 0 on success */
CFArrayRef list = NULL; /* Keychain list */
- DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name));
+ DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name));
if (!credentials)
goto cleanup;
}
+/*
+ * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
+ */
+
+void
+_httpTLSSetOptions(int options) /* I - Options */
+{
+ tls_options = options;
+}
+
+
/*
* '_httpTLSStart()' - Set up SSL/TLS support on a connection.
*/
http_credential_t *credential; /* Credential data */
- DEBUG_printf(("7_httpTLSStart(http=%p)", http));
+ DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http));
+
+ if (tls_options < 0)
+ {
+ DEBUG_puts("4_httpTLSStart: Setting defaults.");
+ _cupsSetDefaults();
+ DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
+ }
#ifdef HAVE_SECKEYCHAINOPEN
if (http->mode == _HTTP_MODE_SERVER && !tls_keychain)
{
error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth,
true);
- DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d",
- (int)error));
+ DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d", (int)error));
}
+ if (!error)
+ {
+ SSLProtocol minProtocol;
+
+ if (tls_options & _HTTP_TLS_DENY_TLS10)
+ minProtocol = kTLSProtocol11;
+ else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+ minProtocol = kSSLProtocol3;
+ else
+ minProtocol = kTLSProtocol1;
+
+ error = SSLSetProtocolVersionMin(http->tls, minProtocol);
+ DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error));
+ }
+
+# if HAVE_SSLSETENABLEDCIPHERS
+ 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_DSS_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_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 :
+ case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
+ case TLS_DHE_PSK_WITH_AES_256_CBC_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;
+
+ /* 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);
+ }
+ }
+#endif /* HAVE_SSLSETENABLEDCIPHERS */
+
if (!error && http->mode == _HTTP_MODE_CLIENT)
{
/*
DEBUG_printf(("4_httpTLSStart: SSLSetCertificate, error=%d", (int)error));
}
- DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", http->tls_credentials));
+ DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", (void *)http->tls_credentials));
/*
* Let the server know which hostname/domain we are trying to connect to
size_t processed; /* Number of bytes processed */
- DEBUG_printf(("2_httpTLSWrite(http=%p, buf=%p, len=%d)", http, buf, len));
+ DEBUG_printf(("2_httpTLSWrite(http=%p, buf=%p, len=%d)", (void *)http, (void *)buf, len));
error = SSLWrite(http->tls, buf, (size_t)len, &processed);
#endif /* HAVE_SECKEYCHAINOPEN */
+/*
+ * 'http_cdsa_create_credential()' - Create a single credential in the internal format.
+ */
+
+static SecCertificateRef /* O - Certificate */
+http_cdsa_create_credential(
+ http_credential_t *credential) /* I - Credential */
+{
+ if (!credential)
+ return (NULL);
+
+ return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen));
+}
+
+
/*
* 'http_cdsa_default_path()' - Get the default keychain path.
*/
/* TLS credentials */
- DEBUG_printf(("7http_tls_set_credentials(%p)", http));
+ DEBUG_printf(("7http_tls_set_credentials(%p)", (void *)http));
/*
* Prefer connection specific credentials...
return (result);
}
-
-
-/*
- * End of "$Id$".
- */