Gracefully handle existing website keys without matching certificates
authorFabian Keil <fk@fabiankeil.de>
Thu, 17 Dec 2020 03:57:04 +0000 (04:57 +0100)
committerFabian Keil <fk@fabiankeil.de>
Thu, 17 Dec 2020 14:14:43 +0000 (15:14 +0100)
This can happen if Privoxy was previously running with an invalid
TLS configuration that didn't allow it to create a certificate.

The problem can be reproduced manually by removing or renaming a
certificate while keeping the key.

Previously this would result in a confusing client error messages:

    fk@t520 ~ $curl -v --head https://www.electrobsd.org/
    * Uses proxy env variable https_proxy == 'http://127.0.1.1:8118/'
    *   Trying 127.0.1.1:8118...
    * Connected to 127.0.1.1 (127.0.1.1) port 8118 (#0)
    * allocate connect buffer!
    * Establish HTTP proxy tunnel to www.electrobsd.org:443
    > CONNECT www.electrobsd.org:443 HTTP/1.1
    > Host: www.electrobsd.org:443
    > User-Agent: curl/7.72.0
    > Proxy-Connection: Keep-Alive
    >
    < HTTP/1.1 200 Connection established
    HTTP/1.1 200 Connection established
    <

    * Proxy replied 200 to CONNECT request
    * CONNECT phase completed!
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
    * successfully set certificate verify locations:
    *   CAfile: /usr/local/share/certs/ca-root-nss.crt
      CApath: none
    * TLSv1.2 (OUT), TLS header, Certificate Status (22):
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.electrobsd.org:443
    * Closing connection 0
    curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.electrobsd.org:443

While the Privoxy log would say something like:
04:53:53.932 099 Error: Subject key was already created
04:53:53.932 099 Error: Loading webpage certificate /usr/local/etc/privoxy/CA/certs/6db5da8a16c246d1bd8c0fa7cd160a5b.crt failed: error:02001002:system library:fopen:No such file or directory
04:53:53.932 099 Error: Loading webpage certificate /usr/local/etc/privoxy/CA/certs/6db5da8a16c246d1bd8c0fa7cd160a5b.crt failed: error:20074002:BIO routines:file_ctrl:system lib
04:53:53.933 099 Error: Loading webpage certificate /usr/local/etc/privoxy/CA/certs/6db5da8a16c246d1bd8c0fa7cd160a5b.crt failed: error:140AD002:SSL routines:SSL_CTX_use_certificate_file:system lib
04:53:53.933 099 Error: Failed to open a secure connection with the client

Instead of failing, just remove the key and continue.

openssl.c
ssl.c

index 72d97d9..e1655d8 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -1793,6 +1793,25 @@ static int generate_webpage_certificate(struct client_state *csp)
       }
    }
 
+   if (file_exists(cert_opt.output_file) == 0 &&
+       file_exists(cert_opt.subject_key) == 1)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "A website key already exists but there's no matching certificate. "
+         "Removing %s before creating a new key and certificate.",
+         cert_opt.subject_key);
+      if (unlink(cert_opt.subject_key))
+      {
+         log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E",
+            cert_opt.subject_key);
+
+         freez(cert_opt.output_file);
+         freez(cert_opt.subject_key);
+
+         return -1;
+      }
+   }
+
    /*
     * Create key for requested host
     */
diff --git a/ssl.c b/ssl.c
index 46b8fd4..13203de 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -1348,6 +1348,25 @@ static int generate_webpage_certificate(struct client_state *csp)
       }
    }
 
+   if (file_exists(cert_opt.output_file) == 0 &&
+       file_exists(cert_opt.subject_key) == 1)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "A website key already exists but there's no matching certificate. "
+         "Removing %s before creating a new key and certificate.",
+         cert_opt.subject_key);
+      if (unlink(cert_opt.subject_key))
+      {
+         log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E",
+            cert_opt.subject_key);
+
+         freez(cert_opt.output_file);
+         freez(cert_opt.subject_key);
+
+         return -1;
+      }
+   }
+
    /*
     * Create key for requested host
     */