Allow contents to indicate if they believe they may not be secure.

HTML contents reference many other objects.  The browser window
needs to know if any of them may not be secure, in which case it
needs to report that in its page state.  If other content types
might refer to sub-contents, they will need to define the callback
too.

Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
This commit is contained in:
Daniel Silverstone 2019-12-01 15:49:08 +00:00
parent 9741df214d
commit 6fc2666d07
No known key found for this signature in database
GPG Key ID: C30DF439F2987D74
8 changed files with 143 additions and 3 deletions

View File

@ -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"
@ -563,6 +564,50 @@ bool content_exec(struct hlcache_handle *h, const char *src, size_t srclen)
return c->handler->exec(c, src, 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)

View File

@ -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

View File

@ -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);

View File

@ -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,
};

View File

@ -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)

View File

@ -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);

View File

@ -589,6 +589,31 @@ html_process_script(void *ctx, dom_node *node)
return err;
}
/* 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)
{

View File

@ -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;