Bug 406755, EV certs not recognized as EV with some cross-certification scenarios r=rrelyea, blocking1.9=dsicore

This commit is contained in:
kaie@kuix.de 2008-03-16 06:42:32 -07:00
Родитель 8386d5d715
Коммит 4d099dd482
2 изменённых файлов: 233 добавлений и 14 удалений

Просмотреть файл

@ -45,6 +45,7 @@
#include "nsTArray.h"
#include "cert.h"
#include "base64.h"
#include "nsNSSComponent.h"
#include "nsNSSIOLayer.h"
#include "nsNSSCertificate.h"
@ -74,6 +75,9 @@ struct nsMyTrustedEVInfo
// (We can't have an empty list, so we'll use a dummy entry)
SECOidTag oid_tag;
char *ev_root_sha1_fingerprint;
char *issuer_base64;
char *serial_base64;
CERTCertificate *cert;
};
static struct nsMyTrustedEVInfo myTrustedEVInfos[] = {
@ -83,6 +87,11 @@ static struct nsMyTrustedEVInfo myTrustedEVInfos[] = {
"Go Daddy EV OID a",
SEC_OID_UNKNOWN,
"27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4",
"MGMxCzAJBgNVBAYTAlVTMSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIElu"
"Yy4xMTAvBgNVBAsTKEdvIERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRo"
"b3JpdHk=",
"AA==",
nsnull
},
{
// E=info@valicert.com,CN=http://www.valicert.com/,OU=ValiCert Class 2 Policy Validation Authority,O=\"ValiCert, Inc.\",L=ValiCert Validation Network
@ -90,6 +99,12 @@ static struct nsMyTrustedEVInfo myTrustedEVInfos[] = {
"Go Daddy EV OID a",
SEC_OID_UNKNOWN,
"31:7A:2A:D0:7F:2B:33:5E:F5:A1:C3:4E:4B:57:E8:B7:D8:F1:FC:A6",
"MIG7MSQwIgYDVQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNV"
"BAoTDlZhbGlDZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAyIFBv"
"bGljeSBWYWxpZGF0aW9uIEF1dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52"
"YWxpY2VydC5jb20vMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHZhbGljZXJ0LmNvbQ==",
"AQ==",
nsnull
},
{
// E=info@valicert.com,CN=http://www.valicert.com/,OU=ValiCert Class 2 Policy Validation Authority,O=\"ValiCert, Inc.\",L=ValiCert Validation Network
@ -97,6 +112,12 @@ static struct nsMyTrustedEVInfo myTrustedEVInfos[] = {
"Go Daddy EV OID b",
SEC_OID_UNKNOWN,
"31:7A:2A:D0:7F:2B:33:5E:F5:A1:C3:4E:4B:57:E8:B7:D8:F1:FC:A6",
"MIG7MSQwIgYDVQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNV"
"BAoTDlZhbGlDZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAyIFBv"
"bGljeSBWYWxpZGF0aW9uIEF1dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52"
"YWxpY2VydC5jb20vMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHZhbGljZXJ0LmNvbQ==",
"AQ==",
nsnull
},
{
// OU=Starfield Class 2 Certification Authority,O=\"Starfield Technologies, Inc.\",C=US
@ -104,27 +125,46 @@ static struct nsMyTrustedEVInfo myTrustedEVInfos[] = {
"Go Daddy EV OID b",
SEC_OID_UNKNOWN,
"AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A",
"MGgxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVz"
"LCBJbmMuMTIwMAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9u"
"IEF1dGhvcml0eQ==",
"AA==",
nsnull
},
{
// CN=DigiCert High Assurance EV Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US
"2.16.840.1.114412.2.1",
"DigiCert EV OID",
SEC_OID_UNKNOWN,
"5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25"
"5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25",
"MGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT"
"EHd3dy5kaWdpY2VydC5jb20xKzApBgNVBAMTIkRpZ2lDZXJ0IEhpZ2ggQXNzdXJh"
"bmNlIEVWIFJvb3QgQ0E=",
"AqxcJmoLQJuPC3nyrkYldw==",
nsnull
},
{
// CN=QuoVadis Root CA 2,O=QuoVadis Limited,C=BM
"1.3.6.1.4.1.8024.0.2.100.1.2",
"Quo Vadis EV OID",
SEC_OID_UNKNOWN,
"CA:3A:FB:CF:12:40:36:4B:44:B2:16:20:88:80:48:39:19:93:7C:F7"
"CA:3A:FB:CF:12:40:36:4B:44:B2:16:20:88:80:48:39:19:93:7C:F7",
"MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYD"
"VQQDExJRdW9WYWRpcyBSb290IENBIDI=",
"BQk=",
nsnull
},
{
// OU=Class 3 Public Primary Certification Authority,O=\"VeriSign, Inc.\",C=US
"2.16.840.1.113733.1.7.23.6",
"Verisign EV OID",
SEC_OID_UNKNOWN,
"74:2C:31:92:E6:07:E4:24:EB:45:49:54:2B:E1:BB:C5:3E:61:74:E2"
"74:2C:31:92:E6:07:E4:24:EB:45:49:54:2B:E1:BB:C5:3E:61:74:E2",
"MF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE"
"CxMuQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0"
"eQ==",
"cLrkHRDZKTS2OMp7A8y6vw==",
nsnull
},
{
// OU=Sample Certification Authority,O=\"Sample, Inc.\",C=US
@ -132,6 +172,9 @@ static struct nsMyTrustedEVInfo myTrustedEVInfos[] = {
0, // for real entries use a string like "Sample INVALID EV OID"
SEC_OID_UNKNOWN,
"00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33"
"Cg==",
"Cg==",
nsnull
}
};
@ -165,6 +208,9 @@ nsMyTrustedEVInfoClass::nsMyTrustedEVInfoClass()
oid_name = nsnull;
oid_tag = SEC_OID_UNKNOWN;
ev_root_sha1_fingerprint = nsnull;
issuer_base64 = nsnull;
serial_base64 = nsnull;
cert = nsnull;
}
nsMyTrustedEVInfoClass::~nsMyTrustedEVInfoClass()
@ -172,6 +218,10 @@ nsMyTrustedEVInfoClass::~nsMyTrustedEVInfoClass()
free(dotted_oid);
free(oid_name);
free(ev_root_sha1_fingerprint);
free(issuer_base64);
free(serial_base64);
if (cert)
CERT_DestroyCertificate(cert);
}
typedef nsTArray< nsMyTrustedEVInfoClass* > testEVArray;
@ -258,10 +308,10 @@ loadTestEVInfos()
PRBool found_error = PR_FALSE;
enum {
pos_fingerprint, pos_readable_oid
pos_fingerprint, pos_readable_oid, pos_issuer, pos_serial
} reader_position = pos_fingerprint;
nsCString fingerprint, readable_oid;
nsCString fingerprint, readable_oid, issuer, serial;
while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
++line_counter;
@ -289,6 +339,16 @@ loadTestEVInfos()
else if (reader_position == pos_readable_oid &&
descriptor.EqualsLiteral(("2_readable_oid"))) {
readable_oid = data;
reader_position = pos_issuer;
}
else if (reader_position == pos_issuer &&
descriptor.EqualsLiteral(("3_issuer"))) {
issuer = data;
reader_position = pos_serial;
}
else if (reader_position == pos_readable_oid &&
descriptor.EqualsLiteral(("4_serial"))) {
serial = data;
reader_position = pos_fingerprint;
}
else {
@ -303,6 +363,35 @@ loadTestEVInfos()
temp_ev->ev_root_sha1_fingerprint = strdup(fingerprint.get());
temp_ev->oid_name = strdup(readable_oid.get());
temp_ev->dotted_oid = strdup(readable_oid.get());
temp_ev->issuer_base64 = strdup(issuer.get());
temp_ev->serial_base64 = strdup(serial.get());
SECStatus rv;
CERTIssuerAndSN ias;
rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(temp_ev->issuer_base64));
NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");
rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(temp_ev->serial_base64));
NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");
temp_ev->cert = CERT_FindCertByIssuerAndSN(nsnull, &ias);
NS_ASSERTION(temp_ev->cert, "Could not find EV root in NSS storage");
if (!temp_ev->cert)
return;
nsNSSCertificate c(temp_ev->cert);
nsAutoString fingerprint;
c.GetSha1Fingerprint(fingerprint);
NS_ConvertASCIItoUTF16 sha1(temp_ev->ev_root_sha1_fingerprint);
if (sha1 != fingerprint) {
NS_ASSERTION(sha1 == fingerprint, "found EV root with unexpected SHA1 mismatch");
CERT_DestroyCertificate(temp_ev->cert);
temp_ev->cert = nsnull;
return;
}
SECItem ev_oid_item;
ev_oid_item.data = nsnull;
@ -351,6 +440,32 @@ isEVPolicyInExternalDebugRootsFile(SECOidTag policyOIDTag)
return PR_FALSE;
}
static PRBool
getRootsForOidFromExternalRootsFile(CERTCertList* certList,
SECOidTag policyOIDTag)
{
if (!testEVInfos)
return PR_FALSE;
char *env_val = getenv("ENABLE_TEST_EV_ROOTS_FILE");
if (!env_val)
return PR_FALSE;
int enabled_val = atoi(env_val);
if (!enabled_val)
return PR_FALSE;
for (size_t i=0; i<testEVInfos->Length(); ++i) {
nsMyTrustedEVInfoClass *ev = testEVInfos->ElementAt(i);
if (!ev)
continue;
if (policyOIDTag == ev->oid_tag)
CERT_AddCertToListTail(certList, ev->cert);
}
return PR_FALSE;
}
static PRBool
isEVMatchInExternalDebugRootsFile(SECOidTag policyOIDTag,
CERTCertificate *rootCert)
@ -402,6 +517,27 @@ isEVPolicy(SECOidTag policyOIDTag)
return PR_FALSE;
}
static CERTCertList*
getRootsForOid(SECOidTag oid_tag)
{
CERTCertList *certList = CERT_NewCertList();
if (!certList)
return nsnull;
for (size_t iEV=0; iEV < (sizeof(myTrustedEVInfos)/sizeof(nsMyTrustedEVInfo)); ++iEV) {
nsMyTrustedEVInfo &entry = myTrustedEVInfos[iEV];
if (!entry.oid_name) // invalid or placeholder list entry
continue;
if (entry.oid_tag == oid_tag)
CERT_AddCertToListTail(certList, entry.cert);
}
#ifdef PSM_ENABLE_TEST_EV_ROOTS
getRootsForOidFromExternalRootsFile(certList, oid_tag);
#endif
return certList;
}
static PRBool
isApprovedForEV(SECOidTag policyOIDTag, CERTCertificate *rootCert)
{
@ -434,6 +570,33 @@ nsNSSComponent::IdentityInfoInit()
if (!entry.oid_name) // invalid or placeholder list entry
continue;
SECStatus rv;
CERTIssuerAndSN ias;
rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(entry.issuer_base64));
NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");
rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(entry.serial_base64));
NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");
entry.cert = CERT_FindCertByIssuerAndSN(nsnull, &ias);
NS_ASSERTION(entry.cert, "Could not find EV root in NSS storage");
if (!entry.cert)
continue;
nsNSSCertificate c(entry.cert);
nsAutoString fingerprint;
c.GetSha1Fingerprint(fingerprint);
NS_ConvertASCIItoUTF16 sha1(entry.ev_root_sha1_fingerprint);
if (sha1 != fingerprint) {
NS_ASSERTION(sha1 == fingerprint, "found EV root with unexpected SHA1 mismatch");
CERT_DestroyCertificate(entry.cert);
entry.cert = nsnull;
continue;
}
SECItem ev_oid_item;
ev_oid_item.data = nsnull;
ev_oid_item.len = 0;
@ -587,17 +750,57 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag &resultOidTag, PRBool &validEV)
if (oid_tag == SEC_OID_UNKNOWN) // not in our list of OIDs accepted for EV
return NS_OK;
CERTCertList *rootList = getRootsForOid(oid_tag);
CERTCertListCleaner rootListCleaner();
CERTRevocationMethodIndex preferedRevMethods[1] = {
cert_revocation_method_ocsp
};
PRUint64 revMethodFlags =
CERT_REV_M_TEST_USING_THIS_METHOD
| CERT_REV_M_ALLOW_NETWORK_FETCHING
| CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE
| CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE
| CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
| CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
PRUint64 revMethodIndependentFlags =
CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
| CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
PRUint64 methodFlags[2];
methodFlags[cert_revocation_method_crl] = revMethodFlags;
methodFlags[cert_revocation_method_ocsp] = revMethodFlags;
CERTRevocationFlags rev;
rev.leafTests.number_of_defined_methods = cert_revocation_method_ocsp +1;
rev.leafTests.cert_rev_flags_per_method = methodFlags;
rev.leafTests.number_of_preferred_methods = 1;
rev.leafTests.preferred_methods = preferedRevMethods;
rev.leafTests.cert_rev_method_independent_flags =
revMethodIndependentFlags;
rev.chainTests.number_of_defined_methods = cert_revocation_method_ocsp +1;
rev.leafTests.cert_rev_flags_per_method = methodFlags;
rev.chainTests.number_of_preferred_methods = 1;
rev.chainTests.preferred_methods = preferedRevMethods;
rev.chainTests.cert_rev_method_independent_flags =
revMethodIndependentFlags;
CERTValInParam cvin[3];
cvin[0].type = cert_pi_policyOID;
cvin[0].value.arraySize = 1;
cvin[0].value.array.oids = &oid_tag;
cvin[1].type = cert_pi_revocationFlags;
cvin[1].value.scalar.ul = CERT_REV_FAIL_SOFT_CRL
| CERT_REV_FLAG_CRL
| CERT_REV_FLAG_OCSP
;
cvin[2].type = cert_pi_end;
cvin[1].value.pointer.revocation = &rev;
cvin[2].type = cert_pi_trustAnchors;
cvin[2].value.pointer.chain = rootList;
cvin[3].type = cert_pi_end;
CERTValOutParam cvout[2];
cvout[0].type = cert_po_trustAnchor;
@ -612,8 +815,16 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag &resultOidTag, PRBool &validEV)
CERTCertificate *issuerCert = cvout[0].value.pointer.cert;
CERTCertificateCleaner issuerCleaner(issuerCert);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CERT_PKIXVerifyCert returned success, issuer: %s\n",
issuerCert->subjectName));
#ifdef PR_LOGGING
if (PR_LOG_TEST(gPIPNSSLog, PR_LOG_DEBUG)) {
nsNSSCertificate ic(issuerCert);
nsAutoString fingerprint;
ic.GetSha1Fingerprint(fingerprint);
NS_LossyConvertUTF16toASCII fpa(fingerprint);
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CERT_PKIXVerifyCert returned success, issuer: %s, SHA1: %s\n",
issuerCert->subjectName, fpa.get()));
}
#endif
validEV = isApprovedForEV(oid_tag, issuerCert);
if (validEV)
@ -700,6 +911,15 @@ nsNSSComponent::EnsureIdentityInfoLoaded()
void
nsNSSComponent::CleanupIdentityInfo()
{
nsNSSShutDownPreventionLock locker;
for (size_t iEV=0; iEV < (sizeof(myTrustedEVInfos)/sizeof(nsMyTrustedEVInfo)); ++iEV) {
nsMyTrustedEVInfo &entry = myTrustedEVInfos[iEV];
if (entry.cert) {
CERT_DestroyCertificate(entry.cert);
entry.cert = nsnull;
}
}
#ifdef PSM_ENABLE_TEST_EV_ROOTS
if (testEVInfosLoaded) {
testEVInfosLoaded = PR_FALSE;

Просмотреть файл

@ -1684,6 +1684,7 @@ nsNSSComponent::ShutdownNSS()
ShutdownSmartCardThreads();
SSL_ClearSessionCache();
UnloadLoadableRoots();
CleanupIdentityInfo();
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("evaporating psm resources\n"));
mShutdownObjectList->evaporateAllNSSResources();
if (SECSuccess != ::NSS_Shutdown()) {
@ -1693,8 +1694,6 @@ nsNSSComponent::ShutdownNSS()
else {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS shutdown =====>> OK <<=====\n"));
}
CleanupIdentityInfo();
}
return rv;