summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/mochitest/browser
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/tests/mochitest/browser')
-rw-r--r--security/manager/ssl/tests/mochitest/browser/.eslintrc.js5
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser.ini18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js102
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_certViewer.js224
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js32
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js135
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js137
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js215
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js150
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js119
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js142
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ca.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/mochitest/browser/code-ee.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/email-ee.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/expired-ca.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-cn.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem16
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-o.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-ou.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/head.js59
-rw-r--r--security/manager/ssl/tests/mochitest/browser/invalid.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/md5-ee.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/moz.build35
-rw-r--r--security/manager/ssl/tests/mochitest/browser/revoked.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ssl-ee.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec4
47 files changed, 1712 insertions, 0 deletions
diff --git a/security/manager/ssl/tests/mochitest/browser/.eslintrc.js b/security/manager/ssl/tests/mochitest/browser/.eslintrc.js
new file mode 100644
index 000000000..c15988365
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "extends": "../../../../../../testing/mochitest/browser.eslintrc.js"
+};
diff --git a/security/manager/ssl/tests/mochitest/browser/browser.ini b/security/manager/ssl/tests/mochitest/browser/browser.ini
new file mode 100644
index 000000000..3c91ceb80
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser.ini
@@ -0,0 +1,18 @@
+[DEFAULT]
+tags = psm
+support-files =
+ head.js
+ *.pem
+
+[browser_bug627234_perwindowpb.js]
+[browser_certificateManagerLeak.js]
+[browser_certViewer.js]
+[browser_clientAuth_connection.js]
+[browser_clientAuth_ui.js]
+[browser_deleteCert_ui.js]
+[browser_downloadCert_ui.js]
+[browser_editCACertTrust.js]
+# An earlier attempt at landing this test resulted in frequent intermittent
+# failures, almost entirely on Linux. See Bug 1309519.
+skip-if = os == "linux"
+[browser_exportP12_passwordUI.js]
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js b/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
new file mode 100644
index 000000000..081521ca9
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
@@ -0,0 +1,102 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var FakeSSLStatus = function() {
+};
+
+FakeSSLStatus.prototype = {
+ serverCert: null,
+ cipherName: null,
+ keyLength: 2048,
+ isDomainMismatch: false,
+ isNotValidAtThisTime: false,
+ isUntrusted: false,
+ isExtendedValidation: false,
+ getInterface: function(aIID) {
+ return this.QueryInterface(aIID);
+ },
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.nsISSLStatus) ||
+ aIID.equals(Ci.nsISupports)) {
+ return this;
+ }
+ throw new Error(Cr.NS_ERROR_NO_INTERFACE);
+ },
+};
+
+function whenNewWindowLoaded(aOptions, aCallback) {
+ let win = OpenBrowserWindow(aOptions);
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad, false);
+ aCallback(win);
+ }, false);
+}
+
+// This is a template to help porting global private browsing tests
+// to per-window private browsing tests
+function test() {
+ // initialization
+ waitForExplicitFinish();
+ let windowsToClose = [];
+ let testURI = "about:blank";
+ let uri;
+ let gSSService = Cc["@mozilla.org/ssservice;1"].
+ getService(Ci.nsISiteSecurityService);
+
+ function privacyFlags(aIsPrivateMode) {
+ return aIsPrivateMode ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
+ }
+
+ function doTest(aIsPrivateMode, aWindow, aCallback) {
+ aWindow.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+ aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+ let sslStatus = new FakeSSLStatus();
+ uri = aWindow.Services.io.newURI("https://localhost/img.png", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000", sslStatus, privacyFlags(aIsPrivateMode));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS, "localhost", privacyFlags(aIsPrivateMode)), "checking sts host");
+
+ aCallback();
+ }, true);
+
+ aWindow.gBrowser.selectedBrowser.loadURI(testURI);
+ }
+
+ function testOnWindow(aOptions, aCallback) {
+ whenNewWindowLoaded(aOptions, function(aWin) {
+ windowsToClose.push(aWin);
+ // execute should only be called when need, like when you are opening
+ // web pages on the test. If calling executeSoon() is not necesary, then
+ // call whenNewWindowLoaded() instead of testOnWindow() on your test.
+ executeSoon(function() { aCallback(aWin); });
+ });
+ }
+
+ // this function is called after calling finish() on the test.
+ registerCleanupFunction(function() {
+ windowsToClose.forEach(function(aWin) {
+ aWin.close();
+ });
+ uri = Services.io.newURI("http://localhost", null, null);
+ gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
+ });
+
+ // test first when on private mode
+ testOnWindow({private: true}, function(aWin) {
+ doTest(true, aWin, function() {
+ //test when not on private mode
+ testOnWindow({}, function(aWin) {
+ doTest(false, aWin, function() {
+ //test again when on private mode
+ testOnWindow({private: true}, function(aWin) {
+ doTest(true, aWin, function () {
+ finish();
+ });
+ });
+ });
+ });
+ });
+ });
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js b/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js
new file mode 100644
index 000000000..d75f9f207
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js
@@ -0,0 +1,224 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Repeatedly opens the certificate viewer dialog with various certificates and
+// determines that the viewer correctly identifies either what usages those
+// certificates are valid for or what errors prevented the certificates from
+// being verified.
+
+var { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
+
+add_task(function* testCAandTitle() {
+ let cert = yield readCertificate("ca.pem", "CTu,CTu,CTu");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["SSL Certificate Authority"]);
+
+ // There's no real need to test the title for every cert, so we just test it
+ // once here.
+ Assert.equal(win.document.title, "Certificate Viewer: \u201Cca\u201D",
+ "Actual and expected title should match");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testSSLEndEntity() {
+ let cert = yield readCertificate("ssl-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["SSL Server Certificate", "SSL Client Certificate"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testEmailEndEntity() {
+ let cert = yield readCertificate("email-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["Email Recipient Certificate", "Email Signer Certificate"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testCodeSignEndEntity() {
+ let cert = yield readCertificate("code-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["Object Signer"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testExpired() {
+ let cert = yield readCertificate("expired-ca.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win, "Could not verify this certificate because it has expired.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testIssuerExpired() {
+ let cert = yield readCertificate("ee-from-expired-ca.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because the CA certificate " +
+ "is invalid.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testUnknownIssuer() {
+ let cert = yield readCertificate("unknown-issuer.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because the issuer is " +
+ "unknown.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testInsecureAlgo() {
+ let cert = yield readCertificate("md5-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because it was signed using " +
+ "a signature algorithm that was disabled because that algorithm " +
+ "is not secure.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testUntrusted() {
+ let cert = yield readCertificate("untrusted-ca.pem", "p,p,p");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because it is not trusted.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testUntrustedIssuer() {
+ let cert = yield readCertificate("ee-from-untrusted-ca.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because the issuer is not " +
+ "trusted.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testRevoked() {
+ // Note that there's currently no way to un-do this. This should only be a
+ // problem if another test re-uses a certificate with this same key (perhaps
+ // likely) and subject (less likely).
+ let certBlocklist = Cc["@mozilla.org/security/certblocklist;1"]
+ .getService(Ci.nsICertBlocklist);
+ certBlocklist.revokeCertBySubjectAndPubKey(
+ "MBIxEDAOBgNVBAMMB3Jldm9rZWQ=", // CN=revoked
+ "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8="); // hash of the shared key
+ let cert = yield readCertificate("revoked.pem", ",,");
+ let win = yield displayCertificate(cert);
+ // As of bug 1312827, OneCRL only applies to TLS web server certificates, so
+ // this certificate will actually verify successfully for every end-entity
+ // usage except TLS web server.
+ checkUsages(win, ["Email Recipient Certificate", "Email Signer Certificate",
+ "Object Signer", "SSL Client Certificate"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testInvalid() {
+ // This certificate has a keyUsage extension asserting cRLSign and
+ // keyCertSign, but it doesn't have a basicConstraints extension. This
+ // shouldn't be valid for any usage. Sadly, we give a pretty lame error
+ // message in this case.
+ let cert = yield readCertificate("invalid.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win, "Could not verify this certificate for unknown reasons.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+/**
+ * Given a certificate, returns a promise that will resolve when the certificate
+ * viewer has opened is displaying that certificate, and has finished
+ * determining its valid usages.
+ *
+ * @param {nsIX509Cert} certificate
+ * The certificate to view and determine usages for.
+ * @return {Promise}
+ * A promise that will resolve with a handle on the opened certificate
+ * viewer window when the usages have been determined.
+ */
+function displayCertificate(certificate) {
+ let win = window.openDialog("chrome://pippki/content/certViewer.xul", "",
+ "", certificate);
+ return TestUtils.topicObserved("ViewCertDetails:CertUsagesDone",
+ (subject, data) => subject == win)
+ .then(([subject, data]) => subject, error => { throw error; });
+}
+
+/**
+ * Given a certificate viewer window, finds the usages the certificate is valid
+ * for.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @return {String[]}
+ * An array of strings describing the usages the certificate is valid
+ * for.
+ */
+function getUsages(win) {
+ let determinedUsages = [];
+ let verifyInfoBox = win.document.getElementById("verify_info_box");
+ Array.from(verifyInfoBox.children).forEach(child => {
+ if (child.getAttribute("hidden") != "true" &&
+ child.getAttribute("id") != "verified") {
+ determinedUsages.push(child.getAttribute("value"));
+ }
+ });
+ return determinedUsages.sort();
+}
+
+/**
+ * Given a certificate viewer window, returns the error string describing a
+ * failure encountered when determining the certificate's usages. It will be
+ * "This certificate has been verified for the following uses:" when the
+ * certificate has successfully verified for at least one usage.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @return {String}
+ * A string describing the error encountered, or the success message if
+ * the certificate is valid for at least one usage.
+ */
+function getError(win) {
+ return win.document.getElementById("verified").textContent;
+}
+
+/**
+ * Given a certificate viewer window and an array of expected usage
+ * descriptions, verifies that the window is actually showing that the
+ * certificate has validated for those usages.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @param {String[]} usages
+ * An array of expected usage descriptions.
+ */
+function checkUsages(win, usages) {
+ Assert.equal(getError(win),
+ "This certificate has been verified for the following uses:",
+ "should have successful verification message");
+ let determinedUsages = getUsages(win);
+ usages.sort();
+ Assert.equal(determinedUsages.length, usages.length,
+ "number of usages as determined by cert viewer should be equal");
+ while (usages.length > 0) {
+ Assert.equal(determinedUsages.pop(), usages.pop(),
+ "usages as determined by cert viewer should be equal");
+ }
+}
+
+/**
+ * Given a certificate viewer window and an expected error, verifies that the
+ * window is actually showing that error.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @param {String} error
+ * The expected error message.
+ */
+function checkError(win, error) {
+ let determinedUsages = getUsages(win);
+ Assert.equal(determinedUsages.length, 0,
+ "should not have any successful usages in error case");
+ Assert.equal(getError(win), error,
+ "determined error should be the same as expected error");
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js b/security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js
new file mode 100644
index 000000000..d1db319d0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js
@@ -0,0 +1,32 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var gBugWindow;
+
+function onLoad() {
+ gBugWindow.removeEventListener("load", onLoad);
+ gBugWindow.addEventListener("unload", onUnload);
+ gBugWindow.close();
+}
+
+function onUnload() {
+ gBugWindow.removeEventListener("unload", onUnload);
+ window.focus();
+ finish();
+}
+
+// This test opens and then closes the certificate manager to test that it
+// does not leak. The test harness keeps track of and reports leaks, so
+// there are no actual checks here.
+function test() {
+ waitForExplicitFinish();
+
+ // This test relies on the test timing out in order to indicate failure so
+ // let's add a dummy pass.
+ ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
+
+ gBugWindow = window.openDialog("chrome://pippki/content/certManager.xul");
+ gBugWindow.addEventListener("load", onLoad);
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js
new file mode 100644
index 000000000..6362fd34d
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js
@@ -0,0 +1,135 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests various scenarios connecting to a server that requires client cert
+// authentication. Also tests that nsIClientAuthDialogs.chooseCertificate
+// is called at the appropriate times and with the correct arguments.
+
+const { MockRegistrar } =
+ Cu.import("resource://testing-common/MockRegistrar.jsm", {});
+
+const DialogState = {
+ // Assert that chooseCertificate() is never called.
+ ASSERT_NOT_CALLED: "ASSERT_NOT_CALLED",
+ // Return that the user selected the first given cert.
+ RETURN_CERT_SELECTED: "RETURN_CERT_SELECTED",
+ // Return that the user canceled.
+ RETURN_CERT_NOT_SELECTED: "RETURN_CERT_NOT_SELECTED",
+};
+
+let sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing);
+
+// Mock implementation of nsIClientAuthDialogs.
+const gClientAuthDialogs = {
+ _state: DialogState.ASSERT_NOT_CALLED,
+
+ set state(newState) {
+ info(`old state: ${this._state}`);
+ this._state = newState;
+ info(`new state: ${this._state}`);
+ },
+
+ get state() {
+ return this._state;
+ },
+
+ chooseCertificate(ctx, hostname, port, organization, issuerOrg, certList,
+ selectedIndex) {
+ Assert.notEqual(this.state, DialogState.ASSERT_NOT_CALLED,
+ "chooseCertificate() should be called only when expected");
+
+ let caud = ctx.QueryInterface(Ci.nsIClientAuthUserDecision);
+ Assert.notEqual(caud, null,
+ "nsIClientAuthUserDecision should be queryable from the " +
+ "given context");
+ caud.rememberClientAuthCertificate = false;
+
+ Assert.equal(hostname, "requireclientcert.example.com",
+ "Hostname should be 'requireclientcert.example.com'");
+ Assert.equal(port, 443, "Port should be 443");
+ Assert.equal(organization, "",
+ "Server cert Organization should be empty/not present");
+ Assert.equal(issuerOrg, "Mozilla Testing",
+ "Server cert issuer Organization should be 'Mozilla Testing'");
+
+ // For mochitests, only the cert at build/pgo/certs/mochitest.client should
+ // be selectable, so we do some brief checks to confirm this.
+ Assert.notEqual(certList, null, "Cert list should not be null");
+ Assert.equal(certList.length, 1, "Only 1 certificate should be available");
+ let cert = certList.queryElementAt(0, Ci.nsIX509Cert);
+ Assert.notEqual(cert, null, "Cert list should contain an nsIX509Cert");
+ Assert.equal(cert.commonName, "Mochitest client",
+ "Cert CN should be 'Mochitest client'");
+
+ if (this.state == DialogState.RETURN_CERT_SELECTED) {
+ selectedIndex.value = 0;
+ return true;
+ }
+ return false;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIClientAuthDialogs])
+};
+
+add_task(function* setup() {
+ let clientAuthDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsClientAuthDialogs;1",
+ gClientAuthDialogs);
+ registerCleanupFunction(() => {
+ MockRegistrar.unregister(clientAuthDialogsCID);
+ });
+});
+
+/**
+ * Test helper for the tests below.
+ *
+ * @param {String} prefValue
+ * Value to set the "security.default_personal_cert" pref to.
+ * @param {String} expectedURL
+ * If the connection is expected to load successfully, the URL that
+ * should load. If the connection is expected to fail and result in an
+ * error page, |undefined|.
+ */
+function* testHelper(prefValue, expectedURL) {
+ yield SpecialPowers.pushPrefEnv({"set": [
+ ["security.default_personal_cert", prefValue],
+ ]});
+
+ yield BrowserTestUtils.loadURI(gBrowser.selectedBrowser,
+ "https://requireclientcert.example.com:443");
+
+ // |loadedURL| will be a string URL if browserLoaded() wins the race, or
+ // |undefined| if waitForErrorPage() wins the race.
+ let loadedURL = yield Promise.race([
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser),
+ BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser),
+ ]);
+ Assert.equal(expectedURL, loadedURL, "Expected and actual URLs should match");
+
+ // Ensure previously successful connections don't influence future tests.
+ sdr.logoutAndTeardown();
+}
+
+// Test that if a certificate is chosen automatically the connection succeeds,
+// and that nsIClientAuthDialogs.chooseCertificate() is never called.
+add_task(function* testCertChosenAutomatically() {
+ gClientAuthDialogs.state = DialogState.ASSERT_NOT_CALLED;
+ yield* testHelper("Select Automatically",
+ "https://requireclientcert.example.com/");
+});
+
+// Test that if the user doesn't choose a certificate, the connection fails and
+// an error page is displayed.
+add_task(function* testCertNotChosenByUser() {
+ gClientAuthDialogs.state = DialogState.RETURN_CERT_NOT_SELECTED;
+ yield* testHelper("Ask Every Time", undefined);
+});
+
+// Test that if the user chooses a certificate the connection suceeeds.
+add_task(function* testCertChosenByUser() {
+ gClientAuthDialogs.state = DialogState.RETURN_CERT_SELECTED;
+ yield* testHelper("Ask Every Time",
+ "https://requireclientcert.example.com/");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js
new file mode 100644
index 000000000..bf4f179c0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js
@@ -0,0 +1,137 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the client authentication certificate chooser correctly displays
+// provided information and correctly returns user input.
+
+const TEST_HOSTNAME = "Test Hostname";
+const TEST_ORG = "Test Org";
+const TEST_ISSUER_ORG = "Test Issuer Org";
+const TEST_PORT = 123;
+
+var certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+/**
+ * Test certificate (i.e. build/pgo/certs/mochitest.client).
+ * @type nsIX509Cert
+ */
+var cert;
+
+/**
+ * Opens the client auth cert chooser dialog.
+ *
+ * @param {nsIX509Cert} cert The cert to pass to the dialog for display.
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value nsIWritablePropertyBag2 passed to the dialog.
+ */
+function openClientAuthDialog(cert) {
+ let certList = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+ certList.appendElement(cert, false);
+
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
+ .createInstance(Ci.nsIWritablePropertyBag2);
+ let win = window.openDialog("chrome://pippki/content/clientauthask.xul", "",
+ "", TEST_HOSTNAME, TEST_ORG, TEST_ISSUER_ORG,
+ TEST_PORT, certList, returnVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, returnVals]);
+ });
+ });
+}
+
+/**
+ * Checks that the contents of the given cert chooser dialog match the details
+ * of build/pgo/certs/mochitest.client.
+ *
+ * @param {window} win The cert chooser window.
+ * @param {String} notBefore
+ * The notBeforeLocalTime attribute of mochitest.client.
+ * @param {String} notAfter
+ * The notAfterLocalTime attribute of mochitest.client.
+ */
+function checkDialogContents(win, notBefore, notAfter) {
+ Assert.equal(win.document.getElementById("hostname").textContent,
+ `${TEST_HOSTNAME}:${TEST_PORT}`,
+ "Actual and expected hostname and port should be equal");
+ // “ and ” don't seem to work when embedded in the following literals, which
+ // is why escape codes are used instead.
+ Assert.equal(win.document.getElementById("organization").textContent,
+ `Organization: \u201C${TEST_ORG}\u201D`,
+ "Actual and expected organization should be equal");
+ Assert.equal(win.document.getElementById("issuer").textContent,
+ `Issued Under: \u201C${TEST_ISSUER_ORG}\u201D`,
+ "Actual and expected issuer organization should be equal");
+
+ Assert.equal(win.document.getElementById("nicknames").label,
+ "test client certificate [03]",
+ "Actual and expected selected cert nickname and serial should " +
+ "be equal");
+
+ let [subject, serialNum, validity, issuer, tokenName] =
+ win.document.getElementById("details").value.split("\n");
+ Assert.equal(subject, "Issued to: CN=Mochitest client",
+ "Actual and expected subject should be equal");
+ Assert.equal(serialNum, "Serial number: 03",
+ "Actual and expected serial number should be equal");
+ Assert.equal(validity, `Valid from ${notBefore} to ${notAfter}`,
+ "Actual and expected validity should be equal");
+ Assert.equal(issuer,
+ "Issued by: CN=Temporary Certificate Authority,O=Mozilla " +
+ "Testing,OU=Profile Guided Optimization",
+ "Actual and expected issuer should be equal");
+ Assert.equal(tokenName, "Stored on: Software Security Device",
+ "Actual and expected token name should be equal");
+}
+
+add_task(function* setup() {
+ cert = certDB.findCertByNickname("test client certificate");
+ Assert.notEqual(cert, null, "Should be able to find the test client cert");
+});
+
+// Test that the contents of the dialog correspond to the details of the
+// provided cert.
+add_task(function* testContents() {
+ let [win, retVals] = yield openClientAuthDialog(cert);
+ checkDialogContents(win, cert.validity.notBeforeLocalTime,
+ cert.validity.notAfterLocalTime);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openClientAuthDialog(cert);
+ win.document.getElementById("rememberBox").checked = true;
+ info("Accepting dialog");
+ win.document.getElementById("certAuthAsk").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.get("certChosen"),
+ "Return value should signal user chose a certificate");
+ Assert.equal(retVals.get("selectedIndex"), 0,
+ "0 should be returned as the selected index");
+ Assert.ok(retVals.get("rememberSelection"),
+ "Return value should signal 'Remember this decision' checkbox was" +
+ "checked");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openClientAuthDialog(cert);
+ win.document.getElementById("rememberBox").checked = false;
+ info("Canceling dialog");
+ win.document.getElementById("certAuthAsk").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.get("certChosen"),
+ "Return value should signal user did not choose a certificate");
+ Assert.ok(!retVals.get("rememberSelection"),
+ "Return value should signal 'Remember this decision' checkbox was" +
+ "unchecked");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
new file mode 100644
index 000000000..b0ac8f95c
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
@@ -0,0 +1,215 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests various aspects of the cert delete confirmation dialog.
+// Among other things, tests that for each type of cert that can be deleted:
+// 1. The various lines of explanation text are correctly set.
+// 2. The implementation correctly falls back through multiple cert attributes
+// to determine what to display to represent a cert.
+
+/**
+ * An array of tree items corresponding to TEST_CASES.
+ * @type nsICertTreeItem[]
+ */
+var gCertArray = [];
+
+const FAKE_HOST_PORT = "Fake host and port";
+
+/**
+ * @typedef {TestCase}
+ * @type Object
+ * @property {String} certFilename
+ * Filename of the cert, or null if we don't want to import a cert for
+ * this test case (i.e. we expect the hostPort attribute of
+ * nsICertTreeItem to be used).
+ * @property {String} expectedDisplayString
+ * The string we expect the UI to display to represent the given cert.
+ */
+
+/**
+ * A list of test cases representing certs that get "deleted".
+ * @type TestCase[]
+ */
+const TEST_CASES = [
+ { certFilename: null,
+ expectedDisplayString: FAKE_HOST_PORT },
+ { certFilename: "has-cn.pem",
+ expectedDisplayString: "Foo" },
+ { certFilename: "has-ou.pem",
+ expectedDisplayString: "Bar" },
+ { certFilename: "has-o.pem",
+ expectedDisplayString: "Baz" },
+ { certFilename: "has-non-empty-subject.pem",
+ expectedDisplayString: "C=US" },
+ { certFilename: "has-empty-subject.pem",
+ expectedDisplayString: "Certificate with serial number: 0A" },
+];
+
+/**
+ * Opens the cert delete confirmation dialog.
+ *
+ * @param {String} tabID
+ * The ID of the cert category tab the certs to delete belong to.
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value object passed to the dialog.
+ */
+function openDeleteCertConfirmDialog(tabID) {
+ let retVals = {
+ deleteConfirmed: false,
+ };
+ let win = window.openDialog("chrome://pippki/content/deletecert.xul", "", "",
+ tabID, gCertArray, retVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, retVals]);
+ });
+ });
+}
+
+add_task(function* setup() {
+ for (let testCase of TEST_CASES) {
+ let cert = null;
+ if (testCase.certFilename) {
+ cert = yield readCertificate(testCase.certFilename, ",,");
+ }
+ let certTreeItem = {
+ hostPort: FAKE_HOST_PORT,
+ cert: cert,
+ QueryInterface(iid) {
+ if (iid.equals(Ci.nsICertTreeItem)) {
+ return this;
+ }
+
+ throw new Error(Cr.NS_ERROR_NO_INTERFACE);
+ }
+ };
+ gCertArray.push(certTreeItem);
+ }
+});
+
+/**
+ * Test helper for the below test cases.
+ *
+ * @param {String} tabID
+ * ID of the cert category tab the certs to delete belong to.
+ * @param {String} expectedTitle
+ * Title the dialog is expected to have.
+ * @param {String} expectedConfirmMsg
+ * Confirmation message the dialog is expected to show.
+ * @param {String} expectedImpact
+ * Impact the dialog is expected to show.
+ */
+function* testHelper(tabID, expectedTitle, expectedConfirmMsg, expectedImpact) {
+ let [win, retVals] = yield openDeleteCertConfirmDialog(tabID);
+ let certList = win.document.getElementById("certlist");
+
+ Assert.equal(win.document.title, expectedTitle,
+ `Actual and expected titles should match for ${tabID}`);
+ Assert.equal(win.document.getElementById("confirm").textContent,
+ expectedConfirmMsg,
+ `Actual and expected confirm message should match for ${tabID}`);
+ Assert.equal(win.document.getElementById("impact").textContent,
+ expectedImpact,
+ `Actual and expected impact should match for ${tabID}`);
+
+ Assert.equal(certList.itemCount, TEST_CASES.length,
+ `No. of certs displayed should match for ${tabID}`);
+ for (let i = 0; i < certList.itemCount; i++) {
+ Assert.equal(certList.getItemAtIndex(i).label,
+ TEST_CASES[i].expectedDisplayString,
+ "Actual and expected display string should match for " +
+ `index ${i} for ${tabID}`);
+ }
+
+ yield BrowserTestUtils.closeWindow(win);
+}
+
+// Test deleting certs from the "Your Certificates" tab.
+add_task(function* testDeletePersonalCerts() {
+ const expectedTitle = "Delete your Certificates";
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these certificates?";
+ const expectedImpact =
+ "If you delete one of your own certificates, you can no longer use it to " +
+ "identify yourself.";
+ yield* testHelper("mine_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "People" tab.
+add_task(function* testDeleteOtherPeopleCerts() {
+ const expectedTitle = "Delete E-Mail Certificates";
+ // ’ doesn't seem to work when embedded in the following literals, which is
+ // why escape codes are used instead.
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these people\u2019s e-mail certificates?";
+ const expectedImpact =
+ "If you delete a person\u2019s e-mail certificate, you will no longer be " +
+ "able to send encrypted e-mail to that person.";
+ yield* testHelper("others_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "Servers" tab.
+add_task(function* testDeleteServerCerts() {
+ const expectedTitle = "Delete Server Certificate Exceptions";
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these server exceptions?";
+ const expectedImpact =
+ "If you delete a server exception, you restore the usual security checks " +
+ "for that server and require it uses a valid certificate.";
+ yield* testHelper("websites_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "Authorities" tab.
+add_task(function* testDeleteCACerts() {
+ const expectedTitle = "Delete or Distrust CA Certificates";
+ const expectedConfirmMsg =
+ "You have requested to delete these CA certificates. For built-in " +
+ "certificates all trust will be removed, which has the same effect. Are " +
+ "you sure you want to delete or distrust?";
+ const expectedImpact =
+ "If you delete or distrust a certificate authority (CA) certificate, " +
+ "this application will no longer trust any certificates issued by that CA.";
+ yield* testHelper("ca_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "Other" tab.
+add_task(function* testDeleteOtherCerts() {
+ const expectedTitle = "Delete Certificates";
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these certificates?";
+ const expectedImpact = "";
+ yield* testHelper("orphan_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openDeleteCertConfirmDialog("ca_tab" /*arbitrary*/);
+ info("Accepting dialog");
+ win.document.getElementById("deleteCertificate").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.deleteConfirmed,
+ "Return value should signal user accepted");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openDeleteCertConfirmDialog("ca_tab" /*arbitrary*/);
+ info("Canceling dialog");
+ win.document.getElementById("deleteCertificate").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.deleteConfirmed,
+ "Return value should signal user did not accept");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js
new file mode 100644
index 000000000..cbd59f883
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js
@@ -0,0 +1,150 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the cert download/import UI correctly identifies the cert being
+// downloaded, and allows the trust of the cert to be specified.
+
+const { MockRegistrar } =
+ Cu.import("resource://testing-common/MockRegistrar.jsm", {});
+
+/**
+ * @typedef {TestCase}
+ * @type Object
+ * @property {String} certFilename
+ * Filename of the cert for this test case.
+ * @property {String} expectedDisplayString
+ * The string we expect the UI to display to represent the given cert.
+ * @property {nsIX509Cert} cert
+ * Handle to the cert once read in setup().
+ */
+
+/**
+ * A list of test cases representing certs that get "downloaded".
+ * @type TestCase[]
+ */
+const TEST_CASES = [
+ { certFilename: "has-cn.pem",
+ expectedDisplayString: "Foo",
+ cert: null },
+ { certFilename: "has-empty-subject.pem",
+ expectedDisplayString: "Certificate Authority (unnamed)",
+ cert: null },
+];
+
+/**
+ * Opens the cert download dialog.
+ *
+ * @param {nsIX509Cert} cert
+ * The cert to pass to the dialog for display.
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value nsIWritablePropertyBag2 passed to the dialog.
+ */
+function openCertDownloadDialog(cert) {
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
+ .createInstance(Ci.nsIWritablePropertyBag2);
+ let win = window.openDialog("chrome://pippki/content/downloadcert.xul", "",
+ "", cert, returnVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, returnVals]);
+ });
+ });
+}
+
+// Mock implementation of nsICertificateDialogs.
+const gCertificateDialogs = {
+ expectedCert: null,
+ viewCertCallCount: 0,
+ confirmDownloadCACert(ctx, cert, trust) {
+ Assert.ok(false, "confirmDownloadCACert() should not have been called");
+ },
+ setPKCS12FilePassword(ctx, password) {
+ Assert.ok(false, "setPKCS12FilePassword() should not have been called");
+ },
+ getPKCS12FilePassword(ctx, password) {
+ Assert.ok(false, "getPKCS12FilePassword() should not have been called");
+ },
+ viewCert(ctx, cert) {
+ this.viewCertCallCount++;
+ Assert.notEqual(cert, null, "Cert to view should not be null");
+ Assert.equal(cert, this.expectedCert,
+ "Actual and expected cert should match");
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs])
+};
+
+add_task(function* setup() {
+ for (let testCase of TEST_CASES) {
+ testCase.cert = yield readCertificate(testCase.certFilename, ",,");
+ Assert.notEqual(testCase.cert, null,
+ `'${testCase.certFilename}' should have been read`);
+ }
+
+ let certificateDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
+ gCertificateDialogs);
+ registerCleanupFunction(() => {
+ MockRegistrar.unregister(certificateDialogsCID);
+ });
+});
+
+// Test that the trust header message corresponds to the provided cert, and that
+// the View Cert button launches the cert viewer for the provided cert.
+add_task(function* testTrustHeaderAndViewCertButton() {
+ for (let testCase of TEST_CASES) {
+ let [win, retVals] = yield openCertDownloadDialog(testCase.cert);
+ let expectedTrustHeaderString =
+ `Do you want to trust \u201C${testCase.expectedDisplayString}\u201D ` +
+ "for the following purposes?";
+ Assert.equal(win.document.getElementById("trustHeader").textContent,
+ expectedTrustHeaderString,
+ "Actual and expected trust header text should match for " +
+ `${testCase.certFilename}`);
+
+ gCertificateDialogs.viewCertCallCount = 0;
+ gCertificateDialogs.expectedCert = testCase.cert;
+ info("Pressing View Cert button");
+ win.document.getElementById("viewC-button").doCommand();
+ Assert.equal(gCertificateDialogs.viewCertCallCount, 1,
+ "viewCert() should've been called once");
+
+ yield BrowserTestUtils.closeWindow(win);
+ }
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openCertDownloadDialog(TEST_CASES[0].cert);
+ win.document.getElementById("trustSSL").checked = true;
+ win.document.getElementById("trustEmail").checked = false;
+ win.document.getElementById("trustObjSign").checked = true;
+ info("Accepting dialog");
+ win.document.getElementById("download_cert").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.get("importConfirmed"),
+ "Return value should signal user chose to import the cert");
+ Assert.ok(retVals.get("trustForSSL"),
+ "Return value should signal SSL trust checkbox was checked");
+ Assert.ok(!retVals.get("trustForEmail"),
+ "Return value should signal E-mail trust checkbox was unchecked");
+ Assert.ok(retVals.get("trustForObjSign"),
+ "Return value should signal Obj Sign trust checkbox was checked");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openCertDownloadDialog(TEST_CASES[0].cert);
+ info("Canceling dialog");
+ win.document.getElementById("download_cert").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.get("importConfirmed"),
+ "Return value should signal user chose not to import the cert");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js b/security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js
new file mode 100644
index 000000000..bc87732a5
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js
@@ -0,0 +1,119 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the UI for editing the trust of a CA certificate correctly
+// reflects trust in the cert DB, and correctly updates trust in the cert DB
+// when requested.
+
+var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+/**
+ * The cert we're editing the trust of.
+ * @type nsIX509Cert
+ */
+var gCert;
+
+/**
+ * Opens the cert trust editing dialog.
+ *
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading with
+ * the window of the opened dialog.
+ */
+function openEditCertTrustDialog() {
+ let win = window.openDialog("chrome://pippki/content/editcacert.xul", "", "",
+ gCert);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve(win);
+ });
+ });
+}
+
+add_task(function* setup() {
+ // Initially trust ca.pem for SSL, but not e-mail or object signing.
+ gCert = yield readCertificate("ca.pem", "CT,,");
+ Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "Sanity check: ca.pem should be trusted for SSL");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "Sanity check: ca.pem should not be trusted for e-mail");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN),
+ "Sanity check: ca.pem should not be trusted for object signing");
+});
+
+// Tests the following:
+// 1. The checkboxes correctly reflect the trust set in setup().
+// 2. Accepting the dialog after flipping some of the checkboxes results in the
+// correct trust being set in the cert DB.
+add_task(function* testAcceptDialog() {
+ let win = yield openEditCertTrustDialog();
+
+ let sslCheckbox = win.document.getElementById("trustSSL");
+ let emailCheckbox = win.document.getElementById("trustEmail");
+ let objSignCheckbox = win.document.getElementById("trustObjSign");
+ Assert.ok(sslCheckbox.checked,
+ "Cert should be trusted for SSL in UI");
+ Assert.ok(!emailCheckbox.checked,
+ "Cert should not be trusted for e-mail in UI");
+ Assert.ok(!objSignCheckbox.checked,
+ "Cert should not be trusted for object signing in UI");
+
+ sslCheckbox.checked = false;
+ emailCheckbox.checked = true;
+
+ info("Accepting dialog");
+ win.document.getElementById("editCaCert").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "Cert should no longer be trusted for SSL");
+ Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "Cert should now be trusted for e-mail");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN),
+ "Cert should still not be trusted for object signing");
+});
+
+// Tests the following:
+// 1. The checkboxes correctly reflect the trust set in testAcceptDialog().
+// 2. Canceling the dialog even after flipping the checkboxes doesn't result in
+// a change of trust in the cert DB.
+add_task(function* testCancelDialog() {
+ let win = yield openEditCertTrustDialog();
+
+ let sslCheckbox = win.document.getElementById("trustSSL");
+ let emailCheckbox = win.document.getElementById("trustEmail");
+ let objSignCheckbox = win.document.getElementById("trustObjSign");
+ Assert.ok(!sslCheckbox.checked,
+ "Cert should not be trusted for SSL in UI");
+ Assert.ok(emailCheckbox.checked,
+ "Cert should be trusted for e-mail in UI");
+ Assert.ok(!objSignCheckbox.checked,
+ "Cert should not be trusted for object signing in UI");
+
+ sslCheckbox.checked = true;
+ emailCheckbox.checked = false;
+ objSignCheckbox.checked = true;
+
+ info("Canceling dialog");
+ win.document.getElementById("editCaCert").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "Cert should still not be trusted for SSL");
+ Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "Cert should still be trusted for e-mail");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN),
+ "Cert should still not be trusted for object signing");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js b/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js
new file mode 100644
index 000000000..fc7591ece
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js
@@ -0,0 +1,142 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the UI for setting the password on a to be exported PKCS #12 file:
+// 1. Correctly requires the password to be typed in twice as confirmation.
+// 2. Calculates and displays the strength of said password.
+
+/**
+ * @typedef {TestCase}
+ * @type Object
+ * @property {String} name
+ * The name of the test case for display purposes.
+ * @property {String} password1
+ * The password to enter into the first password textbox.
+ * @property {String} password2
+ * The password to enter into the second password textbox.
+ * @property {String} strength
+ * The expected strength of the password in the range [0, 100].
+ */
+
+/**
+ * A list of test cases representing various inputs to the password textboxes.
+ * @type TestCase[]
+ */
+const TEST_CASES = [
+ { name: "empty",
+ password1: "",
+ password2: "",
+ strength: "0" },
+ { name: "match-weak",
+ password1: "foo",
+ password2: "foo",
+ strength: "10" },
+ { name: "match-medium",
+ password1: "foo123",
+ password2: "foo123",
+ strength: "60" },
+ { name: "match-strong",
+ password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
+ password2: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
+ strength: "100" },
+ { name: "mismatch-weak",
+ password1: "foo",
+ password2: "bar",
+ strength: "10" },
+ { name: "mismatch-medium",
+ password1: "foo123",
+ password2: "bar",
+ strength: "60" },
+ { name: "mismatch-strong",
+ password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
+ password2: "bar",
+ strength: "100" },
+];
+
+/**
+ * Opens the dialog shown to set the password on a PKCS #12 file being exported.
+ *
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value nsIWritablePropertyBag2 passed to the dialog.
+ */
+function openSetP12PasswordDialog() {
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
+ .createInstance(Ci.nsIWritablePropertyBag2);
+ let win = window.openDialog("chrome://pippki/content/setp12password.xul", "",
+ "", returnVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, returnVals]);
+ });
+ });
+}
+
+// Tests that the first password textbox is the element that is initially
+// focused.
+add_task(function* testFocus() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ Assert.equal(win.document.activeElement,
+ win.document.getElementById("pw1").inputField,
+ "First password textbox should have focus");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+// Tests that the password strength algorithm used is reasonable, and that the
+// Accept button is only enabled if the two passwords match.
+add_task(function* testPasswordStrengthAndEquality() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ let password1Textbox = win.document.getElementById("pw1");
+ let password2Textbox = win.document.getElementById("pw2");
+ let strengthProgressBar = win.document.getElementById("pwmeter");
+
+ for (let testCase of TEST_CASES) {
+ password1Textbox.value = testCase.password1;
+ password2Textbox.value = testCase.password2;
+ // Setting the value of the password textboxes via |.value| apparently
+ // doesn't cause the oninput handlers to be called, so we do it here.
+ password1Textbox.oninput();
+ password2Textbox.oninput();
+
+ Assert.equal(win.document.documentElement.getButton("accept").disabled,
+ password1Textbox.value != password2Textbox.value,
+ "Actual and expected accept button disable state should " +
+ `match for ${testCase.name}`);
+ Assert.equal(strengthProgressBar.value, testCase.strength,
+ "Actual and expected strength value should match for" +
+ `${testCase.name}`);
+ }
+
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ const password = "fooBAR 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三";
+ win.document.getElementById("pw1").value = password;
+ win.document.getElementById("pw2").value = password;
+ info("Accepting dialog");
+ win.document.getElementById("setp12password").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.get("confirmedPassword"),
+ "Return value should signal user confirmed a password");
+ Assert.equal(retVals.get("password"), password,
+ "Actual and expected password should match");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ info("Canceling dialog");
+ win.document.getElementById("setp12password").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.get("confirmedPassword"),
+ "Return value should signal user didn't confirm a password");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/ca.pem b/security/manager/ssl/tests/mochitest/browser/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ca.pem.certspec
new file mode 100644
index 000000000..6660f5d47
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/mochitest/browser/code-ee.pem b/security/manager/ssl/tests/mochitest/browser/code-ee.pem
new file mode 100644
index 000000000..a4fdfaed7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/code-ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxDCCAa6gAwIBAgIUSbYQoLY1s6wWqgbKhxQZ3XME7ukwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB2NvZGUtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsG
+AQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAV69uBbyc/d1eBdZlT7eAw4onQzkdndd8
+kEXdmP3hd+jJm1+/F733IflLLqE5mmUL9l7q7EJ+TgdZa19T6JHEaVjdJcIuwJO/
+kKSJXXqADQXoxHOZADDWjAFStiR3xd78BzYfuUANgozG6hq7QuVh0cYBx/8Q9gx/
+pGtuCJiN0d2Mknu0SoQzIZlXTuqmnFj7G/88O5Yh5MaFZxbvIJJSIWQoS396GrI6
+yXAdqHNoVM9mwwaMcnG5QeeKSIPuvEkZncQsxFc0zqIjeOVx/zEx2Bocx71dLuVB
+fqrIrAXLpwparoSxLzNqq8UgtXF8NQOuAcUu7ok0r1VbdMbSZHZ3Gg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec
new file mode 100644
index 000000000..93f9a8426
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:code-ee
+extension:extKeyUsage:codeSigning
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem
new file mode 100644
index 000000000..5b2cfd940
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaigAwIBAgIUGzSP8KEmmRm3sIPiyQW35sazlHEwCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCmV4cGlyZWQtY2EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowHTEbMBkGA1UEAwwSZWUtZnJvbS1leHBpcmVkLWNhMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq
+5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SSc
+An7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39
+ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYk
+zBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3u
+JtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQAB
+MAsGCSqGSIb3DQEBCwOCAQEAZ6Nrb/1fit8cALMhcbmuZ5kd3J34d0o9p3g3E7m7
+8RsTbYLA4xp9UmSzpO/10x9q4TUZ8jxW1dotoCVf7OqYYxQewrU2x3qoxKvP/Fvf
+8ssWSIang91w+app+fv7QYDySymT6DJMLWyCmxyhaFjYnmr67GKldcgK9hbyjfDB
+Rj382czI/HMSvw/vCB6rRKchzr5hsDGl+YN0MMI4M7/3b5wvMUmxlXqKu1VlslDZ
+8Ez6ONuMdPJD3aQZMxmEph05pEMvhjFhLh+0n7kfLR+9n0D7IR9paVc6LgHLLxsP
+ENoZLGOwJYNdAwwkd6fIa9E6KCpaRgyvWslm+iFCg3XxoA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec
new file mode 100644
index 000000000..3e280fc4f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec
@@ -0,0 +1,2 @@
+issuer:expired-ca
+subject:ee-from-expired-ca
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem
new file mode 100644
index 000000000..ad2d988e0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUI/4Y+KSEZo8YGQK6Ptrdmev5FO0wCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjAfMR0wGwYDVQQDDBRlZS1mcm9tLXVudHJ1c3RlZC1jYTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAATALBgkqhkiG9w0BAQsDggEBAJqsDDoJqxrmV4Mlt815HmJwhr/SuYhPwhoQ
+RyU56Ci5kY/8fYa3F1uxSrpzuiYBX4bq6g8keXmltPZGN9gexPP2QJDAecNt0NKW
++04ZKSiz6Tbu+MEyBaXCINDKaAHVPRnbMWR1eCyHzYpZRKZW2Sb2NinWGebzq0mI
+wt5l7veMkL5ZbeYF8u8bNFsdvhl1PM7/AfAZLJL4+fncaqQeDRyVffxrl4mCooS9
+DYajnw7AhFvN0XtXb5vK3HYiz9mv/OnXeoeWxYcWI6aY6LR0OwHHQQptKQSIOP87
+2mo64IbAwzuBrhxNrdrQKCnf1mtyDZig+2r6R4TP3EM3sCNAoiU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec
new file mode 100644
index 000000000..833e1a23a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec
@@ -0,0 +1,2 @@
+issuer:untrusted-ca
+subject:ee-from-untrusted-ca
diff --git a/security/manager/ssl/tests/mochitest/browser/email-ee.pem b/security/manager/ssl/tests/mochitest/browser/email-ee.pem
new file mode 100644
index 000000000..4211ef27d
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/email-ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUJctkeS6qP+WqsgOLbjATJuPlN40wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBMxETAPBgNVBAMMCGVtYWlsLWVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxcwFTATBgNVHSUEDDAKBggr
+BgEFBQcDBDALBgkqhkiG9w0BAQsDggEBAIFmRk4ZfcxWjetAoyYp0bIFLr5AjGqv
+ecmc0khsRkW7NR23ywJsRsCU1u82JIGrE0bpDu/KQPAMJsi6QMc9hZEOzO1t1QmG
+OJFLhCNTe+wf+5X+UKHKo01lEp7vDcO7DjuZIgEZSyOp9qbV88AtEiqESIzRBWYp
+dL15cS1PDH8fa5k7MHCAh0C/HeDRD5EP8derIWWrFIesEdJAhwzMRzJrCWIqzLPP
+Lv2gsXhehXCN7U14zkoGU97sSE09k5BopHd4fgqZesSApJrd2OenQAzdRIs3+UQy
+iCs7oLH16lOl/yeRxVjcHRWaSRM47eGpn5+YOnGkoE/lqfux+jjB3rc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec
new file mode 100644
index 000000000..82e329670
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:email-ee
+extension:extKeyUsage:emailProtection
diff --git a/security/manager/ssl/tests/mochitest/browser/expired-ca.pem b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem
new file mode 100644
index 000000000..2da553a56
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUAfElDw37NeFULPHd+G2eoaHpvEYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTAwMTAxMDAwMDAwWhgPMjAxMTAxMDEwMDAw
+MDBaMBUxEzARBgNVBAMMCmV4cGlyZWQtY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAde8CQNB8dVo5ly7Lu8x9
+5yDz2hpzAqqPDxP3+UqxzEgXeA4vfv1Bzvmxx69XEd+884M9Lkt2WBTrc+OrAgqX
+pCCt4X8bjV2t+mG1shtYEGKk5BtRVnorHhZyf6+5xtOfpV9DeWkf/aA1SJK1Kpt3
+cNSDW10PwaGuaNiUMEtIFLD/MYZCM98RFOSVDWjqafbfUBn4ZSeoyRi1C2d3lg0C
+jRFmOc1I4DQOUezp3C0WyCumJ0SLTIoYJGdAshMbDWPr0OOaB4GmI8miKhS6LM59
+o6C3fU8MJrRYKctYj0k9gW0DI6KuEFZj2AY8brv6Ufx1TKy5Z2pqIPeUbuJInCXM
+qA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec
new file mode 100644
index 000000000..15bdcd7d7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:expired-ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+validity:20100101-20110101
diff --git a/security/manager/ssl/tests/mochitest/browser/has-cn.pem b/security/manager/ssl/tests/mochitest/browser/has-cn.pem
new file mode 100644
index 000000000..8e7c479ae
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-cn.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0DCCAbqgAwIBAgIUfQIwxuYCoWiJuu/qTiEf7fbljnswCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMDcxDDAKBgNVBAMMA0ZvbzEMMAoGA1UECwwDQmFyMQwwCgYDVQQKDANCYXox
+CzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAJ2fIigbkc2Lh5Z/s
+Y7s4o0D9UnzttXjjEqKYhttk6PJnmVYG3zn3MBmyWPhDcXYW9fJwx7IOcC0woVdJ
+yjkVZUIlJY6xAqIC6kVNtbI3PJ+mji8qQk/ecXCwhTGk0H2lZXrUtc6WMmD3GUIP
+yNQGN/qAniRLnXzzVY3MJPLKKSlWSJEJCY4F4uDwBtwudPc+1yRIR6XblEL3dazS
+H2kuIzGwIu6/i3AN2WIFWFhcuRTfLZINlNeH9gYEaUrwI3MS0aMPqGXtOHz+imZl
+RwNng0xaiDxZXcEPjrRw5HEZcIEGBc6X8WtSzbWufiWBqMue1ltEpc1AkvUamuB3
+KJxYPA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec
new file mode 100644
index 000000000..a4a0fcb5f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/CN=Foo/OU=Bar/O=Baz/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem
new file mode 100644
index 000000000..8800bfb73
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIChjCCAXCgAwIBAgIBCjALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowADCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG
+9w0BAQsDggEBAF/OD4h9UNl2afVbw/Hv2dCV5uMyDV3T8iEUI9eiCvYDMAOElkAN
+NZbDfGfQdg8rNLKG6r7Vz8VBu0T/Vn2lswtKYPll63ANv9qZVtKGsDTGzN8JSC0k
+xgMbtVsj+OsJs81hmNnW6xw7wehpPw3l1UakAEb6dbYuYCanR/p/u/hvTz7phe9D
+AsJyRAo4a+QDyeqgAPKrzTatawshNnz9O4QhNzUqj53fMkpUq2ebOyIGMOvbh/N5
+nT6AVT2wn95mWawnS5v2VTRPALyMkgbl+0bb/VzXHN6CjDHO+n239lL2uQlAZFHe
+8pKr4lmb82dLU9qUFbY7exLyV1aUyYSXSNU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec
new file mode 100644
index 000000000..6346f7b83
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:
+serialNumber:10
diff --git a/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem
new file mode 100644
index 000000000..16964b1c0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpjCCAZCgAwIBAgIUCwPRyN8HCSE5XEIq7e2eEEe1OdIwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAt2CF0E7d
+QYnfn/kc8hb6GF6sYpCFA6egEzr6OsYMYE7jt5mKlMJdbIxw57L8jg8IZ1fjH5AQ
+KA5cchGcgjCkHoJ7jOYfMZCubCBdrsNKx2YYWcna8WIAZjwOIfNC0Ajs3IDiRDWm
+vlBrFP9Z6bGuzNrvLFAB0lU2dM2b99DqzaYNZeQP5DcP6ZjaPkSvqOWr3Lf6ZAvO
+tU70OcTelx74Hj9bI75bxVYd71Vorv5qB77zrl7GHb36f2pkludDOKeZ6XhRgy9e
+vN6DLctM0v6fJprG50xrILDhqsTydTdjhETLaIWhF9aUHzFybpFArp8TLoWbXiX1
+eAVaASutFVprhA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec
new file mode 100644
index 000000000..cc1b668a6
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/has-o.pem b/security/manager/ssl/tests/mochitest/browser/has-o.pem
new file mode 100644
index 000000000..755d3cdae
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-o.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtDCCAZ6gAwIBAgIUeXeYs5jw41bNt0btBeEFNbUQonAwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBsxDDAKBgNVBAoMA0JhejELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
+AQELA4IBAQAs60sU1VqjaVQbGBHvBNyiQn9oTugmuEx9ogwVKhnmgRK+hYw+wgBn
+H4yYZF1gF4xG7Rt+ut+EruSd4ht8vY9ZMvKrbgMrZ6HbNIZg9oIX+u0i9Bba2lh7
+p87mCePS5L7U1gPbg/fZ8jd0FvW8EusC/TX5tOeeUnawXWE4ciqPZfIVriU0iCP1
+nKzvFtawYzWwgN+QZ1ruzBi7qqrHNDAhgLu9+3g+9QyBd40XV7/EhDQ18kViaTSj
+WmaUX7jJD1FUkGBkxjqHfgGkaYnt7UXGMDTeQ8vFeja11PJJIdRT8hSu0oTMdE6M
+WCEw02+Fc+qsYH5I6vp3MOV8wyBqIqYc
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec
new file mode 100644
index 000000000..f7cc3ffc7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/O=Baz/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/has-ou.pem b/security/manager/ssl/tests/mochitest/browser/has-ou.pem
new file mode 100644
index 000000000..06f663b3f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-ou.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUU/td7MxWYwvdFLfgNUraIpy3GP8wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCkxDDAKBgNVBAsMA0JhcjEMMAoGA1UECgwDQmF6MQswCQYDVQQGEwJVUzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAATALBgkqhkiG9w0BAQsDggEBAGbVHQ19S6R62HovLt9Ltir1z9KJ4QXWNAEu
+FKicntKaId+jJY42y1+iAqQHy3FpjfLfx5eVKPW8vHbyTQSL/y0jJ9bPKepYsSay
+5McWggOxMxVFazUCOntZN282WYIg3H/OFaeRarjeHlraZjwmNxrfHKzyBJ6bBqBJ
+2vtmDez/+h+f0reutgnY1v4bJ02x/5YuG39+i08uRI0Vc+lrDiqDPYMxlmzwVvJM
+xqo9TZu9gU4XFbK8c8EUsPjMMO1gKyroiBhthtEZ8a9Q4jdeD92cOZRcPrHtYyvR
+qw9VhFLJRgLJ0DVOWqCHqYXUFfYngFezem1eeNxrz2eAbaURdCs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec
new file mode 100644
index 000000000..8879dabf5
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/OU=Bar/O=Baz/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/head.js b/security/manager/ssl/tests/mochitest/browser/head.js
new file mode 100644
index 000000000..d488e6eeb
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/head.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+/**
+ * List of certs imported via readCertificate(). Certs in this list are
+ * automatically deleted from the cert DB when a test including this head file
+ * finishes.
+ * @type nsIX509Cert[]
+ */
+var gImportedCerts = [];
+
+registerCleanupFunction(() => {
+ for (let cert of gImportedCerts) {
+ gCertDB.deleteCertificate(cert);
+ }
+});
+
+/**
+ * This function serves the same purpose as the one defined in head_psm.js.
+ */
+function pemToBase64(pem) {
+ return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
+ .replace(/-----END CERTIFICATE-----/, "")
+ .replace(/[\r\n]/g, "");
+}
+
+/**
+ * Given the filename of a certificate, returns a promise that will resolve with
+ * a handle to the certificate when that certificate has been read and imported
+ * with the given trust settings.
+ *
+ * Certs imported via this function will automatically be deleted from the cert
+ * DB once the calling test finishes.
+ *
+ * @param {String} filename
+ * The filename of the certificate (assumed to be in the same directory).
+ * @param {String} trustString
+ * A string describing how the certificate should be trusted (see
+ * `certutil -A --help`).
+ * @return {Promise}
+ * A promise that will resolve with a handle to the certificate.
+ */
+function readCertificate(filename, trustString) {
+ return OS.File.read(getTestFilePath(filename)).then(data => {
+ let decoder = new TextDecoder();
+ let pem = decoder.decode(data);
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ let base64 = pemToBase64(pem);
+ certdb.addCertFromBase64(base64, trustString, "unused");
+ let cert = certdb.constructX509FromBase64(base64);
+ gImportedCerts.push(cert);
+ return cert;
+ }, error => { throw error; });
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/invalid.pem b/security/manager/ssl/tests/mochitest/browser/invalid.pem
new file mode 100644
index 000000000..1911098ef
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/invalid.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvDCCAaagAwIBAgIUcy9NBl2j6kWrXfJ6Na36AnwN2Q8wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB2ludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjDzANMAsGA1UdDwQEAwIBBjAL
+BgkqhkiG9w0BAQsDggEBAHw1PeRKbGVaiNBPlshPnuEjJ5XN+ls3Lv8CVplvuFgM
+uvOAfuXNcLcQmqU4QZm9PvIboCAe2FTFMJ+szDbCIFaBzzJ4RnuJ0FnBZDf1fKJm
+/Nj4XikPePo5DnsqSs53aNKM7Nf5dcdCCA8kfpMm50Nw6ufWrr8HAEqQbDixecv1
+6as6xc458UU8AXKZb30VfLFAm0uPz2Y/ZjROnSqrNSB5ZRx9m4MqS3/4H7fSnlFU
+yMcetH5ovGk3xJg65qWhaRlaoeExco9E5x1nUr+eK4OmP3MXlGbxxMQx1R43Ea11
+zSyaqlhGUs06uDOl4rk4b2FmkPgGV+A26gtjMYD005k=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec b/security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec
new file mode 100644
index 000000000..71a1707c3
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:invalid
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/mochitest/browser/md5-ee.pem b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem
new file mode 100644
index 000000000..27bf90085
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqjCCAZSgAwIBAgIURZ4xXpmcV9oh3RekbTwkCGv62NowCwYJKoZIhvcNAQEE
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBm1kNS1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQQDggEBAKs7
+7/g5m901xqDth2t0tDTFWlfh/h94KLk8d8JAAa8AMdVwpMUMc2IKPk+H+f7JkBeE
+hhJ/r4ZEbQkjZuoLSkAR6aKRprE97Ddw1LJLVish39DitEXxpyDemCIl8V6E8FpW
+CWqbOZtvUScOQOlJ2uJfPwHkh93RJbzP9EY8Hd2arFYKuExi5z8Z465feZ53mdOe
+17WG9IKKIQirr4OAxD+ab1EdMuPuXKQ9qfg4fSW/LDsb97x0/ElRfHwFDxsbEiVi
+zR/gGMW9AQhc+eW2qchjYkO0v/ps7dzjDQFDJzLAd/mlb90cK1cpUz6XVn/HagvZ
+0MRczu3MnE6KRPVpW8Y=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec
new file mode 100644
index 000000000..279c15802
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:md5-ee
+signature:md5WithRSAEncryption
diff --git a/security/manager/ssl/tests/mochitest/browser/moz.build b/security/manager/ssl/tests/mochitest/browser/moz.build
new file mode 100644
index 000000000..49d7d5a11
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+BROWSER_CHROME_MANIFESTS += ['browser.ini']
+
+# Temporarily disabled. See bug 1256495.
+# (Note that when this gets enabled, some extra work will have to happen so
+# that the mochitest harness knows where to get the generated certificates -
+# right now it assumes they're in the source directory, which isn't the case
+# when they're automatically generated.)
+#test_certificates = (
+# 'ca.pem',
+# 'code-ee.pem',
+# 'ee-from-expired-ca.pem',
+# 'ee-from-untrusted-ca.pem',
+# 'email-ee.pem',
+# 'expired-ca.pem',
+# 'has-cn.pem',
+# 'has-empty-subject.pem',
+# 'has-non-empty-subject.pem',
+# 'has-o.pem',
+# 'has-ou.pem',
+# 'invalid.pem',
+# 'md5-ee.pem',
+# 'revoked.pem',
+# 'ssl-ee.pem',
+# 'unknown-issuer.pem',
+# 'untrusted-ca.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/mochitest/browser/revoked.pem b/security/manager/ssl/tests/mochitest/browser/revoked.pem
new file mode 100644
index 000000000..b212e8250
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/revoked.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqzCCAZWgAwIBAgIUD1t15yWPBLIhosAm9w9++t/F/fkwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB3Jldm9rZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQCy
+eobd3+MhGhQvhKQax5XNBqAEmogtsv6G1ZCoAx0kKU83r3Oj9ha4VfGN0syP8NQV
+nmkecZ630QXQcyCD3RRiiLqU07N3nC5djm8v+vM5RhuDADkIwddH3WNWB+8KUJEd
+3Sym1EN6xAYdQEAwWdPno73sUsFebuoL/c4gpTjD7PF+/vPzN0c3KVanlrMhayKe
+3PLq8jST2OSdLvooa8qMYsFFG2S4A+gmp9Cx30moMG2+w1GBKZdtY2tlFx5DppIU
+AoQzUl9pvT6AFDcY2RO6UvsWF9Pzr4dTjjgk8SO05jKcmj2GnBm480ZezDx5N5zm
++XVGgonJZRAucaVuJY79
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec b/security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec
new file mode 100644
index 000000000..daf75c670
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:revoked
diff --git a/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem
new file mode 100644
index 000000000..76a688034
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUYfe94xSwDUoffRodCo1TPdV/PaswCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBnNzbC1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMhMB8wHQYDVR0lBBYwFAYIKwYB
+BQUHAwEGCCsGAQUFBwMCMAsGCSqGSIb3DQEBCwOCAQEAprVI8tGWBHIN2SV66ZnC
+vOfWcQguUQg8QO3Al+O4X5U18hzgsmCjqt99b+oJCJD0qWBnPPBgqY52pckCgmTY
+w73TZ5w3Rnr3v+BlQ5xPTyAQoUeutm1LMxY/Ju7m1XV44tyDnq6GZbOZLVWtRLXe
+W4UEqVex4qbCw3GOvFyHmubSNUk81v4Iexe1SmIJN8glZsVmWJdaC2Xo7qhz+vvq
+HljfO+/ejiBtZOJSf9qG6HcGW/Rf15Io0e+IA6jbZWrlAzIjBcYKumZF8LjRONHZ
+vwiCwWit/IP6KvmsHAb7wj5c0U/p1TuyGdvu/ccp6nCdx8Ya7/QKfAEQTZXnloBG
+4w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec
new file mode 100644
index 000000000..c4037675f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ssl-ee
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem
new file mode 100644
index 000000000..d8e750551
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtzCCAaGgAwIBAgIUEfR3vHTQuzModYBSMepORIL++2gwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB3Vua25vd24wIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowGTEXMBUGA1UEAwwOdW5rbm93bi1pc3N1ZXIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVo
+V2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p
+0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKk
+fbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZh
+W7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EI
+TjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZI
+hvcNAQELA4IBAQB4pRQvglUpzNZ2fH0oj5bcqfcTjE3dwEzGg7WaMD2t50zKgCRp
+2sDObvEB1Nv5SHSkebxDeS9xQ6Dghf+TvuCnkapi/6q9etP51lkIOhl6okAGUwdZ
+vO3duIvXCVUWbut3ATQghKovDYuJXKMx1OYapxyLKKCsdvTQ8LNQpPcwbpVtqWKC
+jLYpa1i/vtn4Pv8xs/ceOf10z5AdydpFBgZ8JpY0CbRI73WHR5fr1yYI7tfzaAA8
+d+OBZ7nqlg81khD/Oepl/h6/IJ3L2eB+lUZx6+yWML9jRD0HX1xRje19u2vxCuQ+
+tNo6lQr9fTRG76Md1d4fdg9+F9LGqDd+yBBv
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec
new file mode 100644
index 000000000..c76a4e2c7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec
@@ -0,0 +1,2 @@
+issuer:unknown
+subject:unknown-issuer
diff --git a/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem
new file mode 100644
index 000000000..0f874d9a9
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAgIUT/T//UMr8YnbQBWj+61OMGPKRC4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUw
+AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQCiDFgskGRygaarkruu
+gTwsX59ULb7yhXyYKZLTdsUitHi8Zk4KUmsbkBHGaek30Ud9A1GyLzuP3hb1/M7M
+FdARYO8qrl414tW3hiON36R47qtw5cO6a2YZfvxU79esuoa6uxChhHLUugqNotJb
+bbGwSMszKzkGtOQ5ZTFNc8+t1kWeQfFoPMznjg5WC2oq9Pl45Rt9lFrU3SD8MkVA
+8fLAGR5TEOY2ZvjDDMKg+ceJNIaA3SPXDTVSXWNIakJU2vsdUXThTyfnoCw0sMQG
+ZwkmKbCXioYXDB/nrjoVBgJh85JSc4KX137y5m2FK+wHzkKMgf4yn6Ql2eg/yTen
+CaeK
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec
new file mode 100644
index 000000000..04f443057
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:untrusted-ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign