security/nss/lib/certdb/certdb.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6  * Certificate handling code
     7  */
     9 #include "nssilock.h"
    10 #include "prmon.h"
    11 #include "prtime.h"
    12 #include "cert.h"
    13 #include "certi.h"
    14 #include "secder.h"
    15 #include "secoid.h"
    16 #include "secasn1.h"
    17 #include "genname.h"
    18 #include "keyhi.h"
    19 #include "secitem.h"
    20 #include "certdb.h"
    21 #include "prprf.h"
    22 #include "sechash.h"
    23 #include "prlong.h"
    24 #include "certxutl.h"
    25 #include "portreg.h"
    26 #include "secerr.h"
    27 #include "sslerr.h"
    28 #include "pk11func.h"
    29 #include "xconst.h"   /* for  CERT_DecodeAltNameExtension */
    31 #include "pki.h"
    32 #include "pki3hack.h"
    34 SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
    35 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    36 SEC_ASN1_MKSUB(SEC_BitStringTemplate)
    37 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
    38 SEC_ASN1_MKSUB(SEC_SkipTemplate)
    40 /*
    41  * Certificate database handling code
    42  */
    45 const SEC_ASN1Template CERT_CertExtensionTemplate[] = {
    46     { SEC_ASN1_SEQUENCE,
    47 	  0, NULL, sizeof(CERTCertExtension) },
    48     { SEC_ASN1_OBJECT_ID,
    49 	  offsetof(CERTCertExtension,id) },
    50     { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,		/* XXX DER_DEFAULT */
    51 	  offsetof(CERTCertExtension,critical) },
    52     { SEC_ASN1_OCTET_STRING,
    53 	  offsetof(CERTCertExtension,value) },
    54     { 0, }
    55 };
    57 const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {
    58     { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }
    59 };
    61 const SEC_ASN1Template CERT_TimeChoiceTemplate[] = {
    62   { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
    63   { SEC_ASN1_UTC_TIME, 0, 0, siUTCTime },
    64   { SEC_ASN1_GENERALIZED_TIME, 0, 0, siGeneralizedTime },
    65   { 0 }
    66 };
    68 const SEC_ASN1Template CERT_ValidityTemplate[] = {
    69     { SEC_ASN1_SEQUENCE,
    70 	  0, NULL, sizeof(CERTValidity) },
    71     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    72           offsetof(CERTValidity,notBefore),
    73           SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
    74     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    75           offsetof(CERTValidity,notAfter),
    76           SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
    77     { 0 }
    78 };
    80 const SEC_ASN1Template CERT_CertificateTemplate[] = {
    81     { SEC_ASN1_SEQUENCE,
    82       0, NULL, sizeof(CERTCertificate) },
    83     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
    84 	  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, /* XXX DER_DEFAULT */ 
    85 	  offsetof(CERTCertificate,version),
    86 	  SEC_ASN1_SUB(SEC_IntegerTemplate) },
    87     { SEC_ASN1_INTEGER,
    88 	  offsetof(CERTCertificate,serialNumber) },
    89     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    90 	  offsetof(CERTCertificate,signature),
    91 	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    92     { SEC_ASN1_SAVE, 
    93 	  offsetof(CERTCertificate,derIssuer) },
    94     { SEC_ASN1_INLINE,
    95 	  offsetof(CERTCertificate,issuer),
    96 	  CERT_NameTemplate },
    97     { SEC_ASN1_INLINE,
    98 	  offsetof(CERTCertificate,validity),
    99 	  CERT_ValidityTemplate },
   100     { SEC_ASN1_SAVE,
   101 	  offsetof(CERTCertificate,derSubject) },
   102     { SEC_ASN1_INLINE,
   103 	  offsetof(CERTCertificate,subject),
   104 	  CERT_NameTemplate },
   105     { SEC_ASN1_SAVE,
   106 	  offsetof(CERTCertificate,derPublicKey) },
   107     { SEC_ASN1_INLINE,
   108 	  offsetof(CERTCertificate,subjectPublicKeyInfo),
   109 	  CERT_SubjectPublicKeyInfoTemplate },
   110     { SEC_ASN1_OPTIONAL |  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
   111 	  offsetof(CERTCertificate,issuerID),
   112 	  SEC_ASN1_SUB(SEC_BitStringTemplate) },
   113     { SEC_ASN1_OPTIONAL |  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
   114 	  offsetof(CERTCertificate,subjectID),
   115 	  SEC_ASN1_SUB(SEC_BitStringTemplate) },
   116     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
   117 	  SEC_ASN1_CONTEXT_SPECIFIC | 3,
   118 	  offsetof(CERTCertificate,extensions),
   119 	  CERT_SequenceOfCertExtensionTemplate },
   120     { 0 }
   121 };
   123 const SEC_ASN1Template SEC_SignedCertificateTemplate[] =
   124 {
   125     { SEC_ASN1_SEQUENCE,
   126 	  0, NULL, sizeof(CERTCertificate) },
   127     { SEC_ASN1_SAVE, 
   128 	  offsetof(CERTCertificate,signatureWrap.data) },
   129     { SEC_ASN1_INLINE, 
   130 	  0, CERT_CertificateTemplate },
   131     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   132 	  offsetof(CERTCertificate,signatureWrap.signatureAlgorithm),
   133 	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   134     { SEC_ASN1_BIT_STRING,
   135 	  offsetof(CERTCertificate,signatureWrap.signature) },
   136     { 0 }
   137 };
   139 /*
   140  * Find the subjectName in a DER encoded certificate
   141  */
   142 const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
   143     { SEC_ASN1_SEQUENCE,
   144 	  0, NULL, sizeof(SECItem) },
   145     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
   146 	  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
   147 	  0, SEC_ASN1_SUB(SEC_SkipTemplate) },	/* version */
   148     { SEC_ASN1_SKIP },		/* serial number */
   149     { SEC_ASN1_SKIP },		/* signature algorithm */
   150     { SEC_ASN1_SKIP },		/* issuer */
   151     { SEC_ASN1_SKIP },		/* validity */
   152     { SEC_ASN1_ANY, 0, NULL },		/* subject */
   153     { SEC_ASN1_SKIP_REST },
   154     { 0 }
   155 };
   157 /*
   158  * Find the issuerName in a DER encoded certificate
   159  */
   160 const SEC_ASN1Template SEC_CertIssuerTemplate[] = {
   161     { SEC_ASN1_SEQUENCE,
   162 	  0, NULL, sizeof(SECItem) },
   163     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
   164 	  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
   165 	  0, SEC_ASN1_SUB(SEC_SkipTemplate) },	/* version */
   166     { SEC_ASN1_SKIP },		/* serial number */
   167     { SEC_ASN1_SKIP },		/* signature algorithm */
   168     { SEC_ASN1_ANY, 0, NULL },		/* issuer */
   169     { SEC_ASN1_SKIP_REST },
   170     { 0 }
   171 };
   172 /*
   173  * Find the subjectName in a DER encoded certificate
   174  */
   175 const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {
   176     { SEC_ASN1_SEQUENCE,
   177 	  0, NULL, sizeof(SECItem) },
   178     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
   179 	  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
   180 	  0, SEC_ASN1_SUB(SEC_SkipTemplate) },	/* version */
   181     { SEC_ASN1_ANY, 0, NULL }, /* serial number */
   182     { SEC_ASN1_SKIP_REST },
   183     { 0 }
   184 };
   186 /*
   187  * Find the issuer and serialNumber in a DER encoded certificate.
   188  * This data is used as the database lookup key since its the unique
   189  * identifier of a certificate.
   190  */
   191 const SEC_ASN1Template CERT_CertKeyTemplate[] = {
   192     { SEC_ASN1_SEQUENCE,
   193 	  0, NULL, sizeof(CERTCertKey) },
   194     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
   195 	  SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
   196 	  0, SEC_ASN1_SUB(SEC_SkipTemplate) },	/* version */ 
   197     { SEC_ASN1_INTEGER,
   198 	  offsetof(CERTCertKey,serialNumber) },
   199     { SEC_ASN1_SKIP },		/* signature algorithm */
   200     { SEC_ASN1_ANY,
   201 	  offsetof(CERTCertKey,derIssuer) },
   202     { SEC_ASN1_SKIP_REST },
   203     { 0 }
   204 };
   206 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_TimeChoiceTemplate)
   207 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
   208 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
   209 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate)
   211 SECStatus
   212 CERT_KeyFromIssuerAndSN(PLArenaPool *arena, SECItem *issuer, SECItem *sn,
   213 			SECItem *key)
   214 {
   215     key->len = sn->len + issuer->len;
   217     if ((sn->data == NULL) || (issuer->data == NULL)) {
   218 	goto loser;
   219     }
   221     key->data = (unsigned char*)PORT_ArenaAlloc(arena, key->len);
   222     if ( !key->data ) {
   223 	goto loser;
   224     }
   226     /* copy the serialNumber */
   227     PORT_Memcpy(key->data, sn->data, sn->len);
   229     /* copy the issuer */
   230     PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
   232     return(SECSuccess);
   234 loser:
   235     return(SECFailure);
   236 }
   239 /*
   240  * Extract the subject name from a DER certificate
   241  */
   242 SECStatus
   243 CERT_NameFromDERCert(SECItem *derCert, SECItem *derName)
   244 {
   245     int rv;
   246     PLArenaPool *arena;
   247     CERTSignedData sd;
   248     void *tmpptr;
   250     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   252     if ( ! arena ) {
   253 	return(SECFailure);
   254     }
   256     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
   257     rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
   259     if ( rv ) {
   260 	goto loser;
   261     }
   263     PORT_Memset(derName, 0, sizeof(SECItem));
   264     rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate, &sd.data);
   266     if ( rv ) {
   267 	goto loser;
   268     }
   270     tmpptr = derName->data;
   271     derName->data = (unsigned char*)PORT_Alloc(derName->len);
   272     if ( derName->data == NULL ) {
   273 	goto loser;
   274     }
   276     PORT_Memcpy(derName->data, tmpptr, derName->len);
   278     PORT_FreeArena(arena, PR_FALSE);
   279     return(SECSuccess);
   281 loser:
   282     PORT_FreeArena(arena, PR_FALSE);
   283     return(SECFailure);
   284 }
   286 SECStatus
   287 CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
   288 {
   289     int rv;
   290     PLArenaPool *arena;
   291     CERTSignedData sd;
   292     void *tmpptr;
   294     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   296     if ( ! arena ) {
   297 	return(SECFailure);
   298     }
   300     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
   301     rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
   303     if ( rv ) {
   304 	goto loser;
   305     }
   307     PORT_Memset(derName, 0, sizeof(SECItem));
   308     rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertIssuerTemplate, &sd.data);
   310     if ( rv ) {
   311 	goto loser;
   312     }
   314     tmpptr = derName->data;
   315     derName->data = (unsigned char*)PORT_Alloc(derName->len);
   316     if ( derName->data == NULL ) {
   317 	goto loser;
   318     }
   320     PORT_Memcpy(derName->data, tmpptr, derName->len);
   322     PORT_FreeArena(arena, PR_FALSE);
   323     return(SECSuccess);
   325 loser:
   326     PORT_FreeArena(arena, PR_FALSE);
   327     return(SECFailure);
   328 }
   330 SECStatus
   331 CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
   332 {
   333     int rv;
   334     PLArenaPool *arena;
   335     CERTSignedData sd;
   336     void *tmpptr;
   338     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   340     if ( ! arena ) {
   341 	return(SECFailure);
   342     }
   344     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
   345     rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
   347     if ( rv ) {
   348 	goto loser;
   349     }
   351     PORT_Memset(derName, 0, sizeof(SECItem));
   352     rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSerialNumberTemplate, &sd.data);
   354     if ( rv ) {
   355 	goto loser;
   356     }
   358     tmpptr = derName->data;
   359     derName->data = (unsigned char*)PORT_Alloc(derName->len);
   360     if ( derName->data == NULL ) {
   361 	goto loser;
   362     }
   364     PORT_Memcpy(derName->data, tmpptr, derName->len);
   366     PORT_FreeArena(arena, PR_FALSE);
   367     return(SECSuccess);
   369 loser:
   370     PORT_FreeArena(arena, PR_FALSE);
   371     return(SECFailure);
   372 }
   374 /*
   375  * Generate a database key, based on serial number and issuer, from a
   376  * DER certificate.
   377  */
   378 SECStatus
   379 CERT_KeyFromDERCert(PLArenaPool *reqArena, SECItem *derCert, SECItem *key)
   380 {
   381     int rv;
   382     CERTSignedData sd;
   383     CERTCertKey certkey;
   385     if (!reqArena) {
   386         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   387         return SECFailure;
   388     }
   390     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
   391     rv = SEC_QuickDERDecodeItem(reqArena, &sd, CERT_SignedDataTemplate,
   392                                 derCert);
   394     if ( rv ) {
   395 	goto loser;
   396     }
   398     PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
   399     rv = SEC_QuickDERDecodeItem(reqArena, &certkey, CERT_CertKeyTemplate,
   400                                 &sd.data);
   402     if ( rv ) {
   403 	goto loser;
   404     }
   406     return(CERT_KeyFromIssuerAndSN(reqArena, &certkey.derIssuer,
   407 				   &certkey.serialNumber, key));
   408 loser:
   409     return(SECFailure);
   410 }
   412 /*
   413  * fill in keyUsage field of the cert based on the cert extension
   414  * if the extension is not critical, then we allow all uses
   415  */
   416 static SECStatus
   417 GetKeyUsage(CERTCertificate *cert)
   418 {
   419     SECStatus rv;
   420     SECItem tmpitem;
   422     rv = CERT_FindKeyUsageExtension(cert, &tmpitem);
   423     if ( rv == SECSuccess ) {
   424 	/* remember the actual value of the extension */
   425 	cert->rawKeyUsage = tmpitem.data[0];
   426 	cert->keyUsagePresent = PR_TRUE;
   427 	cert->keyUsage = tmpitem.data[0];
   429 	PORT_Free(tmpitem.data);
   430 	tmpitem.data = NULL;
   432     } else {
   433 	/* if the extension is not present, then we allow all uses */
   434 	cert->keyUsage = KU_ALL;
   435 	cert->rawKeyUsage = KU_ALL;
   436 	cert->keyUsagePresent = PR_FALSE;
   437     }
   439     if ( CERT_GovtApprovedBitSet(cert) ) {
   440 	cert->keyUsage |= KU_NS_GOVT_APPROVED;
   441 	cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;
   442     }
   444     return(SECSuccess);
   445 }
   448 static SECStatus
   449 findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum)
   450 {
   451     SECItem **oids;
   452     SECItem *oid;
   453     SECStatus rv = SECFailure;
   455     if (seq != NULL) {
   456 	oids = seq->oids;
   457 	while (oids != NULL && *oids != NULL) {
   458 	    oid = *oids;
   459 	    if (SECOID_FindOIDTag(oid) == tagnum) {
   460 		rv = SECSuccess;
   461 		break;
   462 	    }
   463 	    oids++;
   464 	}
   465     }
   466     return rv;
   467 }
   469 /*
   470  * fill in nsCertType field of the cert based on the cert extension
   471  */
   472 SECStatus
   473 cert_GetCertType(CERTCertificate *cert)
   474 {
   475     PRUint32 nsCertType;
   477     if (cert->nsCertType) {
   478         /* once set, no need to recalculate */
   479         return SECSuccess;
   480     }
   481     nsCertType = cert_ComputeCertType(cert);
   483     /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
   484     PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
   485     PR_ATOMIC_SET((PRInt32 *)&cert->nsCertType, nsCertType);
   486     return SECSuccess;
   487 }
   489 PRUint32
   490 cert_ComputeCertType(CERTCertificate *cert)
   491 {
   492     SECStatus rv;
   493     SECItem tmpitem;
   494     SECItem encodedExtKeyUsage;
   495     CERTOidSequence *extKeyUsage = NULL;
   496     PRBool basicConstraintPresent = PR_FALSE;
   497     CERTBasicConstraints basicConstraint;
   498     PRUint32 nsCertType = 0;
   500     tmpitem.data = NULL;
   501     CERT_FindNSCertTypeExtension(cert, &tmpitem);
   502     encodedExtKeyUsage.data = NULL;
   503     rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, 
   504 				&encodedExtKeyUsage);
   505     if (rv == SECSuccess) {
   506 	extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
   507     }
   508     rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
   509     if (rv == SECSuccess) {
   510 	basicConstraintPresent = PR_TRUE;
   511     }
   512     if (tmpitem.data != NULL || extKeyUsage != NULL) {
   513 	if (tmpitem.data == NULL) {
   514 	    nsCertType = 0;
   515 	} else {
   516 	    nsCertType = tmpitem.data[0];
   517 	}
   519 	/* free tmpitem data pointer to avoid memory leak */
   520 	PORT_Free(tmpitem.data);
   521 	tmpitem.data = NULL;
   523 	/*
   524 	 * for this release, we will allow SSL certs with an email address
   525 	 * to be used for email
   526 	 */
   527 	if ( ( nsCertType & NS_CERT_TYPE_SSL_CLIENT ) &&
   528 	    cert->emailAddr && cert->emailAddr[0]) {
   529 	    nsCertType |= NS_CERT_TYPE_EMAIL;
   530 	}
   531 	/*
   532 	 * for this release, we will allow SSL intermediate CAs to be
   533 	 * email intermediate CAs too.
   534 	 */
   535 	if ( nsCertType & NS_CERT_TYPE_SSL_CA ) {
   536 	    nsCertType |= NS_CERT_TYPE_EMAIL_CA;
   537 	}
   538 	/*
   539 	 * allow a cert with the extended key usage of EMail Protect
   540 	 * to be used for email or as an email CA, if basic constraints
   541 	 * indicates that it is a CA.
   542 	 */
   543 	if (findOIDinOIDSeqByTagNum(extKeyUsage, 
   544 				    SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
   545 	    SECSuccess) {
   546 	    if (basicConstraintPresent == PR_TRUE &&
   547 		(basicConstraint.isCA)) {
   548 		nsCertType |= NS_CERT_TYPE_EMAIL_CA;
   549 	    } else {
   550 		nsCertType |= NS_CERT_TYPE_EMAIL;
   551 	    }
   552 	}
   553 	if (findOIDinOIDSeqByTagNum(extKeyUsage, 
   554 				    SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) ==
   555 	    SECSuccess){
   556 	    if (basicConstraintPresent == PR_TRUE &&
   557 		(basicConstraint.isCA)) {
   558 		nsCertType |= NS_CERT_TYPE_SSL_CA;
   559 	    } else {
   560 		nsCertType |= NS_CERT_TYPE_SSL_SERVER;
   561 	    }
   562 	}
   563 	/*
   564 	 * Treat certs with step-up OID as also having SSL server type.
   565  	 * COMODO needs this behaviour until June 2020.  See Bug 737802.
   566 	 */
   567 	if (findOIDinOIDSeqByTagNum(extKeyUsage, 
   568 				    SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
   569 	    SECSuccess){
   570 	    if (basicConstraintPresent == PR_TRUE &&
   571 		(basicConstraint.isCA)) {
   572 		nsCertType |= NS_CERT_TYPE_SSL_CA;
   573 	    } else {
   574 		nsCertType |= NS_CERT_TYPE_SSL_SERVER;
   575 	    }
   576 	}
   577 	if (findOIDinOIDSeqByTagNum(extKeyUsage,
   578 				    SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) ==
   579 	    SECSuccess){
   580 	    if (basicConstraintPresent == PR_TRUE &&
   581 		(basicConstraint.isCA)) {
   582 		nsCertType |= NS_CERT_TYPE_SSL_CA;
   583 	    } else {
   584 		nsCertType |= NS_CERT_TYPE_SSL_CLIENT;
   585 	    }
   586 	}
   587 	if (findOIDinOIDSeqByTagNum(extKeyUsage,
   588 				    SEC_OID_EXT_KEY_USAGE_CODE_SIGN) ==
   589 	    SECSuccess) {
   590 	    if (basicConstraintPresent == PR_TRUE &&
   591 		(basicConstraint.isCA)) {
   592 		nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
   593 	    } else {
   594 		nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING;
   595 	    }
   596 	}
   597 	if (findOIDinOIDSeqByTagNum(extKeyUsage,
   598 				    SEC_OID_EXT_KEY_USAGE_TIME_STAMP) ==
   599 	    SECSuccess) {
   600 	    nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
   601 	}
   602 	if (findOIDinOIDSeqByTagNum(extKeyUsage,
   603 				    SEC_OID_OCSP_RESPONDER) == 
   604 	    SECSuccess) {
   605 	    nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
   606 	}
   607     } else {
   608 	/* If no NS Cert Type extension and no EKU extension, then */
   609 	nsCertType = 0;
   610 	if (CERT_IsCACert(cert, &nsCertType))
   611 	    nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
   612 	/* if the basic constraint extension says the cert is a CA, then
   613 	   allow SSL CA and EMAIL CA and Status Responder */
   614 	if (basicConstraintPresent && basicConstraint.isCA ) {
   615 	    nsCertType |= (NS_CERT_TYPE_SSL_CA   |
   616 		           NS_CERT_TYPE_EMAIL_CA |
   617 		           EXT_KEY_USAGE_STATUS_RESPONDER);
   618 	}
   619 	/* allow any ssl or email (no ca or object signing. */
   620 	nsCertType |= NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
   621 	              NS_CERT_TYPE_EMAIL;
   622     }
   624     if (encodedExtKeyUsage.data != NULL) {
   625 	PORT_Free(encodedExtKeyUsage.data);
   626     }
   627     if (extKeyUsage != NULL) {
   628 	CERT_DestroyOidSequence(extKeyUsage);
   629     }
   630     return nsCertType;
   631 }
   633 /*
   634  * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate
   635  */
   636 SECStatus
   637 cert_GetKeyID(CERTCertificate *cert)
   638 {
   639     SECItem tmpitem;
   640     SECStatus rv;
   642     cert->subjectKeyID.len = 0;
   644     /* see of the cert has a key identifier extension */
   645     rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
   646     if ( rv == SECSuccess ) {
   647 	cert->subjectKeyID.data = (unsigned char*) PORT_ArenaAlloc(cert->arena, tmpitem.len);
   648 	if ( cert->subjectKeyID.data != NULL ) {
   649 	    PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len);
   650 	    cert->subjectKeyID.len = tmpitem.len;
   651 	    cert->keyIDGenerated = PR_FALSE;
   652 	}
   654 	PORT_Free(tmpitem.data);
   655     }
   657     /* if the cert doesn't have a key identifier extension, then generate one*/
   658     if ( cert->subjectKeyID.len == 0 ) {
   659 	/*
   660 	 * pkix says that if the subjectKeyID is not present, then we should
   661 	 * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert
   662 	 */
   663 	cert->subjectKeyID.data = (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH);
   664 	if ( cert->subjectKeyID.data != NULL ) {
   665 	    rv = PK11_HashBuf(SEC_OID_SHA1,cert->subjectKeyID.data,
   666 			      cert->derPublicKey.data,
   667 			      cert->derPublicKey.len);
   668 	    if ( rv == SECSuccess ) {
   669 		cert->subjectKeyID.len = SHA1_LENGTH;
   670 	    }
   671 	}
   672     }
   674     if ( cert->subjectKeyID.len == 0 ) {
   675 	return(SECFailure);
   676     }
   677     return(SECSuccess);
   679 }
   681 static PRBool
   682 cert_IsRootCert(CERTCertificate *cert)
   683 {
   684     SECStatus rv;
   685     SECItem tmpitem;
   687     /* cache the authKeyID extension, if present */
   688     cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
   690     /* it MUST be self-issued to be a root */
   691     if (cert->derIssuer.len == 0 ||
   692         !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject))
   693     {
   694 	return PR_FALSE;
   695     }
   697     /* check the authKeyID extension */
   698     if (cert->authKeyID) {
   699 	/* authority key identifier is present */
   700 	if (cert->authKeyID->keyID.len > 0) {
   701 	    /* the keyIdentifier field is set, look for subjectKeyID */
   702 	    rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
   703 	    if (rv == SECSuccess) {
   704 		PRBool match;
   705 		/* also present, they MUST match for it to be a root */
   706 		match = SECITEM_ItemsAreEqual(&cert->authKeyID->keyID,
   707 		                              &tmpitem);
   708 		PORT_Free(tmpitem.data);
   709 		if (!match) return PR_FALSE; /* else fall through */
   710 	    } else {
   711 		/* the subject key ID is required when AKI is present */
   712 		return PR_FALSE;
   713 	    }
   714 	}
   715 	if (cert->authKeyID->authCertIssuer) {
   716 	    SECItem *caName;
   717 	    caName = (SECItem *)CERT_GetGeneralNameByType(
   718 	                                  cert->authKeyID->authCertIssuer,
   719 	                                  certDirectoryName, PR_TRUE);
   720 	    if (caName) {
   721 		if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
   722 		    return PR_FALSE;
   723 		} /* else fall through */
   724 	    } /* else ??? could not get general name as directory name? */
   725 	}
   726 	if (cert->authKeyID->authCertSerialNumber.len > 0) {
   727 	    if (!SECITEM_ItemsAreEqual(&cert->serialNumber,
   728 	                         &cert->authKeyID->authCertSerialNumber)) {
   729 		return PR_FALSE;
   730 	    } /* else fall through */
   731 	}
   732 	/* all of the AKI fields that were present passed the test */
   733 	return PR_TRUE;
   734     }
   735     /* else the AKI was not present, so this is a root */
   736     return PR_TRUE;
   737 }
   739 /*
   740  * take a DER certificate and decode it into a certificate structure
   741  */
   742 CERTCertificate *
   743 CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
   744 			 char *nickname)
   745 {
   746     CERTCertificate *cert;
   747     PLArenaPool *arena;
   748     void *data;
   749     int rv;
   750     int len;
   751     char *tmpname;
   753     /* make a new arena */
   754     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   756     if ( !arena ) {
   757 	return 0;
   758     }
   760     /* allocate the certificate structure */
   761     cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
   763     if ( !cert ) {
   764 	goto loser;
   765     }
   767     cert->arena = arena;
   769     if ( copyDER ) {
   770 	/* copy the DER data for the cert into this arena */
   771 	data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len);
   772 	if ( !data ) {
   773 	    goto loser;
   774 	}
   775 	cert->derCert.data = (unsigned char *)data;
   776 	cert->derCert.len = derSignedCert->len;
   777 	PORT_Memcpy(data, derSignedCert->data, derSignedCert->len);
   778     } else {
   779 	/* point to passed in DER data */
   780 	cert->derCert = *derSignedCert;
   781     }
   783     /* decode the certificate info */
   784     rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate,
   785 		    &cert->derCert);
   787     if ( rv ) {
   788 	goto loser;
   789     }
   791     if (cert_HasUnknownCriticalExten (cert->extensions) == PR_TRUE) {
   792         cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE;
   793     }
   795     /* generate and save the database key for the cert */
   796     rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber,
   797 			&cert->certKey);
   798     if ( rv ) {
   799 	goto loser;
   800     }
   802     /* set the nickname */
   803     if ( nickname == NULL ) {
   804 	cert->nickname = NULL;
   805     } else {
   806 	/* copy and install the nickname */
   807 	len = PORT_Strlen(nickname) + 1;
   808 	cert->nickname = (char*)PORT_ArenaAlloc(arena, len);
   809 	if ( cert->nickname == NULL ) {
   810 	    goto loser;
   811 	}
   813 	PORT_Memcpy(cert->nickname, nickname, len);
   814     }
   816     /* set the email address */
   817     cert->emailAddr = cert_GetCertificateEmailAddresses(cert);
   819     /* initialize the subjectKeyID */
   820     rv = cert_GetKeyID(cert);
   821     if ( rv != SECSuccess ) {
   822 	goto loser;
   823     }
   825     /* initialize keyUsage */
   826     rv = GetKeyUsage(cert);
   827     if ( rv != SECSuccess ) {
   828 	goto loser;
   829     }
   831     /* determine if this is a root cert */
   832     cert->isRoot = cert_IsRootCert(cert);
   834     /* initialize the certType */
   835     rv = cert_GetCertType(cert);
   836     if ( rv != SECSuccess ) {
   837 	goto loser;
   838     }
   840     tmpname = CERT_NameToAscii(&cert->subject);
   841     if ( tmpname != NULL ) {
   842 	cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
   843 	PORT_Free(tmpname);
   844     }
   846     tmpname = CERT_NameToAscii(&cert->issuer);
   847     if ( tmpname != NULL ) {
   848 	cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname);
   849 	PORT_Free(tmpname);
   850     }
   852     cert->referenceCount = 1;
   853     cert->slot = NULL;
   854     cert->pkcs11ID = CK_INVALID_HANDLE;
   855     cert->dbnickname = NULL;
   857     return(cert);
   859 loser:
   861     if ( arena ) {
   862 	PORT_FreeArena(arena, PR_FALSE);
   863     }
   865     return(0);
   866 }
   868 CERTCertificate *
   869 __CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
   870 			 char *nickname)
   871 {
   872     return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname);
   873 }
   876 CERTValidity *
   877 CERT_CreateValidity(PRTime notBefore, PRTime notAfter)
   878 {
   879     CERTValidity *v;
   880     int rv;
   881     PLArenaPool *arena;
   883     if (notBefore > notAfter) {
   884        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   885        return NULL;
   886     }
   887     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   889     if ( !arena ) {
   890 	return(0);
   891     }
   893     v = (CERTValidity*) PORT_ArenaZAlloc(arena, sizeof(CERTValidity));
   894     if (v) {
   895 	v->arena = arena;
   896 	rv = DER_EncodeTimeChoice(arena, &v->notBefore, notBefore);
   897 	if (rv) goto loser;
   898 	rv = DER_EncodeTimeChoice(arena, &v->notAfter, notAfter);
   899 	if (rv) goto loser;
   900     }
   901     return v;
   903   loser:
   904     CERT_DestroyValidity(v);
   905     return 0;
   906 }
   908 SECStatus
   909 CERT_CopyValidity(PLArenaPool *arena, CERTValidity *to, CERTValidity *from)
   910 {
   911     SECStatus rv;
   913     CERT_DestroyValidity(to);
   914     to->arena = arena;
   916     rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore);
   917     if (rv) return rv;
   918     rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter);
   919     return rv;
   920 }
   922 void
   923 CERT_DestroyValidity(CERTValidity *v)
   924 {
   925     if (v && v->arena) {
   926 	PORT_FreeArena(v->arena, PR_FALSE);
   927     }
   928     return;
   929 }
   931 /*
   932 ** Amount of time that a certifiate is allowed good before it is actually
   933 ** good. This is used for pending certificates, ones that are about to be
   934 ** valid. The slop is designed to allow for some variance in the clocks
   935 ** of the machine checking the certificate.
   936 */
   937 #define PENDING_SLOP (24L*60L*60L)		/* seconds per day */
   938 static PRInt32 pendingSlop = PENDING_SLOP;	/* seconds */
   940 PRInt32
   941 CERT_GetSlopTime(void)
   942 {
   943     return pendingSlop;			/* seconds */
   944 }
   946 SECStatus
   947 CERT_SetSlopTime(PRInt32 slop)		/* seconds */
   948 {
   949     if (slop < 0)
   950 	return SECFailure;
   951     pendingSlop = slop;
   952     return SECSuccess;
   953 }
   955 SECStatus
   956 CERT_GetCertTimes(const CERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
   957 {
   958     SECStatus rv;
   960     if (!c || !notBefore || !notAfter) {
   961         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   962         return SECFailure;
   963     }
   965     /* convert DER not-before time */
   966     rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore);
   967     if (rv) {
   968 	return(SECFailure);
   969     }
   971     /* convert DER not-after time */
   972     rv = DER_DecodeTimeChoice(notAfter, &c->validity.notAfter);
   973     if (rv) {
   974 	return(SECFailure);
   975     }
   977     return(SECSuccess);
   978 }
   980 /*
   981  * Check the validity times of a certificate
   982  */
   983 SECCertTimeValidity
   984 CERT_CheckCertValidTimes(const CERTCertificate *c, PRTime t,
   985                          PRBool allowOverride)
   986 {
   987     PRTime notBefore, notAfter, llPendingSlop, tmp1;
   988     SECStatus rv;
   990     if (!c) {
   991         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   992         return(secCertTimeUndetermined);
   993     }
   994     /* if cert is already marked OK, then don't bother to check */
   995     if ( allowOverride && c->timeOK ) {
   996 	return(secCertTimeValid);
   997     }
   999     rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
  1001     if (rv) {
  1002 	return(secCertTimeExpired); /*XXX is this the right thing to do here?*/
  1005     LL_I2L(llPendingSlop, pendingSlop);
  1006     /* convert to micro seconds */
  1007     LL_UI2L(tmp1, PR_USEC_PER_SEC);
  1008     LL_MUL(llPendingSlop, llPendingSlop, tmp1);
  1009     LL_SUB(notBefore, notBefore, llPendingSlop);
  1010     if ( LL_CMP( t, <, notBefore ) ) {
  1011 	PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
  1012 	return(secCertTimeNotValidYet);
  1014     if ( LL_CMP( t, >, notAfter) ) {
  1015 	PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
  1016 	return(secCertTimeExpired);
  1019     return(secCertTimeValid);
  1022 SECStatus
  1023 SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter)
  1025     int rv;
  1027     /* convert DER not-before time */
  1028     rv = DER_DecodeTimeChoice(notBefore, &date->lastUpdate);
  1029     if (rv) {
  1030 	return(SECFailure);
  1033     /* convert DER not-after time */
  1034     if (date->nextUpdate.data) {
  1035 	rv = DER_DecodeTimeChoice(notAfter, &date->nextUpdate);
  1036 	if (rv) {
  1037 	    return(SECFailure);
  1040     else {
  1041 	LL_I2L(*notAfter, 0L);
  1043     return(SECSuccess);
  1046 /* These routines should probably be combined with the cert
  1047  * routines using an common extraction routine.
  1048  */
  1049 SECCertTimeValidity
  1050 SEC_CheckCrlTimes(CERTCrl *crl, PRTime t) {
  1051     PRTime notBefore, notAfter, llPendingSlop, tmp1;
  1052     SECStatus rv;
  1054     rv = SEC_GetCrlTimes(crl, &notBefore, &notAfter);
  1056     if (rv) {
  1057 	return(secCertTimeExpired); 
  1060     LL_I2L(llPendingSlop, pendingSlop);
  1061     /* convert to micro seconds */
  1062     LL_I2L(tmp1, PR_USEC_PER_SEC);
  1063     LL_MUL(llPendingSlop, llPendingSlop, tmp1);
  1064     LL_SUB(notBefore, notBefore, llPendingSlop);
  1065     if ( LL_CMP( t, <, notBefore ) ) {
  1066 	return(secCertTimeNotValidYet);
  1069     /* If next update is omitted and the test for notBefore passes, then
  1070        we assume that the crl is up to date.
  1071      */
  1072     if ( LL_IS_ZERO(notAfter) ) {
  1073 	return(secCertTimeValid);
  1076     if ( LL_CMP( t, >, notAfter) ) {
  1077 	return(secCertTimeExpired);
  1080     return(secCertTimeValid);
  1083 PRBool
  1084 SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old) {
  1085     PRTime newNotBefore, newNotAfter;
  1086     PRTime oldNotBefore, oldNotAfter;
  1087     SECStatus rv;
  1089     /* problems with the new CRL? reject it */
  1090     rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter);
  1091     if (rv) return PR_FALSE;
  1093     /* problems with the old CRL? replace it */
  1094     rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter);
  1095     if (rv) return PR_TRUE;
  1097     /* Question: what about the notAfter's? */
  1098     return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore));
  1101 /*
  1102  * return required key usage and cert type based on cert usage 
  1103  */
  1104 SECStatus
  1105 CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage,
  1106 				 PRBool ca,
  1107 				 unsigned int *retKeyUsage,
  1108 				 unsigned int *retCertType)
  1110     unsigned int requiredKeyUsage = 0;
  1111     unsigned int requiredCertType = 0;
  1113     if ( ca ) {
  1114 	switch ( usage ) {
  1115 	  case certUsageSSLServerWithStepUp:
  1116 	    requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN;
  1117 	    requiredCertType = NS_CERT_TYPE_SSL_CA;
  1118 	    break;
  1119 	  case certUsageSSLClient:
  1120 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1121 	    requiredCertType = NS_CERT_TYPE_SSL_CA;
  1122 	    break;
  1123 	  case certUsageSSLServer:
  1124 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1125 	    requiredCertType = NS_CERT_TYPE_SSL_CA;
  1126 	    break;
  1127 	  case certUsageSSLCA:
  1128 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1129 	    requiredCertType = NS_CERT_TYPE_SSL_CA;
  1130 	    break;
  1131 	  case certUsageEmailSigner:
  1132 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1133 	    requiredCertType = NS_CERT_TYPE_EMAIL_CA;
  1134 	    break;
  1135 	  case certUsageEmailRecipient:
  1136 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1137 	    requiredCertType = NS_CERT_TYPE_EMAIL_CA;
  1138 	    break;
  1139 	  case certUsageObjectSigner:
  1140 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1141 	    requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA;
  1142 	    break;
  1143 	  case certUsageAnyCA:
  1144 	  case certUsageVerifyCA:
  1145 	  case certUsageStatusResponder:
  1146 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1147 	    requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA |
  1148 		NS_CERT_TYPE_EMAIL_CA |
  1149 		    NS_CERT_TYPE_SSL_CA;
  1150 	    break;
  1151 	  default:
  1152 	    PORT_Assert(0);
  1153 	    goto loser;
  1155     } else {
  1156 	switch ( usage ) {
  1157 	  case certUsageSSLClient:
  1158 	    /* 
  1159 	     * RFC 5280 lists digitalSignature and keyAgreement for
  1160 	     * id-kp-clientAuth.  NSS does not support the *_fixed_dh and
  1161 	     * *_fixed_ecdh client certificate types.
  1162 	     */
  1163 	    requiredKeyUsage = KU_DIGITAL_SIGNATURE;
  1164 	    requiredCertType = NS_CERT_TYPE_SSL_CLIENT;
  1165 	    break;
  1166 	  case certUsageSSLServer:
  1167 	    requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
  1168 	    requiredCertType = NS_CERT_TYPE_SSL_SERVER;
  1169 	    break;
  1170 	  case certUsageSSLServerWithStepUp:
  1171 	    requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT |
  1172 		KU_NS_GOVT_APPROVED;
  1173 	    requiredCertType = NS_CERT_TYPE_SSL_SERVER;
  1174 	    break;
  1175 	  case certUsageSSLCA:
  1176 	    requiredKeyUsage = KU_KEY_CERT_SIGN;
  1177 	    requiredCertType = NS_CERT_TYPE_SSL_CA;
  1178 	    break;
  1179 	  case certUsageEmailSigner:
  1180 	    requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
  1181 	    requiredCertType = NS_CERT_TYPE_EMAIL;
  1182 	    break;
  1183 	  case certUsageEmailRecipient:
  1184 	    requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
  1185 	    requiredCertType = NS_CERT_TYPE_EMAIL;
  1186 	    break;
  1187 	  case certUsageObjectSigner:
  1188 	    /* RFC 5280 lists only digitalSignature for id-kp-codeSigning. */
  1189 	    requiredKeyUsage = KU_DIGITAL_SIGNATURE;
  1190 	    requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING;
  1191 	    break;
  1192 	  case certUsageStatusResponder:
  1193 	    requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
  1194 	    requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER;
  1195 	    break;
  1196 	  default:
  1197 	    PORT_Assert(0);
  1198 	    goto loser;
  1202     if ( retKeyUsage != NULL ) {
  1203 	*retKeyUsage = requiredKeyUsage;
  1205     if ( retCertType != NULL ) {
  1206 	*retCertType = requiredCertType;
  1209     return(SECSuccess);
  1210 loser:
  1211     return(SECFailure);
  1214 /*
  1215  * check the key usage of a cert against a set of required values
  1216  */
  1217 SECStatus
  1218 CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage)
  1220     if (!cert) {
  1221         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1222 	return SECFailure;
  1224     /* choose between key agreement or key encipherment based on key
  1225      * type in cert
  1226      */
  1227     if ( requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT ) {
  1228 	KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
  1229 	/* turn off the special bit */
  1230 	requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
  1232 	switch (keyType) {
  1233 	case rsaKey:
  1234 	    requiredUsage |= KU_KEY_ENCIPHERMENT;
  1235 	    break;
  1236 	case dsaKey:
  1237 	    requiredUsage |= KU_DIGITAL_SIGNATURE;
  1238 	    break;
  1239 	case dhKey:
  1240 	    requiredUsage |= KU_KEY_AGREEMENT;
  1241 	    break;
  1242 	case ecKey:
  1243 	    /* Accept either signature or agreement. */
  1244 	    if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)))
  1245 		 goto loser;
  1246 	    break;
  1247 	default:
  1248 	    goto loser;
  1252     /* Allow either digital signature or non-repudiation */
  1253     if ( requiredUsage & KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION ) {
  1254 	/* turn off the special bit */
  1255 	requiredUsage &= (~KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION);
  1257         if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION)))
  1258              goto loser;
  1261     if ( (cert->keyUsage & requiredUsage) == requiredUsage ) 
  1262     	return SECSuccess;
  1264 loser:
  1265     PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
  1266     return SECFailure;
  1270 CERTCertificate *
  1271 CERT_DupCertificate(CERTCertificate *c)
  1273     if (c) {
  1274 	NSSCertificate *tmp = STAN_GetNSSCertificate(c);
  1275 	nssCertificate_AddRef(tmp);
  1277     return c;
  1280 /*
  1281  * Allow use of default cert database, so that apps(such as mozilla) don't
  1282  * have to pass the handle all over the place.
  1283  */
  1284 static CERTCertDBHandle *default_cert_db_handle = 0;
  1286 void
  1287 CERT_SetDefaultCertDB(CERTCertDBHandle *handle)
  1289     default_cert_db_handle = handle;
  1291     return;
  1294 CERTCertDBHandle *
  1295 CERT_GetDefaultCertDB(void)
  1297     return(default_cert_db_handle);
  1300 /* XXX this would probably be okay/better as an xp routine? */
  1301 static void
  1302 sec_lower_string(char *s)
  1304     if ( s == NULL ) {
  1305 	return;
  1308     while ( *s ) {
  1309 	*s = PORT_Tolower(*s);
  1310 	s++;
  1313     return;
  1316 static PRBool
  1317 cert_IsIPAddr(const char *hn)
  1319     PRBool            isIPaddr       = PR_FALSE;
  1320     PRNetAddr         netAddr;
  1321     isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
  1322     return isIPaddr;
  1325 /*
  1326 ** Add a domain name to the list of names that the user has explicitly
  1327 ** allowed (despite cert name mismatches) for use with a server cert.
  1328 */
  1329 SECStatus
  1330 CERT_AddOKDomainName(CERTCertificate *cert, const char *hn)
  1332     CERTOKDomainName *domainOK;
  1333     int	       newNameLen;
  1335     if (!hn || !(newNameLen = strlen(hn))) {
  1336     	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1337 	return SECFailure;
  1339     domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena, 
  1340 				  (sizeof *domainOK) + newNameLen);
  1341     if (!domainOK) 
  1342     	return SECFailure;	/* error code is already set. */
  1344     PORT_Strcpy(domainOK->name, hn);
  1345     sec_lower_string(domainOK->name);
  1347     /* put at head of list. */
  1348     domainOK->next = cert->domainOK;
  1349     cert->domainOK = domainOK;
  1350     return SECSuccess;
  1353 /* returns SECSuccess if hn matches pattern cn,
  1354 ** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match,
  1355 ** returns SECFailure with some other error code if another error occurs.
  1356 **
  1357 ** This function may modify string cn, so caller must pass a modifiable copy.
  1358 */
  1359 static SECStatus
  1360 cert_TestHostName(char * cn, const char * hn)
  1362     static int useShellExp = -1;
  1364     if (useShellExp < 0) {
  1365         useShellExp = (NULL != PR_GetEnv("NSS_USE_SHEXP_IN_CERT_NAME"));
  1367     if (useShellExp) {
  1368     	/* Backward compatible code, uses Shell Expressions (SHEXP). */
  1369 	int regvalid = PORT_RegExpValid(cn);
  1370 	if (regvalid != NON_SXP) {
  1371 	    SECStatus rv;
  1372 	    /* cn is a regular expression, try to match the shexp */
  1373 	    int match = PORT_RegExpCaseSearch(hn, cn);
  1375 	    if ( match == 0 ) {
  1376 		rv = SECSuccess;
  1377 	    } else {
  1378 		PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
  1379 		rv = SECFailure;
  1381 	    return rv;
  1383     } else {
  1384 	/* New approach conforms to RFC 6125. */
  1385 	char *wildcard    = PORT_Strchr(cn, '*');
  1386 	char *firstcndot  = PORT_Strchr(cn, '.');
  1387 	char *secondcndot = firstcndot ? PORT_Strchr(firstcndot+1, '.') : NULL;
  1388 	char *firsthndot  = PORT_Strchr(hn, '.');
  1390 	/* For a cn pattern to be considered valid, the wildcard character...
  1391 	 * - may occur only in a DNS name with at least 3 components, and
  1392 	 * - may occur only as last character in the first component, and
  1393 	 * - may be preceded by additional characters, and
  1394 	 * - must not be preceded by an IDNA ACE prefix (xn--)
  1395 	 */
  1396 	if (wildcard && secondcndot && secondcndot[1] && firsthndot 
  1397 	    && firstcndot  - wildcard  == 1 /* wildcard is last char in first component */
  1398 	    && secondcndot - firstcndot > 1 /* second component is non-empty */
  1399 	    && PORT_Strrchr(cn, '*') == wildcard /* only one wildcard in cn */
  1400 	    && !PORT_Strncasecmp(cn, hn, wildcard - cn)
  1401 	    && !PORT_Strcasecmp(firstcndot, firsthndot)
  1402 	       /* If hn starts with xn--, then cn must start with wildcard */
  1403 	    && (PORT_Strncasecmp(hn, "xn--", 4) || wildcard == cn)) {
  1404 	    /* valid wildcard pattern match */
  1405 	    return SECSuccess;
  1408     /* String cn has no wildcard or shell expression.  
  1409      * Compare entire string hn with cert name. 
  1410      */
  1411     if (PORT_Strcasecmp(hn, cn) == 0) {
  1412 	return SECSuccess;
  1415     PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
  1416     return SECFailure;
  1420 SECStatus
  1421 cert_VerifySubjectAltName(const CERTCertificate *cert, const char *hn)
  1423     PLArenaPool *     arena          = NULL;
  1424     CERTGeneralName * nameList       = NULL;
  1425     CERTGeneralName * current;
  1426     char *            cn;
  1427     int               cnBufLen;
  1428     unsigned int      hnLen;
  1429     int               DNSextCount    = 0;
  1430     int               IPextCount     = 0;
  1431     PRBool            isIPaddr       = PR_FALSE;
  1432     SECStatus         rv             = SECFailure;
  1433     SECItem           subAltName;
  1434     PRNetAddr         netAddr;
  1435     char              cnbuf[128];
  1437     subAltName.data = NULL;
  1438     hnLen    = strlen(hn);
  1439     cn       = cnbuf;
  1440     cnBufLen = sizeof cnbuf;
  1442     rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
  1443 				&subAltName);
  1444     if (rv != SECSuccess) {
  1445 	goto fail;
  1447     isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
  1448     rv = SECFailure;
  1449     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1450     if (!arena) 
  1451 	goto fail;
  1453     nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
  1454     if (!current)
  1455     	goto fail;
  1457     do {
  1458 	switch (current->type) {
  1459 	case certDNSName:
  1460 	    if (!isIPaddr) {
  1461 		/* DNS name current->name.other.data is not null terminated.
  1462 		** so must copy it.  
  1463 		*/
  1464 		int cnLen = current->name.other.len;
  1465 		rv = CERT_RFC1485_EscapeAndQuote(cn, cnBufLen, 
  1466 					    (char *)current->name.other.data,
  1467 					    cnLen);
  1468 		if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_OUTPUT_LEN) {
  1469 		    cnBufLen = cnLen * 3 + 3; /* big enough for worst case */
  1470 		    cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
  1471 		    if (!cn)
  1472 			goto fail;
  1473 		    rv = CERT_RFC1485_EscapeAndQuote(cn, cnBufLen, 
  1474 					    (char *)current->name.other.data,
  1475 					    cnLen);
  1477 		if (rv == SECSuccess)
  1478 		    rv = cert_TestHostName(cn ,hn);
  1479 		if (rv == SECSuccess)
  1480 		    goto finish;
  1482 	    DNSextCount++;
  1483 	    break;
  1484 	case certIPAddress:
  1485 	    if (isIPaddr) {
  1486 		int match = 0;
  1487 		PRIPv6Addr v6Addr;
  1488 		if (current->name.other.len == 4 &&         /* IP v4 address */
  1489 		    netAddr.inet.family == PR_AF_INET) {
  1490 		    match = !memcmp(&netAddr.inet.ip, 
  1491 		                    current->name.other.data, 4);
  1492 		} else if (current->name.other.len == 16 && /* IP v6 address */
  1493 		    netAddr.ipv6.family == PR_AF_INET6) {
  1494 		    match = !memcmp(&netAddr.ipv6.ip,
  1495 		                     current->name.other.data, 16);
  1496 		} else if (current->name.other.len == 16 && /* IP v6 address */
  1497 		    netAddr.inet.family == PR_AF_INET) {
  1498 		    /* convert netAddr to ipv6, then compare. */
  1499 		    /* ipv4 must be in Network Byte Order on input. */
  1500 		    PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr);
  1501 		    match = !memcmp(&v6Addr, current->name.other.data, 16);
  1502 		} else if (current->name.other.len == 4 &&  /* IP v4 address */
  1503 		    netAddr.inet.family == PR_AF_INET6) {
  1504 		    /* convert netAddr to ipv6, then compare. */
  1505 		    PRUint32 ipv4 = (current->name.other.data[0] << 24) |
  1506 		                    (current->name.other.data[1] << 16) |
  1507 				    (current->name.other.data[2] <<  8) |
  1508 				     current->name.other.data[3];
  1509 		    /* ipv4 must be in Network Byte Order on input. */
  1510 		    PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr);
  1511 		    match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16);
  1513 		if (match) {
  1514 		    rv = SECSuccess;
  1515 		    goto finish;
  1518 	    IPextCount++;
  1519 	    break;
  1520 	default:
  1521 	    break;
  1523 	current = CERT_GetNextGeneralName(current);
  1524     } while (current != nameList);
  1526 fail:
  1528     if (!(isIPaddr ? IPextCount : DNSextCount)) {
  1529 	/* no relevant value in the extension was found. */
  1530 	PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
  1531     } else {
  1532 	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
  1534     rv = SECFailure;
  1536 finish:
  1538     /* Don't free nameList, it's part of the arena. */
  1539     if (arena) {
  1540 	PORT_FreeArena(arena, PR_FALSE);
  1543     if (subAltName.data) {
  1544 	SECITEM_FreeItem(&subAltName, PR_FALSE);
  1547     return rv;
  1550 /*
  1551  * If found:
  1552  *   - subAltName contains the extension (caller must free)
  1553  *   - return value is the decoded namelist (allocated off arena)
  1554  * if not found, or if failure to decode:
  1555  *   - return value is NULL
  1556  */
  1557 CERTGeneralName *
  1558 cert_GetSubjectAltNameList(const CERTCertificate *cert, PLArenaPool *arena)
  1560     CERTGeneralName * nameList       = NULL;
  1561     SECStatus         rv             = SECFailure;
  1562     SECItem           subAltName;
  1564     if (!cert || !arena)
  1565       return NULL;
  1567     subAltName.data = NULL;
  1569     rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
  1570                                 &subAltName);
  1571     if (rv != SECSuccess)
  1572       return NULL;
  1574     nameList = CERT_DecodeAltNameExtension(arena, &subAltName);
  1575     SECITEM_FreeItem(&subAltName, PR_FALSE);
  1576     return nameList;
  1579 PRUint32
  1580 cert_CountDNSPatterns(CERTGeneralName *firstName)
  1582     CERTGeneralName * current;
  1583     PRUint32 count = 0;
  1585     if (!firstName)
  1586       return 0;
  1588     current = firstName;
  1589     do {
  1590         switch (current->type) {
  1591         case certDNSName:
  1592         case certIPAddress:
  1593             ++count;
  1594             break;
  1595         default:
  1596             break;
  1598         current = CERT_GetNextGeneralName(current);
  1599     } while (current != firstName);
  1601     return count;
  1604 #ifndef INET6_ADDRSTRLEN
  1605 #define INET6_ADDRSTRLEN 46
  1606 #endif
  1608 /* will fill nickNames, 
  1609  * will allocate all data from nickNames->arena,
  1610  * numberOfGeneralNames should have been obtained from cert_CountDNSPatterns,
  1611  * will ensure the numberOfGeneralNames matches the number of output entries.
  1612  */
  1613 SECStatus
  1614 cert_GetDNSPatternsFromGeneralNames(CERTGeneralName *firstName,
  1615                                     PRUint32 numberOfGeneralNames, 
  1616                                     CERTCertNicknames *nickNames)
  1618     CERTGeneralName *currentInput;
  1619     char **currentOutput;
  1621     if (!firstName || !nickNames || !numberOfGeneralNames)
  1622       return SECFailure;
  1624     nickNames->numnicknames = numberOfGeneralNames;
  1625     nickNames->nicknames = PORT_ArenaAlloc(nickNames->arena,
  1626                                        sizeof(char *) * numberOfGeneralNames);
  1627     if (!nickNames->nicknames)
  1628       return SECFailure;
  1630     currentInput = firstName;
  1631     currentOutput = nickNames->nicknames;
  1632     do {
  1633         char *cn = NULL;
  1634         char ipbuf[INET6_ADDRSTRLEN];
  1635         PRNetAddr addr;
  1637         if (numberOfGeneralNames < 1) {
  1638           /* internal consistency error */
  1639           return SECFailure;
  1642         switch (currentInput->type) {
  1643         case certDNSName:
  1644             /* DNS name currentInput->name.other.data is not null terminated.
  1645             ** so must copy it.  
  1646             */
  1647             cn = (char *)PORT_ArenaAlloc(nickNames->arena, 
  1648                                          currentInput->name.other.len + 1);
  1649             if (!cn)
  1650               return SECFailure;
  1651             PORT_Memcpy(cn, currentInput->name.other.data, 
  1652                             currentInput->name.other.len);
  1653             cn[currentInput->name.other.len] = 0;
  1654             break;
  1655         case certIPAddress:
  1656             if (currentInput->name.other.len == 4) {
  1657               addr.inet.family = PR_AF_INET;
  1658               memcpy(&addr.inet.ip, currentInput->name.other.data, 
  1659                                     currentInput->name.other.len);
  1660             } else if (currentInput->name.other.len == 16) {
  1661               addr.ipv6.family = PR_AF_INET6;
  1662               memcpy(&addr.ipv6.ip, currentInput->name.other.data, 
  1663                                     currentInput->name.other.len);
  1665             if (PR_NetAddrToString(&addr, ipbuf, sizeof(ipbuf)) == PR_FAILURE)
  1666               return SECFailure;
  1667             cn = PORT_ArenaStrdup(nickNames->arena, ipbuf);
  1668             if (!cn)
  1669               return SECFailure;
  1670             break;
  1671         default:
  1672             break;
  1674         if (cn) {
  1675           *currentOutput = cn;
  1676           nickNames->totallen += PORT_Strlen(cn);
  1677           ++currentOutput;
  1678           --numberOfGeneralNames;
  1680         currentInput = CERT_GetNextGeneralName(currentInput);
  1681     } while (currentInput != firstName);
  1683     return (numberOfGeneralNames == 0) ? SECSuccess : SECFailure;
  1686 /*
  1687  * Collect all valid DNS names from the given cert.
  1688  * The output arena will reference some temporaray data,
  1689  * but this saves us from dealing with two arenas.
  1690  * The caller may free all data by freeing CERTCertNicknames->arena.
  1691  */
  1692 CERTCertNicknames *
  1693 CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert)
  1695     CERTGeneralName *generalNames;
  1696     CERTCertNicknames *nickNames;
  1697     PLArenaPool *arena;
  1698     char *singleName;
  1700     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1701     if (!arena) {
  1702         return NULL;
  1705     nickNames = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
  1706     if (!nickNames) {
  1707       PORT_FreeArena(arena, PR_FALSE);
  1708       return NULL;
  1711     /* init the structure */
  1712     nickNames->arena = arena;
  1713     nickNames->head = NULL;
  1714     nickNames->numnicknames = 0;
  1715     nickNames->nicknames = NULL;
  1716     nickNames->totallen = 0;
  1718     generalNames = cert_GetSubjectAltNameList(cert, arena);
  1719     if (generalNames) {
  1720       SECStatus rv_getnames = SECFailure; 
  1721       PRUint32 numNames = cert_CountDNSPatterns(generalNames);
  1723       if (numNames) {
  1724         rv_getnames = cert_GetDNSPatternsFromGeneralNames(generalNames, 
  1725                                                           numNames, nickNames);
  1728       /* if there were names, we'll exit now, either with success or failure */
  1729       if (numNames) {
  1730         if (rv_getnames == SECSuccess) {
  1731           return nickNames;
  1734         /* failure to produce output */
  1735         PORT_FreeArena(arena, PR_FALSE);
  1736         return NULL;
  1740     /* no SAN extension or no names found in extension */
  1741     singleName = CERT_GetCommonName(&cert->subject);
  1742     if (singleName) {
  1743       nickNames->numnicknames = 1;
  1744       nickNames->nicknames = PORT_ArenaAlloc(arena, sizeof(char *));
  1745       if (nickNames->nicknames) {
  1746         *nickNames->nicknames = PORT_ArenaStrdup(arena, singleName);
  1748       PORT_Free(singleName);
  1750       /* Did we allocate both the buffer of pointers and the string? */
  1751       if (nickNames->nicknames && *nickNames->nicknames) {
  1752         return nickNames;
  1756     PORT_FreeArena(arena, PR_FALSE);
  1757     return NULL;
  1760 /* Make sure that the name of the host we are connecting to matches the
  1761  * name that is incoded in the common-name component of the certificate
  1762  * that they are using.
  1763  */
  1764 SECStatus
  1765 CERT_VerifyCertName(const CERTCertificate *cert, const char *hn)
  1767     char *    cn;
  1768     SECStatus rv;
  1769     CERTOKDomainName *domainOK;
  1771     if (!hn || !strlen(hn)) {
  1772     	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1773 	return SECFailure;
  1776     /* if the name is one that the user has already approved, it's OK. */
  1777     for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {
  1778 	if (0 == PORT_Strcasecmp(hn, domainOK->name)) {
  1779 	    return SECSuccess;
  1783     /* Per RFC 2818, if the SubjectAltName extension is present, it must
  1784     ** be used as the cert's identity.
  1785     */
  1786     rv = cert_VerifySubjectAltName(cert, hn);
  1787     if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
  1788     	return rv;
  1790     cn = CERT_GetCommonName(&cert->subject);
  1791     if ( cn ) {
  1792         PRBool isIPaddr = cert_IsIPAddr(hn);
  1793         if (isIPaddr) {
  1794             if (PORT_Strcasecmp(hn, cn) == 0) {
  1795                 rv =  SECSuccess;
  1796             } else {
  1797                 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
  1798                 rv = SECFailure;
  1800         } else {
  1801             rv = cert_TestHostName(cn, hn);
  1803 	PORT_Free(cn);
  1804     } else 
  1805 	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
  1806     return rv;
  1809 PRBool
  1810 CERT_CompareCerts(const CERTCertificate *c1, const CERTCertificate *c2)
  1812     SECComparison comp;
  1814     comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
  1815     if ( comp == SECEqual ) { /* certs are the same */
  1816 	return(PR_TRUE);
  1817     } else {
  1818 	return(PR_FALSE);
  1822 static SECStatus
  1823 StringsEqual(char *s1, char *s2) {
  1824     if ( ( s1 == NULL ) || ( s2 == NULL ) ) {
  1825 	if ( s1 != s2 ) { /* only one is null */
  1826 	    return(SECFailure);
  1828 	return(SECSuccess); /* both are null */
  1831     if ( PORT_Strcmp( s1, s2 ) != 0 ) {
  1832 	return(SECFailure); /* not equal */
  1835     return(SECSuccess); /* strings are equal */
  1839 PRBool
  1840 CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2)
  1842     SECComparison comp;
  1843     char *c1str, *c2str;
  1844     SECStatus eq;
  1846     comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
  1847     if ( comp == SECEqual ) { /* certs are the same */
  1848 	return(PR_TRUE);
  1851     /* check if they are issued by the same CA */
  1852     comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);
  1853     if ( comp != SECEqual ) { /* different issuer */
  1854 	return(PR_FALSE);
  1857     /* check country name */
  1858     c1str = CERT_GetCountryName(&c1->subject);
  1859     c2str = CERT_GetCountryName(&c2->subject);
  1860     eq = StringsEqual(c1str, c2str);
  1861     PORT_Free(c1str);
  1862     PORT_Free(c2str);
  1863     if ( eq != SECSuccess ) {
  1864 	return(PR_FALSE);
  1867     /* check locality name */
  1868     c1str = CERT_GetLocalityName(&c1->subject);
  1869     c2str = CERT_GetLocalityName(&c2->subject);
  1870     eq = StringsEqual(c1str, c2str);
  1871     PORT_Free(c1str);
  1872     PORT_Free(c2str);
  1873     if ( eq != SECSuccess ) {
  1874 	return(PR_FALSE);
  1877     /* check state name */
  1878     c1str = CERT_GetStateName(&c1->subject);
  1879     c2str = CERT_GetStateName(&c2->subject);
  1880     eq = StringsEqual(c1str, c2str);
  1881     PORT_Free(c1str);
  1882     PORT_Free(c2str);
  1883     if ( eq != SECSuccess ) {
  1884 	return(PR_FALSE);
  1887     /* check org name */
  1888     c1str = CERT_GetOrgName(&c1->subject);
  1889     c2str = CERT_GetOrgName(&c2->subject);
  1890     eq = StringsEqual(c1str, c2str);
  1891     PORT_Free(c1str);
  1892     PORT_Free(c2str);
  1893     if ( eq != SECSuccess ) {
  1894 	return(PR_FALSE);
  1897 #ifdef NOTDEF	
  1898     /* check orgUnit name */
  1899     /*
  1900      * We need to revisit this and decide which fields should be allowed to be
  1901      * different
  1902      */
  1903     c1str = CERT_GetOrgUnitName(&c1->subject);
  1904     c2str = CERT_GetOrgUnitName(&c2->subject);
  1905     eq = StringsEqual(c1str, c2str);
  1906     PORT_Free(c1str);
  1907     PORT_Free(c2str);
  1908     if ( eq != SECSuccess ) {
  1909 	return(PR_FALSE);
  1911 #endif
  1913     return(PR_TRUE); /* all fields but common name are the same */
  1917 /* CERT_CertChainFromCert and CERT_DestroyCertificateList moved
  1918    to certhigh.c */
  1921 CERTIssuerAndSN *
  1922 CERT_GetCertIssuerAndSN(PLArenaPool *arena, CERTCertificate *cert)
  1924     CERTIssuerAndSN *result;
  1925     SECStatus rv;
  1927     if ( arena == NULL ) {
  1928 	arena = cert->arena;
  1931     result = (CERTIssuerAndSN*)PORT_ArenaZAlloc(arena, sizeof(*result));
  1932     if (result == NULL) {
  1933 	PORT_SetError (SEC_ERROR_NO_MEMORY);
  1934 	return NULL;
  1937     rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);
  1938     if (rv != SECSuccess)
  1939 	return NULL;
  1941     rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);
  1942     if (rv != SECSuccess)
  1943 	return NULL;
  1945     rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);
  1946     if (rv != SECSuccess)
  1947 	return NULL;
  1949     return result;
  1952 char *
  1953 CERT_MakeCANickname(CERTCertificate *cert)
  1955     char *firstname = NULL;
  1956     char *org = NULL;
  1957     char *nickname = NULL;
  1958     int count;
  1959     CERTCertificate *dummycert;
  1961     firstname = CERT_GetCommonName(&cert->subject);
  1962     if ( firstname == NULL ) {
  1963 	firstname = CERT_GetOrgUnitName(&cert->subject);
  1966     org = CERT_GetOrgName(&cert->issuer);
  1967     if (org == NULL) {
  1968 	org = CERT_GetDomainComponentName(&cert->issuer);
  1969 	if (org == NULL) {
  1970 	    if (firstname) {
  1971 		org = firstname;
  1972 		firstname = NULL;
  1973 	    } else {
  1974 		org = PORT_Strdup("Unknown CA");
  1979     /* can only fail if PORT_Strdup fails, in which case
  1980      * we're having memory problems. */
  1981     if (org == NULL) {
  1982 	goto done;
  1986     count = 1;
  1987     while ( 1 ) {
  1989 	if ( firstname ) {
  1990 	    if ( count == 1 ) {
  1991 		nickname = PR_smprintf("%s - %s", firstname, org);
  1992 	    } else {
  1993 		nickname = PR_smprintf("%s - %s #%d", firstname, org, count);
  1995 	} else {
  1996 	    if ( count == 1 ) {
  1997 		nickname = PR_smprintf("%s", org);
  1998 	    } else {
  1999 		nickname = PR_smprintf("%s #%d", org, count);
  2002 	if ( nickname == NULL ) {
  2003 	    goto done;
  2006 	/* look up the nickname to make sure it isn't in use already */
  2007 	dummycert = CERT_FindCertByNickname(cert->dbhandle, nickname);
  2009 	if ( dummycert == NULL ) {
  2010 	    goto done;
  2013 	/* found a cert, destroy it and loop */
  2014 	CERT_DestroyCertificate(dummycert);
  2016 	/* free the nickname */
  2017 	PORT_Free(nickname);
  2019 	count++;
  2022 done:
  2023     if ( firstname ) {
  2024 	PORT_Free(firstname);
  2026     if ( org ) {
  2027 	PORT_Free(org);
  2030     return(nickname);
  2033 /* CERT_Import_CAChain moved to certhigh.c */
  2035 void
  2036 CERT_DestroyCrl (CERTSignedCrl *crl)
  2038     SEC_DestroyCrl (crl);
  2041 static int
  2042 cert_Version(CERTCertificate *cert)
  2044     int version = 0;
  2045     if (cert && cert->version.data && cert->version.len) {
  2046 	version = DER_GetInteger(&cert->version);
  2047 	if (version < 0)
  2048 	    version = 0;
  2050     return version;
  2053 static unsigned int
  2054 cert_ComputeTrustOverrides(CERTCertificate *cert, unsigned int cType)
  2056     CERTCertTrust trust;
  2057     SECStatus rv = SECFailure;
  2059     rv = CERT_GetCertTrust(cert, &trust);
  2061     if (rv == SECSuccess && (trust.sslFlags |
  2062 		  trust.emailFlags |
  2063 		  trust.objectSigningFlags)) {
  2065 	if (trust.sslFlags & (CERTDB_TERMINAL_RECORD|CERTDB_TRUSTED)) 
  2066 	    cType |= NS_CERT_TYPE_SSL_SERVER|NS_CERT_TYPE_SSL_CLIENT;
  2067 	if (trust.sslFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA)) 
  2068 	    cType |= NS_CERT_TYPE_SSL_CA;
  2069 #if defined(CERTDB_NOT_TRUSTED)
  2070 	if (trust.sslFlags & CERTDB_NOT_TRUSTED) 
  2071 	    cType &= ~(NS_CERT_TYPE_SSL_SERVER|NS_CERT_TYPE_SSL_CLIENT|
  2072 	               NS_CERT_TYPE_SSL_CA);
  2073 #endif
  2074 	if (trust.emailFlags & (CERTDB_TERMINAL_RECORD|CERTDB_TRUSTED)) 
  2075 	    cType |= NS_CERT_TYPE_EMAIL;
  2076 	if (trust.emailFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA)) 
  2077 	    cType |= NS_CERT_TYPE_EMAIL_CA;
  2078 #if defined(CERTDB_NOT_TRUSTED)
  2079 	if (trust.emailFlags & CERTDB_NOT_TRUSTED) 
  2080 	    cType &= ~(NS_CERT_TYPE_EMAIL|NS_CERT_TYPE_EMAIL_CA);
  2081 #endif
  2082 	if (trust.objectSigningFlags & (CERTDB_TERMINAL_RECORD|CERTDB_TRUSTED)) 
  2083 	    cType |= NS_CERT_TYPE_OBJECT_SIGNING;
  2084 	if (trust.objectSigningFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA)) 
  2085 	    cType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
  2086 #if defined(CERTDB_NOT_TRUSTED)
  2087 	if (trust.objectSigningFlags & CERTDB_NOT_TRUSTED) 
  2088 	    cType &= ~(NS_CERT_TYPE_OBJECT_SIGNING|
  2089 	               NS_CERT_TYPE_OBJECT_SIGNING_CA);
  2090 #endif
  2092     return cType;
  2095 /*
  2096  * Does a cert belong to a CA?  We decide based on perm database trust
  2097  * flags, Netscape Cert Type Extension, and KeyUsage Extension.
  2098  */
  2099 PRBool
  2100 CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
  2102     unsigned int cType = cert->nsCertType;
  2103     PRBool ret = PR_FALSE;
  2105     if (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA | 
  2106                 NS_CERT_TYPE_OBJECT_SIGNING_CA)) {
  2107         ret = PR_TRUE;
  2108     } else {
  2109 	SECStatus rv;
  2110 	CERTBasicConstraints constraints;
  2112 	rv = CERT_FindBasicConstraintExten(cert, &constraints);
  2113 	if (rv == SECSuccess && constraints.isCA) {
  2114 	    ret = PR_TRUE;
  2115 	    cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
  2119     /* finally check if it's an X.509 v1 root CA */
  2120     if (!ret && 
  2121         (cert->isRoot && cert_Version(cert) < SEC_CERTIFICATE_VERSION_3)) {
  2122 	ret = PR_TRUE;
  2123 	cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
  2125     /* Now apply trust overrides, if any */
  2126     cType = cert_ComputeTrustOverrides(cert, cType);
  2127     ret = (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
  2128                     NS_CERT_TYPE_OBJECT_SIGNING_CA)) ? PR_TRUE : PR_FALSE;
  2130     if (rettype != NULL) {
  2131 	*rettype = cType;
  2133     return ret;
  2136 PRBool
  2137 CERT_IsCADERCert(SECItem *derCert, unsigned int *type) {
  2138     CERTCertificate *cert;
  2139     PRBool isCA;
  2141     /* This is okay -- only looks at extensions */
  2142     cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
  2143     if (cert == NULL) return PR_FALSE;
  2145     isCA = CERT_IsCACert(cert,type);
  2146     CERT_DestroyCertificate (cert);
  2147     return isCA;
  2150 PRBool
  2151 CERT_IsRootDERCert(SECItem *derCert)
  2153     CERTCertificate *cert;
  2154     PRBool isRoot;
  2156     /* This is okay -- only looks at extensions */
  2157     cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
  2158     if (cert == NULL) return PR_FALSE;
  2160     isRoot = cert->isRoot;
  2161     CERT_DestroyCertificate (cert);
  2162     return isRoot;
  2165 CERTCompareValidityStatus
  2166 CERT_CompareValidityTimes(CERTValidity* val_a, CERTValidity* val_b)
  2168     PRTime notBeforeA, notBeforeB, notAfterA, notAfterB;
  2170     if (!val_a || !val_b)
  2172         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2173         return certValidityUndetermined;
  2176     if ( SECSuccess != DER_DecodeTimeChoice(&notBeforeA, &val_a->notBefore) ||
  2177          SECSuccess != DER_DecodeTimeChoice(&notBeforeB, &val_b->notBefore) ||
  2178          SECSuccess != DER_DecodeTimeChoice(&notAfterA, &val_a->notAfter) ||
  2179          SECSuccess != DER_DecodeTimeChoice(&notAfterB, &val_b->notAfter) ) {
  2180         return certValidityUndetermined;
  2183     /* sanity check */
  2184     if (LL_CMP(notBeforeA,>,notAfterA) || LL_CMP(notBeforeB,>,notAfterB)) {
  2185         PORT_SetError(SEC_ERROR_INVALID_TIME);
  2186         return certValidityUndetermined;
  2189     if (LL_CMP(notAfterA,!=,notAfterB)) {
  2190         /* one cert validity goes farther into the future, select it */
  2191         return LL_CMP(notAfterA,<,notAfterB) ?
  2192             certValidityChooseB : certValidityChooseA;
  2194     /* the two certs have the same expiration date */
  2195     PORT_Assert(LL_CMP(notAfterA, == , notAfterB));
  2196     /* do they also have the same start date ? */
  2197     if (LL_CMP(notBeforeA,==,notBeforeB)) {
  2198 	return certValidityEqual;
  2200     /* choose cert with the later start date */
  2201     return LL_CMP(notBeforeA,<,notBeforeB) ?
  2202         certValidityChooseB : certValidityChooseA;
  2205 /*
  2206  * is certa newer than certb?  If one is expired, pick the other one.
  2207  */
  2208 PRBool
  2209 CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb)
  2211     PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
  2212     SECStatus rv;
  2213     PRBool newerbefore, newerafter;
  2215     rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
  2216     if ( rv != SECSuccess ) {
  2217 	return(PR_FALSE);
  2220     rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
  2221     if ( rv != SECSuccess ) {
  2222 	return(PR_TRUE);
  2225     newerbefore = PR_FALSE;
  2226     if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
  2227 	newerbefore = PR_TRUE;
  2230     newerafter = PR_FALSE;
  2231     if ( LL_CMP(notAfterA, >, notAfterB) ) {
  2232 	newerafter = PR_TRUE;
  2235     if ( newerbefore && newerafter ) {
  2236 	return(PR_TRUE);
  2239     if ( ( !newerbefore ) && ( !newerafter ) ) {
  2240 	return(PR_FALSE);
  2243     /* get current time */
  2244     now = PR_Now();
  2246     if ( newerbefore ) {
  2247 	/* cert A was issued after cert B, but expires sooner */
  2248 	/* if A is expired, then pick B */
  2249 	if ( LL_CMP(notAfterA, <, now ) ) {
  2250 	    return(PR_FALSE);
  2252 	return(PR_TRUE);
  2253     } else {
  2254 	/* cert B was issued after cert A, but expires sooner */
  2255 	/* if B is expired, then pick A */
  2256 	if ( LL_CMP(notAfterB, <, now ) ) {
  2257 	    return(PR_TRUE);
  2259 	return(PR_FALSE);
  2263 void
  2264 CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts)
  2266     unsigned int i;
  2268     if ( certs ) {
  2269 	for ( i = 0; i < ncerts; i++ ) {
  2270 	    if ( certs[i] ) {
  2271 		CERT_DestroyCertificate(certs[i]);
  2275 	PORT_Free(certs);
  2278     return;
  2281 char *
  2282 CERT_FixupEmailAddr(const char *emailAddr)
  2284     char *retaddr;
  2285     char *str;
  2287     if ( emailAddr == NULL ) {
  2288 	return(NULL);
  2291     /* copy the string */
  2292     str = retaddr = PORT_Strdup(emailAddr);
  2293     if ( str == NULL ) {
  2294 	return(NULL);
  2297     /* make it lower case */
  2298     while ( *str ) {
  2299 	*str = tolower( *str );
  2300 	str++;
  2303     return(retaddr);
  2306 /*
  2307  * NOTE - don't allow encode of govt-approved or invisible bits
  2308  */
  2309 SECStatus
  2310 CERT_DecodeTrustString(CERTCertTrust *trust, const char *trusts)
  2312     unsigned int i;
  2313     unsigned int *pflags;
  2315     if (!trust) {
  2316 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2317 	return SECFailure;
  2319     trust->sslFlags = 0;
  2320     trust->emailFlags = 0;
  2321     trust->objectSigningFlags = 0;
  2322     if (!trusts) {
  2323 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2324 	return SECFailure;
  2327     pflags = &trust->sslFlags;
  2329     for (i=0; i < PORT_Strlen(trusts); i++) {
  2330 	switch (trusts[i]) {
  2331 	  case 'p':
  2332 	      *pflags = *pflags | CERTDB_TERMINAL_RECORD;
  2333 	      break;
  2335 	  case 'P':
  2336 	      *pflags = *pflags | CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD;
  2337 	      break;
  2339 	  case 'w':
  2340 	      *pflags = *pflags | CERTDB_SEND_WARN;
  2341 	      break;
  2343 	  case 'c':
  2344 	      *pflags = *pflags | CERTDB_VALID_CA;
  2345 	      break;
  2347 	  case 'T':
  2348 	      *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
  2349 	      break;
  2351 	  case 'C' :
  2352 	      *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
  2353 	      break;
  2355 	  case 'u':
  2356 	      *pflags = *pflags | CERTDB_USER;
  2357 	      break;
  2359 	  case 'i':
  2360 	      *pflags = *pflags | CERTDB_INVISIBLE_CA;
  2361 	      break;
  2362 	  case 'g':
  2363 	      *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
  2364 	      break;
  2366 	  case ',':
  2367 	      if ( pflags == &trust->sslFlags ) {
  2368 		  pflags = &trust->emailFlags;
  2369 	      } else {
  2370 		  pflags = &trust->objectSigningFlags;
  2372 	      break;
  2373 	  default:
  2374 	      return SECFailure;
  2378     return SECSuccess;
  2381 static void
  2382 EncodeFlags(char *trusts, unsigned int flags)
  2384     if (flags & CERTDB_VALID_CA)
  2385 	if (!(flags & CERTDB_TRUSTED_CA) &&
  2386 	    !(flags & CERTDB_TRUSTED_CLIENT_CA))
  2387 	    PORT_Strcat(trusts, "c");
  2388     if (flags & CERTDB_TERMINAL_RECORD)
  2389 	if (!(flags & CERTDB_TRUSTED))
  2390 	    PORT_Strcat(trusts, "p");
  2391     if (flags & CERTDB_TRUSTED_CA)
  2392 	PORT_Strcat(trusts, "C");
  2393     if (flags & CERTDB_TRUSTED_CLIENT_CA)
  2394 	PORT_Strcat(trusts, "T");
  2395     if (flags & CERTDB_TRUSTED)
  2396 	PORT_Strcat(trusts, "P");
  2397     if (flags & CERTDB_USER)
  2398 	PORT_Strcat(trusts, "u");
  2399     if (flags & CERTDB_SEND_WARN)
  2400 	PORT_Strcat(trusts, "w");
  2401     if (flags & CERTDB_INVISIBLE_CA)
  2402 	PORT_Strcat(trusts, "I");
  2403     if (flags & CERTDB_GOVT_APPROVED_CA)
  2404 	PORT_Strcat(trusts, "G");
  2405     return;
  2408 char *
  2409 CERT_EncodeTrustString(CERTCertTrust *trust)
  2411     char tmpTrustSSL[32];
  2412     char tmpTrustEmail[32];
  2413     char tmpTrustSigning[32];
  2414     char *retstr = NULL;
  2416     if ( trust ) {
  2417 	tmpTrustSSL[0] = '\0';
  2418 	tmpTrustEmail[0] = '\0';
  2419 	tmpTrustSigning[0] = '\0';
  2421 	EncodeFlags(tmpTrustSSL, trust->sslFlags);
  2422 	EncodeFlags(tmpTrustEmail, trust->emailFlags);
  2423 	EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);
  2425 	retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,
  2426 			     tmpTrustSigning);
  2429     return(retstr);
  2432 SECStatus
  2433 CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
  2434 		 unsigned int ncerts, SECItem **derCerts,
  2435 		 CERTCertificate ***retCerts, PRBool keepCerts,
  2436 		 PRBool caOnly, char *nickname)
  2438     unsigned int i;
  2439     CERTCertificate **certs = NULL;
  2440     SECStatus rv;
  2441     unsigned int fcerts = 0;
  2443     if ( ncerts ) {
  2444 	certs = PORT_ZNewArray(CERTCertificate*, ncerts);
  2445 	if ( certs == NULL ) {
  2446 	    return(SECFailure);
  2449 	/* decode all of the certs into the temporary DB */
  2450 	for ( i = 0, fcerts= 0; i < ncerts; i++) {
  2451 	    certs[fcerts] = CERT_NewTempCertificate(certdb,
  2452 	                                            derCerts[i],
  2453 	                                            NULL,
  2454 	                                            PR_FALSE,
  2455 	                                            PR_TRUE);
  2456 	    if (certs[fcerts]) {
  2457 		SECItem subjKeyID = {siBuffer, NULL, 0};
  2458 		if (CERT_FindSubjectKeyIDExtension(certs[fcerts],
  2459 		                                   &subjKeyID) == SECSuccess) {
  2460 		    if (subjKeyID.data) {
  2461 			cert_AddSubjectKeyIDMapping(&subjKeyID, certs[fcerts]);
  2463 		    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
  2465 		fcerts++;
  2469 	if ( keepCerts ) {
  2470 	    for ( i = 0; i < fcerts; i++ ) {
  2471                 char* canickname = NULL;
  2472                 PRBool isCA;
  2474 		SECKEY_UpdateCertPQG(certs[i]);
  2476                 isCA = CERT_IsCACert(certs[i], NULL);
  2477                 if ( isCA ) {
  2478                     canickname = CERT_MakeCANickname(certs[i]);
  2481 		if(isCA && (fcerts > 1)) {
  2482 		    /* if we are importing only a single cert and specifying
  2483 		     * a nickname, we want to use that nickname if it a CA,
  2484 		     * otherwise if there are more than one cert, we don't
  2485 		     * know which cert it belongs to. But we still may try
  2486                      * the individual canickname from the cert itself.
  2487 		     */
  2488 		    rv = CERT_AddTempCertToPerm(certs[i], canickname, NULL);
  2489 		} else {
  2490 		    rv = CERT_AddTempCertToPerm(certs[i],
  2491                                                 nickname?nickname:canickname, NULL);
  2494                 PORT_Free(canickname);
  2495 		/* don't care if it fails - keep going */
  2500     if ( retCerts ) {
  2501 	*retCerts = certs;
  2502     } else {
  2503 	if (certs) {
  2504 	    CERT_DestroyCertArray(certs, fcerts);
  2508     return ((fcerts || !ncerts) ? SECSuccess : SECFailure);
  2511 /*
  2512  * a real list of certificates - need to convert CERTCertificateList
  2513  * stuff and ASN 1 encoder/decoder over to using this...
  2514  */
  2515 CERTCertList *
  2516 CERT_NewCertList(void)
  2518     PLArenaPool *arena = NULL;
  2519     CERTCertList *ret = NULL;
  2521     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2522     if ( arena == NULL ) {
  2523 	goto loser;
  2526     ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
  2527     if ( ret == NULL ) {
  2528 	goto loser;
  2531     ret->arena = arena;
  2533     PR_INIT_CLIST(&ret->list);
  2535     return(ret);
  2537 loser:
  2538     if ( arena != NULL ) {
  2539 	PORT_FreeArena(arena, PR_FALSE);
  2542     return(NULL);
  2545 void
  2546 CERT_DestroyCertList(CERTCertList *certs)
  2548     PRCList *node;
  2550     while( !PR_CLIST_IS_EMPTY(&certs->list) ) {
  2551 	node = PR_LIST_HEAD(&certs->list);
  2552 	CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
  2553 	PR_REMOVE_LINK(node);
  2556     PORT_FreeArena(certs->arena, PR_FALSE);
  2558     return;
  2561 void
  2562 CERT_RemoveCertListNode(CERTCertListNode *node)
  2564     CERT_DestroyCertificate(node->cert);
  2565     PR_REMOVE_LINK(&node->links);
  2566     return;
  2570 SECStatus
  2571 CERT_AddCertToListTailWithData(CERTCertList *certs, 
  2572 				CERTCertificate *cert, void *appData)
  2574     CERTCertListNode *node;
  2576     node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
  2577 						sizeof(CERTCertListNode));
  2578     if ( node == NULL ) {
  2579 	goto loser;
  2582     PR_INSERT_BEFORE(&node->links, &certs->list);
  2583     /* certs->count++; */
  2584     node->cert = cert;
  2585     node->appData = appData;
  2586     return(SECSuccess);
  2588 loser:
  2589     return(SECFailure);
  2592 SECStatus
  2593 CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert)
  2595     return CERT_AddCertToListTailWithData(certs, cert, NULL);
  2598 SECStatus
  2599 CERT_AddCertToListHeadWithData(CERTCertList *certs, 
  2600 					CERTCertificate *cert, void *appData)
  2602     CERTCertListNode *node;
  2603     CERTCertListNode *head;
  2605     head = CERT_LIST_HEAD(certs);
  2607     if (head == NULL) return CERT_AddCertToListTail(certs,cert);
  2609     node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
  2610 						sizeof(CERTCertListNode));
  2611     if ( node == NULL ) {
  2612 	goto loser;
  2615     PR_INSERT_BEFORE(&node->links, &head->links);
  2616     /* certs->count++; */
  2617     node->cert = cert;
  2618     node->appData = appData;
  2619     return(SECSuccess);
  2621 loser:
  2622     return(SECFailure);
  2625 SECStatus
  2626 CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert)
  2628     return CERT_AddCertToListHeadWithData(certs, cert, NULL);
  2631 /*
  2632  * Sort callback function to determine if cert a is newer than cert b.
  2633  * Not valid certs are considered older than valid certs.
  2634  */
  2635 PRBool
  2636 CERT_SortCBValidity(CERTCertificate *certa,
  2637 		    CERTCertificate *certb,
  2638 		    void *arg)
  2640     PRTime sorttime;
  2641     PRTime notBeforeA, notAfterA, notBeforeB, notAfterB;
  2642     SECStatus rv;
  2643     PRBool newerbefore, newerafter;
  2644     PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;
  2646     sorttime = *(PRTime *)arg;
  2648     rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
  2649     if ( rv != SECSuccess ) {
  2650 	return(PR_FALSE);
  2653     rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
  2654     if ( rv != SECSuccess ) {
  2655 	return(PR_TRUE);
  2657     newerbefore = PR_FALSE;
  2658     if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
  2659 	newerbefore = PR_TRUE;
  2661     newerafter = PR_FALSE;
  2662     if ( LL_CMP(notAfterA, >, notAfterB) ) {
  2663 	newerafter = PR_TRUE;
  2666     /* check if A is valid at sorttime */
  2667     if ( CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE)
  2668 	!= secCertTimeValid ) {
  2669 	aNotValid = PR_TRUE;
  2672     /* check if B is valid at sorttime */
  2673     if ( CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE)
  2674 	!= secCertTimeValid ) {
  2675 	bNotValid = PR_TRUE;
  2678     /* a is valid, b is not */
  2679     if ( bNotValid && ( ! aNotValid ) ) {
  2680 	return(PR_TRUE);
  2683     /* b is valid, a is not */
  2684     if ( aNotValid && ( ! bNotValid ) ) {
  2685 	return(PR_FALSE);
  2688     /* a and b are either valid or not valid */
  2689     if ( newerbefore && newerafter ) {
  2690 	return(PR_TRUE);
  2693     if ( ( !newerbefore ) && ( !newerafter ) ) {
  2694 	return(PR_FALSE);
  2697     if ( newerbefore ) {
  2698 	/* cert A was issued after cert B, but expires sooner */
  2699 	return(PR_TRUE);
  2700     } else {
  2701 	/* cert B was issued after cert A, but expires sooner */
  2702 	return(PR_FALSE);
  2707 SECStatus
  2708 CERT_AddCertToListSorted(CERTCertList *certs,
  2709 			 CERTCertificate *cert,
  2710 			 CERTSortCallback f,
  2711 			 void *arg)
  2713     CERTCertListNode *node;
  2714     CERTCertListNode *head;
  2715     PRBool ret;
  2717     node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
  2718 						sizeof(CERTCertListNode));
  2719     if ( node == NULL ) {
  2720 	goto loser;
  2723     head = CERT_LIST_HEAD(certs);
  2725     while ( !CERT_LIST_END(head, certs) ) {
  2727 	/* if cert is already in the list, then don't add it again */
  2728 	if ( cert == head->cert ) {
  2729 	    /*XXX*/
  2730 	    /* don't keep a reference */
  2731 	    CERT_DestroyCertificate(cert);
  2732 	    goto done;
  2735 	ret = (* f)(cert, head->cert, arg);
  2736 	/* if sort function succeeds, then insert before current node */
  2737 	if ( ret ) {
  2738 	    PR_INSERT_BEFORE(&node->links, &head->links);
  2739 	    goto done;
  2742 	head = CERT_LIST_NEXT(head);
  2744     /* if we get to the end, then just insert it at the tail */
  2745     PR_INSERT_BEFORE(&node->links, &certs->list);
  2747 done:    
  2748     /* certs->count++; */
  2749     node->cert = cert;
  2750     return(SECSuccess);
  2752 loser:
  2753     return(SECFailure);
  2756 /* This routine is here because pcertdb.c still has a call to it.
  2757  * The SMIME profile code in pcertdb.c should be split into high (find
  2758  * the email cert) and low (store the profile) code.  At that point, we
  2759  * can move this to certhigh.c where it belongs.
  2761  * remove certs from a list that don't have keyUsage and certType
  2762  * that match the given usage.
  2763  */
  2764 SECStatus
  2765 CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
  2766 			   PRBool ca)
  2768     unsigned int requiredKeyUsage;
  2769     unsigned int requiredCertType;
  2770     CERTCertListNode *node, *savenode;
  2771     SECStatus rv;
  2773     if (certList == NULL) goto loser;
  2775     rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,
  2776 					  &requiredCertType);
  2777     if ( rv != SECSuccess ) {
  2778 	goto loser;
  2781     node = CERT_LIST_HEAD(certList);
  2783     while ( !CERT_LIST_END(node, certList) ) {
  2785 	PRBool bad = (PRBool)(!node->cert);
  2787 	/* bad key usage ? */
  2788 	if ( !bad && 
  2789 	     CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess ) {
  2790 	    bad = PR_TRUE;
  2792 	/* bad cert type ? */
  2793 	if ( !bad ) {
  2794 	    unsigned int certType = 0;
  2795 	    if ( ca ) {
  2796 		/* This function returns a more comprehensive cert type that
  2797 		 * takes trust flags into consideration.  Should probably
  2798 		 * fix the cert decoding code to do this.
  2799 		 */
  2800 		(void)CERT_IsCACert(node->cert, &certType);
  2801 	    } else {
  2802 		certType = node->cert->nsCertType;
  2804 	    if ( !( certType & requiredCertType ) ) {
  2805 		bad = PR_TRUE;
  2809 	if ( bad ) {
  2810 	    /* remove the node if it is bad */
  2811 	    savenode = CERT_LIST_NEXT(node);
  2812 	    CERT_RemoveCertListNode(node);
  2813 	    node = savenode;
  2814 	} else {
  2815 	    node = CERT_LIST_NEXT(node);
  2818     return(SECSuccess);
  2820 loser:
  2821     return(SECFailure);
  2824 PRBool CERT_IsUserCert(CERTCertificate* cert)
  2826     CERTCertTrust trust;
  2827     SECStatus rv = SECFailure;
  2829     rv = CERT_GetCertTrust(cert, &trust);
  2830     if (rv == SECSuccess &&
  2831         ((trust.sslFlags & CERTDB_USER ) ||
  2832          (trust.emailFlags & CERTDB_USER ) ||
  2833          (trust.objectSigningFlags & CERTDB_USER )) ) {
  2834         return PR_TRUE;
  2835     } else {
  2836         return PR_FALSE;
  2840 SECStatus
  2841 CERT_FilterCertListForUserCerts(CERTCertList *certList)
  2843     CERTCertListNode *node, *freenode;
  2844     CERTCertificate *cert;
  2846     if (!certList) {
  2847         return SECFailure;
  2850     node = CERT_LIST_HEAD(certList);
  2852     while ( ! CERT_LIST_END(node, certList) ) {
  2853 	cert = node->cert;
  2854 	if ( PR_TRUE != CERT_IsUserCert(cert) ) {
  2855 	    /* Not a User Cert, so remove this cert from the list */
  2856 	    freenode = node;
  2857 	    node = CERT_LIST_NEXT(node);
  2858 	    CERT_RemoveCertListNode(freenode);
  2859 	} else {
  2860 	    /* Is a User cert, so leave it in the list */
  2861 	    node = CERT_LIST_NEXT(node);
  2865     return(SECSuccess);
  2868 static PZLock *certRefCountLock = NULL;
  2870 /*
  2871  * Acquire the cert reference count lock
  2872  * There is currently one global lock for all certs, but I'm putting a cert
  2873  * arg here so that it will be easy to make it per-cert in the future if
  2874  * that turns out to be necessary.
  2875  */
  2876 void
  2877 CERT_LockCertRefCount(CERTCertificate *cert)
  2879     PORT_Assert(certRefCountLock != NULL);
  2880     PZ_Lock(certRefCountLock);
  2881     return;
  2884 /*
  2885  * Free the cert reference count lock
  2886  */
  2887 void
  2888 CERT_UnlockCertRefCount(CERTCertificate *cert)
  2890     PRStatus prstat;
  2892     PORT_Assert(certRefCountLock != NULL);
  2894     prstat = PZ_Unlock(certRefCountLock);
  2896     PORT_Assert(prstat == PR_SUCCESS);
  2898     return;
  2901 static PZLock *certTrustLock = NULL;
  2903 /*
  2904  * Acquire the cert trust lock
  2905  * There is currently one global lock for all certs, but I'm putting a cert
  2906  * arg here so that it will be easy to make it per-cert in the future if
  2907  * that turns out to be necessary.
  2908  */
  2909 void
  2910 CERT_LockCertTrust(const CERTCertificate *cert)
  2912     PORT_Assert(certTrustLock != NULL);
  2913     PZ_Lock(certTrustLock);
  2914     return;
  2917 SECStatus
  2918 cert_InitLocks(void)
  2920     if ( certRefCountLock == NULL ) {
  2921         certRefCountLock = PZ_NewLock(nssILockRefLock);
  2922         PORT_Assert(certRefCountLock != NULL);
  2923         if (!certRefCountLock) {
  2924             return SECFailure;
  2928     if ( certTrustLock == NULL ) {
  2929         certTrustLock = PZ_NewLock(nssILockCertDB);
  2930         PORT_Assert(certTrustLock != NULL);
  2931         if (!certTrustLock) {
  2932             PZ_DestroyLock(certRefCountLock);
  2933             certRefCountLock = NULL;
  2934             return SECFailure;
  2938     return SECSuccess;
  2941 SECStatus
  2942 cert_DestroyLocks(void)
  2944     SECStatus rv = SECSuccess;
  2946     PORT_Assert(certRefCountLock != NULL);
  2947     if (certRefCountLock) {
  2948         PZ_DestroyLock(certRefCountLock);
  2949         certRefCountLock = NULL;
  2950     } else {
  2951         rv = SECFailure;
  2954     PORT_Assert(certTrustLock != NULL);
  2955     if (certTrustLock) {
  2956         PZ_DestroyLock(certTrustLock);
  2957         certTrustLock = NULL;
  2958     } else {
  2959         rv = SECFailure;
  2961     return rv;
  2964 /*
  2965  * Free the cert trust lock
  2966  */
  2967 void
  2968 CERT_UnlockCertTrust(const CERTCertificate *cert)
  2970     PRStatus prstat;
  2972     PORT_Assert(certTrustLock != NULL);
  2974     prstat = PZ_Unlock(certTrustLock);
  2976     PORT_Assert(prstat == PR_SUCCESS);
  2978     return;
  2982 /*
  2983  * Get the StatusConfig data for this handle
  2984  */
  2985 CERTStatusConfig *
  2986 CERT_GetStatusConfig(CERTCertDBHandle *handle)
  2988   return handle->statusConfig;
  2991 /*
  2992  * Set the StatusConfig data for this handle.  There
  2993  * should not be another configuration set.
  2994  */
  2995 void
  2996 CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
  2998   PORT_Assert(handle->statusConfig == NULL);
  2999   handle->statusConfig = statusConfig;
  3002 /*
  3003  * Code for dealing with subjKeyID to cert mappings.
  3004  */
  3006 static PLHashTable *gSubjKeyIDHash = NULL;
  3007 static PRLock      *gSubjKeyIDLock = NULL;
  3008 static PLHashTable *gSubjKeyIDSlotCheckHash = NULL;
  3009 static PRLock      *gSubjKeyIDSlotCheckLock = NULL;
  3011 static void *cert_AllocTable(void *pool, PRSize size)
  3013     return PORT_Alloc(size);
  3016 static void cert_FreeTable(void *pool, void *item)
  3018     PORT_Free(item);
  3021 static PLHashEntry* cert_AllocEntry(void *pool, const void *key)
  3023     return PORT_New(PLHashEntry);
  3026 static void cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
  3028     SECITEM_FreeItem((SECItem*)(he->value), PR_TRUE);
  3029     if (flag == HT_FREE_ENTRY) {
  3030         SECITEM_FreeItem((SECItem*)(he->key), PR_TRUE);
  3031         PORT_Free(he);
  3035 static PLHashAllocOps cert_AllocOps = {
  3036     cert_AllocTable, cert_FreeTable, cert_AllocEntry, cert_FreeEntry
  3037 };
  3039 SECStatus
  3040 cert_CreateSubjectKeyIDSlotCheckHash(void)
  3042     /*
  3043      * This hash is used to remember the series of a slot
  3044      * when we last checked for user certs
  3045      */
  3046     gSubjKeyIDSlotCheckHash = PL_NewHashTable(0, SECITEM_Hash,
  3047                                              SECITEM_HashCompare,
  3048                                              SECITEM_HashCompare,
  3049                                              &cert_AllocOps, NULL);
  3050     if (!gSubjKeyIDSlotCheckHash) {
  3051         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3052         return SECFailure;
  3054     gSubjKeyIDSlotCheckLock = PR_NewLock();
  3055     if (!gSubjKeyIDSlotCheckLock) {
  3056         PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
  3057         gSubjKeyIDSlotCheckHash = NULL;
  3058         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3059         return SECFailure;
  3061     return SECSuccess;
  3064 SECStatus
  3065 cert_CreateSubjectKeyIDHashTable(void)
  3067     gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  3068                                     SECITEM_HashCompare,
  3069                                     &cert_AllocOps, NULL);
  3070     if (!gSubjKeyIDHash) {
  3071         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3072         return SECFailure;
  3074     gSubjKeyIDLock = PR_NewLock();
  3075     if (!gSubjKeyIDLock) {
  3076         PL_HashTableDestroy(gSubjKeyIDHash);
  3077         gSubjKeyIDHash = NULL;
  3078         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3079         return SECFailure;
  3081     /* initialize the companion hash (for remembering slot series) */
  3082     if (cert_CreateSubjectKeyIDSlotCheckHash() != SECSuccess) {
  3083 	cert_DestroySubjectKeyIDHashTable();
  3084 	return SECFailure;
  3086     return SECSuccess;
  3089 SECStatus
  3090 cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
  3092     SECItem *newKeyID, *oldVal, *newVal;
  3093     SECStatus rv = SECFailure;
  3095     if (!gSubjKeyIDLock) {
  3096 	/* If one is created, then both are there.  So only check for one. */
  3097 	return SECFailure;
  3100     newVal = SECITEM_DupItem(&cert->derCert);
  3101     if (!newVal) {
  3102         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3103         goto done;
  3105     newKeyID = SECITEM_DupItem(subjKeyID);
  3106     if (!newKeyID) {
  3107         SECITEM_FreeItem(newVal, PR_TRUE);
  3108         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3109         goto done;
  3112     PR_Lock(gSubjKeyIDLock);
  3113     /* The hash table implementation does not free up the memory 
  3114      * associated with the key of an already existing entry if we add a 
  3115      * duplicate, so we would wind up leaking the previously allocated 
  3116      * key if we don't remove before adding.
  3117      */
  3118     oldVal = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
  3119     if (oldVal) {
  3120         PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
  3123     rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess :
  3124                                                                SECFailure;
  3125     PR_Unlock(gSubjKeyIDLock);
  3126 done:
  3127     return rv;
  3130 SECStatus
  3131 cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID)
  3133     SECStatus rv;
  3134     if (!gSubjKeyIDLock)
  3135         return SECFailure;
  3137     PR_Lock(gSubjKeyIDLock);
  3138     rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess :
  3139                                                            SECFailure;
  3140     PR_Unlock(gSubjKeyIDLock);
  3141     return rv;
  3144 SECStatus
  3145 cert_UpdateSubjectKeyIDSlotCheck(SECItem *slotid, int series)
  3147     SECItem *oldSeries, *newSlotid, *newSeries;
  3148     SECStatus rv = SECFailure;
  3150     if (!gSubjKeyIDSlotCheckLock) {
  3151 	return rv;
  3154     newSlotid = SECITEM_DupItem(slotid);
  3155     newSeries = SECITEM_AllocItem(NULL, NULL, sizeof(int));
  3156     if (!newSlotid || !newSeries ) {
  3157         PORT_SetError(SEC_ERROR_NO_MEMORY);
  3158         goto loser;
  3160     PORT_Memcpy(newSeries->data, &series, sizeof(int));
  3162     PR_Lock(gSubjKeyIDSlotCheckLock);
  3163     oldSeries = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
  3164     if (oldSeries) {
  3165 	/* 
  3166 	 * make sure we don't leak the key of an existing entry
  3167 	 * (similar to cert_AddSubjectKeyIDMapping, see comment there)
  3168 	 */
  3169         PL_HashTableRemove(gSubjKeyIDSlotCheckHash, slotid);
  3171     rv = (PL_HashTableAdd(gSubjKeyIDSlotCheckHash, newSlotid, newSeries)) ?
  3172          SECSuccess : SECFailure;
  3173     PR_Unlock(gSubjKeyIDSlotCheckLock);
  3174     if (rv == SECSuccess) {
  3175 	return rv;
  3178 loser:
  3179     if (newSlotid) {
  3180         SECITEM_FreeItem(newSlotid, PR_TRUE);
  3182     if (newSeries) {
  3183         SECITEM_FreeItem(newSeries, PR_TRUE);
  3185     return rv;
  3188 int
  3189 cert_SubjectKeyIDSlotCheckSeries(SECItem *slotid)
  3191     SECItem *seriesItem = NULL;
  3192     int series;
  3194     if (!gSubjKeyIDSlotCheckLock) {
  3195 	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
  3196 	return -1;
  3199     PR_Lock(gSubjKeyIDSlotCheckLock);
  3200     seriesItem = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
  3201     PR_Unlock(gSubjKeyIDSlotCheckLock);
  3202      /* getting a null series just means we haven't registered one yet, 
  3203       * just return 0 */
  3204     if (seriesItem == NULL) {
  3205 	return 0;
  3207     /* if we got a series back, assert if it's not the proper length. */
  3208     PORT_Assert(seriesItem->len == sizeof(int));
  3209     if (seriesItem->len != sizeof(int)) {
  3210 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  3211 	return -1;
  3213     PORT_Memcpy(&series, seriesItem->data, sizeof(int));
  3214     return series;
  3217 SECStatus
  3218 cert_DestroySubjectKeyIDSlotCheckHash(void)
  3220     if (gSubjKeyIDSlotCheckHash) {
  3221         PR_Lock(gSubjKeyIDSlotCheckLock);
  3222         PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
  3223         gSubjKeyIDSlotCheckHash = NULL;
  3224         PR_Unlock(gSubjKeyIDSlotCheckLock);
  3225         PR_DestroyLock(gSubjKeyIDSlotCheckLock);
  3226         gSubjKeyIDSlotCheckLock = NULL;
  3228     return SECSuccess;
  3231 SECStatus
  3232 cert_DestroySubjectKeyIDHashTable(void)
  3234     if (gSubjKeyIDHash) {
  3235         PR_Lock(gSubjKeyIDLock);
  3236         PL_HashTableDestroy(gSubjKeyIDHash);
  3237         gSubjKeyIDHash = NULL;
  3238         PR_Unlock(gSubjKeyIDLock);
  3239         PR_DestroyLock(gSubjKeyIDLock);
  3240         gSubjKeyIDLock = NULL;
  3242     cert_DestroySubjectKeyIDSlotCheckHash();
  3243     return SECSuccess;
  3246 SECItem*
  3247 cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID)
  3249     SECItem   *val;
  3251     if (!gSubjKeyIDLock)
  3252         return NULL;
  3254     PR_Lock(gSubjKeyIDLock);
  3255     val = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
  3256     if (val) {
  3257         val = SECITEM_DupItem(val);
  3259     PR_Unlock(gSubjKeyIDLock);
  3260     return val;
  3263 CERTCertificate*
  3264 CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
  3266     CERTCertificate *cert = NULL;
  3267     SECItem *derCert;
  3269     derCert = cert_FindDERCertBySubjectKeyID(subjKeyID);
  3270     if (derCert) {
  3271         cert = CERT_FindCertByDERCert(handle, derCert);
  3272         SECITEM_FreeItem(derCert, PR_TRUE);
  3274     return cert;

mercurial