mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
bug 1591927: remote: implement Security.setIgnoreCertificateErrors; r=remote-protocol-reviewers,maja_zf
This implements an all-or-nothing insecure sweeping override that bypasses security exceptions when loading documents with invalid or otherwise bad TLS certificates. Differential Revision: https://phabricator.services.mozilla.com/D50838 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
4b22ebf93f
commit
ea1f27965e
@ -17,5 +17,6 @@ XPCOMUtils.defineLazyModuleGetters(ParentProcessDomains, {
|
|||||||
Input: "chrome://remote/content/domains/parent/Input.jsm",
|
Input: "chrome://remote/content/domains/parent/Input.jsm",
|
||||||
Network: "chrome://remote/content/domains/parent/Network.jsm",
|
Network: "chrome://remote/content/domains/parent/Network.jsm",
|
||||||
Page: "chrome://remote/content/domains/parent/Page.jsm",
|
Page: "chrome://remote/content/domains/parent/Page.jsm",
|
||||||
|
Security: "chrome://remote/content/domains/parent/Security.jsm",
|
||||||
Target: "chrome://remote/content/domains/parent/Target.jsm",
|
Target: "chrome://remote/content/domains/parent/Target.jsm",
|
||||||
});
|
});
|
||||||
|
55
remote/domains/parent/Security.jsm
Normal file
55
remote/domains/parent/Security.jsm
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* 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 EXPORTED_SYMBOLS = ["Security"];
|
||||||
|
|
||||||
|
const { Domain } = ChromeUtils.import(
|
||||||
|
"chrome://remote/content/domains/Domain.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
const { Preferences } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/Preferences.jsm"
|
||||||
|
);
|
||||||
|
const { XPCOMUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||||
|
sss: ["@mozilla.org/ssservice;1", "nsISiteSecurityService"],
|
||||||
|
certOverrideService: [
|
||||||
|
"@mozilla.org/security/certoverride;1",
|
||||||
|
"nsICertOverrideService",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const CERT_PINNING_ENFORCEMENT_PREF = "security.cert_pinning.enforcement_level";
|
||||||
|
const HSTS_PRELOAD_LIST_PREF = "network.stricttransportsecurity.preloadlist";
|
||||||
|
|
||||||
|
class Security extends Domain {
|
||||||
|
destructor() {
|
||||||
|
this.setIgnoreCertificateErrors({ ignore: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
setIgnoreCertificateErrors({ ignore }) {
|
||||||
|
if (ignore) {
|
||||||
|
// make it possible to register certificate overrides for domains
|
||||||
|
// that use HSTS or HPKP
|
||||||
|
Preferences.set(HSTS_PRELOAD_LIST_PREF, false);
|
||||||
|
Preferences.set(CERT_PINNING_ENFORCEMENT_PREF, 0);
|
||||||
|
} else {
|
||||||
|
Preferences.reset(HSTS_PRELOAD_LIST_PREF);
|
||||||
|
Preferences.reset(CERT_PINNING_ENFORCEMENT_PREF);
|
||||||
|
|
||||||
|
// clear collected HSTS and HPKP state
|
||||||
|
sss.clearAll();
|
||||||
|
sss.clearPreloads();
|
||||||
|
}
|
||||||
|
|
||||||
|
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
|
||||||
|
ignore
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,7 @@ remote.jar:
|
|||||||
content/domains/parent/network/NetworkObserver.jsm (domains/parent/network/NetworkObserver.jsm)
|
content/domains/parent/network/NetworkObserver.jsm (domains/parent/network/NetworkObserver.jsm)
|
||||||
content/domains/parent/Page.jsm (domains/parent/Page.jsm)
|
content/domains/parent/Page.jsm (domains/parent/Page.jsm)
|
||||||
content/domains/parent/page/DialogHandler.jsm (domains/parent/page/DialogHandler.jsm)
|
content/domains/parent/page/DialogHandler.jsm (domains/parent/page/DialogHandler.jsm)
|
||||||
|
content/domains/parent/Security.jsm (domains/parent/Security.jsm)
|
||||||
content/domains/parent/Target.jsm (domains/parent/Target.jsm)
|
content/domains/parent/Target.jsm (domains/parent/Target.jsm)
|
||||||
content/domains/parent/target/TabManager.jsm (domains/parent/target/TabManager.jsm)
|
content/domains/parent/target/TabManager.jsm (domains/parent/target/TabManager.jsm)
|
||||||
|
|
||||||
|
8
remote/test/browser/security/browser.ini
Normal file
8
remote/test/browser/security/browser.ini
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
tags = remote
|
||||||
|
subsuite = remote
|
||||||
|
prefs = remote.enabled=true
|
||||||
|
support-files =
|
||||||
|
head.js
|
||||||
|
|
||||||
|
[browser_setIgnoreCertificateErrors.js]
|
@ -0,0 +1,159 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {
|
||||||
|
STATE_IS_SECURE,
|
||||||
|
STATE_IS_BROKEN,
|
||||||
|
STATE_IS_INSECURE,
|
||||||
|
} = Ci.nsIWebProgressListener;
|
||||||
|
|
||||||
|
// from ../../../build/pgo/server-locations.txt
|
||||||
|
const NO_CERT = "https://nocert.example.com:443";
|
||||||
|
const SELF_SIGNED = "https://self-signed.example.com:443";
|
||||||
|
const UNTRUSTED = "https://untrusted.example.com:443";
|
||||||
|
const EXPIRED = "https://expired.example.com:443";
|
||||||
|
const MISMATCH_EXPIRED = "https://mismatch.expired.example.com:443";
|
||||||
|
const MISMATCH_UNTRUSTED = "https://mismatch.untrusted.example.com:443";
|
||||||
|
const UNTRUSTED_EXPIRED = "https://untrusted-expired.example.com:443";
|
||||||
|
const MISMATCH_UNTRUSTED_EXPIRED =
|
||||||
|
"https://mismatch.untrusted-expired.example.com:443";
|
||||||
|
|
||||||
|
const BAD_CERTS = [
|
||||||
|
NO_CERT,
|
||||||
|
SELF_SIGNED,
|
||||||
|
UNTRUSTED,
|
||||||
|
EXPIRED,
|
||||||
|
MISMATCH_EXPIRED,
|
||||||
|
MISMATCH_UNTRUSTED,
|
||||||
|
UNTRUSTED_EXPIRED,
|
||||||
|
MISMATCH_UNTRUSTED_EXPIRED,
|
||||||
|
];
|
||||||
|
|
||||||
|
function getConnectionState() {
|
||||||
|
// prevents items that are being lazy loaded causing issues
|
||||||
|
document.getElementById("identity-box").click();
|
||||||
|
gIdentityHandler.refreshIdentityPopup();
|
||||||
|
return document.getElementById("identity-popup").getAttribute("connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares the security state of the page with what is expected.
|
||||||
|
* Returns one of "secure", "broken", "insecure", or "unknown".
|
||||||
|
*/
|
||||||
|
function isSecurityState(browser, expectedState) {
|
||||||
|
const ui = browser.securityUI;
|
||||||
|
if (!ui) {
|
||||||
|
ok(false, "No security UI to get the security state");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSecure = ui.state & STATE_IS_SECURE;
|
||||||
|
const isBroken = ui.state & STATE_IS_BROKEN;
|
||||||
|
const isInsecure = ui.state & STATE_IS_INSECURE;
|
||||||
|
|
||||||
|
let actualState;
|
||||||
|
if (isSecure && !(isBroken || isInsecure)) {
|
||||||
|
actualState = "secure";
|
||||||
|
} else if (isBroken && !(isSecure || isInsecure)) {
|
||||||
|
actualState = "broken";
|
||||||
|
} else if (isInsecure && !(isSecure || isBroken)) {
|
||||||
|
actualState = "insecure";
|
||||||
|
} else {
|
||||||
|
actualState = "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
is(
|
||||||
|
expectedState,
|
||||||
|
actualState,
|
||||||
|
`Expected state is ${expectedState} and actual state is ${actualState}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(async function testDefault({ Security }) {
|
||||||
|
for (const url of BAD_CERTS) {
|
||||||
|
info(`Navigating to ${url}`);
|
||||||
|
const loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser);
|
||||||
|
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
|
||||||
|
await loaded;
|
||||||
|
|
||||||
|
is(
|
||||||
|
getConnectionState(),
|
||||||
|
"cert-error-page",
|
||||||
|
"Security error page is present"
|
||||||
|
);
|
||||||
|
isSecurityState(gBrowser, "insecure");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function testIgnore({ Security }) {
|
||||||
|
info("Enable security certificate override");
|
||||||
|
await Security.setIgnoreCertificateErrors({ ignore: true });
|
||||||
|
|
||||||
|
for (const url of BAD_CERTS) {
|
||||||
|
info(`Navigating to ${url}`);
|
||||||
|
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
|
||||||
|
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||||
|
|
||||||
|
is(
|
||||||
|
getConnectionState(),
|
||||||
|
"secure-cert-user-overridden",
|
||||||
|
"Security certificate was overridden by user"
|
||||||
|
);
|
||||||
|
isSecurityState(gBrowser, "secure");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function testUnignore({ Security }) {
|
||||||
|
info("Disable security certificate override");
|
||||||
|
await Security.setIgnoreCertificateErrors({ ignore: false });
|
||||||
|
|
||||||
|
for (const url of BAD_CERTS) {
|
||||||
|
info(`Navigating to ${url}`);
|
||||||
|
const loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser);
|
||||||
|
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
|
||||||
|
await loaded;
|
||||||
|
|
||||||
|
is(
|
||||||
|
getConnectionState(),
|
||||||
|
"cert-error-page",
|
||||||
|
"Security error page is present"
|
||||||
|
);
|
||||||
|
isSecurityState(gBrowser, "insecure");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// smoke test for unignored -> ignored -> unignored
|
||||||
|
add_task(async function testToggle({ Security }) {
|
||||||
|
let loaded;
|
||||||
|
|
||||||
|
info("Enable security certificate override");
|
||||||
|
await Security.setIgnoreCertificateErrors({ ignore: true });
|
||||||
|
|
||||||
|
info(`Navigating to ${UNTRUSTED} having set the override`);
|
||||||
|
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, UNTRUSTED);
|
||||||
|
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||||
|
|
||||||
|
is(
|
||||||
|
getConnectionState(),
|
||||||
|
"secure-cert-user-overridden",
|
||||||
|
"Security certificate was overridden by user"
|
||||||
|
);
|
||||||
|
isSecurityState(gBrowser, "secure");
|
||||||
|
|
||||||
|
info("Disable security certificate override");
|
||||||
|
await Security.setIgnoreCertificateErrors({ ignore: false });
|
||||||
|
|
||||||
|
info(`Navigating to ${UNTRUSTED} having unset the override`);
|
||||||
|
loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser);
|
||||||
|
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, UNTRUSTED);
|
||||||
|
await loaded;
|
||||||
|
|
||||||
|
is(
|
||||||
|
getConnectionState(),
|
||||||
|
"cert-error-page",
|
||||||
|
"Security error page is present by default"
|
||||||
|
);
|
||||||
|
isSecurityState(gBrowser, "insecure");
|
||||||
|
});
|
11
remote/test/browser/security/head.js
Normal file
11
remote/test/browser/security/head.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/* import-globals-from ../head.js */
|
||||||
|
|
||||||
|
Services.scriptloader.loadSubScript(
|
||||||
|
"chrome://mochitests/content/browser/remote/test/browser/head.js",
|
||||||
|
this
|
||||||
|
);
|
@ -9,6 +9,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||||||
"browser/network/browser.ini",
|
"browser/network/browser.ini",
|
||||||
"browser/page/browser.ini",
|
"browser/page/browser.ini",
|
||||||
"browser/runtime/browser.ini",
|
"browser/runtime/browser.ini",
|
||||||
|
"browser/security/browser.ini",
|
||||||
"browser/target/browser.ini",
|
"browser/target/browser.ini",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user