Skip to content

Commit f924230

Browse files
authored
Documenting ruleset update channels (EFForg#16446)
1 parent 2f89b0d commit f924230

File tree

5 files changed

+177
-0
lines changed

5 files changed

+177
-0
lines changed
19.1 KB
Loading

docs/en_US/https-updates.png

8.5 KB
Loading

docs/en_US/my-lan.png

20.6 KB
Loading

docs/en_US/options.png

80.6 KB
Loading
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
* [Ruleset Update Channels](#ruleset-update-channels)
2+
* [Update Channel Format & Logic](#update-channel-format--logic)
3+
* [Publishing Custom Update Channels](#publishing-custom-update-channels)
4+
* [1. Creating an RSA key and generating a `jwk` object from it](#1-creating-an-rsa-key-and-generating-a-jwk-object-from-it)
5+
* [2. Signing rulesets with this key](#2-signing-rulesets-with-this-key)
6+
* [Setup](#setup)
7+
* [Signing](#signing)
8+
* [3. Publishing those rulesets somewhere](#3-publishing-those-rulesets-somewhere)
9+
* [4. Getting users to use your update channel](#4-getting-users-to-use-your-update-channel)
10+
* [Adding and Deleting Update Channels](#adding-and-deleting-update-channels)
11+
12+
# Ruleset Update Channels
13+
14+
Whenever you download HTTPS Everywhere, it comes with a long list of *rulesets* that are maintained by the community. These rulesets tell HTTPS Everywhere when and how to redirect requests to the secure version of a site. HTTPS Everywhere includes tens of thousands of these rulesets, which are public and ever-changing as we expand and improve coverage. They are delivered to you with each new version of the extension, along with all the code that makes up the extension itself. Between and in addition to extension updates, code within the extension fetches regular updates to the rulesets. This ensures that you get more up-to-date coverage for sites that offer HTTPS, and you'll encounter fewer sites that break due to bugs in our list of supported sites.
15+
16+
![](https-updates.png)
17+
18+
We deliver these rulesets via what we call an *update channel*. Currently, HTTPS Everywhere is delivered with a single update channel, named `EFF (Full)`. You can see this channel when you click on the HTTPS Everywhere icon and look at the bottom of the popup:
19+
20+
![](https-everywhere-popup.png)
21+
22+
First, the extension version is shown (in this case 2018.8.22), and then the version of the rulesets for a given update channel is shown (in this case 2018.8.30).
23+
24+
## Update Channel Format & Logic
25+
26+
Update channels can be found in [`chromium/background-scripts/update_channels.js`](https://github.com/EFForg/https-everywhere/blob/master/chromium/background-scripts/update_channels.js), and consist of:
27+
28+
1. A `name` string, which identifies it and will be displayed in the extension popup
29+
2. A `jwk` object, which defines the RSA public key to use when verifying downloaded rulesets
30+
3. A `update_path_prefix` string, which tells the extension where to look for new rulesets
31+
4. A `scope` string, which is used to construct a JavaScript `RegExp` object
32+
33+
Every 24 hours, the extension checks the URL contained in `update_path_prefix` appended with `/latest-rulesets-timestamp` (in the case of `EFF (Full)`, `https://www.https-rulesets.org/v1//latest-rulesets-timestamp`). If it discovers the timestamp has updated since the last time it fetched the rulesets, it will download a new ruleset, following the format `update_path_prefix` appended with `default.rulesets.XXXXXXXXXX.gz`, where `XXXXXXXXXX` is the timestamp discovered in the previous request.
34+
35+
It then attempts to verify the rulesets, which are signed with the private RSA key corresponding to the public key in the update channel's `jwk` object. If the signature verifies, the rulesets are stored and applied to the running instance of the extension. If it can not be verified, the rulesets are discarded and the last known good state is used.
36+
37+
Once the rulesets are stored, they will be allowed to operate on URLs only within the `scope` of the update channel, as found above. URLs must match the regular expression in this string in order to be redirected. This string will be used as the first and only argument when constructing a JavaScript `RegExp` object. If you wanted to define an update channel that only operated on URLs with the `www` subdomain, you could do so by entering the string `^https?://www\\.`, for example:
38+
39+
```javascript
40+
> re = new RegExp('^https?://www\\.');
41+
/^https?:\/\/www\./
42+
> "http://www.example.com/".match(re);
43+
[ 'http://www.',
44+
index: 0,
45+
input: 'http://www.example.com/',
46+
groups: undefined ]
47+
> "http://example.com/".match(re);
48+
null
49+
```
50+
51+
## Publishing Custom Update Channels
52+
53+
In addition to the rulesets contained in the EFF update channel, you may want to publish your own. There are a few instances where this may be useful:
54+
55+
1. You are on a corporate LAN and would rather not divulge the internal DNS records for various services by submitting rulesets to the public list
56+
2. You are an organization that verifies `onion` services, and would like to create vanity URLs for the `onion` services that you've verified (this will make [usability of onion URLs](https://blog.torproject.org/cooking-onions-names-your-onions) much better)
57+
3. You would like to implement tracker blocking within HTTPS Everywhere by forwarding a list of hosts to an unroutable address
58+
59+
There may be additional use cases not enumerated here. For this to be effective, an organization has to publish their own custom update channel. This involves a few steps:
60+
61+
1. Creating an RSA key and generating a `jwk` object from it
62+
2. Signing rulesets with this key
63+
3. Publishing those rulesets somewhere
64+
4. Getting users to use your update channel
65+
66+
We will go through each of these in sequence, but first, you'll want to consider if you want your signing process airgapped or not. Airgapped signing has the advantage of making it hard for malware to exfiltrate key material and thus forge a signed ruleset update, but it will also make it slightly more difficult to sign. If you decide on an airgapped signing process, you may want to copy the script [`utils/sign-rulesets/async-airgap.sh`](https://github.com/EFForg/https-everywhere/blob/master/utils/sign-rulesets/async-airgap.sh) to it *before* cutting off networking for the last time. You may also want to install the `python-qr` code on this machine to easily copy the RSA public key to your development environment, once generated, as well as `qrencode` and `eog` for ease in the signing process.
67+
68+
### 1. Creating an RSA key and generating a `jwk` object from it
69+
70+
To create an RSA key, issue the following command (either on your development machine or an airgap):
71+
72+
openssl genrsa -out key.pem 4092
73+
74+
Your RSA keypair will now be stored in the file `key.pem`. To generate a corresping public key, issue this command:
75+
76+
openssl rsa -in key.pem -outform PEM -pubout -out public.pem
77+
78+
Your public key is now stored in `public.pem`. If you are using an airgap, copy this public key (with whatever method is safest in your setup, perhaps with the `qr` command) to your development environment.
79+
80+
At this point, you will need to generate a `jwk` object from the public key. This can be done with the `pem-jwk` node package. You'll have to download node.js and npm, or just issue this command in docker:
81+
82+
sudo docker run -it -v $(pwd):/opt --workdir /opt node bash
83+
84+
And you will be booted into a node environment. Next, run
85+
86+
npm install -g pem-jwk
87+
88+
This will install the `pem-jwk` package globally. You can now run
89+
90+
cat public.pem | pem-jwk
91+
92+
And you should see a `jwk` object displayed. Take note of this, you will need it later.
93+
94+
### 2. Signing rulesets with this key
95+
96+
#### Setup
97+
98+
On your development machine, clone or download the HTTPS Everywhere repository. Since it's quite large, it will suffice to do a shallow clone:
99+
100+
git clone --depth=1 https://github.com/EFForg/https-everywhere.git
101+
102+
or
103+
104+
curl -sLO https://github.com/EFForg/https-everywhere/archive/master.zip; unzip master.zip; mv https-everywhere-master https-everywhere
105+
106+
Next,
107+
108+
cd https-everywhere
109+
rm rules/*.xml
110+
111+
This will remove all the rulesets bundled with the extension itself. All the rulesets you want to sign for your update channel must be in the `rules` directory before moving to the next step. Generate an example ruleset or use your own ruleset:
112+
113+
cd rules
114+
./make-trivial-rule example.com
115+
cd ..
116+
117+
#### Signing
118+
119+
You will need python 3.6 on your system or available via docker for the next step.
120+
121+
sudo docker run -it -v $(pwd):/opt --workdir /opt python:3.6 bash
122+
123+
Next, run
124+
125+
python3.6 utils/merge-rulesets.py
126+
127+
You should see the following output:
128+
129+
```shell
130+
* Parsing XML ruleset and constructing JSON library...
131+
* Writing JSON library to src/chrome/content/rules/default.rulesets
132+
* Everything is okay.
133+
```
134+
135+
This prepares the file you are about to sign. If your do not have an airgap, run the following command:
136+
137+
utils/sign-rulesets/standalone.sh /path/to/key.pem /some/output/path
138+
139+
If you have an airgapped setup, run the following command on your development machine:
140+
141+
utils/sign-rulesets/async-request.sh /path/to/public.pem /some/output/path
142+
143+
This will display a hash for signing, as well as a metahash. On your airgap machine, run the `async-airgap.sh` script that you had previously copied to it:
144+
145+
./async-airgap.sh /path/to/key.pem SHA256_HASH
146+
147+
typing the hash carefully. Check the metahash to make sure it is the same as what was displayed on your development machine. This will output base64-encoded data as well as a QR code representing that data that you can scan, and send that data to your development machine. Once you have that data from the QR code pasted into the development machine prompt, press Ctrl-D and you should have output indicating that your rulesets have been signed successfully.
148+
149+
### 3. Publishing those rulesets somewhere
150+
151+
Once you've signed the rulesets successfully, choose a public URL to make these rulesets accessible. You may want to use a CDN if you expect a lot of traffic on this endpoint. Your rulesets as well as their signatures are stored in `/some/output/path` you chose above, you need only to upload them to an endpoint your users can access.
152+
153+
### 4. Getting users to use your update channel
154+
155+
Once you've established an update channel by published your rulesets, you'll want to let your users know how to use them. From step 1 above, you have a `jwk` object. You may want to also only allow modification of certain URLs, using the `scope` field. The `update_path_prefix` field will simply be the public URL that you chose in step 3.
156+
157+
If your users are using a custom build of HTTPS Everywhere (such as in a corporate LAN environment), you can modify [`chromium/background-scripts/update_channels.js`](https://github.com/EFForg/https-everywhere/blob/master/chromium/background-scripts/update_channels.js) to include a new update channel in the same format as the EFF update channel.
158+
159+
In most cases, your users will just be using a standard HTTPS Everywhere build. In this case, they will have to add your update channel using the UX, as explained below.
160+
161+
## Adding and Deleting Update Channels
162+
163+
In addition to being defined in `update_channels.js`, users can add additional update channels via the extension options.
164+
165+
In Firefox, enter `about:addons` into the URL bar, then click on `Extensions` on the left navbar, then click `Preferences` next to the HTTPS Everywhere extension.
166+
167+
In Chrome, right-click on the HTTPS Everywhere icon and click `Options`.
168+
169+
You will now see the HTTPS Everywhere options page. Click `Update Channels`.
170+
171+
You will now see a list of update channels, with `EFF (Full)` being the first. Below, you can add a new update channel. Once you hit `Update`, the channel will download a new ruleset release (if available) from the channel.
172+
173+
![](options.png)
174+
175+
If a new ruleset update is available, after a few seconds you should now see the new ruleset version in the bottom of the extension popup:
176+
177+
![](my-lan.png)

0 commit comments

Comments
 (0)