mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
bug 1412438 - add preference to disable HPKP by default r=jcj
As Chrome has removed support for the HPKP (HTTP Public Key Pinning) header, continuing to support it in Firefox is a compatibility risk. This patch adds the preference "security.cert_pinning.hpkp.enabled" and sets it to false by default. As such, the platform will no longer process the HPKP header nor consult any cached HPKP information for certificate pins. Preloaded (statically-compiled) pins are still enabled in Firefox by default. This patch also disables dynamically setting pins via our remote security settings infrastructure, as it uses the same backend and represents similar compatibility risk. Differential Revision: https://phabricator.services.mozilla.com/D52773 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
ad56e58826
commit
a841102f18
@ -26,9 +26,10 @@ const gSSService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
);
|
||||
|
||||
const kPinningDomain = "include-subdomains.pinning-dynamic.example.com";
|
||||
const khpkpPinninEnablePref =
|
||||
const kHPKPEnabledPref = "security.cert_pinning.hpkp.enabled";
|
||||
const kProcessHPKPFromNonBuiltInRootsPref =
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots";
|
||||
const kpkpEnforcementPref = "security.cert_pinning.enforcement_level";
|
||||
const kPinningEnforcementPref = "security.cert_pinning.enforcement_level";
|
||||
const kBadPinningDomain = "bad.include-subdomains.pinning-dynamic.example.com";
|
||||
const kURLPath =
|
||||
"/browser/browser/base/content/test/general/pinning_headers.sjs?";
|
||||
@ -37,11 +38,13 @@ function test() {
|
||||
waitForExplicitFinish();
|
||||
// Enable enforcing strict pinning and processing headers from
|
||||
// non-builtin roots.
|
||||
Services.prefs.setIntPref(kpkpEnforcementPref, 2);
|
||||
Services.prefs.setBoolPref(khpkpPinninEnablePref, true);
|
||||
Services.prefs.setIntPref(kPinningEnforcementPref, 2);
|
||||
Services.prefs.setBoolPref(kHPKPEnabledPref, true);
|
||||
Services.prefs.setBoolPref(kProcessHPKPFromNonBuiltInRootsPref, true);
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref(kpkpEnforcementPref);
|
||||
Services.prefs.clearUserPref(khpkpPinninEnablePref);
|
||||
Services.prefs.clearUserPref(kPinningEnforcementPref);
|
||||
Services.prefs.clearUserPref(kHPKPEnabledPref);
|
||||
Services.prefs.clearUserPref(kProcessHPKPFromNonBuiltInRootsPref);
|
||||
let uri = Services.io.newURI("https://" + kPinningDomain);
|
||||
gSSService.resetState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
});
|
||||
|
@ -14,14 +14,18 @@ const LEARN_MORE_URI =
|
||||
"https://developer.mozilla.org/docs/Web/HTTP/" +
|
||||
"Public_Key_Pinning" +
|
||||
DOCS_GA_PARAMS;
|
||||
const HPKP_ENABLED_PREF = "security.cert_pinning.hpkp.enabled";
|
||||
const NON_BUILTIN_ROOT_PREF =
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots";
|
||||
|
||||
add_task(async function() {
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(HPKP_ENABLED_PREF);
|
||||
Services.prefs.clearUserPref(NON_BUILTIN_ROOT_PREF);
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(HPKP_ENABLED_PREF, true);
|
||||
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
await navigateAndCheckForWarningMessage(
|
||||
|
@ -17,7 +17,8 @@
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let gCurrentTestCase = -1;
|
||||
const HPKP_PREF = "security.cert_pinning.process_headers_from_non_builtin_roots";
|
||||
const HPKP_ENABLED_PREF = "security.cert_pinning.hpkp.enabled";
|
||||
const PROCESS_HPKP_FROM_NON_BUILTIN_ROOTS_PREF = "security.cert_pinning.process_headers_from_non_builtin_roots";
|
||||
|
||||
// Static pins tested by unit/test_security-info-static-hpkp.js.
|
||||
const TEST_CASES = [
|
||||
@ -40,11 +41,11 @@ const TEST_CASES = [
|
||||
];
|
||||
|
||||
function startTest() {
|
||||
// Need to enable this pref or pinning headers are rejected due test
|
||||
// certificate.
|
||||
Services.prefs.setBoolPref(HPKP_PREF, true);
|
||||
Services.prefs.setBoolPref(HPKP_ENABLED_PREF, true);
|
||||
Services.prefs.setBoolPref(PROCESS_HPKP_FROM_NON_BUILTIN_ROOTS_PREF, true);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
Services.prefs.setBoolPref(HPKP_PREF, false);
|
||||
Services.prefs.setBoolPref(HPKP_ENABLED_PREF, false);
|
||||
Services.prefs.setBoolPref(PROCESS_HPKP_FROM_NON_BUILTIN_ROOTS_PREF, false);
|
||||
|
||||
// Reset pinning state.
|
||||
let gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
|
@ -2259,6 +2259,15 @@ pref("security.cert_pinning.enforcement_level", 0);
|
||||
// for tests.
|
||||
pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
|
||||
|
||||
// Controls whether or not HPKP (the HTTP Public Key Pinning header) is enabled.
|
||||
// If true, the header is processed and collected HPKP information is consulted
|
||||
// when looking for pinning information.
|
||||
// If false, the header is not processed and collected HPKP information is not
|
||||
// consulted when looking for pinning information. Preloaded pins are not
|
||||
// affected by this preference.
|
||||
// Default: false
|
||||
pref("security.cert_pinning.hpkp.enabled", false);
|
||||
|
||||
// If set to true strict checks will happen on the triggering principal for loads.
|
||||
// Android is disabled at the moment pending Bug 1504968
|
||||
#if !defined(RELEASE_OR_BETA) && !defined(ANDROID)
|
||||
|
@ -455,6 +455,7 @@ nsSiteSecurityService::nsSiteSecurityService()
|
||||
: mMaxMaxAge(kSixtyDaysInSeconds),
|
||||
mUsePreloadList(true),
|
||||
mPreloadListTimeOffset(0),
|
||||
mHPKPEnabled(false),
|
||||
mProcessPKPHeadersFromNonBuiltInRoots(false),
|
||||
mDafsa(kDafsa) {}
|
||||
|
||||
@ -477,6 +478,10 @@ nsresult nsSiteSecurityService::Init() {
|
||||
"network.stricttransportsecurity.preloadlist", true);
|
||||
mozilla::Preferences::AddStrongObserver(
|
||||
this, "network.stricttransportsecurity.preloadlist");
|
||||
mHPKPEnabled = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.hpkp.enabled", false);
|
||||
mozilla::Preferences::AddStrongObserver(this,
|
||||
"security.cert_pinning.hpkp.enabled");
|
||||
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
|
||||
mozilla::Preferences::AddStrongObserver(
|
||||
@ -994,6 +999,17 @@ nsresult nsSiteSecurityService::ProcessPKPHeader(
|
||||
if (aFailureResult) {
|
||||
*aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
|
||||
}
|
||||
if (!mHPKPEnabled) {
|
||||
SSSLOG(("SSS: HPKP disabled: not processing header '%s'", aHeader.get()));
|
||||
if (aMaxAge) {
|
||||
*aMaxAge = 0;
|
||||
}
|
||||
if (aIncludeSubdomains) {
|
||||
*aIncludeSubdomains = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SSSLOG(("SSS: processing HPKP header '%s'", aHeader.get()));
|
||||
NS_ENSURE_ARG(aSecInfo);
|
||||
|
||||
@ -1587,7 +1603,7 @@ nsSiteSecurityService::GetKeyPinsForHostname(
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
/*out*/ nsTArray<nsCString>& pinArray,
|
||||
/*out*/ bool* aIncludeSubdomains,
|
||||
/*out*/ bool* afound) {
|
||||
/*out*/ bool* aFound) {
|
||||
// Child processes are not allowed direct access to this.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_CRASH(
|
||||
@ -1595,11 +1611,18 @@ nsSiteSecurityService::GetKeyPinsForHostname(
|
||||
"nsISiteSecurityService::GetKeyPinsForHostname");
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG(afound);
|
||||
NS_ENSURE_ARG(aFound);
|
||||
|
||||
const nsCString& flatHostname = PromiseFlatCString(aHostname);
|
||||
if (!mHPKPEnabled) {
|
||||
SSSLOG(("HPKP disabled - returning 'pins not found' for %s",
|
||||
flatHostname.get()));
|
||||
*aFound = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SSSLOG(("Top of GetKeyPinsForHostname for %s", flatHostname.get()));
|
||||
*afound = false;
|
||||
*aFound = false;
|
||||
*aIncludeSubdomains = false;
|
||||
pinArray.Clear();
|
||||
|
||||
@ -1640,7 +1663,7 @@ nsSiteSecurityService::GetKeyPinsForHostname(
|
||||
}
|
||||
pinArray = foundEntry->mSHA256keys;
|
||||
*aIncludeSubdomains = foundEntry->mIncludeSubdomains;
|
||||
*afound = true;
|
||||
*aFound = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1660,6 +1683,13 @@ nsSiteSecurityService::SetKeyPins(const nsACString& aHost,
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
if (!mHPKPEnabled) {
|
||||
SSSLOG(("SSS: HPKP disabled: not setting pins"));
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OriginAttributes originAttributes;
|
||||
if (aArgc > 1) {
|
||||
// OriginAttributes were passed in.
|
||||
@ -1815,6 +1845,8 @@ nsSiteSecurityService::Observe(nsISupports* /*subject*/, const char* topic,
|
||||
"network.stricttransportsecurity.preloadlist", true);
|
||||
mPreloadListTimeOffset =
|
||||
mozilla::Preferences::GetInt("test.currentTimeOffsetSeconds", 0);
|
||||
mHPKPEnabled = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.hpkp.enabled", false);
|
||||
mProcessPKPHeadersFromNonBuiltInRoots = mozilla::Preferences::GetBool(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots", false);
|
||||
mMaxMaxAge = mozilla::Preferences::GetInt(
|
||||
|
@ -213,6 +213,7 @@ class nsSiteSecurityService : public nsISiteSecurityService,
|
||||
uint64_t mMaxMaxAge;
|
||||
bool mUsePreloadList;
|
||||
int64_t mPreloadListTimeOffset;
|
||||
bool mHPKPEnabled;
|
||||
bool mProcessPKPHeadersFromNonBuiltInRoots;
|
||||
RefPtr<mozilla::DataStorage> mSiteStateStorage;
|
||||
RefPtr<mozilla::DataStorage> mPreloadStateStorage;
|
||||
|
@ -14,6 +14,8 @@ const sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
|
||||
const { PinningBlocklistClient } = RemoteSecuritySettings.init();
|
||||
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
|
||||
add_task(async function test_uses_a_custom_signer() {
|
||||
Assert.notEqual(
|
||||
PinningBlocklistClient.signerName,
|
||||
|
@ -16,6 +16,7 @@ const { ForgetAboutSite } = ChromeUtils.import(
|
||||
do_get_profile(); // must be done before instantiating nsIX509CertDB
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
@ -46,6 +47,26 @@ function add_tests() {
|
||||
}
|
||||
);
|
||||
|
||||
// Test that with HPKP disabled, processing HPKP headers results in no
|
||||
// information being saved.
|
||||
add_task(async function() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", false);
|
||||
sss.processHeader(
|
||||
Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
uri,
|
||||
GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN,
|
||||
secInfo,
|
||||
0,
|
||||
Ci.nsISiteSecurityService.SOURCE_ORGANIC_REQUEST
|
||||
);
|
||||
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Assert.ok(
|
||||
!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
|
||||
"a.pinning.example.com should not be HPKP"
|
||||
);
|
||||
});
|
||||
|
||||
// Test the normal case of processing HSTS and HPKP headers for
|
||||
// a.pinning.example.com, using "Forget About Site" on a.pinning2.example.com,
|
||||
// and then checking that the platform doesn't consider a.pinning.example.com
|
||||
@ -266,6 +287,7 @@ function add_tests() {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
|
@ -42,6 +42,7 @@ function add_tests() {
|
||||
true,
|
||||
false,
|
||||
function(aSecInfo) {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
@ -74,6 +75,7 @@ function add_tests() {
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
);
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
}
|
||||
);
|
||||
|
@ -299,6 +299,9 @@ function check_pinning_telemetry() {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// Ensure that static pinning works when HPKP is disabled.
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", false);
|
||||
|
||||
add_tls_server_setup("BadCertAndPinningServer", "bad_certs");
|
||||
|
||||
// Add a user-specified trust anchor.
|
||||
|
@ -49,6 +49,7 @@ const NON_ISSUED_KEY_HASH = "KHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN=";
|
||||
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
|
||||
let stateFile = profileDir.clone();
|
||||
@ -145,6 +146,7 @@ function checkStateRead(aSubject, aTopic, aData) {
|
||||
}
|
||||
|
||||
async_check_pins()
|
||||
.then(checkHPKPDisabled)
|
||||
.then(function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
do_timeout(1250, resolve);
|
||||
@ -411,6 +413,16 @@ async function async_check_pins() {
|
||||
);
|
||||
}
|
||||
|
||||
// Check that if HPKP is disabled, accumulated HPKP information isn't consulted.
|
||||
async function checkHPKPDisabled() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", false);
|
||||
await checkOK(
|
||||
certFromFile("a.pinning2.example.com-badca"),
|
||||
"a.pinning2.example.com"
|
||||
);
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
}
|
||||
|
||||
async function checkExpiredState() {
|
||||
await checkOK(
|
||||
certFromFile("a.pinning2.example.com-badca"),
|
||||
|
@ -201,11 +201,13 @@ function add_tests() {
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.max_max_age_seconds");
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
Services.prefs.setIntPref(
|
||||
"security.cert_pinning.max_max_age_seconds",
|
||||
|
@ -73,6 +73,7 @@ function checkSha256Keys(hpkpEntries) {
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
);
|
||||
@ -138,6 +139,7 @@ function add_tests() {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
true
|
||||
|
@ -9,6 +9,7 @@
|
||||
// Ensures nsISiteSecurityService APIs respects origin attributes.
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
Services.prefs.clearUserPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
@ -24,6 +25,7 @@ const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
|
||||
|
||||
do_get_profile(); // must be done before instantiating nsIX509CertDB
|
||||
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
|
@ -109,6 +109,7 @@ const MULTIPLE_KEYS =
|
||||
PINNING_ROOT_KEY_HASH + STARTS_WITH_NUMBER + STARTS_WITH_SYMBOL;
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
let profileDir = do_get_profile();
|
||||
let stateFile = profileDir.clone();
|
||||
stateFile.append(SSS_STATE_FILE_NAME);
|
||||
|
@ -129,12 +129,14 @@ function add_tests() {
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.hpkp.enabled");
|
||||
Services.prefs.clearUserPref(
|
||||
"sercurity.cert_pinning.process_headers_from_non_builtin_roots"
|
||||
);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setBoolPref(
|
||||
"security.cert_pinning.process_headers_from_non_builtin_roots",
|
||||
true
|
||||
|
@ -94,6 +94,7 @@ function checkStateWritten(aSubject, aTopic, aData) {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", true);
|
||||
Services.prefs.setIntPref("test.datastorage.write_timer_ms", 100);
|
||||
gProfileDir = do_get_profile();
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
|
Loading…
Reference in New Issue
Block a user