Bug 991783 - Add generic mechanism to add name constraints to built-in certificates r=wtc
authorRichard Barnes <rbarnes@mozilla.com>
Sat, 11 Apr 2015 22:26:44 +0200
changeset 11420 07da6d86695a416e404dfa4ff973fb0ab26ed49b
parent 11419 9fca4f7066f85ea8489552984010929fc29292a7
child 11421 82de44ead36ffc55baf73f9ac2986f6932fe4e9d
push id611
push userkaie@kuix.de
push dateSat, 11 Apr 2015 20:27:12 +0000
reviewerswtc
bugs991783
Bug 991783 - Add generic mechanism to add name constraints to built-in certificates r=wtc
lib/certdb/cert.h
lib/certdb/genname.c
lib/nss/nss.def
--- a/lib/certdb/cert.h
+++ b/lib/certdb/cert.h
@@ -1167,16 +1167,30 @@ extern CERTPrivKeyUsagePeriod *
 CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue);
 
 extern CERTGeneralName *
 CERT_GetNextGeneralName(CERTGeneralName *current);
 
 extern CERTGeneralName *
 CERT_GetPrevGeneralName(CERTGeneralName *current);
 
+/*
+ * Look up name constraints for some certs that do not include name constraints
+ * (Most importantly, root certificates)
+ *
+ * If a matching subject is found, |extensions| will be populated with a copy of the
+ * DER-encoded name constraints extension. The data in |extensions| will point to
+ * memory that the caller owns.
+ *
+ * There is no mechanism to configure imposed name constraints right now.  All
+ * imposed name constraints are built into NSS.
+ */
+SECStatus
+CERT_GetImposedNameConstraints(const SECItem *derSubject, SECItem *extensions);
+
 CERTNameConstraint *
 CERT_GetNextNameConstraint(CERTNameConstraint *current);
 
 CERTNameConstraint *
 CERT_GetPrevNameConstraint(CERTNameConstraint *current);
 
 void
 CERT_DestroyUserNotice(CERTUserNotice *userNotice);
@@ -1538,16 +1552,19 @@ CERT_CopyNameConstraint(PLArenaPool     
  */
 extern SECStatus
 CERT_CheckNameSpace(PLArenaPool          *arena,
 		    const CERTNameConstraints *constraints,
 		    const CERTGeneralName *currentName);
 
 /*
  * Extract and allocate the name constraints extension from the CA cert.
+ * If the certificate contains no name constraints extension, but
+ * CERT_GetImposedNameConstraints returns a name constraints extension
+ * for the subject of the certificate, then that extension will be returned.
  */
 extern SECStatus
 CERT_FindNameConstraintsExten(PLArenaPool      *arena,
 			      CERTCertificate  *cert,
 			      CERTNameConstraints **constraints);
 
 /*
  * Initialize a new GERTGeneralName fields (link)
--- a/lib/certdb/genname.c
+++ b/lib/certdb/genname.c
@@ -1551,86 +1551,108 @@ done:
     if (rv == SECFailure) {
         PORT_ArenaRelease(arena, mark);
     } else {
         PORT_ArenaUnmark(arena, mark);
     }
     return rv;
 }
 
-/* Add name constraints to certain certs that do not include name constraints
- * This is the core of the implementation for bug 952572.
+/*
+ * Here we define a list of name constraints to be imposed on
+ * certain certificates, most importantly root certificates.
+ *
+ * Each entry in the name constraints list is constructed with this
+ * macro.  An entry contains two SECItems, which have names in
+ * specific forms to make the macro work:
+ *
+ *  * ${CA}_SUBJECT_DN - The subject DN for which the constraints
+ *                       should be applied
+ *  * ${CA}_NAME_CONSTRAINTS - The name constraints extension
+ *
+ * Entities subject to name constraints are identified by subject name
+ * so that we can cover all certificates for that entity, including, e.g.,
+ * cross-certificates.  We use subject rather than public key because
+ * calling methods often have easy access to that field (vs., say, a key ID),
+ * and in practice, subject names and public keys are usually in one-to-one
+ * correspondence anyway.
+ *
  */
 
-static SECStatus
-getNameExtensionsBuiltIn(CERTCertificate  *cert,
-                         SECItem *extensions)
+#define STRING_TO_SECITEM(str) \
+{ siBuffer, (unsigned char*) str, sizeof(str) - 1 }
+
+#define NAME_CONSTRAINTS_ENTRY(CA)  \
+    { \
+        STRING_TO_SECITEM(CA ## _SUBJECT_DN), \
+        STRING_TO_SECITEM(CA ## _NAME_CONSTRAINTS) \
+    }
+
+/* Agence Nationale de la Securite des Systemes d'Information (ANSSI) */
+
+#define ANSSI_SUBJECT_DN \
+    "\x30\x81\x85"                                                     \
+    "\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02" "FR"       /* C */  \
+    "\x31\x0F\x30\x0D\x06\x03\x55\x04\x08\x13\x06" "France"   /* ST */ \
+    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05" "Paris"    /* L */  \
+    "\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07" "PM/SGDN"  /* O */  \
+    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13\x05" "DCSSI"    /* OU */ \
+    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x03\x13\x05" "IGC/A"    /* CN */ \
+    "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"     \
+    "\x16\x14" "igca@sgdn.pm.gouv.fr" /* emailAddress */ \
+
+#define ANSSI_NAME_CONSTRAINTS \
+    "\x30\x5D\xA0\x5B"       \
+    "\x30\x05\x82\x03" ".fr" \
+    "\x30\x05\x82\x03" ".gp" \
+    "\x30\x05\x82\x03" ".gf" \
+    "\x30\x05\x82\x03" ".mq" \
+    "\x30\x05\x82\x03" ".re" \
+    "\x30\x05\x82\x03" ".yt" \
+    "\x30\x05\x82\x03" ".pm" \
+    "\x30\x05\x82\x03" ".bl" \
+    "\x30\x05\x82\x03" ".mf" \
+    "\x30\x05\x82\x03" ".wf" \
+    "\x30\x05\x82\x03" ".pf" \
+    "\x30\x05\x82\x03" ".nc" \
+    "\x30\x05\x82\x03" ".tf" \
+
+static const SECItem builtInNameConstraints[][2] = {
+    NAME_CONSTRAINTS_ENTRY(ANSSI)
+};
+
+SECStatus
+CERT_GetImposedNameConstraints(const SECItem *derSubject,
+                               SECItem *extensions)
 {
-  const char constraintFranceGov[] = "\x30\x5D" /* sequence len = 93*/
-                                     "\xA0\x5B" /* element len =91 */
-                                     "\x30\x05" /* sequence len 5 */
-                                     "\x82\x03" /* entry len 3 */
-                                     ".fr"
-                                     "\x30\x05\x82\x03" /* sequence len5, entry len 3 */
-                                     ".gp"
-                                     "\x30\x05\x82\x03"
-                                     ".gf"
-                                     "\x30\x05\x82\x03"
-                                     ".mq"
-                                     "\x30\x05\x82\x03"
-                                     ".re"
-                                     "\x30\x05\x82\x03"
-                                     ".yt"
-                                     "\x30\x05\x82\x03"
-                                     ".pm"
-                                     "\x30\x05\x82\x03"
-                                     ".bl"
-                                     "\x30\x05\x82\x03"
-                                     ".mf"
-                                     "\x30\x05\x82\x03"
-                                     ".wf"
-                                     "\x30\x05\x82\x03"
-                                     ".pf"
-                                     "\x30\x05\x82\x03"
-                                     ".nc"
-                                     "\x30\x05\x82\x03"
-                                     ".tf";
+    size_t i;
+
+    if (!extensions) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
 
-  /* The stringified value for the subject is:
-     E=igca@sgdn.pm.gouv.fr,CN=IGC/A,OU=DCSSI,O=PM/SGDN,L=Paris,ST=France,C=FR
-   */
-  const char rawANSSISubject[] = "\x30\x81\x85\x31\x0B\x30\x09\x06\x03\x55\x04"
-                                 "\x06\x13\x02\x46\x52\x31\x0F\x30\x0D\x06\x03"
-                                 "\x55\x04\x08\x13\x06\x46\x72\x61\x6E\x63\x65"
-                                 "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05"
-                                 "\x50\x61\x72\x69\x73\x31\x10\x30\x0E\x06\x03"
-                                 "\x55\x04\x0A\x13\x07\x50\x4D\x2F\x53\x47\x44"
-                                 "\x4E\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13"
-                                 "\x05\x44\x43\x53\x53\x49\x31\x0E\x30\x0C\x06"
-                                 "\x03\x55\x04\x03\x13\x05\x49\x47\x43\x2F\x41"
-                                 "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7"
-                                 "\x0D\x01\x09\x01\x16\x14\x69\x67\x63\x61\x40"
-                                 "\x73\x67\x64\x6E\x2E\x70\x6D\x2E\x67\x6F\x75"
-                                 "\x76\x2E\x66\x72";
+    for (i = 0; i < PR_ARRAY_SIZE(builtInNameConstraints); ++i) {
+        if (SECITEM_ItemsAreEqual(derSubject, &builtInNameConstraints[i][0])) {
+            return SECITEM_CopyItem(NULL,
+                                    extensions, 
+                                    &builtInNameConstraints[i][1]);
+        }
+    }
 
-  const SECItem anssi_subject = {0, (unsigned char *) rawANSSISubject,
-                                 sizeof(rawANSSISubject)-1};
-  const SECItem permitFranceGovNC = {0, (unsigned char *) constraintFranceGov,
-                                     sizeof(constraintFranceGov)-1};
-
-  if (SECITEM_ItemsAreEqual(&cert->derSubject, &anssi_subject)) {
-    SECStatus rv;
-    rv = SECITEM_CopyItem(NULL, extensions, &permitFranceGovNC);
-    return rv;
-  }
-  PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
-  return SECFailure;
+    PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+    return SECFailure;
 }
 
-/* Extract the name constraints extension from the CA cert. */
+/* 
+ * Extract the name constraints extension from the CA cert.
+ * If the certificate contains no name constraints extension, but
+ * CERT_GetImposedNameConstraints returns a name constraints extension
+ * for the subject of the certificate, then that extension will be returned.
+ */
 SECStatus
 CERT_FindNameConstraintsExten(PLArenaPool      *arena,
                               CERTCertificate  *cert,
                               CERTNameConstraints **constraints)
 {
     SECStatus            rv = SECSuccess;
     SECItem              constraintsExtension;
     void                *mark = NULL;
@@ -1638,17 +1660,18 @@ CERT_FindNameConstraintsExten(PLArenaPoo
     *constraints = NULL;
 
     rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, 
                                 &constraintsExtension);
     if (rv != SECSuccess) {
         if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
             return rv;
         }
-        rv = getNameExtensionsBuiltIn(cert, &constraintsExtension);
+        rv = CERT_GetImposedNameConstraints(&cert->derSubject,
+                                            &constraintsExtension);
         if (rv != SECSuccess) {
           if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
             return SECSuccess;
           }
           return rv;
         }
     }
 
--- a/lib/nss/nss.def
+++ b/lib/nss/nss.def
@@ -1065,8 +1065,14 @@ PK11_PrivDecrypt;
 ;+NSS_3.18 { 	# NSS 3.18 release
 ;+    global:
 __PK11_SetCertificateNickname;
 SEC_CheckCrlTimes;
 SEC_GetCrlTimes;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.18.1 { 	# NSS 3.18.1 release
+;+    global:
+CERT_GetImposedNameConstraints;
+;+    local:
+;+       *;
+;+};