bug 1245280 - add policy mechanism to optionally enforce BRs for falling back to subject CN r?Cykesiopka,mgoodwin draft
authorDavid Keeler <dkeeler@mozilla.com>
Tue, 09 Feb 2016 10:14:27 -0800
changeset 335869 a4181cf5e1a2909284fccf427295132387104865
parent 335780 a4929411c0aa3ec6b727e2bc2fc050c8199c6573
child 515234 b6d8cbaaaccb6bf079f8a38d0a37ef815bb6d867
push id11897
push userdkeeler@mozilla.com
push dateTue, 01 Mar 2016 19:17:46 +0000
reviewersCykesiopka, mgoodwin
bugs1245280
milestone47.0a1
bug 1245280 - add policy mechanism to optionally enforce BRs for falling back to subject CN r?Cykesiopka,mgoodwin MozReview-Commit-ID: 7xT6JGpOH1g
security/certverifier/BRNameMatchingPolicy.cpp
security/certverifier/BRNameMatchingPolicy.h
security/certverifier/CertVerifier.cpp
security/certverifier/CertVerifier.h
security/certverifier/moz.build
security/manager/ssl/SSLServerCertVerification.cpp
security/manager/ssl/SharedCertVerifier.h
security/manager/ssl/nsNSSComponent.cpp
security/manager/ssl/tests/unit/moz.build
security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem.certspec
security/manager/ssl/tests/unit/test_baseline_requirements/cn-contains-extra-entry-old.pem.certspec
security/manager/ssl/tests/unit/test_baseline_requirements/cn-contains-extra-entry-recent.pem.certspec
security/manager/ssl/tests/unit/test_baseline_requirements/moz.build
security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-badca.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-pinningroot.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-badca.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-pinningroot.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-badca.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-pinningroot.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-badca.pem.certspec
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-pinningroot.pem.certspec
security/manager/ssl/tests/unit/xpcshell.ini
security/pkix/include/pkix/pkix.h
security/pkix/include/pkix/pkixtypes.h
security/pkix/lib/pkixnames.cpp
security/pkix/test/gtest/pkixgtest.h
security/pkix/test/gtest/pkixnames_tests.cpp
new file mode 100644
--- /dev/null
+++ b/security/certverifier/BRNameMatchingPolicy.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "BRNameMatchingPolicy.h"
+
+#include "mozilla/Assertions.h"
+
+using namespace mozilla::psm;
+using namespace mozilla::pkix;
+
+Result
+BRNameMatchingPolicy::FallBackToCommonName(
+  Time notBefore,
+  /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName)
+{
+  // (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::EnforceAfter23August2016:
+      fallBackToCommonName = AUGUST_23_2016 < notBefore
+                           ? FallBackToSearchWithinSubject::No
+                           : FallBackToSearchWithinSubject::Yes;
+      break;
+    case Mode::DoNotEnforce:
+      fallBackToCommonName = FallBackToSearchWithinSubject::Yes;
+      break;
+    default:
+      MOZ_CRASH("Unexpected Mode");
+  }
+  return Success;
+}
new file mode 100644
--- /dev/null
+++ b/security/certverifier/BRNameMatchingPolicy.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_psm__BRNameMatchingPolicy_h
+#define mozilla_psm__BRNameMatchingPolicy_h
+
+#include "pkix/pkixtypes.h"
+
+namespace mozilla { namespace psm {
+
+class BRNameMatchingPolicy : public mozilla::pkix::NameMatchingPolicy
+{
+public:
+  enum class Mode {
+    Enforce = 0,
+    EnforceAfter23August2016 = 1,
+    DoNotEnforce = 2,
+  };
+
+  explicit BRNameMatchingPolicy(Mode mode)
+    : mMode(mode)
+  {
+  }
+
+  virtual mozilla::pkix::Result FallBackToCommonName(
+    mozilla::pkix::Time notBefore,
+    /*out*/ mozilla::pkix::FallBackToSearchWithinSubject& fallBacktoCommonName)
+    override;
+
+private:
+  Mode mMode;
+};
+
+} } // namespace mozilla::psm
+
+#endif // mozilla_psm__BRNameMatchingPolicy_h
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -3,16 +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/. */
 
 #include "CertVerifier.h"
 
 #include <stdint.h>
 
+#include "BRNameMatchingPolicy.h"
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
 #include "NSSErrorsService.h"
 #include "cert.h"
 #include "pk11pub.h"
 #include "pkix/pkix.h"
 #include "pkix/pkixnss.h"
 #include "prerror.h"
@@ -30,23 +31,25 @@ const CertVerifier::Flags CertVerifier::
 const CertVerifier::Flags CertVerifier::FLAG_MUST_BE_EV = 2;
 const CertVerifier::Flags CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST = 4;
 
 CertVerifier::CertVerifier(OcspDownloadConfig odc,
                            OcspStrictConfig osc,
                            OcspGetConfig ogc,
                            uint32_t certShortLifetimeInDays,
                            PinningMode pinningMode,
-                           SHA1Mode sha1Mode)
+                           SHA1Mode sha1Mode,
+                           BRNameMatchingPolicy::Mode nameMatchingMode)
   : mOCSPDownloadConfig(odc)
   , mOCSPStrict(osc == ocspStrict)
   , mOCSPGETEnabled(ogc == ocspGetEnabled)
   , mCertShortLifetimeInDays(certShortLifetimeInDays)
   , mPinningMode(pinningMode)
   , mSHA1Mode(sha1Mode)
+  , mNameMatchingMode(nameMatchingMode)
 {
 }
 
 CertVerifier::~CertVerifier()
 {
 }
 
 void
@@ -691,17 +694,18 @@ CertVerifier::VerifySSLServerCert(CERTCe
   }
 
   Input hostnameInput;
   result = hostnameInput.Init(uint8_t_ptr_cast(hostname), strlen(hostname));
   if (result != Success) {
     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
     return SECFailure;
   }
-  result = CheckCertHostname(peerCertInput, hostnameInput);
+  BRNameMatchingPolicy nameMatchingPolicy(mNameMatchingMode);
+  result = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy);
   if (result != Success) {
     // Treat malformed name information as a domain mismatch.
     if (result == Result::ERROR_BAD_DER) {
       PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
     } else {
       PR_SetError(MapResultToPRErrorCode(result), 0);
     }
     return SECFailure;
--- a/security/certverifier/CertVerifier.h
+++ b/security/certverifier/CertVerifier.h
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_psm__CertVerifier_h
 #define mozilla_psm__CertVerifier_h
 
+#include "BRNameMatchingPolicy.h"
 #include "mozilla/Telemetry.h"
 #include "pkix/pkixtypes.h"
 #include "OCSPCache.h"
 #include "ScopedNSSTypes.h"
 
 namespace mozilla { namespace psm {
 
 // These values correspond to the CERT_CHAIN_KEY_SIZE_STATUS telemetry.
@@ -116,27 +117,29 @@ public:
     ocspOn = 1,
     ocspEVOnly = 2
   };
   enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
   enum OcspGetConfig { ocspGetDisabled = 0, ocspGetEnabled = 1 };
 
   CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
                OcspGetConfig ogc, uint32_t certShortLifetimeInDays,
-               PinningMode pinningMode, SHA1Mode sha1Mode);
+               PinningMode pinningMode, SHA1Mode sha1Mode,
+               BRNameMatchingPolicy::Mode nameMatchingMode);
   ~CertVerifier();
 
   void ClearOCSPCache() { mOCSPCache.Clear(); }
 
   const OcspDownloadConfig mOCSPDownloadConfig;
   const bool mOCSPStrict;
   const bool mOCSPGETEnabled;
   const uint32_t mCertShortLifetimeInDays;
   const PinningMode mPinningMode;
   const SHA1Mode mSHA1Mode;
+  const BRNameMatchingPolicy::Mode mNameMatchingMode;
 
 private:
   OCSPCache mOCSPCache;
 
   // Returns true if the configured SHA1 mode is more restrictive than the given
   // mode. SHA1Mode::Forbidden is more restrictive than any other mode except
   // Forbidden. Next is Before2016, then ImportedRoot, then Allowed.
   // (A mode is never more restrictive than itself.)
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -1,20 +1,22 @@
 # -*- Mode: python; c-basic-offset: 4; 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/.
 
 EXPORTS += [
+    'BRNameMatchingPolicy.h',
     'CertVerifier.h',
     'OCSPCache.h',
 ]
 
 UNIFIED_SOURCES += [
+    'BRNameMatchingPolicy.cpp',
     'CertVerifier.cpp',
     'NSSCertDBTrustDomain.cpp',
     'OCSPCache.cpp',
     'OCSPRequestor.cpp',
     'OCSPVerificationTrustDomain.cpp',
 ]
 
 if not CONFIG['NSS_NO_EV_CERTS']:
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -91,51 +91,50 @@
 // an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because
 // we need the event to interrupt the PR_Poll that may waiting for I/O on the
 // socket for which we are validating the cert.
 
 #include "SSLServerCertVerification.h"
 
 #include <cstring>
 
-#include "pkix/pkix.h"
-#include "pkix/pkixnss.h"
+#include "BRNameMatchingPolicy.h"
 #include "CertVerifier.h"
 #include "CryptoTask.h"
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
-#include "nsIBadCertListener2.h"
-#include "nsICertOverrideService.h"
-#include "nsISiteSecurityService.h"
-#include "nsNSSComponent.h"
-#include "nsNSSIOLayer.h"
-#include "nsNSSShutDown.h"
-
+#include "PSMRunnable.h"
+#include "RootCertificateTelemetryUtils.h"
+#include "SharedSSLState.h"
+#include "cert.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/net/DNS.h"
-#include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
+#include "nsIBadCertListener2.h"
+#include "nsICertOverrideService.h"
+#include "nsISiteSecurityService.h"
+#include "nsISocketProvider.h"
 #include "nsIThreadPool.h"
-#include "nsISocketProvider.h"
-#include "nsXPCOMCIDInternal.h"
-#include "nsComponentManagerUtils.h"
+#include "nsNSSComponent.h"
+#include "nsNSSIOLayer.h"
+#include "nsNSSShutDown.h"
 #include "nsServiceManagerUtils.h"
-#include "PSMRunnable.h"
-#include "RootCertificateTelemetryUtils.h"
-#include "SharedSSLState.h"
-#include "nsContentUtils.h"
 #include "nsURLHelper.h"
-
-#include "ssl.h"
-#include "cert.h"
+#include "nsXPCOMCIDInternal.h"
+#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
 #include "secerr.h"
 #include "secoidt.h"
 #include "secport.h"
+#include "ssl.h"
 #include "sslerr.h"
 
 extern PRLogModuleInfo* gPIPNSSLog;
 
 using namespace mozilla::pkix;
 
 namespace mozilla { namespace psm {
 
@@ -427,23 +426,38 @@ DetermineCertOverrideErrors(CERTCertific
     }
     Input hostnameInput;
     Result result = hostnameInput.Init(uint8_t_ptr_cast(hostName),
                                        strlen(hostName));
     if (result != Success) {
       PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
       return SECFailure;
     }
-    result = CheckCertHostname(certInput, hostnameInput);
+    // Use a lax policy so as to not generate potentially spurrious name
+    // mismatch "hints".
+    BRNameMatchingPolicy nameMatchingPolicy(
+      BRNameMatchingPolicy::Mode::DoNotEnforce);
+    // CheckCertHostname expects that its input represents a certificate that
+    // has already been successfully validated by BuildCertChain. This is
+    // obviously not the case, however, because we're in the error path of
+    // certificate verification. Thus, this is problematic. In the future, it
+    // would be nice to remove this optimistic additional error checking and
+    // simply punt to the front-end, which can more easily (and safely) perform
+    // extra checks to give the user hints as to why verification failed.
+    result = CheckCertHostname(certInput, hostnameInput, nameMatchingPolicy);
     // Treat malformed name information as a domain mismatch.
     if (result == Result::ERROR_BAD_DER ||
         result == Result::ERROR_BAD_CERT_DOMAIN) {
       collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
-    } else if (result != Success) {
+    } else if (IsFatalError(result)) {
+      // Because its input has not been validated by BuildCertChain,
+      // CheckCertHostname can return an error that is less important than the
+      // original certificate verification error. Only return an error result
+      // from this function if we've encountered a fatal error.
       PR_SetError(MapResultToPRErrorCode(result), 0);
       return SECFailure;
     }
   }
 
   return SECSuccess;
 }
 
--- a/security/manager/ssl/SharedCertVerifier.h
+++ b/security/manager/ssl/SharedCertVerifier.h
@@ -16,18 +16,19 @@ class SharedCertVerifier : public mozill
 protected:
   ~SharedCertVerifier();
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedCertVerifier)
 
   SharedCertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
                      OcspGetConfig ogc, uint32_t certShortLifetimeInDays,
-                     PinningMode pinningMode, SHA1Mode sha1Mode)
+                     PinningMode pinningMode, SHA1Mode sha1Mode,
+                     BRNameMatchingPolicy::Mode nameMatchingMode)
     : mozilla::psm::CertVerifier(odc, osc, ogc, certShortLifetimeInDays,
-                                 pinningMode, sha1Mode)
+                                 pinningMode, sha1Mode, nameMatchingMode)
   {
   }
 };
 
 } } // namespace mozilla::psm
 
 #endif // mozilla_psm__SharedCertVerifier_h
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -871,26 +871,40 @@ void nsNSSComponent::setValidationOption
     case CertVerifier::SHA1Mode::Forbidden:
     case CertVerifier::SHA1Mode::Before2016:
     case CertVerifier::SHA1Mode::ImportedRoot:
       break;
     default:
       sha1Mode = CertVerifier::SHA1Mode::Allowed;
   }
 
+  BRNameMatchingPolicy::Mode nameMatchingMode =
+    static_cast<BRNameMatchingPolicy::Mode>
+      (Preferences::GetInt("security.name_matching_mode",
+                           static_cast<int32_t>(BRNameMatchingPolicy::Mode::DoNotEnforce)));
+  switch (nameMatchingMode) {
+    case BRNameMatchingPolicy::Mode::Enforce:
+    case BRNameMatchingPolicy::Mode::EnforceAfter23August2016:
+    case BRNameMatchingPolicy::Mode::DoNotEnforce:
+      break;
+    default:
+      nameMatchingMode = BRNameMatchingPolicy::Mode::DoNotEnforce;
+  }
+
   CertVerifier::OcspDownloadConfig odc;
   CertVerifier::OcspStrictConfig osc;
   CertVerifier::OcspGetConfig ogc;
   uint32_t certShortLifetimeInDays;
 
   GetRevocationBehaviorFromPrefs(&odc, &osc, &ogc, &certShortLifetimeInDays,
                                  lock);
   mDefaultCertVerifier = new SharedCertVerifier(odc, osc, ogc,
                                                 certShortLifetimeInDays,
-                                                pinningMode, sha1Mode);
+                                                pinningMode, sha1Mode,
+                                                nameMatchingMode);
 }
 
 // Enable the TLS versions given in the prefs, defaulting to TLS 1.0 (min) and
 // TLS 1.2 (max) when the prefs aren't set or set to invalid values.
 nsresult
 nsNSSComponent::setEnabledTLSVersions()
 {
   // keep these values in sync with security-prefs.js
@@ -1320,17 +1334,18 @@ nsNSSComponent::Observe(nsISupports* aSu
       ConfigureTLSSessionIdentifiers();
     } else if (prefName.EqualsLiteral("security.OCSP.enabled") ||
                prefName.EqualsLiteral("security.OCSP.require") ||
                prefName.EqualsLiteral("security.OCSP.GET.enabled") ||
                prefName.EqualsLiteral("security.pki.cert_short_lifetime_in_days") ||
                prefName.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
                prefName.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
                prefName.EqualsLiteral("security.cert_pinning.enforcement_level") ||
-               prefName.EqualsLiteral("security.pki.sha1_enforcement_level")) {
+               prefName.EqualsLiteral("security.pki.sha1_enforcement_level") ||
+               prefName.EqualsLiteral("security.name_matching_mode")) {
       MutexAutoLock lock(mutex);
       setValidationOptions(false, lock);
     } else {
       clearSessionCache = false;
     }
     if (clearSessionCache)
       SSL_ClearSessionCache();
   }
--- a/security/manager/ssl/tests/unit/moz.build
+++ b/security/manager/ssl/tests/unit/moz.build
@@ -7,16 +7,17 @@
 DIRS += ['tlsserver']
 
 if not CONFIG['MOZ_NO_SMART_CARDS']:
     DIRS += ['pkcs11testmodule']
 
 TEST_DIRS += [
     'bad_certs',
     'ocsp_certs',
+    'test_baseline_requirements',
     'test_cert_eku',
     'test_cert_embedded_null',
     'test_cert_keyUsage',
     'test_cert_sha1',
     'test_cert_signatures',
     'test_cert_trust',
     'test_cert_version',
     'test_ev_certs',
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/cn-contains-extra-entry-old.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:example.com
+validity:20160724-20160924
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/cn-contains-extra-entry-recent.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:example.com
+validity:20160824-20160924
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; c-basic-offset: 4; 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/.
+
+test_certificates = (
+    'ca.pem',
+    'cn-contains-extra-entry-old.pem',
+    'cn-contains-extra-entry-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_subject_common_name.js
@@ -0,0 +1,51 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// 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/.
+
+// Tests that the baseline requirements for the subject common name field of
+// certificates are appropriately enforced based on the preference
+// security.name_matching_mode.
+
+"use strict";
+
+do_get_profile();
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+                  .getService(Ci.nsIX509CertDB);
+
+function certFromFile(certName) {
+  return constructCertFromFile(`test_baseline_requirements/${certName}.pem`);
+}
+
+function loadCertWithTrust(certName, trustString) {
+  addCertFromFile(gCertDB, `test_baseline_requirements/${certName}.pem`, trustString);
+}
+
+function checkCert(cert, expectedResult) {
+  // (new Date("25 August 2016")).getTime() / 1000
+  const VALIDATION_TIME = 1472108400;
+  checkCertErrorGenericAtTime(gCertDB, cert, expectedResult,
+                              certificateUsageSSLServer, VALIDATION_TIME, {},
+                              "example.com");
+}
+
+function run_test() {
+  loadCertWithTrust("ca", "CTu,,");
+
+  // Enforce BRv1.3.3 section 7.1.4.2.2.a
+  Services.prefs.setIntPref("security.name_matching_mode", 0);
+  checkCert(certFromFile("cn-contains-extra-entry-recent"), SSL_ERROR_BAD_CERT_DOMAIN);
+  checkCert(certFromFile("cn-contains-extra-entry-old"), SSL_ERROR_BAD_CERT_DOMAIN);
+
+  // Enforce BRv1.3.3 section 7.1.4.2.2.a if notBefore > 23 August 2016
+  Services.prefs.setIntPref("security.name_matching_mode", 1);
+  checkCert(certFromFile("cn-contains-extra-entry-recent"), SSL_ERROR_BAD_CERT_DOMAIN);
+  checkCert(certFromFile("cn-contains-extra-entry-old"), PRErrorCodeSuccess);
+
+  // Do not enforce BRv1.3.3 section 7.1.4.2.2.a
+  Services.prefs.setIntPref("security.name_matching_mode", 2);
+  checkCert(certFromFile("cn-contains-extra-entry-recent"), PRErrorCodeSuccess);
+  checkCert(certFromFile("cn-contains-extra-entry-old"), PRErrorCodeSuccess);
+}
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-badca.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-badca.pem.certspec
@@ -1,4 +1,5 @@
 issuer:badca
 subject:a.pinning2.example.com
 issuerKey:alternate
 subjectKey:alternate
+extension:subjectAlternativeName:a.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-pinningroot.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-pinningroot.pem.certspec
@@ -1,3 +1,4 @@
 issuer:pinningroot
 subject:a.pinning2.example.com
 subjectKey:alternate
+extension:subjectAlternativeName:a.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-badca.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-badca.pem.certspec
@@ -1,4 +1,5 @@
 issuer:badca
 subject:b.pinning2.example.com
 issuerKey:alternate
 subjectKey:alternate
+extension:subjectAlternativeName:b.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-pinningroot.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-pinningroot.pem.certspec
@@ -1,3 +1,4 @@
 issuer:pinningroot
 subject:b.pinning2.example.com
 subjectKey:alternate
+extension:subjectAlternativeName:b.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-badca.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-badca.pem.certspec
@@ -1,4 +1,5 @@
 issuer:badca
 subject:x.a.pinning2.example.com
 issuerKey:alternate
 subjectKey:alternate
+extension:subjectAlternativeName:x.a.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-pinningroot.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-pinningroot.pem.certspec
@@ -1,3 +1,4 @@
 issuer:pinningroot
 subject:x.a.pinning2.example.com
 subjectKey:alternate
+extension:subjectAlternativeName:x.a.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-badca.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-badca.pem.certspec
@@ -1,4 +1,5 @@
 issuer:badca
 subject:x.b.pinning2.example.com
 issuerKey:alternate
 subjectKey:alternate
+extension:subjectAlternativeName:x.b.pinning2.example.com
--- a/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-pinningroot.pem.certspec
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-pinningroot.pem.certspec
@@ -1,3 +1,4 @@
 issuer:pinningroot
 subject:x.b.pinning2.example.com
 subjectKey:alternate
+extension:subjectAlternativeName:x.b.pinning2.example.com
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 head = head_psm.js
 tail =
 tags = psm
 support-files =
   ocsp_common/**
+  test_baseline_requirements/**
   test_cert_eku/**
   test_cert_embedded_null/**
   test_cert_keyUsage/**
   test_cert_sha1/**
   test_cert_signatures/**
   test_cert_trust/**
   test_cert_version/**
   test_certviewer_invalid_oids/**
@@ -22,16 +23,17 @@ support-files =
   test_ocsp_url/**
   test_onecrl/**
   test_pinning_dynamic/**
   test_signed_apps/**
   test_validity/**
   tlsserver/**
 
 [test_add_preexisting_cert.js]
+[test_baseline_requirements_subject_common_name.js]
 [test_cert_blocklist.js]
 skip-if = buildapp == "b2g"
 tags = addons psm
 [test_cert_chains.js]
 run-sequentially = hardcoded ports
 [test_cert_dbKey.js]
 [test_cert_eku.js]
 [test_cert_embedded_null.js]
--- a/security/pkix/include/pkix/pkix.h
+++ b/security/pkix/include/pkix/pkix.h
@@ -111,17 +111,18 @@ Result BuildCertChain(TrustDomain& trust
                       /*optional*/ const Input* stapledOCSPResponse);
 
 // Verify that the given end-entity cert, which is assumed to have been already
 // validated with BuildCertChain, is valid for the given hostname. The matching
 // function attempts to implement RFC 6125 with a couple of differences:
 // - IP addresses are out of scope of RFC 6125, but this method accepts them for
 //   backward compatibility (see SearchNames in pkixnames.cpp)
 // - A wildcard in a DNS-ID may only appear as the entirety of the first label.
-Result CheckCertHostname(Input cert, Input hostname);
+Result CheckCertHostname(Input cert, Input hostname,
+                         NameMatchingPolicy& nameMatchingPolicy);
 
 // Construct an RFC-6960-encoded OCSP request, ready for submission to a
 // responder, for the provided CertID. The request has no extensions.
 static const size_t OCSP_REQUEST_MAX_LENGTH = 127;
 Result CreateEncodedOCSPRequest(TrustDomain& trustDomain,
                                 const CertID& certID,
                                 /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
                                 /*out*/ size_t& outLen);
--- a/security/pkix/include/pkix/pkixtypes.h
+++ b/security/pkix/include/pkix/pkixtypes.h
@@ -344,11 +344,35 @@ public:
                            size_t digestBufLen) = 0;
 protected:
   TrustDomain() { }
 
   TrustDomain(const TrustDomain&) = delete;
   void operator=(const TrustDomain&) = delete;
 };
 
+enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 };
+
+// Applications control the behavior of matching presented name information from
+// a certificate against a reference hostname by implementing the
+// NameMatchingPolicy interface. Used in concert with CheckCertHostname.
+class NameMatchingPolicy
+{
+public:
+  virtual ~NameMatchingPolicy() { }
+
+  // Given that the certificate in question has a notBefore field with the given
+  // value, should name matching fall back to searching within the subject
+  // common name field?
+  virtual Result FallBackToCommonName(
+    Time notBefore,
+    /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0;
+
+protected:
+  NameMatchingPolicy() { }
+
+  NameMatchingPolicy(const NameMatchingPolicy&) = delete;
+  void operator=(const NameMatchingPolicy&) = delete;
+};
+
 } } // namespace mozilla::pkix
 
 #endif // mozilla_pkix_pkixtypes_h
--- a/security/pkix/lib/pkixnames.cpp
+++ b/security/pkix/lib/pkixnames.cpp
@@ -109,18 +109,16 @@ ReadGeneralName(Reader& reader,
       generalNameType = GeneralNameType::registeredID;
       break;
     default:
       return Result::ERROR_BAD_DER;
   }
   return Success;
 }
 
-enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 };
-
 enum class MatchResult
 {
   NoNamesOfGivenType = 0,
   Mismatch = 1,
   Match = 2
 };
 
 Result SearchNames(const Input* subjectAltName, Input subject,
@@ -214,24 +212,37 @@ MatchPresentedDNSIDWithReferenceDNSID(In
            referenceDNSID, matches);
 }
 
 // Verify that the given end-entity cert, which is assumed to have been already
 // validated with BuildCertChain, is valid for the given hostname. hostname is
 // assumed to be a string representation of an IPv4 address, an IPv6 addresss,
 // or a normalized ASCII (possibly punycode) DNS name.
 Result
-CheckCertHostname(Input endEntityCertDER, Input hostname)
+CheckCertHostname(Input endEntityCertDER, Input hostname,
+                  NameMatchingPolicy& nameMatchingPolicy)
 {
   BackCert cert(endEntityCertDER, EndEntityOrCA::MustBeEndEntity, nullptr);
   Result rv = cert.Init();
   if (rv != Success) {
     return rv;
   }
 
+  Time notBefore(Time::uninitialized);
+  rv = ParseValidity(cert.GetValidity(), &notBefore);
+  if (rv != Success) {
+    return rv;
+  }
+  FallBackToSearchWithinSubject fallBackToSearchWithinSubject;
+  rv = nameMatchingPolicy.FallBackToCommonName(notBefore,
+                                               fallBackToSearchWithinSubject);
+  if (rv != Success) {
+    return rv;
+  }
+
   const Input* subjectAltName(cert.GetSubjectAltName());
   Input subject(cert.GetSubject());
 
   // For backward compatibility with legacy certificates, we fall back to
   // searching for a name match in the subject common name for DNS names and
   // IPv4 addresses. We don't do so for IPv6 addresses because we do not think
   // there are many certificates that would need such fallback, and because
   // comparisons of string representations of IPv6 addresses are particularly
@@ -239,23 +250,23 @@ CheckCertHostname(Input endEntityCertDER
   //
   // IPv4 and IPv6 addresses are represented using the same type of GeneralName
   // (iPAddress); they are differentiated by the lengths of the values.
   MatchResult match;
   uint8_t ipv6[16];
   uint8_t ipv4[4];
   if (IsValidReferenceDNSID(hostname)) {
     rv = SearchNames(subjectAltName, subject, GeneralNameType::dNSName,
-                     hostname, FallBackToSearchWithinSubject::Yes, match);
+                     hostname, fallBackToSearchWithinSubject, match);
   } else if (ParseIPv6Address(hostname, ipv6)) {
     rv = SearchNames(subjectAltName, subject, GeneralNameType::iPAddress,
                      Input(ipv6), FallBackToSearchWithinSubject::No, match);
   } else if (ParseIPv4Address(hostname, ipv4)) {
     rv = SearchNames(subjectAltName, subject, GeneralNameType::iPAddress,
-                     Input(ipv4), FallBackToSearchWithinSubject::Yes, match);
+                     Input(ipv4), fallBackToSearchWithinSubject, match);
   } else {
     return Result::ERROR_BAD_CERT_DOMAIN;
   }
   if (rv != Success) {
     return rv;
   }
   switch (match) {
     case MatchResult::NoNamesOfGivenType: // fall through
--- a/security/pkix/test/gtest/pkixgtest.h
+++ b/security/pkix/test/gtest/pkixgtest.h
@@ -211,11 +211,22 @@ class DefaultCryptoTrustDomain : public 
 
   Result CheckValidityIsAcceptable(Time, Time, EndEntityOrCA, KeyPurposeId)
                                    override
   {
     return Success;
   }
 };
 
+class DefaultNameMatchingPolicy : public NameMatchingPolicy
+{
+public:
+  virtual Result FallBackToCommonName(
+    Time, /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) override
+  {
+    fallBackToCommonName = FallBackToSearchWithinSubject::Yes;
+    return Success;
+  }
+};
+
 } } } // namespace mozilla::pkix::test
 
 #endif // mozilla_pkix_pkixgtest_h
--- a/security/pkix/test/gtest/pkixnames_tests.cpp
+++ b/security/pkix/test/gtest/pkixnames_tests.cpp
@@ -897,16 +897,18 @@ static const IPAddressParams<16> IPV6_AD
   IPV6_INVALID("::1.2.3.4\0"),
   IPV6_INVALID("::1.2\02.3.4"),
 };
 
 class pkixnames_MatchPresentedDNSIDWithReferenceDNSID
   : public ::testing::Test
   , public ::testing::WithParamInterface<PresentedMatchesReference>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_MatchPresentedDNSIDWithReferenceDNSID,
        MatchPresentedDNSIDWithReferenceDNSID)
 {
   const PresentedMatchesReference& param(GetParam());
   SCOPED_TRACE(param.presentedDNSID.c_str());
   SCOPED_TRACE(param.referenceDNSID.c_str());
@@ -932,16 +934,18 @@ TEST_P(pkixnames_MatchPresentedDNSIDWith
 INSTANTIATE_TEST_CASE_P(pkixnames_MatchPresentedDNSIDWithReferenceDNSID,
                         pkixnames_MatchPresentedDNSIDWithReferenceDNSID,
                         testing::ValuesIn(DNSID_MATCH_PARAMS));
 
 class pkixnames_Turkish_I_Comparison
   : public ::testing::Test
   , public ::testing::WithParamInterface<InputValidity>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_Turkish_I_Comparison, MatchPresentedDNSIDWithReferenceDNSID)
 {
   // Make sure we don't have the similar problems that strcasecmp and others
   // have with the other kinds of "i" and "I" commonly used in Turkish locales.
 
   const InputValidity& inputValidity(GetParam());
@@ -977,16 +981,18 @@ TEST_P(pkixnames_Turkish_I_Comparison, M
 INSTANTIATE_TEST_CASE_P(pkixnames_Turkish_I_Comparison,
                         pkixnames_Turkish_I_Comparison,
                         testing::ValuesIn(DNSNAMES_VALIDITY_TURKISH_I));
 
 class pkixnames_IsValidReferenceDNSID
   : public ::testing::Test
   , public ::testing::WithParamInterface<InputValidity>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_IsValidReferenceDNSID, IsValidReferenceDNSID)
 {
   const InputValidity& inputValidity(GetParam());
   SCOPED_TRACE(inputValidity.input.c_str());
   Input input;
   ASSERT_EQ(Success, input.Init(inputValidity.input.data(),
@@ -1001,16 +1007,18 @@ INSTANTIATE_TEST_CASE_P(pkixnames_IsVali
 INSTANTIATE_TEST_CASE_P(pkixnames_IsValidReferenceDNSID_Turkish_I,
                         pkixnames_IsValidReferenceDNSID,
                         testing::ValuesIn(DNSNAMES_VALIDITY_TURKISH_I));
 
 class pkixnames_ParseIPv4Address
   : public ::testing::Test
   , public ::testing::WithParamInterface<IPAddressParams<4>>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_ParseIPv4Address, ParseIPv4Address)
 {
   const IPAddressParams<4>& param(GetParam());
   SCOPED_TRACE(param.input.c_str());
   Input input;
   ASSERT_EQ(Success, input.Init(param.input.data(),
@@ -1027,16 +1035,18 @@ TEST_P(pkixnames_ParseIPv4Address, Parse
 INSTANTIATE_TEST_CASE_P(pkixnames_ParseIPv4Address,
                         pkixnames_ParseIPv4Address,
                         testing::ValuesIn(IPV4_ADDRESSES));
 
 class pkixnames_ParseIPv6Address
   : public ::testing::Test
   , public ::testing::WithParamInterface<IPAddressParams<16>>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_ParseIPv6Address, ParseIPv6Address)
 {
   const IPAddressParams<16>& param(GetParam());
   SCOPED_TRACE(param.input.c_str());
   Input input;
   ASSERT_EQ(Success, input.Init(param.input.data(),
@@ -1069,16 +1079,18 @@ struct CheckCertHostnameParams
   ByteString subjectAltName;
   Result result;
 };
 
 class pkixnames_CheckCertHostname
   : public ::testing::Test
   , public ::testing::WithParamInterface<CheckCertHostnameParams>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 #define WITH_SAN(r, ps, psan, result) \
   { \
     ByteString(reinterpret_cast<const uint8_t*>(r), sizeof(r) - 1), \
     ps, \
     psan, \
     result \
@@ -1561,17 +1573,18 @@ TEST_P(pkixnames_CheckCertHostname, Chec
   ASSERT_FALSE(ENCODING_FAILED(cert));
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
 
   Input hostnameInput;
   ASSERT_EQ(Success, hostnameInput.Init(param.hostname.data(),
                                         param.hostname.length()));
 
-  ASSERT_EQ(param.result, CheckCertHostname(certInput, hostnameInput));
+  ASSERT_EQ(param.result, CheckCertHostname(certInput, hostnameInput,
+                                            mNameMatchingPolicy));
 }
 
 INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname,
                         pkixnames_CheckCertHostname,
                         testing::ValuesIn(CHECK_CERT_HOSTNAME_PARAMS));
 
 TEST_F(pkixnames_CheckCertHostname, SANWithoutSequence)
 {
@@ -1593,23 +1606,25 @@ TEST_F(pkixnames_CheckCertHostname, SANW
                        Name(RDN(CN("a"))), *keyPair, extensions,
                        *keyPair, sha256WithRSAEncryption()));
   ASSERT_FALSE(ENCODING_FAILED(certDER));
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length()));
 
   static const uint8_t a[] = { 'a' };
   ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
-            CheckCertHostname(certInput, Input(a)));
+            CheckCertHostname(certInput, Input(a), mNameMatchingPolicy));
 }
 
 class pkixnames_CheckCertHostname_PresentedMatchesReference
   : public ::testing::Test
   , public ::testing::WithParamInterface<PresentedMatchesReference>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_CheckCertHostname_PresentedMatchesReference, CN_NoSAN)
 {
   // Since there is no SAN, a valid presented DNS ID in the subject CN field
   // should result in a match.
 
   const PresentedMatchesReference& param(GetParam());
@@ -1619,17 +1634,17 @@ TEST_P(pkixnames_CheckCertHostname_Prese
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
 
   Input hostnameInput;
   ASSERT_EQ(Success, hostnameInput.Init(param.referenceDNSID.data(),
                                         param.referenceDNSID.length()));
 
   ASSERT_EQ(param.expectedMatches ? Success : Result::ERROR_BAD_CERT_DOMAIN,
-            CheckCertHostname(certInput, hostnameInput));
+            CheckCertHostname(certInput, hostnameInput, mNameMatchingPolicy));
 }
 
 TEST_P(pkixnames_CheckCertHostname_PresentedMatchesReference,
        SubjectAltName_CNNotDNSName)
 {
   // A DNSName SAN entry should match, regardless of the contents of the
   // subject CN.
 
@@ -1643,17 +1658,18 @@ TEST_P(pkixnames_CheckCertHostname_Prese
 
   Input hostnameInput;
   ASSERT_EQ(Success, hostnameInput.Init(param.referenceDNSID.data(),
                                         param.referenceDNSID.length()));
   Result expectedResult
     = param.expectedResult != Success ? param.expectedResult
     : param.expectedMatches ? Success
     : Result::ERROR_BAD_CERT_DOMAIN;
-  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, hostnameInput));
+  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, hostnameInput,
+                                              mNameMatchingPolicy));
 }
 
 INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname_DNSID_MATCH_PARAMS,
                         pkixnames_CheckCertHostname_PresentedMatchesReference,
                         testing::ValuesIn(DNSID_MATCH_PARAMS));
 
 TEST_P(pkixnames_Turkish_I_Comparison, CheckCertHostname_CN_NoSAN)
 {
@@ -1672,18 +1688,20 @@ TEST_P(pkixnames_Turkish_I_Comparison, C
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
 
   Result expectedResult = (InputsAreEqual(LOWERCASE_I, input) ||
                            InputsAreEqual(UPPERCASE_I, input))
                         ? Success
                         : Result::ERROR_BAD_CERT_DOMAIN;
 
-  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, UPPERCASE_I));
-  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, LOWERCASE_I));
+  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, UPPERCASE_I,
+                                              mNameMatchingPolicy));
+  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, LOWERCASE_I,
+                                              mNameMatchingPolicy));
 }
 
 TEST_P(pkixnames_Turkish_I_Comparison, CheckCertHostname_SAN)
 {
   // Make sure we don't have the similar problems that strcasecmp and others
   // have with the other kinds of "i" and "I" commonly used in Turkish locales,
   // when we're matching a dNSName in the SAN.
 
@@ -1699,24 +1717,28 @@ TEST_P(pkixnames_Turkish_I_Comparison, C
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
 
   Result expectedResult
     = (!param.isValidPresentedID) ? Result::ERROR_BAD_DER
     : (InputsAreEqual(LOWERCASE_I, input) ||
        InputsAreEqual(UPPERCASE_I, input)) ? Success
     : Result::ERROR_BAD_CERT_DOMAIN;
 
-  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, UPPERCASE_I));
-  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, LOWERCASE_I));
+  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, UPPERCASE_I,
+                                              mNameMatchingPolicy));
+  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, LOWERCASE_I,
+                                              mNameMatchingPolicy));
 }
 
 class pkixnames_CheckCertHostname_IPV4_Addresses
   : public ::testing::Test
   , public ::testing::WithParamInterface<IPAddressParams<4>>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses,
        ValidIPv4AddressInIPAddressSAN)
 {
   // When the reference hostname is a valid IPv4 address, a correctly-formed
   // IPv4 Address SAN matches it.
 
@@ -1728,17 +1750,17 @@ TEST_P(pkixnames_CheckCertHostname_IPV4_
   Input certInput;
   ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
 
   Input hostnameInput;
   ASSERT_EQ(Success, hostnameInput.Init(param.input.data(),
                                         param.input.length()));
 
   ASSERT_EQ(param.isValid ? Success : Result::ERROR_BAD_CERT_DOMAIN,
-            CheckCertHostname(certInput, hostnameInput));
+            CheckCertHostname(certInput, hostnameInput, mNameMatchingPolicy));
 }
 
 TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses,
        ValidIPv4AddressInCN_NoSAN)
 {
   // When the reference hostname is a valid IPv4 address, a correctly-formed
   // IPv4 Address in the CN matches it when there is no SAN.
 
@@ -1755,17 +1777,18 @@ TEST_P(pkixnames_CheckCertHostname_IPV4_
   ASSERT_EQ(Success, hostnameInput.Init(param.input.data(),
                                         param.input.length()));
 
   // Some of the invalid IPv4 addresses are valid DNS names!
   Result expectedResult = (param.isValid || IsValidReferenceDNSID(hostnameInput))
                         ? Success
                         : Result::ERROR_BAD_CERT_DOMAIN;
 
-  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, hostnameInput));
+  ASSERT_EQ(expectedResult, CheckCertHostname(certInput, hostnameInput,
+                                              mNameMatchingPolicy));
 }
 
 INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname_IPV4_ADDRESSES,
                         pkixnames_CheckCertHostname_IPV4_Addresses,
                         testing::ValuesIn(IPV4_ADDRESSES));
 
 struct NameConstraintParams
 {
@@ -2505,16 +2528,18 @@ static const NameConstraintParams NAME_C
     Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
   },
 };
 
 class pkixnames_CheckNameConstraints
   : public ::testing::Test
   , public ::testing::WithParamInterface<NameConstraintParams>
 {
+public:
+  DefaultNameMatchingPolicy mNameMatchingPolicy;
 };
 
 TEST_P(pkixnames_CheckNameConstraints,
        NameConstraintsEnforcedForDirectlyIssuedEndEntity)
 {
   // Test that name constraints are enforced on a certificate directly issued by
   // this certificate.