* not depend on particular TLS/SSL library.
*
* Copyright : Written by and Copyright (c) 2017 Vaclav Svec. FIT CVUT.
- * Copyright (C) 2018-2020 by Fabian Keil <fk@fabiankeil.de>
+ * Copyright (C) 2018-2021 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
#include <string.h>
#include <ctype.h>
+#include <unistd.h>
#include "config.h"
#include "project.h"
#include "miscutil.h"
/* Cleaning buffers */
memset(csp->server_certs_chain.info_buf, 0,
sizeof(csp->server_certs_chain.info_buf));
- memset(csp->server_certs_chain.file_buf, 0,
- sizeof(csp->server_certs_chain.file_buf));
+ freez(csp->server_certs_chain.file_buf);
+
csp->server_certs_chain.next = NULL;
/* Freeing memory in whole linked list */
{
struct certs_chain *cert_for_free = cert;
cert = cert->next;
+
+ /* Cleaning buffers */
+ memset(cert_for_free->info_buf, 0, sizeof(cert_for_free->info_buf));
+ freez(cert_for_free->file_buf);
+
freez(cert_for_free);
}
}
size_t message_len = 0;
int ret = 0;
struct certs_chain *cert = NULL;
+ const size_t head_length = 63;
/* Header of message with certificate information */
const char message_begin[] =
- "HTTP/1.1 200 OK\r\n"
+ "HTTP/1.1 403 Certificate validation failed\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n"
"<!DOCTYPE html>\n"
"<p><a href=\"https://" CGI_SITE_2_HOST "/\">Privoxy</a> was unable "
"to securely connect to the destination server.</p>"
"<p>Reason: ";
- const char message_end[] = "</body></html>\r\n\r\n";
+ const char message_end[] = "</body></html>\n";
char reason[INVALID_CERT_INFO_BUF_SIZE];
memset(reason, 0, sizeof(reason));
cert = &(csp->server_certs_chain);
while (cert->next != NULL)
{
- size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
+ size_t base64_len;
+
+ if (cert->file_buf != NULL)
+ {
+ base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
- message_len += strlen(cert->info_buf) + strlen("<pre></pre>\n")
- + base64_len + strlen("<a href=\"data:application"
- "/x-x509-ca-cert;base64,\">Download certificate</a>");
+ message_len += strlen(cert->info_buf) + strlen("<pre></pre>\n")
+ + base64_len + strlen("<a href=\"data:application"
+ "/x-x509-ca-cert;base64,\">Download certificate</a>");
+ }
+ else
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Incomplete certificate information for %s.",
+ csp->http->hostport);
+ }
cert = cert->next;
}
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 = ssl_base64_encode((unsigned char*)base64_buf,
- base64_len, &olen, (const unsigned char*)cert->file_buf,
- strlen(cert->file_buf));
- if (ret != 0)
+ if (cert->file_buf != NULL)
{
- log_error(LOG_LEVEL_ERROR,
- "Encoding to base64 failed, buffer is to small");
+ /* +1 for terminating null */
+ size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
+ size_t olen = 0;
+ char base64_buf[base64_len];
+
+ memset(base64_buf, 0, base64_len);
+
+ /* Encoding certificate into base64 code */
+ ret = ssl_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->info_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);
+ }
}
- strlcat(message, "<pre>", message_len);
- strlcat(message, cert->info_buf, message_len);
- strlcat(message, "</pre>\n", message_len);
+ cert = cert->next;
+ }
+ strlcat(message, message_end, message_len);
- if (ret == 0)
+ if (0 == strcmpic(csp->http->gpc, "HEAD"))
+ {
+ /* Cut off body */
+ char *header_end = strstr(message, "\r\n\r\n");
+ if (header_end != NULL)
{
- 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);
+ header_end[3] = '\0';
}
-
- cert = cert->next;
}
- strlcat(message, message_end, message_len);
/*
* Sending final message to client
*/
- ssl_send_data(ssl_attr, (const unsigned char *)message, strlen(message));
+ (void)ssl_send_data(ssl_attr, (const unsigned char *)message, strlen(message));
free_certificate_chain(csp);
+
+ log_error(LOG_LEVEL_CRUNCH, "Certificate error: %s: https://%s%s",
+ reason, csp->http->hostport, csp->http->path);
+ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" 403 %lu",
+ csp->ip_addr_str, csp->http->gpc, csp->http->hostport, csp->http->path,
+ csp->http->version, message_len-head_length);
+
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+ csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
+#endif
}
+ strlen(file_name) + strlen(suffix) + 2;
/* Setting delimiter and editing path length */
-#if defined(_WIN32) || defined(__OS2__)
+#if defined(_WIN32)
char delim[] = "\\";
path_size += 1;
-#else /* ifndef _WIN32 || __OS2__ */
+#else /* ifndef _WIN32 */
char delim[] = "/";
-#endif /* ifndef _WIN32 || __OS2__ */
+#endif /* ifndef _WIN32 */
/*
* Building up path from many parts
/*********************************************************************
*
- * Function : host_is_ip_address
+ * Function : enforce_sane_certificate_state
*
- * Description : Checks whether or not a host is specified by
- * IP address. Does not actually validate the
- * address.
+ * Description : Makes sure the certificate state is sane.
*
* Parameters :
- * 1 : host = The host name to check
+ * 1 : certificate = Path to the potentionally existing certifcate.
+ * 2 : key = Path to the potentionally existing key.
*
- * Returns : 1 => Yes
- * 0 => No
+ * Returns : -1 => Error
+ * 0 => Certificate state is sane
*
*********************************************************************/
-extern int host_is_ip_address(const char *host)
+extern int enforce_sane_certificate_state(const char *certificate, const char *key)
{
- const char *p;
+ const int certificate_exists = file_exists(certificate);
+ const int key_exists = file_exists(key);
- if (NULL != strstr(host, ":"))
+ if (!certificate_exists && key_exists)
{
- /* Assume an IPv6 address. */
- return 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.", key);
+ if (unlink(key))
+ {
+ log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E", key);
- for (p = host; *p; p++)
+ return -1;
+ }
+ }
+ if (certificate_exists && !key_exists)
{
- if ((*p != '.') && !privoxy_isdigit(*p))
+ log_error(LOG_LEVEL_ERROR,
+ "A certificate exists but there's no matching key. "
+ "Removing %s before creating a new key and certificate.", certificate);
+ if (unlink(certificate))
{
- /* Not a dot or digit so it can't be an IPv4 address. */
- return 0;
+ log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E", certificate);
+
+ return -1;
}
}
- /*
- * Host only consists of dots and digits so
- * assume that is an IPv4 address.
- */
- return 1;
+ return 0;
}