Merge branch 'master' of ssh://git.privoxy.org:23/git/privoxy
authorLee <ler762@users.sourceforge.net>
Sun, 10 Nov 2019 03:38:07 +0000 (22:38 -0500)
committerLee <ler762@users.sourceforge.net>
Sun, 10 Nov 2019 03:38:07 +0000 (22:38 -0500)
32 files changed:
AUTHORS
GNUmakefile.in
actionlist.h
cgi.c
cgisimple.c
config
configure.in
doc/source/copyright.sgml
doc/source/p-authors.sgml
doc/source/p-config.sgml
doc/source/user-manual.sgml
doc/source/webserver/index.sgml
doc/webserver/faq/copyright.html
doc/webserver/index.html
doc/webserver/privoxy-index.html
doc/webserver/sponsors/index.html
doc/webserver/user-manual/actions-file.html
doc/webserver/user-manual/appendix.html
doc/webserver/user-manual/config.html
doc/webserver/user-manual/copyright.html
doc/webserver/user-manual/index.html
jcc.c
jcc.h
loadcfg.c
parsers.c
parsers.h
project.h
ssl.c [new file with mode: 0644]
ssl.h [new file with mode: 0644]
templates/show-status
user.action
win32.c

diff --git a/AUTHORS b/AUTHORS
index a2ae68e..e9ff3ef 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -142,6 +142,7 @@ include (in alphabetical order):
  Simon South
  Dan Stahlke
  Oliver Stoeneberg
+ Václav Švec
  Rick Sykes
  Spinor S.
  Peter Thoenen
index 9c496f3..8083356 100644 (file)
@@ -231,6 +231,10 @@ W32_HDRS  = @WIN_ONLY@w32log.h w32taskbar.h win32.h w32res.h w32svrapi.h
 W32_LIB   = @WIN_ONLY@-lwsock32 -lcomctl32
 W32_INIS  = @WIN_ONLY@config.txt trust.txt
 
+SSL_SRC      = @FEATURE_HTTPS_FILTERING_ONLY@ssl.c
+SSL_OBJS     = @FEATURE_HTTPS_FILTERING_ONLY@$(SSL_SRC:.c=.o)
+SSL_HDRS     = @FEATURE_HTTPS_FILTERING_ONLY@$(SSL_SRC:.c=.h) project.h
+
 PCRS_SRC     = @STATIC_PCRS_ONLY@pcrs.c
 PCRS_OBJS    = @STATIC_PCRS_ONLY@$(PCRS_SRC:.c=.@OBJEXT@)
 PCRS_HDRS    = @STATIC_PCRS_ONLY@$(PCRS_SRC:.c=.h)
@@ -255,9 +259,9 @@ SOCKET_LIB   = @SOCKET_LIB@
 # PThreads library, if needed.
 PTHREAD_LIB  = @PTHREAD_ONLY@@PTHREAD_LIB@
 
-SRCS         = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC)  $(PCRS_SRC)  $(PCRE_SRC)  $(REGEX_SRC)
-OBJS         = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(PCRE_OBJS) $(REGEX_OBJS)
-HDRS         = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(PCRE_OBJS) $(REGEX_HDRS)
+SRCS         = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC)  $(PCRS_SRC)  $(PCRE_SRC)  $(REGEX_SRC) $(SSL_SRC)
+OBJS         = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(PCRE_OBJS) $(REGEX_OBJS) $(SSL_OBJS)
+HDRS         = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(PCRE_OBJS) $(REGEX_HDRS) $(SSL_HDRS)
 LIBS         = @LIBS@ $(W32_LIB) $(SOCKET_LIB) $(PTHREAD_LIB)
 
 
@@ -276,6 +280,7 @@ SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
 OTHER_CFLAGS =
 
 CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
+         -Imbedtls/include \
          @STATIC_PCRE_ONLY@ -Ipcre
 
 LDFLAGS = @LDFLAGS@ $(DEBUG_CFLAGS) $(SPECIAL_CFLAGS)
index 01d4d37..eca607b 100644 (file)
@@ -73,6 +73,9 @@ DEFINE_ACTION_STRING     ("delay-response",             ACTION_DELAY_RESPONSE,
 DEFINE_CGI_PARAM_NO_RADIO("delay-response",             ACTION_DELAY_RESPONSE,  ACTION_STRING_DELAY_RESPONSE, "100")
 DEFINE_CGI_PARAM_RADIO   ("deanimate-gifs",             ACTION_DEANIMATE,       ACTION_STRING_DEANIMATE,     "last",  1)
 DEFINE_ACTION_BOOL       ("downgrade-http-version",     ACTION_DOWNGRADE)
+#ifdef FEATURE_HTTPS_FILTERING
+DEFINE_ACTION_BOOL       ("enable-https-filtering",     ACTION_ENABLE_HTTPS_FILTER)
+#endif
 #ifdef FEATURE_EXTERNAL_FILTERS
 DEFINE_ACTION_MULTI      ("external-filter",            ACTION_MULTI_EXTERNAL_FILTER)
 #endif
@@ -107,6 +110,9 @@ DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,
 DEFINE_CGI_PARAM_CUSTOM  ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "http://www.privoxy.org/")
 DEFINE_ACTION_STRING     ("hide-user-agent",            ACTION_HIDE_USER_AGENT, ACTION_STRING_USER_AGENT)
 DEFINE_CGI_PARAM_NO_RADIO("hide-user-agent",            ACTION_HIDE_USER_AGENT, ACTION_STRING_USER_AGENT,    "Privoxy " VERSION)
+#ifdef FEATURE_HTTPS_FILTERING
+DEFINE_ACTION_BOOL       ("ignore-certificate-errors",  ACTION_IGNORE_CERTIFICATE_ERRORS)
+#endif
 DEFINE_ACTION_STRING     ("limit-connect",              ACTION_LIMIT_CONNECT,   ACTION_STRING_LIMIT_CONNECT)
 DEFINE_CGI_PARAM_NO_RADIO("limit-connect",              ACTION_LIMIT_CONNECT,   ACTION_STRING_LIMIT_CONNECT,  "443")
 DEFINE_ACTION_STRING     ("limit-cookie-lifetime",      ACTION_LIMIT_COOKIE_LIFETIME, ACTION_STRING_LIMIT_COOKIE_LIFETIME)
diff --git a/cgi.c b/cgi.c
index c67aed4..2e9e265 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -978,6 +978,9 @@ struct http_response *error_response(struct client_state *csp,
          case SOCKS_5T:
             socks_type = "socks5t-";
             break;
+         case FORWARD_WEBSERVER:
+            socks_type = "webserver-";
+            break;
          default:
             log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
       }
index 5711087..a7678ae 100644 (file)
@@ -1828,6 +1828,14 @@ static jb_err show_defines(struct map *exports)
          1,
 #else
          0,
+#endif
+      },
+      {
+         "FEATURE_HTTPS_FILTERING",
+#ifdef FEATURE_HTTPS_FILTERING
+         1,
+#else
+         0,
 #endif
       },
       {
diff --git a/config b/config
index 24dcb5a..0afa1e1 100644 (file)
--- a/config
+++ b/config
@@ -15,7 +15,8 @@
 #        4. ACCESS CONTROL AND SECURITY                             #
 #        5. FORWARDING                                              #
 #        6. MISCELLANEOUS                                           #
-#        7. WINDOWS GUI OPTIONS                                     #
+#        7. TLS                                                     #
+#        8. WINDOWS GUI OPTIONS                                     #
 #                                                                   #
 #####################################################################
 #
@@ -2435,29 +2436,217 @@ socket-timeout 300
 #            receive-buffer-size 32768
 #
 #
+#  7. TLS/SSL
+#  ===========
+#
+#  7.1. ca-directory
+#  ==================
+#
+#  Specifies:
+#
+#      Directory with the CA key, the CA certificate and the trusted
+#      CAs file.
+#
+#  Type of value:
+#
+#      Text
+#
+#  Default value:
+#
+#      Empty string
+#
+#  Effect if unset:
+#
+#      Default value is used.
+#
+#  Notes:
+#
+#      This directive specifies the directory where the CA key, the
+#      CA certificate and the trusted CAs file are located.
+#
+#  Examples:
+#
+#      ca-directory /usr/local/etc/privoxy/CA
+#
+#ca-directory /usr/local/etc/privoxy/CA
+#
+#  7.2. ca-cert-file
+#  ==================
+#
+#  Specifies:
+#
+#      The CA certificate file in ".crt" format.
+#
+#  Type of value:
+#
+#      Text
+#
+#  Default value:
+#
+#      cacert.crt
+#
+#  Effect if unset:
+#
+#      Default value is used.
+#
+#  Notes:
+#
+#      This directive specifies the name of the CA certificate file
+#      in ".crt" format.
+#
+#      It can be generated with: openssl req -new -x509 -extensions
+#      v3_ca -keyout cakey.pem -out cacert.crt -days 3650
+#
+#  Examples:
+#
+#      ca-cert-file root.crt
+#
+#ca-cert-file cacert.crt
+#
+#  7.3. ca-key-file
+#  =================
+#
+#  Specifies:
+#
+#      The CA key file in ".pem" format.
+#
+#  Type of value:
+#
+#      Text
+#
+#  Default value:
+#
+#      cacert.pem
+#
+#  Effect if unset:
+#
+#      Default value is used.
+#
+#  Notes:
+#
+#      This directive specifies the name of the CA key file in ".pem"
+#      format. See the ca-cert-file for a command to generate it.
+#
+#  Examples:
+#
+#      ca-key-file cakey.pem
+#
+#ca-key-file root.pem
+#
+#  7.4. ca-password
+#  =================
 #
-#  7. WINDOWS GUI OPTIONS
+#  Specifies:
+#
+#      The password for the CA keyfile.
+#
+#  Type of value:
+#
+#      Text
+#
+#  Default value:
+#
+#      Empty string
+#
+#  Effect if unset:
+#
+#      Default value is used.
+#
+#  Notes:
+#
+#      This directive specifies the password for the CA keyfile that
+#      is used when Privoxy generates certificates for intercepted
+#      requests.
+#
+#      Note that the password is shown on the CGI page so don't reuse
+#      an important one.
+#
+#  Examples:
+#
+#      ca-password blafasel
+#
+#ca-password swordfish
+#
+#  7.5. certificate-directory
+#  ===========================
+#
+#  Specifies:
+#
+#      Directory to safe generated keys and certificates.
+#
+#  Type of value:
+#
+#      Text
+#
+#  Default value:
+#
+#      ./certs
+#
+#  Effect if unset:
+#
+#      Default value is used.
+#
+#  Notes:
+#
+#      This directive specifies the directory where generated TLS/SSL
+#      keys and certificates are saved.
+#
+#  Examples:
+#
+#      certificate-directory /usr/local/var/privoxy/certs
+#
+#certificate-directory /usr/local/var/privoxy/certs
+#
+#  7.6. trusted-cas-file
+#  ======================
+#
+#  Specifies:
+#
+#      The trusted CAs file in ".pem" format.
+#
+#  Type of value:
+#
+#      File name relative to ca-directory
+#
+#  Default value:
+#
+#      trustedCAs.pem
+#
+#  Effect if unset:
+#
+#      Default value is used.
+#
+#  Notes:
+#
+#      This directive specifies the trusted CAs file that is used
+#      when validating certificates for intercepted TLS/SSL request.
+#
+#      An example file can be downloaded from https://curl.haxx.se/ca
+#      /cacert.pem.
+#
+#  Examples:
+#
+#      trusted-cas-file trusted_cas_file.pem
+#
+#trusted-cas-file trustedCAs.pem
+#
+#  8. WINDOWS GUI OPTIONS
 #  =======================
 #
 #  Privoxy has a number of options specific to the Windows GUI
 #  interface:
 #
 #
-#
 #  If "activity-animation" is set to 1, the Privoxy icon will animate
 #  when "Privoxy" is active. To turn off, set to 0.
 #
 #activity-animation   1
 #
-#
-#
 #  If "log-messages" is set to 1, Privoxy copies log messages to the
 #  console window. The log detail depends on the debug directive.
 #
 #log-messages   1
 #
-#
-#
 #  If "log-buffer-size" is set to 1, the size of the log buffer, i.e.
 #  the amount of memory used for the log messages displayed in the
 #  console window, will be limited to "log-max-lines" (see below).
index e1a8e9d..8739535 100644 (file)
@@ -1131,6 +1131,36 @@ dnl fi
 AC_SUBST(STATIC_PCRE_ONLY)
 AC_SUBST(STATIC_PCRS_ONLY)
 
+dnl =======================================================
+dnl check for mbedTLS which is required for https filtering
+dnl =======================================================
+FEATURE_HTTPS_FILTERING_ONLY=#
+OPT_MBEDTLS=no
+AC_ARG_WITH(mbedtls,dnl
+AC_HELP_STRING([--with-mbedtls],[enable mbedTLS detection for https filtering.])
+AC_HELP_STRING([--without-mbedtls], [disable mbedTLS detection]),
+  OPT_MBEDTLS=$withval)
+
+if test X"$OPT_MBEDTLS" != Xno; then
+
+  AC_CHECK_LIB(mbedtls, mbedtls_ssl_init,
+   [
+     AC_DEFINE(FEATURE_HTTPS_FILTERING, 1, [if mbedTLS is enabled])
+     AC_SUBST(FEATURE_HTTPS_FILTERING, [1])
+     FEATURE_HTTPS_FILTERING="yes"
+   ], [], -lmbedx509 -lmbedcrypto)
+
+  if test "x$FEATURE_HTTPS_FILTERING" = "xyes"; then
+    AC_MSG_NOTICE([Detected mbedTLS. Enabling https filtering.])
+
+    LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $LIBS"
+
+    FEATURE_HTTPS_FILTERING_ONLY=
+  fi
+fi
+AC_SUBST(FEATURE_HTTPS_FILTERING_ONLY)
+
+
 dnl =================================================================
 dnl Final cleanup and output
 dnl =================================================================
index 452f11a..88b3a5b 100644 (file)
@@ -3,7 +3,7 @@
 
  Purpose     :  Entity included in other project documents.
 
- Copyright (C) 2001-2018 Privoxy Developers https://www.privoxy.org/
+ Copyright (C) 2001-2019 Privoxy Developers https://www.privoxy.org/
  See LICENSE.
 
  ======================================================================
@@ -29,7 +29,7 @@
 -->
 
 <para>
- Copyright &my-copy; 2001-2018 by Privoxy Developers <email>privoxy-devel@lists.privoxy.org</email>
+ Copyright &my-copy; 2001-2019 by Privoxy Developers <email>privoxy-devel@lists.privoxy.org</email>
 </para>
 
 <para>
index ebcc701..42b4c0b 100644 (file)
@@ -176,6 +176,7 @@ Current Privoxy Team:
  Simon South
  Dan Stahlke
  Oliver Stoeneberg
+ V&aacute;clav &Scaron;vec
  Rick Sykes
  Spinor S.
  Peter Thoenen
index 0ca5006..9bd21eb 100644 (file)
@@ -107,7 +107,8 @@ Copyright (C) 2001-2019 Privoxy Developers https://www.privoxy.org/
       4. ACCESS CONTROL AND SECURITY                             #
       5. FORWARDING                                              #
       6. MISCELLANEOUS                                           #
-      7. WINDOWS GUI OPTIONS                                     #
+      7. TLS                                                     #
+      8. WINDOWS GUI OPTIONS                                     #
                                                                  #
 ##################################################################
 
@@ -3895,6 +3896,368 @@ forward-socks4, forward-socks4a, forward-socks5 and forward-socks5t</title>
 
 </sect2>
 
+
+<sect2 id="tls">
+<title>TLS/SSL</title>
+
+<!--   ~~~~~       New section      ~~~~~     -->
+
+<sect3 renderas="sect4" id="ca-directory"><title>ca-directory</title>
+<variablelist>
+ <varlistentry>
+  <term>Specifies:</term>
+  <listitem>
+   <para>
+    Directory with the CA key, the CA certificate and the trusted CAs file.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Type of value:</term>
+  <listitem>
+   <para>
+    Text
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Default value:</term>
+  <listitem>
+   <para><emphasis>Empty string</emphasis></para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Effect if unset:</term>
+  <listitem>
+   <para>
+    Default value is used.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This directive specifies the directory where the
+    CA key, the CA certificate and the trusted CAs file
+    are located.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Examples:</term>
+  <listitem>
+   <para>
+    ca-directory /usr/local/etc/privoxy/CA
+   </para>
+  </listitem>
+ </varlistentry>
+</variablelist>
+<![%config-file;[<literallayout>@@#ca-directory /usr/local/etc/privoxy/CA</literallayout>]]>
+</sect3>
+
+<!--  ~  End section  ~  -->
+
+<!--   ~~~~~       New section      ~~~~~     -->
+
+<sect3 renderas="sect4" id="ca-cert-file"><title>ca-cert-file</title>
+<variablelist>
+ <varlistentry>
+  <term>Specifies:</term>
+  <listitem>
+   <para>
+    The CA certificate file in ".crt" format.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Type of value:</term>
+  <listitem>
+   <para>
+    Text
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Default value:</term>
+  <listitem>
+   <para><emphasis>cacert.crt</emphasis></para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Effect if unset:</term>
+  <listitem>
+   <para>
+    Default value is used.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This directive specifies the name of the CA certificate file
+    in ".crt" format.
+   </para>
+   <para>
+    It can be generated with: openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.crt -days 3650
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Examples:</term>
+  <listitem>
+   <para>
+    ca-cert-file root.crt
+   </para>
+  </listitem>
+ </varlistentry>
+</variablelist>
+<![%config-file;[<literallayout>@@#ca-cert-file cacert.crt</literallayout>]]>
+</sect3>
+
+<!--  ~  End section  ~  -->
+
+<!--   ~~~~~       New section      ~~~~~     -->
+
+<sect3 renderas="sect4" id="ca-key-file"><title>ca-key-file</title>
+<variablelist>
+ <varlistentry>
+  <term>Specifies:</term>
+  <listitem>
+   <para>
+    The CA key file in ".pem" format.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Type of value:</term>
+  <listitem>
+   <para>
+    Text
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Default value:</term>
+  <listitem>
+   <para><emphasis>cacert.pem</emphasis></para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Effect if unset:</term>
+  <listitem>
+   <para>
+    Default value is used.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This directive specifies the name of the CA key file
+    in ".pem" format. See the <ulink url="#CA-CERT-FILE">ca-cert-file</ulink>
+    for a command to generate it.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Examples:</term>
+  <listitem>
+   <para>
+    ca-key-file cakey.pem
+   </para>
+  </listitem>
+ </varlistentry>
+</variablelist>
+<![%config-file;[<literallayout>@@#ca-key-file root.pem</literallayout>]]>
+</sect3>
+
+<!--  ~  End section  ~  -->
+
+<!--   ~~~~~       New section      ~~~~~     -->
+
+<sect3 renderas="sect4" id="ca-password"><title>ca-password</title>
+<variablelist>
+ <varlistentry>
+  <term>Specifies:</term>
+  <listitem>
+   <para>
+    The password for the CA keyfile.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Type of value:</term>
+  <listitem>
+   <para>
+    Text
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Default value:</term>
+  <listitem>
+   <para><emphasis>Empty string</emphasis></para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Effect if unset:</term>
+  <listitem>
+   <para>
+    Default value is used.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This directive specifies the password for the CA keyfile
+    that is used when Privoxy generates certificates for intercepted
+    requests.
+   </para>
+   <para>
+     Note that the password is shown on the CGI page so don't
+     reuse an important one.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Examples:</term>
+  <listitem>
+   <para>
+    ca-password blafasel
+   </para>
+  </listitem>
+ </varlistentry>
+</variablelist>
+<![%config-file;[<literallayout>@@#ca-password swordfish</literallayout>]]>
+</sect3>
+
+<!--  ~  End section  ~  -->
+
+<!--   ~~~~~       New section      ~~~~~     -->
+
+<sect3 renderas="sect4" id="certificate-directory"><title>certificate-directory</title>
+<variablelist>
+ <varlistentry>
+  <term>Specifies:</term>
+  <listitem>
+   <para>
+    Directory to safe generated keys and certificates.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Type of value:</term>
+  <listitem>
+   <para>
+    Text
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Default value:</term>
+  <listitem>
+   <para><emphasis>./certs</emphasis></para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Effect if unset:</term>
+  <listitem>
+   <para>
+    Default value is used.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This directive specifies the directory where generated
+    TLS/SSL keys and certificates are saved.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Examples:</term>
+  <listitem>
+   <para>
+    certificate-directory /usr/local/var/privoxy/certs
+   </para>
+  </listitem>
+ </varlistentry>
+</variablelist>
+<![%config-file;[<literallayout>@@#certificate-directory /usr/local/var/privoxy/certs</literallayout>]]>
+</sect3>
+
+<!--  ~  End section  ~  -->
+
+<!--   ~~~~~       New section      ~~~~~     -->
+
+<sect3 renderas="sect4" id="trusted-cas-file"><title>trusted-cas-file</title>
+<variablelist>
+ <varlistentry>
+  <term>Specifies:</term>
+  <listitem>
+   <para>
+    The trusted CAs file in ".pem" format.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Type of value:</term>
+  <listitem>
+   <para>
+    File name relative to ca-directory
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Default value:</term>
+  <listitem>
+   <para><emphasis>trustedCAs.pem</emphasis></para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Effect if unset:</term>
+  <listitem>
+   <para>
+    Default value is used.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This directive specifies the trusted CAs file that is used when validating
+    certificates for intercepted TLS/SSL request.
+   </para>
+   <para>
+    An example file can be downloaded from
+    <ulink url="https://curl.haxx.se/ca/cacert.pem">https://curl.haxx.se/ca/cacert.pem</ulink>.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term>Examples:</term>
+  <listitem>
+   <para>
+    trusted-cas-file trusted_cas_file.pem
+   </para>
+  </listitem>
+ </varlistentry>
+</variablelist>
+<![%config-file;[<literallayout>@@#trusted-cas-file trustedCAs.pem</literallayout>]]>
+</sect3>
+
+<!--  ~  End section  ~  -->
+
+</sect2>
+
 <!--   ~~~~~       New section      ~~~~~     -->
 
 <sect2 id="windows-gui">
index 9483f73..a07188a 100644 (file)
@@ -34,7 +34,7 @@
 
  Purpose     :  user manual
 
- Copyright (C) 2001-2018 Privoxy Developers https://www.privoxy.org/
+ Copyright (C) 2001-2019 Privoxy Developers https://www.privoxy.org/
  See LICENSE.
 
  ========================================================================
@@ -53,7 +53,7 @@
  <subscript>
 <!-- Completely the wrong markup, but very little is allowed  -->
 <!-- in this part of an article. FIXME -->
- <link linkend="copyright">Copyright</link> &my-copy; 2001-2018 by
+ <link linkend="copyright">Copyright</link> &my-copy; 2001-2019 by
  <ulink url="https://www.privoxy.org/">Privoxy Developers</ulink>
  </subscript>
 </pubdate>
@@ -3801,6 +3801,72 @@ problem-host.example.com</screen>
 </variablelist>
 </sect3>
 
+
+<!--   ~~~~~       New section      ~~~~~     -->
+<sect3 renderas="sect4" id="enable-https-filtering">
+<title>enable-https-filtering</title>
+
+<variablelist>
+ <varlistentry>
+  <term>Typical use:</term>
+  <listitem>
+   <para>Filter encrypted requests and responses</para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Effect:</term>
+  <listitem>
+   <para>
+    Encrypted requests are decrypted, filtered and forwarded encrypted.
+   </para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Type:</term>
+  <!-- boolean, parameterized, Multi-value -->
+  <listitem>
+   <para>Boolean.</para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Parameter:</term>
+  <listitem>
+   <para>
+    N/A
+   </para>
+  </listitem>
+ </varlistentry>
+
+<varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    This action allows &my-app; to filter encrypted requests and responses.
+    For this to work &my-app; has to generate a certificate and send it
+    to the client which has to accept it.
+   </para>
+   <para>
+    Before this works the directives in the
+    <link linkend="config">TLS section of the config</link>
+    file have to be configured.
+   </para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Example usage (section):</term>
+  <listitem>
+     <screen>{+enable-https-filtering}
+www.example.com</screen>
+  </listitem>
+ </varlistentry>
+
+</variablelist>
+</sect3>
+
 <!--   ~~~~~       New section      ~~~~~     -->
 <sect3 renderas="sect4" id="external-filter">
 <title>external-filter</title>
@@ -5146,6 +5212,76 @@ new action
 </sect3>
 
 
+<!--   ~~~~~       New section      ~~~~~     -->
+<sect3 renderas="sect4" id="ignore-certificate-errors">
+<title>ignore-certificate-errors</title>
+
+<variablelist>
+ <varlistentry>
+  <term>Typical use:</term>
+  <listitem>
+   <para>Filter encrypted requests and responses without verifying the certificate</para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Effect:</term>
+  <listitem>
+   <para>
+    Encrypted requests are forwarded to sites without verifying the certificate.
+   </para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Type:</term>
+  <!-- Boolean, Parameterized, Multi-value -->
+  <listitem>
+   <para>Boolean.</para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Parameter:</term>
+  <listitem>
+   <para>
+    N/A
+   </para>
+  </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Notes:</term>
+  <listitem>
+   <para>
+    When the
+    <link linkend="ENABLE-HTTPS-FILTERING"><quote>+enable-https-filtering</quote></link>
+    action is used &my-app; by default verifies that the remote site uses a valid
+    certificate.
+   </para>
+   <para>
+    If the certificate is invalid the connection is aborted.
+   </para>
+   <para>
+    This action disabled the certificate check allowing requests to sites
+    with invalid certificates.
+   </para>
+   </listitem>
+ </varlistentry>
+
+ <varlistentry>
+  <term>Example usage:</term>
+  <listitem>
+   <screen>
+    {+ignore-certificate-errors}
+    www.example.org
+   </screen>
+  </listitem>
+ </varlistentry>
+</variablelist>
+</sect3>
+
+
 <!--   ~~~~~       New section      ~~~~~     -->
 <sect3 renderas="sect4" id="limit-connect">
 <title>limit-connect</title>
index bce1263..cc51148 100644 (file)
  <subscript>
   Hosting and development is funded in part by:
  </subscript>
- <subscript>
-  <ulink url="https://thebestvpn.com">https://thebestvpn.com</ulink>
- </subscript>
  <subscript>
   <ulink url="https://www.top10vpn.com">https://www.top10vpn.com</ulink>
  </subscript>
index f4d5f9f..bb3d0a1 100644 (file)
@@ -25,7 +25,7 @@
   </div>
   <div class="SECT1">
     <h1 class="SECT1"><a name="COPYRIGHT" id="COPYRIGHT">7. Privoxy Copyright, License and History</a></h1>
-    <p>Copyright &copy; 2001-2018 by Privoxy Developers <code class="EMAIL">&#60;<a href=
+    <p>Copyright &copy; 2001-2019 by Privoxy Developers <code class="EMAIL">&#60;<a href=
     "mailto:privoxy-devel@lists.privoxy.org">privoxy-devel@lists.privoxy.org</a>&#62;</code></p>
     <p>Some source code is based on code Copyright &copy; 1997 by Anonymous Coders and Junkbusters, Inc. and licensed
     under the <i class="CITETITLE">GNU General Public License</i>.</p>
index 2be6493..17c9873 100644 (file)
@@ -94,8 +94,6 @@
       "http://jvauzb4sb3bwlsnc.onion/" target="_top">Tor onion service</a>.</sub></p>
       <p style="text-align: center"><sub>Copyright &copy; 2001-2019 by Privoxy Developers</sub></p>
       <p style="text-align: center"><sub>Hosting and development is funded in part by:</sub></p>
-      <p style="text-align: center"><sub><a href="https://thebestvpn.com" target=
-      "_top">https://thebestvpn.com</a></sub></p>
       <p style="text-align: center"><sub><a href="https://www.top10vpn.com" target=
       "_top">https://www.top10vpn.com</a></sub></p>
       <p style="text-align: center"><sub><a href="/faq/general.html#SPONSOR" target="_top">Become a
index 30c9743..630eeb1 100644 (file)
@@ -90,7 +90,7 @@
     <div class="SECT1">
       <hr>
       <h2 class="SECT1"><a name="AEN62" id="AEN62"></a></h2>
-      <p><sub>Copyright &copy; 2001-2017 by Privoxy Developers</sub></p>
+      <p><sub>Copyright &copy; 2001-2019 by Privoxy Developers</sub></p>
     </div>
   </div>
 </body>
index fb3cf8a..5fe10db 100644 (file)
@@ -12,7 +12,6 @@
   <p>This page lists <a href="../">Privoxy</a> sponsors and their <a href="../faq/general.html#SPONSOR">sponsor
   level</a> with the exception of sponsors that preferred not to be listed here.</p>
   <h3>Silver sponsors</h3>
-  <p><a href="https://thebestvpn.com">https://thebestvpn.com</a></p>
   <p><a href="https://www.top10vpn.com">https://www.top10vpn.com</a></p>
   <h3>Bronze sponsor</h3>
   <p><a href="https://www.betrugstest.com/">https://www.betrugstest.com/</a></p>
index 55de6de..db8dae2 100644 (file)
@@ -73,7 +73,7 @@
         <p>The default profiles, and their associated actions, as pre-defined in <tt class=
         "FILENAME">default.action</tt> are:</p>
         <div class="TABLE">
-          <a name="AEN2913" id="AEN2913"></a>
+          <a name="AEN3088" id="AEN3088"></a>
           <p><b>Table 1. Default Configurations</b></p>
           <table border="1" frame="border" rules="all" class="CALSTABLE">
             <col width="1*" title="C1">
@@ -1403,7 +1403,50 @@ problem-host.example.com</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="EXTERNAL-FILTER" id="EXTERNAL-FILTER">8.5.15. external-filter</a></h4>
+        <h4 class="SECT3"><a name="ENABLE-HTTPS-FILTERING" id="ENABLE-HTTPS-FILTERING">8.5.15.
+        enable-https-filtering</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Typical use:</dt>
+            <dd>
+              <p>Filter encrypted requests and responses</p>
+            </dd>
+            <dt>Effect:</dt>
+            <dd>
+              <p>Encrypted requests are decrypted, filtered and forwarded encrypted.</p>
+            </dd>
+            <dt>Type:</dt>
+            <dd>
+              <p>Boolean.</p>
+            </dd>
+            <dt>Parameter:</dt>
+            <dd>
+              <p>N/A</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This action allows <span class="APPLICATION">Privoxy</span> to filter encrypted requests and
+              responses. For this to work <span class="APPLICATION">Privoxy</span> has to generate a certificate and
+              send it to the client which has to accept it.</p>
+              <p>Before this works the directives in the <a href="config.html">TLS section of the config</a> file have
+              to be configured.</p>
+            </dd>
+            <dt>Example usage (section):</dt>
+            <dd>
+              <table border="0" bgcolor="#E0E0E0" width="90%">
+                <tr>
+                  <td>
+                    <pre class="SCREEN">{+enable-https-filtering}
+www.example.com</pre>
+                  </td>
+                </tr>
+              </table>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="EXTERNAL-FILTER" id="EXTERNAL-FILTER">8.5.16. external-filter</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -1465,7 +1508,7 @@ problem-host.example.com</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="FAST-REDIRECTS" id="FAST-REDIRECTS">8.5.16. fast-redirects</a></h4>
+        <h4 class="SECT3"><a name="FAST-REDIRECTS" id="FAST-REDIRECTS">8.5.17. fast-redirects</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -1546,7 +1589,7 @@ problem-host.example.com</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="FILTER" id="FILTER">8.5.17. filter</a></h4>
+        <h4 class="SECT3"><a name="FILTER" id="FILTER">8.5.18. filter</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -1861,7 +1904,7 @@ problem-host.example.com</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="FORCE-TEXT-MODE" id="FORCE-TEXT-MODE">8.5.18. force-text-mode</a></h4>
+        <h4 class="SECT3"><a name="FORCE-TEXT-MODE" id="FORCE-TEXT-MODE">8.5.19. force-text-mode</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -1918,7 +1961,7 @@ problem-host.example.com</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="FORWARD-OVERRIDE" id="FORWARD-OVERRIDE">8.5.19. forward-override</a></h4>
+        <h4 class="SECT3"><a name="FORWARD-OVERRIDE" id="FORWARD-OVERRIDE">8.5.20. forward-override</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2025,7 +2068,7 @@ TAG:^User-Agent: fetch libfetch/2\.0$</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HANDLE-AS-EMPTY-DOCUMENT" id="HANDLE-AS-EMPTY-DOCUMENT">8.5.20.
+        <h4 class="SECT3"><a name="HANDLE-AS-EMPTY-DOCUMENT" id="HANDLE-AS-EMPTY-DOCUMENT">8.5.21.
         handle-as-empty-document</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2078,7 +2121,7 @@ example.org/.*\.js$</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HANDLE-AS-IMAGE" id="HANDLE-AS-IMAGE">8.5.21. handle-as-image</a></h4>
+        <h4 class="SECT3"><a name="HANDLE-AS-IMAGE" id="HANDLE-AS-IMAGE">8.5.22. handle-as-image</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2138,7 +2181,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HIDE-ACCEPT-LANGUAGE" id="HIDE-ACCEPT-LANGUAGE">8.5.22.
+        <h4 class="SECT3"><a name="HIDE-ACCEPT-LANGUAGE" id="HIDE-ACCEPT-LANGUAGE">8.5.23.
         hide-accept-language</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2191,7 +2234,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HIDE-CONTENT-DISPOSITION" id="HIDE-CONTENT-DISPOSITION">8.5.23.
+        <h4 class="SECT3"><a name="HIDE-CONTENT-DISPOSITION" id="HIDE-CONTENT-DISPOSITION">8.5.24.
         hide-content-disposition</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2247,7 +2290,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HIDE-IF-MODIFIED-SINCE" id="HIDE-IF-MODIFIED-SINCE">8.5.24.
+        <h4 class="SECT3"><a name="HIDE-IF-MODIFIED-SINCE" id="HIDE-IF-MODIFIED-SINCE">8.5.25.
         hide-if-modified-since</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2306,7 +2349,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HIDE-FROM-HEADER" id="HIDE-FROM-HEADER">8.5.25. hide-from-header</a></h4>
+        <h4 class="SECT3"><a name="HIDE-FROM-HEADER" id="HIDE-FROM-HEADER">8.5.26. hide-from-header</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2357,7 +2400,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HIDE-REFERRER" id="HIDE-REFERRER">8.5.26. hide-referrer</a></h4><a name=
+        <h4 class="SECT3"><a name="HIDE-REFERRER" id="HIDE-REFERRER">8.5.27. hide-referrer</a></h4><a name=
         "HIDE-REFERER" id="HIDE-REFERER"></a>
         <div class="VARIABLELIST">
           <dl>
@@ -2438,7 +2481,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="HIDE-USER-AGENT" id="HIDE-USER-AGENT">8.5.27. hide-user-agent</a></h4>
+        <h4 class="SECT3"><a name="HIDE-USER-AGENT" id="HIDE-USER-AGENT">8.5.28. hide-user-agent</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2499,7 +2542,51 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="LIMIT-CONNECT" id="LIMIT-CONNECT">8.5.28. limit-connect</a></h4>
+        <h4 class="SECT3"><a name="IGNORE-CERTIFICATE-ERRORS" id="IGNORE-CERTIFICATE-ERRORS">8.5.29.
+        ignore-certificate-errors</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Typical use:</dt>
+            <dd>
+              <p>Filter encrypted requests and responses without verifying the certificate</p>
+            </dd>
+            <dt>Effect:</dt>
+            <dd>
+              <p>Encrypted requests are forwarded to sites without verifying the certificate.</p>
+            </dd>
+            <dt>Type:</dt>
+            <dd>
+              <p>Boolean.</p>
+            </dd>
+            <dt>Parameter:</dt>
+            <dd>
+              <p>N/A</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>When the <a href="actions-file.html#ENABLE-HTTPS-FILTERING"><span class=
+              "QUOTE">"+enable-https-filtering"</span></a> action is used <span class="APPLICATION">Privoxy</span> by
+              default verifies that the remote site uses a valid certificate.</p>
+              <p>If the certificate is invalid the connection is aborted.</p>
+              <p>This action disabled the certificate check allowing requests to sites with invalid certificates.</p>
+            </dd>
+            <dt>Example usage:</dt>
+            <dd>
+              <table border="0" bgcolor="#E0E0E0" width="90%">
+                <tr>
+                  <td>
+                    <pre class="SCREEN">    {+ignore-certificate-errors}
+    www.example.org
+   </pre>
+                  </td>
+                </tr>
+              </table>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="LIMIT-CONNECT" id="LIMIT-CONNECT">8.5.30. limit-connect</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2551,7 +2638,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="LIMIT-COOKIE-LIFETIME" id="LIMIT-COOKIE-LIFETIME">8.5.29.
+        <h4 class="SECT3"><a name="LIMIT-COOKIE-LIFETIME" id="LIMIT-COOKIE-LIFETIME">8.5.31.
         limit-cookie-lifetime</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2603,7 +2690,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="PREVENT-COMPRESSION" id="PREVENT-COMPRESSION">8.5.30. prevent-compression</a></h4>
+        <h4 class="SECT3"><a name="PREVENT-COMPRESSION" id="PREVENT-COMPRESSION">8.5.32. prevent-compression</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2674,7 +2761,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="OVERWRITE-LAST-MODIFIED" id="OVERWRITE-LAST-MODIFIED">8.5.31.
+        <h4 class="SECT3"><a name="OVERWRITE-LAST-MODIFIED" id="OVERWRITE-LAST-MODIFIED">8.5.33.
         overwrite-last-modified</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2736,7 +2823,7 @@ nasty-banner-server.example.com/junk.cgi\?output=trash</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="REDIRECT" id="REDIRECT">8.5.32. redirect</a></h4>
+        <h4 class="SECT3"><a name="REDIRECT" id="REDIRECT">8.5.34. redirect</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -2828,7 +2915,7 @@ www.privoxy.org/user-manual/</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="SERVER-HEADER-FILTER" id="SERVER-HEADER-FILTER">8.5.33.
+        <h4 class="SECT3"><a name="SERVER-HEADER-FILTER" id="SERVER-HEADER-FILTER">8.5.35.
         server-header-filter</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2878,7 +2965,7 @@ example.org/instance-that-is-delivered-as-xml-but-is-not</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="SERVER-HEADER-TAGGER" id="SERVER-HEADER-TAGGER">8.5.34.
+        <h4 class="SECT3"><a name="SERVER-HEADER-TAGGER" id="SERVER-HEADER-TAGGER">8.5.36.
         server-header-tagger</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2935,7 +3022,7 @@ TAG:^image/</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="SESSION-COOKIES-ONLY" id="SESSION-COOKIES-ONLY">8.5.35.
+        <h4 class="SECT3"><a name="SESSION-COOKIES-ONLY" id="SESSION-COOKIES-ONLY">8.5.37.
         session-cookies-only</a></h4>
         <div class="VARIABLELIST">
           <dl>
@@ -2997,7 +3084,7 @@ TAG:^image/</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h4 class="SECT3"><a name="SET-IMAGE-BLOCKER" id="SET-IMAGE-BLOCKER">8.5.36. set-image-blocker</a></h4>
+        <h4 class="SECT3"><a name="SET-IMAGE-BLOCKER" id="SET-IMAGE-BLOCKER">8.5.38. set-image-blocker</a></h4>
         <div class="VARIABLELIST">
           <dl>
             <dt>Typical use:</dt>
@@ -3086,7 +3173,7 @@ TAG:^image/</pre>
         </div>
       </div>
       <div class="SECT3">
-        <h3 class="SECT3"><a name="SUMMARY" id="SUMMARY">8.5.37. Summary</a></h3>
+        <h3 class="SECT3"><a name="SUMMARY" id="SUMMARY">8.5.39. Summary</a></h3>
         <p>Note that many of these actions have the potential to cause a page to misbehave, possibly even not to
         display at all. There are many ways a site designer may choose to design his site, and what HTTP header
         content, and other criteria, he may depend on. There is no way to have hard and fast rules for all sites. See
index bcdb32f..d914954 100644 (file)
       these. If not, you will get a friendly error message. Internet access is not necessary either.</p>
       <ul>
         <li>
-          <p>Privoxy main page:</p><a name="AEN6032" id="AEN6032"></a>
+          <p>Privoxy main page:</p><a name="AEN6270" id="AEN6270"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/" target="_top">http://config.privoxy.org/</a></p>
           </blockquote>
           "APPLICATION">Privoxy</span>)</p>
         </li>
         <li>
-          <p>View and toggle client tags:</p><a name="AEN6040" id="AEN6040"></a>
+          <p>View and toggle client tags:</p><a name="AEN6278" id="AEN6278"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/client-tags" target=
             "_top">http://config.privoxy.org/client-tags</a></p>
         </li>
         <li>
           <p>Show information about the current configuration, including viewing and editing of actions
-          files:</p><a name="AEN6045" id="AEN6045"></a>
+          files:</p><a name="AEN6283" id="AEN6283"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/show-status" target=
             "_top">http://config.privoxy.org/show-status</a></p>
           </blockquote>
         </li>
         <li>
-          <p>Show the browser's request headers:</p><a name="AEN6050" id="AEN6050"></a>
+          <p>Show the browser's request headers:</p><a name="AEN6288" id="AEN6288"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/show-request" target=
             "_top">http://config.privoxy.org/show-request</a></p>
           </blockquote>
         </li>
         <li>
-          <p>Show which actions apply to a URL and why:</p><a name="AEN6055" id="AEN6055"></a>
+          <p>Show which actions apply to a URL and why:</p><a name="AEN6293" id="AEN6293"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/show-url-info" target=
             "_top">http://config.privoxy.org/show-url-info</a></p>
         <li>
           <p>Toggle Privoxy on or off. This feature can be turned off/on in the main <tt class="FILENAME">config</tt>
           file. When toggled <span class="QUOTE">"off"</span>, <span class="QUOTE">"Privoxy"</span> continues to run,
-          but only as a pass-through proxy, with no actions taking place:</p><a name="AEN6063" id="AEN6063"></a>
+          but only as a pass-through proxy, with no actions taking place:</p><a name="AEN6301" id="AEN6301"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/toggle" target="_top">http://config.privoxy.org/toggle</a></p>
           </blockquote>
-          <p>Short cuts. Turn off, then on:</p><a name="AEN6067" id="AEN6067"></a>
+          <p>Short cuts. Turn off, then on:</p><a name="AEN6305" id="AEN6305"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/toggle?set=disable" target=
             "_top">http://config.privoxy.org/toggle?set=disable</a></p>
-          </blockquote><a name="AEN6070" id="AEN6070"></a>
+          </blockquote><a name="AEN6308" id="AEN6308"></a>
           <blockquote class="BLOCKQUOTE">
             <p><a href="http://config.privoxy.org/toggle?set=enable" target=
             "_top">http://config.privoxy.org/toggle?set=enable</a></p>
index fbca936..ad8e518 100644 (file)
       </div>
     </div>
     <div class="SECT2">
-      <h2 class="SECT2"><a name="WINDOWS-GUI" id="WINDOWS-GUI">7.7. Windows GUI Options</a></h2>
+      <h2 class="SECT2"><a name="TLS" id="TLS">7.7. TLS/SSL</a></h2>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="CA-DIRECTORY" id="CA-DIRECTORY">7.7.1. ca-directory</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Specifies:</dt>
+            <dd>
+              <p>Directory with the CA key, the CA certificate and the trusted CAs file.</p>
+            </dd>
+            <dt>Type of value:</dt>
+            <dd>
+              <p>Text</p>
+            </dd>
+            <dt>Default value:</dt>
+            <dd>
+              <p><span class="emphasis"><i class="EMPHASIS">Empty string</i></span></p>
+            </dd>
+            <dt>Effect if unset:</dt>
+            <dd>
+              <p>Default value is used.</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This directive specifies the directory where the CA key, the CA certificate and the trusted CAs file
+              are located.</p>
+            </dd>
+            <dt>Examples:</dt>
+            <dd>
+              <p>ca-directory /usr/local/etc/privoxy/CA</p>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="CA-CERT-FILE" id="CA-CERT-FILE">7.7.2. ca-cert-file</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Specifies:</dt>
+            <dd>
+              <p>The CA certificate file in ".crt" format.</p>
+            </dd>
+            <dt>Type of value:</dt>
+            <dd>
+              <p>Text</p>
+            </dd>
+            <dt>Default value:</dt>
+            <dd>
+              <p><span class="emphasis"><i class="EMPHASIS">cacert.crt</i></span></p>
+            </dd>
+            <dt>Effect if unset:</dt>
+            <dd>
+              <p>Default value is used.</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This directive specifies the name of the CA certificate file in ".crt" format.</p>
+              <p>It can be generated with: openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.crt
+              -days 3650</p>
+            </dd>
+            <dt>Examples:</dt>
+            <dd>
+              <p>ca-cert-file root.crt</p>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="CA-KEY-FILE" id="CA-KEY-FILE">7.7.3. ca-key-file</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Specifies:</dt>
+            <dd>
+              <p>The CA key file in ".pem" format.</p>
+            </dd>
+            <dt>Type of value:</dt>
+            <dd>
+              <p>Text</p>
+            </dd>
+            <dt>Default value:</dt>
+            <dd>
+              <p><span class="emphasis"><i class="EMPHASIS">cacert.pem</i></span></p>
+            </dd>
+            <dt>Effect if unset:</dt>
+            <dd>
+              <p>Default value is used.</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This directive specifies the name of the CA key file in ".pem" format. See the <a href="#CA-CERT-FILE"
+              target="_top">ca-cert-file</a> for a command to generate it.</p>
+            </dd>
+            <dt>Examples:</dt>
+            <dd>
+              <p>ca-key-file cakey.pem</p>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="CA-PASSWORD" id="CA-PASSWORD">7.7.4. ca-password</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Specifies:</dt>
+            <dd>
+              <p>The password for the CA keyfile.</p>
+            </dd>
+            <dt>Type of value:</dt>
+            <dd>
+              <p>Text</p>
+            </dd>
+            <dt>Default value:</dt>
+            <dd>
+              <p><span class="emphasis"><i class="EMPHASIS">Empty string</i></span></p>
+            </dd>
+            <dt>Effect if unset:</dt>
+            <dd>
+              <p>Default value is used.</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This directive specifies the password for the CA keyfile that is used when Privoxy generates
+              certificates for intercepted requests.</p>
+              <p>Note that the password is shown on the CGI page so don't reuse an important one.</p>
+            </dd>
+            <dt>Examples:</dt>
+            <dd>
+              <p>ca-password blafasel</p>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="CERTIFICATE-DIRECTORY" id="CERTIFICATE-DIRECTORY">7.7.5.
+        certificate-directory</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Specifies:</dt>
+            <dd>
+              <p>Directory to safe generated keys and certificates.</p>
+            </dd>
+            <dt>Type of value:</dt>
+            <dd>
+              <p>Text</p>
+            </dd>
+            <dt>Default value:</dt>
+            <dd>
+              <p><span class="emphasis"><i class="EMPHASIS">./certs</i></span></p>
+            </dd>
+            <dt>Effect if unset:</dt>
+            <dd>
+              <p>Default value is used.</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This directive specifies the directory where generated TLS/SSL keys and certificates are saved.</p>
+            </dd>
+            <dt>Examples:</dt>
+            <dd>
+              <p>certificate-directory /usr/local/var/privoxy/certs</p>
+            </dd>
+          </dl>
+        </div>
+      </div>
+      <div class="SECT3">
+        <h4 class="SECT3"><a name="TRUSTED-CAS-FILE" id="TRUSTED-CAS-FILE">7.7.6. trusted-cas-file</a></h4>
+        <div class="VARIABLELIST">
+          <dl>
+            <dt>Specifies:</dt>
+            <dd>
+              <p>The trusted CAs file in ".pem" format.</p>
+            </dd>
+            <dt>Type of value:</dt>
+            <dd>
+              <p>File name relative to ca-directory</p>
+            </dd>
+            <dt>Default value:</dt>
+            <dd>
+              <p><span class="emphasis"><i class="EMPHASIS">trustedCAs.pem</i></span></p>
+            </dd>
+            <dt>Effect if unset:</dt>
+            <dd>
+              <p>Default value is used.</p>
+            </dd>
+            <dt>Notes:</dt>
+            <dd>
+              <p>This directive specifies the trusted CAs file that is used when validating certificates for
+              intercepted TLS/SSL request.</p>
+              <p>An example file can be downloaded from <a href="https://curl.haxx.se/ca/cacert.pem" target=
+              "_top">https://curl.haxx.se/ca/cacert.pem</a>.</p>
+            </dd>
+            <dt>Examples:</dt>
+            <dd>
+              <p>trusted-cas-file trusted_cas_file.pem</p>
+            </dd>
+          </dl>
+        </div>
+      </div>
+    </div>
+    <div class="SECT2">
+      <h2 class="SECT2"><a name="WINDOWS-GUI" id="WINDOWS-GUI">7.8. Windows GUI Options</a></h2>
       <p><span class="APPLICATION">Privoxy</span> has a number of options specific to the Windows GUI
       interface:</p><a name="ACTIVITY-ANIMATION" id="ACTIVITY-ANIMATION"></a>
       <p>If <span class="QUOTE">"activity-animation"</span> is set to 1, the <span class="APPLICATION">Privoxy</span>
index 63b670c..7be80d4 100644 (file)
@@ -27,7 +27,7 @@
   </div>
   <div class="SECT1">
     <h1 class="SECT1"><a name="COPYRIGHT">12. Privoxy Copyright, License and History</a></h1>
-    <p>Copyright &copy; 2001-2018 by Privoxy Developers <code class="EMAIL">&#60;<a href=
+    <p>Copyright &copy; 2001-2019 by Privoxy Developers <code class="EMAIL">&#60;<a href=
     "mailto:privoxy-devel@lists.privoxy.org">privoxy-devel@lists.privoxy.org</a>&#62;</code></p>
     <p>Some source code is based on code Copyright &copy; 1997 by Anonymous Coders and Junkbusters, Inc. and licensed
     under the <i class="CITETITLE">GNU General Public License</i>.</p>
@@ -545,6 +545,7 @@ Public License instead of this License.
       &nbsp;Simon&nbsp;South<br>
       &nbsp;Dan&nbsp;Stahlke<br>
       &nbsp;Oliver&nbsp;Stoeneberg<br>
+      &nbsp;V&aacute;clav&nbsp;&Scaron;vec<br>
       &nbsp;Rick&nbsp;Sykes<br>
       &nbsp;Spinor&nbsp;S.<br>
       &nbsp;Peter&nbsp;Thoenen<br>
index ccf079b..4d3898e 100644 (file)
@@ -13,7 +13,7 @@
   <div class="ARTICLE">
     <div class="TITLEPAGE">
       <h1 class="TITLE"><a name="AEN2" id="AEN2">Privoxy 3.0.29 User Manual</a></h1>
-      <p class="PUBDATE"><sub><a href="copyright.html">Copyright</a> &copy; 2001-2018 by <a href=
+      <p class="PUBDATE"><sub><a href="copyright.html">Copyright</a> &copy; 2001-2019 by <a href=
       "https://www.privoxy.org/" target="_top">Privoxy Developers</a></sub><br></p>
       <div>
         <div class="ABSTRACT">
                 <dt>7.6.19. <a href="config.html#RECEIVE-BUFFER-SIZE">receive-buffer-size</a></dt>
               </dl>
             </dd>
-            <dt>7.7. <a href="config.html#WINDOWS-GUI">Windows GUI Options</a></dt>
+            <dt>7.7. <a href="config.html#TLS">TLS/SSL</a></dt>
+            <dd>
+              <dl>
+                <dt>7.7.1. <a href="config.html#CA-DIRECTORY">ca-directory</a></dt>
+                <dt>7.7.2. <a href="config.html#CA-CERT-FILE">ca-cert-file</a></dt>
+                <dt>7.7.3. <a href="config.html#CA-KEY-FILE">ca-key-file</a></dt>
+                <dt>7.7.4. <a href="config.html#CA-PASSWORD">ca-password</a></dt>
+                <dt>7.7.5. <a href="config.html#CERTIFICATE-DIRECTORY">certificate-directory</a></dt>
+                <dt>7.7.6. <a href="config.html#TRUSTED-CAS-FILE">trusted-cas-file</a></dt>
+              </dl>
+            </dd>
+            <dt>7.8. <a href="config.html#WINDOWS-GUI">Windows GUI Options</a></dt>
           </dl>
         </dd>
         <dt>8. <a href="actions-file.html">Actions Files</a></dt>
                 <dt>8.5.12. <a href="actions-file.html#DEANIMATE-GIFS">deanimate-gifs</a></dt>
                 <dt>8.5.13. <a href="actions-file.html#DELAY-RESPONSE">delay-response</a></dt>
                 <dt>8.5.14. <a href="actions-file.html#DOWNGRADE-HTTP-VERSION">downgrade-http-version</a></dt>
-                <dt>8.5.15. <a href="actions-file.html#EXTERNAL-FILTER">external-filter</a></dt>
-                <dt>8.5.16. <a href="actions-file.html#FAST-REDIRECTS">fast-redirects</a></dt>
-                <dt>8.5.17. <a href="actions-file.html#FILTER">filter</a></dt>
-                <dt>8.5.18. <a href="actions-file.html#FORCE-TEXT-MODE">force-text-mode</a></dt>
-                <dt>8.5.19. <a href="actions-file.html#FORWARD-OVERRIDE">forward-override</a></dt>
-                <dt>8.5.20. <a href="actions-file.html#HANDLE-AS-EMPTY-DOCUMENT">handle-as-empty-document</a></dt>
-                <dt>8.5.21. <a href="actions-file.html#HANDLE-AS-IMAGE">handle-as-image</a></dt>
-                <dt>8.5.22. <a href="actions-file.html#HIDE-ACCEPT-LANGUAGE">hide-accept-language</a></dt>
-                <dt>8.5.23. <a href="actions-file.html#HIDE-CONTENT-DISPOSITION">hide-content-disposition</a></dt>
-                <dt>8.5.24. <a href="actions-file.html#HIDE-IF-MODIFIED-SINCE">hide-if-modified-since</a></dt>
-                <dt>8.5.25. <a href="actions-file.html#HIDE-FROM-HEADER">hide-from-header</a></dt>
-                <dt>8.5.26. <a href="actions-file.html#HIDE-REFERRER">hide-referrer</a></dt>
-                <dt>8.5.27. <a href="actions-file.html#HIDE-USER-AGENT">hide-user-agent</a></dt>
-                <dt>8.5.28. <a href="actions-file.html#LIMIT-CONNECT">limit-connect</a></dt>
-                <dt>8.5.29. <a href="actions-file.html#LIMIT-COOKIE-LIFETIME">limit-cookie-lifetime</a></dt>
-                <dt>8.5.30. <a href="actions-file.html#PREVENT-COMPRESSION">prevent-compression</a></dt>
-                <dt>8.5.31. <a href="actions-file.html#OVERWRITE-LAST-MODIFIED">overwrite-last-modified</a></dt>
-                <dt>8.5.32. <a href="actions-file.html#REDIRECT">redirect</a></dt>
-                <dt>8.5.33. <a href="actions-file.html#SERVER-HEADER-FILTER">server-header-filter</a></dt>
-                <dt>8.5.34. <a href="actions-file.html#SERVER-HEADER-TAGGER">server-header-tagger</a></dt>
-                <dt>8.5.35. <a href="actions-file.html#SESSION-COOKIES-ONLY">session-cookies-only</a></dt>
-                <dt>8.5.36. <a href="actions-file.html#SET-IMAGE-BLOCKER">set-image-blocker</a></dt>
-                <dt>8.5.37. <a href="actions-file.html#SUMMARY">Summary</a></dt>
+                <dt>8.5.15. <a href="actions-file.html#ENABLE-HTTPS-FILTERING">enable-https-filtering</a></dt>
+                <dt>8.5.16. <a href="actions-file.html#EXTERNAL-FILTER">external-filter</a></dt>
+                <dt>8.5.17. <a href="actions-file.html#FAST-REDIRECTS">fast-redirects</a></dt>
+                <dt>8.5.18. <a href="actions-file.html#FILTER">filter</a></dt>
+                <dt>8.5.19. <a href="actions-file.html#FORCE-TEXT-MODE">force-text-mode</a></dt>
+                <dt>8.5.20. <a href="actions-file.html#FORWARD-OVERRIDE">forward-override</a></dt>
+                <dt>8.5.21. <a href="actions-file.html#HANDLE-AS-EMPTY-DOCUMENT">handle-as-empty-document</a></dt>
+                <dt>8.5.22. <a href="actions-file.html#HANDLE-AS-IMAGE">handle-as-image</a></dt>
+                <dt>8.5.23. <a href="actions-file.html#HIDE-ACCEPT-LANGUAGE">hide-accept-language</a></dt>
+                <dt>8.5.24. <a href="actions-file.html#HIDE-CONTENT-DISPOSITION">hide-content-disposition</a></dt>
+                <dt>8.5.25. <a href="actions-file.html#HIDE-IF-MODIFIED-SINCE">hide-if-modified-since</a></dt>
+                <dt>8.5.26. <a href="actions-file.html#HIDE-FROM-HEADER">hide-from-header</a></dt>
+                <dt>8.5.27. <a href="actions-file.html#HIDE-REFERRER">hide-referrer</a></dt>
+                <dt>8.5.28. <a href="actions-file.html#HIDE-USER-AGENT">hide-user-agent</a></dt>
+                <dt>8.5.29. <a href="actions-file.html#IGNORE-CERTIFICATE-ERRORS">ignore-certificate-errors</a></dt>
+                <dt>8.5.30. <a href="actions-file.html#LIMIT-CONNECT">limit-connect</a></dt>
+                <dt>8.5.31. <a href="actions-file.html#LIMIT-COOKIE-LIFETIME">limit-cookie-lifetime</a></dt>
+                <dt>8.5.32. <a href="actions-file.html#PREVENT-COMPRESSION">prevent-compression</a></dt>
+                <dt>8.5.33. <a href="actions-file.html#OVERWRITE-LAST-MODIFIED">overwrite-last-modified</a></dt>
+                <dt>8.5.34. <a href="actions-file.html#REDIRECT">redirect</a></dt>
+                <dt>8.5.35. <a href="actions-file.html#SERVER-HEADER-FILTER">server-header-filter</a></dt>
+                <dt>8.5.36. <a href="actions-file.html#SERVER-HEADER-TAGGER">server-header-tagger</a></dt>
+                <dt>8.5.37. <a href="actions-file.html#SESSION-COOKIES-ONLY">session-cookies-only</a></dt>
+                <dt>8.5.38. <a href="actions-file.html#SET-IMAGE-BLOCKER">set-image-blocker</a></dt>
+                <dt>8.5.39. <a href="actions-file.html#SUMMARY">Summary</a></dt>
               </dl>
             </dd>
             <dt>8.6. <a href="actions-file.html#ALIASES">Aliases</a></dt>
diff --git a/jcc.c b/jcc.c
index 34327f2..132618b 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -5,7 +5,7 @@
  * Purpose     :  Main file.  Contains main() method, main loop, and
  *                the main connection-handling function.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2018 the
+ * Copyright   :  Written by and Copyright (C) 2001-2019 the
  *                Privoxy team. http://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
 #include "project.h"
 #include "list.h"
 #include "jcc.h"
+#ifdef FEATURE_HTTPS_FILTERING
+#include "ssl.h"
+#endif
 #include "filters.h"
 #include "loaders.h"
 #include "parsers.h"
@@ -147,7 +150,7 @@ static int client_protocol_is_unsupported(const struct client_state *csp, char *
 static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers);
 static jb_err get_server_headers(struct client_state *csp);
 static const char *crunch_reason(const struct http_response *rsp);
-static void send_crunch_response(const struct client_state *csp, struct http_response *rsp);
+static void send_crunch_response(struct client_state *csp, struct http_response *rsp);
 static char *get_request_line(struct client_state *csp);
 static jb_err receive_client_request(struct client_state *csp);
 static jb_err parse_client_request(struct client_state *csp);
@@ -190,6 +193,13 @@ privoxy_mutex_t log_mutex;
 privoxy_mutex_t log_init_mutex;
 privoxy_mutex_t connection_reuse_mutex;
 
+#ifdef LIMIT_MUTEX_NUMBER
+   privoxy_mutex_t certificates_mutexes[32];
+#else
+   privoxy_mutex_t certificates_mutexes[65536];
+#endif /* LIMIT_MUTEX_NUMBER */
+   privoxy_mutex_t rng_mutex;
+
 #ifdef FEATURE_EXTERNAL_FILTERS
 privoxy_mutex_t external_filter_mutex;
 #endif
@@ -799,7 +809,7 @@ static void log_applied_actions(const struct current_action_spec *actions)
  * Returns     :  Nothing.
  *
  *********************************************************************/
-static void send_crunch_response(const struct client_state *csp, struct http_response *rsp)
+static void send_crunch_response(struct client_state *csp, struct http_response *rsp)
 {
       const struct http_request *http = csp->http;
       char status_code[4];
@@ -834,13 +844,33 @@ static void send_crunch_response(const struct client_state *csp, struct http_res
          csp->ip_addr_str, http->ocmd, status_code, rsp->content_length);
 
       /* Write the answer to the client */
-      if (write_socket_delayed(csp->cfd, rsp->head, rsp->head_length, get_write_delay(csp))
-       || write_socket_delayed(csp->cfd, rsp->body, rsp->content_length, get_write_delay(csp)))
+#ifdef FEATURE_HTTPS_FILTERING
+      if (client_use_ssl(csp))
       {
-         /* There is nothing we can do about it. */
-         log_error(LOG_LEVEL_CONNECT,
-            "Couldn't deliver the error message for %s through client socket %d: %E",
-            http->url, csp->cfd);
+         if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                 (const unsigned char *)rsp->head, rsp->head_length) < 0)
+          || (ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                 (const unsigned char *)rsp->body, rsp->content_length) < 0))
+         {
+            /* There is nothing we can do about it. */
+            log_error(LOG_LEVEL_CONNECT, "Couldn't deliver the error message "
+               "for %s through client socket %d using TLS/SSL",
+               http->url, csp->cfd);
+         }
+      }
+      else
+#endif
+      {
+         if (write_socket_delayed(csp->cfd, rsp->head, rsp->head_length,
+                get_write_delay(csp))
+          || write_socket_delayed(csp->cfd, rsp->body, rsp->content_length,
+                get_write_delay(csp)))
+         {
+            /* There is nothing we can do about it. */
+            log_error(LOG_LEVEL_CONNECT,
+               "Couldn't deliver the error message for %s through client socket %d: %E",
+               http->url, csp->cfd);
+         }
       }
 
       /* Clean up and return */
@@ -941,8 +971,6 @@ static void build_request_line(struct client_state *csp, const struct forward_sp
 {
    struct http_request *http = csp->http;
 
-   assert(http->ssl == 0);
-
    /*
     * Downgrade http version from 1.1 to 1.0
     * if +downgrade action applies.
@@ -1986,6 +2014,300 @@ static int send_http_request(struct client_state *csp)
 }
 
 
+#ifdef FEATURE_HTTPS_FILTERING
+/*********************************************************************
+ *
+ * Function    : send_https_request
+ *
+ * Description : Sends the HTTP headers from the client request
+ *               and all the body data that has already been received.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 on success, anything else is an error.
+ *
+ *********************************************************************/
+static int send_https_request(struct client_state *csp)
+{
+   char *hdr;
+   int ret;
+   long flushed = 0;
+
+   hdr = list_to_text(csp->https_headers);
+   if (hdr == NULL)
+   {
+      /* FIXME Should handle error properly */
+      log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header");
+   }
+   list_remove_all(csp->https_headers);
+
+   /*
+    * Write the client's (modified) header to the server
+    * (along with anything else that may be in the buffer)
+    */
+   ret = ssl_send_data(&(csp->mbedtls_server_attr.ssl),
+      (const unsigned char *)hdr, strlen(hdr));
+   freez(hdr);
+
+   if (ret < 0)
+   {
+      log_error(LOG_LEVEL_CONNECT,
+         "Failed sending encrypted request headers to: %s: %E",
+         csp->http->hostport);
+      mark_server_socket_tainted(csp);
+      close_client_and_server_ssl_connections(csp);
+      return 1;
+   }
+
+   if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0)
+      && ((flushed = ssl_flush_socket(&(csp->mbedtls_server_attr.ssl),
+            csp->client_iob)) < 0))
+   {
+      log_error(LOG_LEVEL_CONNECT, "Failed sending request body to: %s: %E",
+         csp->http->hostport);
+      return 1;
+   }
+   if (flushed != 0)
+   {
+      if (csp->expected_client_content_length != 0)
+      {
+         if (csp->expected_client_content_length < flushed)
+         {
+            log_error(LOG_LEVEL_ERROR,
+               "Flushed %d bytes of request body while only expecting %llu",
+               flushed, csp->expected_client_content_length);
+            csp->expected_client_content_length = 0;
+         }
+         else
+         {
+            log_error(LOG_LEVEL_CONNECT,
+               "Flushed %d bytes of request body while expecting %llu",
+               flushed, csp->expected_client_content_length);
+            csp->expected_client_content_length -= (unsigned)flushed;
+         }
+      }
+      else
+      {
+         log_error(LOG_LEVEL_CONNECT,
+            "Flushed %d bytes of request body", flushed);
+      }
+   }
+
+   log_error(LOG_LEVEL_CONNECT, "Encrypted request sent");
+
+   return 0;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  receive_encrypted_request
+ *
+ * Description :  Receives an encrypted request.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  JB_ERR_OK on success,
+ *                JB_ERR_PARSE or JB_ERR_MEMORY otherwise
+ *
+ *********************************************************************/
+static jb_err receive_encrypted_request(struct client_state *csp)
+{
+   char buf[BUFFER_SIZE];
+   int len;
+   char *p;
+
+   do
+   {
+      log_error(LOG_LEVEL_HEADER, "Reading encrypted headers");
+      if (!data_is_available(csp->cfd, (int)csp->config->keep_alive_timeout))
+      {
+         log_error(LOG_LEVEL_CONNECT,
+            "Socket %d timed out while waiting for client headers", csp->cfd);
+         return JB_ERR_PARSE;
+      }
+      len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl),
+         (unsigned char *)buf, sizeof(buf));
+      if (len == -1)
+      {
+         return JB_ERR_PARSE;
+      }
+      if (add_to_iob(csp->client_iob, csp->config->buffer_limit, buf, len))
+      {
+         return JB_ERR_MEMORY;
+      }
+      p = strstr(csp->client_iob->cur, "\r\n\r\n");
+   } while (p == NULL);
+
+   log_error(LOG_LEVEL_HEADER, "Encrypted headers received completely");
+
+   return JB_ERR_OK;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  process_encrypted_request
+ *
+ * Description :  Receives and parses an encrypted request.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  JB_ERR_OK on success,
+ *                JB_ERR_PARSE or JB_ERR_MEMORY otherwise
+ *
+ *********************************************************************/
+static jb_err process_encrypted_request(struct client_state *csp)
+{
+   char *p;
+   char *request_line;
+   jb_err err;
+   /* Temporary copy of the client's headers before they get enlisted in csp->https_headers */
+   struct list header_list;
+   struct list *headers = &header_list;
+
+   err = receive_encrypted_request(csp);
+   if (err != JB_ERR_OK)
+   {
+      /* XXX: Also used for JB_ERR_MEMORY */
+      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER));
+      return err;
+   }
+
+   /* We don't need get_request_line() because the whole HTTP head is buffered. */
+   request_line = get_header(csp->client_iob);
+   if (request_line == NULL)
+   {
+      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER));
+      return JB_ERR_PARSE;
+   }
+   assert(*request_line != '\0');
+
+   if (client_protocol_is_unsupported(csp, request_line))
+   {
+      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER));
+      return JB_ERR_PARSE;
+   }
+
+#ifdef FEATURE_FORCE_LOAD
+   if (force_required(csp, request_line))
+   {
+      csp->flags |= CSP_FLAG_FORCED;
+   }
+#endif /* def FEATURE_FORCE_LOAD */
+
+   free_http_request(csp->http);
+
+   err = parse_http_request(request_line, csp->http);
+   /* XXX: Restore ssl setting. This is ugly */
+   csp->http->client_ssl = 1;
+   csp->http->server_ssl = 1;
+
+   freez(request_line);
+   if (JB_ERR_OK != err)
+   {
+      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER));
+      /* XXX: Use correct size */
+      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str);
+      log_error(LOG_LEVEL_ERROR,
+         "Couldn't parse request line received from %s: %s",
+         csp->ip_addr_str, jb_err_to_string(err));
+
+      free_http_request(csp->http);
+      return JB_ERR_PARSE;
+   }
+
+   /* Parse the rest of the client's headers. */
+   init_list(headers);
+   for (;;)
+   {
+      p = get_header(csp->client_iob);
+
+      if (p == NULL)
+      {
+         /* There are no additional headers to read. */
+         break;
+      }
+      enlist(headers, p);
+      freez(p);
+   }
+
+   if (JB_ERR_OK != get_destination_from_https_headers(headers, csp->http))
+   {
+      /*
+       * Our attempts to get the request destination
+       * elsewhere failed.
+       */
+      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER));
+      return JB_ERR_PARSE;
+   }
+
+#ifndef FEATURE_EXTENDED_HOST_PATTERNS
+   /* Split the domain we just got for pattern matching */
+   init_domain_components(csp->http);
+#endif
+
+   /*
+    * Determine the actions for this URL
+    */
+#ifdef FEATURE_TOGGLE
+   if (!(csp->flags & CSP_FLAG_TOGGLED_ON))
+   {
+      /* Most compatible set of actions (i.e. none) */
+      init_current_action(csp->action);
+   }
+   else
+#endif /* ndef FEATURE_TOGGLE */
+   {
+      get_url_actions(csp, csp->http);
+   }
+
+   enlist(csp->https_headers, csp->http->cmd);
+
+   /* Append the previously read headers */
+   err = list_append_list_unique(csp->https_headers, headers);
+   destroy_list(headers);
+   if (JB_ERR_OK != err)
+   {
+      /* XXX: Send error message */
+      return err;
+   }
+
+   /* XXX: Work around crash */
+   csp->error_message = NULL;
+
+   /* XXX: Why do this here? */
+   csp->http->ssl = 1;
+
+   err = sed_https(csp);
+   if (JB_ERR_OK != err)
+   {
+      ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+         (const unsigned char *)CHEADER, strlen(CHEADER));
+      log_error(LOG_LEVEL_ERROR, "Failed to parse client request from %s.",
+         csp->ip_addr_str);
+      log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0",
+         csp->ip_addr_str, csp->http->cmd);
+      return JB_ERR_PARSE;
+   }
+
+   log_error(LOG_LEVEL_HEADER, "Encrypted request processed");
+
+   return err;
+
+}
+#endif
+
+
 /*********************************************************************
  *
  * Function    :  handle_established_connection
@@ -2018,6 +2340,24 @@ static void handle_established_connection(struct client_state *csp)
    long len = 0; /* for buffer sizes (and negative error codes) */
    int buffer_and_filter_content = 0;
    unsigned int write_delay;
+#ifdef FEATURE_HTTPS_FILTERING
+   int ret = 0;
+   int use_ssl_tunnel = 0;
+   csp->dont_verify_certificate = 0;
+
+   /*
+    * Preset flags informing if SSL connections with server or client
+    * are opened or closed
+    */
+   csp->ssl_with_server_is_opened = 0;
+   csp->ssl_with_client_is_opened = 0;
+
+   if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER))
+   {
+      /* Pass encrypted content without filtering. */
+      use_ssl_tunnel = 1;
+   }
+#endif
 
    /* Skeleton for HTTP response, if we should intercept the request */
    struct http_response *rsp;
@@ -2116,66 +2456,127 @@ static void handle_established_connection(struct client_state *csp)
          }
          len = 0;
          /*
-          * XXX: should not jump around,
-          * chat() is complicated enough already.
+          * XXX: Should not jump around, handle_established_connection()
+          * is complicated enough already.
           */
          goto reading_done;
       }
 #endif  /* FEATURE_CONNECTION_KEEP_ALIVE */
 
-#ifdef HAVE_POLL
-      poll_fds[0].fd = csp->cfd;
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
-      if (!watch_client_socket)
+#ifdef FEATURE_HTTPS_FILTERING
+      /*
+       * Test if some data from client or destination server are pending
+       * on TLS/SSL. We must work with them preferably. TLS/SSL data can
+       * be pending because of maximal fragment size.
+       */
+      int read_ssl_server = 0;
+      int read_ssl_client = 0;
+
+      if (client_use_ssl(csp))
       {
-         /*
-          * Ignore incoming data, but still watch out
-          * for disconnects etc. These flags are always
-          * implied anyway but explicitly setting them
-          * doesn't hurt.
-          */
-         poll_fds[0].events = POLLERR|POLLHUP;
+         read_ssl_client = is_ssl_pending(&(csp->mbedtls_client_attr.ssl)) != 0;
       }
-      else
-#endif
+
+      if (server_use_ssl(csp))
       {
-         poll_fds[0].events = POLLIN;
+         read_ssl_server = is_ssl_pending(&(csp->mbedtls_server_attr.ssl)) != 0;
       }
-      poll_fds[1].fd = csp->server_connection.sfd;
-      poll_fds[1].events = POLLIN;
-      n = poll(poll_fds, 2, csp->config->socket_timeout * 1000);
+
+      if (!read_ssl_server && !read_ssl_client)
+#endif
+      {
+#ifdef HAVE_POLL
+         poll_fds[0].fd = csp->cfd;
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+         if (!watch_client_socket)
+         {
+            /*
+             * Ignore incoming data, but still watch out
+             * for disconnects etc. These flags are always
+             * implied anyway but explicitly setting them
+             * doesn't hurt.
+             */
+            poll_fds[0].events = POLLERR|POLLHUP;
+         }
+         else
+#endif
+         {
+            poll_fds[0].events = POLLIN;
+         }
+         poll_fds[1].fd = csp->server_connection.sfd;
+         poll_fds[1].events = POLLIN;
+         n = poll(poll_fds, 2, csp->config->socket_timeout * 1000);
 #else
-      timeout.tv_sec = csp->config->socket_timeout;
-      timeout.tv_usec = 0;
-      n = select((int)maxfd+1, &rfds, NULL, NULL, &timeout);
+         timeout.tv_sec = csp->config->socket_timeout;
+         timeout.tv_usec = 0;
+         n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout);
 #endif /* def HAVE_POLL */
 
-      if (n == 0)
-      {
-         log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s",
-            csp->config->socket_timeout, http->url);
-         if ((byte_count == 0) && (http->ssl == 0))
+         /*server or client not responding in timeout */
+         if (n == 0)
          {
-            send_crunch_response(csp, error_response(csp, "connection-timeout"));
+            log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s",
+               csp->config->socket_timeout, http->url);
+            if ((byte_count == 0) && (http->ssl == 0))
+            {
+               send_crunch_response(csp, error_response(csp, "connection-timeout"));
+            }
+            mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+            close_client_and_server_ssl_connections(csp);
+#endif
+            return;
+         }
+         else if (n < 0)
+         {
+#ifdef HAVE_POLL
+            log_error(LOG_LEVEL_ERROR, "poll() failed!: %E");
+#else
+            log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
+#endif
+            mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+            close_client_and_server_ssl_connections(csp);
+#endif
+            return;
          }
-         mark_server_socket_tainted(csp);
-         return;
       }
-      else if (n < 0)
+#ifdef FEATURE_HTTPS_FILTERING
+      else
       {
+         /* set FD if some data are pending on TLS/SSL connections */
+#ifndef HAVE_POLL
+         FD_ZERO(&rfds);
+#endif
+         if (read_ssl_client)
+         {
 #ifdef HAVE_POLL
-         log_error(LOG_LEVEL_ERROR, "poll() failed!: %E");
+            poll_fds[0].fd = csp->cfd;
+            poll_fds[0].events = POLLIN;
 #else
-         log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
+            FD_SET(csp->cfd, &rfds);
 #endif
-         mark_server_socket_tainted(csp);
-         return;
-      }
+            n++;
+         }
 
+         if (read_ssl_server)
+         {
+#ifdef HAVE_POLL
+            poll_fds[1].fd = csp->server_connection.sfd;
+            poll_fds[1].events = POLLIN;
+#else
+            FD_SET(csp->server_connection.sfd, &rfds);
+#endif
+            n++;
+         }
+      }
+#endif
       /*
        * This is the body of the browser's request,
        * just read and write it.
        *
+       * Receives data from browser and sends it to server
+       *
        * XXX: Make sure the client doesn't use pipelining
        * behind Privoxy's back.
        */
@@ -2240,38 +2641,76 @@ static void handle_established_connection(struct client_state *csp)
          assert(max_bytes_to_read <= csp->receive_buffer_size);
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
-         len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read);
-
-         if (len <= 0)
+#ifdef FEATURE_HTTPS_FILTERING
+         /*
+          * Reading data from standard or secured connection (HTTP/HTTPS)
+          */
+         if (client_use_ssl(csp))
          {
-            /* XXX: not sure if this is necessary. */
-            mark_server_socket_tainted(csp);
-            break; /* "game over, man" */
+            /*
+             * Receiving HTTP request from client over TLS/SSL and sending
+             * it to server over TLS/SSL.
+             */
+            len = ssl_recv_data(&(csp->mbedtls_client_attr.ssl),
+               (unsigned char *)csp->receive_buffer, (size_t)max_bytes_to_read);
+
+            if (len <= 0)
+            {
+               mark_server_socket_tainted(csp);
+               break;
+            }
+
+            ret = ssl_send_data(&(csp->mbedtls_server_attr.ssl),
+               (const unsigned char *)csp->receive_buffer, (size_t)len);
+
+            if (ret < 0)
+            {
+               log_error(LOG_LEVEL_ERROR,
+                  "Send request over TLS/SSL to: %s failed", http->host);
+               mark_server_socket_tainted(csp);
+               close_client_and_server_ssl_connections(csp);
+               return;
+            }
          }
+         else
+#endif /* def FEATURE_HTTPS_FILTERING */
+         {
+            len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read);
+
+            if (len <= 0)
+            {
+               /* XXX: not sure if this is necessary. */
+               mark_server_socket_tainted(csp);
+               break; /* "game over, man" */
+            }
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
-         if (csp->expected_client_content_length != 0)
-         {
-            assert(len <= max_bytes_to_read);
-            csp->expected_client_content_length -= (unsigned)len;
-            log_error(LOG_LEVEL_CONNECT,
-               "Expected client content length set to %llu "
-               "after reading %d bytes.",
-               csp->expected_client_content_length, len);
-            if (csp->expected_client_content_length == 0)
+            if (csp->expected_client_content_length != 0)
             {
+               assert(len <= max_bytes_to_read);
+               csp->expected_client_content_length -= (unsigned)len;
                log_error(LOG_LEVEL_CONNECT,
-                  "Done reading from the client.");
-               csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+                  "Expected client content length set to %llu "
+                  "after reading %d bytes.",
+                  csp->expected_client_content_length, len);
+               if (csp->expected_client_content_length == 0)
+               {
+                  log_error(LOG_LEVEL_CONNECT,
+                     "Done reading from the client.");
+                  csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+               }
             }
-         }
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
-         if (write_socket(csp->server_connection.sfd, csp->receive_buffer, (size_t)len))
-         {
-            log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
-            mark_server_socket_tainted(csp);
-            return;
+            if (write_socket(csp->server_connection.sfd, csp->receive_buffer, (size_t)len))
+            {
+               log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
+               mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
+               return;
+            }
          }
          continue;
       }
@@ -2304,18 +2743,39 @@ static void handle_established_connection(struct client_state *csp)
             log_error(LOG_LEVEL_CONNECT,
                "The server still wants to talk, but the client hung up on us.");
             mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+            close_client_and_server_ssl_connections(csp);
+#endif
             return;
 #endif /* def _WIN32 */
          }
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
-         len = read_socket(csp->server_connection.sfd, csp->receive_buffer, (int)csp->receive_buffer_size);
+#ifdef FEATURE_HTTPS_FILTERING
+         /*
+          * Reading data from standard or secured connection (HTTP/HTTPS)
+          */
+         if (server_use_ssl(csp))
+         {
+            len = ssl_recv_data(&(csp->mbedtls_server_attr.ssl),
+               (unsigned char *)csp->receive_buffer, csp->receive_buffer_size);
+         }
+         else
+#endif
+         {
+            len = read_socket(csp->server_connection.sfd, csp->receive_buffer,
+               (int)csp->receive_buffer_size);
+         }
 
          if (len < 0)
          {
             log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
 
-            if (http->ssl && (csp->fwd == NULL))
+            if ((http->ssl && (csp->fwd == NULL))
+#ifdef FEATURE_HTTPS_FILTERING
+               && use_ssl_tunnel
+#endif
+                )
             {
                /*
                 * Just hang up. We already confirmed the client's CONNECT
@@ -2338,6 +2798,9 @@ static void handle_established_connection(struct client_state *csp)
                log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. "
                   "Unable to tell the client about the problem.");
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
             /*
@@ -2403,7 +2866,11 @@ static void handle_established_connection(struct client_state *csp)
          if (len == 0)
          {
 
-            if (server_body || http->ssl)
+            if (server_body || (http->ssl
+#ifdef FEATURE_HTTPS_FILTERING
+                  && use_ssl_tunnel
+#endif
+               ))
             {
                /*
                 * If we have been buffering up the document,
@@ -2450,16 +2917,43 @@ static void handle_established_connection(struct client_state *csp)
                      log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header");
                   }
 
-                  if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay)
-                   || write_socket_delayed(csp->cfd,
-                      ((p != NULL) ? p : csp->iob->cur),
-                      (size_t)csp->content_length, write_delay))
+#ifdef FEATURE_HTTPS_FILTERING
+                  /*
+                   * Sending data with standard or secured connection (HTTP/HTTPS)
+                   */
+                  if (client_use_ssl(csp))
                   {
-                     log_error(LOG_LEVEL_ERROR, "write modified content to client failed: %E");
-                     freez(hdr);
-                     freez(p);
-                     mark_server_socket_tainted(csp);
-                     return;
+                     if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                            (const unsigned char *)hdr, strlen(hdr)) < 0)
+                        || (ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                              (const unsigned char *) ((p != NULL) ? p : csp->iob->cur),
+                              csp->content_length) < 0))
+                     {
+                        log_error(LOG_LEVEL_ERROR, "write modified content to "
+                           "client over TLS/SSL failed");
+                        freez(hdr);
+                        freez(p);
+                        mark_server_socket_tainted(csp);
+                        close_client_and_server_ssl_connections(csp);
+                        return;
+                     }
+                  }
+                  else
+#endif /* def FEATURE_HTTPS_FILTERING */
+                  {
+                     if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay)
+                      || write_socket_delayed(csp->cfd, ((p != NULL) ? p : csp->iob->cur),
+                         (size_t)csp->content_length, write_delay))
+                     {
+                        log_error(LOG_LEVEL_ERROR, "write modified content to client failed: %E");
+                        freez(hdr);
+                        freez(p);
+                        mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                        close_client_and_server_ssl_connections(csp);
+#endif
+                        return;
+                     }
                   }
 
                   freez(hdr);
@@ -2485,11 +2979,15 @@ static void handle_established_connection(struct client_state *csp)
          }
 
          /*
-          * If this is an SSL connection or we're in the body
-          * of the server document, just write it to the client,
-          * unless we need to buffer the body for later content-filtering
+          * If we're in the body of the server document, just write it to
+          * the client, unless we need to buffer the body for later
+          * content-filtering.
           */
-         if (server_body || http->ssl)
+         if (server_body || (http->ssl
+#ifdef FEATURE_HTTPS_FILTERING
+               && use_ssl_tunnel
+#endif
+            ))
          {
             if (buffer_and_filter_content)
             {
@@ -2517,20 +3015,51 @@ static void handle_established_connection(struct client_state *csp)
                      rsp = cgi_error_memory();
                      send_crunch_response(csp, rsp);
                      mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                     close_client_and_server_ssl_connections(csp);
+#endif
                      return;
                   }
-                  hdrlen = strlen(hdr);
-
-                  if (write_socket_delayed(csp->cfd, hdr, hdrlen, write_delay)
-                   || ((flushed = flush_iob(csp->cfd, csp->iob, write_delay)) < 0)
-                   || write_socket_delayed(csp->cfd, csp->receive_buffer,
-                         (size_t)len, write_delay))
+                  hdrlen = strlen(hdr);
+
+#ifdef FEATURE_HTTPS_FILTERING
+                  /*
+                   * Sending data with standard or secured connection (HTTP/HTTPS)
+                   */
+                  if (client_use_ssl(csp))
+                  {
+                     if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                            (const unsigned char *)hdr, hdrlen) < 0)
+                        || ((flushed = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl),
+                                csp->iob)) < 0)
+                        || (ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                              (const unsigned char *)csp->receive_buffer, (size_t)len) < 0))
+                     {
+                        log_error(LOG_LEVEL_CONNECT,
+                           "Flush header and buffers to client failed");
+                        freez(hdr);
+                        mark_server_socket_tainted(csp);
+                        close_client_and_server_ssl_connections(csp);
+                        return;
+                     }
+                  }
+                  else
+#endif /* def FEATURE_HTTPS_FILTERING */
                   {
-                     log_error(LOG_LEVEL_CONNECT,
-                        "Flush header and buffers to client failed: %E");
-                     freez(hdr);
-                     mark_server_socket_tainted(csp);
-                     return;
+                     if (write_socket_delayed(csp->cfd, hdr, hdrlen, write_delay)
+                      || ((flushed = flush_iob(csp->cfd, csp->iob, write_delay)) < 0)
+                      || write_socket_delayed(csp->cfd, csp->receive_buffer, (size_t)len,
+                            write_delay))
+                     {
+                        log_error(LOG_LEVEL_CONNECT,
+                           "Flush header and buffers to client failed: %E");
+                        freez(hdr);
+                        mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                        close_client_and_server_ssl_connections(csp);
+#endif
+                        return;
+                     }
                   }
 
                   /*
@@ -2546,12 +3075,36 @@ static void handle_established_connection(struct client_state *csp)
             }
             else
             {
-               if (write_socket_delayed(csp->cfd, csp->receive_buffer,
-                     (size_t)len, write_delay))
+#ifdef FEATURE_HTTPS_FILTERING
+               /*
+                * Sending data with standard or secured connection (HTTP/HTTPS)
+                */
+               if (client_use_ssl(csp))
                {
-                  log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
-                  mark_server_socket_tainted(csp);
-                  return;
+                  ret = ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     (const unsigned char *)csp->receive_buffer, (size_t)len);
+                  if (ret < 0)
+                  {
+                     log_error(LOG_LEVEL_ERROR,
+                        "Sending data to client failed");
+                     mark_server_socket_tainted(csp);
+                     close_client_and_server_ssl_connections(csp);
+                     return;
+                  }
+               }
+               else
+#endif /* def FEATURE_HTTPS_FILTERING */
+               {
+                  if (write_socket_delayed(csp->cfd, csp->receive_buffer,
+                        (size_t)len, write_delay))
+                  {
+                     log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
+                     mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                     close_client_and_server_ssl_connections(csp);
+#endif
+                     return;
+                  }
                }
             }
             byte_count += (unsigned long long)len;
@@ -2570,6 +3123,9 @@ static void handle_established_connection(struct client_state *csp)
                rsp = cgi_error_memory();
                send_crunch_response(csp, rsp);
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
 
@@ -2587,10 +3143,27 @@ static void handle_established_connection(struct client_state *csp)
                      "Applying the MS IIS5 hack didn't help.");
                   log_error(LOG_LEVEL_CLF,
                      "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-                  write_socket_delayed(csp->cfd,
-                     INVALID_SERVER_HEADERS_RESPONSE,
-                     strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+#ifdef FEATURE_HTTPS_FILTERING
+                  /*
+                   * Sending data with standard or secured connection (HTTP/HTTPS)
+                   */
+                  if (client_use_ssl(csp))
+                  {
+                     ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                        (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
+                        strlen(INVALID_SERVER_HEADERS_RESPONSE));
+                  }
+                  else
+#endif /* def FEATURE_HTTPS_FILTERING */
+                  {
+                     write_socket_delayed(csp->cfd,
+                        INVALID_SERVER_HEADERS_RESPONSE,
+                        strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+                  }
                   mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                  close_client_and_server_ssl_connections(csp);
+#endif
                   return;
                }
                else
@@ -2636,11 +3209,18 @@ static void handle_established_connection(struct client_state *csp)
                }
                free_http_request(http);
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
 
+            if (!csp->headers->first->str)
+            {
+               log_error(LOG_LEVEL_ERROR, "header search: csp->headers->first->str == NULL, assert will be called");
+            }
             assert(csp->headers->first->str);
-            assert(!http->ssl);
+
             if (strncmpic(csp->headers->first->str, "HTTP", 4) &&
                 strncmpic(csp->headers->first->str, "ICY", 3))
             {
@@ -2657,10 +3237,27 @@ static void handle_established_connection(struct client_state *csp)
                   csp->headers->first->str);
                log_error(LOG_LEVEL_CLF,
                   "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-               write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
-                  strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+#ifdef FEATURE_HTTPS_FILTERING
+               /*
+                * Sending data with standard or secured connection (HTTP/HTTPS)
+                */
+               if (client_use_ssl(csp))
+               {
+                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+               }
+               else
+#endif /* def FEATURE_HTTPS_FILTERING */
+               {
+                  write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+               }
                free_http_request(http);
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
 
@@ -2672,10 +3269,27 @@ static void handle_established_connection(struct client_state *csp)
             {
                log_error(LOG_LEVEL_CLF,
                   "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-               write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
-                  strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+#ifdef FEATURE_HTTPS_FILTERING
+               /*
+                * Sending data with standard or secured connection (HTTP/HTTPS)
+                */
+               if (client_use_ssl(csp))
+               {
+                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+               }
+               else
+#endif
+               {
+                  write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+               }
                free_http_request(http);
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
             hdr = list_to_text(csp->headers);
@@ -2710,39 +3324,66 @@ static void handle_established_connection(struct client_state *csp)
                 */
                freez(hdr);
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
+
             /* Buffer and pcrs filter this if appropriate. */
+            buffer_and_filter_content = content_requires_filtering(csp);
 
-            if (!http->ssl) /* We talk plaintext */
-            {
-               buffer_and_filter_content = content_requires_filtering(csp);
-            }
-            /*
-             * Only write if we're not buffering for content modification
-             */
             if (!buffer_and_filter_content)
             {
                /*
                 * Write the server's (modified) header to
                 * the client (along with anything else that
-                * may be in the buffer)
+                * may be in the buffer). Use standard or secured
+                * connection.
                 */
-
-               if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay)
-                  || ((len = flush_iob(csp->cfd, csp->iob, write_delay)) < 0))
+#ifdef FEATURE_HTTPS_FILTERING
+               if (client_use_ssl(csp))
                {
-                  log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
+                  if ((ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                          (const unsigned char *)hdr, strlen(hdr)) < 0)
+                     || (len = ssl_flush_socket(&(csp->mbedtls_client_attr.ssl),
+                            csp->iob) < 0))
+                  {
+                     log_error(LOG_LEVEL_CONNECT, "Write header to client failed");
 
-                  /*
-                   * The write failed, so don't bother mentioning it
-                   * to the client... it probably can't hear us anyway.
-                   */
-                  freez(hdr);
-                  mark_server_socket_tainted(csp);
-                  return;
+                     /*
+                      * The write failed, so don't bother mentioning it
+                      * to the client... it probably can't hear us anyway.
+                      */
+                     freez(hdr);
+                     mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                     close_client_and_server_ssl_connections(csp);
+#endif
+                     return;
+                  }
                }
-            }
+               else
+#endif /* def FEATURE_HTTPS_FILTERING */
+               {
+                  if (write_socket_delayed(csp->cfd, hdr, strlen(hdr), write_delay)
+                     || ((len = flush_iob(csp->cfd, csp->iob, write_delay)) < 0))
+                  {
+                     log_error(LOG_LEVEL_ERROR,
+                        "write header to client failed");
+                     /*
+                      * The write failed, so don't bother mentioning it
+                      * to the client... it probably can't hear us anyway.
+                      */
+                     freez(hdr);
+                     mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+                     close_client_and_server_ssl_connections(csp);
+#endif
+                     return;
+                  }
+               }
+                               }
 
             /* we're finished with the server's header */
 
@@ -2761,18 +3402,40 @@ static void handle_established_connection(struct client_state *csp)
                   "Applying the MS IIS5 hack didn't help.");
                log_error(LOG_LEVEL_CLF,
                   "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
-               write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
-                  strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+#ifdef FEATURE_HTTPS_FILTERING
+               /*
+                * Sending data with standard or secured connection (HTTP/HTTPS)
+                */
+               if (client_use_ssl(csp))
+               {
+                  ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+                     (const unsigned char *)INVALID_SERVER_HEADERS_RESPONSE,
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE));
+               }
+               else
+#endif /* def FEATURE_HTTPS_FILTERING */
+               {
+                  write_socket_delayed(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
+                     strlen(INVALID_SERVER_HEADERS_RESPONSE), write_delay);
+               }
                mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+               close_client_and_server_ssl_connections(csp);
+#endif
                return;
             }
          }
          continue;
       }
       mark_server_socket_tainted(csp);
+#ifdef FEATURE_HTTPS_FILTERING
+      close_client_and_server_ssl_connections(csp);
+#endif
       return; /* huh? we should never get here */
    }
-
+#ifdef FEATURE_HTTPS_FILTERING
+   close_client_and_server_ssl_connections(csp);
+#endif
    if (csp->content_length == 0)
    {
       /*
@@ -2830,6 +3493,9 @@ static void chat(struct client_state *csp)
    struct http_request *http;
    /* Skeleton for HTTP response, if we should intercept the request */
    struct http_response *rsp;
+#ifdef FEATURE_HTTPS_FILTERING
+   int use_ssl_tunnel = 0;
+#endif
 
    http = csp->http;
 
@@ -2851,43 +3517,79 @@ static void chat(struct client_state *csp)
       return;
    }
 
+#ifdef FEATURE_HTTPS_FILTERING
+   /*
+    * Setting flags to use old solution with SSL tunnel and to disable
+    * certificates verification.
+    */
+   if (csp->http->ssl && !(csp->action->flags & ACTION_ENABLE_HTTPS_FILTER))
+   {
+      use_ssl_tunnel = 1;
+   }
+
+   if (http->ssl && csp->action->flags & ACTION_IGNORE_CERTIFICATE_ERRORS)
+   {
+      csp->dont_verify_certificate = 1;
+   }
+#endif
+
    /*
     * build the http request to send to the server
     * we have to do one of the following:
     *
-    * create = use the original HTTP request to create a new
-    *          HTTP request that has either the path component
-    *          without the http://domainspec (w/path) or the
-    *          full orininal URL (w/url)
-    *          Note that the path and/or the HTTP version may
-    *          have been altered by now.
+    * create =    use the original HTTP request to create a new
+    *             HTTP request that has either the path component
+    *             without the http://domainspec (w/path) or the
+    *             full orininal URL (w/url)
+    *             Note that the path and/or the HTTP version may
+    *             have been altered by now.
     *
-    * connect = Open a socket to the host:port of the server
-    *           and short-circuit server and client socket.
+    * SSL proxy = Open a socket to the host:port of the server
+    *             and create TLS/SSL connection with server and
+    *             with client. Then behave like mediator between
+    *             client and server over TLS/SSL.
     *
-    * pass =  Pass the request unchanged if forwarding a CONNECT
-    *         request to a parent proxy. Note that we'll be sending
-    *         the CFAIL message ourselves if connecting to the parent
-    *         fails, but we won't send a CSUCCEED message if it works,
-    *         since that would result in a double message (ours and the
-    *         parent's). After sending the request to the parent, we simply
-    *         tunnel.
+    * SSL proxy = Pass the request unchanged if forwarding a CONNECT
+    *    with     request to a parent proxy. Note that we'll be sending
+    * forwarding  the CFAIL message ourselves if connecting to the parent
+    *             fails, but we won't send a CSUCCEED message if it works,
+    *             since that would result in a double message (ours and the
+    *             parent's). After sending the request to the parent, we
+    *             must parse answer and send it to client. If connection
+    *             with server is established, we do TLS/SSL proxy. Otherwise
+    *             we send parent response to client and close connections.
     *
     * here's the matrix:
     *                        SSL
     *                    0        1
     *                +--------+--------+
     *                |        |        |
-    *             0  | create | connect|
-    *                | w/path |        |
+    *             0  | create |   SSL  |
+    *                | w/path |  proxy |
     *  Forwarding    +--------+--------+
-    *                |        |        |
-    *             1  | create | pass   |
-    *                | w/url  |        |
+    *                |        |   SSL  |
+    *             1  | create |  proxy |
+    *                | w/url  |+forward|
     *                +--------+--------+
     *
     */
 
+#ifdef FEATURE_HTTPS_FILTERING
+   /*
+    * Presetting SSL client and server flags
+    */
+   if (http->ssl && !use_ssl_tunnel)
+   {
+      http->client_ssl = 1;
+      http->server_ssl = 1;
+   }
+   else
+   {
+      http->client_ssl = 0;
+      http->server_ssl = 0;
+   }
+#endif
+
    if (http->ssl && connect_port_is_forbidden(csp))
    {
       const char *acceptable_connect_ports =
@@ -2898,13 +3600,15 @@ static void chat(struct client_state *csp)
          csp->ip_addr_str, acceptable_connect_ports, csp->http->hostport);
       csp->action->flags |= ACTION_BLOCK;
       http->ssl = 0;
+#ifdef FEATURE_HTTPS_FILTERING
+      http->client_ssl = 0;
+      http->server_ssl = 0;
+#endif
    }
 
-   if (http->ssl == 0)
-   {
-      freez(csp->headers->first->str);
-      build_request_line(csp, fwd, &csp->headers->first->str);
-   }
+
+   freez(csp->headers->first->str);
+   build_request_line(csp, fwd, &csp->headers->first->str);
 
    /*
     * We have a request. Check if one of the crunchers wants it.
@@ -2963,7 +3667,63 @@ static void chat(struct client_state *csp)
          mark_connection_closed(&csp->server_connection);
       }
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+#ifdef FEATURE_HTTPS_FILTERING
+      if (http->ssl && !use_ssl_tunnel)
+      {
+         int ret;
+         /*
+          * Creating an SSL proxy. If forwarding is disabled, we must send
+          * CSUCCEED mesage to client. Then TLS/SSL connection with client
+          * is created.
+          */
+
+         if (fwd->forward_host == NULL)
+         {
+            /*
+             * We're lying to the client as the connection hasn't actually
+             * been established yet. We don't establish the connection until
+             * we have seen and parsed the encrypted client headers.
+             */
+            if (write_socket_delayed(csp->cfd, CSUCCEED,
+                  strlen(CSUCCEED), get_write_delay(csp)) != 0)
+            {
+               log_error(LOG_LEVEL_ERROR, "Sending SUCCEED to client failed");
+               return;
+            }
+         }
 
+         ret = create_client_ssl_connection(csp);
+         if (ret != 0)
+         {
+            log_error(LOG_LEVEL_ERROR,
+               "Can't open secure connection with client");
+            close_client_ssl_connection(csp); /* XXX: Is this needed? */
+            return;
+         }
+         if (JB_ERR_OK != process_encrypted_request(csp))
+         {
+            log_error(LOG_LEVEL_ERROR, "Failed to parse encrypted request.");
+            close_client_ssl_connection(csp);
+            return;
+         }
+         /*
+          * We have an encrypted request. Check if one of the crunchers now
+          * wants it (for example because the previously invisible path was
+          * required to match).
+          */
+         if (crunch_response_triggered(csp, crunchers_all))
+         {
+            /*
+             * Yes. The client got the crunch response and we're done here.
+             */
+            close_client_ssl_connection(csp);
+            return;
+         }
+      }
+#endif
+      /*
+       * Connecting to destination server
+       */
       csp->server_connection.sfd = forwarded_connect(fwd, http, csp);
 
       if (csp->server_connection.sfd == JB_INVALID_SOCKET)
@@ -3005,6 +3765,145 @@ static void chat(struct client_state *csp)
 
          return;
       }
+
+#ifdef FEATURE_HTTPS_FILTERING
+      /*
+       * Creating TLS/SSL connections with destination server or parent
+       * proxy. If forwarding is enabled, we must send client request to
+       * parent proxy and receive, parse and resend parent proxy answer.
+       */
+      if (http->ssl && !use_ssl_tunnel)
+      {
+         if (fwd->forward_host != NULL)
+         {
+            char server_response[BUFFER_SIZE];
+            int ret = 0;
+            int len = 0;
+            char *hdr = list_to_text(csp->headers);
+            memset(server_response, 0, sizeof(server_response));
+
+            if (hdr == NULL)
+            {
+               log_error(LOG_LEVEL_FATAL,
+                  "Out of memory parsing client header");
+            }
+            list_remove_all(csp->headers);
+
+            /*
+             * Sending client's CONNECT request to the parent proxy
+             */
+            ret = write_socket(csp->server_connection.sfd, hdr, strlen(hdr));
+
+            freez(hdr);
+
+            if (ret != 0)
+            {
+               log_error(LOG_LEVEL_CONNECT,
+                  "Sending request headers to: %s failed", http->hostport);
+               mark_server_socket_tainted(csp);
+               close_client_ssl_connection(csp);
+               return;
+            }
+
+            /* Waiting for parent proxy server response */
+            len = read_socket(csp->server_connection.sfd, server_response,
+               sizeof(server_response)-1);
+
+            if (len <= 0)
+            {
+               log_error(LOG_LEVEL_ERROR, "No response from parent proxy "
+                  "server on socket %d.", csp->server_connection.sfd);
+
+               rsp = error_response(csp, "no-server-data");
+               if (rsp)
+               {
+                  send_crunch_response(csp, rsp);
+               }
+               mark_server_socket_tainted(csp);
+               close_client_ssl_connection(csp);
+               return;
+            }
+
+            /*
+             * Test if connection with destination server was established
+             * successfully by parent proxy. Then we can send response to
+             * the client and continue or stop.
+             */
+            if (!tunnel_established_successfully(server_response, (unsigned int)len))
+            {
+               log_error(LOG_LEVEL_ERROR, "Forwarder hasn't established "
+                  "connection with destination server.");
+
+               write_socket(csp->cfd, server_response, (size_t)len);
+               mark_server_socket_tainted(csp);
+               close_client_ssl_connection(csp);
+               return;
+            }
+
+            /*
+             * Parent proxy has established connection with destination server.
+             * Now we must create TLS/SSL connection with parent proxy.
+             */
+            ret = create_server_ssl_connection(csp);
+
+            /*
+            * If TLS/SSL connection wasn't created and invalid certificate
+            * wasn't detected, we can interrupt this fuction. Otherwise, we
+            * must inform the client about invalid server certificate.
+            */
+            if (ret != 0
+               && (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED
+                  || csp->server_cert_verification_result == SSL_CERT_VALID))
+            {
+               rsp = error_response(csp, "connect-failed");
+               if (rsp)
+               {
+                  send_crunch_response(csp, rsp);
+               }
+               return;
+            }
+
+            /*
+             * TLS/SSL connection with parent proxy is established, we can
+             * inform client about success.
+             */
+            ret = write_socket(csp->cfd, server_response, (size_t)len);
+            if (ret != 0)
+            {
+               log_error(LOG_LEVEL_ERROR,
+                  "Sending parent proxy response to client failed");
+               mark_server_socket_tainted(csp);
+               close_client_ssl_connection(csp);
+               return;
+            }
+         }/* -END- if (fwd->forward_host != NULL) */
+         else
+         {
+            /*
+             * Parent proxy is not used, we can just create TLS/SSL connection
+             * with destination server
+             */
+            int ret = create_server_ssl_connection(csp);
+            /*
+             * If TLS/SSL connection wasn't created and invalid certificate
+             * wasn't detected, we can interrupt this function. Otherwise, we
+             * must inform client about invalid server certificate.
+             */
+            if (ret != 0
+               && (csp->server_cert_verification_result == SSL_CERT_NOT_VERIFIED
+                  || csp->server_cert_verification_result == SSL_CERT_VALID))
+            {
+               rsp = error_response(csp, "connect-failed");
+               if (rsp)
+               {
+                  send_crunch_response(csp, rsp);
+               }
+               return;
+            }
+         }
+      }/* -END- if (http->ssl) */
+#endif /* def FEATURE_HTTPS_FILTERING */
+
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
       save_connection_destination(csp->server_connection.sfd,
          http, fwd, &csp->server_connection);
@@ -3020,7 +3919,11 @@ static void chat(struct client_state *csp)
       /* Client headers have been sent optimistically */
       assert(csp->headers->last == NULL);
    }
-   else if (fwd->forward_host || (http->ssl == 0))
+   else if (http->ssl == 0 || (fwd->forward_host
+#ifdef FEATURE_HTTPS_FILTERING
+         && use_ssl_tunnel
+#endif
+           ))
    {
       if (send_http_request(csp))
       {
@@ -3035,18 +3938,51 @@ static void chat(struct client_state *csp)
    else
    {
       /*
-       * We're running an SSL tunnel and we're not forwarding,
-       * so just ditch the client headers, send the "connect succeeded"
-       * message to the client, flush the rest, and get out of the way.
+       * Using old solution with SSL tunnel or new solution with SSL proxy
        */
       list_remove_all(csp->headers);
-      if (write_socket_delayed(csp->cfd, CSUCCEED,
-            strlen(CSUCCEED), get_write_delay(csp)))
+#ifdef FEATURE_HTTPS_FILTERING
+      if (use_ssl_tunnel)
+#endif
       {
-         return;
+         /*
+         * We're running an SSL tunnel and we're not forwarding,
+         * so just ditch the client headers, send the "connect succeeded"
+         * message to the client, flush the rest, and get out of the way.
+         */
+         if (write_socket_delayed(csp->cfd, CSUCCEED,
+               strlen(CSUCCEED), get_write_delay(csp)))
+         {
+            return;
+         }
+      }
+#ifdef FEATURE_HTTPS_FILTERING
+      else
+      {
+         /*
+          * If server certificate is invalid, we must inform client and then
+          * close connection with client.
+          */
+         if (csp->server_cert_verification_result != SSL_CERT_VALID)
+         {
+            ssl_send_certificate_error(csp);
+            close_client_and_server_ssl_connections(csp);
+            return;
+         }
+         if (send_https_request(csp))
+         {
+            rsp = error_response(csp, "connect-failed");
+            if (rsp)
+            {
+               send_crunch_response(csp, rsp); /* XXX: use ssl*/
+            }
+            close_client_and_server_ssl_connections(csp);
+            return;
+         }
       }
+#endif /* def FEATURE_HTTPS_FILTERING */
       clear_iob(csp->client_iob);
-   }
+   }/* -END- else ... if (http->ssl == 1) */
 
    log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport);
 
@@ -3582,6 +4518,19 @@ static void initialize_mutexes(void)
    /*
     * Prepare global mutex semaphores
     */
+
+#ifdef LIMIT_MUTEX_NUMBER
+   int i = 0;
+   for (i = 0; i < 32; i++)
+#else
+   int i = 0;
+   for (i = 0; i < 65536; i++)
+#endif /* LIMIT_MUTEX_NUMBER */
+   {
+      privoxy_mutex_init(&(certificates_mutexes[i]));
+   }
+   privoxy_mutex_init(&rng_mutex);
+
    privoxy_mutex_init(&log_mutex);
    privoxy_mutex_init(&log_init_mutex);
    privoxy_mutex_init(&connection_reuse_mutex);
@@ -4617,7 +5566,15 @@ static void listen_loop(void)
 
    /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */
 
+#ifdef FEATURE_HTTPS_FILTERING
    /* Clean up.  Aim: free all memory (no leaks) */
+   if (rng_seeded == 1)
+   {
+      mbedtls_ctr_drbg_free(&ctr_drbg);
+      mbedtls_entropy_free(&entropy);
+   }
+#endif
+
 #ifdef FEATURE_GRACEFUL_TERMINATION
 
    log_error(LOG_LEVEL_ERROR, "Graceful termination requested");
diff --git a/jcc.h b/jcc.h
index 866c2a7..2df0755 100644 (file)
--- a/jcc.h
+++ b/jcc.h
@@ -102,6 +102,13 @@ extern privoxy_mutex_t resolver_mutex;
 extern privoxy_mutex_t rand_mutex;
 #endif /* ndef HAVE_RANDOM */
 
+#ifdef LIMIT_MUTEX_NUMBER
+   extern privoxy_mutex_t certificates_mutexes[32];
+#else
+   extern privoxy_mutex_t certificates_mutexes[65536];
+#endif /* LIMIT_MUTEX_NUMBER */
+extern privoxy_mutex_t rng_mutex;
+
 #endif /* FEATURE_PTHREAD */
 
 /* Functions */
index 256dccf..73fa6e3 100644 (file)
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -135,6 +135,11 @@ static struct file_list *current_configfile = NULL;
 #define hash_admin_address               4112573064U /* "admin-address" */
 #define hash_allow_cgi_request_crunching  258915987U /* "allow-cgi-request-crunching" */
 #define hash_buffer_limit                1881726070U /* "buffer-limit */
+#define hash_ca_cert_file                1622923720U /* "ca-cert-file" */
+#define hash_ca_directory                1623615670U /* "ca-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_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" */
@@ -181,6 +186,7 @@ static struct file_list *current_configfile = NULL;
 #define hash_trust_info_url               430331967U /* "trust-info-url" */
 #define hash_trust_x_forwarded_for       2971537414U /* "trust-x-forwarded-for" */
 #define hash_trusted_cgi_referrer        4270883427U /* "trusted-cgi-referrer" */
+#define hash_trusted_cas_file            2679803024U /* "trusted-cas-files" */
 #define hash_trustfile                     56494766U /* "trustfile" */
 #define hash_usermanual                  1416668518U /* "user-manual" */
 #define hash_activity_animation          1817904738U /* "activity-animation" */
@@ -272,6 +278,15 @@ static void unload_configfile (void * data)
    freez(config->usermanual);
    freez(config->trusted_cgi_referrer);
 
+#ifdef FEATURE_HTTPS_FILTERING
+   freez(config->ca_password);
+   freez(config->ca_directory);
+   freez(config->ca_cert_file);
+   freez(config->ca_key_file);
+   freez(config->certificate_directory);
+   freez(config->trusted_cas_file);
+#endif
+
 #ifdef FEATURE_TRUST
    freez(config->trustfile);
    list_remove_all(config->trust_info);
@@ -568,7 +583,14 @@ struct configuration_spec * load_config(void)
    struct file_list *fs;
    unsigned long linenum = 0;
    int i;
-   char *logfile = NULL;
+   char *logfile          = NULL;
+#ifdef FEATURE_HTTPS_FILTERING
+   char *ca_cert_file     = NULL;
+   char *ca_key_file      = NULL;
+   char *ca_directory     = NULL;
+   char *trusted_cas_file = NULL;
+   char *certificate_directory = NULL;
+#endif
 
    if (!check_file_changed(current_configfile, configfile, &fs))
    {
@@ -613,6 +635,15 @@ struct configuration_spec * load_config(void)
    config->usermanual                = strdup_or_die(USER_MANUAL_URL);
    config->proxy_args                = strdup_or_die("");
    config->forwarded_connect_retries = 0;
+#ifdef FEATURE_HTTPS_FILTERING
+   config->ca_password               = strdup("");
+   ca_cert_file                      = strdup("cacert.crt");
+   ca_key_file                       = strdup("cakey.pem");
+   ca_directory                      = strdup("./CA");
+   trusted_cas_file                  = strdup("trustedCAs.pem");
+   certificate_directory             = strdup("./certs");
+#endif
+
 #ifdef FEATURE_CLIENT_TAGS
    config->client_tag_lifetime       = 60;
 #endif
@@ -1702,6 +1733,84 @@ struct configuration_spec * load_config(void)
             config->usermanual = strdup_or_die(arg);
             break;
 
+#ifdef FEATURE_HTTPS_FILTERING
+/* *************************************************************************
+ * ca private key file password
+ * *************************************************************************/
+         case hash_ca_password:
+            freez(config->ca_password);
+            config->ca_password = strdup(arg);
+            break;
+
+/* *************************************************************************
+ * ca-directory directory
+ * *************************************************************************/
+         case hash_ca_directory:
+            ca_directory = make_path(NULL, arg);
+
+            if (NULL == ca_directory)
+            {
+               log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca dir path");
+            }
+
+            break;
+
+/* *************************************************************************
+ * ca cert file ca-cert-file
+ * In ca dir by default
+ * *************************************************************************/
+         case hash_ca_cert_file:
+            ca_cert_file = make_path(config->ca_directory, arg);
+
+            if (NULL == ca_cert_file)
+            {
+               log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca certificate file path");
+            }
+
+            break;
+
+/* *************************************************************************
+ * ca key file ca-key-file
+ * In ca dir by default
+ * *************************************************************************/
+         case hash_ca_key_file:
+            ca_key_file = make_path(config->ca_directory, arg);
+
+            if (NULL == ca_key_file)
+            {
+               log_error(LOG_LEVEL_FATAL, "Out of memory while creating ca key file path");
+            }
+
+            break;
+
+/* *************************************************************************
+ * certificate-directory directory
+ * *************************************************************************/
+         case hash_certificate_directory:
+            certificate_directory = make_path(NULL, arg);
+
+            if (NULL == certificate_directory)
+            {
+               log_error(LOG_LEVEL_FATAL,
+                  "Out of memory while creating certificate directory path");
+            }
+
+            break;
+
+/* *************************************************************************
+ * trusted CAs file name trusted-cas-file
+ * *************************************************************************/
+         case hash_trusted_cas_file:
+            trusted_cas_file = make_path(config->ca_directory, arg);
+
+            if (NULL == trusted_cas_file)
+            {
+               log_error(LOG_LEVEL_FATAL, "Out of memory while creating trusted CAs file path");
+            }
+
+            break;
+#endif
+
 /* *************************************************************************
  * Win32 Console options:
  * *************************************************************************/
@@ -1877,6 +1986,30 @@ struct configuration_spec * load_config(void)
       }
    }
 
+#ifdef FEATURE_HTTPS_FILTERING
+   /*
+    * Setting SSL parameters from loaded values into structures
+    */
+   freez(config->ca_directory);
+   config->ca_directory = make_path(NULL, ca_directory);
+   freez(ca_directory);
+
+   freez(config->ca_cert_file);
+   config->ca_cert_file = make_path(config->ca_directory, ca_cert_file);
+   freez(ca_cert_file);
+
+   freez(config->ca_key_file);
+   config->ca_key_file  = make_path(config->ca_directory, ca_key_file);
+   freez(ca_key_file);
+
+   freez(config->trusted_cas_file);
+   config->trusted_cas_file = make_path(config->ca_directory, trusted_cas_file);
+   freez(trusted_cas_file);
+
+   freez(config->certificate_directory);
+   config->certificate_directory = make_path(NULL, certificate_directory);
+   freez(certificate_directory);
+#endif
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    if (config->default_server_timeout > config->keep_alive_timeout)
    {
index 699ae7c..e48ae25 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -1185,6 +1185,46 @@ jb_err sed(struct client_state *csp, int filter_server_headers)
 }
 
 
+#ifdef FEATURE_HTTPS_FILTERING
+/*********************************************************************
+ *
+ * Function    :  sed_https
+ *
+ * Description :  add, delete or modify lines in the HTTPS client
+ *                header streams. Wrapper around sed().
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  JB_ERR_OK in case off success, or
+ *                JB_ERR_MEMORY on some out-of-memory errors, or
+ *                JB_ERR_PARSE in case of fatal parse errors.
+ *
+ *********************************************************************/
+jb_err sed_https(struct client_state *csp)
+{
+   jb_err err;
+   struct list headers;
+
+   /*
+    * Temporarly replace csp->headers with csp->https_headers
+    * to trick sed() into filtering the https headers.
+    */
+   headers.first = csp->headers->first;
+   headers.last  = csp->headers->last;
+   csp->headers->first = csp->https_headers->first;
+   csp->headers->last  = csp->https_headers->last;
+
+   err = sed(csp, FILTER_CLIENT_HEADERS);
+
+   csp->headers->first = headers.first;
+   csp->headers->last  = headers.last;
+
+   return err;
+}
+#endif /* def FEATURE_HTTPS_FILTERING */
+
+
 /*********************************************************************
  *
  * Function    :  update_server_headers
@@ -4429,8 +4469,6 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ
    char *p;
    char *host;
 
-   assert(!http->ssl);
-
    host = get_header_value(headers, "Host:");
 
    if (NULL == host)
@@ -4494,6 +4532,88 @@ jb_err get_destination_from_headers(const struct list *headers, struct http_requ
 }
 
 
+#ifdef FEATURE_HTTPS_FILTERING
+/*********************************************************************
+ *
+ * Function    :  get_destination_from_https_headers
+ *
+ * Description :  Parse the previously encrypted "Host:" header to
+ *                get the request's destination.
+ *
+ * Parameters  :
+ *          1  :  headers = List of headers (one of them hopefully being
+ *                the "Host:" header)
+ *          2  :  http = storage for the result (host, port and hostport).
+ *
+ * Returns     :  JB_ERR_MEMORY (or terminates) in case of memory problems,
+ *                JB_ERR_PARSE if the host header couldn't be found,
+ *                JB_ERR_OK otherwise.
+ *
+ *********************************************************************/
+jb_err get_destination_from_https_headers(const struct list *headers, struct http_request *http)
+{
+   char *q;
+   char *p;
+   char *host;
+
+   host = get_header_value(headers, "Host:");
+
+   if (NULL == host)
+   {
+      log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found.");
+      return JB_ERR_PARSE;
+   }
+
+   p = strdup_or_die(host);
+   chomp(p);
+   q = strdup_or_die(p);
+
+   freez(http->hostport);
+   http->hostport = p;
+   freez(http->host);
+   http->host = q;
+   q = strchr(http->host, ':');
+   if (q != NULL)
+   {
+      /* Terminate hostname and evaluate port string */
+      *q++ = '\0';
+      http->port = atoi(q);
+   }
+   else
+   {
+      http->port = 443;
+   }
+
+   /* Rebuild request URL */
+   freez(http->url);
+   http->url = strdup_or_die(http->path);
+
+   log_error(LOG_LEVEL_HEADER,
+      "Destination extracted from \"Host\" header. New request URL: %s",
+      http->url);
+
+   /*
+    * Regenerate request line in "proxy format"
+    * to make rewrites more convenient.
+    */
+   assert(http->cmd != NULL);
+   freez(http->cmd);
+   http->cmd = strdup_or_die(http->gpc);
+   string_append(&http->cmd, " ");
+   string_append(&http->cmd, http->url);
+   string_append(&http->cmd, " ");
+   string_append(&http->cmd, http->ver);
+   if (http->cmd == NULL)
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   return JB_ERR_OK;
+
+}
+#endif /* def FEATURE_HTTPS_FILTERING */
+
+
 /*********************************************************************
  *
  * Function    :  create_forged_referrer
index d4cfc1c..4fa8aae 100644 (file)
--- a/parsers.h
+++ b/parsers.h
@@ -56,9 +56,15 @@ extern jb_err decompress_iob(struct client_state *csp);
 extern char *get_header(struct iob *iob);
 extern char *get_header_value(const struct list *header_list, const char *header_name);
 extern jb_err sed(struct client_state *csp, int filter_server_headers);
+#ifdef FEATURE_HTTPS_FILTERING
+extern jb_err sed_https(struct client_state *csp);
+#endif
 extern jb_err update_server_headers(struct client_state *csp);
 extern void get_http_time(int time_offset, char *buf, size_t buffer_size);
 extern jb_err get_destination_from_headers(const struct list *headers, struct http_request *http);
+#ifdef FEATURE_HTTPS_FILTERING
+extern jb_err get_destination_from_https_headers(const struct list *headers, struct http_request *http);
+#endif
 extern unsigned long long get_expected_content_length(struct list *headers);
 extern jb_err client_transfer_encoding(struct client_state *csp, char **header);
 
index eed9f87..20f693a 100644 (file)
--- a/project.h
+++ b/project.h
 /* Needed for pcre choice */
 #include "config.h"
 
+#ifdef FEATURE_HTTPS_FILTERING
+#ifdef FEATURE_PTHREAD
+#  include <pthread.h>
+   typedef pthread_mutex_t privoxy_mutex_t;
+#else
+#  ifdef _WIN32
+#     include <windows.h>
+#  endif
+   typedef CRITICAL_SECTION privoxy_mutex_t;
+#endif
+
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
+
+/*
+* Macros for SSL structures
+*/
+#define CERT_INFO_BUF_SIZE         4096
+#define CERT_FILE_BUF_SIZE         16384
+#define ISSUER_NAME_BUF_SIZE       2048
+#define HASH_OF_HOST_BUF_SIZE      16
+#endif
+
 /* Need for struct sockaddr_storage */
 #ifdef HAVE_RFC2553
 #  ifndef _WIN32
@@ -259,6 +287,23 @@ struct map
    struct map_entry *last;
 };
 
+#ifdef FEATURE_HTTPS_FILTERING
+/*
+ * Struct of attributes necessary for TLS/SSL connection
+ */
+typedef struct {
+   mbedtls_ssl_context      ssl;
+   mbedtls_ssl_config       conf;
+   mbedtls_net_context      socket_fd;
+   mbedtls_x509_crt         server_cert;
+   mbedtls_x509_crt         ca_cert;
+   mbedtls_pk_context       prim_key;
+
+   #if defined(MBEDTLS_SSL_CACHE_C)
+      mbedtls_ssl_cache_context cache;
+   #endif
+} mbedtls_connection_attr;
+#endif
 
 /**
  * A HTTP request.  This includes the method (GET, POST) and
@@ -291,8 +336,55 @@ struct http_request
    char **dvec;    /**< List of pointers to the strings in dbuffer.       */
    int    dcount;  /**< How many parts to this domain? (length of dvec)   */
 #endif /* ndef FEATURE_EXTENDED_HOST_PATTERNS */
+
+#ifdef FEATURE_HTTPS_FILTERING
+   int client_ssl;                                                  /**< Flag if we should comunicate with slient over ssl   */
+   int server_ssl;                                                  /**< Flag if we should comunicate with server over ssl   */
+   unsigned char hash_of_host_hex[(HASH_OF_HOST_BUF_SIZE * 2) + 1]; /**< chars for hash in hex string and one for '\0'       */
+   unsigned char hash_of_host[HASH_OF_HOST_BUF_SIZE+1];             /**< chars for bytes of hash and one for '\0'            */
+#endif
 };
 
+
+#ifdef FEATURE_HTTPS_FILTERING
+/*
+ * Properties of cert for generating
+ */
+typedef struct{
+   char       *issuer_crt;                         /* filename of the issuer certificate       */
+   char       *subject_key;                        /* filename of the subject key file         */
+   char       *issuer_key;                         /* filename of the issuer key file          */
+   const char *subject_pwd;                        /* password for the subject key file        */
+   const char *issuer_pwd;                         /* password for the issuer key file         */
+   char       *output_file;                        /* where to store the constructed key file  */
+   const char *subject_name;                       /* subject name for certificate             */
+   char       issuer_name[ISSUER_NAME_BUF_SIZE];   /* issuer name for certificate              */
+   const char *not_before;                         /* validity period not before               */
+   const char *not_after;                          /* validity period not after                */
+   const char *serial;                             /* serial number string                     */
+   int        is_ca;                               /* is a CA certificate                      */
+   int        max_pathlen;                         /* maximum CA path length                   */
+} cert_options;
+
+/*
+ * Properties of key for generating
+ */
+typedef struct{
+   mbedtls_pk_type_t type;       /* type of key to generate    */
+   int  rsa_keysize;             /* length of key in bits      */
+   char *key_file_path;          /* filename of the key file   */
+} key_options;
+
+/*
+ * Struct for linked list containing certificates
+ */
+typedef struct certs_chain {
+   char text_buf[CERT_INFO_BUF_SIZE];    /* text info about properties of certificate               */
+   char file_buf[CERT_FILE_BUF_SIZE];    /* buffer for whole certificate - format to save in file   */
+   struct certs_chain *next;             /* next certificate in chain of trust                      */
+}certs_chain_t;
+#endif
+
 /**
  * Reasons for generating a http_response instead of delivering
  * the requested resource. Mostly ordered the way they are checked
@@ -503,7 +595,10 @@ struct iob
 #define ACTION_LIMIT_COOKIE_LIFETIME                 0x08000000UL
 /** Action bitmap: Delay writes */
 #define ACTION_DELAY_RESPONSE                        0x10000000UL
-
+/** Action bitmap: Turn https filtering on */
+#define ACTION_ENABLE_HTTPS_FILTER                   0x20000000UL
+/** Action bitmap: Turn certificates verification off */
+#define ACTION_IGNORE_CERTIFICATE_ERRORS             0x40000000UL
 
 /** Action string index: How to deanimate GIFs */
 #define ACTION_STRING_DEANIMATE             0
@@ -948,6 +1043,11 @@ struct client_state
    /* XXX: should be renamed to server_iob */
    struct iob iob[1];
 
+#ifdef FEATURE_HTTPS_FILTERING
+   mbedtls_connection_attr  mbedtls_server_attr; /* attributes for connection to server */
+   mbedtls_connection_attr  mbedtls_client_attr; /* attributes for connection to client */
+#endif
+
    /** An I/O buffer used for buffering data read from the client */
    struct iob client_iob[1];
 
@@ -960,6 +1060,11 @@ struct client_state
    /** List of all headers for this request */
    struct list headers[1];
 
+#ifdef FEATURE_HTTPS_FILTERING
+   /** List of all encrypted headers for this request */
+   struct list https_headers[1];
+#endif
+
    /** List of all tags that apply to this request */
    struct list tags[1];
 
@@ -1010,6 +1115,28 @@ struct client_state
     * or NULL. Currently only used for socks errors.
     */
    char *error_message;
+
+#ifdef FEATURE_HTTPS_FILTERING
+   /* Result of server certificate verification */
+   uint32_t server_cert_verification_result;
+
+   /* Flag for certificate validity checking */
+   int dont_verify_certificate;
+
+   /*
+    * Flags if SSL connection with server or client is opened.
+    * Thanks to this flags, we can call function to close both connections
+    * and we don't have to care about more details.
+    */
+   int ssl_with_server_is_opened;
+   int ssl_with_client_is_opened;
+
+   /*
+    * Server certificate chain of trust including strings with certificates
+    * informations and string with whole certificate file
+    */
+   struct certs_chain server_certs_chain;
+#endif
 };
 
 /**
@@ -1433,6 +1560,26 @@ struct configuration_spec
 
    /** Nonzero if we need to bind() to the new port. */
    int need_bind;
+
+#ifdef FEATURE_HTTPS_FILTERING
+   /** Password for proxy ca file **/
+   char * ca_password;
+
+   /** Directory with files of ca **/
+   char *ca_directory;
+
+   /** Filename of ca certificate **/
+   char * ca_cert_file;
+
+   /** Filename of ca key **/
+   char * ca_key_file;
+
+   /** Directory for saving certificates and keys for each webpage **/
+   char *certificate_directory;
+
+   /** Filename of trusted CAs certificates **/
+   char * trusted_cas_file;
+#endif
 };
 
 /** Calculates the number of elements in an array, using sizeof. */
diff --git a/ssl.c b/ssl.c
new file mode 100644 (file)
index 0000000..0a45564
--- /dev/null
+++ b/ssl.c
@@ -0,0 +1,2069 @@
+/*********************************************************************
+*
+* File        :  $Source: /cvsroot/ijbswa/current/ssl.c,v $
+*
+* 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 (C) 2018-2019 by Fabian Keil <fk@fabiankeil.de>
+*
+*                This program is free software; you can redistribute it
+*                and/or modify it under the terms of the GNU General
+*                Public License as published by the Free Software
+*                Foundation; either version 2 of the License, or (at
+*                your option) any later version.
+*
+*                This program is distributed in the hope that it will
+*                be useful, but WITHOUT ANY WARRANTY; without even the
+*                implied warranty of MERCHANTABILITY or FITNESS FOR A
+*                PARTICULAR PURPOSE.  See the GNU General Public
+*                License for more details.
+*
+*                The GNU General Public License should be included with
+*                this file.  If not, you can view it at
+*                http://www.gnu.org/copyleft/gpl.html
+*                or write to the Free Software Foundation, Inc., 59
+*                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*
+*********************************************************************/
+
+#include <string.h>
+#include <unistd.h>
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#  include "mbedtls/config.h"
+#else
+#  include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "mbedtls/md5.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/error.h"
+
+#include "project.h"
+#include "miscutil.h"
+#include "errlog.h"
+#include "jcc.h"
+#include "config.h"
+#include "ssl.h"
+
+
+/*
+ * Macros for searching begin and end of certificates.
+ * Necessary to convert structure mbedtls_x509_crt to crt file.
+ */
+#define PEM_BEGIN_CRT     "-----BEGIN CERTIFICATE-----\n"
+#define PEM_END_CRT       "-----END CERTIFICATE-----\n"
+
+/*
+ * Macros for ssl.c
+ */
+#define ERROR_BUF_SIZE                   1024              /* Size of buffer for error messages */
+#define CERTIFICATE_BUF_SIZE             16384             /* Size of buffer to save certificate. Value 4096 is mbedtls library buffer size for certificate in DER form */
+#define PRIVATE_KEY_BUF_SIZE             16000             /* Size of buffer to save private key. Value 16000 is taken from mbed TLS library examples. */
+#define RSA_KEY_PUBLIC_EXPONENT          65537             /* Public exponent for RSA private key generating */
+#define RSA_KEYSIZE                      2048              /* Size of generated RSA keys */
+#define GENERATED_CERT_VALID_FROM        "20100101000000"  /* Date and time, which will be set in generated certificates as parameter valid from */
+#define GENERATED_CERT_VALID_TO          "20401231235959"  /* Date and time, which will be setted in generated certificates as parameter valid to */
+#define CERT_SIGNATURE_ALGORITHM         MBEDTLS_MD_SHA256 /* The MD algorithm to use for the signature */
+#define CERT_SERIAL_NUM_LENGTH           4                 /* Bytes of hash to be used for creating serial number of certificate. Min=2 and max=16 */
+#define LIMIT_MUTEX_NUMBER                                 /* If this macro is defined, mutexes count for generating private keys is changed from 65536 to 32 */
+#define INVALID_CERT_INFO_BUF_SIZE       2048              /* Size of buffer for message with information about reason of certificate invalidity. Data after the end of buffer will not be saved */
+#define CERT_PARAM_COMMON_NAME           "CN="
+#define CERT_PARAM_ORGANIZATION          ",O="
+#define CERT_PARAM_ORG_UNIT              ",OU="
+#define CERT_PARAM_COUNTRY               ",C=CZ"
+#define KEY_FILE_TYPE                    ".pem"
+#define CERT_FILE_TYPE                   ".crt"
+#define CERT_SUBJECT_PASSWORD            ""
+#define CERT_INFO_PREFIX                 ""
+
+
+extern int generate_webpage_certificate(struct client_state * csp);
+static char * make_certs_path(const char * conf_dir, const char * file_name, const char * suffix);
+static int file_exists(const char * path);
+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_certificate_chain(struct client_state *csp);
+static unsigned int get_certificate_mutex_id(struct client_state *csp);
+static unsigned long  get_certificate_serial(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);
+
+/*********************************************************************
+ *
+ * Function    :  client_use_ssl
+ *
+ * Description :  Tests if client in current client state structure
+ *                should use SSL connection or standard connection.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  If client should use TLS/SSL connection, 1 is returned.
+ *                Otherwise 0 is returned.
+ *
+ *********************************************************************/
+extern int client_use_ssl(const struct client_state *csp)
+{
+   return csp->http->client_ssl;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  server_use_ssl
+ *
+ * Description :  Tests if server in current client state structure
+ *                should use SSL connection or standard connection.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  If server should use TLS/SSL connection, 1 is returned.
+ *                Otherwise 0 is returned.
+ *
+ *********************************************************************/
+extern int server_use_ssl(const struct client_state *csp)
+{
+   return csp->http->server_ssl;
+}
+
+
+/*********************************************************************
+*
+* Function    :  is_ssl_pending
+*
+* Description :  Tests if there are some waitting data on ssl connection
+*
+* Parameters  :
+*          1  :  ssl = SSL context to test
+*
+* Returns     :   0 => No data are pending
+*                >0 => Pending data length
+*
+*********************************************************************/
+extern size_t is_ssl_pending(mbedtls_ssl_context *ssl)
+{
+   if (ssl == NULL)
+   {
+      return 0;
+   }
+
+   return mbedtls_ssl_get_bytes_avail(ssl);
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ssl_send_data
+ *
+ * Description :  Sends the content of buf (for n bytes) to given SSL
+ *                connection context.
+ *
+ * Parameters  :
+ *          1  :  ssl = SSL context to send data to
+ *          2  :  buf = Pointer to data to be sent
+ *          3  :  len = Length of data to be sent to the SSL context
+ *
+ * Returns     :  Length of sent data or negative value on error.
+ *
+ *********************************************************************/
+extern int ssl_send_data(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len)
+{
+   int ret = 0;
+   size_t max_fragment_size = 0;  /* Maximal length of data in one SSL fragment*/
+   int send_len             = 0;  /* length of one data part to send */
+   int pos                  = 0;  /* Position of unsent part in buffer */
+
+   if (len == 0)
+   {
+      return 0;
+   }
+
+   /* Getting maximal length of data sent in one fragment */
+   max_fragment_size = mbedtls_ssl_get_max_frag_len(ssl);
+
+   /*
+    * Whole buffer must be sent in many fragments, because each fragment
+    * has its maximal length.
+    */
+   while (pos < len)
+   {
+      /* Compute length of data, that can be send in next fragment */
+      if ((pos + (int)max_fragment_size) > len)
+      {
+         send_len = (int)len - pos;
+      }
+      else
+      {
+         send_len = (int)max_fragment_size;
+      }
+
+      /*
+       * Sending one part of the buffer
+       */
+      while ((ret = mbedtls_ssl_write(ssl,
+         (const unsigned char *)(buf + pos),
+         (size_t)send_len)) < 0)
+      {
+         if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+             ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+         {
+            char err_buf[ERROR_BUF_SIZE];
+
+            memset(err_buf, 0, sizeof(err_buf));
+            mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+            log_error(LOG_LEVEL_ERROR,
+               "Sending data over TLS/SSL failed: %s", err_buf);
+            return -1;
+         }
+      }
+      /* Adding count of sent bytes to position in buffer */
+      pos = pos + send_len;
+   }
+
+   return (int)len;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ssl_recv_data
+ *
+ * Description :  Receives data from given SSL context and puts
+ *                it into buffer.
+ *
+ * Parameters  :
+ *          1  :  ssl = SSL context to receive data from
+ *          2  :  buf = Pointer to buffer where data will be written
+ *          3  :  max_length = Maximum number of bytes to read
+ *
+ * Returns     :  Number of bytes read, 0 for EOF, or negative
+ *                value on error.
+ *
+ *********************************************************************/
+extern int ssl_recv_data(mbedtls_ssl_context *ssl, unsigned char *buf, size_t max_length)
+{
+   int ret = 0;
+   memset(buf, 0, max_length);
+
+   /*
+    * Receiving data from SSL context into buffer
+    */
+   do
+   {
+      ret = mbedtls_ssl_read(ssl, buf, max_length);
+   } while (ret == MBEDTLS_ERR_SSL_WANT_READ
+      || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+   if (ret < 0)
+   {
+      char err_buf[ERROR_BUF_SIZE];
+
+      memset(err_buf, 0, sizeof(err_buf));
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Receiving data over TLS/SSL failed: %s", err_buf);
+   }
+
+   return ret;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ssl_flush_socket
+ *
+ * Description :  Send any pending "buffered" content with given
+ *                SSL connection. Alternative to function flush_socket.
+ *
+ * Parameters  :
+ *          1  :  ssl = SSL context to send buffer to
+ *          2  :  iob = The I/O buffer to flush, usually csp->iob.
+ *
+ * Returns     :  On success, the number of bytes send are returned (zero
+ *                indicates nothing was sent).  On error, -1 is returned.
+ *
+ *********************************************************************/
+extern long ssl_flush_socket(mbedtls_ssl_context *ssl, struct iob *iob)
+{
+   /* Computing length of buffer part to send */
+   long len = iob->eod - iob->cur;
+
+   if (len <= 0)
+   {
+      return(0);
+   }
+
+   /* Sending data to given SSl context */
+   if (ssl_send_data(ssl, (const unsigned char *)iob->cur, (size_t)len) < 0)
+   {
+      return -1;
+   }
+   iob->eod = iob->cur = iob->buf;
+   return(len);
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ssl_debug_callback
+ *
+ * Description :  Debug callback function for mbedtls library.
+ *                Prints info into log file.
+ *
+ * Parameters  :
+ *          1  :  ctx   = File to save log in
+ *          2  :  level = Debug level
+ *          3  :  file  = File calling debug message
+ *          4  :  line  = Line calling debug message
+ *          5  :  str   = Debug message
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void ssl_debug_callback(void *ctx, int level, const char *file, int line, const char *str)
+{
+   /*
+   ((void)level);
+   fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str);
+   fflush((FILE *)ctx);
+   log_error(LOG_LEVEL_INFO, "SSL debug message: %s:%04d: %s", file, line, str);
+   */
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  create_client_ssl_connection
+ *
+ * Description :  Creates TLS/SSL secured connection with client
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 on success, negative value if connection wasn't created
+ *                successfully.
+ *
+ *********************************************************************/
+extern int create_client_ssl_connection(struct client_state *csp)
+{
+   /* Paths to certificates file and key file */
+   char *key_file  = NULL;
+   char *ca_file   = NULL;
+   char *cert_file = NULL;
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+
+   memset(err_buf, 0, sizeof(err_buf));
+
+   /*
+    * Initializing mbedtls structures for TLS/SSL connection
+    */
+   mbedtls_net_init(&(csp->mbedtls_client_attr.socket_fd));
+   mbedtls_ssl_init(&(csp->mbedtls_client_attr.ssl));
+   mbedtls_ssl_config_init(&(csp->mbedtls_client_attr.conf));
+   mbedtls_x509_crt_init(&(csp->mbedtls_client_attr.server_cert));
+   mbedtls_pk_init(&(csp->mbedtls_client_attr.prim_key));
+#if defined(MBEDTLS_SSL_CACHE_C)
+   mbedtls_ssl_cache_init(&(csp->mbedtls_client_attr.cache));
+#endif
+
+   /*
+    * Preparing hash of host for creating certificates
+    */
+   ret = host_to_hash(csp);
+   if (ret != 0)
+   {
+      log_error(LOG_LEVEL_ERROR, "Generating hash of host failed: %d", ret);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Preparing paths to certificates files and key file
+    */
+   ca_file   = csp->config->ca_cert_file;
+   cert_file = make_certs_path(csp->config->certificate_directory,
+      (const char *)csp->http->hash_of_host_hex, CERT_FILE_TYPE);
+   key_file  = make_certs_path(csp->config->certificate_directory,
+      (const char *)csp->http->hash_of_host_hex, KEY_FILE_TYPE);
+
+   if (cert_file == NULL || key_file == NULL)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Generating certificate for requested host. Mutex to prevent
+    * certificate and key inconsistence must be locked.
+    */
+   unsigned int cert_mutex_id = get_certificate_mutex_id(csp);
+   privoxy_mutex_lock(&(certificates_mutexes[cert_mutex_id]));
+
+   ret = generate_webpage_certificate(csp);
+   if (ret < 0)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Generate_webpage_certificate failed: %d", ret);
+      privoxy_mutex_unlock(&(certificates_mutexes[cert_mutex_id]));
+      ret = -1;
+      goto exit;
+   }
+   privoxy_mutex_unlock(&(certificates_mutexes[cert_mutex_id]));
+
+   /*
+    * Seed the RNG
+    */
+   ret = seed_rng(csp);
+   if (ret != 0)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Loading CA file, webpage certificate and key files
+    */
+   ret = mbedtls_x509_crt_parse_file(&(csp->mbedtls_client_attr.server_cert),
+      cert_file);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Loading webpage certificate %s failed: %s", cert_file, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_x509_crt_parse_file(&(csp->mbedtls_client_attr.server_cert),
+      ca_file);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Loading CA certificate %s failed: %s", ca_file, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_pk_parse_keyfile(&(csp->mbedtls_client_attr.prim_key),
+      key_file, NULL);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Loading and parsing webpage certificate private key %s failed: %s",
+         key_file, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Setting SSL parameters
+    */
+   ret = mbedtls_ssl_config_defaults(&(csp->mbedtls_client_attr.conf),
+      MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
+      MBEDTLS_SSL_PRESET_DEFAULT);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "mbedtls_ssl_config_defaults failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   mbedtls_ssl_conf_rng(&(csp->mbedtls_client_attr.conf),
+      mbedtls_ctr_drbg_random, &ctr_drbg);
+   mbedtls_ssl_conf_dbg(&(csp->mbedtls_client_attr.conf),
+      ssl_debug_callback, stdout);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+   mbedtls_ssl_conf_session_cache(&(csp->mbedtls_client_attr.conf),
+      &(csp->mbedtls_client_attr.cache), mbedtls_ssl_cache_get,
+      mbedtls_ssl_cache_set);
+#endif
+
+   /*
+    * Setting certificates
+    */
+   ret = mbedtls_ssl_conf_own_cert(&(csp->mbedtls_client_attr.conf),
+      &(csp->mbedtls_client_attr.server_cert),
+      &(csp->mbedtls_client_attr.prim_key));
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "mbedtls_ssl_conf_own_cert failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_ssl_setup(&(csp->mbedtls_client_attr.ssl),
+      &(csp->mbedtls_client_attr.conf));
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_ssl_setup failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   mbedtls_ssl_set_bio(&(csp->mbedtls_client_attr.ssl),
+      &(csp->mbedtls_client_attr.socket_fd), mbedtls_net_send,
+      mbedtls_net_recv, NULL);
+   mbedtls_ssl_session_reset(&(csp->mbedtls_client_attr.ssl));
+
+   /*
+    * Setting socket fd in mbedtls_net_context structure. This structure
+    * can't be set by mbedtls functions, because we already have created
+    * a TCP connection when this function is called.
+    */
+   csp->mbedtls_client_attr.socket_fd.fd = csp->cfd;
+
+   /*
+    *  Handshake with client
+    */
+   log_error(LOG_LEVEL_CONNECT,
+      "Performing the TLS/SSL handshake with client. Hash of host: %s",
+      csp->http->hash_of_host_hex);
+   while ((ret = mbedtls_ssl_handshake(&(csp->mbedtls_client_attr.ssl))) != 0)
+   {
+      if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+          ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+      {
+         mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+         log_error(LOG_LEVEL_ERROR,
+            "medtls_ssl_handshake with client failed: %s", err_buf);
+         ret = -1;
+         goto exit;
+      }
+   }
+
+   log_error(LOG_LEVEL_CONNECT, "Client successfully connected over TLS/SSL");
+   csp->ssl_with_client_is_opened = 1;
+
+exit:
+   /*
+    * Freeing allocated paths to files
+    */
+   freez(cert_file);
+   freez(key_file);
+
+   /* Freeing structures if connection wasn't created successfully */
+   if (ret < 0)
+   {
+      free_client_ssl_structures(csp);
+   }
+   return ret;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  close_client_ssl_connection
+ *
+ * Description :  Closes TLS/SSL connection with client. This function
+ *                checks if this connection is already created.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+extern void close_client_ssl_connection(struct client_state *csp)
+{
+   int ret = 0;
+
+   if (csp->ssl_with_client_is_opened == 0)
+   {
+      return;
+   }
+
+   /*
+    * Notifying the peer that the connection is being closed.
+    */
+   do {
+      ret = mbedtls_ssl_close_notify(&(csp->mbedtls_client_attr.ssl));
+   } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+   free_client_ssl_structures(csp);
+   csp->ssl_with_client_is_opened = 0;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  free_client_ssl_structures
+ *
+ * Description :  Frees structures used for SSL communication with
+ *                client.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void free_client_ssl_structures(struct client_state *csp)
+{
+   /*
+   * We can't use function mbedtls_net_free, because this function
+   * inter alia close TCP connection on setted fd. Instead of this
+   * function, we change fd to -1, which is the same what does
+   * rest of mbedtls_net_free function.
+   */
+   csp->mbedtls_client_attr.socket_fd.fd = -1;
+
+   /* Freeing mbedtls structures */
+   mbedtls_x509_crt_free(&(csp->mbedtls_client_attr.server_cert));
+   mbedtls_pk_free(&(csp->mbedtls_client_attr.prim_key));
+   mbedtls_ssl_free(&(csp->mbedtls_client_attr.ssl));
+   mbedtls_ssl_config_free(&(csp->mbedtls_client_attr.conf));
+#if defined(MBEDTLS_SSL_CACHE_C)
+   mbedtls_ssl_cache_free(&(csp->mbedtls_client_attr.cache));
+#endif
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  create_server_ssl_connection
+ *
+ * Description :  Creates TLS/SSL secured connection with server.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 on success, negative value if connection wasn't created
+ *                successfully.
+ *
+ *********************************************************************/
+extern int create_server_ssl_connection(struct client_state *csp)
+{
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+   char *trusted_cas_file = NULL;
+   int auth_mode = MBEDTLS_SSL_VERIFY_REQUIRED;
+
+   memset(err_buf, 0, sizeof(err_buf));
+
+   csp->server_cert_verification_result = SSL_CERT_NOT_VERIFIED;
+   csp->server_certs_chain.next = NULL;
+
+   /* Setting path to file with trusted CAs */
+   trusted_cas_file = csp->config->trusted_cas_file;
+
+   /*
+    * Initializing mbedtls structures for TLS/SSL connection
+    */
+   mbedtls_net_init(&(csp->mbedtls_server_attr.socket_fd));
+   mbedtls_ssl_init(&(csp->mbedtls_server_attr.ssl));
+   mbedtls_ssl_config_init(&(csp->mbedtls_server_attr.conf));
+   mbedtls_x509_crt_init( &(csp->mbedtls_server_attr.ca_cert));
+
+   /*
+   * Setting socket fd in mbedtls_net_context structure. This structure
+   * can't be set by mbedtls functions, because we already have created
+   * TCP connection when calling this function.
+   */
+   csp->mbedtls_server_attr.socket_fd.fd = csp->server_connection.sfd;
+
+   /*
+    * Seed the RNG
+    */
+   ret = seed_rng(csp);
+   if (ret != 0)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Loading file with trusted CAs
+    */
+   ret = mbedtls_x509_crt_parse_file(&(csp->mbedtls_server_attr.ca_cert),
+      trusted_cas_file);
+   if (ret < 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "Loading trusted CAs file %s failed: %s",
+         trusted_cas_file, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Set TLS/SSL options
+    */
+   ret = mbedtls_ssl_config_defaults(&(csp->mbedtls_server_attr.conf),
+      MBEDTLS_SSL_IS_CLIENT,
+      MBEDTLS_SSL_TRANSPORT_STREAM,
+      MBEDTLS_SSL_PRESET_DEFAULT);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_ssl_config_defaults failed: %s",
+         err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Setting how strict should certificate verification be and other
+    * parameters for certificate verification
+    */
+   if (csp->dont_verify_certificate)
+   {
+      auth_mode = MBEDTLS_SSL_VERIFY_NONE;
+   }
+
+   mbedtls_ssl_conf_authmode(&(csp->mbedtls_server_attr.conf), auth_mode);
+   mbedtls_ssl_conf_ca_chain(&(csp->mbedtls_server_attr.conf),
+      &(csp->mbedtls_server_attr.ca_cert), NULL);
+
+   /* Setting callback function for certificates verification */
+   mbedtls_ssl_conf_verify(&(csp->mbedtls_server_attr.conf),
+      ssl_verify_callback, (void *)csp);
+
+   mbedtls_ssl_conf_rng(&(csp->mbedtls_server_attr.conf),
+      mbedtls_ctr_drbg_random, &ctr_drbg);
+   mbedtls_ssl_conf_dbg(&(csp->mbedtls_server_attr.conf),
+      ssl_debug_callback, stdout);
+
+   ret = mbedtls_ssl_setup(&(csp->mbedtls_server_attr.ssl),
+      &(csp->mbedtls_server_attr.conf));
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_ssl_setup failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Set the hostname to check against the received server certificate
+    */
+   ret = mbedtls_ssl_set_hostname(&(csp->mbedtls_server_attr.ssl),
+      csp->http->host);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_ssl_set_hostname failed: %s",
+         err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   mbedtls_ssl_set_bio(&(csp->mbedtls_server_attr.ssl),
+      &(csp->mbedtls_server_attr.socket_fd), mbedtls_net_send,
+      mbedtls_net_recv, NULL);
+
+   /*
+    * Handshake with server
+    */
+   log_error(LOG_LEVEL_CONNECT,
+      "Performing the TLS/SSL handshake with server");
+
+   while ((ret = mbedtls_ssl_handshake(&(csp->mbedtls_server_attr.ssl))) != 0)
+   {
+      if (ret != MBEDTLS_ERR_SSL_WANT_READ
+       && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+      {
+         mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+
+         if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED)
+         {
+            log_error(LOG_LEVEL_ERROR,
+               "Server certificate verification failed: %s", err_buf);
+            csp->server_cert_verification_result =
+               mbedtls_ssl_get_verify_result(&(csp->mbedtls_server_attr.ssl));
+
+            ret = -1;
+         }
+         else
+         {
+            log_error(LOG_LEVEL_ERROR,
+               "mbedtls_ssl_handshake with server failed: %s", err_buf);
+            ret = -1;
+         }
+         goto exit;
+      }
+   }
+
+   log_error(LOG_LEVEL_CONNECT, "Server successfully connected over TLS/SSL");
+
+   /*
+    * Server certificate chain is valid, so we can clean
+    * chain, because we will not send it to client.
+    */
+   free_certificate_chain(csp);
+
+   csp->ssl_with_server_is_opened = 1;
+   csp->server_cert_verification_result =
+      mbedtls_ssl_get_verify_result(&(csp->mbedtls_server_attr.ssl));
+
+exit:
+   /* Freeing structures if connection wasn't created successfully */
+   if (ret < 0)
+   {
+      free_server_ssl_structures(csp);
+   }
+
+   return ret;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  close_server_ssl_connection
+ *
+ * Description :  Closes TLS/SSL connection with server. This function
+ *                checks if this connection is already opened.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void close_server_ssl_connection(struct client_state *csp)
+{
+   int ret = 0;
+
+   if (csp->ssl_with_server_is_opened == 0)
+   {
+      return;
+   }
+
+   /*
+   * Notifying the peer that the connection is being closed.
+   */
+   do {
+      ret = mbedtls_ssl_close_notify(&(csp->mbedtls_server_attr.ssl));
+   } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+   free_server_ssl_structures(csp);
+   csp->ssl_with_server_is_opened = 0;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  free_server_ssl_structures
+ *
+ * Description :  Frees structures used for SSL communication with server
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void free_server_ssl_structures(struct client_state *csp)
+{
+   /*
+   * We can't use function mbedtls_net_free, because this function
+   * inter alia close TCP connection on setted fd. Instead of this
+   * function, we change fd to -1, which is the same what does
+   * rest of mbedtls_net_free function.
+   */
+   csp->mbedtls_client_attr.socket_fd.fd = -1;
+
+   mbedtls_x509_crt_free(&(csp->mbedtls_server_attr.ca_cert));
+   mbedtls_ssl_free(&(csp->mbedtls_server_attr.ssl));
+   mbedtls_ssl_config_free(&(csp->mbedtls_server_attr.conf));
+}
+
+
+/*********************************************************************
+ * Function    :  close_client_and_server_ssl_connections
+ *
+ * Description :  Checks if client or server should use secured
+ *                connection over SSL and if so, closes all of them.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+extern void close_client_and_server_ssl_connections(struct client_state *csp)
+{
+   if (client_use_ssl(csp) == 1)
+   {
+      close_client_ssl_connection(csp);
+   }
+   if (server_use_ssl(csp) == 1)
+   {
+      close_server_ssl_connection(csp);
+   }
+}
+
+/*====================== Certificates ======================*/
+
+/*********************************************************************
+ * Function    :  write_certificate
+ *
+ * Description :  Writes certificate into file.
+ *
+ * Parameters  :
+ *          1  :  crt = certificate to write into file
+ *          2  :  output_file = path to save certificate file
+ *          3  :  f_rng = mbedtls_ctr_drbg_random
+ *          4  :  p_rng = mbedtls_ctr_drbg_context
+ *
+ * Returns     :  Length of written certificate on success or negative value
+ *                on error
+ *
+ *********************************************************************/
+static int write_certificate(mbedtls_x509write_cert *crt, const char *output_file,
+   int(*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+   FILE *f = NULL;
+   size_t len = 0;
+   unsigned char cert_buf[CERTIFICATE_BUF_SIZE + 1]; /* Buffer for certificate in PEM format + terminating NULL */
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+
+   memset(err_buf,  0, sizeof(err_buf));
+   memset(cert_buf, 0, sizeof(cert_buf));
+
+   /*
+    * Writing certificate into PEM string. If buffer is too small, fuction
+    * returns specific error and no buffer overflow can happen.
+    */
+   if ((ret = mbedtls_x509write_crt_pem(crt, cert_buf,
+      sizeof(cert_buf) - 1, f_rng, p_rng)) != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Writing certificate into buffer failed: %s", err_buf);
+      return -1;
+   }
+
+   len = strlen((char *)cert_buf);
+
+   /*
+    * Saving certificate into file
+    */
+   if ((f = fopen(output_file, "w")) == NULL)
+   {
+      log_error(LOG_LEVEL_ERROR, "Opening file %s to save certificate failed",
+         output_file);
+      return -1;
+   }
+
+   if (fwrite(cert_buf, 1, len, f) != len)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Writing certificate into file %s failed", output_file);
+      fclose(f);
+      return -1;
+   }
+
+   fclose(f);
+
+   return (int)len;
+}
+
+
+/*********************************************************************
+ * Function    :  write_private_key
+ *
+ * Description :  Writes private key into file and copies saved
+ *                content into given pointer to string. If function
+ *                returns 0 for success, this copy must be freed by
+ *                caller.
+ *
+ * Parameters  :
+ *          1  :  key = key to write into file
+ *          2  :  ret_buf = pointer to string with created key file content
+ *          3  :  key_file_path = path where to save key file
+ *
+ * Returns     :  Length of written private key on success or negative value
+ *                on error
+ *
+ *********************************************************************/
+static int write_private_key(mbedtls_pk_context *key, unsigned char **ret_buf,
+   const char *key_file_path)
+{
+   size_t len = 0;                /* Length of created key    */
+   FILE *f = NULL;                /* File to save certificate */
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+
+   memset(err_buf, 0, sizeof(err_buf));
+
+   /* Initializing buffer for key file content */
+   *ret_buf = (unsigned char *)malloc(PRIVATE_KEY_BUF_SIZE + 1);
+   if (*ret_buf == NULL)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Creating buffer for private key failed: malloc fail");
+      ret = -1;
+      goto exit;
+   }
+   memset(*ret_buf, 0, PRIVATE_KEY_BUF_SIZE + 1);
+
+   /*
+    * Writing private key into PEM string
+    */
+   if ((ret = mbedtls_pk_write_key_pem(key, *ret_buf, PRIVATE_KEY_BUF_SIZE)) != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Writing private key into PEM string failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+   len = strlen((char *)*ret_buf);
+
+   /*
+    * Saving key into file
+    */
+   if ((f = fopen(key_file_path, "wb")) == NULL)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Opening file %s to save private key failed: %E",
+         key_file_path);
+      ret = -1;
+      goto exit;
+   }
+
+   if (fwrite(*ret_buf, 1, len, f) != len)
+   {
+      fclose(f);
+      log_error(LOG_LEVEL_ERROR,
+         "Writing private key into file %s failed",
+         key_file_path);
+      ret = -1;
+      goto exit;
+   }
+
+   fclose(f);
+
+exit:
+   if (ret < 0)
+   {
+      freez(*ret_buf);
+      *ret_buf = NULL;
+      return ret;
+   }
+   return (int)len;
+}
+
+
+/*********************************************************************
+ * Function    :  generate_key
+ *
+ * Description : Tests if private key for host saved in csp already
+ *               exists.  If this file doesn't exists, a new key is
+ *               generated and saved in a file. The generated key is also
+ *               copied into given parameter key_buf, which must be then
+ *               freed by caller. If file with key exists, key_buf
+ *               contain NULL and no private key is generated.
+ *
+ * Parameters  :
+ *          1  :  key_buf = buffer to save new generated key
+ *          2  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  -1 => Error while generating private key
+ *                 0 => Key already exists
+ *                >0 => Length of generated private key
+ *
+ *********************************************************************/
+static int generate_key(unsigned char **key_buf, struct client_state *csp)
+{
+   mbedtls_pk_context key;
+   key_options key_opt;
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+
+   key_opt.key_file_path = NULL;
+   memset(err_buf, 0, sizeof(err_buf));
+
+   /*
+    * Initializing structures for key generating
+    */
+   mbedtls_pk_init(&key);
+
+   /*
+    * Preparing path for key file and other properties for generating key
+    */
+   key_opt.type        = MBEDTLS_PK_RSA;
+   key_opt.rsa_keysize = RSA_KEYSIZE;
+
+   key_opt.key_file_path = make_certs_path(csp->config->certificate_directory,
+      (char *)csp->http->hash_of_host_hex, KEY_FILE_TYPE);
+   if (key_opt.key_file_path == NULL)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Test if key already exists. If so, we don't have to create it again.
+    */
+   if (file_exists(key_opt.key_file_path) == 1)
+   {
+      ret = 0;
+      goto exit;
+   }
+
+   /*
+    * Seed the RNG
+    */
+   ret = seed_rng(csp);
+   if (ret != 0)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Setting attributes of private key and generating it
+    */
+   if ((ret = mbedtls_pk_setup(&key,
+      mbedtls_pk_info_from_type(key_opt.type))) != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_pk_setup failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random,
+      &ctr_drbg, (unsigned)key_opt.rsa_keysize, RSA_KEY_PUBLIC_EXPONENT);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "Key generating failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Exporting private key into file
+    */
+   if ((ret = write_private_key(&key, key_buf, key_opt.key_file_path)) < 0)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Writing private key into file %s failed", key_opt.key_file_path);
+      ret = -1;
+      goto exit;
+   }
+
+exit:
+   /*
+    * Freeing used variables
+    */
+   freez(key_opt.key_file_path);
+
+   mbedtls_pk_free(&key);
+
+   return ret;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  generate_webpage_certificate
+ *
+ * Description :  Creates certificate file in presetted directory.
+ *                If certificate already exists, no other certificate
+ *                will be created. Subject of certificate is named
+ *                by csp->http->host from parameter. This function also
+ *                triggers generating of private key for new certificate.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  -1 => Error while creating certificate.
+ *                 0 => Certificate alreaday exist.
+ *                >0 => Length of created certificate.
+ *
+ *********************************************************************/
+extern int generate_webpage_certificate(struct client_state * csp)
+{
+   mbedtls_x509_crt issuer_cert;
+   mbedtls_pk_context loaded_issuer_key, loaded_subject_key;
+   mbedtls_pk_context *issuer_key  = &loaded_issuer_key;
+   mbedtls_pk_context *subject_key = &loaded_subject_key;
+   mbedtls_x509write_cert cert;
+   mbedtls_mpi serial;
+
+   unsigned char *key_buf = NULL;    /* Buffer for created key */
+
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+   cert_options cert_opt;
+
+   memset(err_buf, 0, sizeof(err_buf));
+
+   /* Paths to keys and certificates needed to create certificate */
+   cert_opt.issuer_key  = NULL;
+   cert_opt.subject_key = NULL;
+   cert_opt.issuer_crt  = NULL;
+   cert_opt.output_file = NULL;
+
+   /*
+    * Create key for requested host
+    */
+   int subject_key_len = generate_key(&key_buf, csp);
+   if (subject_key_len < 0)
+   {
+      log_error(LOG_LEVEL_ERROR, "Key generating failed");
+      return -1;
+   }
+
+   /*
+    * Initializing structures for certificate generating
+    */
+   mbedtls_x509write_crt_init(&cert);
+   mbedtls_x509write_crt_set_md_alg( &cert, CERT_SIGNATURE_ALGORITHM);
+   mbedtls_pk_init(&loaded_issuer_key);
+   mbedtls_pk_init(&loaded_subject_key);
+   mbedtls_mpi_init(&serial);
+   mbedtls_x509_crt_init(&issuer_cert);
+
+   /*
+    * Presetting parameters for certificate. We must compute total length
+    * of parameters.
+    */
+   size_t cert_params_len = strlen(CERT_PARAM_COMMON_NAME) +
+      strlen(CERT_PARAM_ORGANIZATION) + strlen(CERT_PARAM_COUNTRY) +
+      strlen(CERT_PARAM_ORG_UNIT) +
+      3 * strlen(csp->http->host) + 1;
+   char cert_params[cert_params_len];
+   memset(cert_params, 0, cert_params_len);
+
+   /*
+    * Converting unsigned long serial number to char * serial number.
+    * We must compute length of serial number in string + terminating null.
+    */
+   unsigned long certificate_serial = get_certificate_serial(csp);
+   int serial_num_size = snprintf(NULL, 0, "%lu", certificate_serial) + 1;
+   if (serial_num_size <= 0)
+   {
+      serial_num_size = 1;
+   }
+
+   char serial_num_text[serial_num_size];  /* Buffer for serial number */
+   ret = snprintf(serial_num_text, (size_t)serial_num_size, "%lu", certificate_serial);
+   if (ret < 0 || ret >= serial_num_size)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Converting certificate serial number into string failed");
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Preparing parameters for certificate
+    */
+   strlcpy(cert_params, CERT_PARAM_COMMON_NAME,  cert_params_len);
+   strlcat(cert_params, csp->http->host,         cert_params_len);
+   strlcat(cert_params, CERT_PARAM_ORGANIZATION, cert_params_len);
+   strlcat(cert_params, csp->http->host,         cert_params_len);
+   strlcat(cert_params, CERT_PARAM_ORG_UNIT,     cert_params_len);
+   strlcat(cert_params, csp->http->host,         cert_params_len);
+   strlcat(cert_params, CERT_PARAM_COUNTRY,      cert_params_len);
+
+   cert_opt.issuer_crt = csp->config->ca_cert_file;
+   cert_opt.issuer_key = csp->config->ca_key_file;
+   cert_opt.subject_key = make_certs_path(csp->config->certificate_directory,
+      (const char *)csp->http->hash_of_host_hex, KEY_FILE_TYPE);
+   cert_opt.output_file = make_certs_path(csp->config->certificate_directory,
+      (const char *)csp->http->hash_of_host_hex, CERT_FILE_TYPE);
+
+   if (cert_opt.subject_key == NULL || cert_opt.output_file == NULL)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   cert_opt.subject_pwd   = CERT_SUBJECT_PASSWORD;
+   cert_opt.issuer_pwd    = csp->config->ca_password;
+   cert_opt.subject_name  = cert_params;
+   cert_opt.not_before    = GENERATED_CERT_VALID_FROM;
+   cert_opt.not_after     = GENERATED_CERT_VALID_TO;
+   cert_opt.serial        = serial_num_text;
+   cert_opt.is_ca         = 0;
+   cert_opt.max_pathlen   = -1;
+
+   /*
+    * Test if certificate exists and private key was already created
+    */
+   if (file_exists(cert_opt.output_file) == 1 && subject_key_len == 0)
+   {
+      ret = 0;
+      goto exit;
+   }
+
+   /*
+    * Seed the PRNG
+    */
+   ret = seed_rng(csp);
+   if (ret != 0)
+   {
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Parse serial to MPI
+    */
+   ret = mbedtls_mpi_read_string(&serial, 10, cert_opt.serial);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "mbedtls_mpi_read_string failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Loading certificates
+    */
+   ret = mbedtls_x509_crt_parse_file(&issuer_cert, cert_opt.issuer_crt);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "Loading issuer certificate %s failed: %s",
+         cert_opt.issuer_crt, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_x509_dn_gets(cert_opt.issuer_name,
+      sizeof(cert_opt.issuer_name), &issuer_cert.subject);
+   if (ret < 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_x509_dn_gets failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Loading keys from file or from buffer
+    */
+   if (key_buf != NULL && subject_key_len > 0)
+   {
+      /* Key was created in this function and is stored in buffer */
+      ret = mbedtls_pk_parse_key(&loaded_subject_key, key_buf,
+         (size_t)(subject_key_len + 1), (unsigned const char *)
+         cert_opt.subject_pwd, strlen(cert_opt.subject_pwd));
+   }
+   else
+   {
+      /* Key wasn't created in this function, because it already existed */
+      ret = mbedtls_pk_parse_keyfile(&loaded_subject_key,
+         cert_opt.subject_key, cert_opt.subject_pwd);
+   }
+
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "Parsing subject key %s failed: %s",
+         cert_opt.subject_key, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_pk_parse_keyfile(&loaded_issuer_key, cert_opt.issuer_key,
+      cert_opt.issuer_pwd);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Parsing issuer key %s failed: %s", cert_opt.issuer_key, err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Check if key and issuer certificate match
+    */
+   if (!mbedtls_pk_can_do(&issuer_cert.pk, MBEDTLS_PK_RSA) ||
+      mbedtls_mpi_cmp_mpi(&mbedtls_pk_rsa(issuer_cert.pk)->N,
+         &mbedtls_pk_rsa(*issuer_key)->N) != 0 ||
+      mbedtls_mpi_cmp_mpi( &mbedtls_pk_rsa(issuer_cert.pk)->E,
+         &mbedtls_pk_rsa(*issuer_key )->E) != 0)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Issuer key doesn't match issuer certificate");
+      ret = -1;
+      goto exit;
+   }
+
+   mbedtls_x509write_crt_set_subject_key(&cert, subject_key);
+   mbedtls_x509write_crt_set_issuer_key(&cert, issuer_key);
+
+   /*
+    * Setting parameters of signed certificate
+    */
+   ret = mbedtls_x509write_crt_set_subject_name(&cert, cert_opt.subject_name);
+   if (ret != 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Setting subject name in signed certificate failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_x509write_crt_set_issuer_name(&cert, cert_opt.issuer_name);
+   if (ret != 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Setting issuer name in signed certificate failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_x509write_crt_set_serial(&cert, &serial);
+   if (ret != 0)
+   {
+      mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Setting serial number in signed certificate failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   ret = mbedtls_x509write_crt_set_validity(&cert, cert_opt.not_before,
+      cert_opt.not_after);
+   if (ret != 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR,
+         "Setting validity in signed certificate failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /*
+    * Setting the basicConstraints extension for certificate
+    */
+   ret = mbedtls_x509write_crt_set_basic_constraints(&cert, cert_opt.is_ca,
+      cert_opt.max_pathlen);
+   if (ret != 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "Setting the basicConstraints extension "
+         "in signed certificate failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+#if defined(MBEDTLS_SHA1_C)
+   /* Setting the subjectKeyIdentifier extension for certificate */
+   ret = mbedtls_x509write_crt_set_subject_key_identifier(&cert);
+   if (ret != 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_x509write_crt_set_subject_key_"
+         "identifier failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+
+   /* Setting the authorityKeyIdentifier extension for certificate */
+   ret = mbedtls_x509write_crt_set_authority_key_identifier(&cert);
+   if (ret != 0)
+   {
+      mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+      log_error(LOG_LEVEL_ERROR, "mbedtls_x509write_crt_set_authority_key_"
+         "identifier failed: %s", err_buf);
+      ret = -1;
+      goto exit;
+   }
+#endif /* MBEDTLS_SHA1_C */
+
+   /*
+    * Writing certificate into file
+    */
+   ret = write_certificate(&cert, cert_opt.output_file,
+      mbedtls_ctr_drbg_random, &ctr_drbg);
+   if (ret < 0)
+   {
+      log_error(LOG_LEVEL_ERROR, "Writing certificate into file failed");
+      goto exit;
+   }
+
+exit:
+   /*
+    * Freeing used structures
+    */
+   mbedtls_x509write_crt_free(&cert);
+   mbedtls_pk_free(&loaded_subject_key);
+   mbedtls_pk_free(&loaded_issuer_key);
+   mbedtls_mpi_free(&serial);
+   mbedtls_x509_crt_free(&issuer_cert);
+
+   freez(cert_opt.subject_key);
+   freez(cert_opt.output_file);
+   freez(key_buf);
+
+   return ret;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  make_certs_path
+ *
+ * Description : Creates path to file from three pieces. This fuction
+ *               takes parameters and puts them in one new mallocated
+ *               char * in correct order. Returned variable must be freed
+ *               by caller. This function is mainly used for creating
+ *               paths of certificates and keys files.
+ *
+ * Parameters  :
+ *          1  :  conf_dir  = Name/path of directory where is the file.
+ *                            '.' can be used for current directory.
+ *          2  :  file_name = Name of file in conf_dir without suffix.
+ *          3  :  suffix    = Suffix of given file_name.
+ *
+ * Returns     :  path => Path was built up successfully
+ *                NULL => Path can't be built up
+ *
+ *********************************************************************/
+static char *make_certs_path(const char *conf_dir, const char *file_name,
+   const char *suffix)
+{
+   /* Test if all given parameters are valid */
+   if (conf_dir == NULL || *conf_dir == '\0' || file_name == NULL ||
+      *file_name == '\0' || suffix == NULL || *suffix == '\0')
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "make_certs_path failed: bad input parameters");
+      return NULL;
+   }
+
+   char *path = NULL;
+   size_t path_size = strlen(conf_dir)
+      + strlen(file_name) + strlen(suffix) + 2;
+
+   /* Setting delimiter and editing path length */
+#if defined(_WIN32) || defined(__OS2__)
+   char delim[] = "\\";
+   path_size += 1;
+#else /* ifndef _WIN32 || __OS2__ */
+   char delim[] = "/";
+#endif /* ifndef _WIN32 || __OS2__ */
+
+   /*
+    * Building up path from many parts
+    */
+#if defined(unix)
+   if (*conf_dir != '/' && basedir && *basedir)
+   {
+      /*
+       * Replacing conf_dir with basedir. This new variable contains
+       * absolute path to cwd.
+       */
+      path_size += strlen(basedir) + 2;
+      path = (char *)malloc(path_size);
+      if (path == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR, "make_certs_path failed: malloc fail");
+         return NULL;
+      }
+      memset(path, 0, path_size);
+
+      strlcpy(path, basedir,   path_size);
+      strlcat(path, delim,     path_size);
+      strlcat(path, conf_dir,  path_size);
+      strlcat(path, delim,     path_size);
+      strlcat(path, file_name, path_size);
+      strlcat(path, suffix,    path_size);
+   }
+   else
+#endif /* defined unix */
+   {
+      path = (char *)malloc(path_size);
+      if (path == NULL)
+      {
+         log_error(LOG_LEVEL_ERROR, "make_certs_path failed: malloc fail");
+         return NULL;
+      }
+      memset(path, 0, path_size);
+
+      strlcpy(path, conf_dir,  path_size);
+      strlcat(path, delim,     path_size);
+      strlcat(path, file_name, path_size);
+      strlcat(path, suffix,    path_size);
+   }
+
+   return path;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  get_certificate_mutex_id
+ *
+ * Description :  Computes mutex id from host name hash. This hash must
+ *                be already saved in csp structure
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Mutex id for given host name
+ *
+ *********************************************************************/
+static unsigned int get_certificate_mutex_id(struct client_state *csp) {
+#ifdef LIMIT_MUTEX_NUMBER
+   return (unsigned int)(csp->http->hash_of_host[0] % 32);
+#else
+   return (unsigned int)(csp->http->hash_of_host[1]
+      + 256 * (int)csp->http->hash_of_host[0]);
+#endif /* LIMIT_MUTEX_NUMBER */
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  get_certificate_serial
+ *
+ * Description :  Computes serial number for new certificate from host
+ *                name hash. This hash must be already saved in csp
+ *                structure.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  Serial number for new certificate
+ *
+ *********************************************************************/
+static unsigned long  get_certificate_serial(struct client_state *csp) {
+   unsigned long exp    = 1;
+   unsigned long serial = 0;
+
+   int i = CERT_SERIAL_NUM_LENGTH;
+   /* Length of hash is 16 bytes, we must avoid to read next chars */
+   if (i > 16)
+   {
+      i = 16;
+   }
+   if (i < 2)
+   {
+      i = 2;
+   }
+
+   for (; i >= 0; i--)
+   {
+      serial += exp * (unsigned)csp->http->hash_of_host[i];
+      exp *= 256;
+   }
+   return serial;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ssl_send_certificate_error
+ *
+ * Description :  Sends info about invalid server certificate to client.
+ *                Sent message is including all trusted chain certificates,
+ *                that can be downloaded in web browser.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+extern void ssl_send_certificate_error(struct client_state *csp)
+{
+   size_t message_len = 0;
+   int ret = 0;
+   struct certs_chain *cert = NULL;
+
+   /* Header of message with certificate informations */
+   const char message_begin[] =
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Type: text/html\r\n"
+      "Connection: close\r\n\r\n"
+      "<html><body><h1>Invalid server certificate</h1><p>Reason: ";
+   const char message_end[] = "</body></html>\r\n\r\n";
+   char reason[INVALID_CERT_INFO_BUF_SIZE];
+   memset(reason, 0, sizeof(reason));
+
+   /* Get verification message from verification return code */
+   mbedtls_x509_crt_verify_info(reason, sizeof(reason), " ",
+      csp->server_cert_verification_result);
+
+   /*
+    * Computing total length of message with all certificates inside
+    */
+   message_len = strlen(message_begin) + strlen(message_end)
+                 + strlen(reason) + strlen("</p>") + 1;
+
+   cert = &(csp->server_certs_chain);
+   while (cert->next != NULL)
+   {
+      size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
+
+      message_len += strlen(cert->text_buf) + strlen("<pre></pre>\n")
+                     +  base64_len + strlen("<a href=\"data:application"
+                        "/x-x509-ca-cert;base64,\">Download certificate</a>");
+      cert = cert->next;
+   }
+
+   /*
+    * Joining all blocks in one long message
+    */
+   char message[message_len];
+   memset(message, 0, message_len);
+
+   strlcpy(message, message_begin, message_len);
+   strlcat(message, reason       , message_len);
+   strlcat(message, "</p>"       , message_len);
+
+   cert = &(csp->server_certs_chain);
+   while (cert->next != NULL)
+   {
+      size_t olen = 0;
+      size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1; /* +1 for terminating null*/
+      char base64_buf[base64_len];
+      memset(base64_buf, 0, base64_len);
+
+      /* Encoding certificate into base64 code */
+      ret = mbedtls_base64_encode((unsigned char*)base64_buf,
+               base64_len, &olen, (const unsigned char*)cert->file_buf,
+               strlen(cert->file_buf));
+      if (ret != 0)
+      {
+         log_error(LOG_LEVEL_ERROR,
+            "Encoding to base64 failed, buffer is to small");
+      }
+
+      strlcat(message, "<pre>",        message_len);
+      strlcat(message, cert->text_buf, message_len);
+      strlcat(message, "</pre>\n",     message_len);
+
+      if (ret == 0)
+      {
+         strlcat(message, "<a href=\"data:application/x-x509-ca-cert;base64,",
+            message_len);
+         strlcat(message, base64_buf, message_len);
+         strlcat(message, "\">Download certificate</a>", message_len);
+      }
+
+      cert = cert->next;
+   }
+   strlcat(message, message_end, message_len);
+
+   /*
+    * Sending final message to client
+    */
+   ssl_send_data(&(csp->mbedtls_client_attr.ssl),
+      (const unsigned char *)message, strlen(message));
+   /*
+    * Waiting before closing connection. Some browsers doesn't show received
+    * message if there isn't this delay.
+    */
+   sleep(1);
+
+   free_certificate_chain(csp);
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  ssl_verify_callback
+ *
+ * Description :  This is a callback function for certificate verification.
+ *                It's called for all certificates in server certificate
+ *                trusted chain and it's preparing information about this
+ *                certificates. Prepared informations can be used to inform
+ *                user about invalid certificates.
+ *
+ * Parameters  :
+ *          1  :  csp_void = Current client state (buffers, headers, etc...)
+ *          2  :  crt   = certificate from trusted chain
+ *          3  :  depth = depth in trusted chain
+ *          4  :  flags = certificate flags
+ *
+ * Returns     :  0 on success and negative value on error
+ *
+ *********************************************************************/
+static int ssl_verify_callback(void *csp_void, mbedtls_x509_crt *crt,
+   int depth, uint32_t *flags)
+{
+   struct client_state *csp  = (struct client_state *)csp_void;
+   struct certs_chain  *last = &(csp->server_certs_chain);
+   size_t olen = 0;
+   int ret = 0;
+
+   /*
+    * Searching for last item in certificates linked list
+    */
+   while (last->next != NULL)
+   {
+      last = last->next;
+   }
+
+   /*
+    * Preparing next item in linked list for next certificate
+    * If malloc fails, we are continuing without this certificate
+    */
+   last->next = (struct certs_chain *)malloc(sizeof(struct certs_chain));
+   if (last->next != NULL)
+   {
+      last->next->next = NULL;
+      memset(last->next->text_buf, 0, sizeof(last->next->text_buf));
+      memset(last->next->file_buf, 0, sizeof(last->next->file_buf));
+
+      /*
+       * Saving certificate file into buffer
+       */
+      if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT,
+         crt->raw.p, crt->raw.len, (unsigned char *)last->file_buf,
+         sizeof(last->file_buf)-1, &olen)) != 0)
+      {
+         return(ret);
+      }
+
+      /*
+       * Saving certificate information into buffer
+       */
+      mbedtls_x509_crt_info(last->text_buf, sizeof(last->text_buf) - 1,
+         CERT_INFO_PREFIX, crt);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Malloc memory for server certificate informations failed");
+      return -1;
+   }
+
+   return 0;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  free_certificate_chain
+ *
+ * Description :  Frees certificates linked list. This linked list is
+ *                used to save informations about certificates in
+ *                trusted chain.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+static void free_certificate_chain(struct client_state *csp)
+{
+   struct certs_chain *cert = csp->server_certs_chain.next;
+
+   /* Cleaning buffers */
+   memset(csp->server_certs_chain.text_buf, 0,
+      sizeof(csp->server_certs_chain.text_buf));
+   memset(csp->server_certs_chain.text_buf, 0,
+      sizeof(csp->server_certs_chain.file_buf));
+   csp->server_certs_chain.next = NULL;
+
+   /* Freeing memory in whole linked list */
+   if (cert != NULL)
+   {
+      do
+      {
+         struct certs_chain *cert_for_free = cert;
+         cert = cert->next;
+         freez(cert_for_free);
+      } while (cert != NULL);
+   }
+}
+
+
+/*********************************************************************
+*
+* Function    :  file_exists
+*
+* Description :  Tests if file exists and is readable.
+*
+* Parameters  :
+*          1  :  path = Path to tested file.
+*
+* Returns     :  1 => File exists and is readable.
+*                0 => File doesn't exist or is not readable.
+*
+*********************************************************************/
+static int file_exists(const char *path)
+{
+   FILE *f;
+   if ((f = fopen(path, "r")) != NULL)
+   {
+      fclose(f);
+      return 1;
+   }
+
+   return 0;
+}
+
+
+/*********************************************************************
+*
+* Function    :  host_to_hash
+*
+* Description :  Creates MD5 hash from host name. Host name is loaded
+*                from structure csp and saved again into it.
+*
+* Parameters  :
+*          1  :  csp = Current client state (buffers, headers, etc...)
+*
+* Returns     :  1 => Error while creating hash
+*                0 => Hash created successfully
+*
+*********************************************************************/
+static int host_to_hash(struct client_state * csp)
+{
+   int ret = 0;
+
+#if !defined(MBEDTLS_MD5_C)
+   log_error(LOG_LEVEL_ERROR, "MBEDTLS_MD5_C is not defined. Can't create"
+      "MD5 hash for certificate and key name.");
+   return -1;
+#else
+   memset(csp->http->hash_of_host, 0, sizeof(csp->http->hash_of_host));
+   mbedtls_md5((unsigned char *)csp->http->host, strlen(csp->http->host),
+      csp->http->hash_of_host);
+
+   /* Converting hash into string with hex */
+   size_t i = 0;
+   for (; i < 16; i++)
+   {
+      if ((ret = sprintf((char *)csp->http->hash_of_host_hex + 2 * i, "%02x",
+         csp->http->hash_of_host[i])) < 0)
+      {
+         log_error(LOG_LEVEL_ERROR, "Sprintf return value: %d", ret);
+         return -1;
+      }
+   }
+
+   return 0;
+#endif /* MBEDTLS_MD5_C */
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  tunnel_established_successfully
+ *
+ * Description :  Check if parent proxy server response contains
+ *                informations about successfully created connection with
+ *                destination server. (HTTP/... 2xx ...)
+ *
+ * Parameters  :
+ *          1  :  server_response = Buffer with parent proxy server response
+ *          2  :  response_len = Length of server_response
+ *
+ * Returns     :  1 => Connection created successfully
+ *                0 => Connection wasn't created successfully
+ *
+ *********************************************************************/
+extern int tunnel_established_successfully(const char *server_response,
+   unsigned int response_len)
+{
+   unsigned int pos = 0;
+
+   if (server_response == NULL)
+   {
+      return 0;
+   }
+
+   /* Tests if "HTTP/" string is at the begin of received response */
+   if (strncmp(server_response, "HTTP/", 5) != 0)
+   {
+      return 0;
+   }
+
+   for (pos = 0; pos < response_len; pos++)
+   {
+      if (server_response[pos] == ' ')
+      {
+         break;
+      }
+   }
+
+   /*
+    * response_len -3 because of buffer end, response structure and 200 code.
+    * There must be at least 3 chars after space.
+    * End of buffer: ... 2xx'\0'
+    *             pos = |
+    */
+   if (pos >= (response_len - 3))
+   {
+      return 0;
+   }
+
+   /* Test HTTP status code */
+   if (server_response[pos + 1] != '2')
+   {
+      return 0;
+   }
+
+   return 1;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  seed_rng
+ *
+ * Description :  Seeding the RNG for all SSL uses
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     : -1 => RNG wasn't seed successfully
+ *                0 => RNG is seeded successfully
+ *
+ *********************************************************************/
+static int seed_rng(struct client_state *csp)
+{
+   int ret = 0;
+   char err_buf[ERROR_BUF_SIZE];
+
+   memset(err_buf, 0, sizeof(err_buf));
+
+   if (rng_seeded == 0)
+   {
+      privoxy_mutex_lock(&rng_mutex);
+      if (rng_seeded == 0)
+      {
+         mbedtls_ctr_drbg_init(&ctr_drbg);
+         mbedtls_entropy_init(&entropy);
+         ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+            &entropy, NULL, 0);
+         if (ret != 0)
+         {
+            mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+            log_error(LOG_LEVEL_ERROR,
+               "mbedtls_ctr_drbg_seed failed: %s", err_buf);
+            privoxy_mutex_unlock(&rng_mutex);
+            return -1;
+         }
+         rng_seeded = 1;
+      }
+      privoxy_mutex_unlock(&rng_mutex);
+   }
+   return 0;
+}
diff --git a/ssl.h b/ssl.h
new file mode 100644 (file)
index 0000000..33ab33a
--- /dev/null
+++ b/ssl.h
@@ -0,0 +1,67 @@
+#ifndef SSL_H_INCLUDED
+#define SSL_H_INCLUDED
+/*********************************************************************
+*
+* File        :  $Source: /cvsroot/ijbswa/current/ssl.h,v $
+*
+* 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.
+*
+*                This program is free software; you can redistribute it
+*                and/or modify it under the terms of the GNU General
+*                Public License as published by the Free Software
+*                Foundation; either version 2 of the License, or (at
+*                your option) any later version.
+*
+*                This program is distributed in the hope that it will
+*                be useful, but WITHOUT ANY WARRANTY; without even the
+*                implied warranty of MERCHANTABILITY or FITNESS FOR A
+*                PARTICULAR PURPOSE.  See the GNU General Public
+*                License for more details.
+*
+*                The GNU General Public License should be included with
+*                this file.  If not, you can view it at
+*                http://www.gnu.org/copyleft/gpl.html
+*                or write to the Free Software Foundation, Inc., 59
+*                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*
+*********************************************************************/
+
+#include "project.h"
+
+/*
+ * Values for flag determining certificate validity.
+ * These values are compatible with return value of function
+ * mbedtls_ssl_get_verify_result. There is not value for invalid
+ * certificate, this value is setted by function
+ * mbedtls_ssl_get_verify_result.
+ */
+#define SSL_CERT_VALID          0
+#define SSL_CERT_NOT_VERIFIED   0xFFFFFFFF
+
+/* Variables for one common RNG for all SSL use */
+static mbedtls_ctr_drbg_context ctr_drbg;
+static mbedtls_entropy_context  entropy;
+static int rng_seeded;
+
+/* Boolean functions to get informations about TLS/SSL connections */
+extern int    client_use_ssl(const struct client_state *csp);
+extern int    server_use_ssl(const struct client_state *csp);
+extern size_t is_ssl_pending(mbedtls_ssl_context *ssl);
+extern int tunnel_established_successfully(const char * response, unsigned int response_len);
+
+/* Functions for sending and receiving data over TLS/SSL connections */
+extern int  ssl_send_data(mbedtls_ssl_context * ssl, const unsigned char * buf, size_t len);
+extern int  ssl_recv_data(mbedtls_ssl_context * ssl, unsigned char * buf, size_t maxLen);
+extern long ssl_flush_socket(mbedtls_ssl_context * ssl, struct iob *iob);
+extern void ssl_send_certificate_error(struct client_state *csp);
+
+/* Functions for opening and closing TLS/SSL connections */
+extern int  create_client_ssl_connection(struct client_state *csp);
+extern int  create_server_ssl_connection(struct client_state *csp);
+extern void close_client_and_server_ssl_connections(struct client_state *csp);
+extern void close_client_ssl_connection(struct client_state *csp);
+
+#endif /* ndef SSL_H_INCLUDED */
index 4b3a2ac..c7844a7 100644 (file)
               <td>@if-FEATURE_GRACEFUL_TERMINATION-then@ Yes @else-not-FEATURE_GRACEFUL_TERMINATION@ No @endif-FEATURE_GRACEFUL_TERMINATION@</td>
               <td>Allows to shutdown Privoxy through the web interface.</td>
             </tr>
+            <tr>
+              <td><code>FEATURE_HTTPS_FILTERING</code></td>
+              <td>@if-FEATURE_HTTPS_FILTERING-then@ Yes @else-not-FEATURE_HTTPS_FILTERING@ No @endif-FEATURE_HTTPS_FILTERING@</td>
+              <td>Allows to intercept and filter HTTPS traffic.</td>
+            </tr>
             <tr>
               <td><code>FEATURE_IMAGE_BLOCKING</code></td>
               <td>@if-FEATURE_IMAGE_BLOCKING-then@ Yes @else-not-FEATURE_IMAGE_BLOCKING@ No @endif-FEATURE_IMAGE_BLOCKING@</td>
index 7e8eb8e..2277c12 100644 (file)
@@ -193,3 +193,12 @@ www.example.com/nasty-ads/sponsor.gif
 #
 #{+block{Facebook "like" and similar tracking URLs.}}
 #www.facebook.com/(extern|plugins)/(login_status|like(box)?|activity|fan)\.php
+
+######### Examples for SSL actions #########
+# Following section enables TLS/SSL filtering for all sites defined by pattern and requested by HTTPS.
+# {+enable-https-filtering}
+# privoxy.org
+
+# Following section turns off certificate verification for all sites defined by pattern.
+# {+ignore-certificate-errors}
+# privoxy.org
diff --git a/win32.c b/win32.c
index 370d2b3..ce024dd 100644 (file)
--- a/win32.c
+++ b/win32.c
@@ -65,7 +65,7 @@
  */
 const char win32_blurb[] =
 "Privoxy version " VERSION " for Windows\n"
-"Copyright (C) 2000-2010 the Privoxy Team (" HOME_PAGE_URL ")\n"
+"Copyright (C) 2000-2019 the Privoxy Team (" HOME_PAGE_URL ")\n"
 "Based on the Internet Junkbuster by Junkbusters Corp.\n"
 "This is free software; it may be used and copied under the\n"
 "GNU General Public License, version 2: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n"