diff --git a/src/core/config.xml b/src/core/config.xml
index 1561478..db5cdc0 100644
--- a/src/core/config.xml
+++ b/src/core/config.xml
@@ -428,7 +428,6 @@
0.3.3
-
Certificate file
0.3.0
+
+ List of TLS ciphers to use
+
+ 0.5.0
+
+ High security with emphasis on forward secrecy:
+ tls_ciphersuite = "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"
+
+
+ Allow ChaCha20/Poly1305 which are secure, yet generally faster:
+ tls_ciphersuite = "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
+
+ ]]>
+
+
+
+ Specify minimum TLS version supported.
+
+ This allows you to specify the minimum TLS version the hub requires from connecting clients in order to
+ connect to the hub.
+
+
+ TLS version 1.2 is recommended and enabled by default.
+ TLS version 1.1 is acceptable without any known flaws, and allows for older clients to connect.
+ TLS version 1.0 should be avoided, even though it is the most compatible with older ADC clients.
+
+ ]]>
+ 0.5.0
+
+
File containing access control lists
tls_require_redirect_addr = hub_strdup("");
config->tls_certificate = hub_strdup("");
config->tls_private_key = hub_strdup("");
+ config->tls_ciphersuite = hub_strdup("ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS");
+ config->tls_version = hub_strdup("1.2");
config->file_acl = hub_strdup("");
config->file_plugins = hub_strdup("");
config->msg_hub_full = hub_strdup("Hub is full");
@@ -552,6 +554,26 @@ static int apply_config(struct hub_config* config, char* key, char* data, int li
return 0;
}
+ if (!strcmp(key, "tls_ciphersuite"))
+ {
+ if (!apply_string(key, data, &config->tls_ciphersuite, (char*) ""))
+ {
+ LOG_ERROR("Configuration parse error on line %d", line_count);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (!strcmp(key, "tls_version"))
+ {
+ if (!apply_string(key, data, &config->tls_version, (char*) ""))
+ {
+ LOG_ERROR("Configuration parse error on line %d", line_count);
+ return -1;
+ }
+ return 0;
+ }
+
if (!strcmp(key, "file_acl"))
{
if (!apply_string(key, data, &config->file_acl, (char*) ""))
@@ -955,6 +977,10 @@ void free_config(struct hub_config* config)
hub_free(config->tls_private_key);
+ hub_free(config->tls_ciphersuite);
+
+ hub_free(config->tls_version);
+
hub_free(config->file_acl);
hub_free(config->file_plugins);
@@ -1164,6 +1190,12 @@ void dump_config(struct hub_config* config, int ignore_defaults)
if (!ignore_defaults || strcmp(config->tls_private_key, "") != 0)
fprintf(stdout, "tls_private_key = \"%s\"\n", config->tls_private_key);
+ if (!ignore_defaults || strcmp(config->tls_ciphersuite, "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS") != 0)
+ fprintf(stdout, "tls_ciphersuite = \"%s\"\n", config->tls_ciphersuite);
+
+ if (!ignore_defaults || strcmp(config->tls_version, "1.2") != 0)
+ fprintf(stdout, "tls_version = \"%s\"\n", config->tls_version);
+
if (!ignore_defaults || strcmp(config->file_acl, "") != 0)
fprintf(stdout, "file_acl = \"%s\"\n", config->file_acl);
diff --git a/src/core/gen_config.h b/src/core/gen_config.h
index 359c144..cc8415b 100644
--- a/src/core/gen_config.h
+++ b/src/core/gen_config.h
@@ -3,7 +3,7 @@
* Copyright (C) 2007-2014, Jan Vidar Krey
*
* THIS FILE IS AUTOGENERATED - DO NOT MODIFY
- * Created 2014-05-14 11:38, by config.py
+ * Created 2014-07-29 12:22, by config.py
*/
struct hub_config
@@ -51,6 +51,8 @@ struct hub_config
char* tls_require_redirect_addr; /*<<< A redirect address in case a client connects using "adc://" when "adcs://" is required. (default: "") */
char* tls_certificate; /*<<< Certificate file (default: "") */
char* tls_private_key; /*<<< Private key file (default: "") */
+ char* tls_ciphersuite; /*<<< List of TLS ciphers to use (default: "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS") */
+ char* tls_version; /*<<< Specify minimum TLS version supported. (default: "1.2") */
char* file_acl; /*<<< File containing access control lists (default: "") */
char* file_plugins; /*<<< Plugin configuration file (default: "") */
char* msg_hub_full; /*<<< "Hub is full" */
diff --git a/src/core/hub.c b/src/core/hub.c
index 443b380..b2912b5 100644
--- a/src/core/hub.c
+++ b/src/core/hub.c
@@ -731,7 +731,11 @@ static int load_ssl_certificates(struct hub_info* hub, struct hub_config* config
{
if (config->tls_enable)
{
- hub->ctx = net_ssl_context_create();
+ hub->ctx = net_ssl_context_create(config->tls_version, config->tls_ciphersuite);
+
+ if (!hub->ctx)
+ return 0;
+
if (ssl_load_certificate(hub->ctx, config->tls_certificate) &&
ssl_load_private_key(hub->ctx, config->tls_private_key) &&
ssl_check_private_key(hub->ctx))
diff --git a/src/network/openssl.c b/src/network/openssl.c
index 09efb48..b6e5d24 100644
--- a/src/network/openssl.c
+++ b/src/network/openssl.c
@@ -43,8 +43,7 @@ struct net_ssl_openssl
struct net_context_openssl
{
- SSL_METHOD* ssl_method;
- SSL_CTX* ssl_ctx;
+ SSL_CTX* ssl;
};
static struct net_ssl_openssl* get_handle(struct net_connection* con)
@@ -97,26 +96,61 @@ static void add_io_stats(struct net_ssl_openssl* handle)
}
}
+static const SSL_METHOD* get_ssl_method(const char* tls_version)
+{
+ if (!tls_version || !*tls_version)
+ {
+ LOG_ERROR("tls_version is not set.");
+ return 0;
+ }
+
+ if (!strcmp(tls_version, "1.0"))
+ return TLSv1_method();
+ if (!strcmp(tls_version, "1.1"))
+ return TLSv1_1_method();
+ if (!strcmp(tls_version, "1.2"))
+ return TLSv1_2_method();
+
+ LOG_ERROR("Unable to recognize tls_version.");
+ return 0;
+}
+
/**
* Create a new SSL context.
*/
-struct ssl_context_handle* net_ssl_context_create()
+struct ssl_context_handle* net_ssl_context_create(const char* tls_version, const char* tls_ciphersuite)
{
-
struct net_context_openssl* ctx = (struct net_context_openssl*) hub_malloc_zero(sizeof(struct net_context_openssl));
- ctx->ssl_method = (SSL_METHOD*) SSLv23_method(); /* TLSv1_method() */
- ctx->ssl_ctx = SSL_CTX_new(ctx->ssl_method);
+ const SSL_METHOD* ssl_method = get_ssl_method(tls_version);
+
+ if (!ssl_method)
+ {
+ hub_free(ctx);
+ return 0;
+ }
+
+ ctx->ssl = SSL_CTX_new(ssl_method);
/* Disable SSLv2 */
- SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ctx->ssl, SSL_OP_NO_SSLv2);
+
+ // FIXME: Why did we need this again?
+ SSL_CTX_set_quiet_shutdown(ctx->ssl, 1);
#ifdef SSL_OP_NO_COMPRESSION
- /* Disable compression? */
+ /* Disable compression */
LOG_TRACE("Disabling SSL compression."); /* "CRIME" attack */
- SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
+ SSL_CTX_set_options(ctx->ssl, SSL_OP_NO_COMPRESSION);
#endif
- SSL_CTX_set_quiet_shutdown(ctx->ssl_ctx, 1);
+ /* Set preferred cipher suite */
+ if (SSL_CTX_set_cipher_list(ctx->ssl, tls_ciphersuite) != 1)
+ {
+ LOG_ERROR("Unable to set cipher suite.");
+ SSL_CTX_free(ctx->ssl);
+ hub_free(ctx);
+ return 0;
+ }
return (struct ssl_context_handle*) ctx;
}
@@ -124,16 +158,16 @@ struct ssl_context_handle* net_ssl_context_create()
extern void net_ssl_context_destroy(struct ssl_context_handle* ctx_)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
- SSL_CTX_free(ctx->ssl_ctx);
+ SSL_CTX_free(ctx->ssl);
hub_free(ctx);
}
int ssl_load_certificate(struct ssl_context_handle* ctx_, const char* pem_file)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
- if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem_file) < 0)
+ if (SSL_CTX_use_certificate_chain_file(ctx->ssl, pem_file) < 0)
{
- LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL));
+ LOG_ERROR("SSL_CTX_use_certificate_chain_file: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
}
@@ -143,7 +177,7 @@ int ssl_load_certificate(struct ssl_context_handle* ctx_, const char* pem_file)
int ssl_load_private_key(struct ssl_context_handle* ctx_, const char* pem_file)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
- if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem_file, SSL_FILETYPE_PEM) < 0)
+ if (SSL_CTX_use_PrivateKey_file(ctx->ssl, pem_file, SSL_FILETYPE_PEM) < 0)
{
LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
@@ -154,7 +188,7 @@ int ssl_load_private_key(struct ssl_context_handle* ctx_, const char* pem_file)
int ssl_check_private_key(struct ssl_context_handle* ctx_)
{
struct net_context_openssl* ctx = (struct net_context_openssl*) ctx_;
- if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1)
+ if (SSL_CTX_check_private_key(ctx->ssl) != 1)
{
LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL));
return 0;
@@ -238,7 +272,7 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode
if (ssl_mode == net_con_ssl_mode_server)
{
- handle->ssl = SSL_new(ctx->ssl_ctx);
+ handle->ssl = SSL_new(ctx->ssl);
if (!handle->ssl)
{
LOG_ERROR("Unable to create new SSL stream\n");
diff --git a/src/network/tls.h b/src/network/tls.h
index b1822d0..7ddb8b7 100644
--- a/src/network/tls.h
+++ b/src/network/tls.h
@@ -56,8 +56,9 @@ extern int net_ssl_library_shutdown();
/**
* Create a new SSL context.
+ * Specify a TLS version as a string: "1.2" for TLS 1.2.
*/
-extern struct ssl_context_handle* net_ssl_context_create();
+extern struct ssl_context_handle* net_ssl_context_create(const char* tls_version, const char* tls_ciphersuite);
extern void net_ssl_context_destroy(struct ssl_context_handle* ctx);
/**