Bug 1328718 - Implement system add-on to facilitate rollout of disabling SHA-1. r=Felipe, r=jcj, data-review=bsmedberg, a=jcristau
authorDavid Keeler <dkeeler@mozilla.com>
Wed, 25 Jan 2017 16:12:42 -0800
changeset 366802 6b6f15c4beceef5b055756bc18317262779f816f
parent 366801 f271c045f7abe68f3c4e650f3901be6f32892b48
child 366803 603587ec2ecdd948558249e7543e8424c7fa4e57
push id6853
push userryanvm@gmail.com
push dateTue, 31 Jan 2017 20:51:17 +0000
treeherdermozilla-beta@c2d975acbc83 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersFelipe, jcj, jcristau
bugs1328718
milestone52.0
Bug 1328718 - Implement system add-on to facilitate rollout of disabling SHA-1. r=Felipe, r=jcj, data-review=bsmedberg, a=jcristau
browser/extensions/disableSHA1rollout/README.md
browser/extensions/disableSHA1rollout/bootstrap.js
browser/extensions/disableSHA1rollout/install.rdf.in
browser/extensions/disableSHA1rollout/moz.build
browser/extensions/moz.build
testing/talos/talos/xtalos/xperf_whitelist.json
new file mode 100644
--- /dev/null
+++ b/browser/extensions/disableSHA1rollout/README.md
@@ -0,0 +1,99 @@
+This system add-on is a follow-up to the MITM prevalence experiment. The purpose
+is to facilitate rolling out the disabling of SHA-1 in signatures on
+certificates issued by publicly-trusted roots. When installed, this add-on will
+perform a number of checks to determine if it should change the preference that
+controls the SHA-1 policy. First, this should only apply to users on the beta
+update channel. It should also only apply to users who have not otherwise
+changed the policy to always allow or always forbid SHA-1. Additionally, it
+must double-check that the user is not affected by a TLS intercepting proxy
+using a publicly-trusted root. If these checks pass, the add-on will divide the
+population into a test group and a control group (starting on a 10%/90% split).
+The test group will have the policy changed. After doing this, a telemetry
+payload is reported with the following values:
+
+* cohortName -- the name of the group this user is in:
+  1. "notSafeToDisableSHA1" if the user is behind a MITM proxy using a
+     publicly-trusted root
+  2. "optedOut" if the user already set the SHA-1 policy to always allow or
+     always forbid
+  3. "optedIn" if the user already set the SHA-1 policy to only allow for
+     non-built-in roots
+  4. "test" if the user is in the test cohort (and SHA-1 will be disabled)
+  5. "control" if the user is not in the test cohort
+* errorCode -- 0 for successful connections, some PR error code otherwise
+* error -- a short description of one of four error conditions encountered, if
+  applicable, and an empty string otherwise:
+  1. "timeout" if the connection to telemetry.mozilla.org timed out
+  2. "user override" if the user has stored a permanent certificate exception
+     override for telemetry.mozilla.org (due to technical limitations, we can't
+     gather much information in this situation)
+  3. "certificate reverification" if re-building the certificate chain after
+     connecting failed for some reason (unfortunately this step is necessary
+     due to technical limitations)
+  4. "connection error" if the connection to telemetry.mozilla.org failed for
+     another reason
+* chain -- a list of dictionaries each corresponding to a certificate in the
+  verified certificate chain, if it was successfully constructed. The first
+  entry is the end-entity certificate. The last entry is the root certificate.
+  This will be empty if the connection failed or if reverification failed. Each
+  element in the list contains the following values:
+  * sha256Fingerprint -- a hex string representing the SHA-256 hash of the
+    certificate
+  * isBuiltInRoot -- true if the certificate is a trust anchor in the web PKI,
+    false otherwise
+  * signatureAlgorithm -- a description of the algorithm used to sign the
+    certificate. Will be one of "md2WithRSAEncryption", "md5WithRSAEncryption",
+    "sha1WithRSAEncryption", "sha256WithRSAEncryption",
+    "sha384WithRSAEncryption", "sha512WithRSAEncryption", "ecdsaWithSHA1",
+    "ecdsaWithSHA224", "ecdsaWithSHA256", "ecdsaWithSHA384", "ecdsaWithSHA512",
+    or "unknown".
+* disabledSHA1 -- true if SHA-1 was disabled, false otherwise
+* didNotDisableSHA1Because -- a short string describing why SHA-1 could not be
+    disabled, if applicable. Reasons are limited to:
+    1. "MITM" if the user is behind a TLS intercepting proxy using a
+       publicly-trusted root
+    2. "connection error" if there was an error connecting to
+       telemetry.mozilla.org
+    3. "code error" if some inconsistent state was detected, and it was
+       determined that the experiment should not attempt to change the
+       preference
+    4. "preference:userReset" if the user reset the SHA-1 policy after it had
+       been changed by this add-on
+    5. "preference:allow" if the user had already configured Firefox to always
+       accept SHA-1 signatures
+    6. "preference:forbid" if the user had already configured Firefox to always
+       forbid SHA-1 signatures
+
+For a connection not intercepted by a TLS proxy and where the user is in the
+test cohort, the expected result will be:
+
+    { "cohortName": "test",
+      "errorCode": 0,
+      "error": "",
+      "chain": [
+        { "sha256Fingerprint": "197feaf3faa0f0ad637a89c97cb91336bfc114b6b3018203cbd9c3d10c7fa86c",
+          "isBuiltInRoot": false,
+          "signatureAlgorithm": "sha256WithRSAEncryption"
+        },
+        { "sha256Fingerprint": "154c433c491929c5ef686e838e323664a00e6a0d822ccc958fb4dab03e49a08f",
+          "isBuiltInRoot": false,
+          "signatureAlgorithm": "sha256WithRSAEncryption"
+        },
+        { "sha256Fingerprint": "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161",
+          "isBuiltInRoot": true,
+          "signatureAlgorithm": "sha1WithRSAEncryption"
+        }
+      ],
+      "disabledSHA1": true,
+      "didNotDisableSHA1Because": ""
+    }
+
+When this result is encountered, the user's preferences are updated to disable
+SHA-1 in signatures on certificates issued by publicly-trusted roots.
+Similarly, if the user is behind a TLS intercepting proxy but the root
+certificate is not part of the public web PKI, we can also disable SHA-1 in
+signatures on certificates issued by publicly-trusted roots.
+
+If the user has already indicated in their preferences that they will always
+accept SHA-1 in signatures or that they will never accept SHA-1 in signatures,
+then the preference is not changed.
new file mode 100644
--- /dev/null
+++ b/browser/extensions/disableSHA1rollout/bootstrap.js
@@ -0,0 +1,317 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/UpdateUtils.jsm");
+Cu.import("resource://gre/modules/TelemetryController.jsm");
+
+ // Percentage of the population to attempt to disable SHA-1 for, by channel.
+const TEST_THRESHOLD = {
+  beta: 0.1, // 10%
+};
+
+const PREF_COHORT_SAMPLE = "disableSHA1.rollout.cohortSample";
+const PREF_COHORT_NAME = "disableSHA1.rollout.cohort";
+const PREF_SHA1_POLICY = "security.pki.sha1_enforcement_level";
+const PREF_SHA1_POLICY_SET_BY_ADDON = "disableSHA1.rollout.policySetByAddOn";
+const PREF_SHA1_POLICY_RESET_BY_USER = "disableSHA1.rollout.userResetPref";
+
+const SHA1_MODE_ALLOW = 0;
+const SHA1_MODE_FORBID = 1;
+const SHA1_MODE_IMPORTED_ROOTS_ONLY = 3;
+const SHA1_MODE_CURRENT_DEFAULT = 4;
+
+function startup() {
+  Preferences.observe(PREF_SHA1_POLICY, policyPreferenceChanged);
+}
+
+function install() {
+  let updateChannel = UpdateUtils.getUpdateChannel(false);
+  // Only run if we have a good indication that we're not in a testing
+  // environment (in which case attempting to connect to telemetry.mozilla.org
+  // will result in a test failure).
+  let telemetryServerURL = Preferences.get("toolkit.telemetry.server",
+                                           undefined);
+  // Also only run if the user has unified telemetry enabled (because we don't
+  // want to submit a telemetry ping if they've opted out).
+  let unifiedTelemetryEnabled = Preferences.get("toolkit.telemetry.unified",
+                                                undefined);
+  if (updateChannel in TEST_THRESHOLD &&
+      telemetryServerURL == "https://incoming.telemetry.mozilla.org" &&
+      unifiedTelemetryEnabled === true) {
+    makeRequest().then(defineCohort).catch((e) => console.error(e));
+  }
+}
+
+function policyPreferenceChanged() {
+  let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
+                                         SHA1_MODE_CURRENT_DEFAULT);
+  Preferences.reset(PREF_SHA1_POLICY_RESET_BY_USER);
+  if (currentPrefValue == SHA1_MODE_CURRENT_DEFAULT) {
+    Preferences.set(PREF_SHA1_POLICY_RESET_BY_USER, true);
+  }
+}
+
+function defineCohort(result) {
+  let userOptedOut = optedOut();
+  let userOptedIn = optedIn();
+  let shouldNotDisableSHA1Because = reasonToNotDisableSHA1(result);
+  let safeToDisableSHA1 = shouldNotDisableSHA1Because.length == 0;
+  let updateChannel = UpdateUtils.getUpdateChannel(false);
+  let testGroup = getUserSample() < TEST_THRESHOLD[updateChannel];
+
+  let cohortName;
+  if (!safeToDisableSHA1) {
+    cohortName = "notSafeToDisableSHA1";
+  } else if (userOptedOut) {
+    cohortName = "optedOut";
+  } else if (userOptedIn) {
+    cohortName = "optedIn";
+  } else if (testGroup) {
+    cohortName = "test";
+    Preferences.ignore(PREF_SHA1_POLICY, policyPreferenceChanged);
+    Preferences.set(PREF_SHA1_POLICY, SHA1_MODE_IMPORTED_ROOTS_ONLY);
+    Preferences.observe(PREF_SHA1_POLICY, policyPreferenceChanged);
+    Preferences.set(PREF_SHA1_POLICY_SET_BY_ADDON, true);
+  } else {
+    cohortName = "control";
+  }
+  Preferences.set(PREF_COHORT_NAME, cohortName);
+  reportTelemetry(result, cohortName, shouldNotDisableSHA1Because,
+                  cohortName == "test");
+}
+
+function shutdown(data, reason) {
+  Preferences.ignore(PREF_SHA1_POLICY, policyPreferenceChanged);
+}
+
+function uninstall() {
+}
+
+function getUserSample() {
+  let prefValue = Preferences.get(PREF_COHORT_SAMPLE, undefined);
+  let value = 0.0;
+
+  if (typeof(prefValue) == "string") {
+    value = parseFloat(prefValue, 10);
+    return value;
+  }
+
+  value = Math.random();
+
+  Preferences.set(PREF_COHORT_SAMPLE, value.toString().substr(0, 8));
+  return value;
+}
+
+function reportTelemetry(result, cohortName, didNotDisableSHA1Because,
+                         disabledSHA1) {
+  result.cohortName = cohortName;
+  result.disabledSHA1 = disabledSHA1;
+  if (cohortName == "optedOut") {
+    let userResetPref = Preferences.get(PREF_SHA1_POLICY_RESET_BY_USER, false);
+    let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
+                                           SHA1_MODE_CURRENT_DEFAULT);
+    if (userResetPref) {
+      didNotDisableSHA1Because = "preference:userReset";
+    } else if (currentPrefValue == SHA1_MODE_ALLOW) {
+      didNotDisableSHA1Because = "preference:allow";
+    } else {
+      didNotDisableSHA1Because = "preference:forbid";
+    }
+  }
+  result.didNotDisableSHA1Because = didNotDisableSHA1Because;
+  return TelemetryController.submitExternalPing("disableSHA1rollout", result,
+                                                {});
+}
+
+function optedIn() {
+  let policySetByAddOn = Preferences.get(PREF_SHA1_POLICY_SET_BY_ADDON, false);
+  let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
+                                         SHA1_MODE_CURRENT_DEFAULT);
+  return currentPrefValue == SHA1_MODE_IMPORTED_ROOTS_ONLY && !policySetByAddOn;
+}
+
+function optedOut() {
+  // Users can also opt-out by setting the policy to always allow or always
+  // forbid SHA-1, or by resetting the preference after this add-on has changed
+  // it (in that case, this will be reported the next time this add-on is
+  // updated).
+  let currentPrefValue = Preferences.get(PREF_SHA1_POLICY,
+                                         SHA1_MODE_CURRENT_DEFAULT);
+  let userResetPref = Preferences.get(PREF_SHA1_POLICY_RESET_BY_USER, false);
+  return currentPrefValue == SHA1_MODE_ALLOW ||
+         currentPrefValue == SHA1_MODE_FORBID ||
+         userResetPref;
+}
+
+function delocalizeAlgorithm(localizedString) {
+  let bundle = Services.strings.createBundle(
+    "chrome://pipnss/locale/pipnss.properties");
+  let algorithmStringIdsToOIDDescriptionMap = {
+    "CertDumpMD2WithRSA":                       "md2WithRSAEncryption",
+    "CertDumpMD5WithRSA":                       "md5WithRSAEncryption",
+    "CertDumpSHA1WithRSA":                      "sha1WithRSAEncryption",
+    "CertDumpSHA256WithRSA":                    "sha256WithRSAEncryption",
+    "CertDumpSHA384WithRSA":                    "sha384WithRSAEncryption",
+    "CertDumpSHA512WithRSA":                    "sha512WithRSAEncryption",
+    "CertDumpAnsiX962ECDsaSignatureWithSha1":   "ecdsaWithSHA1",
+    "CertDumpAnsiX962ECDsaSignatureWithSha224": "ecdsaWithSHA224",
+    "CertDumpAnsiX962ECDsaSignatureWithSha256": "ecdsaWithSHA256",
+    "CertDumpAnsiX962ECDsaSignatureWithSha384": "ecdsaWithSHA384",
+    "CertDumpAnsiX962ECDsaSignatureWithSha512": "ecdsaWithSHA512",
+  };
+
+  let description;
+  Object.keys(algorithmStringIdsToOIDDescriptionMap).forEach((l10nID) => {
+    let candidateLocalizedString = bundle.GetStringFromName(l10nID);
+    if (localizedString == candidateLocalizedString) {
+      description = algorithmStringIdsToOIDDescriptionMap[l10nID];
+    }
+  });
+  if (!description) {
+    return "unknown";
+  }
+  return description;
+}
+
+function getSignatureAlgorithm(cert) {
+  // Certificate  ::=  SEQUENCE  {
+  //      tbsCertificate       TBSCertificate,
+  //      signatureAlgorithm   AlgorithmIdentifier,
+  //      signatureValue       BIT STRING  }
+  let certificate = cert.ASN1Structure.QueryInterface(Ci.nsIASN1Sequence);
+  let signatureAlgorithm = certificate.ASN1Objects
+                                      .queryElementAt(1, Ci.nsIASN1Sequence);
+  // AlgorithmIdentifier  ::=  SEQUENCE  {
+  //      algorithm               OBJECT IDENTIFIER,
+  //      parameters              ANY DEFINED BY algorithm OPTIONAL  }
+
+  // If parameters is NULL (or empty), signatureAlgorithm won't be a container
+  // under this implementation. Just get its displayValue.
+  if (!signatureAlgorithm.isValidContainer) {
+    return signatureAlgorithm.displayValue;
+  }
+  let oid = signatureAlgorithm.ASN1Objects.queryElementAt(0, Ci.nsIASN1Object);
+  return oid.displayValue;
+}
+
+function processCertChain(chain) {
+  let output = [];
+  let enumerator = chain.getEnumerator();
+  while (enumerator.hasMoreElements()) {
+    let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
+    output.push({
+      sha256Fingerprint: cert.sha256Fingerprint.replace(/:/g, "").toLowerCase(),
+      isBuiltInRoot: cert.isBuiltInRoot,
+      signatureAlgorithm: delocalizeAlgorithm(getSignatureAlgorithm(cert)),
+    });
+  }
+  return output;
+}
+
+class CertificateVerificationResult {
+  constructor(resolve) {
+    this.resolve = resolve;
+  }
+
+  verifyCertFinished(aPRErrorCode, aVerifiedChain, aEVStatus) {
+    let result = { errorCode: aPRErrorCode, error: "", chain: [] };
+    if (aPRErrorCode == 0) {
+      result.chain = processCertChain(aVerifiedChain);
+    } else {
+      result.error = "certificate reverification";
+    }
+    this.resolve(result);
+  }
+}
+
+function makeRequest() {
+  return new Promise((resolve) => {
+    let hostname = "telemetry.mozilla.org";
+    let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+    req.open("GET", "https://" + hostname);
+    req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
+    req.timeout = 30000;
+    req.addEventListener("error", (evt) => {
+      // If we can't connect to telemetry.mozilla.org, then how did we even
+      // download the experiment? In any case, we may still be able to get some
+      // information.
+      let result = { error: "connection error" };
+      if (evt.target.channel && evt.target.channel.securityInfo) {
+        let securityInfo = evt.target.channel.securityInfo
+                             .QueryInterface(Ci.nsITransportSecurityInfo);
+        if (securityInfo) {
+          result.errorCode = securityInfo.errorCode;
+        }
+        if (securityInfo && securityInfo.failedCertChain) {
+          result.chain = processCertChain(securityInfo.failedCertChain);
+        }
+      }
+      resolve(result);
+    });
+    req.addEventListener("timeout", (evt) => {
+      resolve({ error: "timeout" });
+    });
+    req.addEventListener("load", (evt) => {
+      let securityInfo = evt.target.channel.securityInfo
+                           .QueryInterface(Ci.nsITransportSecurityInfo);
+      if (securityInfo.securityState &
+          Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN) {
+        resolve({ error: "user override" });
+        return;
+      }
+      let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
+                        .SSLStatus;
+      let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+                     .getService(Ci.nsIX509CertDB);
+      let result = new CertificateVerificationResult(resolve);
+      // Unfortunately, we don't have direct access to the verified certificate
+      // chain as built by the AuthCertificate hook, so we have to re-build it
+      // here. In theory we are likely to get the same result.
+      certdb.asyncVerifyCertAtTime(sslStatus.serverCert,
+                                   2, // certificateUsageSSLServer
+                                   0, // flags
+                                   hostname,
+                                   Date.now() / 1000,
+                                   result);
+    });
+    req.send();
+  });
+}
+
+// As best we know, it is safe to disable SHA1 if the connection was successful
+// and either the connection was MITM'd by a root not in the public PKI or the
+// chain is part of the public PKI and is the one served by the real
+// telemetry.mozilla.org.
+// This will return a short string description of why it might not be safe to
+// disable SHA1 or an empty string if it is safe to disable SHA1.
+function reasonToNotDisableSHA1(result) {
+  if (!("errorCode" in result) || result.errorCode != 0) {
+    return "connection error";
+  }
+  if (!("chain" in result)) {
+    return "code error";
+  }
+  if (!result.chain[result.chain.length - 1].isBuiltInRoot) {
+    return "";
+  }
+  if (result.chain.length != 3) {
+    return "MITM";
+  }
+  const kEndEntityFingerprint = "197feaf3faa0f0ad637a89c97cb91336bfc114b6b3018203cbd9c3d10c7fa86c";
+  const kIntermediateFingerprint = "154c433c491929c5ef686e838e323664a00e6a0d822ccc958fb4dab03e49a08f";
+  const kRootFingerprint = "4348a0e9444c78cb265e058d5e8944b4d84f9662bd26db257f8934a443c70161";
+  if (result.chain[0].sha256Fingerprint != kEndEntityFingerprint ||
+      result.chain[1].sha256Fingerprint != kIntermediateFingerprint ||
+      result.chain[2].sha256Fingerprint != kRootFingerprint) {
+    return "MITM";
+  }
+  return "";
+}
copy from browser/extensions/e10srollout/install.rdf.in
copy to browser/extensions/disableSHA1rollout/install.rdf.in
--- a/browser/extensions/e10srollout/install.rdf.in
+++ b/browser/extensions/disableSHA1rollout/install.rdf.in
@@ -4,29 +4,29 @@
    - 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>e10srollout@mozilla.org</em:id>
-    <em:version>1.7</em:version>
+    <em:id>disableSHA1rollout@mozilla.org</em:id>
+    <em:version>1.0</em:version>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
 
     <!-- Target Application this theme can install into,
         with minimum and maximum supported versions. -->
     <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>Multi-process staged rollout</em:name>
-    <em:description>Staged rollout of Firefox multi-process feature.</em:description>
+    <em:name>SHA-1 deprecation staged rollout</em:name>
+    <em:description>Staged rollout deprecating SHA-1 in certificate signatures.</em:description>
   </Description>
 </RDF>
copy from browser/extensions/e10srollout/moz.build
copy to browser/extensions/disableSHA1rollout/moz.build
--- a/browser/extensions/e10srollout/moz.build
+++ b/browser/extensions/disableSHA1rollout/moz.build
@@ -2,15 +2,15 @@
 # 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['e10srollout@mozilla.org'] += [
+FINAL_TARGET_FILES.features['disableSHA1rollout@mozilla.org'] += [
   'bootstrap.js'
 ]
 
-FINAL_TARGET_PP_FILES.features['e10srollout@mozilla.org'] += [
+FINAL_TARGET_PP_FILES.features['disableSHA1rollout@mozilla.org'] += [
   'install.rdf.in'
 ]
--- a/browser/extensions/moz.build
+++ b/browser/extensions/moz.build
@@ -1,16 +1,17 @@
 # -*- 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/.
 
 DIRS += [
     'aushelper',
+    'disableSHA1rollout',
     'e10srollout',
     'pdfjs',
     'pocket',
     'webcompat',
 ]
 
 # Only include the following system add-ons if building Aurora or Nightly
 if 'a' in CONFIG['GRE_MILESTONE']:
--- a/testing/talos/talos/xtalos/xperf_whitelist.json
+++ b/testing/talos/talos/xtalos/xperf_whitelist.json
@@ -2,16 +2,17 @@
  "C:\\$Mft": {"ignore": true}, 
  "C:\\$Extend\\$UsnJrnl:$J": {"ignore": true}, 
  "C:\\Windows\\Prefetch\\{prefetch}.pf": {"ignore": true}, 
  "C:\\$Secure": {"ignore": true},
  "C:\\$logfile": {"ignore": true},
  "{firefox}\\omni.ja": {"mincount": 0, "maxcount": 46, "minbytes": 0, "maxbytes": 3014656},
  "{firefox}\\browser\\omni.ja": {"mincount": 0, "maxcount": 28, "minbytes": 0, "maxbytes": 1835008},
  "{firefox}\\browser\\features\\aushelper@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
+ "{firefox}\\browser\\features\\disableSHA1rollout@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\e10srollout@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\flyweb@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\formautofill@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\loop@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\firefox@getpocket.com.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{firefox}\\browser\\features\\webcompat@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000},
  "{talos}\\tests\\tp5n\\tp5n.manifest": {"mincount": 0, "maxcount": 8, "minbytes": 0, "maxbytes": 32786},
  "{talos}\\talos\\tests\\tp5n\\tp5n.manifest": {"mincount": 0, "maxcount": 8, "minbytes": 0, "maxbytes": 32786},