Skip to content

Commit

Permalink
Bug 991783 - Add generic mechanism to add name constraints to built-i…
Browse files Browse the repository at this point in the history
…n certificates r=wtc
  • Loading branch information
Richard Barnes committed Apr 11, 2015
1 parent e69fe10 commit e0982ae
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 66 deletions.
17 changes: 17 additions & 0 deletions lib/certdb/cert.h
Expand Up @@ -1172,6 +1172,20 @@ 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);

Expand Down Expand Up @@ -1543,6 +1557,9 @@ CERT_CheckNameSpace(PLArenaPool *arena,

/*
* 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,
Expand Down
155 changes: 89 additions & 66 deletions lib/certdb/genname.c
Expand Up @@ -1556,76 +1556,98 @@ CERT_AddNameConstraintByGeneralName(PLArenaPool *arena,
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";

/* 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";

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;
size_t i;

if (!extensions) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}

for (i = 0; i < PR_ARRAY_SIZE(builtInNameConstraints); ++i) {
if (SECITEM_ItemsAreEqual(derSubject, &builtInNameConstraints[i][0])) {
return SECITEM_CopyItem(NULL,
extensions,
&builtInNameConstraints[i][1]);
}
}

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,
Expand All @@ -1643,7 +1665,8 @@ CERT_FindNameConstraintsExten(PLArenaPool *arena,
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;
Expand Down
6 changes: 6 additions & 0 deletions lib/nss/nss.def
Expand Up @@ -1070,3 +1070,9 @@ SEC_GetCrlTimes;
;+ local:
;+ *;
;+};
;+NSS_3.18.1 { # NSS 3.18.1 release
;+ global:
CERT_GetImposedNameConstraints;
;+ local:
;+ *;
;+};

0 comments on commit e0982ae

Please sign in to comment.