about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJosh Rickmar <jrick@devio.us>2012-07-31 09:55:26 -0400
committerJosh Rickmar <jrick@devio.us>2012-07-31 09:55:26 -0400
commit0c240f728d489408cda135786cf29244c1cd4d83 (patch)
treee063f765a1c73d301ec3ad5e8a5904165337a63e
parent02e03fcb67ee3ee37ff7bd5f287a7c53ca55f97e (diff)
downloadxombrero-0c240f728d489408cda135786cf29244c1cd4d83.tar.gz
Add a force_https setting (using the same domain syntax as the
whitelist settings) to make all requests to that domain use the HTTPS
scheme, similar to HSTS.

Install a new file, hsts-preload, into the resource dir.  This is a
regular config file with a bunch of force_https = ... lines, which is
used to implement a preloaded HSTS list.  Right now all the domains in
this file, except for conformal.com and cyphertite.com, are taken
directly from chromium's preloaded HSTS list (and should be synced
with this file every so often).  Also implement a new setting,
preload_strict_transport (enabled by default), to enable or disable
the loading of this preloaded HSTS list.  Document force_https and
preload_strict_transport in the manpage.
-rw-r--r--Makefile1
-rw-r--r--freebsd/Makefile1
-rw-r--r--hsts-preload108
-rw-r--r--linux/Makefile3
-rw-r--r--settings.c35
-rw-r--r--unix.c2
-rw-r--r--whitelist.c6
-rw-r--r--xombrero.120
-rw-r--r--xombrero.c44
-rw-r--r--xombrero.conf10
-rw-r--r--xombrero.h9
11 files changed, 228 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 5867dcb..e9ada1a 100644
--- a/Makefile
+++ b/Makefile
@@ -62,6 +62,7 @@ beforeinstall:
 	install -m 644 ${.CURDIR}/xombreroicon128.png ${PREFIX}/share/xombrero
 	install -m 644 ${.CURDIR}/tld-rules ${PREFIX}/share/xombrero
 	install -m 644 ${.CURDIR}/style.css ${PREFIX}/share/xombrero
+	install -m 644 ${.CURDIR}/hsts-preload ${PREFIX}/share/xombrero
 
 ${PROG} ${OBJS} beforedepend: javascript.h
 
diff --git a/freebsd/Makefile b/freebsd/Makefile
index a6be6af..9ed119b 100644
--- a/freebsd/Makefile
+++ b/freebsd/Makefile
@@ -72,6 +72,7 @@ install: all
 	install -m 644 ../xombreroicon128.png $(DESTDIR)$(RESDIR)
 	install -m 644 ../tld-rules $(DESTDIR)$(RESDIR)
 	install -m 644 ../style.css $(DESTDIR)$(RESDIR)
+	install -m 644 ../hsts-preload $(DESTDIR)$(RESDIR)
 
 clean:
 	rm -f xombrero *.o
diff --git a/hsts-preload b/hsts-preload
new file mode 100644
index 0000000..5bff60d
--- /dev/null
+++ b/hsts-preload
@@ -0,0 +1,108 @@
+force_https = bitbucket.org
+force_https = .bitrig.org
+force_https = .conformal.com
+force_https = .conformalsys.org
+force_https = .cyphertite.com
+force_https = .defcon.org
+force_https = duck.co
+force_https = .eff.org
+force_https = github.com
+force_https = gist.github.com
+force_https = bugzilla.gnome.org
+force_https = lobste.rs
+force_https = .bugzilla.mozilla.org
+force_https = mtgox.com
+force_https = gitweb.torproject.org
+force_https = twitter.com
+
+# sites from chromium's preloaded HSTS list
+# http://src.chromium.org/viewvc/chrome/trunk/src/net/base/transport_security_state_static.json?view=markup
+force_https = .market.android.com
+force_https = .ssl.google-analytics.com
+force_https = .googleplex.com
+force_https = www.paypal.com
+force_https = www.elanex.biz
+force_https = .jottit.com
+force_https = .sunshinepress.org
+force_https = www.noisebridge.net
+force_https = .neg9.org
+force_https = .riseup.net
+force_https = factor.cc
+force_https = members.mayfirst.org
+force_https = support.mayfirst.org
+force_https = id.mayfirst.org
+force_https = lists.mayfirst.org
+force_https = aladdinschools.appspot.com
+force_https = .ottospora.nl
+force_https = www.paycheckrecords.com
+force_https = lastpass.com
+force_https = www.lastpass.com
+force_https = .keyerror.com
+force_https = entropia.de
+force_https = www.entropia.de
+force_https = .romab.com
+force_https = logentries.com
+force_https = www.logentries.com
+force_https = .stripe.com
+force_https = .cloudsecurityalliance.org
+force_https = .login.sapo.pt
+force_https = .mattmccutchen.net
+force_https = .betnet.fr
+force_https = .uprotect.it
+force_https = squareup.com
+force_https = .cert.se
+force_https = .crypto.is
+force_https = .simon.butcher.name
+force_https = .linx.net
+force_https = dropcam.com
+force_https = www.dropcam.com
+force_https = .ebanking.indovinabank.com.vn
+force_https = epoxate.com
+force_https = torproject.org
+force_https = .blog.torproject.org
+force_https = .check.torproject.org
+force_https = .www.torproject.org
+force_https = .www.moneybookers.com
+force_https = ledgerscope.net
+force_https = www.ledgerscope.net
+force_https = kyps.net
+force_https = www.kyps.net
+force_https = .app.recurly.com
+force_https = .api.recurly.com
+force_https = greplin.com
+force_https = www.greplin.com
+force_https = .luneta.nearbuysystems.com
+force_https = .ubertt.org
+force_https = .pixi.me
+force_https = .grepular.com
+force_https = mydigipass.com
+force_https = www.mydigipass.com
+force_https = developer.mydigipass.com
+force_https = www.developer.mydigipass.com
+force_https = sandbox.mydigipass.com
+force_https = www.sandbox.mydigipass.com
+force_https = .crypto.cat
+force_https = .bigshinylock.minazo.net
+force_https = .crate.io
+force_https = .braintreegateway.com
+force_https = braintreepayments.com
+force_https = www.braintreepayments.com
+force_https = emailprivacytester.com
+force_https = .business.medbank.com.mt
+force_https = .arivo.com.br
+force_https = .www.apollo-auto.com
+force_https = .www.cueup.com
+force_https = jitsi.org
+force_https = www.jitsi.org
+force_https = download.jitsi.org
+force_https = .sol.io
+force_https = irccloud.com
+force_https = www.irccloud.com
+force_https = alpha.irccloud.com
+force_https = .passwd.io
+force_https = .browserid.org
+force_https = .login.persona.org
+force_https = gmail.com
+force_https = googlemail.com
+force_https = www.gmail.com
+force_https = www.googlemail.com
diff --git a/linux/Makefile b/linux/Makefile
index c0c2455..8d4e3cf 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -61,6 +61,7 @@ install: all
 	install -m 644 ../xombreroicon128.png $(DESTDIR)$(RESDIR)
 	install -m 644 ../tld-rules $(DESTDIR)$(RESDIR)
 	install -m 644 ../style.css $(DESTDIR)$(RESDIR)
+	install -m 644 ../hsts-preload $(DESTDIR)$(RESDIR)
 
 uninstall:
 	rm -f $(DESTDIR)$(BINDIR)/xombrero
@@ -71,7 +72,9 @@ uninstall:
 	rm -f $(DESTDIR)$(RESDIR)/xombreroicon48.png
 	rm -f $(DESTDIR)$(RESDIR)/xombreroicon64.png
 	rm -f $(DESTDIR)$(RESDIR)/xombreroicon128.png
+	rm -f $(DESTDIR)$(RESDIR)/tld-rules
 	rm -f $(DESTDIR)$(RESDIR)/style.css
+	rm -f $(DESTDIR)$(RESDIR)/hsts-preload
 	if [ -d $(DESTDIR)$(RESDIR) ]; then rmdir $(DESTDIR)$(RESDIR); fi
 clean:
 	rm -f xombrero $(OBJS) $(DEPS)
diff --git a/settings.c b/settings.c
index 053d145..0850b4e 100644
--- a/settings.c
+++ b/settings.c
@@ -112,6 +112,7 @@ int		warn_cert_changes = 0;
 int		allow_insecure_content = XT_DS_ALLOW_INSECURE_CONTENT;
 int		allow_insecure_scripts = XT_DS_ALLOW_INSECURE_SCRIPTS;
 int		do_not_track = XT_DS_DO_NOT_TRACK;
+int		preload_strict_transport = XT_DS_PRELOAD_STRICT_TRANSPORT;
 
 char		*cmd_font_name = NULL;	/* these are all set at startup */
 char		*oops_font_name = NULL;
@@ -140,6 +141,7 @@ int		add_ua(struct settings *, char *);
 int		add_http_accept(struct settings *, char *);
 int		add_cmd_alias(struct settings *, char *);
 int		add_custom_uri(struct settings *, char *);
+int		add_force_https(struct settings *, char *);
 
 int		set_append_next(char *);
 int		set_autofocus_onload(char *);
@@ -226,6 +228,8 @@ void		walk_cmd_alias(struct settings *, void (*)(struct settings *,
 		    char *, void *), void *);
 void		walk_custom_uri(struct settings *, void (*)(struct settings *,
 		    char *, void *), void *);
+void		walk_force_https(struct settings *, void (*)(struct settings *,
+		    char *, void *), void *);
 
 int
 set_http_proxy(char *proxy)
@@ -395,6 +399,12 @@ struct special		s_userstyle = {
 	NULL
 };
 
+struct special		s_force_https = {
+	add_force_https,
+	NULL,
+	walk_force_https
+};
+
 struct settings		rs[] = {
 	{ "allow_insecure_content",	XT_S_INT, 0,		&allow_insecure_content, NULL, NULL, NULL, set_allow_insecure_content },
 	{ "allow_insecure_scripts",	XT_S_INT, 0,		&allow_insecure_scripts, NULL, NULL, NULL, set_allow_insecure_scripts },
@@ -442,6 +452,7 @@ struct settings		rs[] = {
 	{ "max_connections",		XT_S_INT, XT_SF_RESTART,&max_connections, NULL, NULL, NULL, NULL },
 	{ "max_host_connections",	XT_S_INT, XT_SF_RESTART,&max_host_connections, NULL, NULL, NULL, NULL },
 	{ "oops_font",			XT_S_STR, 0, NULL, &oops_font_name, NULL, NULL, set_oops_font },
+	{ "preload_strict_transport",	XT_S_INT, 0,		&preload_strict_transport, NULL, NULL, NULL, NULL },
 	{ "read_only_cookies",		XT_S_INT, 0,		&read_only_cookies, NULL, NULL, NULL, set_read_only_cookies },
 	{ "referer",			XT_S_STR, 0, NULL, NULL,&s_referer, NULL, set_referer_rt },
 	{ "refresh_interval",		XT_S_INT, 0,		&refresh_interval, NULL, NULL, NULL, set_refresh_interval },
@@ -478,6 +489,7 @@ struct settings		rs[] = {
 	{ "cmd_alias",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cmd_alias, NULL, NULL },
 	{ "cookie_wl",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cookie_wl, NULL, NULL },
 	{ "custom_uri",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_uri, NULL, NULL },
+	{ "force_https",		XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_force_https, NULL, NULL },
 	{ "http_accept",		XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_http_accept, NULL, NULL },
 	{ "js_wl",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_js, NULL, NULL },
 	{ "keybinding",			XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_kb, NULL, NULL },
@@ -1476,6 +1488,14 @@ walk_ua(struct settings *s,
 }
 
 int
+add_force_https(struct settings *s, char *value)
+{
+	wl_add(value, &force_https,
+	    XT_WL_FLAG_HANDY | XT_WL_FLAG_EXCLUDE_SUBDOMAINS);
+	return (0);
+}
+
+int
 add_http_accept(struct settings *s, char *value)
 {
 	struct http_accept		*ha;
@@ -2582,6 +2602,21 @@ walk_pl_wl(struct settings *s,
 		cb(s, d->d, cb_args);
 }
 
+void
+walk_force_https(struct settings *s,
+    void (*cb)(struct settings *, char *, void *), void *cb_args)
+{
+	struct domain		*d;
+
+	if (s == NULL || cb == NULL) {
+		show_oops(NULL, "walk_force_https invalid parameters");
+		return;
+	}
+
+	RB_FOREACH_REVERSE(d, domain_list, &force_https)
+		cb(s, d->d, cb_args);
+}
+
 int
 settings_add(char *var, char *val)
 {
diff --git a/unix.c b/unix.c
index e7a883e..93d0b1c 100644
--- a/unix.c
+++ b/unix.c
@@ -19,7 +19,7 @@
 void
 init_unix(void)
 {
-	resource_dir = g_strdup("/usr/local/share/xombrero/");
+	resource_dir = g_strdup("/usr/local/share/xombrero");
 }
 
 void	(*os_init)(void) = init_unix;
diff --git a/whitelist.c b/whitelist.c
index 9719dac..2c3ee01 100644
--- a/whitelist.c
+++ b/whitelist.c
@@ -266,7 +266,7 @@ wl_show(struct tab *t, struct karg *args, char *title, struct domain_list *wl)
 }
 
 void
-wl_add(char *str, struct domain_list *wl, int handy)
+wl_add(const char *str, struct domain_list *wl, int flags)
 {
 	struct domain		*d;
 	int			add_dot = 0;
@@ -282,7 +282,7 @@ wl_add(char *str, struct domain_list *wl, int handy)
 		str = &str[1];
 	else if (str[0] == '.')
 		str = &str[0];
-	else
+	else if (!(flags & XT_WL_FLAG_EXCLUDE_SUBDOMAINS))
 		add_dot = 1;
 
 	/* slice off port number */
@@ -295,7 +295,7 @@ wl_add(char *str, struct domain_list *wl, int handy)
 		d->d = g_strdup_printf(".%s", str);
 	else
 		d->d = g_strdup(str);
-	d->handy = handy;
+	d->handy = flags & XT_WL_FLAG_HANDY;
 
 	if (RB_INSERT(domain_list, wl, d))
 		goto unwind;
diff --git a/xombrero.1 b/xombrero.1
index 6cf5c27..a896599 100644
--- a/xombrero.1
+++ b/xombrero.1
@@ -1232,6 +1232,14 @@ Enables a backward, forward, and stop button to the toolbar.
 Additionally if
 .Cm search_string
 is set it'll enable an entry box for searches.
+.It Cm force_https
+This setting is used to define the domains of sites that should be
+only accessed over the HTTPS scheme.
+Any requests to these domains over HTTP will be rewritten to use HTTPS
+instead.
+See
+.Cm cookie_wl
+for semantics.
 .It Cm guess_search
 When enabled
 .Nm
@@ -1365,6 +1373,18 @@ This is a plugin whitelist item.
 See
 .Cm cookie_wl
 for semantics and more details.
+.It Cm preload_strict_transport
+If enabled, a preloaded list of sites which set the HTTP Strict
+Transport Security header will be used to automatically set the
+.Cm force_https
+setting for these sites.
+This is used to prevent SSL stripping attacks when first visiting
+these sites, before they have been added to the strict-transport file.
+This list is comprised of domains chosen by the
+.Nm
+authors, as well as domains included in Chromium's preloaded HSTS
+list.
+Default is 1.
 .It Cm read_only_cookies
 Mark cookies file read-only and discard all cookies once the session is
 terminated.
diff --git a/xombrero.c b/xombrero.c
index 439b367..b215e32 100644
--- a/xombrero.c
+++ b/xombrero.c
@@ -216,6 +216,7 @@ struct session_list	sessions;
 struct domain_list	c_wl;
 struct domain_list	js_wl;
 struct domain_list	pl_wl;
+struct domain_list	force_https;
 struct strict_transport_tree	st_tree;
 struct undo_tailq	undos;
 struct keybinding_list	kbl;
@@ -4722,6 +4723,20 @@ corrupt_file:
 	return (1);
 }
 
+int
+force_https_check(const char *uri)
+{
+	struct domain		*d = NULL;
+
+	if (uri == NULL)
+		return (0);
+
+	if ((d = wl_find_uri(uri, &force_https)) == NULL)
+		return (0);
+	else
+		return (1);
+}
+
 void
 strict_transport_security_cb(SoupMessage *msg, gpointer data)
 {
@@ -4918,19 +4933,23 @@ webview_rrs_cb(WebKitWebView *wv, WebKitWebFrame *wf, WebKitWebResource *res,
     WebKitNetworkRequest *request, WebKitNetworkResponse *response,
     struct tab *t)
 {
-	SoupMessage		*msg;
-	SoupURI			*uri;
-	struct http_accept	ha_find, *ha;
-	const char		*accept;
+	SoupMessage		*msg = NULL;
+	SoupURI			*uri = NULL;
+	struct http_accept	ha_find, *ha = NULL;
+	const char		*accept = NULL;
+	char			*uri_s = NULL;
 
 	msg = webkit_network_request_get_message(request);
 	if (!msg) return;
 
 	uri = soup_message_get_uri(msg);
-	if (!uri) return;
+	if (!uri)
+		return;
+	uri_s = soup_uri_to_string(uri, FALSE);
 
 	if (strcmp(uri->scheme, SOUP_URI_SCHEME_HTTP) == 0) {
-		if (strict_transport_check(uri->host)) {
+		if (strict_transport_check(uri->host) ||
+		    force_https_check(uri_s)) {
 			DNPRINTF(XT_D_NAV, "webview_rrs_cb: force https for %s\n",
 					uri->host);
 			soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTPS);
@@ -4946,7 +4965,7 @@ webview_rrs_cb(WebKitWebView *wv, WebKitWebFrame *wf, WebKitWebResource *res,
 		    "Accept");
 		if (accept == NULL ||
 		    strncmp(accept, "text/html", strlen("text/html")))
-			return;
+			goto done;
 
 		ha_find.id = t->http_accept_id;
 		ha = RB_FIND(http_accept_list, &ha_list, &ha_find);
@@ -4963,6 +4982,9 @@ webview_rrs_cb(WebKitWebView *wv, WebKitWebFrame *wf, WebKitWebResource *res,
 		soup_message_headers_replace(msg->request_headers, "Accept",
 		    http_accept->value);
 	}
+done:
+	if (uri_s)
+		g_free(uri_s);
 }
 
 WebKitWebView *
@@ -8365,6 +8387,7 @@ main(int argc, char **argv)
 	RB_INIT(&hl);
 	RB_INIT(&js_wl);
 	RB_INIT(&pl_wl);
+	RB_INIT(&force_https);
 	RB_INIT(&downloads);
 	RB_INIT(&st_tree);
 	RB_INIT(&svl);
@@ -8494,6 +8517,13 @@ main(int argc, char **argv)
 		    pwd->pw_dir, XT_CONF_FILE);
 	config_parse(conf, 0);
 
+	/* read preloaded HSTS list */
+	if (preload_strict_transport) {
+		snprintf(conf, sizeof conf, "%s" PS "%s",
+		    resource_dir, XT_HSTS_PRELOAD_FILE);
+		config_parse(conf, 0);
+	}
+
 	/* init fonts */
 	cmd_font = pango_font_description_from_string(cmd_font_name);
 	oops_font = pango_font_description_from_string(oops_font_name);
diff --git a/xombrero.conf b/xombrero.conf
index b3643c4..f04eddb 100644
--- a/xombrero.conf
+++ b/xombrero.conf
@@ -59,6 +59,7 @@
 # userstyle_global	= 1
 # enable_favicon_entry	= 0
 # enable_favicon_tabs	= 1
+# preload_strict_transport = 1
 # referer		= always
 # warn_cert_changes	= 1
 
@@ -146,6 +147,15 @@
 
 
 ##
+## FORCE HTTPS FOR SITES
+##
+
+# Add the domains of sites that should be only accesed over HTTPS.
+
+# force_https		= .conformal.com
+
+
+##
 ## MIME TYPES
 ##
 
diff --git a/xombrero.h b/xombrero.h
index 218d712..cd8f4c7 100644
--- a/xombrero.h
+++ b/xombrero.h
@@ -370,6 +370,7 @@ RB_PROTOTYPE(http_accept_list, http_accept, entry, http_accept_rb_cmp);
 #define XT_CSS_FILE		("xombrero.css")
 #define XT_FAVS_FILE		("favorites")
 #define XT_SOD_FILE		("startofday")
+#define XT_HSTS_PRELOAD_FILE	("hsts-preload")
 #define XT_RESERVED_CHARS	"$&+,/:;=?@ \"<>#%%{}|^~[]`"
 
 int			run_script(struct tab *, char *);
@@ -525,6 +526,9 @@ void			startpage_add(const char *, ...);
 #define XT_WL_COOKIE		(2)
 #define XT_WL_PLUGIN		(3)
 
+#define XT_WL_FLAG_HANDY	(1<<0)
+#define XT_WL_FLAG_EXCLUDE_SUBDOMAINS	(1<<1)
+
 struct domain {
 	RB_ENTRY(domain)	entry;
 	gchar			*d;
@@ -648,6 +652,7 @@ int		command_mode(struct tab *, struct karg *);
 #define XT_DS_ALLOW_INSECURE_CONTENT	(TRUE)
 #define XT_DS_ALLOW_INSECURE_SCRIPTS	(TRUE)
 #define XT_DS_DO_NOT_TRACK	(0)
+#define XT_DS_PRELOAD_STRICT_TRANSPORT	(1)
 
 
 /* actions */
@@ -739,6 +744,8 @@ int		cert_cmd(struct tab *, struct karg *);
 void		focus_webview(struct tab *);
 int		is_g_object_setting(GObject *, char *);
 int		set_scrollbar_visibility(struct tab *, int);
+void		wl_add(const char *, struct domain_list *, int);
+void		preload_hsts(void);
 
 #define		XT_DL_START	(0)
 #define		XT_DL_RESTART	(1)
@@ -828,6 +835,7 @@ extern regex_t	url_re;
 extern int	allow_insecure_content;
 extern int	allow_insecure_scripts;
 extern int	do_not_track;
+extern int	preload_strict_transport;
 
 /* globals */
 extern void		(*os_init)(void);
@@ -854,6 +862,7 @@ extern struct about_type	about_list[];
 extern struct domain_list	c_wl;
 extern struct domain_list	js_wl;
 extern struct domain_list	pl_wl;
+extern struct domain_list	force_https;
 extern struct strict_transport_tree	st_tree;
 extern struct alias_list	aliases;
 extern struct mime_type_list	mtl;