/*********************************************************************
-*
-* 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.
-*
-*********************************************************************/
+ *
+ * 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-2020 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>
#include "mbedtls/pem.h"
#include "mbedtls/base64.h"
#include "mbedtls/error.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/asn1write.h"
+#include "config.h"
#include "project.h"
#include "miscutil.h"
#include "errlog.h"
#include "jcc.h"
-#include "config.h"
#include "ssl.h"
#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_SUBJECT_PASSWORD ""
#define CERT_INFO_PREFIX ""
+/*
+ * 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;
-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);
+/*
+ * 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;
+
+static 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);
/*********************************************************************
-*
-* 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
-*
-*********************************************************************/
+ *
+ * Function : is_ssl_pending
+ *
+ * Description : Tests if there are some waiting 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)
send_len = (int)max_fragment_size;
}
+ log_error(LOG_LEVEL_WRITING, "TLS: %N", send_len, buf+pos);
+
/*
* Sending one part of the buffer
*/
{
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);
* 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.
+ * Returns : Number of bytes read, 0 for EOF, or -1
+ * on error.
*
*********************************************************************/
extern int ssl_recv_data(mbedtls_ssl_context *ssl, unsigned char *buf, size_t max_length)
{
char err_buf[ERROR_BUF_SIZE];
- memset(err_buf, 0, sizeof(err_buf));
+ if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "The peer notified us that the connection is going to be closed");
+ return 0;
+ }
mbedtls_strerror(ret, err_buf, sizeof(err_buf));
log_error(LOG_LEVEL_ERROR,
"Receiving data over TLS/SSL failed: %s", err_buf);
+
+ return -1;
}
+ log_error(LOG_LEVEL_RECEIVED, "TLS: %N", ret, buf);
+
return ret;
}
int ret = 0;
char err_buf[ERROR_BUF_SIZE];
- memset(err_buf, 0, sizeof(err_buf));
-
/*
* Initializing mbedtls structures for TLS/SSL connection
*/
* 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]));
+ privoxy_mutex_lock(&certificate_mutex);
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]));
+ privoxy_mutex_unlock(&certificate_mutex);
ret = -1;
goto exit;
}
- privoxy_mutex_unlock(&(certificates_mutexes[cert_mutex_id]));
+ privoxy_mutex_unlock(&certificate_mutex);
/*
* Seed the RNG
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;
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));
+ mbedtls_x509_crt_init(&(csp->mbedtls_server_attr.ca_cert));
/*
* Setting socket fd in mbedtls_net_context structure. This structure
* Handshake with server
*/
log_error(LOG_LEVEL_CONNECT,
- "Performing the TLS/SSL handshake with server");
+ "Performing the TLS/SSL handshake with the server");
while ((ret = mbedtls_ssl_handshake(&(csp->mbedtls_server_attr.ssl))) != 0)
{
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED)
{
- log_error(LOG_LEVEL_ERROR,
- "Server certificate verification failed: %s", err_buf);
+ char reason[INVALID_CERT_INFO_BUF_SIZE];
+
csp->server_cert_verification_result =
mbedtls_ssl_get_verify_result(&(csp->mbedtls_server_attr.ssl));
+ mbedtls_x509_crt_verify_info(reason, sizeof(reason), "",
+ csp->server_cert_verification_result);
+ /* Log the reason without the trailing new line */
+ log_error(LOG_LEVEL_ERROR,
+ "X509 certificate verification for %s failed: %N",
+ csp->http->hostport, strlen(reason)-1, reason);
ret = -1;
}
else
* 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;
+ csp->mbedtls_server_attr.socket_fd.fd = -1;
mbedtls_x509_crt_free(&(csp->mbedtls_server_attr.ca_cert));
mbedtls_ssl_free(&(csp->mbedtls_server_attr.ssl));
/*********************************************************************
+ *
* Function : close_client_and_server_ssl_connections
*
* Description : Checks if client or server should use secured
/*====================== Certificates ======================*/
/*********************************************************************
+ *
* Function : write_certificate
*
* Description : Writes certificate into file.
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
+ * Writing certificate into PEM string. If buffer is too small, function
* returns specific error and no buffer overflow can happen.
*/
if ((ret = mbedtls_x509write_crt_pem(crt, cert_buf,
/*********************************************************************
+ *
* Function : write_private_key
*
* Description : Writes private key into file and copies saved
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);
+ *ret_buf = zalloc_or_die(PRIVATE_KEY_BUF_SIZE + 1);
/*
* Writing private key into PEM string
/*********************************************************************
+ *
* Function : generate_key
*
* Description : Tests if private key for host saved in csp already
* 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...)
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : key_buf = buffer to save new generated key
*
* 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)
+static int generate_key(struct client_state *csp, unsigned char **key_buf)
{
mbedtls_pk_context key;
key_options key_opt;
char err_buf[ERROR_BUF_SIZE];
key_opt.key_file_path = NULL;
- memset(err_buf, 0, sizeof(err_buf));
/*
* Initializing structures for key generating
}
+/*********************************************************************
+ *
+ * Function : ssl_certificate_is_invalid
+ *
+ * Description : Checks whether or not a certificate is valid.
+ * Currently only checks that the certificate can be
+ * parsed and that the "valid to" date is in the future.
+ *
+ * Parameters :
+ * 1 : cert_file = The certificate to check
+ *
+ * Returns : 0 => The certificate is valid.
+ * 1 => The certificate is invalid
+ *
+ *********************************************************************/
+static int ssl_certificate_is_invalid(const char *cert_file)
+{
+ mbedtls_x509_crt cert;
+ int ret;
+
+ mbedtls_x509_crt_init(&cert);
+
+ ret = mbedtls_x509_crt_parse_file(&cert, cert_file);
+ if (ret != 0)
+ {
+ char err_buf[ERROR_BUF_SIZE];
+
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "Loading certificate %s to check validity failed: %s",
+ cert_file, err_buf);
+ mbedtls_x509_crt_free(&cert);
+
+ return 1;
+ }
+ if (mbedtls_x509_time_is_past(&cert.valid_to))
+ {
+ mbedtls_x509_crt_free(&cert);
+
+ return 1;
+ }
+
+ mbedtls_x509_crt_free(&cert);
+
+ return 0;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : generate_certificate_valid_date
+ *
+ * Description : Turns a time_t into the format expected by mbedTLS.
+ *
+ * Parameters :
+ * 1 : time_spec = The timestamp to convert
+ * 2 : buffer = The buffer to write the date to
+ * 3 : buffer_size = The size of the buffer
+ *
+ * Returns : 0 => The conversion worked
+ * 1 => The conversion failed
+ *
+ *********************************************************************/
+static int generate_certificate_valid_date(time_t time_spec, char *buffer,
+ size_t buffer_size)
+{
+ struct tm valid_date;
+ size_t ret;
+
+#ifndef HAVE_GMTIME_R
+#error HTTP inspection currently requires gmtime_r() which seems to be missing
+#endif
+ if (NULL == gmtime_r(&time_spec, &valid_date))
+ {
+ return 1;
+ }
+
+ ret = strftime(buffer, buffer_size, "%Y%m%d%H%M%S", &valid_date);
+ if (ret != 14)
+ {
+ return 1;
+ }
+
+ return 0;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : get_certificate_valid_from_date
+ *
+ * Description : Generates a "valid from" date in the format
+ * expected by mbedTLS.
+ *
+ * Parameters :
+ * 1 : buffer = The buffer to write the date to
+ * 2 : buffer_size = The size of the buffer
+ *
+ * Returns : 0 => The generation worked
+ * 1 => The generation failed
+ *
+ *********************************************************************/
+static int get_certificate_valid_from_date(char *buffer, size_t buffer_size)
+{
+ time_t time_spec;
+
+ time_spec = time(NULL);
+ /* 1 month in the past */
+ time_spec -= 30 * 24 * 60 * 60;
+
+ return generate_certificate_valid_date(time_spec, buffer, buffer_size);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : get_certificate_valid_to_date
+ *
+ * Description : Generates a "valid to" date in the format
+ * expected by mbedTLS.
+ *
+ * Parameters :
+ * 1 : buffer = The buffer to write the date to
+ * 2 : buffer_size = The size of the buffer
+ *
+ * Returns : 0 => The generation worked
+ * 1 => The generation failed
+ *
+ *********************************************************************/
+static int get_certificate_valid_to_date(char *buffer, size_t buffer_size)
+{
+ time_t time_spec;
+
+ time_spec = time(NULL);
+ /* Three months in the future */
+ time_spec += 90 * 24 * 60 * 60;
+
+ return generate_certificate_valid_date(time_spec, buffer, buffer_size);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : set_subject_alternative_name
+ *
+ * Description : Sets the Subject Alternative Name extension to a cert
+ *
+ * Parameters :
+ * 1 : cert = The certificate to modify
+ * 2 : hostname = The hostname to add
+ *
+ * Returns : <0 => Error while creating certificate.
+ * 0 => It worked
+ *
+ *********************************************************************/
+static int set_subject_alternative_name(mbedtls_x509write_cert *cert, const char *hostname)
+{
+ char err_buf[ERROR_BUF_SIZE];
+ int ret;
+ char *subject_alternative_name;
+ size_t subject_alternative_name_len;
+#define MBEDTLS_SUBJECT_ALTERNATIVE_NAME_MAX_LEN 255
+ unsigned char san_buf[MBEDTLS_SUBJECT_ALTERNATIVE_NAME_MAX_LEN + 1];
+ unsigned char *c;
+ int len;
+
+ subject_alternative_name_len = strlen(hostname) + 1;
+ subject_alternative_name = zalloc_or_die(subject_alternative_name_len);
+
+ strlcpy(subject_alternative_name, hostname, subject_alternative_name_len);
+
+ memset(san_buf, 0, sizeof(san_buf));
+
+ c = san_buf + sizeof(san_buf);
+ len = 0;
+
+ ret = mbedtls_asn1_write_raw_buffer(&c, san_buf,
+ (const unsigned char *)subject_alternative_name,
+ strlen(subject_alternative_name));
+ if (ret < 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "mbedtls_asn1_write_raw_buffer() failed: %s", err_buf);
+ goto exit;
+ }
+ len += ret;
+
+ ret = mbedtls_asn1_write_len(&c, san_buf, strlen(subject_alternative_name));
+ if (ret < 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "mbedtls_asn1_write_len() failed: %s", err_buf);
+ goto exit;
+ }
+ len += ret;
+
+ ret = mbedtls_asn1_write_tag(&c, san_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2);
+ if (ret < 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "mbedtls_asn1_write_tag() failed: %s", err_buf);
+ goto exit;
+ }
+ len += ret;
+
+ ret = mbedtls_asn1_write_len(&c, san_buf, (size_t)len);
+ if (ret < 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "mbedtls_asn1_write_len() failed: %s", err_buf);
+ goto exit;
+ }
+ len += ret;
+
+ ret = mbedtls_asn1_write_tag(&c, san_buf,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (ret < 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "mbedtls_asn1_write_tag() failed: %s", err_buf);
+ goto exit;
+ }
+ len += ret;
+
+ ret = mbedtls_x509write_crt_set_extension(cert,
+ MBEDTLS_OID_SUBJECT_ALT_NAME,
+ MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
+ 0, san_buf + sizeof(san_buf) - len, (size_t)len);
+ if (ret < 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR,
+ "mbedtls_x509write_crt_set_extension() failed: %s", err_buf);
+ }
+
+exit:
+ freez(subject_alternative_name);
+
+ return ret;
+
+}
+
/*********************************************************************
*
* Function : generate_webpage_certificate
* 1 : csp = Current client state (buffers, headers, etc...)
*
* Returns : -1 => Error while creating certificate.
- * 0 => Certificate alreaday exist.
+ * 0 => Certificate already exists.
* >0 => Length of created certificate.
*
*********************************************************************/
-extern int generate_webpage_certificate(struct client_state * csp)
+static int generate_webpage_certificate(struct client_state *csp)
{
mbedtls_x509_crt issuer_cert;
mbedtls_pk_context loaded_issuer_key, loaded_subject_key;
int ret = 0;
char err_buf[ERROR_BUF_SIZE];
cert_options cert_opt;
-
- memset(err_buf, 0, sizeof(err_buf));
+ char cert_valid_from[15];
+ char cert_valid_to[15];
/* 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;
+
+ 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.output_file == NULL)
+ {
+ return -1;
+ }
+
+ cert_opt.subject_key = make_certs_path(csp->config->certificate_directory,
+ (const char *)csp->http->hash_of_host_hex, KEY_FILE_TYPE);
+ if (cert_opt.subject_key == NULL)
+ {
+ freez(cert_opt.output_file);
+ return -1;
+ }
+
+ if (file_exists(cert_opt.output_file) == 1)
+ {
+ /* The file exists, but is it valid? */
+ if (ssl_certificate_is_invalid(cert_opt.output_file))
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "Certificate %s is no longer valid. Removing it.",
+ cert_opt.output_file);
+ if (unlink(cert_opt.output_file))
+ {
+ log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E",
+ cert_opt.output_file);
+
+ freez(cert_opt.output_file);
+ freez(cert_opt.subject_key);
+
+ return -1;
+ }
+ 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;
+ }
+ }
+ else
+ {
+ freez(cert_opt.output_file);
+ freez(cert_opt.subject_key);
+
+ return 0;
+ }
+ }
/*
* Create key for requested host
*/
- int subject_key_len = generate_key(&key_buf, csp);
+ int subject_key_len = generate_key(csp, &key_buf);
if (subject_key_len < 0)
{
+ freez(cert_opt.output_file);
+ freez(cert_opt.subject_key);
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_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);
* 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;
+ unsigned long certificate_serial_time = (unsigned long)time(NULL);
+ int serial_num_size = snprintf(NULL, 0, "%lu%lu",
+ certificate_serial_time, 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);
+ ret = snprintf(serial_num_text, (size_t)serial_num_size, "%lu%lu",
+ certificate_serial_time, certificate_serial);
if (ret < 0 || ret >= serial_num_size)
{
log_error(LOG_LEVEL_ERROR,
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)
+ if (get_certificate_valid_from_date(cert_valid_from, sizeof(cert_valid_from))
+ || get_certificate_valid_to_date(cert_valid_to, sizeof(cert_valid_to)))
{
+ log_error(LOG_LEVEL_ERROR, "Generating one of the validity dates failed");
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.not_before = cert_valid_from;
+ cert_opt.not_after = 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
+ * Test if the private key was already created.
+ * XXX: Can this still happen?
*/
- if (file_exists(cert_opt.output_file) == 1 && subject_key_len == 0)
+ if (subject_key_len == 0)
{
+ log_error(LOG_LEVEL_ERROR, "Subject key was already created");
ret = 0;
goto exit;
}
sizeof(cert_opt.issuer_name), &issuer_cert.subject);
if (ret < 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ 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;
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)
+ 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 = mbedtls_x509write_crt_set_subject_name(&cert, cert_opt.subject_name);
if (ret != 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ 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;
ret = mbedtls_x509write_crt_set_issuer_name(&cert, cert_opt.issuer_name);
if (ret != 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ 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;
cert_opt.not_after);
if (ret != 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
log_error(LOG_LEVEL_ERROR,
"Setting validity in signed certificate failed: %s", err_buf);
ret = -1;
cert_opt.max_pathlen);
if (ret != 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ 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;
ret = mbedtls_x509write_crt_set_subject_key_identifier(&cert);
if (ret != 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ 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;
ret = mbedtls_x509write_crt_set_authority_key_identifier(&cert);
if (ret != 0)
{
- mbedtls_strerror( ret, err_buf, sizeof(err_buf));
+ 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;
}
#endif /* MBEDTLS_SHA1_C */
+ if (set_subject_alternative_name(&cert, csp->http->host))
+ {
+ /* Errors are already logged by set_subject_alternative_name() */
+ ret = -1;
+ goto exit;
+ }
+
/*
* Writing certificate into file
*/
*
* Function : make_certs_path
*
- * Description : Creates path to file from three pieces. This fuction
+ * Description : Creates path to file from three pieces. This function
* 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
* 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);
+ path = zalloc_or_die(path_size);
strlcpy(path, basedir, path_size);
strlcat(path, delim, 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);
+ path = zalloc_or_die(path_size);
strlcpy(path, conf_dir, path_size);
strlcat(path, delim, path_size);
}
-/*********************************************************************
- *
- * 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
* Returns : Serial number for new certificate
*
*********************************************************************/
-static unsigned long get_certificate_serial(struct client_state *csp) {
+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--)
{
"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: ";
+ "<html><body><h1>Server certificate verification failed</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));
*/
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);
}
/*
* 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);
- }
+ last->next = malloc_or_die(sizeof(struct certs_chain));
+ 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 information into buffer
- */
- mbedtls_x509_crt_info(last->text_buf, sizeof(last->text_buf) - 1,
- CERT_INFO_PREFIX, crt);
- }
- else
+ /*
+ * 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)
{
- log_error(LOG_LEVEL_ERROR,
- "Malloc memory for server certificate informations failed");
- return -1;
+ return(ret);
}
+ /*
+ * Saving certificate information into buffer
+ */
+ mbedtls_x509_crt_info(last->text_buf, sizeof(last->text_buf) - 1,
+ CERT_INFO_PREFIX, crt);
+
return 0;
}
/* 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,
+ memset(csp->server_certs_chain.file_buf, 0,
sizeof(csp->server_certs_chain.file_buf));
csp->server_certs_chain.next = 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.
-*
-*********************************************************************/
+ *
+ * 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;
/*********************************************************************
-*
-* 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)
+ *
+ * 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;
+#error mbedTLS needs to be compiled with md5 support
#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),
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);