#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"
}
+/*********************************************************************
+ *
+ * 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
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(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;
}
* 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)
- {
- ret = -1;
- goto exit;
- }
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)))
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)
{
- /* 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.",
- cert_opt.output_file);
- if (unlink(cert_opt.output_file))
- {
- log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E",
- cert_opt.output_file);
- ret = -1;
- goto exit;
- }
- }
- else
- {
- ret = 0;
- goto exit;
- }
+ log_error(LOG_LEVEL_ERROR, "Subject key was already created");
+ ret = 0;
+ goto exit;
}
/*
}
#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
*/
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--)
{