bug 171224, changes to path construction

r=nelsonb
This commit is contained in:
ian.mcgreer%sun.com 2002-10-01 14:32:15 +00:00
parent cc93338c09
commit 6199159d80
8 changed files with 257 additions and 98 deletions

View File

@ -34,7 +34,7 @@
/* /*
* Certificate handling code * Certificate handling code
* *
* $Id: certdb.c,v 1.42 2002/08/24 00:45:55 jpierre%netscape.com Exp $ * $Id: certdb.c,v 1.43 2002/10/01 14:32:07 ian.mcgreer%sun.com Exp $
*/ */
#include "nssilock.h" #include "nssilock.h"
@ -725,6 +725,64 @@ cert_GetKeyID(CERTCertificate *cert)
} }
static PRBool
cert_IsRootCert(CERTCertificate *cert)
{
SECStatus rv;
SECItem tmpitem;
/* cache the authKeyID extension, if present */
cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
/* it MUST be self-issued to be a root */
if (cert->derIssuer.len == 0 ||
!SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject))
{
return PR_FALSE;
}
/* check the authKeyID extension */
if (cert->authKeyID) {
/* authority key identifier is present */
if (cert->authKeyID->keyID.len > 0) {
/* the keyIdentifier field is set, look for subjectKeyID */
rv = CERT_FindSubjectKeyIDExten(cert, &tmpitem);
if (rv == SECSuccess) {
PRBool match;
/* also present, they MUST match for it to be a root */
match = SECITEM_ItemsAreEqual(&cert->authKeyID->keyID,
&tmpitem);
PORT_Free(tmpitem.data);
if (!match) return PR_FALSE; /* else fall through */
} else {
/* the subject key ID is required when AKI is present */
return PR_FALSE;
}
}
if (cert->authKeyID->authCertIssuer) {
SECItem *caName;
caName = (SECItem *)CERT_GetGeneralNameByType(
cert->authKeyID->authCertIssuer,
certDirectoryName, PR_TRUE);
if (caName) {
if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
return PR_FALSE;
} /* else fall through */
} /* else ??? could not get general name as directory name? */
}
if (cert->authKeyID->authCertSerialNumber.len > 0) {
if (!SECITEM_ItemsAreEqual(&cert->serialNumber,
&cert->authKeyID->authCertSerialNumber)) {
return PR_FALSE;
} /* else fall through */
}
/* all of the AKI fields that were present passed the test */
return PR_TRUE;
}
/* else the AKI was not present, so this is a root */
return PR_TRUE;
}
/* /*
* take a DER certificate and decode it into a certificate structure * take a DER certificate and decode it into a certificate structure
*/ */
@ -824,6 +882,9 @@ CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
goto loser; goto loser;
} }
/* determine if this is a root cert */
cert->isRoot = cert_IsRootCert(cert);
tmpname = CERT_NameToAscii(&cert->subject); tmpname = CERT_NameToAscii(&cert->subject);
if ( tmpname != NULL ) { if ( tmpname != NULL ) {
cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname); cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
@ -1721,7 +1782,7 @@ CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
ret = PR_FALSE; ret = PR_FALSE;
type = 0; type = 0;
if ( cert->trust && (cert->trust->sslFlags|cert->trust->emailFlags| if ( cert->trust && (cert->trust->sslFlags|cert->trust->emailFlags|
cert->trust->objectSigningFlags)) { cert->trust->objectSigningFlags)) {
trust = cert->trust; trust = cert->trust;
@ -1769,6 +1830,14 @@ CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
} }
} }
} }
/* the isRoot flag trumps all */
if (cert->isRoot) {
ret = PR_TRUE;
/* set only these by default, same as above */
type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
}
if ( rettype != NULL ) { if ( rettype != NULL ) {
*rettype = type; *rettype = type;
} }

View File

@ -33,7 +33,7 @@
/* /*
* certt.h - public data structures for the certificate library * certt.h - public data structures for the certificate library
* *
* $Id: certt.h,v 1.20 2002/08/07 03:42:45 jpierre%netscape.com Exp $ * $Id: certt.h,v 1.21 2002/10/01 14:32:09 ian.mcgreer%sun.com Exp $
*/ */
#ifndef _CERTT_H_ #ifndef _CERTT_H_
#define _CERTT_H_ #define _CERTT_H_
@ -285,13 +285,17 @@ struct CERTCertificateStr {
*/ */
CERTSubjectList *subjectList; CERTSubjectList *subjectList;
/* these belong in the static section, but are here to maintain
* the structure's integrity
*/
CERTAuthKeyID * authKeyID; /* x509v3 authority key identifier */
PRBool isRoot; /* cert is the end of a chain */
/* these fields are used by client GUI code to keep track of ssl sockets /* these fields are used by client GUI code to keep track of ssl sockets
* that are blocked waiting on GUI feedback related to this cert. * that are blocked waiting on GUI feedback related to this cert.
* XXX - these should be moved into some sort of application specific * XXX - these should be moved into some sort of application specific
* data structure. They are only used by the browser right now. * data structure. They are only used by the browser right now.
*/ */
struct SECSocketNode *socketlist;
int socketcount;
struct SECSocketNode *authsocketlist; struct SECSocketNode *authsocketlist;
int series; /* was int authsocketcount; record the series of the pkcs11ID */ int series; /* was int authsocketcount; record the series of the pkcs11ID */

View File

@ -1111,8 +1111,14 @@ loser:
derCert.data = (unsigned char *)stanCert->encoding.data; derCert.data = (unsigned char *)stanCert->encoding.data;
derCert.type = siBuffer; derCert.type = siBuffer;
SECITEM_CopyItem(arena, &chain->certs[i], &derCert); SECITEM_CopyItem(arena, &chain->certs[i], &derCert);
CERT_DestroyCertificate(cCert);
stanCert = stanChain[++i]; stanCert = stanChain[++i];
if (!stanCert && !cCert->isRoot) {
/* reached the end of the chain, but the final cert is
* not a root. Don't discard it.
*/
includeRoot = PR_TRUE;
}
CERT_DestroyCertificate(cCert);
} }
if ( !includeRoot && len > 1) { if ( !includeRoot && len > 1) {
chain->len = len - 1; chain->len = len - 1;

View File

@ -619,7 +619,6 @@ cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
PRBool isca; PRBool isca;
PRBool isFortezzaV1 = PR_FALSE; PRBool isFortezzaV1 = PR_FALSE;
SECStatus rv; SECStatus rv;
SECComparison rvCompare;
SECStatus rvFinal = SECSuccess; SECStatus rvFinal = SECSuccess;
int count; int count;
int currentPathLen = -1; int currentPathLen = -1;
@ -924,9 +923,7 @@ cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
/* make sure that the issuer is not self signed. If it is, then /* make sure that the issuer is not self signed. If it is, then
* stop here to prevent looping. * stop here to prevent looping.
*/ */
rvCompare = SECITEM_CompareItem(&issuerCert->derSubject, if (issuerCert->isRoot) {
&issuerCert->derIssuer);
if (rvCompare == SECEqual) {
PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
LOG_ERROR(log, issuerCert, count+1, 0); LOG_ERROR(log, issuerCert, count+1, 0);
goto loser; goto loser;

View File

@ -32,7 +32,7 @@
*/ */
#ifdef DEBUG #ifdef DEBUG
static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.43 $ $Date: 2002/09/23 21:32:31 $ $Name: $"; static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.44 $ $Date: 2002/10/01 14:32:15 $ $Name: $";
#endif /* DEBUG */ #endif /* DEBUG */
#ifndef NSSPKI_H #ifndef NSSPKI_H
@ -280,20 +280,48 @@ nssCertificate_GetDecoding (
static NSSCertificate ** static NSSCertificate **
filter_subject_certs_for_id ( filter_subject_certs_for_id (
NSSCertificate **subjectCerts, NSSCertificate **subjectCerts,
NSSItem *id void *id
) )
{ {
NSSCertificate **si; NSSCertificate **si;
nssDecodedCert *dcp; nssDecodedCert *dcp;
int nextOpenSlot = 0; int nextOpenSlot = 0;
int i;
nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
nssCertIDMatch match;
/* walk the subject certs */ /* walk the subject certs */
for (si = subjectCerts; *si; si++) { for (si = subjectCerts; *si; si++) {
dcp = nssCertificate_GetDecoding(*si); dcp = nssCertificate_GetDecoding(*si);
if (dcp->matchIdentifier(dcp, id)) { if (!dcp) {
/* this cert has the correct identifier */ NSSCertificate_Destroy(*si);
continue;
}
match = dcp->matchIdentifier(dcp, id);
switch (match) {
case nssCertIDMatch_Yes:
if (matchLevel == nssCertIDMatch_Unknown) {
/* we have non-definitive matches, forget them */
for (i = 0; i < nextOpenSlot; i++) {
NSSCertificate_Destroy(subjectCerts[i]);
subjectCerts[i] = NULL;
}
nextOpenSlot = 0;
/* only keep definitive matches from now on */
matchLevel = nssCertIDMatch_Yes;
}
/* keep the cert */
subjectCerts[nextOpenSlot++] = *si; subjectCerts[nextOpenSlot++] = *si;
} else { break;
case nssCertIDMatch_Unknown:
if (matchLevel == nssCertIDMatch_Unknown) {
/* only have non-definitive matches so far, keep it */
subjectCerts[nextOpenSlot++] = *si;
break;
}
/* else fall through, we have a definitive match already */
case nssCertIDMatch_No:
default:
NSSCertificate_Destroy(*si); NSSCertificate_Destroy(*si);
*si = NULL; *si = NULL;
} }
@ -302,6 +330,28 @@ filter_subject_certs_for_id (
return subjectCerts; return subjectCerts;
} }
static NSSCertificate **
filter_certs_for_valid_issuers (
NSSCertificate **certs
)
{
NSSCertificate **cp;
nssDecodedCert *dcp;
int nextOpenSlot = 0;
int i;
for (cp = certs; *cp; cp++) {
dcp = nssCertificate_GetDecoding(*cp);
if (dcp && dcp->isValidIssuer(dcp)) {
certs[nextOpenSlot++] = *cp;
} else {
NSSCertificate_Destroy(*cp);
}
}
certs[nextOpenSlot] = NULL;
return certs;
}
static NSSCertificate * static NSSCertificate *
find_cert_issuer ( find_cert_issuer (
NSSCertificate *c, NSSCertificate *c,
@ -343,15 +393,15 @@ find_cert_issuer (
certs = nssCertificateArray_Join(ccIssuers, tdIssuers); certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
if (certs) { if (certs) {
nssDecodedCert *dc = NULL; nssDecodedCert *dc = NULL;
NSSItem *issuerID = NULL; void *issuerID = NULL;
dc = nssCertificate_GetDecoding(c); dc = nssCertificate_GetDecoding(c);
if (dc) { if (dc) {
issuerID = dc->getIssuerIdentifier(dc); issuerID = dc->getIssuerIdentifier(dc);
} }
if (issuerID) { if (issuerID) {
certs = filter_subject_certs_for_id(certs, issuerID); certs = filter_subject_certs_for_id(certs, issuerID);
nssItem_Destroy(issuerID); }
} certs = filter_certs_for_valid_issuers(certs);
issuer = nssCertificateArray_FindBestCertificate(certs, issuer = nssCertificateArray_FindBestCertificate(certs,
timeOpt, timeOpt,
usage, usage,
@ -378,18 +428,22 @@ nssCertificate_BuildChain (
PRStatus *statusOpt PRStatus *statusOpt
) )
{ {
PRStatus status;
NSSCertificate **rvChain; NSSCertificate **rvChain;
#ifdef NSS_3_4_CODE #ifdef NSS_3_4_CODE
NSSCertificate *cp; NSSCertificate *cp;
CERTCertificate *cCert;
#endif #endif
NSSUsage issuerUsage = *usage;
NSSTrustDomain *td; NSSTrustDomain *td;
nssPKIObjectCollection *collection; nssPKIObjectCollection *collection;
td = NSSCertificate_GetTrustDomain(c); td = NSSCertificate_GetTrustDomain(c);
#ifdef NSS_3_4_CODE #ifdef NSS_3_4_CODE
if (!td) { if (!td) {
td = STAN_GetDefaultTrustDomain(); td = STAN_GetDefaultTrustDomain();
} }
/* bump the usage up to CA level */
issuerUsage.nss3lookingForCA = PR_TRUE;
#endif #endif
if (statusOpt) *statusOpt = PR_SUCCESS; if (statusOpt) *statusOpt = PR_SUCCESS;
collection = nssCertificateCollection_Create(td, NULL); collection = nssCertificateCollection_Create(td, NULL);
@ -401,24 +455,22 @@ nssCertificate_BuildChain (
if (rvLimit == 1) { if (rvLimit == 1) {
goto finish; goto finish;
} }
while (!nssItem_Equal(&c->subject, &c->issuer, &status)) { /* XXX This breaks code for which NSS_3_4_CODE is not defined (pure
* 4.0 builds). That won't affect the tip. But be careful
* when merging 4.0!!!
*/
while (c != (NSSCertificate *)NULL) {
#ifdef NSS_3_4_CODE #ifdef NSS_3_4_CODE
cCert = STAN_GetCERTCertificate(c);
if (cCert->isRoot) {
/* not including the issuer of the self-signed cert, which is,
* of course, itself
*/
break;
}
cp = c; cp = c;
#endif #endif
c = find_cert_issuer(c, timeOpt, usage, policiesOpt); c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt);
#ifdef NSS_3_4_CODE
if (!c) {
PRBool tmpca = usage->nss3lookingForCA;
usage->nss3lookingForCA = PR_TRUE;
c = find_cert_issuer(cp, timeOpt, usage, policiesOpt);
if (!c && !usage->anyUsage) {
usage->anyUsage = PR_TRUE;
c = find_cert_issuer(cp, timeOpt, usage, policiesOpt);
usage->anyUsage = PR_FALSE;
}
usage->nss3lookingForCA = tmpca;
}
#endif /* NSS_3_4_CODE */
if (c) { if (c) {
nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c); nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
nssCertificate_Destroy(c); /* collection has it */ nssCertificate_Destroy(c); /* collection has it */

View File

@ -32,7 +32,7 @@
*/ */
#ifdef DEBUG #ifdef DEBUG
static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.69 $ $Date: 2002/09/30 20:33:44 $ $Name: $"; static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.70 $ $Date: 2002/10/01 14:32:15 $ $Name: $";
#endif /* DEBUG */ #endif /* DEBUG */
/* /*
@ -231,61 +231,75 @@ nss3certificate_getIdentifier(nssDecodedCert *dc)
return rvID; return rvID;
} }
static NSSItem * static void *
nss3certificate_getIssuerIdentifier(nssDecodedCert *dc) nss3certificate_getIssuerIdentifier(nssDecodedCert *dc)
{ {
CERTCertificate *c = (CERTCertificate *)dc->data; CERTCertificate *c = (CERTCertificate *)dc->data;
CERTAuthKeyID *cAuthKeyID; return (void *)c->authKeyID;
PRArenaPool *tmpArena = NULL; }
NSSItem *rvID = NULL;
tmpArena = PORT_NewArena(512); static nssCertIDMatch
cAuthKeyID = CERT_FindAuthKeyIDExten(tmpArena, c); nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id)
if (cAuthKeyID == NULL) { {
goto done; CERTCertificate *c = (CERTCertificate *)dc->data;
CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id;
SECItem skid;
nssCertIDMatch match = nssCertIDMatch_Unknown;
/* keyIdentifier */
if (authKeyID->keyID.len > 0) {
if (CERT_FindSubjectKeyIDExten(c, &skid) == SECSuccess) {
PRBool skiEqual;
skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid);
PORT_Free(skid.data);
if (skiEqual) {
/* change the state to positive match, but keep going */
match = nssCertIDMatch_Yes;
} else {
/* exit immediately on failure */
return nssCertIDMatch_No;
}
} /* else fall through */
} }
if (cAuthKeyID->keyID.data) {
rvID = nssItem_Create(NULL, NULL, cAuthKeyID->keyID.len, /* issuer/serial (treated as pair) */
cAuthKeyID->keyID.data); if (authKeyID->authCertIssuer) {
} else if (cAuthKeyID->authCertIssuer) {
SECItem *caName = NULL; SECItem *caName = NULL;
CERTIssuerAndSN issuerSN; SECItem *caSN = &authKeyID->authCertSerialNumber;
CERTCertificate *issuer = NULL;
caName = (SECItem *)CERT_GetGeneralNameByType( caName = (SECItem *)CERT_GetGeneralNameByType(
cAuthKeyID->authCertIssuer, authKeyID->authCertIssuer,
certDirectoryName, PR_TRUE); certDirectoryName, PR_TRUE);
if (caName == NULL) { if (caName == NULL) {
goto done; /* this is some kind of error, so treat it as unknown */
return nssCertIDMatch_Unknown;
} }
issuerSN.derIssuer.data = caName->data; if (SECITEM_ItemsAreEqual(&c->derSubject, caName) &&
issuerSN.derIssuer.len = caName->len; SECITEM_ItemsAreEqual(&c->serialNumber, caSN))
issuerSN.derIssuer.type = siBuffer; {
issuerSN.serialNumber.data = cAuthKeyID->authCertSerialNumber.data; /* change the state to positive match, but keep going */
issuerSN.serialNumber.len = cAuthKeyID->authCertSerialNumber.len; match = nssCertIDMatch_Yes;
issuerSN.serialNumber.type = siBuffer; } else {
issuer = PK11_FindCertByIssuerAndSN(NULL, &issuerSN, NULL); /* exit immediately on failure */
if (issuer) { return nssCertIDMatch_No;
rvID = nssItem_Create(NULL, NULL, issuer->subjectKeyID.len,
issuer->subjectKeyID.data);
CERT_DestroyCertificate(issuer);
} }
} }
done:
if (tmpArena) PORT_FreeArena(tmpArena, PR_FALSE); /* If the issued cert has a keyIdentifier field with a value, but
return rvID; * this issuer cert does not have a subjectKeyID extension, and
* the issuer/serial number fields of the authKeyID extension
* are empty, the state will be Unknown. Otherwise it should have
* been set to Yes.
*/
return match;
} }
static PRBool static PRBool
nss3certificate_matchIdentifier(nssDecodedCert *dc, NSSItem *id) nss3certificate_isValidIssuer(nssDecodedCert *dc)
{ {
CERTCertificate *c = (CERTCertificate *)dc->data; CERTCertificate *c = (CERTCertificate *)dc->data;
SECItem *subjectKeyID, authKeyID; unsigned int ignore;
subjectKeyID = &c->subjectKeyID; return CERT_IsCACert(c, &ignore);
SECITEM_FROM_NSSITEM(&authKeyID, id);
if (SECITEM_CompareItem(subjectKeyID, &authKeyID) == SECEqual) {
return PR_TRUE;
}
return PR_FALSE;
} }
static NSSUsage * static NSSUsage *
@ -331,6 +345,11 @@ nss3certificate_matchUsage(nssDecodedCert *dc, NSSUsage *usage)
CERTCertificate *cc = (CERTCertificate *)dc->data; CERTCertificate *cc = (CERTCertificate *)dc->data;
SECCertUsage secUsage = usage->nss3usage; SECCertUsage secUsage = usage->nss3usage;
PRBool ca = usage->nss3lookingForCA; PRBool ca = usage->nss3lookingForCA;
/* This is for NSS 3.3 functions that do not specify a usage */
if (usage->anyUsage) {
return PR_TRUE;
}
secrv = CERT_KeyUsageAndTypeForCertUsage(secUsage, ca, secrv = CERT_KeyUsageAndTypeForCertUsage(secUsage, ca,
&requiredKeyUsage, &requiredKeyUsage,
&requiredCertType); &requiredCertType);
@ -391,6 +410,7 @@ nssDecodedPKIXCertificate_Create (
rvDC->getIdentifier = nss3certificate_getIdentifier; rvDC->getIdentifier = nss3certificate_getIdentifier;
rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
rvDC->matchIdentifier = nss3certificate_matchIdentifier; rvDC->matchIdentifier = nss3certificate_matchIdentifier;
rvDC->isValidIssuer = nss3certificate_isValidIssuer;
rvDC->getUsage = nss3certificate_getUsage; rvDC->getUsage = nss3certificate_getUsage;
rvDC->isValidAtTime = nss3certificate_isValidAtTime; rvDC->isValidAtTime = nss3certificate_isValidAtTime;
rvDC->isNewerThan = nss3certificate_isNewerThan; rvDC->isNewerThan = nss3certificate_isNewerThan;
@ -413,6 +433,7 @@ create_decoded_pkix_cert_from_nss3cert (
rvDC->getIdentifier = nss3certificate_getIdentifier; rvDC->getIdentifier = nss3certificate_getIdentifier;
rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
rvDC->matchIdentifier = nss3certificate_matchIdentifier; rvDC->matchIdentifier = nss3certificate_matchIdentifier;
rvDC->isValidIssuer = nss3certificate_isValidIssuer;
rvDC->getUsage = nss3certificate_getUsage; rvDC->getUsage = nss3certificate_getUsage;
rvDC->isValidAtTime = nss3certificate_isValidAtTime; rvDC->isValidAtTime = nss3certificate_isValidAtTime;
rvDC->isNewerThan = nss3certificate_isNewerThan; rvDC->isNewerThan = nss3certificate_isNewerThan;

View File

@ -32,7 +32,7 @@
*/ */
#ifdef DEBUG #ifdef DEBUG
static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.15 $ $Date: 2002/09/23 21:32:33 $ $Name: $"; static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.16 $ $Date: 2002/10/01 14:32:15 $ $Name: $";
#endif /* DEBUG */ #endif /* DEBUG */
#ifndef DEV_H #ifndef DEV_H
@ -429,6 +429,9 @@ nssCertificateArray_FindBestCertificate (
{ {
NSSCertificate *bestCert = NULL; NSSCertificate *bestCert = NULL;
NSSTime *time, sTime; NSSTime *time, sTime;
PRBool haveUsageMatch = PR_FALSE;
PRBool thisCertMatches;
if (timeOpt) { if (timeOpt) {
time = timeOpt; time = timeOpt;
} else { } else {
@ -442,32 +445,31 @@ nssCertificateArray_FindBestCertificate (
nssDecodedCert *dc, *bestdc; nssDecodedCert *dc, *bestdc;
NSSCertificate *c = *certs; NSSCertificate *c = *certs;
dc = nssCertificate_GetDecoding(c); dc = nssCertificate_GetDecoding(c);
if (!dc) continue;
thisCertMatches = dc->matchUsage(dc, usage);
if (!bestCert) { if (!bestCert) {
/* take the first cert with matching usage */ /* always take the first cert, but remember whether or not
#ifdef NSS_3_4_CODE * the usage matched
if (usage->anyUsage) { */
#else bestCert = nssCertificate_AddRef(c);
if (!usage || usage->anyUsage) { haveUsageMatch = thisCertMatches;
#endif
bestCert = nssCertificate_AddRef(c);
} else {
if (dc->matchUsage(dc, usage)) {
bestCert = nssCertificate_AddRef(c);
}
}
continue; continue;
} else { } else {
/* already have a cert for this usage, if this cert doesn't have if (haveUsageMatch && !thisCertMatches) {
* the correct usage, continue /* if already have a cert for this usage, and if this cert
* if ths cert does match usage, defer to time/policies * doesn't have the correct usage, continue
*/ */
#ifdef NSS_3_4_CODE continue;
if (!usage->anyUsage && !dc->matchUsage(dc, usage)) { } else if (!haveUsageMatch && thisCertMatches) {
#else /* this one does match usage, replace the other */
if (PR_TRUE) { nssCertificate_Destroy(bestCert);
#endif bestCert = nssCertificate_AddRef(c);
haveUsageMatch = PR_TRUE;
continue; continue;
} }
/* this cert match as well as any cert we've found so far,
* defer to time/policies
* */
} }
bestdc = nssCertificate_GetDecoding(bestCert); bestdc = nssCertificate_GetDecoding(bestCert);
/* time */ /* time */

View File

@ -35,7 +35,7 @@
#define PKITM_H #define PKITM_H
#ifdef DEBUG #ifdef DEBUG
static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.9 $ $Date: 2002/04/18 17:30:04 $ $Name: $"; static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.10 $ $Date: 2002/10/01 14:32:15 $ $Name: $";
#endif /* DEBUG */ #endif /* DEBUG */
/* /*
@ -54,6 +54,12 @@ static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.9 $
PR_BEGIN_EXTERN_C PR_BEGIN_EXTERN_C
typedef enum nssCertIDMatchEnum {
nssCertIDMatch_Yes = 0,
nssCertIDMatch_No = 1,
nssCertIDMatch_Unknown = 2
} nssCertIDMatch;
/* /*
* nssDecodedCert * nssDecodedCert
* *
@ -68,9 +74,11 @@ struct nssDecodedCertStr {
/* returns the unique identifier for the cert */ /* returns the unique identifier for the cert */
NSSItem * (*getIdentifier)(nssDecodedCert *dc); NSSItem * (*getIdentifier)(nssDecodedCert *dc);
/* returns the unique identifier for this cert's issuer */ /* returns the unique identifier for this cert's issuer */
NSSItem * (*getIssuerIdentifier)(nssDecodedCert *dc); void * (*getIssuerIdentifier)(nssDecodedCert *dc);
/* is id the identifier for this cert? */ /* is id the identifier for this cert? */
PRBool (*matchIdentifier)(nssDecodedCert *dc, NSSItem *id); nssCertIDMatch (*matchIdentifier)(nssDecodedCert *dc, void *id);
/* is this cert a valid CA cert? */
PRBool (*isValidIssuer)(nssDecodedCert *dc);
/* returns the cert usage */ /* returns the cert usage */
NSSUsage * (*getUsage)(nssDecodedCert *dc); NSSUsage * (*getUsage)(nssDecodedCert *dc);
/* is time within the validity period of the cert? */ /* is time within the validity period of the cert? */