Last active
March 4, 2017 08:24
-
-
Save rhelmer/13193fd0f9d48559521d80129c83e70d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Robert Helmer <[email protected]> | |
# Date 1488615603 28800 | |
# Sat Mar 04 00:20:03 2017 -0800 | |
# Node ID 003b53ae28d334d7cdce242a5d45ef1aed091c1f | |
# Parent ed3f666f580073edf76b538c3dde6badd81c7d40 | |
Bug 1325872 - system add-on for TLS 1.3 Compatibility Testing | |
MozReview-Commit-ID: IASvvAIxOGh | |
diff --git a/browser/extensions/moz.build b/browser/extensions/moz.build | |
--- a/browser/extensions/moz.build | |
+++ b/browser/extensions/moz.build | |
@@ -5,16 +5,17 @@ | |
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
DIRS += [ | |
'aushelper', | |
'e10srollout', | |
'pdfjs', | |
'pocket', | |
'webcompat', | |
+ 'tls13-compat-ff51', | |
] | |
# Only include the following system add-ons if building Aurora or Nightly | |
if 'a' in CONFIG['GRE_MILESTONE']: | |
DIRS += [ | |
'flyweb', | |
'formautofill', | |
] | |
diff --git a/browser/extensions/tls13-compat-ff51/bootstrap.js b/browser/extensions/tls13-compat-ff51/bootstrap.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/bootstrap.js | |
@@ -0,0 +1,219 @@ | |
+/* This Source Code Form is subject to the terms of the Mozilla Public | |
+ * License, v. 2.0. If a copy of the MPL was not distributed with this | |
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
+ | |
+"use strict"; | |
+ | |
+let {classes: Cc, interfaces: Ci, utils: Cu} = Components; | |
+ | |
+const { Preferences } = Cu.import("resource://gre/modules/Preferences.jsm", {}); | |
+const { setTimeout, clearTimeout } = Cu.import("resource://gre/modules/Timer.jsm", {}); | |
+const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); | |
+const { TelemetryController } = Cu.import("resource://gre/modules/TelemetryController.jsm", {}); | |
+ | |
+// The Firefox TLS setting. 3 is TLS 1.2, 4 is TLS 1.3 | |
+const VERSION_MAX_PREF = "security.tls.version.max"; | |
+ | |
+// Whether or not to print messages to the console. | |
+const DEBUG = false; | |
+ | |
+// Timeout after 2 minutes. | |
+const TIMEOUT = 120000; | |
+ | |
+// These should be different hosts so that we don't bias any performance test | |
+// toward 1.2. | |
+/* | |
+const URLs = { | |
+ "https://enabled.tls13.com/" : true, | |
+ "https://disabled.tls13.com/" : true, | |
+ "https://short.tls13.com/" : true, | |
+ "https://control.tls12.com/" : false | |
+}; | |
+*/ | |
+ | |
+const URLs = { | |
+ "https://test1.example.com": true, | |
+ "https://test2.example.com": true, | |
+ //"https://control.example.com": false, | |
+}; | |
+ | |
+let gStarted = false; | |
+let gNewInstall = false; | |
+let gPrefs = new Preferences({ defaultBranch: true }); | |
+let gTimer; | |
+ | |
+function debug(msg) { | |
+ if (DEBUG) { | |
+ console.log(`TLSEXP: ${msg}`); | |
+ } | |
+} | |
+ | |
+// These variables are unreliable for some reason. | |
+function read(obj, field) { | |
+ try { | |
+ return obj[field]; | |
+ } catch (e) { | |
+ Cu.reportError(e); | |
+ } | |
+ return undefined; | |
+} | |
+ | |
+function setTlsPref(prefs, value) { | |
+ debug("Setting pref to " + value); | |
+ prefs.set(VERSION_MAX_PREF, value); | |
+} | |
+ | |
+// This might help us work out if there was a MitM | |
+function recordSecInfo(channel, result) { | |
+ let secInfo = channel.securityInfo; | |
+ if (secInfo instanceof Ci.nsITransportSecurityInfo) { | |
+ secInfo.QueryInterface(Ci.nsITransportSecurityInfo); | |
+ const isSecure = Ci.nsIWebProgressListener.STATE_IS_SECURE; | |
+ result.secure = !!(read(secInfo, 'securityState') & isSecure); | |
+ result.prError = read(secInfo, 'errorCode'); | |
+ } | |
+ if (secInfo instanceof Ci.nsISSLStatusProvider) { | |
+ let sslStatus = secInfo.QueryInterface(Ci.nsISSLStatusProvider) | |
+ .SSLStatus.QueryInterface(Ci.nsISSLStatus); | |
+ let cert = read(sslStatus, 'serverCert'); | |
+ result.certfp = read(cert, 'sha256Fingerprint'); // A hex string | |
+ result.version = read(sslStatus, 'protocolVersion'); | |
+ } | |
+} | |
+ | |
+function makeRequest(prefs, index, url, body) { | |
+ return new Promise(resolve => { | |
+ if (!gStarted) { | |
+ return; | |
+ } | |
+ | |
+ debug("Setting pref"); | |
+ setTlsPref(prefs, URLs[url] ? 4 : 3); | |
+ | |
+ let t0 = Date.now(); | |
+ let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] | |
+ .createInstance(Ci.nsIXMLHttpRequest); | |
+ req.open( | |
+ body ? "POST" : "GET", url, true); | |
+ req.setRequestHeader("Content-Type", "application/json"); | |
+ | |
+ var result = { | |
+ "index" : index, | |
+ "url" : url, | |
+ "start_time" : t0 | |
+ }; | |
+ req.timeout = 10000; // 10s is low intentionally | |
+ req.addEventListener("error", e => { | |
+ debug("Finished with error"); | |
+ let channel = e.target.channel; | |
+ let nsireq = channel.QueryInterface(Ci.nsIRequest); | |
+ result.error= nsireq ? nsireq.status : NS_ERROR_NOT_AVAILABLE; | |
+ recordSecInfo(channel, result); | |
+ result.elapsed = Date.now() - t0; | |
+ debug("Re-setting pref"); | |
+ setTlsPref(prefs, 3); | |
+ resolve(result); | |
+ }); | |
+ req.addEventListener("loadend", e => { | |
+ debug("Finished with load"); | |
+ result.status = e.target.status; | |
+ recordSecInfo(e.target.channel, result); | |
+ result.elapsed = Date.now() - t0; | |
+ debug("Resetting pref"); | |
+ setTlsPref(prefs, 3); | |
+ resolve(result); | |
+ }); | |
+ | |
+ debug("Starting request for " + url + " TLS 1.3=" + URLs[url]); | |
+ if (body) { | |
+ req.send(JSON.stringify(body)); | |
+ } else { | |
+ req.send(); | |
+ } | |
+ }); | |
+} | |
+ | |
+ | |
+function report(result) { | |
+ return TelemetryController.submitExternalPing( | |
+ "tls-13-study-v4", | |
+ { | |
+ time: Date.now(), | |
+ results: result | |
+ }, {}); | |
+} | |
+ | |
+// Inefficient shuffle algorithm, but n <= 10 | |
+function shuffleArray(orig) { | |
+ var inarr = []; | |
+ for (let i in orig) { | |
+ inarr.push(orig[i]); | |
+ } | |
+ var out = []; | |
+ while (inarr.length > 0) { | |
+ let x = Math.floor(Math.random() * inarr.length); | |
+ out.push(inarr.splice(x, 1)[0]) | |
+ } | |
+ return out; | |
+} | |
+ | |
+function startup() { // eslint-disable-line no-unused-vars | |
+ if (!gNewInstall) { | |
+ return; | |
+ } | |
+ | |
+ // deadman timer to ensure we reset pref after 2 minutes | |
+ gTimer = setTimeout(() => { | |
+ try { | |
+ debug("compat test timed out"); | |
+ gStarted = false; | |
+ setTlsPref(gPrefs, 3); | |
+ report([{ "status": "timeout" }]); | |
+ } catch (ex) { | |
+ debug("timer failed:", ex); | |
+ } | |
+ }, TIMEOUT); | |
+} | |
+ | |
+function shutdown() {} // eslint-disable-line no-unused-vars | |
+ | |
+// This is a simple experiment: | |
+// - Install | |
+// - Enable TLS 1.3. | |
+// - Connect to a bunch of servers and record the results | |
+// (see README.md for details on report format) | |
+function install() { // eslint-disable-line no-unused-vars | |
+ // Don't do anything if the user has already messed with this | |
+ // setting. | |
+ let userprefs = new Preferences(); | |
+ if (userprefs.isSet(VERSION_MAX_PREF)) { | |
+ console.log("User has changed TLS max version. Skipping"); | |
+ return; | |
+ } | |
+ | |
+ // Only ever want to run once. | |
+ gNewInstall = true; | |
+ gStarted = true; | |
+ | |
+ report([{ "status": "startup" }]); | |
+ | |
+ let shuffled = shuffleArray(Object.keys(URLs)); | |
+ let results = []; | |
+ | |
+ Task.spawn(function* () { | |
+ for (var i in shuffled) { | |
+ results.push(yield makeRequest(gPrefs, i, shuffled[i], null)); | |
+ } | |
+ | |
+ report(results); | |
+ }) | |
+ .catch(e => Cu.reportError(e)) | |
+ .then(_ => { | |
+ // Make sure we re-set to TLS 1.2. | |
+ setTlsPref(gPrefs, 3); | |
+ | |
+ clearTimeout(gTimer); | |
+ report([{ "status": "finished" }]); | |
+ }); | |
+} | |
+function uninstall() {} // eslint-disable-line no-unused-vars | |
diff --git a/browser/extensions/tls13-compat-ff51/install.rdf.in b/browser/extensions/tls13-compat-ff51/install.rdf.in | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/install.rdf.in | |
@@ -0,0 +1,31 @@ | |
+<?xml version="1.0"?> | |
+<!-- This Source Code Form is subject to the terms of the Mozilla Public | |
+ - License, v. 2.0. If a copy of the MPL was not distributed with this | |
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> | |
+ | |
+#filter substitution | |
+ | |
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> | |
+ <Description about="urn:mozilla:install-manifest"> | |
+ <em:id>[email protected]</em:id> | |
+ <em:version>1.0.4</em:version> | |
+ <em:type>2</em:type> | |
+ <em:bootstrap>true</em:bootstrap> | |
+ <em:unpack>false</em:unpack> | |
+ <em:multiprocessCompatible>true</em:multiprocessCompatible> | |
+ | |
+ <!-- Firefox --> | |
+ <em:targetApplication> | |
+ <Description> | |
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> | |
+ <em:minVersion>@MOZ_APP_VERSION@</em:minVersion> | |
+ <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion> | |
+ </Description> | |
+ </em:targetApplication> | |
+ | |
+ <!-- Front End MetaData --> | |
+ <em:name>TLS 1.3 Compatibility Testing</em:name> | |
+ <em:description>Testing compatibility of TLS 1.3.</em:description> | |
+ <em:aboutURL>https://bugzilla.mozilla.org/show_bug.cgi?id=1325872</em:aboutURL> | |
+ </Description> | |
+</RDF> | |
diff --git a/browser/extensions/tls13-compat-ff51/jar.mn b/browser/extensions/tls13-compat-ff51/jar.mn | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/jar.mn | |
@@ -0,0 +1,3 @@ | |
+[features/[email protected]] chrome.jar: | |
+% content tls13-compat-ff51 %content/ | |
+ content/ (content/*) | |
diff --git a/browser/extensions/tls13-compat-ff51/moz.build b/browser/extensions/tls13-compat-ff51/moz.build | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/moz.build | |
@@ -0,0 +1,22 @@ | |
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- | |
+# vim: set filetype=python: | |
+# This Source Code Form is subject to the terms of the Mozilla Public | |
+# License, v. 2.0. If a copy of the MPL was not distributed with this | |
+# file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
+ | |
+DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] | |
+DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION'] | |
+ | |
+FINAL_TARGET_FILES.features['[email protected]'] += [ | |
+ 'bootstrap.js' | |
+] | |
+ | |
+FINAL_TARGET_PP_FILES.features['[email protected]'] += [ | |
+ 'install.rdf.in' | |
+] | |
+ | |
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] | |
+JAR_MANIFESTS += ['jar.mn'] | |
+ | |
+with Files('**'): | |
+ BUG_COMPONENT = ('Web Compatibility', 'Go Faster') | |
diff --git a/browser/extensions/tls13-compat-ff51/test/.eslintrc.js b/browser/extensions/tls13-compat-ff51/test/.eslintrc.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/test/.eslintrc.js | |
@@ -0,0 +1,7 @@ | |
+"use strict"; | |
+ | |
+module.exports = { | |
+ "extends": [ | |
+ "../../../../testing/mochitest/browser.eslintrc.js" | |
+ ] | |
+}; | |
diff --git a/browser/extensions/tls13-compat-ff51/test/browser.ini b/browser/extensions/tls13-compat-ff51/test/browser.ini | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/test/browser.ini | |
@@ -0,0 +1,4 @@ | |
+[DEFAULT] | |
+ | |
+[browser_check_installed.js] | |
+[browser_test_tls_setting.js] | |
diff --git a/browser/extensions/tls13-compat-ff51/test/browser_check_installed.js b/browser/extensions/tls13-compat-ff51/test/browser_check_installed.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/test/browser_check_installed.js | |
@@ -0,0 +1,19 @@ | |
+/* This Source Code Form is subject to the terms of the Mozilla Public | |
+ * License, v. 2.0. If a copy of the MPL was not distributed with this | |
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
+ | |
+/* global AddonManager */ | |
+ | |
+"use strict"; | |
+ | |
+add_task(function* installed() { | |
+ let addon = yield new Promise( | |
+ (resolve) => AddonManager.getAddonByID("[email protected]", resolve) | |
+ ); | |
+ isnot(addon, null, "addon should exist"); | |
+ is(addon.name, "TLS 1.3 Compatibility Testing"); | |
+ ok(addon.isCompatible, "addon is compatible with Firefox"); | |
+ ok(!addon.appDisabled, "addon is not app disabled"); | |
+ ok(addon.isActive, "addon is active"); | |
+ is(addon.type, "extension", "addon is type extension"); | |
+}); | |
diff --git a/browser/extensions/tls13-compat-ff51/test/browser_test_tls_setting.js b/browser/extensions/tls13-compat-ff51/test/browser_test_tls_setting.js | |
new file mode 100644 | |
--- /dev/null | |
+++ b/browser/extensions/tls13-compat-ff51/test/browser_test_tls_setting.js | |
@@ -0,0 +1,49 @@ | |
+/* This Source Code Form is subject to the terms of the Mozilla Public | |
+ * License, v. 2.0. If a copy of the MPL was not distributed with this | |
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
+ | |
+const { Preferences } = Cu.import("resource://gre/modules/Preferences.jsm", {}); | |
+const { TelemetryArchive } = Cu.import("resource://gre/modules/TelemetryArchive.jsm", {}); | |
+ | |
+ | |
+"use strict"; | |
+ | |
+// The Firefox TLS setting. 3 is TLS 1.2, 4 is TLS 1.3 | |
+const VERSION_MAX_PREF = "security.tls.version.max"; | |
+ | |
+add_task(function* installed() { | |
+ let userprefs = new Preferences(); | |
+ ok(!userprefs.isSet(VERSION_MAX_PREF), "setting should not have been user modified"); | |
+ | |
+ let addon = yield new Promise( | |
+ (resolve) => AddonManager.getAddonByID("[email protected]", resolve) | |
+ ); | |
+ ok(addon.isActive, "addon is active"); | |
+ is(userprefs.get(VERSION_MAX_PREF), 3, "setting should be reset after add-on is active"); | |
+ | |
+ let list = yield TelemetryArchive.promiseArchivedPingList(); | |
+ is(list.length, 3, "correct number of telemetry entries") | |
+ | |
+ let expectedType = "tls-13-study-v4"; | |
+ | |
+ let startPing = yield TelemetryArchive.promiseArchivedPingById(list[0].id); | |
+ is(startPing.type, expectedType, "startup telemetry ping type is correct") | |
+ is(startPing.payload.results[0].status, "startup", "first telemetry ping is startup"); | |
+ | |
+ let dataPing = yield TelemetryArchive.promiseArchivedPingById(list[1].id); | |
+ is(dataPing.type, expectedType, "data telemetry ping type is correct"); | |
+ is(dataPing.payload.results.length, 2, "data telemetry ping correct number of results"); | |
+ | |
+ // the add-on shuffles the order it loads URLs. | |
+ for (let result of dataPing.payload.results) { | |
+ let expectedUrl = (result.url == "https://test1.example.com" || | |
+ result.url == "https://test2.example.com"); | |
+ ok(expectedUrl, "data ping URL is expected"); | |
+ is(result.status, "200", "data ping result status is 200"); | |
+ ok(result.secure, "data ping result secure is true"); | |
+ } | |
+ | |
+ let finishedPing = yield TelemetryArchive.promiseArchivedPingById(list[2].id); | |
+ is(finishedPing.type, expectedType, "finished telemetry ping type is correct") | |
+ is(finishedPing.payload.results[0].status, "finished", "first telemetry ping is startup"); | |
+}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment