summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2019-08-06 13:15:23 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2019-08-06 13:15:23 +0100
commit1cf1ec55bc7647e737d7ec41bfe1def721269c02 (patch)
tree7fd4c9bdfe1d14789dbbe3eba696bba761dabf74
parent75349e79d82c43b9731b9349364f467c81fce94b (diff)
downloadnetsurf-1cf1ec55bc7647e737d7ec41bfe1def721269c02.tar.gz
netsurf-1cf1ec55bc7647e737d7ec41bfe1def721269c02.tar.bz2
Support SSL verification through new about: handler
In doing this, also propagate why the certificates were bad so that the page can display a reason. We will need FatMessages for all these. Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
-rw-r--r--content/fetch.h18
-rw-r--r--content/fetchers/curl.c43
-rw-r--r--desktop/browser_window.c145
-rw-r--r--frontends/amiga/gui.c1
-rw-r--r--frontends/atari/gui.c1
-rw-r--r--frontends/gtk/gui.c1
-rw-r--r--frontends/riscos/gui.c1
-rw-r--r--frontends/windows/main.c2
-rw-r--r--include/netsurf/ssl_certs.h61
-rw-r--r--utils/corestringlist.h1
-rw-r--r--utils/messages.c48
-rw-r--r--utils/messages.h9
12 files changed, 291 insertions, 40 deletions
diff --git a/content/fetch.h b/content/fetch.h
index 7c02fb0d7..66be857f8 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -28,6 +28,7 @@
#include "utils/config.h"
#include "utils/nsurl.h"
#include "utils/inet.h"
+#include "netsurf/ssl_certs.h"
struct content;
struct fetch;
@@ -88,23 +89,6 @@ struct fetch_multipart_data {
bool file; /**< Item is a file */
};
-/**
- * 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 */
-};
-
-/** 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 f5649e0c3..345f16ce1 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -555,6 +555,49 @@ fetch_curl_report_certs_upstream(struct curl_fetch_info *f)
ssl_certs[depth].cert_type =
X509_certificate_type(certs[depth].cert,
X509_get_pubkey(certs[depth].cert));
+
+ /* error code (if any) */
+ switch (certs[depth].err) {
+ case X509_V_OK:
+ ssl_certs[depth].err = SSL_CERT_ERR_OK;
+ break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ /* fallthrough */
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ ssl_certs[depth].err = SSL_CERT_ERR_BAD_ISSUER;
+ break;
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ /* fallthrough */
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ /* fallthrough */
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ /* fallthrough */
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ ssl_certs[depth].err = SSL_CERT_ERR_BAD_SIG;
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ /* fallthrough */
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ ssl_certs[depth].err = SSL_CERT_ERR_TOO_YOUNG;
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ /* fallthrough */
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ ssl_certs[depth].err = SSL_CERT_ERR_TOO_OLD;
+ break;
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ ssl_certs[depth].err = SSL_CERT_ERR_SELF_SIGNED;
+ break;
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ ssl_certs[depth].err = SSL_CERT_ERR_CHAIN_SELF_SIGNED;
+ break;
+ case X509_V_ERR_CERT_REVOKED:
+ ssl_certs[depth].err = SSL_CERT_ERR_REVOKED;
+ break;
+ default:
+ ssl_certs[depth].err = SSL_CERT_ERR_UNKNOWN;
+ break;
+ }
}
msg.type = FETCH_CERTS;
diff --git a/desktop/browser_window.c b/desktop/browser_window.c
index d74b56a77..a6d3ae92c 100644
--- a/desktop/browser_window.c
+++ b/desktop/browser_window.c
@@ -844,23 +844,45 @@ browser_window_content_done(struct browser_window *bw)
* Handle query responses from SSL requests
*/
static nserror
-browser_window__handle_query_response(bool proceed, void *pw)
+browser_window__handle_ssl_query_response(bool proceed, void *pw)
{
struct browser_window *bw = (struct browser_window *)pw;
- nserror res = NSERROR_OK;
- if (proceed) {
- /* We want to restart the request, with the loading
- * context
+ /* If we're in the process of loading, stop the load */
+ if (bw->loading_content != NULL) {
+ /* We had a loading content (maybe auth page?) */
+ browser_window_stop(bw);
+ browser_window_remove_caret(bw, false);
+ browser_window_destroy_children(bw);
+ }
+
+ if (!proceed) {
+ /* We're processing a "back to safety", do a rough-and-ready
+ * nav to the old 'current' parameters, with any post data
+ * stripped away
*/
- res = browser_window__navigate_internal(bw, &bw->loading_parameters);
+ if (bw->current_parameters.post_urlenc != NULL) {
+ free(bw->current_parameters.post_urlenc);
+ bw->current_parameters.post_urlenc = NULL;
+ }
- if (res != NSERROR_OK) {
- NSLOG(netsurf, WARNING, "Unable to navigate after query proceeds");
+ if (bw->current_parameters.post_multipart != NULL) {
+ fetch_multipart_data_destroy(bw->current_parameters.post_multipart);
+ bw->current_parameters.post_multipart = NULL;
}
+
+ bw->current_parameters.flags &= ~BW_NAVIGATE_HISTORY;
+ bw->internal_nav = false;
+ return browser_window__navigate_internal(bw, &bw->current_parameters);
}
- return res;
+ /* We're processing a "proceed" attempt from the form */
+ /* First, we permit the SSL */
+ urldb_set_cert_permissions(bw->loading_parameters.url, true);
+
+ /* And then we navigate to the original loading parameters */
+ bw->internal_nav = false;
+ return browser_window__navigate_internal(bw, &bw->loading_parameters);
}
/**
@@ -1074,6 +1096,70 @@ out:
}
/**
+ * Handle a certificate verification request (BAD_CERTS) during a fetch
+ */
+static nserror
+browser_window__handle_bad_certs(struct browser_window *bw,
+ nsurl *url)
+{
+ struct browser_fetch_parameters params;
+ nserror err;
+ /* Initially we don't know WHY the SSL cert was bad */
+ const char *reason = messages_get_sslcode(SSL_CERT_ERR_UNKNOWN);
+ size_t n;
+
+ memset(&params, 0, sizeof(params));
+
+ err = nsurl_create("about:query/ssl", &params.url);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ err = fetch_multipart_data_new_kv(&params.post_multipart,
+ "siteurl",
+ nsurl_access(url));
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ for (n = 0; n < bw->loading_ssl_info.num; ++n) {
+ size_t idx = bw->loading_ssl_info.num - (n + 1);
+ ssl_cert_err err = bw->loading_ssl_info.certs[idx].err;
+ if (err != SSL_CERT_ERR_OK) {
+ reason = messages_get_sslcode(err);
+ break;
+ }
+ }
+
+ err = fetch_multipart_data_new_kv(&params.post_multipart,
+ "reason",
+ reason);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ /* Now we issue the fetch */
+ bw->internal_nav = true;
+ err = browser_window__navigate_internal(bw, &params);
+ if (err != NSERROR_OK) {
+ goto out;
+ }
+
+ err = guit->misc->cert_verify(url,
+ bw->loading_ssl_info.certs,
+ bw->loading_ssl_info.num,
+ browser_window__handle_ssl_query_response,
+ bw);
+
+ if (err == NSERROR_NOT_IMPLEMENTED) {
+ err = NSERROR_OK;
+ }
+out:
+ browser_window__free_fetch_parameters(&params);
+ return err;
+}
+
+/**
* Handle errors during content fetch
*/
static nserror
@@ -1129,14 +1215,7 @@ browser_window__handle_error(struct browser_window *bw,
res = browser_window__handle_login(bw, message, url);
break;
case NSERROR_BAD_CERTS:
- res = guit->misc->cert_verify(url,
- bw->loading_ssl_info.certs,
- bw->loading_ssl_info.num,
- browser_window__handle_query_response,
- bw);
- if (res != NSERROR_OK) {
- NSLOG(netsurf, DEBUG, "Unable to start GUI callback for SSL certs");
- }
+ res = browser_window__handle_bad_certs(bw, url);
break;
default:
break;
@@ -2986,6 +3065,8 @@ browser_window_navigate(struct browser_window *bw,
if (scheme == corestring_lwc_about) {
if (path == corestring_lwc_query_auth) {
is_internal = true;
+ } else if (path == corestring_lwc_query_ssl) {
+ is_internal = true;
}
}
lwc_string_unref(scheme);
@@ -3331,6 +3412,32 @@ browser_window__navigate_internal_query_auth(struct browser_window *bw,
}
+/**
+ * Internal navigation handler for the SSL/privacy query page.
+ *
+ * If the parameters indicate we're processing a *response* from the handler
+ * then we deal with that, otherwise we pass it on to the about: handler
+ */
+static nserror
+browser_window__navigate_internal_query_ssl(struct browser_window *bw,
+ struct browser_fetch_parameters *params)
+{
+ bool is_proceed = false, is_back = false;
+
+ assert(params->post_multipart != NULL);
+
+ is_proceed = fetch_multipart_data_find(params->post_multipart, "proceed") != NULL;
+ is_back = fetch_multipart_data_find(params->post_multipart, "back") != NULL;
+
+ if (!(is_proceed || is_back)) {
+ /* This is a request, so pass it on */
+ return browser_window__navigate_internal_real(bw, params);
+ }
+
+ return browser_window__handle_ssl_query_response(is_proceed, bw);
+}
+
+
nserror
browser_window__navigate_internal(struct browser_window *bw,
struct browser_fetch_parameters *params)
@@ -3356,6 +3463,10 @@ browser_window__navigate_internal(struct browser_window *bw,
lwc_string_unref(path);
return browser_window__navigate_internal_query_auth(bw, params);
}
+ if (path == corestring_lwc_query_ssl) {
+ lwc_string_unref(path);
+ return browser_window__navigate_internal_query_ssl(bw, params);
+ }
lwc_string_unref(path);
/* Fall through to a normal about: fetch */
diff --git a/frontends/amiga/gui.c b/frontends/amiga/gui.c
index af9322e53..a81de1692 100644
--- a/frontends/amiga/gui.c
+++ b/frontends/amiga/gui.c
@@ -6086,7 +6086,6 @@ static struct gui_misc_table amiga_misc_table = {
.quit = gui_quit,
.launch_url = gui_launch_url,
- .cert_verify = ami_cert_verify,
};
/** Normal entry point from OS */
diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c
index cce4e13ee..517289d49 100644
--- a/frontends/atari/gui.c
+++ b/frontends/atari/gui.c
@@ -1107,7 +1107,6 @@ static struct gui_misc_table atari_misc_table = {
.warning = atari_warn_user,
.quit = gui_quit,
- .cert_verify = gui_cert_verify,
};
/* #define WITH_DBG_LOGFILE 1 */
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index 740543b44..384f3fccc 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -1072,7 +1072,6 @@ static struct gui_misc_table nsgtk_misc_table = {
.quit = gui_quit,
.launch_url = gui_launch_url,
- .cert_verify = gtk_cert_verify,
.pdf_password = nsgtk_pdf_password,
};
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
index ef215487d..169b89b1c 100644
--- a/frontends/riscos/gui.c
+++ b/frontends/riscos/gui.c
@@ -2431,7 +2431,6 @@ static struct gui_misc_table riscos_misc_table = {
.quit = gui_quit,
.launch_url = gui_launch_url,
- .cert_verify = gui_cert_verify,
};
diff --git a/frontends/windows/main.c b/frontends/windows/main.c
index bae7815ae..ea9d99571 100644
--- a/frontends/windows/main.c
+++ b/frontends/windows/main.c
@@ -312,8 +312,6 @@ static nserror nsw32_messages_init(char **respaths)
static struct gui_misc_table win32_misc_table = {
.schedule = win32_schedule,
.warning = win32_warning,
-
- .cert_verify = nsw32_cert_verify,
};
/**
diff --git a/include/netsurf/ssl_certs.h b/include/netsurf/ssl_certs.h
new file mode 100644
index 000000000..a73dc604c
--- /dev/null
+++ b/include/netsurf/ssl_certs.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * SSL related types and values
+ */
+
+#ifndef NETSURF_SSL_CERTS_H_
+#define NETSURF_SSL_CERTS_H_
+
+/**
+ * ssl certificate error status
+ */
+typedef enum {
+ SSL_CERT_ERR_OK, /**< Nothing wrong with this certificate */
+ SSL_CERT_ERR_UNKNOWN, /**< Unknown error */
+ SSL_CERT_ERR_BAD_ISSUER, /**< Bad issuer */
+ SSL_CERT_ERR_BAD_SIG, /**< Bad signature on this certificate */
+ SSL_CERT_ERR_TOO_YOUNG, /**< This certificate is not yet valid */
+ SSL_CERT_ERR_TOO_OLD, /**< This certificate is no longer valid */
+ SSL_CERT_ERR_SELF_SIGNED, /**< This certificate (or the chain) is self signed */
+ SSL_CERT_ERR_CHAIN_SELF_SIGNED, /**< This certificate chain is self signed */
+ SSL_CERT_ERR_REVOKED, /**< This certificate has been revoked */
+} ssl_cert_err;
+
+/**
+ * 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 */
+};
+
+/** maximum number of X509 certificates in chain for TLS connection */
+#define MAX_SSL_CERTS 10
+
+#endif /* NETSURF_SSL_CERTS_H_ */
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index e6530c506..82fffe263 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -147,6 +147,7 @@ CORESTRING_LWC_VALUE(max_age, "max-age");
CORESTRING_LWC_VALUE(no_cache, "no-cache");
CORESTRING_LWC_VALUE(no_store, "no-store");
CORESTRING_LWC_VALUE(query_auth, "query/auth");
+CORESTRING_LWC_VALUE(query_ssl, "query/ssl");
/* mime types */
CORESTRING_LWC_VALUE(multipart_form_data, "multipart/form-data");
diff --git a/utils/messages.c b/utils/messages.c
index 5beeba38d..29443f99e 100644
--- a/utils/messages.c
+++ b/utils/messages.c
@@ -343,6 +343,54 @@ const char *messages_get_errorcode(nserror code)
return messages_get_ctx("Unknown", messages_hash);
}
+/* exported function documented in utils/messages.h */
+const char *messages_get_sslcode(ssl_cert_err code)
+{
+ switch (code) {
+ case SSL_CERT_ERR_OK:
+ /* Nothing wrong with this certificate */
+ return messages_get_ctx("SSLCertErrOk", messages_hash);
+
+ case SSL_CERT_ERR_UNKNOWN:
+ /* Unknown error */
+ return messages_get_ctx("SSLCertErrUnknown", messages_hash);
+
+ case SSL_CERT_ERR_BAD_ISSUER:
+ /* Bad issuer */
+ return messages_get_ctx("SSLCertErrBadIssuer", messages_hash);
+
+ case SSL_CERT_ERR_BAD_SIG:
+ /* Bad signature on this certificate */
+ return messages_get_ctx("SSLCertErrBadSig", messages_hash);
+
+ case SSL_CERT_ERR_TOO_YOUNG:
+ /* This certificate is not yet valid */
+ return messages_get_ctx("SSLCertErrTooYoung", messages_hash);
+
+ case SSL_CERT_ERR_TOO_OLD:
+ /* This certificate is no longer valid */
+ return messages_get_ctx("SSLCertErrTooOld", messages_hash);
+
+ case SSL_CERT_ERR_SELF_SIGNED:
+ /* This certificate is self signed */
+ return messages_get_ctx("SSLCertErrSelfSigned", messages_hash);
+
+ case SSL_CERT_ERR_CHAIN_SELF_SIGNED:
+ /* This certificate chain is self signed */
+ return messages_get_ctx("SSLCertErrChainSelfSigned", messages_hash);
+
+ case SSL_CERT_ERR_REVOKED:
+ /* This certificate has been revoked */
+ return messages_get_ctx("SSLCertErrRevoked", messages_hash);
+ }
+
+ /* The switch has no default, so the compiler should tell us when we
+ * forget to add messages for new error codes. As such, we should
+ * never get here.
+ */
+ assert(0);
+ return messages_get_ctx("Unknown", messages_hash);
+}
/* exported function documented in utils/messages.h */
void messages_destroy(void)
diff --git a/utils/messages.h b/utils/messages.h
index 4024f7e77..635d6e8e4 100644
--- a/utils/messages.h
+++ b/utils/messages.h
@@ -36,6 +36,7 @@
#include <stdint.h>
#include "utils/errors.h"
+#include "netsurf/ssl_certs.h"
/**
* Read keys and values from messages file into the standard Messages hash.
@@ -79,6 +80,14 @@ const char *messages_get(const char *key);
const char *messages_get_errorcode(nserror code);
/**
+ * lookup of a message by SSL error code from the standard Messages hash.
+ *
+ * \param code ssl error code
+ * \return message text
+ */
+const char *messages_get_sslcode(ssl_cert_err code);
+
+/**
* Formatted message from a key in the global message hash.
*
* \param key key of message