diff --git a/mozilla/security/nss/lib/pki/pki3hack.c b/mozilla/security/nss/lib/pki/pki3hack.c index d4adcb699e5..473bf023620 100644 --- a/mozilla/security/nss/lib/pki/pki3hack.c +++ b/mozilla/security/nss/lib/pki/pki3hack.c @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.108 $ $Date: 2012-05-17 21:39:40 $"; +static const char CVS_ID[] = "@(#) $RCSfile: pki3hack.c,v $ $Revision: 1.109 $ $Date: 2012-07-27 21:41:52 $"; #endif /* DEBUG */ /* @@ -412,6 +412,50 @@ nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage) return match; } +static PRBool +nss3certificate_isTrustedForUsage(nssDecodedCert *dc, const NSSUsage *usage) +{ + CERTCertificate *cc; + PRBool ca; + SECStatus secrv; + unsigned int requiredFlags; + unsigned int trustFlags; + SECTrustType trustType; + CERTCertTrust trust; + + /* This is for NSS 3.3 functions that do not specify a usage */ + if (usage->anyUsage) { + return PR_FALSE; /* XXX is this right? */ + } + cc = (CERTCertificate *)dc->data; + ca = usage->nss3lookingForCA; + if (!ca) { + PRBool trusted; + unsigned int failedFlags; + secrv = cert_CheckLeafTrust(cc, usage->nss3usage, + &failedFlags, &trusted); + return secrv == SECSuccess && trusted; + } + secrv = CERT_TrustFlagsForCACertUsage(usage->nss3usage, &requiredFlags, + &trustType); + if (secrv != SECSuccess) { + return PR_FALSE; + } + secrv = CERT_GetCertTrust(cc, &trust); + if (secrv != SECSuccess) { + return PR_FALSE; + } + if (trustType == trustTypeNone) { + /* normally trustTypeNone usages accept any of the given trust bits + * being on as acceptable. */ + trustFlags = trust.sslFlags | trust.emailFlags | + trust.objectSigningFlags; + } else { + trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType); + } + return (trustFlags & requiredFlags) == requiredFlags; +} + static NSSASCII7 * nss3certificate_getEmailAddress(nssDecodedCert *dc) { @@ -462,6 +506,7 @@ nssDecodedPKIXCertificate_Create ( rvDC->isValidAtTime = nss3certificate_isValidAtTime; rvDC->isNewerThan = nss3certificate_isNewerThan; rvDC->matchUsage = nss3certificate_matchUsage; + rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage; rvDC->getEmailAddress = nss3certificate_getEmailAddress; rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber; } else { @@ -489,7 +534,9 @@ create_decoded_pkix_cert_from_nss3cert ( rvDC->isValidAtTime = nss3certificate_isValidAtTime; rvDC->isNewerThan = nss3certificate_isNewerThan; rvDC->matchUsage = nss3certificate_matchUsage; + rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage; rvDC->getEmailAddress = nss3certificate_getEmailAddress; + rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber; } return rvDC; } diff --git a/mozilla/security/nss/lib/pki/pkibase.c b/mozilla/security/nss/lib/pki/pkibase.c index 4e77a721eb9..8881b820a1c 100644 --- a/mozilla/security/nss/lib/pki/pkibase.c +++ b/mozilla/security/nss/lib/pki/pkibase.c @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef DEBUG -static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.35 $ $Date: 2012-05-17 21:39:40 $"; +static const char CVS_ID[] = "@(#) $RCSfile: pkibase.c,v $ $Revision: 1.36 $ $Date: 2012-07-27 21:41:52 $"; #endif /* DEBUG */ #ifndef DEV_H @@ -434,9 +434,12 @@ nssCertificateArray_FindBestCertificate ( ) { NSSCertificate *bestCert = NULL; + nssDecodedCert *bestdc = NULL; NSSTime *time, sTime; - PRBool haveUsageMatch = PR_FALSE; + PRBool bestCertMatches = PR_FALSE; PRBool thisCertMatches; + PRBool bestCertIsValidAtTime = PR_FALSE; + PRBool bestCertIsTrusted = PR_FALSE; if (timeOpt) { time = timeOpt; @@ -448,7 +451,7 @@ nssCertificateArray_FindBestCertificate ( return (NSSCertificate *)NULL; } for (; *certs; certs++) { - nssDecodedCert *dc, *bestdc; + nssDecodedCert *dc; NSSCertificate *c = *certs; dc = nssCertificate_GetDecoding(c); if (!dc) continue; @@ -458,34 +461,31 @@ nssCertificateArray_FindBestCertificate ( * the usage matched */ bestCert = nssCertificate_AddRef(c); - haveUsageMatch = thisCertMatches; + bestCertMatches = thisCertMatches; + bestdc = dc; continue; } else { - if (haveUsageMatch && !thisCertMatches) { + if (bestCertMatches && !thisCertMatches) { /* if already have a cert for this usage, and if this cert * doesn't have the correct usage, continue */ continue; - } else if (!haveUsageMatch && thisCertMatches) { + } else if (!bestCertMatches && thisCertMatches) { /* this one does match usage, replace the other */ nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); - haveUsageMatch = PR_TRUE; + bestCertMatches = thisCertMatches; + bestdc = dc; continue; } /* this cert match as well as any cert we've found so far, * defer to time/policies * */ } - bestdc = nssCertificate_GetDecoding(bestCert); - if (!bestdc) { - nssCertificate_Destroy(bestCert); - bestCert = nssCertificate_AddRef(c); - continue; - } /* time */ - if (bestdc->isValidAtTime(bestdc, time)) { + if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) { /* The current best cert is valid at time */ + bestCertIsValidAtTime = PR_TRUE; if (!dc->isValidAtTime(dc, time)) { /* If the new cert isn't valid at time, it's not better */ continue; @@ -496,14 +496,36 @@ nssCertificateArray_FindBestCertificate ( /* If the new cert is valid at time, it's better */ nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); + bestdc = dc; + bestCertIsValidAtTime = PR_TRUE; + continue; } } - /* either they are both valid at time, or neither valid; - * take the newer one + /* Either they are both valid at time, or neither valid. + * If only one is trusted for this usage, take it. */ + if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) { + bestCertIsTrusted = PR_TRUE; + if (!dc->isTrustedForUsage(dc, usage)) { + continue; + } + } else { + /* The current best cert is not trusted */ + if (dc->isTrustedForUsage(dc, usage)) { + /* If the new cert is trusted, it's better */ + nssCertificate_Destroy(bestCert); + bestCert = nssCertificate_AddRef(c); + bestdc = dc; + bestCertIsTrusted = PR_TRUE; + continue; + } + } + /* Otherwise, take the newer one. */ if (!bestdc->isNewerThan(bestdc, dc)) { nssCertificate_Destroy(bestCert); bestCert = nssCertificate_AddRef(c); + bestdc = dc; + continue; } /* policies */ /* XXX later -- defer to policies */ diff --git a/mozilla/security/nss/lib/pki/pkitm.h b/mozilla/security/nss/lib/pki/pkitm.h index d0fc8897909..e7f8a4dd2cf 100644 --- a/mozilla/security/nss/lib/pki/pkitm.h +++ b/mozilla/security/nss/lib/pki/pkitm.h @@ -6,7 +6,7 @@ #define PKITM_H #ifdef DEBUG -static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.16 $ $Date: 2012-04-25 14:50:07 $"; +static const char PKITM_CVS_ID[] = "@(#) $RCSfile: pkitm.h,v $ $Revision: 1.17 $ $Date: 2012-07-27 21:41:52 $"; #endif /* DEBUG */ /* @@ -58,6 +58,9 @@ struct nssDecodedCertStr { PRBool (*isNewerThan)(nssDecodedCert *dc, nssDecodedCert *cmpdc); /* does the usage for this cert match the requested usage? */ PRBool (*matchUsage)(nssDecodedCert *dc, const NSSUsage *usage); + /* is this cert trusted for the requested usage? */ + PRBool (*isTrustedForUsage)(nssDecodedCert *dc, + const NSSUsage *usage); /* extract the email address */ NSSASCII7 *(*getEmailAddress)(nssDecodedCert *dc); /* extract the DER-encoded serial number */