Skip to content

Commit 194a575

Browse files
Mike Perrypde
authored andcommitted
Clean up submission mechanisms, improve logging.
Also toss in some filtering primatives for privacy and load.
1 parent f7c97f4 commit 194a575

File tree

2 files changed

+97
-36
lines changed

2 files changed

+97
-36
lines changed

src/components/ssl-observatory.js

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,39 +27,21 @@ function SSLObservatory() {
2727
this.prefs = Components.classes["@mozilla.org/preferences-service;1"]
2828
.getService(Components.interfaces.nsIPrefBranch);
2929

30-
dump("Dump: Loaded observatory component\n");
31-
this.log(DBUG, "Loaded observatory component!");
32-
3330
try {
3431
// Check for torbutton
3532
this.tor_logger = Components.classes["@torproject.org/torbutton-logger;1"]
3633
.getService(Components.interfaces.nsISupports).wrappedJSObject;
37-
3834
this.torbutton_installed = true;
39-
40-
// If the user wants to use their Tor proxy, grab it automatically
41-
if (this.prefs.getBoolPref("extensions.https_everywhere._prefs.use_tor_proxy")) {
42-
// extract torbutton proxy settings
43-
this.proxy_port = this.prefs.getIntPref("extensions.torbutton.https_port");
44-
this.proxy_host = this.prefs.getCharPref("extensions.torbutton.https_proxy");
45-
this.proxy_type = "http";
46-
47-
if (!this.proxy_port) {
48-
this.proxy_host = this.prefs.getCharPref("extensions.torbutton.socks_host");
49-
this.proxy_port = this.prefs.getIntPref("extensions.torbutton.socks_port");
50-
this.proxy_type = "socks";
51-
}
52-
}
5335
} catch(e) {
54-
dump("Torbutton not found\n");
5536
this.torbutton_installed = false;
5637
}
5738

58-
if (this.prefs.getBoolPref("extensions.https_everywhere._observatory_prefs.use_custom_proxy")) {
59-
this.proxy_host = this.prefs.getCharPref("extensions.https_everywhere._observatory_prefs.proxy_host");
60-
this.proxy_port = this.prefs.getIntPref("extensions.https_everywhere._observatory_prefs.proxy_port");
61-
this.proxy_type = this.prefs.getCharPref("extensions.https_everywhere._observatory_prefs.proxy_type");
62-
}
39+
// XXX: Clear this on cookies-cleared observer event?
40+
this.already_submitted = {};
41+
42+
// XXX: Read these two from a file? Or hardcode them?
43+
this.public_roots = {};
44+
this.popular_fps = {};
6345

6446
// The url to submit to
6547
this.submit_url = "https://observatory.eff.org/submit_cert";
@@ -79,6 +61,7 @@ function SSLObservatory() {
7961

8062
this.pps.registerFilter(this, 0);
8163
this.wrappedJSObject = this;
64+
this.log(DBUG, "Loaded observatory component!");
8265
}
8366

8467
SSLObservatory.prototype = {
@@ -132,21 +115,31 @@ SSLObservatory.prototype = {
132115
&& !this.prefs.getBoolPref("extensions.torbutton.tor_enabled")) {
133116
return;
134117
}
118+
} else if (!this.prefs.getBoolPref("extensions.https_everywhere._observatory_prefs.use_custom_proxy")) {
119+
this.log(WARN, "No torbutton installed, but no custom proxies either. Not submitting certs");
120+
return;
135121
}
136122

137123
if ("http-on-examine-response" == topic) {
138124
subject.QueryInterface(Ci.nsIHttpChannel);
139125
var certchain = this.getSSLCert(subject);
140-
if(certchain) {
126+
if (certchain) {
141127
var chainEnum = certchain.getChain();
142128
var chainArray = [];
129+
// XXX: We get chains for requests that have never completed if they
130+
// match cached certs!
131+
if (chainEnum.length && subject.status != 0) {
132+
this.log(NOTE, "Got a certificate chain for "
133+
+subject.URI.host+" despite error "+subject.status);
134+
return;
135+
}
143136
for(var i = 0; i < chainEnum.length; i++) {
144137
var cert = chainEnum.queryElementAt(i, Ci.nsIX509Cert);
145138
chainArray.push(cert);
146139
}
147140

148141
if (subject.URI.port == -1) {
149-
this.submitChain(chainArray, subject.URI.host);
142+
this.submitChain(chainArray, new String(subject.URI.host));
150143
} else {
151144
this.submitChain(chainArray, subject.URI.host+":"+subject.URI.port);
152145
}
@@ -161,14 +154,36 @@ SSLObservatory.prototype = {
161154
for (var i = 0; i < certArray.length; i++) {
162155
var fp = (certArray[i].md5Fingerprint+certArray[i].sha1Fingerprint).replace(":", "", "g");
163156
fps.push(fp);
157+
}
158+
159+
// XXX: is 0 the root? or is the last one the root?
160+
/*
161+
if (!(fps[0] in this.public_roots)) {
162+
this.log(INFO, "Got a private root cert. Ignoring");
163+
return;
164+
}
165+
*/
166+
167+
if (fps[fps.length-1] in this.already_submitted) {
168+
this.log(INFO, "Already submitted cert for "+domain+". Ignoring");
169+
return;
170+
}
164171

172+
if (fps[fps.length-1] in this.popular_fps) {
173+
this.log(INFO, "Excluding popuar cert for "+domain);
174+
return;
175+
}
176+
177+
for (var i = 0; i < certArray.length; i++) {
165178
var len = new Object();
166179
var derData = certArray[i].getRawDER(len);
167180
base64Certs.push(this.base64_encode(derData, false, false));
168181
}
169182

170-
// XXX: AS number??
171-
// XXX: Server ip??
183+
// TODO: Refetch AS number every time one of these two changes:
184+
// https://developer.mozilla.org/en/online_and_offline_events
185+
// https://developer.mozilla.org/En/Monitoring_WiFi_access_points
186+
// TODO: Server ip??
172187
var reqParams = [];
173188
reqParams.push("domain="+domain);
174189
reqParams.push("server_ip=-1");
@@ -180,16 +195,18 @@ SSLObservatory.prototype = {
180195
var params = reqParams.join("&") + "&padding=0";
181196
var tot_len = 1024;
182197

183-
this.log(DBUG, "Params: "+params);
198+
this.log(INFO, "Submitting cert for "+domain);
199+
this.log(DBUG, "submit_cert params: "+params);
184200

185-
// Pad to exp scale
201+
// Pad to exp scale. This is done because the distribution of cert sizes
202+
// is almost certainly pareto, and definitely not uniform.
186203
for (tot_len = 1024; tot_len < params.length; tot_len*=2);
187204

188205
while (params.length != tot_len) {
189206
params += "0";
190207
}
191208

192-
this.log(DBUG, "Padded params: "+params);
209+
//this.log(DBUG, "Padded params: "+params);
193210

194211
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
195212
.createInstance(Ci.nsIXMLHttpRequest);
@@ -201,35 +218,76 @@ SSLObservatory.prototype = {
201218
req.setRequestHeader("Content-length", params.length);
202219
req.setRequestHeader("Connection", "close");
203220

221+
var that = this; // We have neither SSLObservatory nor this in scope in the lambda
204222
req.onreadystatechange = function(evt) {
205223
if (req.readyState == 4) {
206224
// XXX: Handle errors properly?
207-
// XXX: We have neither SSLObservatory nor this in scope.
208225
if (req.status == 200) {
209226
dump("Got ReadyStateChange == 4\n");
210-
//SSLObservatory.log(INFO, "Successful cert submission");
227+
that.log(INFO, "Successful cert submission");
228+
if (!that.prefs.getBoolPref("extensions.https_everywhere._observatory_prefs.cache_submitted")) {
229+
if (fps[fps.length-1] in that.already_submitted)
230+
delete that.already_submitted[fps[fps.length-1]];
231+
}
211232
} else {
212233
dump("Fail ReadyStateChange == 4\n");
213-
//SSLObservatory.log(WARN, "Cert submission failure");
234+
that.log(WARN, "Cert submission failure: "+req.status);
235+
if (fps[fps.length-1] in that.already_submitted)
236+
delete that.already_submitted[fps[fps.length-1]];
214237
}
215238
}
216239
};
217240

241+
// Cache this here to prevent multiple submissions for all the content elements.
242+
that.already_submitted[fps[fps.length-1]] = true;
218243
req.send(params);
219244
},
220245

246+
getProxySettings: function() {
247+
var proxy_settings = ["direct", "", 0];
248+
if (this.torbutton_installed &&
249+
this.prefs.getBoolPref("extensions.https_everywhere._observatory_prefs.use_tor_proxy")) {
250+
// extract torbutton proxy settings
251+
proxy_settings[0] = "http";
252+
proxy_settings[1] = this.prefs.getCharPref("extensions.torbutton.https_proxy");
253+
proxy_settings[2] = this.prefs.getIntPref("extensions.torbutton.https_port");
254+
255+
if (proxy_settings[2] == 0) {
256+
proxy_settings[0] = "socks";
257+
proxy_settings[1] = this.prefs.getCharPref("extensions.torbutton.socks_host");
258+
proxy_settings[2] = this.prefs.getIntPref("extensions.torbutton.socks_port");
259+
}
260+
} else if (this.prefs.getBoolPref("extensions.https_everywhere._observatory_prefs.use_custom_proxy")) {
261+
proxy_settings[0] = this.prefs.getCharPref("extensions.https_everywhere._observatory_prefs.proxy_type");
262+
proxy_settings[1] = this.prefs.getCharPref("extensions.https_everywhere._observatory_prefs.proxy_host");
263+
proxy_settings[2] = this.prefs.getIntPref("extensions.https_everywhere._observatory_prefs.proxy_port");
264+
} else {
265+
this.log(WARN, "Proxy settings are strange: No Torbutton found, but no proxy specified. Using direct.");
266+
}
267+
return proxy_settings;
268+
},
269+
221270
applyFilter: function(aProxyService, aURI, aProxy) {
222271
if (aURI.spec.search("^"+this.submit_url) != -1 &&
223272
aURI.path.search(this.csrf_nonce+"$") != -1) {
224273

225274
this.log(INFO, "Got observatory url + nonce: "+aURI.spec);
275+
var proxy_settings = null;
276+
var proxy = null;
226277

227278
// Send it through tor by creating an nsIProxy instance
228279
// for the torbutton proxy settings.
229-
var proxy = this.pps.newProxyInfo(this.proxy_type, this.proxy_host,
230-
this.proxy_port,
280+
try {
281+
proxy_settings = this.getProxySettings();
282+
proxy = this.pps.newProxyInfo(proxy_settings[0], proxy_settings[1],
283+
proxy_settings[2],
231284
Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST,
232285
0xFFFFFFFF, null);
286+
} catch(e) {
287+
this.log(WARN, "Error specifying proxy for observatory: "+e);
288+
}
289+
290+
this.log(INFO, "Specifying proxy: "+proxy);
233291

234292
// TODO: Use new identity or socks u/p to ensure we get a unique
235293
// tor circuit for this request

src/defaults/preferences/preferences.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// SSl Observatory preferences
22
pref("extensions.https_everywhere._observatory_prefs.enabled",true);
33

4+
pref("extensions.https_everywhere._observatory_prefs.use_tor_proxy",true);
45
pref("extensions.https_everywhere._observatory_prefs.submit_during_tor",false);
56
pref("extensions.https_everywhere._observatory_prefs.submit_during_nontor",true);
67

8+
pref("extensions.https_everywhere._observatory_prefs.cache_submitted",true);
9+
710
pref("extensions.https_everywhere._observatory_prefs.use_custom_proxy",false);
811
pref("extensions.https_everywhere._observatory_prefs.proxy_host","");
912
pref("extensions.https_everywhere._observatory_prefs.proxy_port",0);

0 commit comments

Comments
 (0)