diff options
-rw-r--r-- | content/content.c | 45 | ||||
-rw-r--r-- | content/content.h | 12 | ||||
-rw-r--r-- | content/content_protected.h | 1 | ||||
-rw-r--r-- | content/handlers/html/html.c | 29 | ||||
-rw-r--r-- | content/handlers/html/html_css.c | 17 | ||||
-rw-r--r-- | content/handlers/html/html_internal.h | 8 | ||||
-rw-r--r-- | content/handlers/html/html_script.c | 25 | ||||
-rw-r--r-- | desktop/browser_window.c | 9 |
8 files changed, 143 insertions, 3 deletions
diff --git a/content/content.c b/content/content.c index 82a87c536..c0119eac9 100644 --- a/content/content.c +++ b/content/content.c @@ -28,6 +28,7 @@ #include "netsurf/inttypes.h" #include "utils/log.h" #include "utils/messages.h" +#include "utils/corestrings.h" #include "netsurf/browser_window.h" #include "netsurf/bitmap.h" #include "netsurf/content.h" @@ -564,6 +565,50 @@ bool content_exec(struct hlcache_handle *h, const char *src, size_t srclen) } /* exported interface, documented in content/content.h */ +bool content_saw_insecure_objects(struct hlcache_handle *h) +{ + struct content *c = hlcache_handle_get_content(h); + lwc_string *scheme = nsurl_get_component(content_get_url(c), NSURL_SCHEME); + bool match; + + /* Is this an internal scheme? If so, we trust here and stop */ + if ((lwc_string_isequal(scheme, corestring_lwc_about, + &match) == lwc_error_ok && + (match == true)) || + (lwc_string_isequal(scheme, corestring_lwc_data, + &match) == lwc_error_ok && + (match == true)) || + (lwc_string_isequal(scheme, corestring_lwc_resource, + &match) == lwc_error_ok && + (match == true))) { + /* No insecurity to find */ + return false; + } + + /* Okay, not internal, am *I* secure? */ + if ((lwc_string_isequal(scheme, corestring_lwc_https, + &match) == lwc_error_ok) + && (match == false)) { + /* I did see something insecure -- ME! */ + return true; + } + + /* I am supposed to be secure, but was I overridden */ + if (urldb_get_cert_permissions(content_get_url(c))) { + /* I was https:// but I was overridden, that's no good */ + return true; + } + + /* Otherwise try and chain through the handler */ + if (c->handler->saw_insecure_objects != NULL) { + return c->handler->saw_insecure_objects(c); + } + + /* If we can't see insecure objects, we can't see them */ + return false; +} + +/* exported interface, documented in content/content.h */ bool content_redraw(hlcache_handle *h, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx) { diff --git a/content/content.h b/content/content.h index f3e578b6b..0dbd58d95 100644 --- a/content/content.h +++ b/content/content.h @@ -420,5 +420,17 @@ bool content_is_locked(struct hlcache_handle *h); */ bool content_exec(struct hlcache_handle *h, const char *src, size_t srclen); +/** + * Determine if the content referred to any insecure objects. + * + * Query the content to determine if any of its referred objects were loaded + * in a manner not considered secure. For a content to be recursively + * secure it must only load over https and must not have certificate overrides + * in place. + * + * \param h The handle to the content + * \return Whether the content referred to any insecure objects + */ +bool content_saw_insecure_objects(struct hlcache_handle *h); #endif diff --git a/content/content_protected.h b/content/content_protected.h index ec62a2183..af0ee7259 100644 --- a/content/content_protected.h +++ b/content/content_protected.h @@ -83,6 +83,7 @@ struct content_handler { void (*add_user)(struct content *c); void (*remove_user)(struct content *c); bool (*exec)(struct content *c, const char *src, size_t srclen); + bool (*saw_insecure_objects)(struct content *c); /** handler dependant content sensitive internal data interface. */ void * (*get_internal)(const struct content *c, void *context); diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c index 25633a875..c49697b50 100644 --- a/content/handlers/html/html.c +++ b/content/handlers/html/html.c @@ -2667,6 +2667,34 @@ out_no_string: return result; } +/* See \ref content_saw_insecure_objects */ +static bool +html_saw_insecure_objects(struct content *c) +{ + html_content *htmlc = (html_content *)c; + struct content_html_object *obj = htmlc->object_list; + + /* Check through the object list */ + while (obj != NULL) { + if (obj->content != NULL) { + if (content_saw_insecure_objects(obj->content)) + return true; + } + } + + /* Now check the script list */ + if (html_saw_insecure_scripts(htmlc)) { + return true; + } + + /* Now check stylesheets */ + if (html_saw_insecure_stylesheets(htmlc)) { + return true; + } + + return false; +} + /** * Compute the type of a content * @@ -2710,6 +2738,7 @@ static const content_handler html_content_handler = { .get_encoding = html_encoding, .type = html_content_type, .exec = html_exec, + .saw_insecure_objects = html_saw_insecure_objects, .no_share = true, }; diff --git a/content/handlers/html/html_css.c b/content/handlers/html/html_css.c index 5550573ba..5d9987d5a 100644 --- a/content/handlers/html/html_css.c +++ b/content/handlers/html/html_css.c @@ -487,6 +487,23 @@ struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n) return c->stylesheets; } +/* exported interface documented in html/html_internal.h */ +bool html_saw_insecure_stylesheets(html_content *html) +{ + struct html_stylesheet *s; + unsigned int i; + + for (i = 0, s = html->stylesheets; i < html->stylesheet_count; + i++, s++) { + if (s->sheet != NULL) { + if (content_saw_insecure_objects(s->sheet)) { + return true; + } + } + } + + return false; +} /* exported interface documented in html/html_internal.h */ nserror html_css_free_stylesheets(html_content *html) diff --git a/content/handlers/html/html_internal.h b/content/handlers/html/html_internal.h index 388c1558d..11891e681 100644 --- a/content/handlers/html/html_internal.h +++ b/content/handlers/html/html_internal.h @@ -328,6 +328,11 @@ nserror html_script_free(html_content *htmlc); */ nserror html_script_invalidate_ctx(html_content *htmlc); +/** + * Check if any of the scripts loaded were insecure + */ +bool html_saw_insecure_scripts(html_content *htmlc); + /* in html/html_forms.c */ struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc); struct form_control *html_forms_get_control_for_node(struct form *forms, @@ -347,6 +352,9 @@ nserror html_css_new_stylesheets(html_content *c); nserror html_css_quirks_stylesheets(html_content *c); nserror html_css_free_stylesheets(html_content *html); +/** Return if any of the stylesheets were loaded insecurely */ +bool html_saw_insecure_stylesheets(html_content *html); + bool html_css_process_link(html_content *htmlc, dom_node *node); bool html_css_process_style(html_content *htmlc, dom_node *node); bool html_css_update_style(html_content *c, dom_node *style); diff --git a/content/handlers/html/html_script.c b/content/handlers/html/html_script.c index f7131e2a2..f4754fe8a 100644 --- a/content/handlers/html/html_script.c +++ b/content/handlers/html/html_script.c @@ -590,6 +590,31 @@ html_process_script(void *ctx, dom_node *node) } /* exported internal interface documented in html/html_internal.h */ +bool html_saw_insecure_scripts(html_content *htmlc) +{ + struct html_script *s; + unsigned int i; + + for (i = 0, s = htmlc->scripts; i != htmlc->scripts_count; i++, s++) { + if (s->type == HTML_SCRIPT_INLINE) { + /* Inline scripts are no less secure than their + * containing HTML content + */ + continue; + } + if (s->data.handle == NULL) { + /* We've not begun loading this? */ + continue; + } + if (content_saw_insecure_objects(s->data.handle)) { + return true; + } + } + + return false; +} + +/* exported internal interface documented in html/html_internal.h */ nserror html_script_free(html_content *html) { unsigned int i; diff --git a/desktop/browser_window.c b/desktop/browser_window.c index a9c277846..7227023af 100644 --- a/desktop/browser_window.c +++ b/desktop/browser_window.c @@ -4649,7 +4649,8 @@ browser_window_page_info_state browser_window_get_page_info_state( assert(bw != NULL); /* Do we have any parameters? If not -- UNKNOWN */ - if (bw->current_parameters.url == NULL) { + if (bw->current_parameters.url == NULL || + bw->current_content == NULL) { return PAGE_STATE_UNKNOWN; } @@ -4688,8 +4689,10 @@ browser_window_page_info_state browser_window_get_page_info_state( return PAGE_STATE_SECURE_OVERRIDE; } - /** \todo Determine if sub-elements of this fetch were insecure */ - /* If so, return PAGE_STATE_SECURE_ISSUES */ + /* If we've seen insecure content internally then we need to say so */ + if (content_saw_insecure_objects(bw->current_content)) { + return PAGE_STATE_SECURE_ISSUES; + } /* All is well, return secure state */ return PAGE_STATE_SECURE; |