Kai Engert 23da238
diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp
Kai Engert 23da238
--- a/security/certverifier/CertVerifier.cpp
Kai Engert 23da238
+++ b/security/certverifier/CertVerifier.cpp
Kai Engert 23da238
@@ -120,16 +120,20 @@ IsCertChainRootBuiltInRoot(const UniqueC
Kai Engert 23da238
   }
Kai Engert 23da238
   CERTCertificate* root = rootNode->cert;
Kai Engert 23da238
   if (!root) {
Kai Engert 23da238
     return Result::FATAL_ERROR_LIBRARY_FAILURE;
Kai Engert 23da238
   }
Kai Engert 23da238
   return IsCertBuiltInRoot(root, result);
Kai Engert 23da238
 }
Kai Engert 23da238
 
Kai Engert 23da238
+// The term "builtin root" traditionally refers to a root CA certificate that
Kai Engert 23da238
+// has been added to the NSS trust store, because it has been approved
Kai Engert 23da238
+// for inclusion according to the Mozilla CA policy, and might be accepted
Kai Engert 23da238
+// by Mozilla applications as an issuer for certificates seen on the public web.
Kai Engert 23da238
 Result
Kai Engert 23da238
 IsCertBuiltInRoot(CERTCertificate* cert, bool& result)
Kai Engert 23da238
 {
Kai Engert 23da238
   result = false;
Kai Engert 23da238
 #ifdef DEBUG
Kai Engert 23da238
   nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
Kai Engert 23da238
   if (!component) {
Kai Engert 23da238
     return Result::FATAL_ERROR_LIBRARY_FAILURE;
Kai Engert 23da238
@@ -142,25 +146,38 @@ IsCertBuiltInRoot(CERTCertificate* cert,
Kai Engert 23da238
     return Success;
Kai Engert 23da238
   }
Kai Engert 23da238
 #endif // DEBUG
Kai Engert 23da238
   AutoSECMODListReadLock lock;
Kai Engert 23da238
   for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
Kai Engert 23da238
        list = list->next) {
Kai Engert 23da238
     for (int i = 0; i < list->module->slotCount; i++) {
Kai Engert 23da238
       PK11SlotInfo* slot = list->module->slots[i];
Kai Engert 23da238
-      // PK11_HasRootCerts should return true if and only if the given slot has
Kai Engert 23da238
-      // an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST, which
Kai Engert 23da238
-      // should be true only of the builtin root list.
Kai Engert 23da238
-      // If we can find a copy of the given certificate on the slot with the
Kai Engert 23da238
-      // builtin root list, that certificate must be a builtin.
Kai Engert 23da238
-      if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot) &&
Kai Engert 23da238
-          PK11_FindCertInSlot(slot, cert, nullptr) != CK_INVALID_HANDLE) {
Kai Engert 23da238
-        result = true;
Kai Engert 23da238
-        return Success;
Kai Engert 23da238
+      // We're searching for the "builtin root module", which is a module that
Kai Engert 23da238
+      // contains an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST.
Kai Engert 23da238
+      // We use PK11_HasRootCerts() to identify a module with that property.
Kai Engert 23da238
+      // In the past, we exclusively used the PKCS#11 module named nssckbi,
Kai Engert 23da238
+      // which is provided by the NSS library.
Kai Engert 23da238
+      // Nowadays, some distributions use a replacement module, which contains
Kai Engert 23da238
+      // the builtin roots, but which also contains additional CA certificates,
Kai Engert 23da238
+      // such as CAs trusted in a local deployment.
Kai Engert 23da238
+      // We want to be able to distinguish between these two categories,
Kai Engert 23da238
+      // because a CA, which may issue certificates for the public web,
Kai Engert 23da238
+      // is expected to comply with additional requirements.
Kai Engert 23da238
+      // If the certificate has attribute CKA_NSS_MOZILLA_CA_POLICY set to true,
Kai Engert 23da238
+      // then we treat it as a "builtin root".
Kai Engert 23da238
+      if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) {
Kai Engert 23da238
+        CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, cert, nullptr);
Kai Engert 23da238
+        if (handle != CK_INVALID_HANDLE &&
Kai Engert 23da238
+            PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY,
Kai Engert 23da238
+                                 false)) {
Kai Engert 23da238
+          // Attribute was found, and is set to true
Kai Engert 23da238
+          result = true;
Kai Engert 23da238
+          break;
Kai Engert 23da238
+        }
Kai Engert 23da238
       }
Kai Engert 23da238
     }
Kai Engert 23da238
   }
Kai Engert 23da238
   return Success;
Kai Engert 23da238
 }
Kai Engert 23da238
 
Kai Engert 23da238
 static Result
Kai Engert 23da238
 BuildCertChainForOneKeyUsage(NSSCertDBTrustDomain& trustDomain, Input certDER,