+/*********************************************************************
+ *
+ * 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;
+ struct tm *timeptr;
+ size_t ret;
+
+ timeptr = privoxy_gmtime_r(&time_spec, &valid_date);
+ if (NULL == timeptr)
+ {
+ return 1;
+ }
+
+ ret = strftime(buffer, buffer_size, "%Y%m%d%H%M%S", timeptr);
+ 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 : host_is_ip_address
+ *
+ * Description : Checks whether or not a host is specified by
+ * IP address. Does not actually validate the
+ * address.
+ *
+ * Parameters :
+ * 1 : host = The host name to check
+ *
+ * Returns : 1 => Yes
+ * 0 => No
+ *
+ *********************************************************************/
+static int host_is_ip_address(const char *host)
+{
+ const char *p;
+
+ if (NULL != strstr(host, ":"))
+ {
+ /* Assume an IPv6 address. */
+ return 1;
+ }
+
+ for (p = host; *p; p++)
+ {
+ if ((*p != '.') && !privoxy_isdigit(*p))
+ {
+ /* Not a dot or digit so it can't be an IPv4 address. */
+ return 0;
+ }
+ }
+
+ /*
+ * Host only consists of dots and digits so
+ * assume that is an IPv4 address.
+ */
+ return 1;
+
+}
+
+