Add a cipher-list directive to specify the ciphers used
authorFabian Keil <fk@fabiankeil.de>
Tue, 6 Oct 2020 11:28:14 +0000 (13:28 +0200)
committerFabian Keil <fk@fabiankeil.de>
Fri, 9 Oct 2020 07:40:39 +0000 (09:40 +0200)
... in the TLS handshake.

The get_ciphersuites_from_string() function in the
MbedTLS code is based on code contributed by Václav Švec.

loadcfg.c
openssl.c
project.h
ssl.c

index ad15c64..d9014bc 100644 (file)
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -138,6 +138,7 @@ static struct file_list *current_configfile = NULL;
 #define hash_ca_key_file                 1184187891U /* "ca-key-file" */
 #define hash_ca_password                 1184543320U /* "ca-password" */
 #define hash_certificate_directory       1367994217U /* "certificate-directory" */
 #define hash_ca_key_file                 1184187891U /* "ca-key-file" */
 #define hash_ca_password                 1184543320U /* "ca-password" */
 #define hash_certificate_directory       1367994217U /* "certificate-directory" */
+#define hash_cipher_list                 1225729316U /* "cipher-list" */
 #define hash_client_header_order         2701453514U /* "client-header-order" */
 #define hash_client_specific_tag         3353703383U /* "client-specific-tag" */
 #define hash_client_tag_lifetime          647957580U /* "client-tag-lifetime" */
 #define hash_client_header_order         2701453514U /* "client-header-order" */
 #define hash_client_specific_tag         3353703383U /* "client-specific-tag" */
 #define hash_client_tag_lifetime          647957580U /* "client-tag-lifetime" */
@@ -281,6 +282,7 @@ static void unload_configfile (void * data)
    freez(config->ca_cert_file);
    freez(config->ca_key_file);
    freez(config->certificate_directory);
    freez(config->ca_cert_file);
    freez(config->ca_key_file);
    freez(config->certificate_directory);
+   freez(config->cipher_list);
    freez(config->trusted_cas_file);
 #endif
 
    freez(config->trusted_cas_file);
 #endif
 
@@ -1796,6 +1798,15 @@ struct configuration_spec * load_config(void)
 
             break;
 
 
             break;
 
+/* *************************************************************************
+ * cipher-list list-of-ciphers
+ * *************************************************************************/
+         case hash_cipher_list:
+            freez(config->cipher_list);
+            config->cipher_list = strdup_or_die(arg);
+
+            break;
+
 /* *************************************************************************
  * trusted CAs file name trusted-cas-file
  * *************************************************************************/
 /* *************************************************************************
  * trusted CAs file name trusted-cas-file
  * *************************************************************************/
index 37b8069..2c065cc 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -837,6 +837,18 @@ extern int create_client_ssl_connection(struct client_state *csp)
       goto exit;
    }
 
       goto exit;
    }
 
+   if (csp->config->cipher_list != NULL)
+   {
+      if (!SSL_set_cipher_list(ssl, csp->config->cipher_list))
+      {
+         log_ssl_errors(LOG_LEVEL_ERROR,
+            "Setting the cipher list '%s' for the client connection failed",
+            csp->config->cipher_list);
+         ret = -1;
+         goto exit;
+      }
+   }
+
    /*
     *  Handshake with client
     */
    /*
     *  Handshake with client
     */
@@ -1061,6 +1073,18 @@ extern int create_server_ssl_connection(struct client_state *csp)
       goto exit;
    }
 
       goto exit;
    }
 
+   if (csp->config->cipher_list != NULL)
+   {
+      if (!SSL_set_cipher_list(ssl, csp->config->cipher_list))
+      {
+         log_ssl_errors(LOG_LEVEL_ERROR,
+            "Setting the cipher list '%s' for the server connection failed",
+            csp->config->cipher_list);
+         ret = -1;
+         goto exit;
+      }
+   }
+
    /*
     * Set the hostname to check against the received server certificate
     */
    /*
     * Set the hostname to check against the received server certificate
     */
index 9445383..ec3c155 100644 (file)
--- a/project.h
+++ b/project.h
@@ -311,6 +311,7 @@ typedef struct {
    mbedtls_x509_crt         server_cert;
    mbedtls_x509_crt         ca_cert;
    mbedtls_pk_context       prim_key;
    mbedtls_x509_crt         server_cert;
    mbedtls_x509_crt         ca_cert;
    mbedtls_pk_context       prim_key;
+   int                     *ciphersuites_list;
 
    #if defined(MBEDTLS_SSL_CACHE_C)
       mbedtls_ssl_cache_context cache;
 
    #if defined(MBEDTLS_SSL_CACHE_C)
       mbedtls_ssl_cache_context cache;
@@ -1588,6 +1589,9 @@ struct configuration_spec
    /** Directory for saving certificates and keys for each webpage **/
    char *certificate_directory;
 
    /** Directory for saving certificates and keys for each webpage **/
    char *certificate_directory;
 
+   /** Cipher list to use **/
+   char *cipher_list;
+
    /** Filename of trusted CAs certificates **/
    char * trusted_cas_file;
 #endif
    /** Filename of trusted CAs certificates **/
    char * trusted_cas_file;
 #endif
diff --git a/ssl.c b/ssl.c
index 7334fb9..46b8fd4 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -5,7 +5,7 @@
  * Purpose     :  File with TLS/SSL extension. Contains methods for
  *                creating, using and closing TLS/SSL connections.
  *
  * Purpose     :  File with TLS/SSL extension. Contains methods for
  *                creating, using and closing TLS/SSL connections.
  *
- * Copyright   :  Written by and Copyright (c) 2017 Vaclav Svec. FIT CVUT.
+ * Copyright   :  Written by and Copyright (c) 2017-2020 Vaclav Svec. FIT CVUT.
  *                Copyright (C) 2018-2020 by Fabian Keil <fk@fabiankeil.de>
  *
  *                This program is free software; you can redistribute it
  *                Copyright (C) 2018-2020 by Fabian Keil <fk@fabiankeil.de>
  *
  *                This program is free software; you can redistribute it
@@ -94,6 +94,7 @@ static int ssl_verify_callback(void *data, mbedtls_x509_crt *crt, int depth, uin
 static void free_client_ssl_structures(struct client_state *csp);
 static void free_server_ssl_structures(struct client_state *csp);
 static int seed_rng(struct client_state *csp);
 static void free_client_ssl_structures(struct client_state *csp);
 static void free_server_ssl_structures(struct client_state *csp);
 static int seed_rng(struct client_state *csp);
+static int *get_ciphersuites_from_string(const char *ciphersuites_string);
 
 /*********************************************************************
  *
 
 /*********************************************************************
  *
@@ -421,6 +422,22 @@ extern int create_client_ssl_connection(struct client_state *csp)
       goto exit;
    }
 
       goto exit;
    }
 
+   if (csp->config->cipher_list != NULL)
+   {
+      ssl_attr->mbedtls_attr.ciphersuites_list =
+         get_ciphersuites_from_string(csp->config->cipher_list);
+      if (ssl_attr->mbedtls_attr.ciphersuites_list == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR,
+            "Setting the cipher list '%s' for the client connection failed",
+            csp->config->cipher_list);
+         ret = -1;
+         goto exit;
+      }
+      mbedtls_ssl_conf_ciphersuites(&(ssl_attr->mbedtls_attr.conf),
+         ssl_attr->mbedtls_attr.ciphersuites_list);
+   }
+
    ret = mbedtls_ssl_setup(&(ssl_attr->mbedtls_attr.ssl),
       &(ssl_attr->mbedtls_attr.conf));
    if (ret != 0)
    ret = mbedtls_ssl_setup(&(ssl_attr->mbedtls_attr.ssl),
       &(ssl_attr->mbedtls_attr.conf));
    if (ret != 0)
@@ -544,6 +561,7 @@ static void free_client_ssl_structures(struct client_state *csp)
    mbedtls_x509_crt_free(&(ssl_attr->mbedtls_attr.server_cert));
    mbedtls_pk_free(&(ssl_attr->mbedtls_attr.prim_key));
    mbedtls_ssl_free(&(ssl_attr->mbedtls_attr.ssl));
    mbedtls_x509_crt_free(&(ssl_attr->mbedtls_attr.server_cert));
    mbedtls_pk_free(&(ssl_attr->mbedtls_attr.prim_key));
    mbedtls_ssl_free(&(ssl_attr->mbedtls_attr.ssl));
+   freez(ssl_attr->mbedtls_attr.ciphersuites_list);
    mbedtls_ssl_config_free(&(ssl_attr->mbedtls_attr.conf));
 #if defined(MBEDTLS_SSL_CACHE_C)
    mbedtls_ssl_cache_free(&(ssl_attr->mbedtls_attr.cache));
    mbedtls_ssl_config_free(&(ssl_attr->mbedtls_attr.conf));
 #if defined(MBEDTLS_SSL_CACHE_C)
    mbedtls_ssl_cache_free(&(ssl_attr->mbedtls_attr.cache));
@@ -653,6 +671,22 @@ extern int create_server_ssl_connection(struct client_state *csp)
    mbedtls_ssl_conf_rng(&(ssl_attr->mbedtls_attr.conf),
       mbedtls_ctr_drbg_random, &ctr_drbg);
 
    mbedtls_ssl_conf_rng(&(ssl_attr->mbedtls_attr.conf),
       mbedtls_ctr_drbg_random, &ctr_drbg);
 
+   if (csp->config->cipher_list != NULL)
+   {
+      ssl_attr->mbedtls_attr.ciphersuites_list =
+         get_ciphersuites_from_string(csp->config->cipher_list);
+      if (ssl_attr->mbedtls_attr.ciphersuites_list == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR,
+            "Setting the cipher list '%s' for the server connection failed",
+            csp->config->cipher_list);
+         ret = -1;
+         goto exit;
+      }
+      mbedtls_ssl_conf_ciphersuites(&(ssl_attr->mbedtls_attr.conf),
+         ssl_attr->mbedtls_attr.ciphersuites_list);
+   }
+
    ret = mbedtls_ssl_setup(&(ssl_attr->mbedtls_attr.ssl),
       &(ssl_attr->mbedtls_attr.conf));
    if (ret != 0)
    ret = mbedtls_ssl_setup(&(ssl_attr->mbedtls_attr.ssl),
       &(ssl_attr->mbedtls_attr.conf));
    if (ret != 0)
@@ -803,6 +837,7 @@ static void free_server_ssl_structures(struct client_state *csp)
 
    mbedtls_x509_crt_free(&(ssl_attr->mbedtls_attr.ca_cert));
    mbedtls_ssl_free(&(ssl_attr->mbedtls_attr.ssl));
 
    mbedtls_x509_crt_free(&(ssl_attr->mbedtls_attr.ca_cert));
    mbedtls_ssl_free(&(ssl_attr->mbedtls_attr.ssl));
+   freez(ssl_attr->mbedtls_attr.ciphersuites_list);
    mbedtls_ssl_config_free(&(ssl_attr->mbedtls_attr.conf));
 }
 
    mbedtls_ssl_config_free(&(ssl_attr->mbedtls_attr.conf));
 }
 
@@ -1860,3 +1895,73 @@ extern void ssl_release(void)
       mbedtls_entropy_free(&entropy);
    }
 }
       mbedtls_entropy_free(&entropy);
    }
 }
+
+
+/*********************************************************************
+ *
+ * Function    :  get_ciphersuites_from_string
+ *
+ * Description :  Converts a string of ciphersuite names to
+ *                an array of ciphersuite ids.
+ *
+ * Parameters  :
+ *          1  :  ciphersuites_string = String containing allowed
+ *                ciphersuites.
+ *
+ * Returns     :  Array of ciphersuite ids
+ *
+ *********************************************************************/
+static int *get_ciphersuites_from_string(const char *parameter_string)
+{
+   char *ciphersuites_index;
+   char *item_end;
+   char *ciphersuites_string;
+   int *ciphersuite_ids;
+   size_t count = 2;
+   int index = 0;
+   const char separator = ':';
+   size_t parameter_len = strlen(parameter_string);
+
+   ciphersuites_string = zalloc_or_die(parameter_len + 1);
+   strncpy(ciphersuites_string, parameter_string, parameter_len);
+   ciphersuites_index = ciphersuites_string;
+
+   while (*ciphersuites_index)
+   {
+      if (*ciphersuites_index++ == separator)
+      {
+         ++count;
+      }
+   }
+
+   ciphersuite_ids = zalloc_or_die(count * sizeof(int));
+
+   ciphersuites_index = ciphersuites_string;
+   do
+   {
+      item_end = strchr(ciphersuites_index, separator);
+      if (item_end != NULL)
+      {
+         *item_end = '\0';
+      }
+
+      ciphersuite_ids[index] =
+         mbedtls_ssl_get_ciphersuite_id(ciphersuites_index);
+      if (ciphersuite_ids[index] == 0)
+      {
+         log_error(LOG_LEVEL_ERROR,
+            "Failed to get ciphersuite id for %s", ciphersuites_index);
+         freez(ciphersuite_ids);
+         freez(ciphersuites_string);
+         return NULL;
+      }
+      ciphersuites_index = item_end + 1;
+      index++;
+   } while (item_end != NULL);
+
+   ciphersuite_ids[index] = 0;
+   freez(ciphersuites_string);
+
+   return ciphersuite_ids;
+
+}