Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/f172a21df9e5e5e73379a4a700957e965d872d3c
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/f172a21df9e5e5e73379a4a700957e965d872d3c
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/f172a21df9e5e5e73379a4a700957e965d872d3c

The branch, master has been updated
       via  f172a21df9e5e5e73379a4a700957e965d872d3c (commit)
      from  5c205fbff0a307bf04439ed884b5c294873ef1f2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=f172a21df9e5e5e73379a4a700957e965d872d3c
commit f172a21df9e5e5e73379a4a700957e965d872d3c
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    about scheme certificate viewer initial implementation

diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 0e85eff..c140fde 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -261,7 +261,7 @@ static bool fetch_about_licence_handler(struct 
fetch_about_context *ctx)
 
 
 /**
- * Handler to generate about:cache page.
+ * Handler to generate about:imagecache page.
  *
  * Shows details of current image cache.
  *
@@ -396,6 +396,276 @@ fetch_about_imagecache_handler_aborted:
 
 
 /**
+ * ssl certificate information for certificate chain
+ */
+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 */
+};
+
+#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;
+}
+
+/* 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;
+}
+
+#else
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+                          struct ssl_cert_info **cert_info_out)
+{
+       return NSERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+
+/**
+ * Handler to generate about:certificate page.
+ *
+ * Shows details of a certificate chain
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
+{
+       int code = 200;
+       nserror res;
+       struct cert_chain *chain = NULL;
+
+
+       /* content is going to return ok */
+       fetch_set_http_code(ctx->fetchh, code);
+
+       /* content type */
+       if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+               goto fetch_about_certificate_handler_aborted;
+
+       /* page head */
+       res = ssenddataf(ctx,
+                        "<html>\n<head>\n"
+                       "<title>NetSurf Browser Certificate Viewer</title>\n"
+                       "<link rel=\"stylesheet\" type=\"text/css\" "
+                       "href=\"resource:internal.css\">\n"
+                       "</head>\n"
+                       "<body id =\"certificate\">\n"
+                       "<p class=\"banner\">"
+                       "<a href=\"http://www.netsurf-browser.org/\";>"
+                       "<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>"
+                       "</p>\n"
+                       "<h1>NetSurf Browser Certificate Viewer</h1>\n");
+       if (res != NSERROR_OK) {
+               goto fetch_about_certificate_handler_aborted;
+       }
+
+       res = cert_chain_from_query(ctx->url, &chain);
+       if (res != NSERROR_OK) {
+               res = ssenddataf(ctx, "<p>Could not process that</p>\n");
+               if (res != NSERROR_OK) {
+                       goto fetch_about_certificate_handler_aborted;
+               }
+       } else {
+               struct ssl_cert_info *cert_info;
+               res = convert_chain_to_cert_info(chain, &cert_info);
+               if (res == NSERROR_OK) {
+                       size_t depth;
+                       for (depth = 0; depth < chain->depth; depth++) {
+                               res = ssenddataf(ctx,
+                                                "<h2>Certificate: %d</h2>\n"
+                                                "<p>Subject: %s</p>"
+                                                "<p>Serial Number: %s</p>"
+                                                "<p>Type: %i</p>"
+                                                "<p>Version: %ld</p>"
+                                                "<p>Issuer: %s</p>"
+                                                "<p>Valid From: %s</p>"
+                                                "<p>Valid Untill: %s</p>",
+                                                depth,
+                                                cert_info[depth].subject,
+                                                cert_info[depth].serialnum,
+                                                cert_info[depth].cert_type,
+                                                cert_info[depth].version,
+                                                cert_info[depth].issuer,
+                                                cert_info[depth].not_before,
+                                                cert_info[depth].not_after);
+                               if (res != NSERROR_OK) {
+                                       goto 
fetch_about_certificate_handler_aborted;
+                               }
+
+                       }
+                       free(cert_info);
+               } else {
+                       res = ssenddataf(ctx,
+                                        "<p>Invalid certificate data</p>\n");
+                       if (res != NSERROR_OK) {
+                               goto fetch_about_certificate_handler_aborted;
+                       }
+               }
+       }
+
+
+       /* page footer */
+       res = ssenddataf(ctx, "</body>\n</html>\n");
+       if (res != NSERROR_OK) {
+               goto fetch_about_certificate_handler_aborted;
+       }
+
+       fetch_about_send_finished(ctx);
+
+       cert_chain_free(chain);
+
+       return true;
+
+fetch_about_certificate_handler_aborted:
+       cert_chain_free(chain);
+       return false;
+}
+
+
+/**
  * Handler to generate about scheme config page
  *
  * \param ctx The fetcher context.
@@ -1383,6 +1653,14 @@ struct about_handlers about_handler_list[] = {
                true
        },
        {
+               /* details about a certificate */
+               "certificate",
+               SLEN("certificate"),
+               NULL,
+               fetch_about_certificate_handler,
+               true
+       },
+       {
                "query/auth",
                SLEN("query/auth"),
                NULL,
diff --git a/include/netsurf/ssl_certs.h b/include/netsurf/ssl_certs.h
index b5e79ab..e3e4188 100644
--- a/include/netsurf/ssl_certs.h
+++ b/include/netsurf/ssl_certs.h
@@ -25,6 +25,8 @@
 #ifndef NETSURF_SSL_CERTS_H_
 #define NETSURF_SSL_CERTS_H_
 
+struct nsurl;
+
 /**
  * ssl certificate error status
  *
@@ -108,6 +110,15 @@ nserror cert_chain_dup_into(const struct cert_chain *src, 
struct cert_chain *dst
 nserror cert_chain_dup(const struct cert_chain *src, struct cert_chain 
**dst_out);
 
 /**
+ * create a certificate chain from a fetch query string
+ *
+ * \param url The url to convert the query from
+ * \param dst_out A pointer to recive the duplicated chain
+ * \return NSERROR_OK on success or NSERROR_NOMEM on memory exhaustion
+ */
+nserror cert_chain_from_query(struct nsurl *url, struct cert_chain 
**chain_out);
+
+/**
  * free a certificate chain
  *
  * \param chain The certificate chain to free
diff --git a/utils/ssl_certs.c b/utils/ssl_certs.c
index 09500a4..94e83eb 100644
--- a/utils/ssl_certs.c
+++ b/utils/ssl_certs.c
@@ -24,9 +24,11 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <nsutils/base64.h>
 
 #include "utils/errors.h"
 #include "utils/log.h"
+#include "utils/nsurl.h"
 
 #include "netsurf/ssl_certs.h"
 
@@ -128,6 +130,91 @@ cert_chain_dup(const struct cert_chain *src, struct 
cert_chain **dst_out)
 }
 
 
+#define MIN_CERT_LEN 64
+
+static nserror
+process_query_section(const char *str, size_t len, struct cert_chain* chain)
+{
+       nsuerror nsures;
+
+       if ((len > (5 + MIN_CERT_LEN)) &&
+           (strncmp(str, "cert=", 5) == 0)) {
+               /* possible certificate entry */
+               nsures = nsu_base64_decode_alloc_url(
+                       (const uint8_t *)str + 5,
+                       len - 5,
+                       &chain->certs[chain->depth].der,
+                       &chain->certs[chain->depth].der_length);
+               if (nsures == NSUERROR_OK) {
+                       chain->depth++;
+               }
+       } else if ((len > 8) &&
+                  (strncmp(str, "certerr=", 8) == 0)) {
+               /* certificate entry error code */
+               if (chain->depth > 0) {
+                       chain->certs[chain->depth - 1].err = strtoul(str + 8, 
NULL, 10);
+               }
+       }
+       return NSERROR_OK;
+}
+
+/*
+ * create a certificate chain from a fetch query string
+ *
+ * exported interface documented in netsurf/ssl_certs.h
+ */
+nserror cert_chain_from_query(struct nsurl *url, struct cert_chain **chain_out)
+{
+       struct cert_chain* chain;
+       nserror res;
+       char *querystr;
+       size_t querylen;
+       size_t kvstart;
+       size_t kvlen;
+
+       res = nsurl_get(url, NSURL_QUERY, &querystr, &querylen);
+       if (res != NSERROR_OK) {
+               return res;
+       }
+
+       if (querylen < MIN_CERT_LEN) {
+               free(querystr);
+               return NSERROR_NEED_DATA;
+       }
+
+       res = cert_chain_alloc(0, &chain);
+       if (res != NSERROR_OK) {
+               free(querystr);
+               return res;
+       }
+
+       for (kvlen = 0, kvstart = 0; kvstart < querylen; kvstart += kvlen) {
+               /* get query section length */
+               kvlen = 0;
+               while (((kvstart + kvlen) < querylen) &&
+                      (querystr[kvstart + kvlen] != '&')) {
+                       kvlen++;
+               }
+
+               res = process_query_section(querystr + kvstart, kvlen, chain);
+               if (res != NSERROR_OK) {
+                       break;
+               }
+               kvlen++; /* account for & separator */
+       }
+       free(querystr);
+
+       if (chain->depth > 0) {
+               *chain_out = chain;
+       } else {
+               free(chain);
+               return NSERROR_INVALID;
+       }
+
+       return NSERROR_OK;
+}
+
+
 /*
  * free certificate chain
  *


-----------------------------------------------------------------------

Summary of changes:
 content/fetchers/about.c    |  280 ++++++++++++++++++++++++++++++++++++++++++-
 include/netsurf/ssl_certs.h |   11 ++
 utils/ssl_certs.c           |   87 ++++++++++++++
 3 files changed, 377 insertions(+), 1 deletion(-)

diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 0e85eff..c140fde 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -261,7 +261,7 @@ static bool fetch_about_licence_handler(struct 
fetch_about_context *ctx)
 
 
 /**
- * Handler to generate about:cache page.
+ * Handler to generate about:imagecache page.
  *
  * Shows details of current image cache.
  *
@@ -396,6 +396,276 @@ fetch_about_imagecache_handler_aborted:
 
 
 /**
+ * ssl certificate information for certificate chain
+ */
+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 */
+};
+
+#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;
+}
+
+/* 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;
+}
+
+#else
+static nserror
+convert_chain_to_cert_info(const struct cert_chain *chain,
+                          struct ssl_cert_info **cert_info_out)
+{
+       return NSERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+
+/**
+ * Handler to generate about:certificate page.
+ *
+ * Shows details of a certificate chain
+ *
+ * \param ctx The fetcher context.
+ * \return true if handled false if aborted.
+ */
+static bool fetch_about_certificate_handler(struct fetch_about_context *ctx)
+{
+       int code = 200;
+       nserror res;
+       struct cert_chain *chain = NULL;
+
+
+       /* content is going to return ok */
+       fetch_set_http_code(ctx->fetchh, code);
+
+       /* content type */
+       if (fetch_about_send_header(ctx, "Content-Type: text/html"))
+               goto fetch_about_certificate_handler_aborted;
+
+       /* page head */
+       res = ssenddataf(ctx,
+                        "<html>\n<head>\n"
+                       "<title>NetSurf Browser Certificate Viewer</title>\n"
+                       "<link rel=\"stylesheet\" type=\"text/css\" "
+                       "href=\"resource:internal.css\">\n"
+                       "</head>\n"
+                       "<body id =\"certificate\">\n"
+                       "<p class=\"banner\">"
+                       "<a href=\"http://www.netsurf-browser.org/\";>"
+                       "<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>"
+                       "</p>\n"
+                       "<h1>NetSurf Browser Certificate Viewer</h1>\n");
+       if (res != NSERROR_OK) {
+               goto fetch_about_certificate_handler_aborted;
+       }
+
+       res = cert_chain_from_query(ctx->url, &chain);
+       if (res != NSERROR_OK) {
+               res = ssenddataf(ctx, "<p>Could not process that</p>\n");
+               if (res != NSERROR_OK) {
+                       goto fetch_about_certificate_handler_aborted;
+               }
+       } else {
+               struct ssl_cert_info *cert_info;
+               res = convert_chain_to_cert_info(chain, &cert_info);
+               if (res == NSERROR_OK) {
+                       size_t depth;
+                       for (depth = 0; depth < chain->depth; depth++) {
+                               res = ssenddataf(ctx,
+                                                "<h2>Certificate: %d</h2>\n"
+                                                "<p>Subject: %s</p>"
+                                                "<p>Serial Number: %s</p>"
+                                                "<p>Type: %i</p>"
+                                                "<p>Version: %ld</p>"
+                                                "<p>Issuer: %s</p>"
+                                                "<p>Valid From: %s</p>"
+                                                "<p>Valid Untill: %s</p>",
+                                                depth,
+                                                cert_info[depth].subject,
+                                                cert_info[depth].serialnum,
+                                                cert_info[depth].cert_type,
+                                                cert_info[depth].version,
+                                                cert_info[depth].issuer,
+                                                cert_info[depth].not_before,
+                                                cert_info[depth].not_after);
+                               if (res != NSERROR_OK) {
+                                       goto 
fetch_about_certificate_handler_aborted;
+                               }
+
+                       }
+                       free(cert_info);
+               } else {
+                       res = ssenddataf(ctx,
+                                        "<p>Invalid certificate data</p>\n");
+                       if (res != NSERROR_OK) {
+                               goto fetch_about_certificate_handler_aborted;
+                       }
+               }
+       }
+
+
+       /* page footer */
+       res = ssenddataf(ctx, "</body>\n</html>\n");
+       if (res != NSERROR_OK) {
+               goto fetch_about_certificate_handler_aborted;
+       }
+
+       fetch_about_send_finished(ctx);
+
+       cert_chain_free(chain);
+
+       return true;
+
+fetch_about_certificate_handler_aborted:
+       cert_chain_free(chain);
+       return false;
+}
+
+
+/**
  * Handler to generate about scheme config page
  *
  * \param ctx The fetcher context.
@@ -1383,6 +1653,14 @@ struct about_handlers about_handler_list[] = {
                true
        },
        {
+               /* details about a certificate */
+               "certificate",
+               SLEN("certificate"),
+               NULL,
+               fetch_about_certificate_handler,
+               true
+       },
+       {
                "query/auth",
                SLEN("query/auth"),
                NULL,
diff --git a/include/netsurf/ssl_certs.h b/include/netsurf/ssl_certs.h
index b5e79ab..e3e4188 100644
--- a/include/netsurf/ssl_certs.h
+++ b/include/netsurf/ssl_certs.h
@@ -25,6 +25,8 @@
 #ifndef NETSURF_SSL_CERTS_H_
 #define NETSURF_SSL_CERTS_H_
 
+struct nsurl;
+
 /**
  * ssl certificate error status
  *
@@ -108,6 +110,15 @@ nserror cert_chain_dup_into(const struct cert_chain *src, 
struct cert_chain *dst
 nserror cert_chain_dup(const struct cert_chain *src, struct cert_chain 
**dst_out);
 
 /**
+ * create a certificate chain from a fetch query string
+ *
+ * \param url The url to convert the query from
+ * \param dst_out A pointer to recive the duplicated chain
+ * \return NSERROR_OK on success or NSERROR_NOMEM on memory exhaustion
+ */
+nserror cert_chain_from_query(struct nsurl *url, struct cert_chain 
**chain_out);
+
+/**
  * free a certificate chain
  *
  * \param chain The certificate chain to free
diff --git a/utils/ssl_certs.c b/utils/ssl_certs.c
index 09500a4..94e83eb 100644
--- a/utils/ssl_certs.c
+++ b/utils/ssl_certs.c
@@ -24,9 +24,11 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <nsutils/base64.h>
 
 #include "utils/errors.h"
 #include "utils/log.h"
+#include "utils/nsurl.h"
 
 #include "netsurf/ssl_certs.h"
 
@@ -128,6 +130,91 @@ cert_chain_dup(const struct cert_chain *src, struct 
cert_chain **dst_out)
 }
 
 
+#define MIN_CERT_LEN 64
+
+static nserror
+process_query_section(const char *str, size_t len, struct cert_chain* chain)
+{
+       nsuerror nsures;
+
+       if ((len > (5 + MIN_CERT_LEN)) &&
+           (strncmp(str, "cert=", 5) == 0)) {
+               /* possible certificate entry */
+               nsures = nsu_base64_decode_alloc_url(
+                       (const uint8_t *)str + 5,
+                       len - 5,
+                       &chain->certs[chain->depth].der,
+                       &chain->certs[chain->depth].der_length);
+               if (nsures == NSUERROR_OK) {
+                       chain->depth++;
+               }
+       } else if ((len > 8) &&
+                  (strncmp(str, "certerr=", 8) == 0)) {
+               /* certificate entry error code */
+               if (chain->depth > 0) {
+                       chain->certs[chain->depth - 1].err = strtoul(str + 8, 
NULL, 10);
+               }
+       }
+       return NSERROR_OK;
+}
+
+/*
+ * create a certificate chain from a fetch query string
+ *
+ * exported interface documented in netsurf/ssl_certs.h
+ */
+nserror cert_chain_from_query(struct nsurl *url, struct cert_chain **chain_out)
+{
+       struct cert_chain* chain;
+       nserror res;
+       char *querystr;
+       size_t querylen;
+       size_t kvstart;
+       size_t kvlen;
+
+       res = nsurl_get(url, NSURL_QUERY, &querystr, &querylen);
+       if (res != NSERROR_OK) {
+               return res;
+       }
+
+       if (querylen < MIN_CERT_LEN) {
+               free(querystr);
+               return NSERROR_NEED_DATA;
+       }
+
+       res = cert_chain_alloc(0, &chain);
+       if (res != NSERROR_OK) {
+               free(querystr);
+               return res;
+       }
+
+       for (kvlen = 0, kvstart = 0; kvstart < querylen; kvstart += kvlen) {
+               /* get query section length */
+               kvlen = 0;
+               while (((kvstart + kvlen) < querylen) &&
+                      (querystr[kvstart + kvlen] != '&')) {
+                       kvlen++;
+               }
+
+               res = process_query_section(querystr + kvstart, kvlen, chain);
+               if (res != NSERROR_OK) {
+                       break;
+               }
+               kvlen++; /* account for & separator */
+       }
+       free(querystr);
+
+       if (chain->depth > 0) {
+               *chain_out = chain;
+       } else {
+               free(chain);
+               return NSERROR_INVALID;
+       }
+
+       return NSERROR_OK;
+}
+
+
 /*
  * free certificate chain
  *


-- 
NetSurf Browser

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to