bug 1267463 - add a more nuanced subject common name fallback option for prerelease channels
MozReview-Commit-ID: 1vHXrPAHTRm
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -54,17 +54,19 @@ pref("security.pki.sha1_enforcement_leve
// security.pki.name_matching_mode controls how the platform matches hostnames
// to name information in TLS certificates. The possible values are:
// 0: always fall back to the subject common name if necessary (as in, if the
// subject alternative name extension is either not present or does not
// contain any DNS names or IP addresses)
// 1: fall back to the subject common name for certificates valid before 23
// August 2016 if necessary
-// 2: only use name information from the subject alternative name extension
+// 2: fall back to the subject common name for certificates valid before 23
+// August 2015 if necessary
+// 3: only use name information from the subject alternative name extension
#ifdef RELEASE_BUILD
pref("security.pki.name_matching_mode", 1);
#else
pref("security.pki.name_matching_mode", 2);
#endif
pref("security.webauth.u2f", false);
pref("security.webauth.u2f_enable_softtoken", false);
--- a/security/certverifier/BRNameMatchingPolicy.cpp
+++ b/security/certverifier/BRNameMatchingPolicy.cpp
@@ -11,23 +11,30 @@
using namespace mozilla::psm;
using namespace mozilla::pkix;
Result
BRNameMatchingPolicy::FallBackToCommonName(
Time notBefore,
/*out*/ FallBackToSearchWithinSubject& fallBackToCommonName)
{
+ // (new Date("2015-08-23T00:00:00Z")).getTime() / 1000
+ static const Time AUGUST_23_2015 = TimeFromEpochInSeconds(1440288000);
// (new Date("2016-08-23T00:00:00Z")).getTime() / 1000
static const Time AUGUST_23_2016 = TimeFromEpochInSeconds(1471910400);
switch (mMode)
{
case Mode::Enforce:
fallBackToCommonName = FallBackToSearchWithinSubject::No;
break;
+ case Mode::EnforceAfter23August2015:
+ fallBackToCommonName = notBefore > AUGUST_23_2015
+ ? FallBackToSearchWithinSubject::No
+ : FallBackToSearchWithinSubject::Yes;
+ break;
case Mode::EnforceAfter23August2016:
fallBackToCommonName = notBefore > AUGUST_23_2016
? FallBackToSearchWithinSubject::No
: FallBackToSearchWithinSubject::Yes;
break;
case Mode::DoNotEnforce:
fallBackToCommonName = FallBackToSearchWithinSubject::Yes;
break;
--- a/security/certverifier/BRNameMatchingPolicy.h
+++ b/security/certverifier/BRNameMatchingPolicy.h
@@ -18,28 +18,31 @@ namespace mozilla { namespace psm {
// subjectAltName extension". Consequently, since any name information present
// in the common name must be present in the subject alternative name extension,
// when performing name matching, it should not be necessary to fall back to the
// common name. Because this consequence has not commonly been enforced, this
// implementation provides a mechanism to start enforcing it gradually while
// maintaining some backwards compatibility. If configured with the mode
// "EnforceAfter23August2016", name matching will only fall back to using the
// subject common name for certificates where the notBefore field is before 23
-// August 2016.
+// August 2016. Similarly, the mode "EnforceAfter23August2015" is also
+// available. This is to provide a balance between allowing preexisting
+// long-lived certificates and detecting newly-issued problematic certificates.
// Note that this implementation does not actually directly enforce that if the
// subject common name is present, its value corresponds to a dNSName or
// iPAddress entry in the subject alternative name extension.
class BRNameMatchingPolicy : public mozilla::pkix::NameMatchingPolicy
{
public:
enum class Mode {
DoNotEnforce = 0,
EnforceAfter23August2016 = 1,
- Enforce = 2,
+ EnforceAfter23August2015 = 2,
+ Enforce = 3,
};
explicit BRNameMatchingPolicy(Mode mode)
: mMode(mode)
{
}
virtual mozilla::pkix::Result FallBackToCommonName(
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1335,16 +1335,17 @@ void nsNSSComponent::setValidationOption
}
BRNameMatchingPolicy::Mode nameMatchingMode =
static_cast<BRNameMatchingPolicy::Mode>
(Preferences::GetInt("security.pki.name_matching_mode",
static_cast<int32_t>(BRNameMatchingPolicy::Mode::DoNotEnforce)));
switch (nameMatchingMode) {
case BRNameMatchingPolicy::Mode::Enforce:
+ case BRNameMatchingPolicy::Mode::EnforceAfter23August2015:
case BRNameMatchingPolicy::Mode::EnforceAfter23August2016:
case BRNameMatchingPolicy::Mode::DoNotEnforce:
break;
default:
nameMatchingMode = BRNameMatchingPolicy::Mode::DoNotEnforce;
break;
}
--- a/security/manager/ssl/tests/unit/test_baseline_requirements/moz.build
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/moz.build
@@ -3,15 +3,17 @@
# 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/.
# Temporarily disabled. See bug 1256495.
#test_certificates = (
# 'ca.pem',
# 'no-san-old.pem',
+# 'no-san-really-old.pem',
# 'no-san-recent.pem',
# 'san-contains-no-hostnames-old.pem',
+# 'san-contains-no-hostnames-really-old.pem',
# 'san-contains-no-hostnames-recent.pem',
#)
#
#for test_certificate in test_certificates:
# GeneratedTestCertificate(test_certificate)
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-really-old.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUZ3gdKZRvWFYArMRStT2zAGE6JDQwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEAn81HiHxHv7Mhq16XWoD6ttEu9sllOHssw452wRdIieM2XcMIi5DPI81XDhqk
+5Zw/pUDfWxNFLq92JM2UArF7RtWICBYqi4UJcdnrMb84rwOVdgt9sDQYdamqj5qF
+90XpTOIA+ZyfAMXxJpJTEC9WN1rc3cK6Epv0+7KqE6FBa5aH8uAYXAb/+eKmtwY/
+ELQWT2jsoplihEw8aJsXTR9M9y2UudxPhqgA7lPpstbOMNuw2xg8oWBnqgZGRGvH
+7Afu2CoxEmYbxXnO6cJ30/pAuVLnVpmJg1n7DLT8is+2fUiOMyuve7KAjxuAo3KT
+XEiTdgDBOOO+gIY532x/jErbRA==
+-----END CERTIFICATE-----
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-really-old.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:example.com
+validity:20150724-20160924
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-really-old.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4TCCAcugAwIBAgIUTePOoF7EmrE46xg5zgyv8RLxEhYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozAwLjAsBgNVHREEJTAj
+pCEwHzEdMBsGA1UECgwURXhhbXBsZSBPcmdhbml6YXRpb24wCwYJKoZIhvcNAQEL
+A4IBAQCdicLQK5tTHkNs58IySxDedV+BqQYxvNZN3cfrqzFdehS4OzVe8hQkwKhJ
+5PpOfkh86KxoBActVL8AtP+mIBZ765qEFPhGEFMfEhqattsO6BluMNTB7ZP8HeDm
+/oCI7Ae5u+Yr5IvjBNSv5fpY7sfDiM4oqXBolJYkR+YTu+GSKYhLZTtiHhG1/Jgw
+yzBzWkfYxIW7EOe2t99krNWpPaf1MyUXO3Pj/7qfURMDeocaAvPGw7tqCZ0nsbOe
+rJvNVZDMaPbOVQKsSSyIrEDfBlQViG10eQIUaURuAY4hJs6AoLvS5b3EaxAQAWtJ
+okbLuSVbj7giOF84hkcFM3hE1FTs
+-----END CERTIFICATE-----
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-really-old.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:example.com
+validity:20150724-20160924
+extension:subjectAlternativeName:/O=Example Organization
--- a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
@@ -51,81 +51,138 @@ function run_test() {
// not in general treated as built-ins, these should all successfully verify
// regardless of the value of the pref.
Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
do_print("current mode: always fall back, root not built-in");
checkCertOn25August2016(certFromFile("no-san-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("no-san-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
do_print("current mode: fall back for notBefore < August 23, 2016, root " +
"not built-in");
checkCertOn25August2016(certFromFile("no-san-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("no-san-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
+ do_print("current mode: fall back for notBefore < August 23, 2015, root " +
+ "not built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
+
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
do_print("current mode: never fall back, root not built-in");
checkCertOn25August2016(certFromFile("no-san-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("no-san-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
// In debug builds, we can treat an imported root as a built-in, and thus we
// can actually test the different values of the pref.
if (isDebugBuild) {
let root = certFromFile("ca");
Services.prefs.setCharPref("security.test.built_in_root_hash",
root.sha256Fingerprint);
// Always fall back if necessary.
Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
do_print("current mode: always fall back, root built-in");
checkCertOn25August2016(certFromFile("no-san-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("no-san-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
// Only fall back if notBefore < 23 August 2016
Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
do_print("current mode: fall back for notBefore < August 23, 2016, root " +
"built-in");
checkCertOn25August2016(certFromFile("no-san-recent"),
SSL_ERROR_BAD_CERT_DOMAIN);
checkCertOn25August2016(certFromFile("no-san-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
SSL_ERROR_BAD_CERT_DOMAIN);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
+
+ // Only fall back if notBefore < 23 August 2015
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
+ do_print("current mode: fall back for notBefore < August 23, 2015, root " +
+ "built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ PRErrorCodeSuccess);
// Never fall back.
- Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
do_print("current mode: never fall back, root built-in");
checkCertOn25August2016(certFromFile("no-san-recent"),
SSL_ERROR_BAD_CERT_DOMAIN);
checkCertOn25August2016(certFromFile("no-san-old"),
SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-really-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
SSL_ERROR_BAD_CERT_DOMAIN);
checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-really-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
}
}