summaryrefslogtreecommitdiff
path: root/desktop/sslcert_viewer.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2020-02-23 16:06:52 +0000
committerVincent Sanders <vince@kyllikki.org>2020-02-23 16:23:50 +0000
commit0c34d06494afe217ace7460c66df800d457dd2e8 (patch)
tree17cc135e3513e7235421502e2e58a2f44ff1a137 /desktop/sslcert_viewer.c
parent214478fc15a2b9ee67e19e08cf27657c0157037a (diff)
downloadnetsurf-0c34d06494afe217ace7460c66df800d457dd2e8.tar.gz
netsurf-0c34d06494afe217ace7460c66df800d457dd2e8.tar.bz2
Keep the complete certificate chain from a fetch
Instead of extracting information from the X509 certificate chain in the fetcher the entire chain is propagated in Distinguished Encoding Rules (DER) format. This allows all the information contained in a certificate chain to be retained which can subsequently be presented to the user
Diffstat (limited to 'desktop/sslcert_viewer.c')
-rw-r--r--desktop/sslcert_viewer.c184
1 files changed, 172 insertions, 12 deletions
diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c
index 4d8725757..ec0fd3431 100644
--- a/desktop/sslcert_viewer.c
+++ b/desktop/sslcert_viewer.c
@@ -52,6 +52,21 @@ enum sslcert_viewer_field {
typedef nserror (*response_cb)(bool proceed, void *pw);
/**
+ * ssl certificate information for certificate error message
+ */
+struct ssl_cert_info {
+ long version; /**< Certificate version */
+ char not_before[32]; /**< Valid from date */
+ char not_after[32]; /**< Valid to date */
+ int sig_type; /**< Signature type */
+ char serialnum[64]; /**< Serial number */
+ char issuer[256]; /**< Issuer details */
+ char subject[256]; /**< Subject details */
+ int cert_type; /**< Certificate type */
+ ssl_cert_err err; /**< Whatever is wrong with this certificate */
+};
+
+/**
* ssl certificate verification context.
*/
struct sslcert_session_data {
@@ -473,38 +488,183 @@ nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d)
return err;
}
+#ifdef WITH_OPENSSL
+
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+static nserror
+der_to_certinfo(const uint8_t *der,
+ size_t der_length,
+ struct ssl_cert_info *info)
+{
+ BIO *mem;
+ BUF_MEM *buf;
+ const ASN1_INTEGER *asn1_num;
+ BIGNUM *bignum;
+ X509 *cert; /**< Pointer to certificate */
+
+ if (der == NULL) {
+ return NSERROR_OK;
+ }
+
+ cert = d2i_X509(NULL, &der, der_length);
+ if (cert == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ /* get certificate version */
+ info->version = X509_get_version(cert);
+
+ /* not before date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem, X509_get_notBefore(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ memcpy(info->not_before,
+ buf->data,
+ min(sizeof(info->not_before) - 1, (unsigned)buf->length));
+ info->not_before[min(sizeof(info->not_before) - 1, (unsigned)buf->length)] = 0;
+ BUF_MEM_free(buf);
+
+ /* not after date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem,
+ X509_get_notAfter(cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ memcpy(info->not_after,
+ buf->data,
+ min(sizeof(info->not_after) - 1, (unsigned)buf->length));
+ info->not_after[min(sizeof(info->not_after) - 1, (unsigned)buf->length)] = 0;
+ BUF_MEM_free(buf);
+
+ /* signature type */
+ info->sig_type = X509_get_signature_type(cert);
+
+ /* serial number */
+ asn1_num = X509_get_serialNumber(cert);
+ if (asn1_num != NULL) {
+ bignum = ASN1_INTEGER_to_BN(asn1_num, NULL);
+ if (bignum != NULL) {
+ char *tmp = BN_bn2hex(bignum);
+ if (tmp != NULL) {
+ strncpy(info->serialnum,
+ tmp,
+ sizeof(info->serialnum));
+ info->serialnum[sizeof(info->serialnum)-1] = '\0';
+ OPENSSL_free(tmp);
+ }
+ BN_free(bignum);
+ bignum = NULL;
+ }
+ }
+
+ /* issuer name */
+ mem = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(mem,
+ X509_get_issuer_name(cert),
+ 0, XN_FLAG_SEP_CPLUS_SPC |
+ XN_FLAG_DN_REV | XN_FLAG_FN_NONE);
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ memcpy(info->issuer,
+ buf->data,
+ min(sizeof(info->issuer) - 1, (unsigned) buf->length));
+ info->issuer[min(sizeof(info->issuer) - 1, (unsigned) buf->length)] = 0;
+ BUF_MEM_free(buf);
+
+ /* subject */
+ mem = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(mem,
+ X509_get_subject_name(cert),
+ 0,
+ XN_FLAG_SEP_CPLUS_SPC |
+ XN_FLAG_DN_REV |
+ XN_FLAG_FN_NONE);
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ memcpy(info->subject,
+ buf->data,
+ min(sizeof(info->subject) - 1, (unsigned)buf->length));
+ info->subject[min(sizeof(info->subject) - 1, (unsigned) buf->length)] = 0;
+ BUF_MEM_free(buf);
+
+ /* type of certificate */
+ info->cert_type = X509_certificate_type(cert, X509_get_pubkey(cert));
+
+ X509_free(cert);
+
+ return NSERROR_OK;
+}
+#else
+static nserror
+der_to_certinfo(uint8_t *der, size_t der_length, struct ssl_cert_info *info)
+{
+ return NSERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+/* copy certificate data */
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+ struct ssl_cert_info **cert_info_out)
+{
+ struct ssl_cert_info *certs;
+ size_t depth;
+ nserror res;
+
+ certs = calloc(chain->depth, sizeof(struct ssl_cert_info));
+ if (certs == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ for (depth = 0; depth < chain->depth;depth++) {
+ res = der_to_certinfo(chain->certs[depth].der,
+ chain->certs[depth].der_length,
+ certs + depth);
+ if (res != NSERROR_OK) {
+ free(certs);
+ return res;
+ }
+ certs[depth].err = chain->certs[depth].err;
+ }
+
+ *cert_info_out = certs;
+ return NSERROR_OK;
+}
/* Exported interface, documented in sslcert_viewer.h */
nserror
-sslcert_viewer_create_session_data(unsigned long num,
- struct nsurl *url,
+sslcert_viewer_create_session_data(struct nsurl *url,
nserror (*cb)(bool proceed, void *pw),
void *cbpw,
- const struct ssl_cert_info *certs,
+ const struct cert_chain *chain,
struct sslcert_session_data **ssl_d)
{
struct sslcert_session_data *data;
-
+ nserror res;
assert(url != NULL);
- assert(certs != NULL);
+ assert(chain != NULL);
data = malloc(sizeof(struct sslcert_session_data));
if (data == NULL) {
*ssl_d = NULL;
return NSERROR_NOMEM;
}
-
- /* copy certificate data */
- data->certs = malloc(num * sizeof(struct ssl_cert_info));
- if (data->certs == NULL) {
+ res = convert_chain_to_cert_info(chain, &data->certs);
+ if (res != NSERROR_OK) {
free(data);
*ssl_d = NULL;
- return NSERROR_NOMEM;
+ return res;
}
- memcpy(data->certs, certs, num * sizeof(struct ssl_cert_info));
data->url = nsurl_ref(url);
- data->num = num;
+ data->num = chain->depth;
data->cb = cb;
data->cbpw = cbpw;