summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/fetchers/about.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 796b39091..b00e59d91 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -461,6 +461,14 @@ struct ns_cert_pkey {
};
/**
+ * Certificate subject alternative name
+ */
+struct ns_cert_san {
+ struct ns_cert_san *next;
+ char *name;
+};
+
+/**
* certificate information for certificate chain
*/
struct ns_cert_info {
@@ -475,6 +483,7 @@ struct ns_cert_info {
char *serialnum; /**< Serial number */
char *sha1fingerprint; /**< fingerprint shar1 encoded */
char *sha256fingerprint; /**< fingerprint shar256 encoded */
+ struct ns_cert_san *san; /**< subject alternative names */
ssl_cert_err err; /**< Whatever is wrong with this certificate */
};
@@ -483,6 +492,8 @@ struct ns_cert_info {
*/
static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
{
+ struct ns_cert_san *san;
+
free(cinfo->subject_name.common_name);
free(cinfo->subject_name.organisation);
free(cinfo->subject_name.organisation_unit);
@@ -504,6 +515,16 @@ static nserror free_ns_cert_info(struct ns_cert_info *cinfo)
free(cinfo->not_after);
free(cinfo->sig_algor);
free(cinfo->serialnum);
+
+ /* free san list avoiding use after free */
+ san = cinfo->san;
+ while (san != NULL) {
+ struct ns_cert_san *next;
+ next = san->next;
+ free(san);
+ san = next;
+ }
+
free(cinfo);
return NSERROR_OK;
@@ -917,6 +938,44 @@ pkey_to_info(EVP_PKEY *pkey, struct ns_cert_pkey *ikey)
return res;
}
+static nserror san_to_info(X509 *cert, struct ns_cert_san **prev_next)
+{
+ int idx;
+ int san_names_nb = -1;
+ const GENERAL_NAME *current_name;
+ const unsigned char *dns_name;
+ struct ns_cert_san *isan;
+
+ STACK_OF(GENERAL_NAME) *san_names = NULL;
+
+ san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names == NULL) {
+ return NSERROR_OK;
+ }
+
+ san_names_nb = sk_GENERAL_NAME_num(san_names);
+
+ /* Check each name within the extension */
+ for (idx = 0; idx < san_names_nb; idx++) {
+ current_name = sk_GENERAL_NAME_value(san_names, idx);
+
+ if (current_name->type == GEN_DNS) {
+ /* extract DNS name into info structure */
+ dns_name = ns_ASN1_STRING_get0_data(current_name->d.dNSName);
+
+ isan = malloc(sizeof(struct ns_cert_san));
+ if (isan != NULL) {
+ isan->name = strdup((const char *)dns_name);
+ isan->next = NULL;
+ *prev_next = isan;
+ prev_next = &isan->next;
+ }
+ }
+ }
+ sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+
+ return NSERROR_OK;
+}
static nserror
der_to_certinfo(const uint8_t *der,
@@ -1024,6 +1083,8 @@ der_to_certinfo(const uint8_t *der,
free(buff);
}
+ /* subject alternative names */
+ san_to_info(cert, &info->san);
/* issuer name */
xname_to_info(X509_get_issuer_name(cert), &info->issuer_name);
@@ -1138,6 +1199,43 @@ format_certificate_name(struct fetch_about_context *ctx,
return res;
}
+/**
+ * output formatted certificate subject alternate names
+ */
+static nserror
+format_certificate_san(struct fetch_about_context *ctx,
+ struct ns_cert_san *san)
+{
+ nserror res;
+
+ if (san == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = ssenddataf(ctx,
+ "<table class=\"info\">\n"
+ "<tr><th>Alternative Names</th><td><hr></td></tr>\n");
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ while (san != NULL) {
+ res = ssenddataf(ctx,
+ "<tr><th>DNS Name</th><td>%s</td></tr>\n",
+ san->name);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ san = san->next;
+ }
+
+ res = ssenddataf(ctx, "</table>\n");
+
+ return res;
+
+}
+
static nserror
format_certificate_public_key(struct fetch_about_context *ctx,
@@ -1322,6 +1420,11 @@ format_certificate(struct fetch_about_context *ctx,
return res;
}
+ res = format_certificate_san(ctx, cert_info->san);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
res = format_certificate_public_key(ctx, &cert_info->public_key);
if (res != NSERROR_OK) {
return res;