mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-03 09:44:24 +03:00
HSTS: teach llcache to update and enforce policy.
This commit is contained in:
parent
f2121d1c0f
commit
83f5332708
@ -114,6 +114,8 @@ typedef struct {
|
||||
bool tried_with_tls_downgrade; /**< Whether we've tried TLS <= 1.0 */
|
||||
|
||||
bool outstanding_query; /**< Waiting for a query response */
|
||||
|
||||
bool tainted_tls; /**< Whether the TLS transport is tainted */
|
||||
} llcache_fetch_ctx;
|
||||
|
||||
/**
|
||||
@ -1856,6 +1858,86 @@ static nserror llcache_object_add_user(llcache_object *object,
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a request-URI based on HSTS policy
|
||||
*
|
||||
* \param url URL to transform
|
||||
* \param result Pointer to location to receive transformed URL
|
||||
* \param hsts_in_use Pointer to location to receive HSTS in-use flag
|
||||
* \return NSERROR_OK on success, appropriate error otherwise
|
||||
*/
|
||||
static nserror llcache_hsts_transform_url(nsurl *url, nsurl **result,
|
||||
bool *hsts_in_use)
|
||||
{
|
||||
lwc_string *scheme = NULL;
|
||||
bool match;
|
||||
nserror error = NSERROR_OK;
|
||||
|
||||
scheme = nsurl_get_component(url, NSURL_SCHEME);
|
||||
if (lwc_string_caseless_isequal(scheme, corestring_lwc_http,
|
||||
&match) != lwc_error_ok || match == false) {
|
||||
/* Non-HTTP fetch: ignore */
|
||||
lwc_string_unref(scheme);
|
||||
*result = nsurl_ref(url);
|
||||
*hsts_in_use = false;
|
||||
return error;
|
||||
}
|
||||
lwc_string_unref(scheme);
|
||||
|
||||
if (urldb_get_hsts_enabled(url)) {
|
||||
/* Only need to force HTTPS. If original port was explicitly
|
||||
* specified as 80, nsurl_create/join will remove it (as
|
||||
* it's redundant) */
|
||||
error = nsurl_replace_scheme(url, corestring_lwc_https,
|
||||
result);
|
||||
*hsts_in_use = (error == NSERROR_OK);
|
||||
} else {
|
||||
*result = nsurl_ref(url);
|
||||
*hsts_in_use = false;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update HSTS policy for target domain.
|
||||
*
|
||||
* \param object Newly-fetched cache object
|
||||
* \return NSERROR_OK on success, appropriate error otherwise
|
||||
*/
|
||||
static nserror llcache_hsts_update_policy(llcache_object *object)
|
||||
{
|
||||
size_t i;
|
||||
lwc_string *scheme = NULL;
|
||||
bool match = false;
|
||||
|
||||
scheme = nsurl_get_component(object->url, NSURL_SCHEME);
|
||||
if (lwc_string_caseless_isequal(scheme, corestring_lwc_https,
|
||||
&match) != lwc_error_ok || match == false) {
|
||||
/* Non-HTTPS fetch: ignore */
|
||||
lwc_string_unref(scheme);
|
||||
return NSERROR_OK;
|
||||
}
|
||||
lwc_string_unref(scheme);
|
||||
|
||||
if (object->fetch.tainted_tls) {
|
||||
/* Transport is tainted: ignore */
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
for (i = 0; i < object->num_headers; i++) {
|
||||
if (strcasecmp("Strict-Transport-Security",
|
||||
object->headers[i].name) == 0) {
|
||||
urldb_set_hsts_policy(object->url,
|
||||
object->headers[i].value);
|
||||
/* Only process the first one we find */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle FETCH_REDIRECT event
|
||||
*
|
||||
@ -1871,10 +1953,10 @@ static nserror llcache_fetch_redirect(llcache_object *object,
|
||||
llcache_object *dest;
|
||||
llcache_object_user *user, *next;
|
||||
const llcache_post_data *post = object->fetch.post;
|
||||
nsurl *url;
|
||||
nsurl *url, *hsts_url;
|
||||
lwc_string *scheme;
|
||||
lwc_string *object_scheme;
|
||||
bool match;
|
||||
bool match, hsts_in_use;
|
||||
/* Extract HTTP response code from the fetch object */
|
||||
long http_code = fetch_http_code(object->fetch.fetch);
|
||||
llcache_event event;
|
||||
@ -1906,15 +1988,23 @@ static nserror llcache_fetch_redirect(llcache_object *object,
|
||||
if (error != NSERROR_OK)
|
||||
return error;
|
||||
|
||||
/* Perform HSTS transform */
|
||||
error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
|
||||
if (error != NSERROR_OK) {
|
||||
nsurl_unref(url);
|
||||
return error;
|
||||
}
|
||||
nsurl_unref(url);
|
||||
|
||||
/* Inform users of redirect */
|
||||
event.type = LLCACHE_EVENT_REDIRECT;
|
||||
event.data.redirect.from = object->url;
|
||||
event.data.redirect.to = url;
|
||||
event.data.redirect.to = hsts_url;
|
||||
|
||||
error = llcache_send_event_to_users(object, &event);
|
||||
|
||||
if (error != NSERROR_OK) {
|
||||
nsurl_unref(url);
|
||||
nsurl_unref(hsts_url);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1922,7 +2012,7 @@ static nserror llcache_fetch_redirect(llcache_object *object,
|
||||
* A "validated" scheme is one over which we have some guarantee that
|
||||
* the source is trustworthy. */
|
||||
object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
|
||||
scheme = nsurl_get_component(url, NSURL_SCHEME);
|
||||
scheme = nsurl_get_component(hsts_url, NSURL_SCHEME);
|
||||
|
||||
/* resource: and about: are allowed to redirect anywhere */
|
||||
if ((lwc_string_isequal(object_scheme, corestring_lwc_resource,
|
||||
@ -1938,7 +2028,7 @@ static nserror llcache_fetch_redirect(llcache_object *object,
|
||||
&match) == lwc_error_ok && match == true)) {
|
||||
lwc_string_unref(object_scheme);
|
||||
lwc_string_unref(scheme);
|
||||
nsurl_unref(url);
|
||||
nsurl_unref(hsts_url);
|
||||
return NSERROR_OK;
|
||||
}
|
||||
}
|
||||
@ -1947,8 +2037,8 @@ static nserror llcache_fetch_redirect(llcache_object *object,
|
||||
lwc_string_unref(object_scheme);
|
||||
|
||||
/* Bail out if we've no way of handling this URL */
|
||||
if (fetch_can_fetch(url) == false) {
|
||||
nsurl_unref(url);
|
||||
if (fetch_can_fetch(hsts_url) == false) {
|
||||
nsurl_unref(hsts_url);
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
@ -1957,17 +2047,17 @@ static nserror llcache_fetch_redirect(llcache_object *object,
|
||||
post = NULL;
|
||||
} else if (http_code != 307 || post != NULL) {
|
||||
/** \todo 300, 305, 307 with POST */
|
||||
nsurl_unref(url);
|
||||
nsurl_unref(hsts_url);
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/* Attempt to fetch target URL */
|
||||
error = llcache_object_retrieve(url, object->fetch.flags,
|
||||
error = llcache_object_retrieve(hsts_url, object->fetch.flags,
|
||||
object->fetch.referer, post,
|
||||
object->fetch.redirect_count + 1, &dest);
|
||||
|
||||
/* No longer require url */
|
||||
nsurl_unref(url);
|
||||
nsurl_unref(hsts_url);
|
||||
|
||||
if (error != NSERROR_OK)
|
||||
return error;
|
||||
@ -2059,6 +2149,8 @@ static nserror llcache_fetch_notmodified(llcache_object *object,
|
||||
/* Mark it complete */
|
||||
object->fetch.state = LLCACHE_FETCH_COMPLETE;
|
||||
|
||||
(void) llcache_hsts_update_policy(object);
|
||||
|
||||
/* Old object will be flushed from the cache on the next poll */
|
||||
|
||||
return NSERROR_OK;
|
||||
@ -2253,6 +2345,9 @@ static nserror llcache_fetch_cert_error(llcache_object *object,
|
||||
/* Invalidate cache-control data */
|
||||
llcache_invalidate_cache_control_data(object);
|
||||
|
||||
/* Consider the TLS transport tainted */
|
||||
object->fetch.tainted_tls = true;
|
||||
|
||||
if (llcache->query_cb != NULL) {
|
||||
llcache_query query;
|
||||
|
||||
@ -2303,6 +2398,9 @@ static nserror llcache_fetch_ssl_error(llcache_object *object)
|
||||
/* Invalidate cache-control data */
|
||||
llcache_invalidate_cache_control_data(object);
|
||||
|
||||
/* Consider the TLS transport tainted */
|
||||
object->fetch.tainted_tls = true;
|
||||
|
||||
if (object->fetch.tried_with_tls_downgrade == true) {
|
||||
/* Have already tried to downgrade, so give up */
|
||||
llcache_event event;
|
||||
@ -2684,6 +2782,8 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
|
||||
/* record when the fetch finished */
|
||||
object->cache.fin_time = time(NULL);
|
||||
|
||||
(void) llcache_hsts_update_policy(object);
|
||||
|
||||
guit->misc->schedule(5000, llcache_persist, NULL);
|
||||
}
|
||||
break;
|
||||
@ -3483,23 +3583,34 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
|
||||
nserror error;
|
||||
llcache_object_user *user;
|
||||
llcache_object *object;
|
||||
nsurl *hsts_url;
|
||||
bool hsts_in_use;
|
||||
|
||||
/* Perform HSTS transform */
|
||||
error = llcache_hsts_transform_url(url, &hsts_url, &hsts_in_use);
|
||||
if (error != NSERROR_OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Can we fetch this URL at all? */
|
||||
if (fetch_can_fetch(url) == false) {
|
||||
if (fetch_can_fetch(hsts_url) == false) {
|
||||
nsurl_unref(hsts_url);
|
||||
return NSERROR_NO_FETCH_HANDLER;
|
||||
}
|
||||
|
||||
/* Create a new object user */
|
||||
error = llcache_object_user_new(cb, pw, &user);
|
||||
if (error != NSERROR_OK) {
|
||||
nsurl_unref(hsts_url);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Retrieve a suitable object from the cache,
|
||||
* creating a new one if needed. */
|
||||
error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
|
||||
error = llcache_object_retrieve(hsts_url, flags, referer, post, 0, &object);
|
||||
if (error != NSERROR_OK) {
|
||||
llcache_object_user_destroy(user);
|
||||
nsurl_unref(hsts_url);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -3511,6 +3622,8 @@ nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
|
||||
/* Users exist which are now not caught up! */
|
||||
llcache_users_not_caught_up();
|
||||
|
||||
nsurl_unref(hsts_url);
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user