summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2019-08-05 18:11:13 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2019-08-05 18:12:47 +0100
commitbfb1bb119241d85bb9b400881328496e12a39aed (patch)
tree4f05e7c9e1d61cb5229895da7d4f318f94ef90f1 /content
parentbccf101714f2ca165b1fd754879f3813993d26ca (diff)
downloadnetsurf-bfb1bb119241d85bb9b400881328496e12a39aed.tar.gz
netsurf-bfb1bb119241d85bb9b400881328496e12a39aed.tar.bz2
Migrate SSL certificate storage to the browser window
* Fetchers now provide the certificates before headers * This is propagated all the way to the browser window * When a query occurs, we retrieve it from there and fire the query with those stored certificates. * The serial number is a bignum, store it as hex. Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
Diffstat (limited to 'content')
-rw-r--r--content/content.c3
-rw-r--r--content/content.h7
-rw-r--r--content/fetch.h8
-rw-r--r--content/fetchers/curl.c251
-rw-r--r--content/hlcache.c12
-rw-r--r--content/llcache.c21
-rw-r--r--content/llcache.h5
7 files changed, 177 insertions, 130 deletions
diff --git a/content/content.c b/content/content.c
index bb69c766d..dc9805448 100644
--- a/content/content.c
+++ b/content/content.c
@@ -142,6 +142,9 @@ nserror content_llcache_callback(llcache_handle *llcache,
nserror error = NSERROR_OK;
switch (event->type) {
+ case LLCACHE_EVENT_GOT_CERTS:
+ /* Will never happen: handled in hlcache */
+ break;
case LLCACHE_EVENT_HAD_HEADERS:
/* Will never happen: handled in hlcache */
break;
diff --git a/content/content.h b/content/content.h
index 4fdcaf2c0..6e298e045 100644
--- a/content/content.h
+++ b/content/content.h
@@ -44,6 +44,7 @@ struct object_params;
struct rect;
struct redraw_context;
struct llcache_query_msg;
+struct ssl_cert_info;
/** Status of a content */
typedef enum {
@@ -59,6 +60,7 @@ typedef enum {
/** Used in callbacks to indicate what has occurred. */
typedef enum {
CONTENT_MSG_LOG, /**< Content wishes to log something */
+ CONTENT_MSG_SSL_CERTS, /**< Content is from SSL and this is its chain */
CONTENT_MSG_QUERY, /**< Something under the content has a query */
CONTENT_MSG_QUERY_FINISHED, /**< Something under the content finished its query */
CONTENT_MSG_LOADING, /**< fetching or converting */
@@ -107,6 +109,11 @@ union content_msg_data {
size_t msglen; /**< The length of that message */
browser_window_console_flags flags; /**< The flags of the logging */
} log;
+ /** CONTENT_MSG_SSL_CERTS - The certificate chain from the underlying fetch */
+ struct {
+ const struct ssl_cert_info *certs; /**< The chain */
+ size_t num; /**< The number of certs in the chain */
+ } certs;
/** CONTENT_MSG_QUERY - Query from underlying object somewhere */
const struct llcache_query_msg *query_msg;
/** CONTENT_MSG_QUERY_FINISHED - Query from underlying object finished */
diff --git a/content/fetch.h b/content/fetch.h
index 0b4b52a2f..174e07bf6 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -42,6 +42,7 @@ typedef enum {
FETCH_ERROR,
FETCH_REDIRECT,
FETCH_NOTMODIFIED,
+ FETCH_CERTS,
FETCH_AUTH,
FETCH_CERT_ERR,
FETCH_SSL_ERR
@@ -70,7 +71,7 @@ typedef struct fetch_msg {
struct {
const struct ssl_cert_info *certs;
size_t num_certs;
- } cert_err;
+ } certs;
} data;
} fetch_msg;
@@ -95,12 +96,15 @@ struct ssl_cert_info {
char not_before[32]; /**< Valid from date */
char not_after[32]; /**< Valid to date */
int sig_type; /**< Signature type */
- long serial; /**< Serial number */
+ char serialnum[64]; /**< Serial number */
char issuer[256]; /**< Issuer details */
char subject[256]; /**< Subject details */
int cert_type; /**< Certificate type */
};
+/** maximum number of X509 certificates in chain for TLS connection */
+#define MAX_SSL_CERTS 10
+
typedef void (*fetch_callback)(const fetch_msg *msg, void *p);
/**
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index 0ab0b6c24..fdfe53d30 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -64,9 +64,6 @@
/** maximum number of progress notifications per second */
#define UPDATES_PER_SECOND 2
-/** maximum number of X509 certificates in chain for TLS connection */
-#define MAX_CERTS 10
-
/* the ciphersuites we are willing to use */
#define CIPHER_LIST \
/* disable everything */ \
@@ -109,7 +106,7 @@ struct curl_fetch_info {
struct curl_httppost *post_multipart; /**< Multipart post data, or 0. */
uint64_t last_progress_update; /**< Time of last progress update */
int cert_depth; /**< deepest certificate in use */
- struct cert_info cert_data[MAX_CERTS]; /**< HTTPS certificate data */
+ struct cert_info cert_data[MAX_SSL_CERTS]; /**< HTTPS certificate data */
};
/** curl handle cache entry */
@@ -446,6 +443,129 @@ failed:
/**
+ * Report the certificate information in the fetch to the users
+ */
+static void
+fetch_curl_report_certs_upstream(struct curl_fetch_info *f)
+{
+ int depth;
+ BIO *mem;
+ BUF_MEM *buf;
+ const ASN1_INTEGER *asn1_num;
+ BIGNUM *bignum;
+ struct ssl_cert_info ssl_certs[MAX_SSL_CERTS];
+ fetch_msg msg;
+ struct cert_info *certs = f->cert_data;
+ memset(ssl_certs, 0, sizeof(ssl_certs));
+
+ for (depth = 0; depth <= f->cert_depth; depth++) {
+ assert(certs[depth].cert != NULL);
+
+ /* get certificate version */
+ ssl_certs[depth].version = X509_get_version(certs[depth].cert);
+
+ /* not before date */
+ mem = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(mem, X509_get_notBefore(certs[depth].cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ memcpy(ssl_certs[depth].not_before,
+ buf->data,
+ min(sizeof(ssl_certs[depth].not_before) - 1,
+ (unsigned)buf->length));
+ ssl_certs[depth].not_before[min(sizeof(ssl_certs[depth].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(certs[depth].cert));
+ BIO_get_mem_ptr(mem, &buf);
+ (void) BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ memcpy(ssl_certs[depth].not_after,
+ buf->data,
+ min(sizeof(ssl_certs[depth].not_after) - 1,
+ (unsigned)buf->length));
+ ssl_certs[depth].not_after[min(sizeof(ssl_certs[depth].not_after) - 1,
+ (unsigned)buf->length)] = 0;
+ BUF_MEM_free(buf);
+
+ /* signature type */
+ ssl_certs[depth].sig_type =
+ X509_get_signature_type(certs[depth].cert);
+
+ /* serial number */
+ asn1_num = X509_get0_serialNumber(certs[depth].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(ssl_certs[depth].serialnum,
+ tmp,
+ sizeof(ssl_certs[depth].serialnum));
+ ssl_certs[depth].serialnum[sizeof(ssl_certs[depth].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(certs[depth].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(ssl_certs[depth].issuer,
+ buf->data,
+ min(sizeof(ssl_certs[depth].issuer) - 1,
+ (unsigned) buf->length));
+ ssl_certs[depth].issuer[min(sizeof(ssl_certs[depth].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(certs[depth].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(ssl_certs[depth].subject,
+ buf->data,
+ min(sizeof(ssl_certs[depth].subject) - 1,
+ (unsigned)buf->length));
+ ssl_certs[depth].subject[min(sizeof(ssl_certs[depth].subject) - 1,
+ (unsigned) buf->length)] = 0;
+ BUF_MEM_free(buf);
+
+ /* type of certificate */
+ ssl_certs[depth].cert_type =
+ X509_certificate_type(certs[depth].cert,
+ X509_get_pubkey(certs[depth].cert));
+ }
+
+ msg.type = FETCH_CERTS;
+ msg.data.certs.certs = ssl_certs;
+ msg.data.certs.num_certs = depth;
+
+ fetch_send_callback(&msg, f->fetch_handle);
+}
+
+
+/**
* OpenSSL Certificate verification callback
*
* Called for each certificate in a chain being verified. OpenSSL
@@ -479,7 +599,7 @@ fetch_curl_verify_callback(int verify_ok, X509_STORE_CTX *x509_ctx)
}
/* certificate chain is excessively deep so fail verification */
- if (depth >= MAX_CERTS) {
+ if (depth >= MAX_SSL_CERTS) {
X509_STORE_CTX_set_error(x509_ctx,
X509_V_ERR_CERT_CHAIN_TOO_LONG);
return 0;
@@ -524,6 +644,7 @@ fetch_curl_verify_callback(int verify_ok, X509_STORE_CTX *x509_ctx)
*/
static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm)
{
+ struct curl_fetch_info *f = (struct curl_fetch_info *) parm;
int ok;
/* Store fetch struct in context for verify callback */
@@ -534,6 +655,8 @@ static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm)
ok = X509_verify_cert(x509_ctx);
}
+ fetch_curl_report_certs_upstream(f);
+
return ok;
}
@@ -886,7 +1009,7 @@ static void fetch_curl_free(void *vf)
curl_formfree(f->post_multipart);
}
- for (i = 0; i < MAX_CERTS && f->cert_data[i].cert; i++) {
+ for (i = 0; i < MAX_SSL_CERTS && f->cert_data[i].cert; i++) {
ns_X509_free(f->cert_data[i].cert);
}
@@ -955,114 +1078,6 @@ static bool fetch_curl_process_headers(struct curl_fetch_info *f)
return false;
}
-/**
- * setup callback to allow the user to examine certificates which have
- * failed to validate during fetch.
- */
-static void
-curl_start_cert_validate(struct curl_fetch_info *f,
- struct cert_info *certs)
-{
- int depth;
- BIO *mem;
- BUF_MEM *buf;
- struct ssl_cert_info ssl_certs[MAX_CERTS];
- fetch_msg msg;
-
- for (depth = 0; depth <= f->cert_depth; depth++) {
- assert(certs[depth].cert != NULL);
-
- /* get certificate version */
- ssl_certs[depth].version = X509_get_version(certs[depth].cert);
-
- /* not before date */
- mem = BIO_new(BIO_s_mem());
- ASN1_TIME_print(mem, X509_get_notBefore(certs[depth].cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- memcpy(ssl_certs[depth].not_before,
- buf->data,
- min(sizeof(ssl_certs[depth].not_before) - 1,
- (unsigned)buf->length));
- ssl_certs[depth].not_before[min(sizeof(ssl_certs[depth].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(certs[depth].cert));
- BIO_get_mem_ptr(mem, &buf);
- (void) BIO_set_close(mem, BIO_NOCLOSE);
- BIO_free(mem);
- memcpy(ssl_certs[depth].not_after,
- buf->data,
- min(sizeof(ssl_certs[depth].not_after) - 1,
- (unsigned)buf->length));
- ssl_certs[depth].not_after[min(sizeof(ssl_certs[depth].not_after) - 1,
- (unsigned)buf->length)] = 0;
- BUF_MEM_free(buf);
-
- /* signature type */
- ssl_certs[depth].sig_type =
- X509_get_signature_type(certs[depth].cert);
-
- /* serial number */
- ssl_certs[depth].serial =
- ASN1_INTEGER_get(
- X509_get_serialNumber(certs[depth].cert));
-
- /* issuer name */
- mem = BIO_new(BIO_s_mem());
- X509_NAME_print_ex(mem,
- X509_get_issuer_name(certs[depth].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(ssl_certs[depth].issuer,
- buf->data,
- min(sizeof(ssl_certs[depth].issuer) - 1,
- (unsigned) buf->length));
- ssl_certs[depth].issuer[min(sizeof(ssl_certs[depth].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(certs[depth].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(ssl_certs[depth].subject,
- buf->data,
- min(sizeof(ssl_certs[depth].subject) - 1,
- (unsigned)buf->length));
- ssl_certs[depth].subject[min(sizeof(ssl_certs[depth].subject) - 1,
- (unsigned) buf->length)] = 0;
- BUF_MEM_free(buf);
-
- /* type of certificate */
- ssl_certs[depth].cert_type =
- X509_certificate_type(certs[depth].cert,
- X509_get_pubkey(certs[depth].cert));
-
- /* and clean up */
- ns_X509_free(certs[depth].cert);
- }
-
- msg.type = FETCH_CERT_ERR;
- msg.data.cert_err.certs = ssl_certs;
- msg.data.cert_err.num_certs = depth;
- fetch_send_callback(&msg, f->fetch_handle);
-}
/**
* Handle a completed fetch (CURLMSG_DONE from curl_multi_info_read()).
@@ -1079,7 +1094,6 @@ static void fetch_curl_done(CURL *curl_handle, CURLcode result)
struct curl_fetch_info *f;
char **_hideous_hack = (char **) (void *) &f;
CURLcode code;
- struct cert_info certs[MAX_CERTS];
/* find the structure associated with this fetch */
/* For some reason, cURL thinks CURLINFO_PRIVATE should be a string?! */
@@ -1127,9 +1141,6 @@ static void fetch_curl_done(CURL *curl_handle, CURLcode result)
/* CURLE_SSL_PEER_CERTIFICATE renamed to
* CURLE_PEER_FAILED_VERIFICATION
*/
- memset(certs, 0, sizeof(certs));
- memcpy(certs, f->cert_data, sizeof(certs));
- memset(f->cert_data, 0, sizeof(f->cert_data));
cert = true;
} else {
NSLOG(netsurf, INFO, "Unknown cURL response code %d", result);
@@ -1146,7 +1157,9 @@ static void fetch_curl_done(CURL *curl_handle, CURLcode result)
fetch_send_callback(&msg, f->fetch_handle);
} else if (cert) {
/* user needs to validate certificate with issue */
- curl_start_cert_validate(f, certs);
+ fetch_msg msg;
+ msg.type = FETCH_CERT_ERR;
+ fetch_send_callback(&msg, f->fetch_handle);
} else if (error) {
fetch_msg msg;
switch (result) {
diff --git a/content/hlcache.c b/content/hlcache.c
index ca0e47907..d2b612d05 100644
--- a/content/hlcache.c
+++ b/content/hlcache.c
@@ -433,6 +433,18 @@ static nserror hlcache_llcache_callback(llcache_handle *handle,
assert(ctx->llcache == handle);
switch (event->type) {
+ case LLCACHE_EVENT_GOT_CERTS:
+ /* Pass them on upward */
+ if (ctx->handle->cb != NULL) {
+ hlcache_event hlevent;
+
+ hlevent.type = CONTENT_MSG_SSL_CERTS;
+ hlevent.data.certs.certs = event->data.certs.certs;
+ hlevent.data.certs.num = event->data.certs.num;
+
+ ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
+ }
+ break;
case LLCACHE_EVENT_HAD_HEADERS:
error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"), NULL, 0,
ctx->flags & HLCACHE_RETRIEVE_SNIFF_TYPE,
diff --git a/content/llcache.c b/content/llcache.c
index f3f4b68b0..b0f22b7fa 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -2360,12 +2360,9 @@ static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
* Handle a TLS certificate verification failure
*
* \param object Object being fetched
- * \param certs Certificate chain
- * \param num Number of certificates in chain
* \return NSERROR_OK on success, appropriate error otherwise
*/
-static nserror llcache_fetch_cert_error(llcache_object *object,
- const struct ssl_cert_info *certs, size_t num)
+static nserror llcache_fetch_cert_error(llcache_object *object)
{
nserror error = NSERROR_OK;
@@ -2386,8 +2383,6 @@ static nserror llcache_fetch_cert_error(llcache_object *object,
/* Emit query for TLS */
query.type = LLCACHE_QUERY_SSL;
query.url = object->url;
- query.data.ssl.certs = certs;
- query.data.ssl.num = num;
/* Construct the query event */
event.type = LLCACHE_EVENT_QUERY;
@@ -2880,7 +2875,17 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
error = llcache_send_event_to_users(object, &event);
break;
+ case FETCH_CERTS:
+ /* Certificate information from the fetch */
+ /** \todo CERTS - Should we persist this on the object and
+ * then catch up new users etc?
+ */
+ event.type = LLCACHE_EVENT_GOT_CERTS;
+ event.data.certs.certs = msg->data.certs.certs;
+ event.data.certs.num = msg->data.certs.num_certs;
+ error = llcache_send_event_to_users(object, &event);
+ break;
/* Events requiring action */
case FETCH_AUTH:
/* Need Authentication */
@@ -2902,9 +2907,7 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
object->candidate = NULL;
}
- error = llcache_fetch_cert_error(object,
- msg->data.cert_err.certs,
- msg->data.cert_err.num_certs);
+ error = llcache_fetch_cert_error(object);
break;
case FETCH_SSL_ERR:
/* TLS connection setup failed */
diff --git a/content/llcache.h b/content/llcache.h
index dd2dadc72..b2577a6c1 100644
--- a/content/llcache.h
+++ b/content/llcache.h
@@ -103,6 +103,7 @@ typedef nserror (*llcache_query_response)(bool proceed, void *cbpw);
/** Low-level cache event types */
typedef enum {
+ LLCACHE_EVENT_GOT_CERTS, /**< SSL certificates arrived */
LLCACHE_EVENT_HAD_HEADERS, /**< Received all headers */
LLCACHE_EVENT_HAD_DATA, /**< Received some data */
LLCACHE_EVENT_DONE, /**< Finished fetching data */
@@ -143,6 +144,10 @@ typedef struct {
nsurl *from; /**< Redirect origin */
nsurl *to; /**< Redirect target */
} redirect; /**< Fetch URL redirect occured */
+ struct {
+ const struct ssl_cert_info *certs; /**< The chain */
+ size_t num; /**< Number of certs in chain */
+ } certs;
llcache_query_msg query;/**< Query event */
} data; /**< Event data */
} llcache_event;