Bug 1244816 - Override invalid H2 server certificate in the Push tests. draft
authorKit Cambridge <kcambridge@mozilla.com>
Tue, 02 Feb 2016 10:08:46 -0800
changeset 328353 1cc1d55377229d100b8c4a9ec5aad04b05e62eae
parent 328352 f0be03e1630d4f68f9f5019ad41f8e2d6495c973
child 328354 9e027af444f95b2b0ad9ccbd751ace7f1be19485
push id10356
push userkcambridge@mozilla.com
push dateWed, 03 Feb 2016 02:26:08 +0000
bugs1244816
milestone47.0a1
Bug 1244816 - Override invalid H2 server certificate in the Push tests.
dom/push/test/test_data.html
dom/push/test/test_has_permissions.html
dom/push/test/test_multiple_register.html
dom/push/test/test_multiple_register_different_scope.html
dom/push/test/test_multiple_register_during_service_activation.html
dom/push/test/test_permissions.html
dom/push/test/test_register.html
dom/push/test/test_serviceworker_lifetime.html
dom/push/test/test_try_registering_offline_disabled.html
dom/push/test/test_unregister.html
testing/specialpowers/content/SpecialPowersObserver.jsm
testing/specialpowers/content/SpecialPowersObserverAPI.js
testing/specialpowers/content/specialpowers.js
testing/specialpowers/content/specialpowersAPI.js
--- a/dom/push/test/test_data.html
+++ b/dom/push/test/test_data.html
@@ -26,16 +26,26 @@ http://creativecommons.org/licenses/publ
 <script class="testbody" type="text/javascript">
 
   SimpleTest.registerCleanupFunction(() =>
     new Promise(resolve => SpecialPowers.popPermissions(resolve))
   );
 
   var registration;
   add_task(function* start() {
+    const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                             .getService(SpecialPowers.Ci.nsIEnvironment);
+    var serverPort = env.get("MOZHTTP2_PORT");
+
+    SpecialPowers.addCertOverride("localhost", serverPort,
+      SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+      SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+      SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+    );
+
     yield new Promise(resolve => {
       SpecialPowers.pushPermissions([
         { type: "desktop-notification", allow: true, context: document },
         ], resolve);
     });
     yield new Promise(resolve => {
       SpecialPowers.pushPrefEnv({"set": [
         ["dom.push.enabled", true],
--- a/dom/push/test/test_has_permissions.html
+++ b/dom/push/test/test_has_permissions.html
@@ -60,16 +60,26 @@ http://creativecommons.org/licenses/publ
     start()
     .then(hasPermission)
     .then(unregister)
     .catch(function(e) {
       ok(false, "Some test failed with error " + e);
     }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.addPermission("desktop-notification", false, document);
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SimpleTest.waitForExplicitFinish();
--- a/dom/push/test/test_multiple_register.html
+++ b/dom/push/test/test_multiple_register.html
@@ -113,16 +113,26 @@ http://creativecommons.org/licenses/publ
     .then(getEndpoint)
     .then(unregisterPushNotification)
     .then(unregister)
     .catch(function(e) {
       ok(false, "Some test failed with error " + e);
     }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission("desktop-notification", true, document);
   SimpleTest.waitForExplicitFinish();
--- a/dom/push/test/test_multiple_register_different_scope.html
+++ b/dom/push/test/test_multiple_register_different_scope.html
@@ -108,16 +108,26 @@ http://creativecommons.org/licenses/publ
             .then(_ => unregister(swrB))
         )
     )
     .catch(err => {
       ok(false, "Some test failed with error " + err);
     }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission("desktop-notification", true, document);
   SimpleTest.waitForExplicitFinish();
--- a/dom/push/test/test_multiple_register_during_service_activation.html
+++ b/dom/push/test/test_multiple_register_during_service_activation.html
@@ -95,16 +95,26 @@ var defaultServerURL = SpecialPowers.get
         .then(sub => unsubscribe(sub))
         .then(_ => unregister(swr))
     )
     .catch(err => {
       ok(false, "Some test failed with error " + err);
     }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true],
     ["dom.push.serverURL", "wss://something.org"]
     ]}, runTest);
   SpecialPowers.addPermission("desktop-notification", true, document);
--- a/dom/push/test/test_permissions.html
+++ b/dom/push/test/test_permissions.html
@@ -25,16 +25,26 @@ http://creativecommons.org/licenses/publ
 <script class="testbody" type="text/javascript">
 
   function debug(str) {
   //  console.log(str + "\n");
   }
 
   var registration;
   add_task(function* start() {
+    const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                             .getService(SpecialPowers.Ci.nsIEnvironment);
+    var serverPort = env.get("MOZHTTP2_PORT");
+
+    SpecialPowers.addCertOverride("localhost", serverPort,
+      SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+      SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+      SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+    );
+
     SpecialPowers.addPermission("desktop-notification", false, document);
     yield new Promise(resolve => {
       SpecialPowers.pushPrefEnv({"set": [
         ["dom.push.enabled", true],
         ["dom.serviceWorkers.exemptFromPerDomainMax", true],
         ["dom.serviceWorkers.enabled", true],
         ["dom.serviceWorkers.testing.enabled", true]
         ]}, resolve);
--- a/dom/push/test/test_register.html
+++ b/dom/push/test/test_register.html
@@ -120,16 +120,26 @@ http://creativecommons.org/licenses/publ
     .then(waitForPushNotification)
     .then(unregisterPushNotification)
     .then(unregister)
     .catch(function(e) {
       ok(false, "Some test failed with error " + e);
     }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission("desktop-notification", true, document);
   SimpleTest.waitForExplicitFinish();
--- a/dom/push/test/test_serviceworker_lifetime.html
+++ b/dom/push/test/test_serviceworker_lifetime.html
@@ -315,16 +315,26 @@
       .then(subTest(test3))
       .then(unregisterPushNotification)
       .then(unregister)
       .catch(function(e) {
         ok(false, "Some test failed with error " + e)
       }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true],
     ["dom.serviceWorkers.interception.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission('desktop-notification', true, document);
--- a/dom/push/test/test_try_registering_offline_disabled.html
+++ b/dom/push/test/test_try_registering_offline_disabled.html
@@ -282,16 +282,26 @@ http://creativecommons.org/licenses/publ
     .then(_ => runTest2())
     .then(_ => runTest3())
     .then(_ => runTest4())
     .then(_ => runTest5())
     .then(_ => runTest6())
     .then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission("desktop-notification", true, document);
   SimpleTest.waitForExplicitFinish();
--- a/dom/push/test/test_unregister.html
+++ b/dom/push/test/test_unregister.html
@@ -74,16 +74,26 @@ http://creativecommons.org/licenses/publ
     .then(unregisterPushNotification)
     .then(unregisterAgain)
     .then(unregisterSW)
     .catch(function(e) {
       ok(false, "Some test failed with error " + e);
     }).then(SimpleTest.finish);
   }
 
+  const env = SpecialPowers.Cc["@mozilla.org/process/environment;1"]
+                           .getService(SpecialPowers.Ci.nsIEnvironment);
+  var serverPort = env.get("MOZHTTP2_PORT");
+
+  SpecialPowers.addCertOverride("localhost", serverPort,
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_MISMATCH |
+    SpecialPowers.Ci.nsICertOverrideService.ERROR_TIME
+  );
+
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.push.enabled", true],
     ["dom.serviceWorkers.exemptFromPerDomainMax", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
     ]}, runTest);
   SpecialPowers.addPermission("desktop-notification", true, document);
   SimpleTest.waitForExplicitFinish();
--- a/testing/specialpowers/content/SpecialPowersObserver.jsm
+++ b/testing/specialpowers/content/SpecialPowersObserver.jsm
@@ -84,16 +84,17 @@ SpecialPowersObserver.prototype._loadFra
     this._messageManager.addMessageListener("SPChromeScriptMessage", this);
     this._messageManager.addMessageListener("SPQuotaManager", this);
     this._messageManager.addMessageListener("SPSetTestPluginEnabledState", this);
     this._messageManager.addMessageListener("SPLoadExtension", this);
     this._messageManager.addMessageListener("SPStartupExtension", this);
     this._messageManager.addMessageListener("SPUnloadExtension", this);
     this._messageManager.addMessageListener("SPExtensionMessage", this);
     this._messageManager.addMessageListener("SPCleanUpSTSData", this);
+    this._messageManager.addMessageListener("SPAddCertOverride", this);
 
     this._messageManager.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
     this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
     this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
     this._isFrameScriptLoaded = true;
     this._createdFiles = null;
   }
 };
@@ -156,16 +157,17 @@ SpecialPowersObserver.prototype.uninit =
     this._messageManager.removeMessageListener("SPChromeScriptMessage", this);
     this._messageManager.removeMessageListener("SPQuotaManager", this);
     this._messageManager.removeMessageListener("SPSetTestPluginEnabledState", this);
     this._messageManager.removeMessageListener("SPLoadExtension", this);
     this._messageManager.removeMessageListener("SPStartupExtension", this);
     this._messageManager.removeMessageListener("SPUnloadExtension", this);
     this._messageManager.removeMessageListener("SPExtensionMessage", this);
     this._messageManager.removeMessageListener("SPCleanUpSTSData", this);
+    this._messageManager.removeMessageListener("SPAddCertOverride", this);
 
     this._messageManager.removeDelayedFrameScript(CHILD_LOGGER_SCRIPT);
     this._messageManager.removeDelayedFrameScript(CHILD_SCRIPT_API);
     this._messageManager.removeDelayedFrameScript(CHILD_SCRIPT);
     this._isFrameScriptLoaded = false;
   }
 };
 
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -10,16 +10,67 @@ Components.utils.import("resource://gre/
 if (typeof(Ci) == 'undefined') {
   var Ci = Components.interfaces;
 }
 
 if (typeof(Cc) == 'undefined') {
   var Cc = Components.classes;
 }
 
+// Support for making sure we can talk to the invalid cert the server presents
+var CertOverrideListener = function(host, port, bits) {
+  this.host = host;
+  this.port = port || 443;
+  this.bits = bits;
+};
+
+CertOverrideListener.prototype = {
+  host: null,
+  bits: null,
+
+  getInterface: function(aIID) {
+    return this.QueryInterface(aIID);
+  },
+
+  QueryInterface: function(aIID) {
+    if (aIID.equals(Ci.nsIBadCertListener2) ||
+        aIID.equals(Ci.nsIInterfaceRequestor) ||
+        aIID.equals(Ci.nsISupports))
+      return this;
+    throw Components.results.NS_ERROR_NO_INTERFACE;
+  },
+
+  notifyCertProblem: function(socketInfo, sslStatus, targetHost) {
+    var cert = sslStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
+    var cos = Cc["@mozilla.org/security/certoverride;1"].
+              getService(Ci.nsICertOverrideService);
+    cos.rememberValidityOverride(this.host, this.port, cert, this.bits, false);
+    dump("Certificate Override in place\n");
+    return true;
+  },
+};
+
+function addCertOverride(host, port, bits) {
+  var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+            .createInstance(Ci.nsIXMLHttpRequest);
+  try {
+    var url;
+    if (port && (port > 0) && (port !== 443)) {
+      url = "https://" + host + ":" + port + "/";
+    } else {
+      url = "https://" + host + "/";
+    }
+    req.open("GET", url, false);
+    req.channel.notificationCallbacks = new CertOverrideListener(host, port, bits);
+    req.send(null);
+  } catch (e) {
+    // This will fail since the server is not trusted yet
+  }
+}
+
 this.SpecialPowersError = function(aMsg) {
   Error.call(this);
   let {stack} = new Error();
   this.message = aMsg;
   this.name = "SpecialPowersError";
 }
 SpecialPowersError.prototype = Object.create(Error.prototype);
 
@@ -268,20 +319,20 @@ SpecialPowersObserverAPI.prototype = {
           throw new SpecialPowersError("Invalid operation for SPPrefService");
         }
 
         // Now we make the call
         switch(prefType) {
           case "BOOL":
             if (aMessage.json.op == "get")
               return(prefs.getBoolPref(prefName));
-            else 
+            else
               return(prefs.setBoolPref(prefName, prefValue));
           case "INT":
-            if (aMessage.json.op == "get") 
+            if (aMessage.json.op == "get")
               return(prefs.getIntPref(prefName));
             else
               return(prefs.setIntPref(prefName, prefValue));
           case "CHAR":
             if (aMessage.json.op == "get")
               return(prefs.getCharPref(prefName));
             else
               return(prefs.setCharPref(prefName, prefValue));
@@ -572,16 +623,22 @@ SpecialPowersObserverAPI.prototype = {
         let id = aMessage.data.id;
         let extension = this._extensions.get(id);
         this._extensions.delete(id);
         extension.shutdown();
         this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionUnloaded", args: []});
         return undefined;
       }
 
+      case "SPAddCertOverride": {
+        let {host, port, bits} = aMessage.data;
+        addCertOverride(host, port, bits);
+        return undefined;
+      }
+
       default:
         throw new SpecialPowersError("Unrecognized Special Powers API");
     }
 
     // We throw an exception before reaching this explicit return because
     // we should never be arriving here anyway.
     throw new SpecialPowersError("Unreached code");
     return undefined;
--- a/testing/specialpowers/content/specialpowers.js
+++ b/testing/specialpowers/content/specialpowers.js
@@ -30,17 +30,18 @@ function SpecialPowers(window) {
                            "SPLoadChromeScript",
                            "SPImportInMainProcess",
                            "SPObserverService",
                            "SPPermissionManager",
                            "SPPrefService",
                            "SPProcessCrashService",
                            "SPSetTestPluginEnabledState",
                            "SPWebAppService",
-                           "SPCleanUpSTSData"];
+                           "SPCleanUpSTSData",
+                           "SPAddCertOverride"];
 
   this.SP_ASYNC_MESSAGES = ["SpecialPowers.Focus",
                             "SpecialPowers.Quit",
                             "SpecialPowers.CreateFiles",
                             "SpecialPowers.RemoveFiles",
                             "SPPingService",
                             "SPLoadExtension",
                             "SPStartupExtension",
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1936,13 +1936,21 @@ SpecialPowersAPI.prototype = {
 
     this._addMessageListener("SPExtensionMessage", listener);
     return extension;
   },
 
   invalidateExtensionStorageCache: function() {
     this.notifyObserversInParentProcess(null, "extension-invalidate-storage-cache", "");
   },
+
+  addCertOverride: function(host, port, bits) {
+    this._sendSyncMessage("SPAddCertOverride", {
+      host: host,
+      port: port,
+      bits: bits,
+    });
+  },
 };
 
 this.SpecialPowersAPI = SpecialPowersAPI;
 this.bindDOMWindowUtils = bindDOMWindowUtils;
 this.getRawComponents = getRawComponents;