зеркало из https://github.com/mozilla/gecko-dev.git
Bug 406755, EV certs not recognized as EV with some cross-certification scenarios r=rrelyea, blocking1.9=dsicore
This commit is contained in:
Родитель
8386d5d715
Коммит
4d099dd482
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче