Bug 1224467 - Add a preference for controlling whether oneCRL blocklists are updated via AMO. Also add a test. r=keeler,mossop
authorMark Goodwin <mgoodwin@mozilla.com>
Wed, 18 Nov 2015 11:53:54 +0000
changeset 273127 9207e17e5e38be9bdadaeb4eb016a599f61dca30
parent 273126 6d2641e05d2b04668176569d0e34fd3839018efd
child 273128 9e4218058d633480b4a17db6cf3d3831418b6ec3
push id29696
push usercbook@mozilla.com
push dateThu, 19 Nov 2015 13:45:03 +0000
treeherdermozilla-central@a523d4c7efe2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler, mossop
bugs1224467
milestone45.0a1
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 1224467 - Add a preference for controlling whether oneCRL blocklists are updated via AMO. Also add a test. r=keeler,mossop
security/manager/ssl/CertBlocklist.cpp
security/manager/ssl/CertBlocklist.h
security/manager/ssl/tests/unit/test_cert_blocklist.js
security/manager/ssl/tests/unit/test_ev_certs.js
toolkit/mozapps/extensions/nsBlocklistService.js
--- a/security/manager/ssl/CertBlocklist.cpp
+++ b/security/manager/ssl/CertBlocklist.cpp
@@ -26,21 +26,23 @@
 
 NS_IMPL_ISUPPORTS(CertBlocklist, nsICertBlocklist)
 
 using namespace mozilla;
 using namespace mozilla::pkix;
 
 #define PREF_BACKGROUND_UPDATE_TIMER "app.update.lastUpdateTime.blocklist-background-update-timer"
 #define PREF_MAX_STALENESS_IN_SECONDS "security.onecrl.maximum_staleness_in_seconds"
+#define PREF_ONECRL_VIA_AMO "security.onecrl.via.amo"
 
 static PRLogModuleInfo* gCertBlockPRLog;
 
 uint32_t CertBlocklist::sLastBlocklistUpdate = 0U;
 uint32_t CertBlocklist::sMaxStaleness = 0U;
+bool CertBlocklist::sUseAMO = true;
 
 CertBlocklistItem::CertBlocklistItem(const uint8_t* DNData,
                                      size_t DNLength,
                                      const uint8_t* otherData,
                                      size_t otherLength,
                                      CertBlocklistItemMechanism itemMechanism)
   : mIsCurrent(false)
   , mItemMechanism(itemMechanism)
@@ -134,16 +136,19 @@ CertBlocklist::CertBlocklist()
 CertBlocklist::~CertBlocklist()
 {
   Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
                                   PREF_BACKGROUND_UPDATE_TIMER,
                                   this);
   Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
                                   PREF_MAX_STALENESS_IN_SECONDS,
                                   this);
+  Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
+                                  PREF_ONECRL_VIA_AMO,
+                                  this);
 }
 
 nsresult
 CertBlocklist::Init()
 {
   MOZ_LOG(gCertBlockPRLog, LogLevel::Debug, ("CertBlocklist::Init"));
 
   // Init must be on main thread for getting the profile directory
@@ -162,16 +167,22 @@ CertBlocklist::Init()
     return rv;
   }
   rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
                                             PREF_MAX_STALENESS_IN_SECONDS,
                                             this);
   if (NS_FAILED(rv)) {
     return rv;
   }
+  rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
+                                            PREF_ONECRL_VIA_AMO,
+                                            this);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   // Get the profile directory
   rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                               getter_AddRefs(mBackingFile));
   if (NS_FAILED(rv) || !mBackingFile) {
     MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
            ("CertBlocklist::Init - couldn't get profile dir"));
     // Since we're returning NS_OK here, set mBackingFile to a safe value.
@@ -601,16 +612,21 @@ CertBlocklist::IsCertRevoked(const uint8
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CertBlocklist::IsBlocklistFresh(bool* _retval)
 {
   MutexAutoLock lock(mMutex);
   *_retval = false;
+  if (!sUseAMO) {
+    // for the time being, if we're not using AMO data, assume the blocklist is
+    // not fresh (in particular, prevent OneCRL OCSP bypass).
+    return NS_OK;
+  }
 
   uint32_t now = uint32_t(PR_Now() / PR_USEC_PER_SEC);
 
   if (now > sLastBlocklistUpdate) {
     int64_t interval = now - sLastBlocklistUpdate;
     MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
            ("CertBlocklist::IsBlocklistFresh we're after the last BlocklistUpdate "
             "interval is %i, staleness %u", interval, sMaxStaleness));
@@ -633,10 +649,12 @@ CertBlocklist::PreferenceChanged(const c
   MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
          ("CertBlocklist::PreferenceChanged %s changed", aPref));
   if (strcmp(aPref, PREF_BACKGROUND_UPDATE_TIMER) == 0) {
     sLastBlocklistUpdate = Preferences::GetUint(PREF_BACKGROUND_UPDATE_TIMER,
                                                 uint32_t(0));
   } else if (strcmp(aPref, PREF_MAX_STALENESS_IN_SECONDS) == 0) {
     sMaxStaleness = Preferences::GetUint(PREF_MAX_STALENESS_IN_SECONDS,
                                          uint32_t(0));
+  } else if (strcmp(aPref, PREF_ONECRL_VIA_AMO) == 0) {
+    sUseAMO = Preferences::GetBool(PREF_ONECRL_VIA_AMO, true);
   }
 }
--- a/security/manager/ssl/CertBlocklist.h
+++ b/security/manager/ssl/CertBlocklist.h
@@ -76,12 +76,13 @@ private:
   // modify CertBlocklist data
   nsresult EnsureBackingFileInitialized(mozilla::MutexAutoLock& lock);
   nsCOMPtr<nsIFile> mBackingFile;
 
 protected:
   static void PreferenceChanged(const char* aPref, void* aClosure);
   static uint32_t sLastBlocklistUpdate;
   static uint32_t sMaxStaleness;
+  static bool sUseAMO;
   virtual ~CertBlocklist();
 };
 
 #endif // CertBlocklist_h
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -77,18 +77,17 @@ if (!revocations.exists()) {
 }
 
 var certDB = Cc["@mozilla.org/security/x509certdb;1"]
                .getService(Ci.nsIX509CertDB);
 
 // set up a test server to serve the blocklist.xml
 var testserver = new HttpServer();
 
-var blocklist_contents =
-    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+var initialBlocklist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
     "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
     // test with some bad data ...
     "<certItems><certItem issuerName='Some nonsense in issuer'>" +
     "<serialNumber>AkHVNA==</serialNumber>" +
     "</certItem><certItem issuerName='MA0xCzAJBgNVBAMMAmNh'>" +
     "<serialNumber>some nonsense in serial</serialNumber>" +
     "</certItem><certItem issuerName='some nonsense in both issuer'>" +
     "<serialNumber>and serial</serialNumber></certItem>" +
@@ -112,20 +111,38 @@ var blocklist_contents =
     // also in the blocklist
     "<certItem issuerName='YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy'>" +
     "<serialNumber>c2VyaWFsMi4=</serialNumber>" +
     "<serialNumber>YW5vdGhlciBzZXJpYWwu</serialNumber>" +
     // This item revokes same-issuer-ee.pem by subject and pubKeyHash.
     "</certItem><certItem subject='MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5'"+
     " pubKeyHash='VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8='>" +
     "</certItem></certItems></blocklist>";
-testserver.registerPathHandler("/push_blocked_cert/",
-  function serveResponse(request, response) {
-    response.write(blocklist_contents);
-  });
+
+var updatedBlocklist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+    "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
+    "<certItems>" +
+    "<certItem issuerName='something new in both the issuer'>" +
+    "<serialNumber>and the serial number</serialNumber></certItem>" +
+    "</certItems></blocklist>"
+
+
+var blocklists = {
+  "/initialBlocklist/" : initialBlocklist,
+  "/updatedBlocklist/" : updatedBlocklist
+}
+
+function serveResponse(request, response) {
+  do_print("Serving for path " + request.path + "\n");
+  response.write(blocklists[request.path]);
+}
+
+for (path in blocklists) {
+  testserver.registerPathHandler(path, serveResponse);
+}
 
 // start the test server
 testserver.start(-1);
 var port = testserver.identity.primaryPort;
 
 // Setup the addonManager
 var addonManager = Cc["@mozilla.org/addons/integration;1"]
                      .getService(Ci.nsIObserver)
@@ -165,78 +182,118 @@ function test_is_revoked(certList, issue
                                 serial,
                                 serialString ? serialString.length : 0,
                                 subject,
                                 subjectString ? subjectString.length : 0,
                                 pubKey,
                                 pubKeyString ? pubKeyString.length : 0);
 }
 
+function fetch_blocklist(blocklistPath) {
+  do_print("path is " + blocklistPath + "\n");
+  let certblockObserver = {
+    observe: function(aSubject, aTopic, aData) {
+      Services.obs.removeObserver(this, "blocklist-updated");
+      run_next_test();
+    }
+  }
+
+  Services.obs.addObserver(certblockObserver, "blocklist-updated", false);
+  Services.prefs.setCharPref("extensions.blocklist.url",
+                              `http://localhost:${port}/${blocklistPath}`);
+  let blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
+                    .getService(Ci.nsITimerCallback);
+  blocklist.notify(null);
+}
+
+function check_revocations_txt_contents(expected) {
+  let profile = do_get_profile();
+  let revocations = profile.clone();
+  revocations.append("revocations.txt");
+  ok(revocations.exists(), "the revocations file should exist");
+  let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
+                      .createInstance(Ci.nsIFileInputStream);
+  inputStream.init(revocations,-1, -1, 0);
+  inputStream.QueryInterface(Ci.nsILineInputStream);
+  let contents = "";
+  let hasmore = false;
+  do {
+    var line = {};
+    hasmore = inputStream.readLine(line);
+    contents = contents + (contents.length == 0 ? "" : "\n") + line.value;
+  } while (hasmore);
+
+  equal(contents, expected, "revocations.txt should be as expected");
+}
+
 function run_test() {
   // import the certificates we need
   load_cert("test-ca", "CTu,CTu,CTu");
   load_cert("test-int", ",,");
   load_cert("other-test-ca", "CTu,CTu,CTu");
 
   let certList = Cc["@mozilla.org/security/certblocklist;1"]
-                   .getService(Ci.nsICertBlocklist);
+                  .getService(Ci.nsICertBlocklist);
 
-  // check some existing items in revocations.txt are blocked. Since the
-  // CertBlocklistItems don't know about the data they contain, we can use
-  // arbitrary data (not necessarily DER) to test if items are revoked or not.
-  // This test corresponds to:
-  // issuer: c29tZSBpbWFnaW5hcnkgaXNzdWVy
-  // serial: c2VyaWFsLg==
-  ok(test_is_revoked(certList, "some imaginary issuer", "serial."),
-     "issuer / serial pair should be blocked");
+  let expected = "# Auto generated contents. Do not edit.\n" +
+                 "MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5\n"+
+                 "\tVCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=\n"+
+                 "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=\n" +
+                 " BVio/iQ21GCi2iUven8oJ/gae74=\n" +
+                 "MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=\n" +
+                 " exJUIJpq50jgqOwQluhVrAzTF74=\n" +
+                 "YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy\n" +
+                 " YW5vdGhlciBzZXJpYWwu\n" +
+                 " c2VyaWFsMi4=";
 
-  // This test corresponds to:
-  // issuer: YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
-  // serial: c2VyaWFsLg==
-  ok(test_is_revoked(certList, "another imaginary issuer", "serial."),
-     "issuer / serial pair should be blocked");
+  add_test(function () {
+    // check some existing items in revocations.txt are blocked. Since the
+    // CertBlocklistItems don't know about the data they contain, we can use
+    // arbitrary data (not necessarily DER) to test if items are revoked or not.
+    // This test corresponds to:
+    // issuer: c29tZSBpbWFnaW5hcnkgaXNzdWVy
+    // serial: c2VyaWFsLg==
+    ok(test_is_revoked(certList, "some imaginary issuer", "serial."),
+      "issuer / serial pair should be blocked");
 
-  // And this test corresponds to:
-  // issuer: YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
-  // serial: c2VyaWFsMi4=
-  // (we test this issuer twice to ensure we can read multiple serials)
-  ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
-     "issuer / serial pair should be blocked");
+    // This test corresponds to:
+    // issuer: YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
+    // serial: c2VyaWFsLg==
+    ok(test_is_revoked(certList, "another imaginary issuer", "serial."),
+      "issuer / serial pair should be blocked");
+
+    // And this test corresponds to:
+    // issuer: YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
+    // serial: c2VyaWFsMi4=
+    // (we test this issuer twice to ensure we can read multiple serials)
+    ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
+      "issuer / serial pair should be blocked");
 
-  // Soon we'll load a blocklist which revokes test-int.pem, which issued
-  // test-int-ee.pem.
-  // Check the cert validates before we load the blocklist
-  let file = "test_onecrl/test-int-ee.pem";
-  verify_cert(file, PRErrorCodeSuccess);
+    // Soon we'll load a blocklist which revokes test-int.pem, which issued
+    // test-int-ee.pem.
+    // Check the cert validates before we load the blocklist
+    let file = "test_onecrl/test-int-ee.pem";
+    verify_cert(file, PRErrorCodeSuccess);
 
-  // The blocklist also revokes other-test-ca.pem, which issued other-ca-ee.pem.
-  // Check the cert validates before we load the blocklist
-  file = "bad_certs/other-issuer-ee.pem";
-  verify_cert(file, PRErrorCodeSuccess);
+    // The blocklist also revokes other-test-ca.pem, which issued
+    // other-ca-ee.pem. Check the cert validates before we load the blocklist
+    file = "bad_certs/other-issuer-ee.pem";
+    verify_cert(file, PRErrorCodeSuccess);
 
-  // The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash.
-  // Check the cert validates before we load the blocklist
-  file = "test_onecrl/same-issuer-ee.pem";
-  verify_cert(file, PRErrorCodeSuccess);
+    // The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash.
+    // Check the cert validates before we load the blocklist
+    file = "test_onecrl/same-issuer-ee.pem";
+    verify_cert(file, PRErrorCodeSuccess);
+
+    run_next_test();
+  });
 
   // blocklist load is async so we must use add_test from here
   add_test(function() {
-    let certblockObserver = {
-      observe: function(aSubject, aTopic, aData) {
-        Services.obs.removeObserver(this, "blocklist-updated");
-        run_next_test();
-      }
-    }
-
-    Services.obs.addObserver(certblockObserver, "blocklist-updated", false);
-    Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                               port + "/push_blocked_cert/");
-    let blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
-                      .getService(Ci.nsITimerCallback);
-    blocklist.notify(null);
+    fetch_blocklist("initialBlocklist/");
   });
 
   add_test(function() {
     // The blocklist will be loaded now. Let's check the data is sane.
     // In particular, we should still have the revoked issuer / serial pair
     // that was in both revocations.txt and the blocklist.xml
     ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
       "issuer / serial pair should be blocked");
@@ -250,42 +307,17 @@ function run_test() {
 
     // test a subject / pubKey revocation
     ok(test_is_revoked(certList, "nonsense", "more nonsense",
        "some imaginary subject", "some imaginary pubkey"),
        "issuer / serial pair should be blocked");
 
     // Check the blocklist entry has been persisted properly to the backing
     // file
-    let profile = do_get_profile();
-    let revocations = profile.clone();
-    revocations.append("revocations.txt");
-    ok(revocations.exists(), "the revocations file should exist");
-    let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
-                        .createInstance(Ci.nsIFileInputStream);
-    inputStream.init(revocations,-1, -1, 0);
-    inputStream.QueryInterface(Ci.nsILineInputStream);
-    let contents = "";
-    let hasmore = false;
-    do {
-      var line = {};
-      hasmore = inputStream.readLine(line);
-      contents = contents + (contents.length == 0 ? "" : "\n") + line.value;
-    } while (hasmore);
-    let expected = "# Auto generated contents. Do not edit.\n" +
-                  "MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5\n"+
-                  "\tVCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=\n"+
-                  "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=\n" +
-                  " BVio/iQ21GCi2iUven8oJ/gae74=\n" +
-                  "MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=\n" +
-                  " exJUIJpq50jgqOwQluhVrAzTF74=\n" +
-                  "YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy\n" +
-                  " YW5vdGhlciBzZXJpYWwu\n" +
-                  " c2VyaWFsMi4=";
-    equal(contents, expected, "revocations.txt should be as expected");
+    check_revocations_txt_contents(expected);
 
     // Check the blocklisted intermediate now causes a failure
     let file = "test_onecrl/test-int-ee.pem";
     verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
 
     // Check the ee with the blocklisted root also causes a failure
     file = "bad_certs/other-issuer-ee.pem";
     verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
@@ -310,11 +342,23 @@ function run_test() {
     certList.saveEntries();
     let newModified = revocations.lastModifiedTime;
     equal(lastModified, newModified,
           "saveEntries with no modifications should not update the backing file");
 
     run_next_test();
   });
 
-  // we need to start the async portions of the test
+  // disable AMO cert blocklist - and check blocklist.xml changes do not
+  // affect the data stored.
+  add_test(function() {
+    Services.prefs.setBoolPref("security.onecrl.via.amo", false);
+    fetch_blocklist("updatedBlocklist/");
+  });
+
+  add_test(function() {
+    // Check the blocklist entry has not changed
+    check_revocations_txt_contents(expected);
+    run_next_test();
+  });
+
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ev_certs.js
+++ b/security/manager/ssl/tests/unit/test_ev_certs.js
@@ -182,16 +182,35 @@ function run_test() {
     let ocspResponder = start_ocsp_responder(
                           gEVExpected ? ["int-ev-valid", "ev-valid"]
                                       : ["ev-valid"]);
     check_ee_for_ev("ev-valid", gEVExpected);
     Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
     ocspResponder.stop(run_next_test);
   });
 
+  add_test(function () {
+    // test that setting "security.onecrl.via.amo" to false will prevent
+    // OCSP skipping
+    Services.prefs.setBoolPref("security.onecrl.via.amo", false);
+    // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
+    Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds", 108000);
+    // set the blocklist-background-update-timer value to the recent past
+    Services.prefs.setIntPref("app.update.lastUpdateTime.blocklist-background-update-timer",
+                              Math.floor(Date.now() / 1000) - 1);
+    clearOCSPCache();
+    // the intermediate should have an associated OCSP request
+    let ocspResponder = start_ocsp_responder(
+                          gEVExpected ? ["int-ev-valid", "ev-valid"]
+                                      : ["ev-valid"]);
+    check_ee_for_ev("ev-valid", gEVExpected);
+    Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
+    ocspResponder.stop(run_next_test);
+  });
+
   // Test the EV continues to work with flags after successful EV verification
   add_test(function () {
     clearOCSPCache();
     let ocspResponder = start_ocsp_responder(
                           gEVExpected ? ["int-ev-valid", "ev-valid"]
                                       : ["ev-valid"]);
     check_ee_for_ev("ev-valid", gEVExpected);
     ocspResponder.stop(function () {
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -41,16 +41,17 @@ const PREF_BLOCKLIST_LASTUPDATETIME   = 
 const PREF_BLOCKLIST_URL              = "extensions.blocklist.url";
 const PREF_BLOCKLIST_ITEM_URL         = "extensions.blocklist.itemURL";
 const PREF_BLOCKLIST_ENABLED          = "extensions.blocklist.enabled";
 const PREF_BLOCKLIST_INTERVAL         = "extensions.blocklist.interval";
 const PREF_BLOCKLIST_LEVEL            = "extensions.blocklist.level";
 const PREF_BLOCKLIST_PINGCOUNTTOTAL   = "extensions.blocklist.pingCountTotal";
 const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
 const PREF_BLOCKLIST_SUPPRESSUI       = "extensions.blocklist.suppressUI";
+const PREF_ONECRL_VIA_AMO             = "security.onecrl.via.amo";
 const PREF_PLUGINS_NOTIFYUSER         = "plugins.update.notifyUser";
 const PREF_GENERAL_USERAGENT_LOCALE   = "general.useragent.locale";
 const PREF_APP_DISTRIBUTION           = "distribution.id";
 const PREF_APP_DISTRIBUTION_VERSION   = "distribution.version";
 const PREF_EM_LOGGING_ENABLED         = "extensions.logging.enabled";
 const XMLURI_BLOCKLIST                = "http://www.mozilla.org/2006/addons-blocklist";
 const XMLURI_PARSE_ERROR              = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
 const UNKNOWN_XPCOM_ABI               = "unknownABI";
@@ -885,16 +886,18 @@ Blocklist.prototype = {
       var doc = parser.parseFromString(text, "text/xml");
       if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) {
         LOG("Blocklist::_loadBlocklistFromFile: aborting due to incorrect " +
             "XML Namespace.\r\nExpected: " + XMLURI_BLOCKLIST + "\r\n" +
             "Received: " + doc.documentElement.namespaceURI);
         return;
       }
 
+      var populateCertBlocklist = getPref("getBoolPref", PREF_ONECRL_VIA_AMO, true);
+
       var childNodes = doc.documentElement.childNodes;
       for (let element of childNodes) {
         if (!(element instanceof Ci.nsIDOMElement))
           continue;
         switch (element.localName) {
         case "emItems":
           // Special case for b2g, since we don't use the addon manager.
           if (AppConstants.MOZ_B2G) {
@@ -910,26 +913,30 @@ Blocklist.prototype = {
           // We don't support plugins on b2g.
           if (AppConstants.MOZ_B2G) {
             return;
           }
           this._pluginEntries = this._processItemNodes(element.childNodes, "plugin",
                                                        this._handlePluginItemNode);
           break;
         case "certItems":
-          this._processItemNodes(element.childNodes, "cert",
-                                 this._handleCertItemNode.bind(this));
+          if (populateCertBlocklist) {
+            this._processItemNodes(element.childNodes, "cert",
+                                   this._handleCertItemNode.bind(this));
+          }
           break;
         default:
           Services.obs.notifyObservers(element,
                                        "blocklist-data-" + element.localName,
                                        null);
         }
       }
-      gCertBlocklistService.saveEntries();
+      if (populateCertBlocklist) {
+        gCertBlocklistService.saveEntries();
+      }
     }
     catch (e) {
       LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e);
       return;
     }
   },
 
   _processItemNodes: function Blocklist_processItemNodes(itemNodes, prefix, handler) {