From 3ab21dbaa4ca855e757002ba1cf0c87da76cbd95 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 18 May 2020 23:16:56 +0100 Subject: add subject alternative names to certificate viewer --- content/fetchers/about.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'content/fetchers/about.c') 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 @@ -460,6 +460,14 @@ struct ns_cert_pkey { char *public; }; +/** + * Certificate subject alternative name + */ +struct ns_cert_san { + struct ns_cert_san *next; + char *name; +}; + /** * certificate information for certificate chain */ @@ -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, + "\n" + "\n"); + if (res != NSERROR_OK) { + return res; + } + + while (san != NULL) { + res = ssenddataf(ctx, + "\n", + san->name); + if (res != NSERROR_OK) { + return res; + } + + san = san->next; + } + + res = ssenddataf(ctx, "
Alternative Names
DNS Name%s
\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; -- cgit v1.2.3