michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // XXX: This must be done prior to including cert.h (directly or indirectly). michael@0: // CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm, but it is michael@0: // only exported so PSM can use it for this specific purpose. michael@0: #define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm michael@0: michael@0: #include "nsNSSComponent.h" michael@0: #include "nsNSSCertificateDB.h" michael@0: michael@0: #include "CertVerifier.h" michael@0: #include "ExtendedValidation.h" michael@0: #include "NSSCertDBTrustDomain.h" michael@0: #include "pkix/pkixtypes.h" michael@0: #include "nsNSSComponent.h" michael@0: #include "mozilla/Base64.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsNSSCertificate.h" michael@0: #include "nsNSSHelper.h" michael@0: #include "nsNSSCertHelper.h" michael@0: #include "nsNSSCertCache.h" michael@0: #include "nsCRT.h" michael@0: #include "nsICertificateDialogs.h" michael@0: #include "nsNSSCertTrust.h" michael@0: #include "nsIFile.h" michael@0: #include "nsPKCS12Blob.h" michael@0: #include "nsPK11TokenDB.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsArrayUtils.h" michael@0: #include "nsNSSShutDown.h" michael@0: #include "nsIPrefService.h" michael@0: #include "nsIPrefBranch.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsIPrompt.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsRecentBadCerts.h" michael@0: #include "SharedSSLState.h" michael@0: michael@0: #include "nspr.h" michael@0: #include "certdb.h" michael@0: #include "secerr.h" michael@0: #include "nssb64.h" michael@0: #include "secasn1.h" michael@0: #include "secder.h" michael@0: #include "ssl.h" michael@0: #include "ocsp.h" michael@0: #include "plbase64.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::psm; michael@0: using mozilla::psm::SharedSSLState; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gPIPNSSLog; michael@0: #endif michael@0: michael@0: static nsresult michael@0: attemptToLogInWithDefaultPassword() michael@0: { michael@0: #ifdef NSS_DISABLE_DBM michael@0: // The SQL NSS DB requires the user to be authenticated to set certificate michael@0: // trust settings, even if the user's password is empty. To maintain michael@0: // compatibility with the DBM-based database, try to log in with the michael@0: // default empty password. This will allow, at least, tests that need to michael@0: // change certificate trust to pass on all platforms. TODO(bug 978120): Do michael@0: // proper testing and/or implement a better solution so that we are confident michael@0: // that this does the correct thing outside of xpcshell tests too. michael@0: ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); michael@0: if (!slot) { michael@0: return MapSECStatus(SECFailure); michael@0: } michael@0: if (PK11_NeedUserInit(slot)) { michael@0: // Ignore the return value. Presumably PK11_InitPin will fail if the user michael@0: // has a non-default password. michael@0: (void) PK11_InitPin(slot, nullptr, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2) michael@0: michael@0: nsNSSCertificateDB::nsNSSCertificateDB() michael@0: : mBadCertsLock("nsNSSCertificateDB::mBadCertsLock") michael@0: { michael@0: SharedSSLState::NoteCertDBServiceInstantiated(); michael@0: } michael@0: michael@0: nsNSSCertificateDB::~nsNSSCertificateDB() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken, michael@0: const nsAString &nickname, michael@0: nsIX509Cert **_rvCert) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_rvCert); michael@0: *_rvCert = nullptr; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: char *asciiname = nullptr; michael@0: NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname); michael@0: asciiname = const_cast(aUtf8Nickname.get()); michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname)); michael@0: cert = PK11_FindCertFromNickname(asciiname, nullptr); michael@0: if (!cert) { michael@0: cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname); michael@0: } michael@0: if (cert) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n")); michael@0: nsCOMPtr pCert = nsNSSCertificate::Create(cert.get()); michael@0: if (pCert) { michael@0: pCert.forget(_rvCert); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken, michael@0: nsIX509Cert **_cert) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDBkey); michael@0: NS_ENSURE_ARG(aDBkey[0]); michael@0: NS_ENSURE_ARG_POINTER(_cert); michael@0: *_cert = nullptr; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: SECItem keyItem = {siBuffer, nullptr, 0}; michael@0: SECItem *dummy; michael@0: CERTIssuerAndSN issuerSN; michael@0: //unsigned long moduleID,slotID; michael@0: michael@0: dummy = NSSBase64_DecodeBuffer(nullptr, &keyItem, aDBkey, michael@0: (uint32_t)strlen(aDBkey)); michael@0: if (!dummy || keyItem.len < NS_NSS_LONG*4) { michael@0: PR_FREEIF(keyItem.data); michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: // someday maybe we can speed up the search using the moduleID and slotID michael@0: // moduleID = NS_NSS_GET_LONG(keyItem.data); michael@0: // slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]); michael@0: michael@0: // build the issuer/SN structure michael@0: issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]); michael@0: issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]); michael@0: if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0 michael@0: || issuerSN.serialNumber.len + issuerSN.derIssuer.len michael@0: != keyItem.len - NS_NSS_LONG*4) { michael@0: PR_FREEIF(keyItem.data); michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4]; michael@0: issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+ michael@0: issuerSN.serialNumber.len]; michael@0: michael@0: cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN); michael@0: PR_FREEIF(keyItem.data); michael@0: if (cert) { michael@0: nsCOMPtr nssCert = nsNSSCertificate::Create(cert.get()); michael@0: if (!nssCert) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: nssCert.forget(_cert); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::FindCertNicknames(nsISupports *aToken, michael@0: uint32_t aType, michael@0: uint32_t *_count, michael@0: char16_t ***_certNames) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: /* michael@0: * obtain the cert list from NSS michael@0: */ michael@0: mozilla::pkix::ScopedCERTCertList certList; michael@0: certList = PK11_ListCerts(PK11CertListUnique, nullptr); michael@0: if (!certList) michael@0: goto cleanup; michael@0: /* michael@0: * get list of cert names from list of certs michael@0: * XXX also cull the list (NSS only distinguishes based on user/non-user michael@0: */ michael@0: getCertNames(certList.get(), aType, _count, _certNames, locker); michael@0: rv = NS_OK; michael@0: /* michael@0: * finish up michael@0: */ michael@0: cleanup: michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: collect_certs(void *arg, SECItem **certs, int numcerts) michael@0: { michael@0: CERTDERCerts *collectArgs; michael@0: SECItem *cert; michael@0: SECStatus rv; michael@0: michael@0: collectArgs = (CERTDERCerts *)arg; michael@0: michael@0: collectArgs->numcerts = numcerts; michael@0: collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena, michael@0: sizeof(SECItem) * numcerts); michael@0: if (!collectArgs->rawCerts) michael@0: return(SECFailure); michael@0: michael@0: cert = collectArgs->rawCerts; michael@0: michael@0: while ( numcerts-- ) { michael@0: rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs); michael@0: if ( rv == SECFailure ) michael@0: return(SECFailure); michael@0: cert++; michael@0: certs++; michael@0: } michael@0: michael@0: return (SECSuccess); michael@0: } michael@0: michael@0: CERTDERCerts* michael@0: nsNSSCertificateDB::getCertsFromPackage(PLArenaPool *arena, uint8_t *data, michael@0: uint32_t length, michael@0: const nsNSSShutDownPreventionLock &/*proofOfLock*/) michael@0: { michael@0: CERTDERCerts *collectArgs = michael@0: (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts)); michael@0: if (!collectArgs) michael@0: return nullptr; michael@0: michael@0: collectArgs->arena = arena; michael@0: SECStatus sec_rv = CERT_DecodeCertPackage(reinterpret_cast(data), michael@0: length, collect_certs, michael@0: (void *)collectArgs); michael@0: if (sec_rv != SECSuccess) michael@0: return nullptr; michael@0: michael@0: return collectArgs; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs, michael@0: nsIInterfaceRequestor *ctx, michael@0: const nsNSSShutDownPreventionLock &proofOfLock) michael@0: { michael@0: // First thing we have to do is figure out which certificate we're michael@0: // gonna present to the user. The CA may have sent down a list of michael@0: // certs which may or may not be a chained list of certs. Until michael@0: // the day we can design some solid UI for the general case, we'll michael@0: // code to the > 90% case. That case is where a CA sends down a michael@0: // list that is a hierarchy whose root is either the first or michael@0: // the last cert. What we're gonna do is compare the first michael@0: // 2 entries, if the second was signed by the first, we assume michael@0: // the root cert is the first cert and display it. Otherwise, michael@0: // we compare the last 2 entries, if the second to last cert was michael@0: // signed by the last cert, then we assume the last cert is the michael@0: // root and display it. michael@0: michael@0: uint32_t numCerts; michael@0: michael@0: x509Certs->GetLength(&numCerts); michael@0: NS_ASSERTION(numCerts > 0, "Didn't get any certs to import."); michael@0: if (numCerts == 0) michael@0: return NS_OK; // Nothing to import, so nothing to do. michael@0: michael@0: nsCOMPtr certToShow; michael@0: nsCOMPtr isupports; michael@0: uint32_t selCertIndex; michael@0: if (numCerts == 1) { michael@0: // There's only one cert, so let's show it. michael@0: selCertIndex = 0; michael@0: certToShow = do_QueryElementAt(x509Certs, selCertIndex); michael@0: } else { michael@0: nsCOMPtr cert0; // first cert michael@0: nsCOMPtr cert1; // second cert michael@0: nsCOMPtr certn_2; // second to last cert michael@0: nsCOMPtr certn_1; // last cert michael@0: michael@0: cert0 = do_QueryElementAt(x509Certs, 0); michael@0: cert1 = do_QueryElementAt(x509Certs, 1); michael@0: certn_2 = do_QueryElementAt(x509Certs, numCerts-2); michael@0: certn_1 = do_QueryElementAt(x509Certs, numCerts-1); michael@0: michael@0: nsXPIDLString cert0SubjectName; michael@0: nsXPIDLString cert1IssuerName; michael@0: nsXPIDLString certn_2IssuerName; michael@0: nsXPIDLString certn_1SubjectName; michael@0: michael@0: cert0->GetSubjectName(cert0SubjectName); michael@0: cert1->GetIssuerName(cert1IssuerName); michael@0: certn_2->GetIssuerName(certn_2IssuerName); michael@0: certn_1->GetSubjectName(certn_1SubjectName); michael@0: michael@0: if (cert1IssuerName.Equals(cert0SubjectName)) { michael@0: // In this case, the first cert in the list signed the second, michael@0: // so the first cert is the root. Let's display it. michael@0: selCertIndex = 0; michael@0: certToShow = cert0; michael@0: } else michael@0: if (certn_2IssuerName.Equals(certn_1SubjectName)) { michael@0: // In this case the last cert has signed the second to last cert. michael@0: // The last cert is the root, so let's display it. michael@0: selCertIndex = numCerts-1; michael@0: certToShow = certn_1; michael@0: } else { michael@0: // It's not a chain, so let's just show the first one in the michael@0: // downloaded list. michael@0: selCertIndex = 0; michael@0: certToShow = cert0; michael@0: } michael@0: } michael@0: michael@0: if (!certToShow) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr dialogs; michael@0: nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), michael@0: NS_GET_IID(nsICertificateDialogs), michael@0: NS_CERTIFICATEDIALOGS_CONTRACTID); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: SECItem der; michael@0: rv=certToShow->GetRawDER(&der.len, (uint8_t **)&der.data); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); michael@0: mozilla::pkix::ScopedCERTCertificate tmpCert; michael@0: CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); michael@0: tmpCert = CERT_FindCertByDERCert(certdb, &der); michael@0: if (!tmpCert) { michael@0: tmpCert = CERT_NewTempCertificate(certdb, &der, michael@0: nullptr, false, true); michael@0: } michael@0: nsMemory::Free(der.data); michael@0: der.data = nullptr; michael@0: der.len = 0; michael@0: michael@0: if (!tmpCert) { michael@0: NS_ERROR("Couldn't create cert from DER blob"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!CERT_IsCACert(tmpCert.get(), nullptr)) { michael@0: DisplayCertificateAlert(ctx, "NotACACert", certToShow, proofOfLock); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (tmpCert->isperm) { michael@0: DisplayCertificateAlert(ctx, "CaCertExists", certToShow, proofOfLock); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: uint32_t trustBits; michael@0: bool allows; michael@0: rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (!allows) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits)); michael@0: nsXPIDLCString nickname; michael@0: nickname.Adopt(CERT_MakeCANickname(tmpCert.get())); michael@0: michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); michael@0: michael@0: nsNSSCertTrust trust; michael@0: trust.SetValidCA(); michael@0: trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL), michael@0: !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL), michael@0: !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN)); michael@0: michael@0: SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(), michael@0: const_cast(nickname.get()), michael@0: trust.GetTrust()); michael@0: michael@0: if (srv != SECSuccess) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Import additional delivered certificates that can be verified. michael@0: michael@0: // build a CertList for filtering michael@0: mozilla::pkix::ScopedCERTCertList certList(CERT_NewCertList()); michael@0: if (!certList) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // get all remaining certs into temp store michael@0: michael@0: for (uint32_t i=0; iGetRawDER(&der.len, (uint8_t **)&der.data); michael@0: michael@0: CERTCertificate *tmpCert2 = michael@0: CERT_NewTempCertificate(certdb, &der, nullptr, false, true); michael@0: michael@0: nsMemory::Free(der.data); michael@0: der.data = nullptr; michael@0: der.len = 0; michael@0: michael@0: if (!tmpCert2) { michael@0: NS_ERROR("Couldn't create temp cert from DER blob"); michael@0: continue; // Let's try to import the rest of 'em michael@0: } michael@0: michael@0: CERT_AddCertToListTail(certList.get(), tmpCert2); michael@0: } michael@0: michael@0: return ImportValidCACertsInList(certList.get(), ctx, proofOfLock); michael@0: } michael@0: michael@0: /* michael@0: * [noscript] void importCertificates(in charPtr data, in unsigned long length, michael@0: * in unsigned long type, michael@0: * in nsIInterfaceRequestor ctx); michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ImportCertificates(uint8_t * data, uint32_t length, michael@0: uint32_t type, michael@0: nsIInterfaceRequestor *ctx) michael@0: michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsresult nsrv; michael@0: michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker); michael@0: if (!certCollection) { michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: nsCOMPtr array = michael@0: do_CreateInstance(NS_ARRAY_CONTRACTID, &nsrv); michael@0: if (NS_FAILED(nsrv)) { michael@0: PORT_FreeArena(arena, false); michael@0: return nsrv; michael@0: } michael@0: michael@0: // Now let's create some certs to work with michael@0: nsCOMPtr x509Cert; michael@0: nsNSSCertificate *nssCert; michael@0: SECItem *currItem; michael@0: for (int i=0; inumcerts; i++) { michael@0: currItem = &certCollection->rawCerts[i]; michael@0: nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len); michael@0: if (!nssCert) michael@0: return NS_ERROR_FAILURE; michael@0: x509Cert = do_QueryInterface((nsIX509Cert*)nssCert); michael@0: array->AppendElement(x509Cert, false); michael@0: } michael@0: switch (type) { michael@0: case nsIX509Cert::CA_CERT: michael@0: nsrv = handleCACertDownload(array, ctx, locker); michael@0: break; michael@0: default: michael@0: // We only deal with import CA certs in this method currently. michael@0: nsrv = NS_ERROR_FAILURE; michael@0: break; michael@0: } michael@0: PORT_FreeArena(arena, false); michael@0: return nsrv; michael@0: } michael@0: michael@0: static michael@0: SECStatus michael@0: ImportCertsIntoPermanentStorage( michael@0: const mozilla::pkix::ScopedCERTCertList& certChain, michael@0: const SECCertUsage usage, const PRBool caOnly) michael@0: { michael@0: CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); michael@0: michael@0: int chainLen = 0; michael@0: for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain); michael@0: !CERT_LIST_END(chainNode, certChain); michael@0: chainNode = CERT_LIST_NEXT(chainNode)) { michael@0: chainLen++; michael@0: } michael@0: michael@0: SECItem **rawArray; michael@0: rawArray = (SECItem **) PORT_Alloc(chainLen * sizeof(SECItem *)); michael@0: if (!rawArray) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: int i = 0; michael@0: for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain); michael@0: !CERT_LIST_END(chainNode, certChain); michael@0: chainNode = CERT_LIST_NEXT(chainNode), i++) { michael@0: rawArray[i] = &chainNode->cert->derCert; michael@0: } michael@0: SECStatus srv = CERT_ImportCerts(certdb, usage, chainLen, rawArray, michael@0: nullptr, true, caOnly, nullptr); michael@0: michael@0: PORT_Free(rawArray); michael@0: return srv; michael@0: } michael@0: michael@0: michael@0: /* michael@0: * [noscript] void importEmailCertificates(in charPtr data, in unsigned long length, michael@0: * in nsIInterfaceRequestor ctx); michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ImportEmailCertificate(uint8_t * data, uint32_t length, michael@0: nsIInterfaceRequestor *ctx) michael@0: michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: SECStatus srv = SECFailure; michael@0: nsresult nsrv = NS_OK; michael@0: CERTCertDBHandle *certdb; michael@0: CERTCertificate **certArray = nullptr; michael@0: mozilla::pkix::ScopedCERTCertList certList; michael@0: CERTCertListNode *node; michael@0: SECItem **rawArray; michael@0: int numcerts; michael@0: int i; michael@0: michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker); michael@0: if (!certCollection) { michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: RefPtr certVerifier(GetDefaultCertVerifier()); michael@0: NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); michael@0: michael@0: certdb = CERT_GetDefaultCertDB(); michael@0: const PRTime now = PR_Now(); michael@0: michael@0: numcerts = certCollection->numcerts; michael@0: michael@0: rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); michael@0: if ( !rawArray ) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: michael@0: for (i=0; i < numcerts; i++) { michael@0: rawArray[i] = &certCollection->rawCerts[i]; michael@0: } michael@0: michael@0: srv = CERT_ImportCerts(certdb, certUsageEmailRecipient, numcerts, rawArray, michael@0: &certArray, false, false, nullptr); michael@0: michael@0: PORT_Free(rawArray); michael@0: rawArray = nullptr; michael@0: michael@0: if (srv != SECSuccess) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: michael@0: // build a CertList for filtering michael@0: certList = CERT_NewCertList(); michael@0: if (!certList) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: for (i=0; i < numcerts; i++) { michael@0: CERTCertificate *cert = certArray[i]; michael@0: if (cert) michael@0: cert = CERT_DupCertificate(cert); michael@0: if (cert) michael@0: CERT_AddCertToListTail(certList.get(), cert); michael@0: } michael@0: michael@0: /* go down the remaining list of certs and verify that they have michael@0: * valid chains, then import them. michael@0: */ michael@0: michael@0: for (node = CERT_LIST_HEAD(certList); michael@0: !CERT_LIST_END(node,certList); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: michael@0: if (!node->cert) { michael@0: continue; michael@0: } michael@0: michael@0: mozilla::pkix::ScopedCERTCertList certChain; michael@0: michael@0: SECStatus rv = certVerifier->VerifyCert(node->cert, michael@0: certificateUsageEmailRecipient, michael@0: now, ctx, nullptr, 0, michael@0: nullptr, &certChain); michael@0: michael@0: if (rv != SECSuccess) { michael@0: nsCOMPtr certToShow = nsNSSCertificate::Create(node->cert); michael@0: DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker); michael@0: continue; michael@0: } michael@0: rv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient, michael@0: false); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: CERT_SaveSMimeProfile(node->cert, nullptr, nullptr); michael@0: michael@0: } michael@0: michael@0: loser: michael@0: if (certArray) { michael@0: CERT_DestroyCertArray(certArray, numcerts); michael@0: } michael@0: if (arena) michael@0: PORT_FreeArena(arena, true); michael@0: return nsrv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ImportServerCertificate(uint8_t * data, uint32_t length, michael@0: nsIInterfaceRequestor *ctx) michael@0: michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: SECStatus srv = SECFailure; michael@0: nsresult nsrv = NS_OK; michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: SECItem **rawCerts = nullptr; michael@0: int numcerts; michael@0: int i; michael@0: nsNSSCertTrust trust; michael@0: char *serverNickname = nullptr; michael@0: michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker); michael@0: if (!certCollection) { michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts, michael@0: nullptr, false, true); michael@0: if (!cert) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: numcerts = certCollection->numcerts; michael@0: rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts); michael@0: if ( !rawCerts ) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: michael@0: for ( i = 0; i < numcerts; i++ ) { michael@0: rawCerts[i] = &certCollection->rawCerts[i]; michael@0: } michael@0: michael@0: serverNickname = DefaultServerNicknameForCert(cert.get()); michael@0: srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer, michael@0: numcerts, rawCerts, nullptr, true, false, michael@0: serverNickname); michael@0: PR_FREEIF(serverNickname); michael@0: if ( srv != SECSuccess ) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: michael@0: trust.SetValidServerPeer(); michael@0: srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert.get(), michael@0: trust.GetTrust()); michael@0: if ( srv != SECSuccess ) { michael@0: nsrv = NS_ERROR_FAILURE; michael@0: goto loser; michael@0: } michael@0: loser: michael@0: PORT_Free(rawCerts); michael@0: if (arena) michael@0: PORT_FreeArena(arena, true); michael@0: return nsrv; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx, const nsNSSShutDownPreventionLock &proofOfLock) michael@0: { michael@0: ScopedCERTCertList certList; michael@0: SECItem **rawArray; michael@0: michael@0: // build a CertList for filtering michael@0: certList = CERT_NewCertList(); michael@0: if (!certList) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // get all certs into temp store michael@0: SECStatus srv = SECFailure; michael@0: CERTCertificate **certArray = nullptr; michael@0: michael@0: rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts); michael@0: if ( !rawArray ) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: for (int i=0; i < numCACerts; i++) { michael@0: rawArray[i] = &CACerts[i]; michael@0: } michael@0: michael@0: srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray, michael@0: &certArray, false, true, nullptr); michael@0: michael@0: PORT_Free(rawArray); michael@0: rawArray = nullptr; michael@0: michael@0: if (srv != SECSuccess) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: for (int i2=0; i2 < numCACerts; i2++) { michael@0: CERTCertificate *cacert = certArray[i2]; michael@0: if (cacert) michael@0: cacert = CERT_DupCertificate(cacert); michael@0: if (cacert) michael@0: CERT_AddCertToListTail(certList, cacert); michael@0: } michael@0: michael@0: CERT_DestroyCertArray(certArray, numCACerts); michael@0: michael@0: return ImportValidCACertsInList(certList, ctx, proofOfLock); michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx, michael@0: const nsNSSShutDownPreventionLock &proofOfLock) michael@0: { michael@0: RefPtr certVerifier(GetDefaultCertVerifier()); michael@0: if (!certVerifier) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: /* filter out the certs we don't want */ michael@0: SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, true); michael@0: if (srv != SECSuccess) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* go down the remaining list of certs and verify that they have michael@0: * valid chains, if yes, then import. michael@0: */ michael@0: CERTCertListNode *node; michael@0: michael@0: for (node = CERT_LIST_HEAD(certList); michael@0: !CERT_LIST_END(node,certList); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: mozilla::pkix::ScopedCERTCertList certChain; michael@0: SECStatus rv = certVerifier->VerifyCert(node->cert, michael@0: certificateUsageVerifyCA, michael@0: PR_Now(), ctx, nullptr, 0, nullptr, michael@0: &certChain); michael@0: if (rv != SECSuccess) { michael@0: nsCOMPtr certToShow = nsNSSCertificate::Create(node->cert); michael@0: DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock); michael@0: continue; michael@0: } michael@0: michael@0: rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true); michael@0: if (rv != SECSuccess) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx, michael@0: const char *stringID, michael@0: nsIX509Cert *certToShow, michael@0: const nsNSSShutDownPreventionLock &/*proofOfLock*/) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: if (!NS_IsMainThread()) { michael@0: NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread"); michael@0: return; michael@0: } michael@0: michael@0: nsPSMUITracker tracker; michael@0: if (!tracker.isUIForbidden()) { michael@0: michael@0: nsCOMPtr my_ctx = ctx; michael@0: if (!my_ctx) michael@0: my_ctx = new PipUIContext(); michael@0: michael@0: // This shall be replaced by embedding ovverridable prompts michael@0: // as discussed in bug 310446, and should make use of certToShow. michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsAutoString tmpMessage; michael@0: nssComponent->GetPIPNSSBundleString(stringID, tmpMessage); michael@0: michael@0: nsCOMPtr prompt (do_GetInterface(my_ctx)); michael@0: if (!prompt) michael@0: return; michael@0: michael@0: prompt->Alert(nullptr, tmpMessage.get()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx) michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread"); michael@0: return NS_ERROR_NOT_SAME_THREAD; michael@0: } michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: ScopedPK11SlotInfo slot; michael@0: nsAutoCString nickname; michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: int numCACerts; michael@0: SECItem *CACerts; michael@0: CERTDERCerts * collectArgs; michael@0: PLArenaPool *arena; michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) { michael@0: goto loser; michael@0: } michael@0: michael@0: collectArgs = getCertsFromPackage(arena, data, length, locker); michael@0: if (!collectArgs) { michael@0: goto loser; michael@0: } michael@0: michael@0: cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts, michael@0: nullptr, false, true); michael@0: if (!cert) { michael@0: goto loser; michael@0: } michael@0: michael@0: slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx); michael@0: if (!slot) { michael@0: nsCOMPtr certToShow = nsNSSCertificate::Create(cert.get()); michael@0: DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker); michael@0: goto loser; michael@0: } michael@0: slot = nullptr; michael@0: michael@0: /* pick a nickname for the cert */ michael@0: if (cert->nickname) { michael@0: /* sigh, we need a call to look up other certs with this subject and michael@0: * identify nicknames from them. We can no longer walk down internal michael@0: * database structures rjr */ michael@0: nickname = cert->nickname; michael@0: } michael@0: else { michael@0: get_default_nickname(cert.get(), ctx, nickname, locker); michael@0: } michael@0: michael@0: /* user wants to import the cert */ michael@0: { michael@0: char *cast_const_away = const_cast(nickname.get()); michael@0: slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx); michael@0: } michael@0: if (!slot) { michael@0: goto loser; michael@0: } michael@0: slot = nullptr; michael@0: michael@0: { michael@0: nsCOMPtr certToShow = nsNSSCertificate::Create(cert.get()); michael@0: DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker); michael@0: } michael@0: rv = NS_OK; michael@0: michael@0: numCACerts = collectArgs->numcerts - 1; michael@0: if (numCACerts) { michael@0: CACerts = collectArgs->rawCerts+1; michael@0: rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker); michael@0: } michael@0: michael@0: loser: michael@0: if (arena) { michael@0: PORT_FreeArena(arena, false); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: * void deleteCertificate(in nsIX509Cert aCert); michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: nsCOMPtr nssCert = do_QueryInterface(aCert); michael@0: mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert()); michael@0: if (!cert) return NS_ERROR_FAILURE; michael@0: SECStatus srv = SECSuccess; michael@0: michael@0: uint32_t certType; michael@0: nssCert->GetCertType(&certType); michael@0: if (NS_FAILED(nssCert->MarkForPermDeletion())) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (cert->slot && certType != nsIX509Cert::USER_CERT) { michael@0: // To delete a cert of a slot (builtin, most likely), mark it as michael@0: // completely untrusted. This way we keep a copy cached in the michael@0: // local database, and next time we try to load it off of the michael@0: // external token/slot, we'll know not to trust it. We don't michael@0: // want to do that with user certs, because a user may re-store michael@0: // the cert onto the card again at which point we *will* want to michael@0: // trust that cert if it chains up properly. michael@0: nsNSSCertTrust trust(0, 0, 0); michael@0: srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), michael@0: cert.get(), trust.GetTrust()); michael@0: } michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv)); michael@0: return (srv) ? NS_ERROR_FAILURE : NS_OK; michael@0: } michael@0: michael@0: /* michael@0: * void setCertTrust(in nsIX509Cert cert, michael@0: * in unsigned long type, michael@0: * in unsigned long trust); michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert, michael@0: uint32_t type, michael@0: uint32_t trusted) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: nsNSSCertTrust trust; michael@0: nsresult rv; michael@0: nsCOMPtr pipCert = do_QueryInterface(cert, &rv); michael@0: if (!pipCert) { michael@0: return rv; michael@0: } michael@0: mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert()); michael@0: michael@0: rv = attemptToLogInWithDefaultPassword(); michael@0: if (NS_WARN_IF(rv != NS_OK)) { michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus srv; michael@0: if (type == nsIX509Cert::CA_CERT) { michael@0: // always start with untrusted and move up michael@0: trust.SetValidCA(); michael@0: trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL), michael@0: !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), michael@0: !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN)); michael@0: srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), michael@0: nsscert.get(), michael@0: trust.GetTrust()); michael@0: } else if (type == nsIX509Cert::SERVER_CERT) { michael@0: // always start with untrusted and move up michael@0: trust.SetValidPeer(); michael@0: trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0); michael@0: srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), michael@0: nsscert.get(), michael@0: trust.GetTrust()); michael@0: } else if (type == nsIX509Cert::EMAIL_CERT) { michael@0: // always start with untrusted and move up michael@0: trust.SetValidPeer(); michael@0: trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0); michael@0: srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), michael@0: nsscert.get(), michael@0: trust.GetTrust()); michael@0: } else { michael@0: // ignore user certs michael@0: return NS_OK; michael@0: } michael@0: return MapSECStatus(srv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert, michael@0: uint32_t certType, michael@0: uint32_t trustType, michael@0: bool *_isTrusted) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_isTrusted); michael@0: *_isTrusted = false; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: SECStatus srv; michael@0: nsCOMPtr pipCert = do_QueryInterface(cert); michael@0: mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert()); michael@0: CERTCertTrust nsstrust; michael@0: srv = CERT_GetCertTrust(nsscert.get(), &nsstrust); michael@0: if (srv != SECSuccess) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsNSSCertTrust trust(&nsstrust); michael@0: if (certType == nsIX509Cert::CA_CERT) { michael@0: if (trustType & nsIX509CertDB::TRUSTED_SSL) { michael@0: *_isTrusted = trust.HasTrustedCA(true, false, false); michael@0: } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { michael@0: *_isTrusted = trust.HasTrustedCA(false, true, false); michael@0: } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { michael@0: *_isTrusted = trust.HasTrustedCA(false, false, true); michael@0: } else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } else if (certType == nsIX509Cert::SERVER_CERT) { michael@0: if (trustType & nsIX509CertDB::TRUSTED_SSL) { michael@0: *_isTrusted = trust.HasTrustedPeer(true, false, false); michael@0: } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { michael@0: *_isTrusted = trust.HasTrustedPeer(false, true, false); michael@0: } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { michael@0: *_isTrusted = trust.HasTrustedPeer(false, false, true); michael@0: } else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } else if (certType == nsIX509Cert::EMAIL_CERT) { michael@0: if (trustType & nsIX509CertDB::TRUSTED_SSL) { michael@0: *_isTrusted = trust.HasTrustedPeer(true, false, false); michael@0: } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) { michael@0: *_isTrusted = trust.HasTrustedPeer(false, true, false); michael@0: } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) { michael@0: *_isTrusted = trust.HasTrustedPeer(false, false, true); michael@0: } else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } /* user: ignore */ michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ImportCertsFromFile(nsISupports *aToken, michael@0: nsIFile *aFile, michael@0: uint32_t aType) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_ENSURE_ARG(aFile); michael@0: switch (aType) { michael@0: case nsIX509Cert::CA_CERT: michael@0: case nsIX509Cert::EMAIL_CERT: michael@0: case nsIX509Cert::SERVER_CERT: michael@0: // good michael@0: break; michael@0: michael@0: default: michael@0: // not supported (yet) michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult rv; michael@0: PRFileDesc *fd = nullptr; michael@0: michael@0: rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (!fd) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: PRFileInfo file_info; michael@0: if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &file_info)) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: unsigned char *buf = new unsigned char[file_info.size]; michael@0: michael@0: int32_t bytes_obtained = PR_Read(fd, buf, file_info.size); michael@0: PR_Close(fd); michael@0: michael@0: if (bytes_obtained != file_info.size) michael@0: rv = NS_ERROR_FAILURE; michael@0: else { michael@0: nsCOMPtr cxt = new PipUIContext(); michael@0: michael@0: switch (aType) { michael@0: case nsIX509Cert::CA_CERT: michael@0: rv = ImportCertificates(buf, bytes_obtained, aType, cxt); michael@0: break; michael@0: michael@0: case nsIX509Cert::SERVER_CERT: michael@0: rv = ImportServerCertificate(buf, bytes_obtained, cxt); michael@0: break; michael@0: michael@0: case nsIX509Cert::EMAIL_CERT: michael@0: rv = ImportEmailCertificate(buf, bytes_obtained, cxt); michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: delete [] buf; michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ImportPKCS12File(nsISupports *aToken, michael@0: nsIFile *aFile) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_ENSURE_ARG(aFile); michael@0: nsPKCS12Blob blob; michael@0: nsCOMPtr token = do_QueryInterface(aToken); michael@0: if (token) { michael@0: blob.SetToken(token); michael@0: } michael@0: return blob.ImportFromFile(aFile); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ExportPKCS12File(nsISupports *aToken, michael@0: nsIFile *aFile, michael@0: uint32_t count, michael@0: nsIX509Cert **certs) michael@0: //const char16_t **aCertNames) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_ENSURE_ARG(aFile); michael@0: nsPKCS12Blob blob; michael@0: if (count == 0) return NS_OK; michael@0: nsCOMPtr localRef; michael@0: if (!aToken) { michael@0: ScopedPK11SlotInfo keySlot(PK11_GetInternalKeySlot()); michael@0: NS_ASSERTION(keySlot,"Failed to get the internal key slot"); michael@0: localRef = new nsPK11Token(keySlot); michael@0: } michael@0: else { michael@0: localRef = do_QueryInterface(aToken); michael@0: } michael@0: blob.SetToken(localRef); michael@0: //blob.LoadCerts(aCertNames, count); michael@0: //return blob.ExportToFile(aFile); michael@0: return blob.ExportToFile(aFile, certs, count); michael@0: } michael@0: michael@0: /* michael@0: * NSS Helper Routines (private to nsNSSCertificateDB) michael@0: */ michael@0: michael@0: #define DELIM '\001' michael@0: michael@0: /* michael@0: * GetSortedNameList michael@0: * michael@0: * Converts a CERTCertList to a list of certificate names michael@0: */ michael@0: void michael@0: nsNSSCertificateDB::getCertNames(CERTCertList *certList, michael@0: uint32_t type, michael@0: uint32_t *_count, michael@0: char16_t ***_certNames, michael@0: const nsNSSShutDownPreventionLock &/*proofOfLock*/) michael@0: { michael@0: CERTCertListNode *node; michael@0: uint32_t numcerts = 0, i=0; michael@0: char16_t **tmpArray = nullptr; michael@0: michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type)); michael@0: for (node = CERT_LIST_HEAD(certList); michael@0: !CERT_LIST_END(node, certList); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: if (getCertType(node->cert) == type) { michael@0: numcerts++; michael@0: } michael@0: } michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts)); michael@0: int nc = (numcerts == 0) ? 1 : numcerts; michael@0: tmpArray = (char16_t **)nsMemory::Alloc(sizeof(char16_t *) * nc); michael@0: if (numcerts == 0) goto finish; michael@0: for (node = CERT_LIST_HEAD(certList); michael@0: !CERT_LIST_END(node, certList); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: if (getCertType(node->cert) == type) { michael@0: nsNSSCertificate pipCert(node->cert); michael@0: char *dbkey = nullptr; michael@0: char *namestr = nullptr; michael@0: nsAutoString certstr; michael@0: pipCert.GetDbKey(&dbkey); michael@0: nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey); michael@0: PR_FREEIF(dbkey); michael@0: if (type == nsIX509Cert::EMAIL_CERT) { michael@0: namestr = node->cert->emailAddr; michael@0: } else { michael@0: namestr = node->cert->nickname; michael@0: if (namestr) { michael@0: char *sc = strchr(namestr, ':'); michael@0: if (sc) *sc = DELIM; michael@0: } michael@0: } michael@0: nsAutoString certname = NS_ConvertASCIItoUTF16(namestr ? namestr : ""); michael@0: certstr.Append(char16_t(DELIM)); michael@0: certstr += certname; michael@0: certstr.Append(char16_t(DELIM)); michael@0: certstr += keystr; michael@0: tmpArray[i++] = ToNewUnicode(certstr); michael@0: } michael@0: } michael@0: finish: michael@0: *_count = numcerts; michael@0: *_certNames = tmpArray; michael@0: } michael@0: michael@0: /* nsIX509Cert getDefaultEmailEncryptionCert (); */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = nullptr; michael@0: michael@0: if (aNickname.IsEmpty()) michael@0: return NS_OK; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsCOMPtr ctx = new PipUIContext(); michael@0: char *asciiname = nullptr; michael@0: NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname); michael@0: asciiname = const_cast(aUtf8Nickname.get()); michael@0: michael@0: /* Find a good cert in the user's database */ michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, michael@0: certUsageEmailRecipient, true, ctx); michael@0: if (!cert) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr nssCert = nsNSSCertificate::Create(cert.get()); michael@0: if (!nssCert) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: nssCert.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIX509Cert getDefaultEmailSigningCert (); */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = nullptr; michael@0: michael@0: if (aNickname.IsEmpty()) michael@0: return NS_OK; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: nsCOMPtr ctx = new PipUIContext(); michael@0: char *asciiname = nullptr; michael@0: NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname); michael@0: asciiname = const_cast(aUtf8Nickname.get()); michael@0: michael@0: /* Find a good cert in the user's database */ michael@0: cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, michael@0: certUsageEmailSigner, true, ctx); michael@0: if (!cert) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr nssCert = nsNSSCertificate::Create(cert.get()); michael@0: if (!nssCert) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: nssCert.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: RefPtr certVerifier(GetDefaultCertVerifier()); michael@0: NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); michael@0: michael@0: ScopedCERTCertList certlist( michael@0: PK11_FindCertsFromEmailAddress(aEmailAddress, nullptr)); michael@0: if (!certlist) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // certlist now contains certificates with the right email address, michael@0: // but they might not have the correct usage or might even be invalid michael@0: michael@0: if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) michael@0: return NS_ERROR_FAILURE; // no certs found michael@0: michael@0: CERTCertListNode *node; michael@0: // search for a valid certificate michael@0: for (node = CERT_LIST_HEAD(certlist); michael@0: !CERT_LIST_END(node, certlist); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: michael@0: SECStatus srv = certVerifier->VerifyCert(node->cert, michael@0: certificateUsageEmailRecipient, michael@0: PR_Now(), nullptr /*XXX pinarg*/, michael@0: nullptr /*hostname*/); michael@0: if (srv == SECSuccess) { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (CERT_LIST_END(node, certlist)) { michael@0: // no valid cert found michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // node now contains the first valid certificate with correct usage michael@0: nsNSSCertificate *nssCert = nsNSSCertificate::Create(node->cert); michael@0: if (!nssCert) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(nssCert); michael@0: *_retval = static_cast(nssCert); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIX509Cert constructX509FromBase64 (in string base64); */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ConstructX509FromBase64(const char *base64, michael@0: nsIX509Cert **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: if (NS_WARN_IF(!_retval)) { michael@0: return NS_ERROR_INVALID_POINTER; michael@0: } michael@0: michael@0: // sure would be nice to have a smart pointer class for PL_ allocations michael@0: // unfortunately, we cannot distinguish out-of-memory from bad-input here michael@0: uint32_t len = base64 ? strlen(base64) : 0; michael@0: char *certDER = PL_Base64Decode(base64, len, nullptr); michael@0: if (!certDER) michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: if (!*certDER) { michael@0: PL_strfree(certDER); michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: michael@0: // If we get to this point, we know we had well-formed base64 input; michael@0: // therefore the input string cannot have been less than two michael@0: // characters long. Compute the unpadded length of the decoded data. michael@0: uint32_t lengthDER = (len * 3) / 4; michael@0: if (base64[len-1] == '=') { michael@0: lengthDER--; michael@0: if (base64[len-2] == '=') michael@0: lengthDER--; michael@0: } michael@0: michael@0: nsresult rv = ConstructX509(certDER, lengthDER, _retval); michael@0: PL_strfree(certDER); michael@0: return rv; michael@0: } michael@0: michael@0: /* nsIX509Cert constructX509 (in string certDER, unsigned long len); */ michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ConstructX509(const char* certDER, michael@0: uint32_t lengthDER, michael@0: nsIX509Cert** _retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: if (NS_WARN_IF(!_retval)) { michael@0: return NS_ERROR_INVALID_POINTER; michael@0: } michael@0: michael@0: SECItem secitem_cert; michael@0: secitem_cert.type = siDERCertBuffer; michael@0: secitem_cert.data = (unsigned char*)certDER; michael@0: secitem_cert.len = lengthDER; michael@0: michael@0: mozilla::pkix::ScopedCERTCertificate cert; michael@0: cert = michael@0: CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, michael@0: nullptr, false, true); michael@0: if (!cert) michael@0: return (PORT_GetError() == SEC_ERROR_NO_MEMORY) michael@0: ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr nssCert = nsNSSCertificate::Create(cert.get()); michael@0: if (!nssCert) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: nssCert.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, michael@0: nsIInterfaceRequestor* ctx, michael@0: nsCString &nickname, michael@0: const nsNSSShutDownPreventionLock &/*proofOfLock*/) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nickname.Truncate(); michael@0: michael@0: nsresult rv; michael@0: CK_OBJECT_HANDLE keyHandle; michael@0: michael@0: CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB(); michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: nsAutoCString username; michael@0: char *temp_un = CERT_GetCommonName(&cert->subject); michael@0: if (temp_un) { michael@0: username = temp_un; michael@0: PORT_Free(temp_un); michael@0: temp_un = nullptr; michael@0: } michael@0: michael@0: nsAutoCString caname; michael@0: char *temp_ca = CERT_GetOrgName(&cert->issuer); michael@0: if (temp_ca) { michael@0: caname = temp_ca; michael@0: PORT_Free(temp_ca); michael@0: temp_ca = nullptr; michael@0: } michael@0: michael@0: nsAutoString tmpNickFmt; michael@0: nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt); michael@0: NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt); michael@0: michael@0: nsAutoCString baseName; michael@0: char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get()); michael@0: if (!temp_nn) { michael@0: return; michael@0: } else { michael@0: baseName = temp_nn; michael@0: PR_smprintf_free(temp_nn); michael@0: temp_nn = nullptr; michael@0: } michael@0: michael@0: nickname = baseName; michael@0: michael@0: /* michael@0: * We need to see if the private key exists on a token, if it does michael@0: * then we need to check for nicknames that already exist on the smart michael@0: * card. michael@0: */ michael@0: ScopedPK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx)); michael@0: if (!slot) michael@0: return; michael@0: michael@0: if (!PK11_IsInternal(slot)) { michael@0: char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get()); michael@0: if (!tmp) { michael@0: nickname.Truncate(); michael@0: return; michael@0: } michael@0: baseName = tmp; michael@0: PR_smprintf_free(tmp); michael@0: michael@0: nickname = baseName; michael@0: } michael@0: michael@0: int count = 1; michael@0: while (true) { michael@0: if ( count > 1 ) { michael@0: char *tmp = PR_smprintf("%s #%d", baseName.get(), count); michael@0: if (!tmp) { michael@0: nickname.Truncate(); michael@0: return; michael@0: } michael@0: nickname = tmp; michael@0: PR_smprintf_free(tmp); michael@0: } michael@0: michael@0: mozilla::pkix::ScopedCERTCertificate dummycert; michael@0: michael@0: if (PK11_IsInternal(slot)) { michael@0: /* look up the nickname to make sure it isn't in use already */ michael@0: dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get()); michael@0: michael@0: } else { michael@0: /* michael@0: * Check the cert against others that already live on the smart michael@0: * card. michael@0: */ michael@0: dummycert = PK11_FindCertFromNickname(nickname.get(), ctx); michael@0: if (dummycert) { michael@0: /* michael@0: * Make sure the subject names are different. michael@0: */ michael@0: if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) michael@0: { michael@0: /* michael@0: * There is another certificate with the same nickname and michael@0: * the same subject name on the smart card, so let's use this michael@0: * nickname. michael@0: */ michael@0: dummycert = nullptr; michael@0: } michael@0: } michael@0: } michael@0: if (!dummycert) michael@0: break; michael@0: michael@0: count++; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aBase64); michael@0: nsCOMPtr newCert; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsNSSCertTrust trust; michael@0: michael@0: // need to calculate the trust bits from the aTrust string. michael@0: SECStatus stat = CERT_DecodeTrustString(trust.GetTrust(), michael@0: /* this is const, but not declared that way */(char *) aTrust); michael@0: NS_ENSURE_STATE(stat == SECSuccess); // if bad trust passed in, return error. michael@0: michael@0: michael@0: nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: SECItem der; michael@0: rv = newCert->GetRawDER(&der.len, (uint8_t **)&der.data); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); michael@0: CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); michael@0: mozilla::pkix::ScopedCERTCertificate tmpCert(CERT_FindCertByDERCert(certdb, &der)); michael@0: if (!tmpCert) michael@0: tmpCert = CERT_NewTempCertificate(certdb, &der, michael@0: nullptr, false, true); michael@0: nsMemory::Free(der.data); michael@0: der.data = nullptr; michael@0: der.len = 0; michael@0: michael@0: if (!tmpCert) { michael@0: NS_ERROR("Couldn't create cert from DER blob"); michael@0: return MapSECStatus(SECFailure); michael@0: } michael@0: michael@0: if (tmpCert->isperm) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsXPIDLCString nickname; michael@0: nickname.Adopt(CERT_MakeCANickname(tmpCert.get())); michael@0: michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); michael@0: michael@0: rv = attemptToLogInWithDefaultPassword(); michael@0: if (NS_WARN_IF(rv != NS_OK)) { michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(), michael@0: const_cast(nickname.get()), michael@0: trust.GetTrust()); michael@0: return MapSECStatus(srv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust, michael@0: const char *aName) michael@0: { michael@0: nsCString base64; michael@0: nsresult rv = Base64Encode(aCertDER, base64); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: return AddCertFromBase64(base64.get(), aTrust, aName); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert, michael@0: const char* trustString) michael@0: { michael@0: CERTCertTrust trust; michael@0: michael@0: // need to calculate the trust bits from the aTrust string. michael@0: SECStatus srv = CERT_DecodeTrustString(&trust, michael@0: const_cast(trustString)); michael@0: if (srv != SECSuccess) { michael@0: return MapSECStatus(SECFailure); michael@0: } michael@0: mozilla::pkix::ScopedCERTCertificate nssCert(cert->GetCert()); michael@0: michael@0: nsresult rv = attemptToLogInWithDefaultPassword(); michael@0: if (NS_WARN_IF(rv != NS_OK)) { michael@0: return rv; michael@0: } michael@0: michael@0: srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust); michael@0: return MapSECStatus(srv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsCOMPtr ctx = new PipUIContext(); michael@0: nsCOMPtr nssCertList; michael@0: mozilla::pkix::ScopedCERTCertList certList( michael@0: PK11_ListCerts(PK11CertListUnique, ctx)); michael@0: michael@0: // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine. michael@0: // (returns an empty list) michael@0: nssCertList = new nsNSSCertList(certList, locker); michael@0: michael@0: *_retval = nssCertList; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: MutexAutoLock lock(mBadCertsLock); michael@0: if (isPrivate) { michael@0: if (!mPrivateRecentBadCerts) { michael@0: mPrivateRecentBadCerts = new nsRecentBadCerts; michael@0: } michael@0: NS_ADDREF(*result = mPrivateRecentBadCerts); michael@0: } else { michael@0: if (!mPublicRecentBadCerts) { michael@0: mPublicRecentBadCerts = new nsRecentBadCerts; michael@0: } michael@0: NS_ADDREF(*result = mPublicRecentBadCerts); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert, michael@0: int64_t /*SECCertificateUsage*/ aUsage, michael@0: uint32_t aFlags, michael@0: nsIX509CertList** verifiedChain, michael@0: bool* aHasEVPolicy, michael@0: int32_t* /*PRErrorCode*/ _retval ) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCert); michael@0: NS_ENSURE_ARG_POINTER(aHasEVPolicy); michael@0: NS_ENSURE_ARG_POINTER(verifiedChain); michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: michael@0: *verifiedChain = nullptr; michael@0: *aHasEVPolicy = false; michael@0: *_retval = PR_UNKNOWN_ERROR; michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: #ifndef MOZ_NO_EV_CERTS michael@0: EnsureIdentityInfoLoaded(); michael@0: #endif michael@0: michael@0: nsCOMPtr x509Cert = do_QueryInterface(aCert); michael@0: if (!x509Cert) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: ScopedCERTCertificate nssCert(x509Cert->GetCert()); michael@0: michael@0: RefPtr certVerifier(GetDefaultCertVerifier()); michael@0: NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); michael@0: michael@0: mozilla::pkix::ScopedCERTCertList resultChain; michael@0: SECOidTag evOidPolicy; michael@0: SECStatus srv; michael@0: michael@0: srv = certVerifier->VerifyCert(nssCert, michael@0: aUsage, PR_Now(), michael@0: nullptr, // Assume no context michael@0: nullptr, // hostname michael@0: aFlags, michael@0: nullptr, // stapledOCSPResponse michael@0: &resultChain, michael@0: &evOidPolicy); michael@0: michael@0: PRErrorCode error = PR_GetError(); michael@0: michael@0: nsCOMPtr nssCertList; michael@0: // This adopts the list michael@0: nssCertList = new nsNSSCertList(resultChain, locker); michael@0: NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE); michael@0: michael@0: if (srv == SECSuccess) { michael@0: if (evOidPolicy != SEC_OID_UNKNOWN) { michael@0: *aHasEVPolicy = true; michael@0: } michael@0: *_retval = 0; michael@0: } else { michael@0: NS_ENSURE_TRUE(evOidPolicy == SEC_OID_UNKNOWN, NS_ERROR_FAILURE); michael@0: NS_ENSURE_TRUE(error != 0, NS_ERROR_FAILURE); michael@0: *_retval = error; michael@0: } michael@0: nssCertList.forget(verifiedChain); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificateDB::ClearOCSPCache() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: RefPtr certVerifier(GetDefaultCertVerifier()); michael@0: NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); michael@0: if (certVerifier->mImplementation == CertVerifier::mozillapkix) { michael@0: certVerifier->ClearOCSPCache(); michael@0: } else { michael@0: SECStatus srv = CERT_ClearOCSPCache(); michael@0: if (srv != SECSuccess) { michael@0: return MapSECStatus(srv); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: }