Log a message right before exiting gracefully
[privoxy.git] / ssl.c
diff --git a/ssl.c b/ssl.c
index bc4c5af..58bd222 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.
  *
- * 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
@@ -88,12 +88,13 @@ static mbedtls_ctr_drbg_context ctr_drbg;
 static mbedtls_entropy_context  entropy;
 static int rng_seeded;
 
-static int generate_webpage_certificate(struct client_state *csp);
+static int generate_host_certificate(struct client_state *csp);
 static int host_to_hash(struct client_state *csp);
 static int ssl_verify_callback(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
 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);
 
 /*********************************************************************
  *
@@ -170,7 +171,8 @@ extern int ssl_send_data(struct ssl_attr *ssl_attr, const unsigned char *buf, si
          send_len = (int)max_fragment_size;
       }
 
-      log_error(LOG_LEVEL_WRITING, "TLS: %N", send_len, buf+pos);
+      log_error(LOG_LEVEL_WRITING, "TLS on socket %d: %N",
+         ssl_attr->mbedtls_attr.socket_fd.fd, send_len, buf+pos);
 
       /*
        * Sending one part of the buffer
@@ -186,7 +188,8 @@ extern int ssl_send_data(struct ssl_attr *ssl_attr, const unsigned char *buf, si
 
             mbedtls_strerror(ret, err_buf, sizeof(err_buf));
             log_error(LOG_LEVEL_ERROR,
-               "Sending data over TLS/SSL failed: %s", err_buf);
+               "Sending data on socket %d over TLS/SSL failed: %s",
+               ssl_attr->mbedtls_attr.socket_fd.fd, err_buf);
             return -1;
          }
       }
@@ -235,18 +238,21 @@ extern int ssl_recv_data(struct ssl_attr *ssl_attr, unsigned char *buf, size_t m
 
       if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
       {
-         log_error(LOG_LEVEL_CONNECT,
-            "The peer notified us that the connection is going to be closed");
+         log_error(LOG_LEVEL_CONNECT, "The peer notified us that "
+            "the connection on socket %d is going to be closed",
+            ssl_attr->mbedtls_attr.socket_fd.fd);
          return 0;
       }
       mbedtls_strerror(ret, err_buf, sizeof(err_buf));
       log_error(LOG_LEVEL_ERROR,
-         "Receiving data over TLS/SSL failed: %s", err_buf);
+         "Receiving data on socket %d over TLS/SSL failed: %s",
+         ssl_attr->mbedtls_attr.socket_fd.fd, err_buf);
 
       return -1;
    }
 
-   log_error(LOG_LEVEL_RECEIVED, "TLS: %N", ret, buf);
+   log_error(LOG_LEVEL_RECEIVED, "TLS from socket %d: %N",
+      ssl_attr->mbedtls_attr.socket_fd.fd, ret, buf);
 
    return ret;
 }
@@ -319,11 +325,11 @@ extern int create_client_ssl_connection(struct client_state *csp)
     */
    privoxy_mutex_lock(&certificate_mutex);
 
-   ret = generate_webpage_certificate(csp);
+   ret = generate_host_certificate(csp);
    if (ret < 0)
    {
       log_error(LOG_LEVEL_ERROR,
-         "Generate_webpage_certificate failed: %d", ret);
+         "generate_host_certificate failed: %d", ret);
       privoxy_mutex_unlock(&certificate_mutex);
       ret = -1;
       goto exit;
@@ -416,6 +422,22 @@ extern int create_client_ssl_connection(struct client_state *csp)
       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)
@@ -539,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));
+   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));
@@ -648,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);
 
+   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)
@@ -798,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));
+   freez(ssl_attr->mbedtls_attr.ciphersuites_list);
    mbedtls_ssl_config_free(&(ssl_attr->mbedtls_attr.conf));
 }
 
@@ -1217,7 +1257,7 @@ exit:
 
 /*********************************************************************
  *
- * Function    :  generate_webpage_certificate
+ * Function    :  generate_host_certificate
  *
  * Description :  Creates certificate file in presetted directory.
  *                If certificate already exists, no other certificate
@@ -1233,7 +1273,7 @@ exit:
  *                >0 => Length of created certificate.
  *
  *********************************************************************/
-static int generate_webpage_certificate(struct client_state *csp)
+static int generate_host_certificate(struct client_state *csp)
 {
    mbedtls_x509_crt issuer_cert;
    mbedtls_pk_context loaded_issuer_key, loaded_subject_key;
@@ -1270,6 +1310,15 @@ static int generate_webpage_certificate(struct client_state *csp)
       return -1;
    }
 
+   if (enforce_sane_certificate_state(cert_opt.output_file,
+         cert_opt.subject_key))
+   {
+      freez(cert_opt.output_file);
+      freez(cert_opt.subject_key);
+
+      return -1;
+   }
+
    if (file_exists(cert_opt.output_file) == 1)
    {
       /* The file exists, but is it valid? */
@@ -1691,6 +1740,7 @@ static int ssl_verify_callback(void *csp_void, mbedtls_x509_crt *crt,
    {
       char buf[CERT_INFO_BUF_SIZE];
       char *encoded_text;
+#define CERT_INFO_PREFIX                 ""
 
       mbedtls_x509_crt_info(buf, sizeof(buf), CERT_INFO_PREFIX, crt);
       encoded_text = html_encode(buf);
@@ -1832,7 +1882,16 @@ extern int ssl_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
  *********************************************************************/
 extern void ssl_crt_verify_info(char *buf, size_t size, struct client_state *csp)
 {
-   mbedtls_x509_crt_verify_info(buf, size, " ", csp->server_cert_verification_result);
+   char *last_byte;
+
+   mbedtls_x509_crt_verify_info(buf, size, "",
+      csp->server_cert_verification_result);
+   last_byte = buf + strlen(buf)-1;
+   if (*last_byte == '\n')
+   {
+      /* Overwrite trailing new line character */
+      *last_byte = '\0';
+   }
 }
 
 
@@ -1855,3 +1914,73 @@ extern void ssl_release(void)
       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;
+
+}