commit a450c91afb6bfd1551675ac7c230843f93820e1d
parent d28568cb3ae26dad261a006fef4fbc62a81504b6
Author: Malte Jürgens <maltejur@mozilla.com>
Date: Thu, 13 Nov 2025 13:54:09 +0000
Bug 1968527 - Add test for preventing HTTPS-Only/-First downgrade during client cert dialog r=simonf
Differential Revision: https://phabricator.services.mozilla.com/D271796
Diffstat:
2 files changed, 87 insertions(+), 0 deletions(-)
diff --git a/dom/security/test/https-first/browser.toml b/dom/security/test/https-first/browser.toml
@@ -4,6 +4,8 @@ support-files = ["head.js"]
["browser_beforeunload_permit_http.js"]
support-files = ["file_beforeunload_permit_http.html"]
+["browser_client_cert.js"]
+
["browser_downgrade_mixed_content_auto_upgrade_console.js"]
support-files = [
"file_mixed_content_auto_upgrade.html",
diff --git a/dom/security/test/https-first/browser_client_cert.js b/dom/security/test/https-first/browser_client_cert.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+ https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that HTTPS-Only/-First doesn't downgrade the current load on its
+// background timer if the load is blocked by the client certificate dialog (Bug
+// 1968527).
+
+function runTest() {
+ return BrowserTestUtils.withNewTab("about:blank", async function (browser) {
+ const certDialogPromise = new Promise(resolve =>
+ Services.obs.addObserver(resolve, "cert-dialog-loaded")
+ );
+
+ BrowserTestUtils.startLoadingURIString(
+ browser,
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://requireclientcert.example.com"
+ );
+
+ const certDialog = await certDialogPromise;
+
+ is(certDialog.checkVisibility(), true, "Client cert dialog should be open");
+
+ is(browser.currentURI.displaySpec, "about:blank", "Page should be loading");
+
+ await new Promise(resolve => {
+ // The expected behavior is to have no downgrade happen and have the load
+ // continue indefinetely waiting for user input. There is no event we can
+ // listen to to test this, so we will have to do this with a timeout
+ // instead.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(resolve, 500);
+ });
+
+ is(
+ certDialog.checkVisibility(),
+ true,
+ "Client cert dialog should still be open after 500ms"
+ );
+
+ is(
+ browser.currentURI.displaySpec,
+ "about:blank",
+ "Page should still be loading after 500ms"
+ );
+ });
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.default_personal_cert", "Ask Every Time"],
+ // (Almost) instantly perform the downgrade
+ ["dom.security.https_only_fire_http_request_background_timer_ms", 100],
+ ],
+ });
+});
+
+describe("Client certificate", function () {
+ afterEach(async function () {
+ // Forget about requireclientcert.example.com again
+ await new Promise(resolve =>
+ Services.clearData.deleteDataFromHost(
+ "requireclientcert.example.com",
+ false,
+ Services.clearData.CLEAR_CLIENT_AUTH_REMEMBER_SERVICE,
+ resolve
+ )
+ );
+ });
+
+ it("HTTPS-First", async function () {
+ await runTest();
+ });
+
+ it("HTTPS-Only", async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.security.https_only_mode", true]],
+ });
+
+ await runTest();
+ });
+});