Bug 435743: Allow installs and updates from non-built in certificates. r=robstrong, a=gavin
authorDave Townsend <dtownsend@oxymoronical.com>
Tue, 07 Sep 2010 13:49:02 -0700
changeset 52111 297b77bb886895d909eb10cc0154e751c61c4bbe
parent 52110 975d22824233867331ad0929115aeb277d0063cd
child 52112 552065e24bc8d68c4f13224d958caea72ebcc20c
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobstrong, gavin
bugs435743
milestone2.0b6pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 435743: Allow installs and updates from non-built in certificates. r=robstrong, a=gavin
toolkit/mozapps/extensions/AddonUpdateChecker.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/test/browser/browser_installssl.js
toolkit/mozapps/extensions/test/browser/browser_updatessl.js
--- a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm
@@ -51,16 +51,18 @@ const TIMEOUT               = 2 * 60 * 1
 const PREFIX_NS_RDF         = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
 const PREFIX_NS_EM          = "http://www.mozilla.org/2004/em-rdf#";
 const PREFIX_ITEM           = "urn:mozilla:item:";
 const PREFIX_EXTENSION      = "urn:mozilla:extension:";
 const PREFIX_THEME          = "urn:mozilla:theme:";
 const TOOLKIT_ID            = "toolkit@mozilla.org"
 const XMLURI_PARSE_ERROR    = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
 
+const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
+
 Components.utils.import("resource://gre/modules/Services.jsm");
 // shared code for suppressing bad cert dialogs
 Components.utils.import("resource://gre/modules/CertUtils.jsm");
 
 var gRDF = Cc["@mozilla.org/rdf/rdf-service;1"].
            getService(Ci.nsIRDFService);
 
 ["LOG", "WARN", "ERROR"].forEach(function(aName) {
@@ -418,21 +420,28 @@ function UpdateParser(aId, aType, aUpdat
   this.type = aType;
   this.updateKey = aUpdateKey;
   this.observer = aObserver;
 
   this.timer = Cc["@mozilla.org/timer;1"].
                createInstance(Ci.nsITimer);
   this.timer.initWithCallback(this, TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
 
+  let requireBuiltIn = true;
+  try {
+    requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+  }
+  catch (e) {
+  }
+
   LOG("Requesting " + aUrl);
   this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
                  createInstance(Ci.nsIXMLHttpRequest);
   this.request.open("GET", aUrl, true);
-  this.request.channel.notificationCallbacks = new BadCertHandler();
+  this.request.channel.notificationCallbacks = new BadCertHandler(!requireBuiltIn);
   this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
   this.request.overrideMimeType("text/xml");
   var self = this;
   this.request.onload = function(event) { self.onLoad() };
   this.request.onerror = function(event) { self.onError() };
   this.request.send(null);
 }
 
@@ -448,18 +457,25 @@ UpdateParser.prototype = {
    * Called when the manifest has been successfully loaded.
    */
   onLoad: function UP_onLoad() {
     this.timer.cancel();
     this.timer = null;
     let request = this.request;
     this.request = null;
 
+    let requireBuiltIn = true;
     try {
-      checkCert(request.channel);
+      requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+    }
+    catch (e) {
+    }
+
+    try {
+      checkCert(request.channel, !requireBuiltIn);
     }
     catch (e) {
       this.notifyError(AddonUpdateChecker.ERROR_DOWNLOAD_ERROR);
       return;
     }
 
     if (!Components.isSuccessCode(request.status)) {
       WARN("Request failed: " + request.status);
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -66,16 +66,17 @@ const PREF_EM_ENABLED_ADDONS          = 
 const PREF_EM_EXTENSION_FORMAT        = "extensions.";
 const PREF_EM_ENABLED_SCOPES          = "extensions.enabledScopes";
 const PREF_EM_SHOW_MISMATCH_UI        = "extensions.showMismatchUI";
 const PREF_EM_DISABLED_ADDONS_LIST    = "extensions.disabledAddons";
 const PREF_XPI_ENABLED                = "xpinstall.enabled";
 const PREF_XPI_WHITELIST_REQUIRED     = "xpinstall.whitelist.required";
 const PREF_XPI_WHITELIST_PERMISSIONS  = "xpinstall.whitelist.add";
 const PREF_XPI_BLACKLIST_PERMISSIONS  = "xpinstall.blacklist.add";
+const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
 
 const URI_EXTENSION_UPDATE_DIALOG     = "chrome://mozapps/content/extensions/update.xul";
 
 const DIR_EXTENSIONS                  = "extensions";
 const DIR_STAGE                       = "staged";
 
 const FILE_OLD_DATABASE               = "extensions.rdf";
 const FILE_DATABASE                   = "extensions.sqlite";
@@ -4023,17 +4024,18 @@ function XPINotificationCallbacks(aWindo
   this.window = aWindow;
 
   // Verify that we don't end up on an insecure channel if we haven't got a
   // hash to verify with (see bug 537761 for discussion)
   this.needBadCertHandling = aNeedBadCertHandling;
 
   if (this.needBadCertHandling) {
     Components.utils.import("resource://gre/modules/CertUtils.jsm");
-    this.badCertHandler = new BadCertHandler();
+    let requireBuiltIn = Prefs.getBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, true);
+    this.badCertHandler = new BadCertHandler(!requireBuiltIn);
   }
 }
 
 XPINotificationCallbacks.prototype = {
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIInterfaceRequestor))
       return this;
     throw Components.results.NS_ERROR_NO_INTERFACE;
@@ -4657,17 +4659,18 @@ AddonInstall.prototype = {
       return;
 
     LOG("Download of " + this.sourceURI.spec + " completed.");
 
     if (Components.isSuccessCode(aStatus)) {
       if (!(aRequest instanceof Ci.nsIHttpChannel) || aRequest.requestSucceeded) {
         if (!this.hash && (aRequest instanceof Ci.nsIChannel)) {
           try {
-            checkCert(aRequest);
+            checkCert(aRequest,
+                      !Prefs.getBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, true));
           }
           catch (e) {
             this.downloadFailed(AddonManager.ERROR_NETWORK_FAILURE, e);
             return;
           }
         }
 
         // return the two-digit hexadecimal code for a byte
--- a/toolkit/mozapps/extensions/test/browser/browser_installssl.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_installssl.js
@@ -9,49 +9,57 @@ const NETWORK_FAILURE = AddonManager.ERR
 
 const HTTP = "http://example.com/";
 const HTTPS = "https://example.com/";
 const NOCERT = "https://nocert.example.com/";
 const SELFSIGNED = "https://self-signed.example.com/";
 const UNTRUSTED = "https://untrusted.example.com/";
 const EXPIRED = "https://expired.example.com/";
 
+const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
+
 var gTests = [];
 var gStart = 0;
 var gLast = 0;
 var gPendingInstall = null;
 
 function test() {
   gStart = Date.now();
-  requestLongerTimeout(2);
+  requestLongerTimeout(4);
   waitForExplicitFinish();
 
   registerCleanupFunction(function() {
+    var cos = Cc["@mozilla.org/security/certoverride;1"].
+              getService(Ci.nsICertOverrideService);
+    cos.clearValidityOverride("nocert.example.com", -1);
+    cos.clearValidityOverride("self-signed.example.com", -1);
+    cos.clearValidityOverride("untrusted.example.com", -1);
+    cos.clearValidityOverride("expired.example.com", -1);
+
+    try {
+      Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
+    }
+    catch (e) {
+    }
+
     if (gPendingInstall) {
       gTests = [];
       ok(false, "Timed out in the middle of downloading " + gPendingInstall.sourceURI.spec);
       try {
         gPendingInstall.cancel();
       }
       catch (e) {
       }
     }
   });
 
   run_next_test();
 }
 
 function end_test() {
-  var cos = Cc["@mozilla.org/security/certoverride;1"].
-            getService(Ci.nsICertOverrideService);
-  cos.clearValidityOverride("nocert.example.com", -1);
-  cos.clearValidityOverride("self-signed.example.com", -1);
-  cos.clearValidityOverride("untrusted.example.com", -1);
-  cos.clearValidityOverride("expired.example.com", -1);
-
   info("All tests completed in " + (Date.now() - gStart) + "ms");
   finish();
 }
 
 function add_install_test(mainURL, redirectURL, expectedStatus) {
   gTests.push([mainURL, redirectURL, expectedStatus]);
 }
 
@@ -167,19 +175,84 @@ add_test(function() {
   add_install_test(EXPIRED,    NOCERT,     NETWORK_FAILURE);
   add_install_test(EXPIRED,    SELFSIGNED, NETWORK_FAILURE);
   add_install_test(EXPIRED,    UNTRUSTED,  NETWORK_FAILURE);
   add_install_test(EXPIRED,    EXPIRED,    NETWORK_FAILURE);
 
   run_install_tests(run_next_test);
 });
 
+// Runs tests without requiring built-in certificates, no certificate
+// exceptions and no hashes
+add_test(function() {
+  Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+
+  // Tests that a simple install works as expected.
+  add_install_test(HTTP,       null,       SUCCESS);
+  add_install_test(HTTPS,      null,       SUCCESS);
+  add_install_test(NOCERT,     null,       NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, null,       NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  null,       NETWORK_FAILURE);
+  add_install_test(EXPIRED,    null,       NETWORK_FAILURE);
+
+  // Tests that redirecting from http to other servers works as expected
+  add_install_test(HTTP,       HTTP,       SUCCESS);
+  add_install_test(HTTP,       HTTPS,      SUCCESS);
+  add_install_test(HTTP,       NOCERT,     NETWORK_FAILURE);
+  add_install_test(HTTP,       SELFSIGNED, NETWORK_FAILURE);
+  add_install_test(HTTP,       UNTRUSTED,  NETWORK_FAILURE);
+  add_install_test(HTTP,       EXPIRED,    NETWORK_FAILURE);
+
+  // Tests that redirecting from valid https to other servers works as expected
+  add_install_test(HTTPS,      HTTP,       NETWORK_FAILURE);
+  add_install_test(HTTPS,      HTTPS,      SUCCESS);
+  add_install_test(HTTPS,      NOCERT,     NETWORK_FAILURE);
+  add_install_test(HTTPS,      SELFSIGNED, NETWORK_FAILURE);
+  add_install_test(HTTPS,      UNTRUSTED,  NETWORK_FAILURE);
+  add_install_test(HTTPS,      EXPIRED,    NETWORK_FAILURE);
+
+  // Tests that redirecting from nocert https to other servers works as expected
+  add_install_test(NOCERT,     HTTP,       NETWORK_FAILURE);
+  add_install_test(NOCERT,     HTTPS,      NETWORK_FAILURE);
+  add_install_test(NOCERT,     NOCERT,     NETWORK_FAILURE);
+  add_install_test(NOCERT,     SELFSIGNED, NETWORK_FAILURE);
+  add_install_test(NOCERT,     UNTRUSTED,  NETWORK_FAILURE);
+  add_install_test(NOCERT,     EXPIRED,    NETWORK_FAILURE);
+
+  // Tests that redirecting from self-signed https to other servers works as expected
+  add_install_test(SELFSIGNED, HTTP,       NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, HTTPS,      NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, NOCERT,     NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, SELFSIGNED, NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, UNTRUSTED,  NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, EXPIRED,    NETWORK_FAILURE);
+
+  // Tests that redirecting from untrusted https to other servers works as expected
+  add_install_test(UNTRUSTED,  HTTP,       NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  HTTPS,      NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  NOCERT,     NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  SELFSIGNED, NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  UNTRUSTED,  NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  EXPIRED,    NETWORK_FAILURE);
+
+  // Tests that redirecting from expired https to other servers works as expected
+  add_install_test(EXPIRED,    HTTP,       NETWORK_FAILURE);
+  add_install_test(EXPIRED,    HTTPS,      NETWORK_FAILURE);
+  add_install_test(EXPIRED,    NOCERT,     NETWORK_FAILURE);
+  add_install_test(EXPIRED,    SELFSIGNED, NETWORK_FAILURE);
+  add_install_test(EXPIRED,    UNTRUSTED,  NETWORK_FAILURE);
+  add_install_test(EXPIRED,    EXPIRED,    NETWORK_FAILURE);
+
+  run_install_tests(run_next_test);
+});
+
 // Runs tests with built-in certificates required, all certificate exceptions
 // and no hashes
 add_test(function() {
+  Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
   addCertOverrides();
 
   // Tests that a simple install works as expected.
   add_install_test(HTTP,       null,       SUCCESS);
   add_install_test(HTTPS,      null,       NETWORK_FAILURE);
   add_install_test(NOCERT,     null,       NETWORK_FAILURE);
   add_install_test(SELFSIGNED, null,       NETWORK_FAILURE);
   add_install_test(UNTRUSTED,  null,       NETWORK_FAILURE);
@@ -230,8 +303,72 @@ add_test(function() {
   add_install_test(EXPIRED,    HTTPS,      NETWORK_FAILURE);
   add_install_test(EXPIRED,    NOCERT,     NETWORK_FAILURE);
   add_install_test(EXPIRED,    SELFSIGNED, NETWORK_FAILURE);
   add_install_test(EXPIRED,    UNTRUSTED,  NETWORK_FAILURE);
   add_install_test(EXPIRED,    EXPIRED,    NETWORK_FAILURE);
 
   run_install_tests(run_next_test);
 });
+
+// Runs tests without requiring built-in certificates, all certificate
+// exceptions and no hashes
+add_test(function() {
+  Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+
+  // Tests that a simple install works as expected.
+  add_install_test(HTTP,       null,       SUCCESS);
+  add_install_test(HTTPS,      null,       SUCCESS);
+  add_install_test(NOCERT,     null,       SUCCESS);
+  add_install_test(SELFSIGNED, null,       SUCCESS);
+  add_install_test(UNTRUSTED,  null,       SUCCESS);
+  add_install_test(EXPIRED,    null,       SUCCESS);
+
+  // Tests that redirecting from http to other servers works as expected
+  add_install_test(HTTP,       HTTP,       SUCCESS);
+  add_install_test(HTTP,       HTTPS,      SUCCESS);
+  add_install_test(HTTP,       NOCERT,     SUCCESS);
+  add_install_test(HTTP,       SELFSIGNED, SUCCESS);
+  add_install_test(HTTP,       UNTRUSTED,  SUCCESS);
+  add_install_test(HTTP,       EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from valid https to other servers works as expected
+  add_install_test(HTTPS,      HTTP,       NETWORK_FAILURE);
+  add_install_test(HTTPS,      HTTPS,      SUCCESS);
+  add_install_test(HTTPS,      NOCERT,     SUCCESS);
+  add_install_test(HTTPS,      SELFSIGNED, SUCCESS);
+  add_install_test(HTTPS,      UNTRUSTED,  SUCCESS);
+  add_install_test(HTTPS,      EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from nocert https to other servers works as expected
+  add_install_test(NOCERT,     HTTP,       NETWORK_FAILURE);
+  add_install_test(NOCERT,     HTTPS,      SUCCESS);
+  add_install_test(NOCERT,     NOCERT,     SUCCESS);
+  add_install_test(NOCERT,     SELFSIGNED, SUCCESS);
+  add_install_test(NOCERT,     UNTRUSTED,  SUCCESS);
+  add_install_test(NOCERT,     EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from self-signed https to other servers works as expected
+  add_install_test(SELFSIGNED, HTTP,       NETWORK_FAILURE);
+  add_install_test(SELFSIGNED, HTTPS,      SUCCESS);
+  add_install_test(SELFSIGNED, NOCERT,     SUCCESS);
+  add_install_test(SELFSIGNED, SELFSIGNED, SUCCESS);
+  add_install_test(SELFSIGNED, UNTRUSTED,  SUCCESS);
+  add_install_test(SELFSIGNED, EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from untrusted https to other servers works as expected
+  add_install_test(UNTRUSTED,  HTTP,       NETWORK_FAILURE);
+  add_install_test(UNTRUSTED,  HTTPS,      SUCCESS);
+  add_install_test(UNTRUSTED,  NOCERT,     SUCCESS);
+  add_install_test(UNTRUSTED,  SELFSIGNED, SUCCESS);
+  add_install_test(UNTRUSTED,  UNTRUSTED,  SUCCESS);
+  add_install_test(UNTRUSTED,  EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from expired https to other servers works as expected
+  add_install_test(EXPIRED,    HTTP,       NETWORK_FAILURE);
+  add_install_test(EXPIRED,    HTTPS,      SUCCESS);
+  add_install_test(EXPIRED,    NOCERT,     SUCCESS);
+  add_install_test(EXPIRED,    SELFSIGNED, SUCCESS);
+  add_install_test(EXPIRED,    UNTRUSTED,  SUCCESS);
+  add_install_test(EXPIRED,    EXPIRED,    SUCCESS);
+
+  run_install_tests(run_next_test);
+});
--- a/toolkit/mozapps/extensions/test/browser/browser_updatessl.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_updatessl.js
@@ -11,29 +11,33 @@ const DOWNLOAD_ERROR = AddonUpdateChecke
 
 const HTTP = "http://example.com/";
 const HTTPS = "https://example.com/";
 const NOCERT = "https://nocert.example.com/";
 const SELFSIGNED = "https://self-signed.example.com/";
 const UNTRUSTED = "https://untrusted.example.com/";
 const EXPIRED = "https://expired.example.com/";
 
+const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
+
 var gTests = [];
 var gStart = 0;
 var gLast = 0;
 
 function test() {
   gStart = Date.now();
-  requestLongerTimeout(2);
+  requestLongerTimeout(4);
   waitForExplicitFinish();
 
   run_next_test();
 }
 
 function end_test() {
+  Services.prefs.clearUserPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+
   var cos = Cc["@mozilla.org/security/certoverride;1"].
             getService(Ci.nsICertOverrideService);
   cos.clearValidityOverride("nocert.example.com", -1);
   cos.clearValidityOverride("self-signed.example.com", -1);
   cos.clearValidityOverride("untrusted.example.com", -1);
   cos.clearValidityOverride("expired.example.com", -1);
 
   info("All tests completed in " + (Date.now() - gStart) + "ms");
@@ -148,18 +152,83 @@ add_test(function() {
   add_update_test(EXPIRED,    NOCERT,     DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    SELFSIGNED, DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    UNTRUSTED,  DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    EXPIRED,    DOWNLOAD_ERROR);
 
   run_update_tests(run_next_test);
 });
 
+// Runs tests without requiring built-in certificates and no certificate
+// exceptions.
+add_test(function() {
+  Services.prefs.setBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, false);
+
+  // Tests that a simple update.rdf retrieval works as expected.
+  add_update_test(HTTP,       null,       SUCCESS);
+  add_update_test(HTTPS,      null,       SUCCESS);
+  add_update_test(NOCERT,     null,       DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, null,       DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  null,       DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    null,       DOWNLOAD_ERROR);
+
+  // Tests that redirecting from http to other servers works as expected
+  add_update_test(HTTP,       HTTP,       SUCCESS);
+  add_update_test(HTTP,       HTTPS,      SUCCESS);
+  add_update_test(HTTP,       NOCERT,     DOWNLOAD_ERROR);
+  add_update_test(HTTP,       SELFSIGNED, DOWNLOAD_ERROR);
+  add_update_test(HTTP,       UNTRUSTED,  DOWNLOAD_ERROR);
+  add_update_test(HTTP,       EXPIRED,    DOWNLOAD_ERROR);
+
+  // Tests that redirecting from valid https to other servers works as expected
+  add_update_test(HTTPS,      HTTP,       DOWNLOAD_ERROR);
+  add_update_test(HTTPS,      HTTPS,      SUCCESS);
+  add_update_test(HTTPS,      NOCERT,     DOWNLOAD_ERROR);
+  add_update_test(HTTPS,      SELFSIGNED, DOWNLOAD_ERROR);
+  add_update_test(HTTPS,      UNTRUSTED,  DOWNLOAD_ERROR);
+  add_update_test(HTTPS,      EXPIRED,    DOWNLOAD_ERROR);
+
+  // Tests that redirecting from nocert https to other servers works as expected
+  add_update_test(NOCERT,     HTTP,       DOWNLOAD_ERROR);
+  add_update_test(NOCERT,     HTTPS,      DOWNLOAD_ERROR);
+  add_update_test(NOCERT,     NOCERT,     DOWNLOAD_ERROR);
+  add_update_test(NOCERT,     SELFSIGNED, DOWNLOAD_ERROR);
+  add_update_test(NOCERT,     UNTRUSTED,  DOWNLOAD_ERROR);
+  add_update_test(NOCERT,     EXPIRED,    DOWNLOAD_ERROR);
+
+  // Tests that redirecting from self-signed https to other servers works as expected
+  add_update_test(SELFSIGNED, HTTP,       DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, HTTPS,      DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, NOCERT,     DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, SELFSIGNED, DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, UNTRUSTED,  DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, EXPIRED,    DOWNLOAD_ERROR);
+
+  // Tests that redirecting from untrusted https to other servers works as expected
+  add_update_test(UNTRUSTED,  HTTP,       DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  HTTPS,      DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  NOCERT,     DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  SELFSIGNED, DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  UNTRUSTED,  DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  EXPIRED,    DOWNLOAD_ERROR);
+
+  // Tests that redirecting from expired https to other servers works as expected
+  add_update_test(EXPIRED,    HTTP,       DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    HTTPS,      DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    NOCERT,     DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    SELFSIGNED, DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    UNTRUSTED,  DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    EXPIRED,    DOWNLOAD_ERROR);
+
+  run_update_tests(run_next_test);
+});
+
 // Runs tests with built-in certificates required and all certificate exceptions.
 add_test(function() {
+  Services.prefs.clearUserPref(PREF_UPDATE_REQUIREBUILTINCERTS);
   addCertOverrides();
 
   // Tests that a simple update.rdf retrieval works as expected.
   add_update_test(HTTP,       null,       SUCCESS);
   add_update_test(HTTPS,      null,       DOWNLOAD_ERROR);
   add_update_test(NOCERT,     null,       DOWNLOAD_ERROR);
   add_update_test(SELFSIGNED, null,       DOWNLOAD_ERROR);
   add_update_test(UNTRUSTED,  null,       DOWNLOAD_ERROR);
@@ -210,8 +279,72 @@ add_test(function() {
   add_update_test(EXPIRED,    HTTPS,      DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    NOCERT,     DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    SELFSIGNED, DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    UNTRUSTED,  DOWNLOAD_ERROR);
   add_update_test(EXPIRED,    EXPIRED,    DOWNLOAD_ERROR);
 
   run_update_tests(run_next_test);
 });
+
+// Runs tests without requiring built-in certificates and all certificate
+// exceptions.
+add_test(function() {
+  Services.prefs.setBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, false);
+
+  // Tests that a simple update.rdf retrieval works as expected.
+  add_update_test(HTTP,       null,       SUCCESS);
+  add_update_test(HTTPS,      null,       SUCCESS);
+  add_update_test(NOCERT,     null,       SUCCESS);
+  add_update_test(SELFSIGNED, null,       SUCCESS);
+  add_update_test(UNTRUSTED,  null,       SUCCESS);
+  add_update_test(EXPIRED,    null,       SUCCESS);
+
+  // Tests that redirecting from http to other servers works as expected
+  add_update_test(HTTP,       HTTP,       SUCCESS);
+  add_update_test(HTTP,       HTTPS,      SUCCESS);
+  add_update_test(HTTP,       NOCERT,     SUCCESS);
+  add_update_test(HTTP,       SELFSIGNED, SUCCESS);
+  add_update_test(HTTP,       UNTRUSTED,  SUCCESS);
+  add_update_test(HTTP,       EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from valid https to other servers works as expected
+  add_update_test(HTTPS,      HTTP,       DOWNLOAD_ERROR);
+  add_update_test(HTTPS,      HTTPS,      SUCCESS);
+  add_update_test(HTTPS,      NOCERT,     SUCCESS);
+  add_update_test(HTTPS,      SELFSIGNED, SUCCESS);
+  add_update_test(HTTPS,      UNTRUSTED,  SUCCESS);
+  add_update_test(HTTPS,      EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from nocert https to other servers works as expected
+  add_update_test(NOCERT,     HTTP,       DOWNLOAD_ERROR);
+  add_update_test(NOCERT,     HTTPS,      SUCCESS);
+  add_update_test(NOCERT,     NOCERT,     SUCCESS);
+  add_update_test(NOCERT,     SELFSIGNED, SUCCESS);
+  add_update_test(NOCERT,     UNTRUSTED,  SUCCESS);
+  add_update_test(NOCERT,     EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from self-signed https to other servers works as expected
+  add_update_test(SELFSIGNED, HTTP,       DOWNLOAD_ERROR);
+  add_update_test(SELFSIGNED, HTTPS,      SUCCESS);
+  add_update_test(SELFSIGNED, NOCERT,     SUCCESS);
+  add_update_test(SELFSIGNED, SELFSIGNED, SUCCESS);
+  add_update_test(SELFSIGNED, UNTRUSTED,  SUCCESS);
+  add_update_test(SELFSIGNED, EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from untrusted https to other servers works as expected
+  add_update_test(UNTRUSTED,  HTTP,       DOWNLOAD_ERROR);
+  add_update_test(UNTRUSTED,  HTTPS,      SUCCESS);
+  add_update_test(UNTRUSTED,  NOCERT,     SUCCESS);
+  add_update_test(UNTRUSTED,  SELFSIGNED, SUCCESS);
+  add_update_test(UNTRUSTED,  UNTRUSTED,  SUCCESS);
+  add_update_test(UNTRUSTED,  EXPIRED,    SUCCESS);
+
+  // Tests that redirecting from expired https to other servers works as expected
+  add_update_test(EXPIRED,    HTTP,       DOWNLOAD_ERROR);
+  add_update_test(EXPIRED,    HTTPS,      SUCCESS);
+  add_update_test(EXPIRED,    NOCERT,     SUCCESS);
+  add_update_test(EXPIRED,    SELFSIGNED, SUCCESS);
+  add_update_test(EXPIRED,    UNTRUSTED,  SUCCESS);
+  add_update_test(EXPIRED,    EXPIRED,    SUCCESS);
+
+  run_update_tests(run_next_test);
+});