Bug 1244357: Use a shim around the certificate DB to allow the add-ons manager to think that add-ons are signed when they aren't. r=rhelmer draft
authorDave Townsend <dtownsend@oxymoronical.com>
Fri, 29 Jan 2016 16:41:18 -0800
changeset 329856 ac9fe26f07d9c485dc6341fd537c6f6f9a498e4e
parent 329855 5afb767f35912c1931481d24b31571fd8d14ac4c
child 514043 b4c513d352cc32197d423d82add2b384468501b6
push id10617
push userdtownsend@mozilla.com
push dateTue, 09 Feb 2016 16:30:19 +0000
reviewersrhelmer
bugs1244357
milestone47.0a1
Bug 1244357: Use a shim around the certificate DB to allow the add-ons manager to think that add-ons are signed when they aren't. r=rhelmer Because the add-ons manager hasn't startup up yet we can replace the certificate database in xpcshell tests with one that claims add-ons are signed by valid certificates even when they aren't. This allows us to run tests even in builds where signing cannot be disabled during for the normal application. This adds an override for all tests except those that are explicitely testing signing.
python/mozbuild/mozbuild/mozinfo.py
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
toolkit/mozapps/extensions/test/xpcshell/test_e10s_restartless.js
toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_migrate.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_multi.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_updatepref.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js
toolkit/mozapps/extensions/test/xpcshell/test_temporary.js
toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
--- a/python/mozbuild/mozbuild/mozinfo.py
+++ b/python/mozbuild/mozbuild/mozinfo.py
@@ -87,16 +87,17 @@ def build_dict(config, env=os.environ):
     d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
     d['sync'] = substs.get('MOZ_SERVICES_SYNC') == '1'
     d['asan'] = substs.get('MOZ_ASAN') == '1'
     d['tsan'] = substs.get('MOZ_TSAN') == '1'
     d['telemetry'] = substs.get('MOZ_TELEMETRY_REPORTING') == '1'
     d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
     d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
     d['addon_signing'] = substs.get('MOZ_ADDON_SIGNING') == '1'
+    d['require_signing'] = substs.get('MOZ_REQUIRE_SIGNING') == '1'
     d['official'] = bool(substs.get('MOZILLA_OFFICIAL'))
 
     def guess_platform():
         if d['buildapp'] in ('browser', 'mulet'):
             p = d['os']
             if p == 'mac':
                 p = 'macosx64'
             elif d['bits'] == 64:
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -1010,17 +1010,17 @@ add_task(function* test_addonsAndPlugins
     appDisabled: false,
     version: "1.0",
     scope: 1,
     type: "extension",
     foreignInstall: false,
     hasBinaryComponents: false,
     installDay: ADDON_INSTALL_DATE,
     updateDay: ADDON_INSTALL_DATE,
-    signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
+    signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
   };
 
   const EXPECTED_PLUGIN_DATA = {
     name: FLASH_PLUGIN_NAME,
     version: FLASH_PLUGIN_VERSION,
     description: FLASH_PLUGIN_DESC,
     blocklisted: false,
     disabled: false,
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -1636,21 +1636,28 @@ function verifyZipSignedState(aFile, aAd
   let certDB = Cc["@mozilla.org/security/x509certdb;1"]
                .getService(Ci.nsIX509CertDB);
 
   let root = Ci.nsIX509CertDB.AddonsPublicRoot;
   if (!REQUIRE_SIGNING && Preferences.get(PREF_XPI_SIGNATURES_DEV_ROOT, false))
     root = Ci.nsIX509CertDB.AddonsStageRoot;
 
   return new Promise(resolve => {
-    certDB.openSignedAppFileAsync(root, aFile, (aRv, aZipReader, aCert) => {
-      if (aZipReader)
-        aZipReader.close();
-      resolve(getSignedStatus(aRv, aCert, aAddon.id));
-    });
+    let callback = {
+      openSignedAppFileFinished: function(aRv, aZipReader, aCert) {
+        if (aZipReader)
+          aZipReader.close();
+        resolve(getSignedStatus(aRv, aCert, aAddon.id));
+      }
+    };
+    // This allows the certificate DB to get the raw JS callback object so the
+    // test code can pass through objects that XPConnect would reject.
+    callback.wrappedJSObject = callback;
+
+    certDB.openSignedAppFileAsync(root, aFile, callback);
   });
 }
 
 /**
  * Verifies that a directory's contents are all correctly signed by an
  * AMO-issued certificate
  *
  * @param  aDir
@@ -1666,19 +1673,26 @@ function verifyDirSignedState(aDir, aAdd
   let certDB = Cc["@mozilla.org/security/x509certdb;1"]
                .getService(Ci.nsIX509CertDB);
 
   let root = Ci.nsIX509CertDB.AddonsPublicRoot;
   if (!REQUIRE_SIGNING && Preferences.get(PREF_XPI_SIGNATURES_DEV_ROOT, false))
     root = Ci.nsIX509CertDB.AddonsStageRoot;
 
   return new Promise(resolve => {
-    certDB.verifySignedDirectoryAsync(root, aDir, (aRv, aCert) => {
-      resolve(getSignedStatus(aRv, aCert, aAddon.id));
-    });
+    let callback = {
+      verifySignedDirectoryFinished: function(aRv, aCert) {
+        resolve(getSignedStatus(aRv, aCert, aAddon.id));
+      }
+    };
+    // This allows the certificate DB to get the raw JS callback object so the
+    // test code can pass through objects that XPConnect would reject.
+    callback.wrappedJSObject = callback;
+
+    certDB.verifySignedDirectoryAsync(root, aDir, callback);
   });
 }
 
 /**
  * Verifies that a bundle's contents are all correctly signed by an
  * AMO-issued certificate
  *
  * @param  aBundle
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -2,16 +2,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var AM_Cc = Components.classes;
 var AM_Ci = Components.interfaces;
 
 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
+const CERTDB_CONTRACTID = "@mozilla.org/security/x509certdb;1";
+const CERTDB_CID = Components.ID("{fb0bbc5c-452e-4783-b32c-80124693d871}");
 
 const PREF_EM_CHECK_UPDATE_SECURITY   = "extensions.checkUpdateSecurity";
 const PREF_EM_STRICT_COMPATIBILITY    = "extensions.strictCompatibility";
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
 const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
 const PREF_GETADDONS_BYIDS               = "extensions.getAddons.get.url";
 const PREF_GETADDONS_BYIDS_PERFORMANCE   = "extensions.getAddons.getWithPerformance.url";
 const PREF_XPI_SIGNATURES_REQUIRED    = "xpinstall.signatures.required";
@@ -291,16 +293,189 @@ function createAppInfo(id, name, version
       return gAppInfo.QueryInterface(iid);
     }
   };
   var registrar = Components.manager.QueryInterface(AM_Ci.nsIComponentRegistrar);
   registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
                             XULAPPINFO_CONTRACTID, XULAppInfoFactory);
 }
 
+function getManifestURIForBundle(file) {
+  if (file.isDirectory()) {
+    file.append("install.rdf");
+    if (file.exists()) {
+      return NetUtil.newURI(file);
+    }
+
+    file.leafName = "manifest.json";
+    if (file.exists()) {
+      return NetUtil.newURI(file);
+    }
+
+    throw new Error("No manifest file present");
+  }
+
+  let zip = AM_Cc["@mozilla.org/libjar/zip-reader;1"].
+            createInstance(AM_Ci.nsIZipReader);
+  zip.open(file);
+  try {
+    let uri = NetUtil.newURI(file);
+
+    if (zip.hasEntry("install.rdf")) {
+      return NetUtil.newURI("jar:" + uri.spec + "!/" + "install.rdf");
+    }
+
+    if (zip.hasEntry("manifest.json")) {
+      return NetUtil.newURI("jar:" + uri.spec + "!/" + "manifest.json");
+    }
+
+    throw new Error("No manifest file present");
+  }
+  finally {
+    zip.close();
+  }
+}
+
+let getIDForManifest = Task.async(function*(manifestURI) {
+  // Load it
+  let inputStream = yield new Promise((resolve, reject) => {
+    NetUtil.asyncFetch({
+      uri: manifestURI,
+      loadUsingSystemPrincipal: true,
+    }, (inputStream, status) => {
+      if (status != Components.results.NS_OK)
+        reject(status);
+      resolve(inputStream);
+    });
+  });
+
+  // Get the data as a string
+  let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
+
+  if (manifestURI.spec.endsWith(".rdf")) {
+    let rdfParser = AM_Cc["@mozilla.org/rdf/xml-parser;1"].
+                    createInstance(AM_Ci.nsIRDFXMLParser)
+    let ds = AM_Cc["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"].
+             createInstance(AM_Ci.nsIRDFDataSource);
+    rdfParser.parseString(ds, manifestURI, data);
+
+    let rdfService = AM_Cc["@mozilla.org/rdf/rdf-service;1"].
+                     getService(AM_Ci.nsIRDFService);
+
+    let rdfID = ds.GetTarget(rdfService.GetResource("urn:mozilla:install-manifest"),
+                             rdfService.GetResource("http://www.mozilla.org/2004/em-rdf#id"),
+                             true);
+    return rdfID.QueryInterface(AM_Ci.nsIRDFLiteral).Value;
+  }
+  else {
+    let manifest = JSON.parse(data);
+    return manifest.applications.gecko.id;
+  }
+});
+
+let gUseRealCertChecks = false;
+function overrideCertDB(handler) {
+  // Unregister the real database. This only works because the add-ons manager
+  // hasn't started up and grabbed the certificate database yet.
+  let registrar = Components.manager.QueryInterface(AM_Ci.nsIComponentRegistrar);
+  let factory = registrar.getClassObject(CERTDB_CID, AM_Ci.nsIFactory);
+  registrar.unregisterFactory(CERTDB_CID, factory);
+
+  // Get the real DB
+  let realCertDB = factory.createInstance(null, AM_Ci.nsIX509CertDB);
+
+  let verifyCert = Task.async(function*(caller, file, result, cert, callback) {
+    // If this isn't a callback we can get directly to through JS then just
+    // pass on the results
+    if (!callback.wrappedJSObject) {
+      caller(callback, result, cert);
+      return;
+    }
+
+    // Bypassing XPConnect allows us to create a fake x509 certificate from
+    // JS
+    callback = callback.wrappedJSObject;
+
+    if (gUseRealCertChecks || result != Components.results.NS_ERROR_SIGNED_JAR_NOT_SIGNED) {
+      // If the real DB found a useful result of some kind then pass it on.
+      caller(callback, result, cert);
+      return;
+    }
+
+    try {
+      let manifestURI = getManifestURIForBundle(file);
+
+      let id = yield getIDForManifest(manifestURI);
+
+      // Make sure to close the open zip file or it will be locked.
+      if (file.isFile()) {
+        Services.obs.notifyObservers(file, "flush-cache-entry", "cert-override");
+      }
+
+      let fakeCert = {
+        commonName: id
+      }
+      caller(callback, Components.results.NS_OK, fakeCert);
+    }
+    catch (e) {
+      // If there is any error then just pass along the original results
+      caller(callback, result, cert);
+    }
+  });
+
+  let fakeCertDB = {
+    openSignedAppFileAsync(root, file, callback) {
+      // First try calling the real cert DB
+      realCertDB.openSignedAppFileAsync(root, file, (result, zipReader, cert) => {
+        function call(callback, result, cert) {
+          callback.openSignedAppFileFinished(result, zipReader, cert);
+        }
+
+        verifyCert(call, file.clone(), result, cert, callback);
+      });
+    },
+
+    verifySignedDirectoryAsync(root, dir, callback) {
+      // First try calling the real cert DB
+      realCertDB.verifySignedDirectoryAsync(root, dir, (result, cert) => {
+        function call(callback, result, cert) {
+          callback.verifySignedDirectoryFinished(result, cert);
+        }
+
+        verifyCert(call, dir.clone(), result, cert, callback);
+      });
+    },
+
+    QueryInterface: XPCOMUtils.generateQI([AM_Ci.nsIX509CertDB])
+  };
+
+  for (let property of Object.keys(realCertDB)) {
+    if (property in fakeCertDB) {
+      continue;
+    }
+
+    if (typeof realCertDB[property] == "function") {
+      fakeCertDB[property] = realCertDB[property].bind(realCertDB);
+    }
+  }
+
+  let certDBFactory = {
+    createInstance: function(outer, iid) {
+      if (outer != null) {
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      }
+      return fakeCertDB.QueryInterface(iid);
+    }
+  };
+  registrar.registerFactory(CERTDB_CID, "CertDB",
+                            CERTDB_CONTRACTID, certDBFactory);
+}
+
+overrideCertDB();
+
 /**
  * Tests that an add-on does appear in the crash report annotations, if
  * crash reporting is enabled. The test will fail if the add-on is not in the
  * annotation.
  * @param  aId
  *         The ID of the add-on
  * @param  aVersion
  *         The version of the add-on
@@ -1731,18 +1906,18 @@ Services.prefs.setBoolPref("extensions.s
 
 // By default don't check for hotfixes
 Services.prefs.setCharPref("extensions.hotfix.id", "");
 
 // By default, set min compatible versions to 0
 Services.prefs.setCharPref(PREF_EM_MIN_COMPAT_APP_VERSION, "0");
 Services.prefs.setCharPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, "0");
 
-// Disable signature checks for most tests
-Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
+// Ensure signature checks are enabled by default
+Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
 
 // Register a temporary directory for the tests.
 const gTmpD = gProfD.clone();
 gTmpD.append("temp");
 gTmpD.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 registerDirectory("TmpD", gTmpD);
 
 // Create a replacement app directory for the tests.
--- a/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
@@ -6,16 +6,19 @@
 
 var gExpectedFile = null;
 var gCacheFlushCount = 0;
 
 var CacheFlushObserver = {
   observe: function(aSubject, aTopic, aData) {
     if (aTopic != "flush-cache-entry")
       return;
+    // Ignore flushes triggered by the fake cert DB
+    if (aData == "cert-override")
+      return;
 
     do_check_true(gExpectedFile != null);
     do_check_true(aSubject instanceof AM_Ci.nsIFile);
     do_check_eq(aSubject.path, gExpectedFile.path);
     gCacheFlushCount++;
   }
 };
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_e10s_restartless.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_e10s_restartless.js
@@ -280,11 +280,12 @@ add_task(function*() {
   restartManager();
 });
 
 // The hotfix is unaffected
 add_task(function*() {
   gAppInfo.browserTabsRemoteAutostart = true;
   Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", true);
   Services.prefs.setCharPref("extensions.hotfix.id", ID);
+  Services.prefs.setBoolPref("extensions.hotfix.cert.checkAttributes", false);
 
   yield check_normal();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
@@ -44,17 +44,17 @@ add_task(function*() {
 
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1 (proxy)");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   do_check_true(proxyFile.exists());
 
   addon.uninstall();
   unpackedAddon.remove(true);
 
   yield promiseRestartManager();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js
@@ -1,10 +1,10 @@
 // Enable signature checks for these tests
-Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
+gUseRealCertChecks = true;
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 
 const DATA = "data/signing_checks/";
 const ADDONS = {
   bootstrap: {
     unsigned: "unsigned_bootstrap_2.xpi",
     badid: "signed_bootstrap_badid_2.xpi",
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js
@@ -1,10 +1,10 @@
 // Enable signature checks for these tests
-Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
+gUseRealCertChecks = true;
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 
 const DATA = "data/signing_checks/";
 const ADDONS = {
   bootstrap: {
     unsigned: "unsigned_bootstrap_2.xpi",
     badid: "signed_bootstrap_badid_2.xpi",
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js
@@ -1,16 +1,18 @@
 const PREF_XPI_SIGNATURES_DEV_ROOT    = "xpinstall.signatures.dev-root";
 
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 
 // The test add-ons were signed by the dev root
 Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, true);
 
+gUseRealCertChecks = true;
+
 const DATA = "data/signing_checks/";
 
 const ID_63 = "123456789012345678901234567890123456789012345@tests.mozilla.org"
 const ID_64 = "1234567890123456789012345678901234567890123456@tests.mozilla.org"
 const ID_65 = "12345678901234567890123456789012345678901234568@tests.mozilla.org"
 
 function run_test() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
@@ -30,22 +32,23 @@ add_task(function* test_working() {
   for (let addon of addons) {
     do_check_neq(addon, null);
     do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_SIGNED);
 
     addon.uninstall();
   }
 });
 
-// Installs the cases that should be broken
+// Checks the cases that should be broken
 add_task(function* test_broken() {
- yield promiseInstallAllFiles([do_get_file(DATA + "long_63_hash.xpi"),
-                               do_get_file(DATA + "long_64_hash.xpi")]);
+  function promiseInstallForFile(file) {
+    return new Promise(resolve => AddonManager.getInstallForFile(file, resolve));
+  }
 
-  let addons = yield promiseAddonsByIDs([ID_63, ID_64]);
+  let promises = [promiseInstallForFile(do_get_file(DATA + "long_63_hash.xpi")),
+                  promiseInstallForFile(do_get_file(DATA + "long_64_hash.xpi"))];
+  let installs = yield Promise.all(promises);
 
-  for (let addon of addons) {
-    do_check_neq(addon, null);
-    do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
-
-    addon.uninstall();
+  for (let install of installs) {
+    do_check_eq(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
+    do_check_eq(install.error, AddonManager.ERROR_CORRUPT_FILE);
   }
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_migrate.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_migrate.js
@@ -1,10 +1,10 @@
 // Enable signature checks for these tests
-Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
+gUseRealCertChecks = true;
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 // Allow attempting to show the compatibility UI which should not happen
 Services.prefs.setBoolPref("extensions.showMismatchUI", true);
 
 const DATA = "data/signing_checks/";
 const ADDONS = {
   bootstrap: {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_multi.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_multi.js
@@ -1,10 +1,10 @@
 // Enable signature checks for these tests
-Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
+gUseRealCertChecks = true;
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 
 const DATA = "data/signing_checks/";
 
 // Each multi-package XPI contains one valid theme and one other add-on that
 // has the following error state:
 const ADDONS = {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_updatepref.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_updatepref.js
@@ -1,10 +1,11 @@
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
+gUseRealCertChecks = true;
 
 const DATA = "data/signing_checks/";
 const ID = "test@tests.mozilla.org";
 
 Components.utils.import("resource://testing-common/httpd.js");
 var gServer = new HttpServer();
 gServer.start();
 
@@ -49,16 +50,17 @@ function run_test() {
   shutdownManager();
 
   run_next_test();
 }
 
 // Updating the pref without changing the app version won't disable add-ons
 // immediately but will after a signing check
 add_task(function*() {
+  Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
   startupManager();
 
   // Install the signed add-on
   yield promiseInstallAllFiles([do_get_file(DATA + "unsigned_bootstrap_2.xpi")]);
 
   let addon = yield promiseAddonByID(ID);
   do_check_neq(addon, null);
   do_check_false(addon.appDisabled);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js
@@ -1,10 +1,10 @@
 // Enable signature checks for these tests
-Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
+gUseRealCertChecks = true;
 // Disable update security
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 
 const DATA = "data/signing_checks/";
 const GOOD = [
   ["signed_bootstrap_2.xpi", AddonManager.SIGNEDSTATE_SIGNED],
   ["signed_nonbootstrap_2.xpi", AddonManager.SIGNEDSTATE_SIGNED]
 ];
--- a/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js
@@ -52,17 +52,17 @@ add_task(function*() {
 
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   yield promiseRestartManager();
 
   BootstrapMonitor.checkAddonNotInstalled(ID);
   BootstrapMonitor.checkAddonNotStarted(ID);
 
   addon = yield promiseAddonByID(ID);
   do_check_eq(addon, null);
@@ -82,17 +82,17 @@ add_task(function*() {
 
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   // test that an unpacked add-on works too
   let tempdir = gTmpD.clone();
 
   writeInstallRDFToDir({
     id: ID,
     version: "2.0",
     bootstrap: true,
@@ -120,34 +120,34 @@ add_task(function*() {
   // temporary add-on is installed and started
   do_check_neq(addon, null);
   do_check_eq(addon.version, "2.0");
   do_check_eq(addon.name, "Test Bootstrap 1 (temporary)");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   restartManager();
 
   BootstrapMonitor.checkAddonInstalled(ID, "1.0");
   BootstrapMonitor.checkAddonStarted(ID, "1.0");
 
   addon = yield promiseAddonByID(ID);
 
   // existing add-on is back
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   unpacked_addon.remove(true);
   addon.uninstall();
 
   BootstrapMonitor.checkAddonNotInstalled(ID);
   BootstrapMonitor.checkAddonNotStarted(ID);
 
   yield promiseRestartManager();
@@ -221,34 +221,34 @@ add_task(function*() {
   // temporary add-on is installed and started
   do_check_neq(addon, null);
   do_check_eq(addon.version, "2.0");
   do_check_eq(addon.name, "Test Bootstrap 1 (temporary)");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   addon.uninstall();
 
   addon = yield promiseAddonByID(ID);
 
   BootstrapMonitor.checkAddonInstalled(ID);
   BootstrapMonitor.checkAddonStarted(ID);
 
   // existing add-on is back
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   unpacked_addon.remove(true);
   addon.uninstall();
 
   BootstrapMonitor.checkAddonNotInstalled(ID);
   BootstrapMonitor.checkAddonNotStarted(ID);
 
   yield promiseRestartManager();
@@ -309,17 +309,17 @@ add_task(function*() {
   // temporary add-on is installed and started
   do_check_neq(tempAddon, null);
   do_check_eq(tempAddon.version, "2.0");
   do_check_eq(tempAddon.name, "Test Bootstrap 1 (temporary)");
   do_check_true(tempAddon.isCompatible);
   do_check_false(tempAddon.appDisabled);
   do_check_true(tempAddon.isActive);
   do_check_eq(tempAddon.type, "extension");
-  do_check_eq(tempAddon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(tempAddon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   tempAddon.uninstall();
   unpacked_addon.remove(true);
 
   addon.userDisabled = false;
   addon = yield promiseAddonByID(ID);
 
   BootstrapMonitor.checkAddonInstalled(ID, "1.0");
@@ -328,17 +328,17 @@ add_task(function*() {
   // existing add-on is back
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   addon.uninstall();
 
   BootstrapMonitor.checkAddonNotInstalled(ID);
   BootstrapMonitor.checkAddonNotStarted(ID);
 
   yield promiseRestartManager();
 });
@@ -363,17 +363,17 @@ add_task(function*(){
   do_check_neq(addon, null);
   do_check_eq(addon.id, non_restartless_ID);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   let tempdir = gTmpD.clone();
   writeInstallRDFToDir({
     id: non_restartless_ID,
     version: "2.0",
     bootstrap: true,
     unpack: true,
     targetApplications: [{
@@ -418,17 +418,17 @@ add_task(function*() {
 
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Test Bootstrap 1");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   try {
     yield AddonManager.installTemporaryAddon(do_get_addon("test_bootstrap1_1"));
     do_throw("Installing a temporary second temporary add-on should return"
              + " a rejected promise");
   } catch (err) {
     do_check_eq(err.message,
         "Add-on with ID bootstrap1@tests.mozilla.org is already temporarily"
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
@@ -50,17 +50,17 @@ add_task(function*() {
   let addon = yield promiseAddonByID(ID);
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Web Extension Name");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   let uri = do_get_addon_root_uri(profileDir, ID);
 
   do_check_eq(addon.iconURL, uri + "icon48.png");
   do_check_eq(addon.icon64URL, uri + "icon64.png");
 
   // Should persist through a restart
   yield promiseShutdownManager();
@@ -77,17 +77,17 @@ add_task(function*() {
   addon = yield promiseAddonByID(ID);
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Web Extension Name");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   let file = getFileForAddon(profileDir, ID);
   do_check_true(file.exists());
 
   uri = do_get_addon_root_uri(profileDir, ID);
 
   do_check_eq(addon.iconURL, uri + "icon48.png");
   do_check_eq(addon.icon64URL, uri + "icon64.png");
@@ -130,17 +130,17 @@ add_task(function*() {
   let addon = yield promiseAddonByID(ID);
   do_check_neq(addon, null);
   do_check_eq(addon.version, "1.0");
   do_check_eq(addon.name, "Web Extension Name");
   do_check_true(addon.isCompatible);
   do_check_false(addon.appDisabled);
   do_check_true(addon.isActive);
   do_check_eq(addon.type, "extension");
-  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+  do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
 
   let file = getFileForAddon(profileDir, ID);
   do_check_true(file.exists());
 
   addon.uninstall();
 
   yield promiseRestartManager();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
@@ -234,16 +234,17 @@ skip-if = os == "android"
 [test_pluginBlocklistCtp.js]
 # Bug 676992: test consistently fails on Android
 fail-if = buildapp == "mulet" || os == "android"
 [test_pref_properties.js]
 [test_registry.js]
 [test_safemode.js]
 [test_signed_updatepref.js]
 run-if = addon_signing
+skip-if = require_signing
 [test_signed_verify.js]
 run-if = addon_signing
 [test_signed_inject.js]
 run-if = addon_signing
 [test_signed_install.js]
 run-if = addon_signing
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_signed_long.js]