LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNSSCertificateDB.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 747 0.1 %
Date: 2017-07-14 16:53:18 Functions: 2 47 4.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "nsNSSCertificateDB.h"
       6             : 
       7             : #include "CertVerifier.h"
       8             : #include "CryptoTask.h"
       9             : #include "ExtendedValidation.h"
      10             : #include "NSSCertDBTrustDomain.h"
      11             : #include "SharedSSLState.h"
      12             : #include "certdb.h"
      13             : #include "mozilla/Assertions.h"
      14             : #include "mozilla/Base64.h"
      15             : #include "mozilla/Casting.h"
      16             : #include "mozilla/Unused.h"
      17             : #include "nsArray.h"
      18             : #include "nsArrayUtils.h"
      19             : #include "nsCOMPtr.h"
      20             : #include "nsComponentManagerUtils.h"
      21             : #include "nsICertificateDialogs.h"
      22             : #include "nsIFile.h"
      23             : #include "nsIMutableArray.h"
      24             : #include "nsIObserverService.h"
      25             : #include "nsIPrefBranch.h"
      26             : #include "nsIPrefService.h"
      27             : #include "nsIPrompt.h"
      28             : #include "nsNSSCertHelper.h"
      29             : #include "nsNSSCertTrust.h"
      30             : #include "nsNSSCertificate.h"
      31             : #include "nsNSSComponent.h"
      32             : #include "nsNSSHelper.h"
      33             : #include "nsNSSShutDown.h"
      34             : #include "nsPKCS12Blob.h"
      35             : #include "nsPromiseFlatString.h"
      36             : #include "nsProxyRelease.h"
      37             : #include "nsReadableUtils.h"
      38             : #include "nsThreadUtils.h"
      39             : #include "nspr.h"
      40             : #include "pkix/Time.h"
      41             : #include "pkix/pkixnss.h"
      42             : #include "pkix/pkixtypes.h"
      43             : #include "secasn1.h"
      44             : #include "secder.h"
      45             : #include "secerr.h"
      46             : #include "ssl.h"
      47             : 
      48             : #ifdef XP_WIN
      49             : #include <winsock.h> // for ntohl
      50             : #endif
      51             : 
      52             : using namespace mozilla;
      53             : using namespace mozilla::psm;
      54             : using mozilla::psm::SharedSSLState;
      55             : 
      56             : extern LazyLogModule gPIPNSSLog;
      57             : 
      58             : static nsresult
      59           0 : attemptToLogInWithDefaultPassword()
      60             : {
      61             : #ifdef NSS_DISABLE_DBM
      62             :   // The SQL NSS DB requires the user to be authenticated to set certificate
      63             :   // trust settings, even if the user's password is empty. To maintain
      64             :   // compatibility with the DBM-based database, try to log in with the
      65             :   // default empty password. This will allow, at least, tests that need to
      66             :   // change certificate trust to pass on all platforms. TODO(bug 978120): Do
      67             :   // proper testing and/or implement a better solution so that we are confident
      68             :   // that this does the correct thing outside of xpcshell tests too.
      69             :   UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
      70             :   if (!slot) {
      71             :     return MapSECStatus(SECFailure);
      72             :   }
      73             :   if (PK11_NeedUserInit(slot.get())) {
      74             :     // Ignore the return value. Presumably PK11_InitPin will fail if the user
      75             :     // has a non-default password.
      76             :     Unused << PK11_InitPin(slot.get(), nullptr, nullptr);
      77             :   }
      78             : #endif
      79             : 
      80           0 :   return NS_OK;
      81             : }
      82             : 
      83           0 : NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
      84             : 
      85           0 : nsNSSCertificateDB::~nsNSSCertificateDB()
      86             : {
      87           0 :   nsNSSShutDownPreventionLock locker;
      88           0 :   if (isAlreadyShutDown()) {
      89           0 :     return;
      90             :   }
      91             : 
      92           0 :   shutdown(ShutdownCalledFrom::Object);
      93           0 : }
      94             : 
      95             : NS_IMETHODIMP
      96           0 : nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey,
      97             :                             /*out*/ nsIX509Cert** _cert)
      98             : {
      99           0 :   NS_ENSURE_ARG_POINTER(_cert);
     100           0 :   *_cert = nullptr;
     101             : 
     102           0 :   if (aDBKey.IsEmpty()) {
     103           0 :     return NS_ERROR_INVALID_ARG;
     104             :   }
     105             : 
     106           0 :   nsNSSShutDownPreventionLock locker;
     107           0 :   if (isAlreadyShutDown()) {
     108           0 :     return NS_ERROR_NOT_AVAILABLE;
     109             :   }
     110             : 
     111           0 :   UniqueCERTCertificate cert;
     112           0 :   nsresult rv = FindCertByDBKey(aDBKey, cert);
     113           0 :   if (NS_FAILED(rv)) {
     114           0 :     return rv;
     115             :   }
     116             :   // If we can't find the certificate, that's not an error. Just return null.
     117           0 :   if (!cert) {
     118           0 :     return NS_OK;
     119             :   }
     120           0 :   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
     121           0 :   if (!nssCert) {
     122           0 :     return NS_ERROR_OUT_OF_MEMORY;
     123             :   }
     124           0 :   nssCert.forget(_cert);
     125           0 :   return NS_OK;
     126             : }
     127             : 
     128             : nsresult
     129           0 : nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey,
     130             :                                     UniqueCERTCertificate& cert)
     131             : {
     132             :   static_assert(sizeof(uint64_t) == 8, "type size sanity check");
     133             :   static_assert(sizeof(uint32_t) == 4, "type size sanity check");
     134             :   // (From nsNSSCertificate::GetDbKey)
     135             :   // The format of the key is the base64 encoding of the following:
     136             :   // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
     137             :   //                        never implemented)
     138             :   // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
     139             :   //                        never implemented)
     140             :   // 4 bytes: <serial number length in big-endian order>
     141             :   // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
     142             :   // n bytes: <bytes of serial number>
     143             :   // m bytes: <DER-encoded issuer distinguished name>
     144           0 :   nsAutoCString decoded;
     145           0 :   nsAutoCString tmpDBKey(aDBKey);
     146             :   // Filter out any whitespace for backwards compatibility.
     147           0 :   tmpDBKey.StripWhitespace();
     148           0 :   nsresult rv = Base64Decode(tmpDBKey, decoded);
     149           0 :   if (NS_FAILED(rv)) {
     150           0 :     return rv;
     151             :   }
     152           0 :   if (decoded.Length() < 16) {
     153           0 :     return NS_ERROR_ILLEGAL_INPUT;
     154             :   }
     155           0 :   const char* reader = decoded.BeginReading();
     156           0 :   uint64_t zeroes = *BitwiseCast<const uint64_t*, const char*>(reader);
     157           0 :   if (zeroes != 0) {
     158           0 :     return NS_ERROR_ILLEGAL_INPUT;
     159             :   }
     160           0 :   reader += sizeof(uint64_t);
     161             :   // Note: We surround the ntohl() argument with parentheses to stop the macro
     162             :   //       from thinking two arguments were passed.
     163           0 :   uint32_t serialNumberLen = ntohl(
     164           0 :     (*BitwiseCast<const uint32_t*, const char*>(reader)));
     165           0 :   reader += sizeof(uint32_t);
     166           0 :   uint32_t issuerLen = ntohl(
     167           0 :     (*BitwiseCast<const uint32_t*, const char*>(reader)));
     168           0 :   reader += sizeof(uint32_t);
     169           0 :   if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) {
     170           0 :     return NS_ERROR_ILLEGAL_INPUT;
     171             :   }
     172             :   CERTIssuerAndSN issuerSN;
     173           0 :   issuerSN.serialNumber.len = serialNumberLen;
     174           0 :   issuerSN.serialNumber.data = BitwiseCast<unsigned char*, const char*>(reader);
     175           0 :   reader += serialNumberLen;
     176           0 :   issuerSN.derIssuer.len = issuerLen;
     177           0 :   issuerSN.derIssuer.data = BitwiseCast<unsigned char*, const char*>(reader);
     178           0 :   reader += issuerLen;
     179           0 :   MOZ_ASSERT(reader == decoded.EndReading());
     180             : 
     181           0 :   cert.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
     182           0 :   return NS_OK;
     183             : }
     184             : 
     185             : SECStatus
     186           0 : collect_certs(void *arg, SECItem **certs, int numcerts)
     187             : {
     188             :   CERTDERCerts *collectArgs;
     189             :   SECItem *cert;
     190             :   SECStatus rv;
     191             : 
     192           0 :   collectArgs = (CERTDERCerts *)arg;
     193             : 
     194           0 :   collectArgs->numcerts = numcerts;
     195           0 :   collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
     196             :                                            sizeof(SECItem) * numcerts);
     197           0 :   if (!collectArgs->rawCerts)
     198           0 :     return(SECFailure);
     199             : 
     200           0 :   cert = collectArgs->rawCerts;
     201             : 
     202           0 :   while ( numcerts-- ) {
     203           0 :     rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
     204           0 :     if ( rv == SECFailure )
     205           0 :       return(SECFailure);
     206           0 :     cert++;
     207           0 :     certs++;
     208             :   }
     209             : 
     210           0 :   return (SECSuccess);
     211             : }
     212             : 
     213             : CERTDERCerts*
     214           0 : nsNSSCertificateDB::getCertsFromPackage(const UniquePLArenaPool& arena,
     215             :                                         uint8_t* data, uint32_t length,
     216             :                                         const nsNSSShutDownPreventionLock& /*proofOfLock*/)
     217             : {
     218           0 :   CERTDERCerts* collectArgs = PORT_ArenaZNew(arena.get(), CERTDERCerts);
     219           0 :   if (!collectArgs) {
     220           0 :     return nullptr;
     221             :   }
     222             : 
     223           0 :   collectArgs->arena = arena.get();
     224           0 :   if (CERT_DecodeCertPackage(BitwiseCast<char*, uint8_t*>(data), length,
     225             :                              collect_certs, collectArgs) != SECSuccess) {
     226           0 :     return nullptr;
     227             :   }
     228             : 
     229           0 :   return collectArgs;
     230             : }
     231             : 
     232             : nsresult
     233           0 : nsNSSCertificateDB::handleCACertDownload(NotNull<nsIArray*> x509Certs,
     234             :                                          nsIInterfaceRequestor *ctx,
     235             :                                          const nsNSSShutDownPreventionLock &proofOfLock)
     236             : {
     237             :   // First thing we have to do is figure out which certificate we're
     238             :   // gonna present to the user.  The CA may have sent down a list of
     239             :   // certs which may or may not be a chained list of certs.  Until
     240             :   // the day we can design some solid UI for the general case, we'll
     241             :   // code to the > 90% case.  That case is where a CA sends down a
     242             :   // list that is a hierarchy whose root is either the first or
     243             :   // the last cert.  What we're gonna do is compare the first
     244             :   // 2 entries, if the second was signed by the first, we assume
     245             :   // the root cert is the first cert and display it.  Otherwise,
     246             :   // we compare the last 2 entries, if the second to last cert was
     247             :   // signed by the last cert, then we assume the last cert is the
     248             :   // root and display it.
     249             : 
     250             :   uint32_t numCerts;
     251             : 
     252           0 :   x509Certs->GetLength(&numCerts);
     253           0 :   MOZ_ASSERT(numCerts > 0, "Didn't get any certs to import.");
     254           0 :   if (numCerts == 0)
     255           0 :     return NS_OK; // Nothing to import, so nothing to do.
     256             : 
     257           0 :   nsCOMPtr<nsIX509Cert> certToShow;
     258             :   uint32_t selCertIndex;
     259           0 :   if (numCerts == 1) {
     260             :     // There's only one cert, so let's show it.
     261           0 :     selCertIndex = 0;
     262           0 :     certToShow = do_QueryElementAt(x509Certs, selCertIndex);
     263             :   } else {
     264           0 :     nsCOMPtr<nsIX509Cert> cert0;    // first cert
     265           0 :     nsCOMPtr<nsIX509Cert> cert1;    // second cert
     266           0 :     nsCOMPtr<nsIX509Cert> certn_2;  // second to last cert
     267           0 :     nsCOMPtr<nsIX509Cert> certn_1;  // last cert
     268             : 
     269           0 :     cert0 = do_QueryElementAt(x509Certs, 0);
     270           0 :     cert1 = do_QueryElementAt(x509Certs, 1);
     271           0 :     certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
     272           0 :     certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
     273             : 
     274           0 :     nsXPIDLString cert0SubjectName;
     275           0 :     nsXPIDLString cert1IssuerName;
     276           0 :     nsXPIDLString certn_2IssuerName;
     277           0 :     nsXPIDLString certn_1SubjectName;
     278             : 
     279           0 :     cert0->GetSubjectName(cert0SubjectName);
     280           0 :     cert1->GetIssuerName(cert1IssuerName);
     281           0 :     certn_2->GetIssuerName(certn_2IssuerName);
     282           0 :     certn_1->GetSubjectName(certn_1SubjectName);
     283             : 
     284           0 :     if (cert1IssuerName.Equals(cert0SubjectName)) {
     285             :       // In this case, the first cert in the list signed the second,
     286             :       // so the first cert is the root.  Let's display it.
     287           0 :       selCertIndex = 0;
     288           0 :       certToShow = cert0;
     289             :     } else
     290           0 :     if (certn_2IssuerName.Equals(certn_1SubjectName)) {
     291             :       // In this case the last cert has signed the second to last cert.
     292             :       // The last cert is the root, so let's display it.
     293           0 :       selCertIndex = numCerts-1;
     294           0 :       certToShow = certn_1;
     295             :     } else {
     296             :       // It's not a chain, so let's just show the first one in the
     297             :       // downloaded list.
     298           0 :       selCertIndex = 0;
     299           0 :       certToShow = cert0;
     300             :     }
     301             :   }
     302             : 
     303           0 :   if (!certToShow)
     304           0 :     return NS_ERROR_FAILURE;
     305             : 
     306           0 :   nsCOMPtr<nsICertificateDialogs> dialogs;
     307           0 :   nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
     308             :                                 NS_GET_IID(nsICertificateDialogs),
     309           0 :                                 NS_CERTIFICATEDIALOGS_CONTRACTID);
     310           0 :   if (NS_FAILED(rv)) {
     311           0 :     return rv;
     312             :   }
     313             : 
     314           0 :   UniqueCERTCertificate tmpCert(certToShow->GetCert());
     315           0 :   if (!tmpCert) {
     316           0 :     return NS_ERROR_FAILURE;
     317             :   }
     318             : 
     319           0 :   if (!CERT_IsCACert(tmpCert.get(), nullptr)) {
     320           0 :     DisplayCertificateAlert(ctx, "NotACACert", certToShow, proofOfLock);
     321           0 :     return NS_ERROR_FAILURE;
     322             :   }
     323             : 
     324           0 :   if (tmpCert->isperm) {
     325           0 :     DisplayCertificateAlert(ctx, "CaCertExists", certToShow, proofOfLock);
     326           0 :     return NS_ERROR_FAILURE;
     327             :   }
     328             : 
     329             :   uint32_t trustBits;
     330             :   bool allows;
     331           0 :   rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
     332           0 :   if (NS_FAILED(rv))
     333           0 :     return rv;
     334             : 
     335           0 :   if (!allows)
     336           0 :     return NS_ERROR_NOT_AVAILABLE;
     337             : 
     338           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trust is %d\n", trustBits));
     339           0 :   UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
     340             : 
     341           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get()));
     342             : 
     343           0 :   nsNSSCertTrust trust;
     344           0 :   trust.SetValidCA();
     345           0 :   trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
     346           0 :                    !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL),
     347           0 :                    !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN));
     348             : 
     349           0 :   UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
     350           0 :   SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE,
     351           0 :                                   nickname.get(),
     352           0 :                                   false); // this parameter is ignored by NSS
     353           0 :   if (srv != SECSuccess) {
     354           0 :     return MapSECStatus(srv);
     355             :   }
     356             :   // NSS ignores the first argument to CERT_ChangeCertTrust
     357           0 :   srv = CERT_ChangeCertTrust(nullptr, tmpCert.get(), trust.GetTrust());
     358           0 :   if (srv != SECSuccess) {
     359           0 :     return MapSECStatus(srv);
     360             :   }
     361             : 
     362             :   // Import additional delivered certificates that can be verified.
     363             : 
     364             :   // build a CertList for filtering
     365           0 :   UniqueCERTCertList certList(CERT_NewCertList());
     366           0 :   if (!certList) {
     367           0 :     return NS_ERROR_FAILURE;
     368             :   }
     369             : 
     370             :   // get all remaining certs into temp store
     371             : 
     372           0 :   for (uint32_t i=0; i<numCerts; i++) {
     373           0 :     if (i == selCertIndex) {
     374             :       // we already processed that one
     375           0 :       continue;
     376             :     }
     377             : 
     378           0 :     nsCOMPtr<nsIX509Cert> remainingCert = do_QueryElementAt(x509Certs, i);
     379           0 :     if (!remainingCert) {
     380           0 :       continue;
     381             :     }
     382             : 
     383           0 :     UniqueCERTCertificate tmpCert2(remainingCert->GetCert());
     384           0 :     if (!tmpCert2) {
     385           0 :       continue;  // Let's try to import the rest of 'em
     386             :     }
     387             : 
     388           0 :     if (CERT_AddCertToListTail(certList.get(), tmpCert2.get()) != SECSuccess) {
     389           0 :       continue;
     390             :     }
     391             : 
     392           0 :     Unused << tmpCert2.release();
     393             :   }
     394             : 
     395           0 :   return ImportValidCACertsInList(certList, ctx, proofOfLock);
     396             : }
     397             : 
     398             : NS_IMETHODIMP
     399           0 : nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length,
     400             :                                        uint32_t type,
     401             :                                        nsIInterfaceRequestor* ctx)
     402             : {
     403           0 :   nsNSSShutDownPreventionLock locker;
     404           0 :   if (isAlreadyShutDown()) {
     405           0 :     return NS_ERROR_NOT_AVAILABLE;
     406             :   }
     407             : 
     408             :   // We currently only handle CA certificates.
     409           0 :   if (type != nsIX509Cert::CA_CERT) {
     410           0 :     return NS_ERROR_FAILURE;
     411             :   }
     412             : 
     413           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     414           0 :   if (!arena) {
     415           0 :     return NS_ERROR_OUT_OF_MEMORY;
     416             :   }
     417             : 
     418             :   CERTDERCerts* certCollection = getCertsFromPackage(arena, data, length,
     419           0 :                                                      locker);
     420           0 :   if (!certCollection) {
     421           0 :     return NS_ERROR_FAILURE;
     422             :   }
     423             : 
     424           0 :   nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
     425           0 :   if (!array) {
     426           0 :     return NS_ERROR_FAILURE;
     427             :   }
     428             : 
     429             :   // Now let's create some certs to work with
     430           0 :   for (int i = 0; i < certCollection->numcerts; i++) {
     431           0 :     SECItem* currItem = &certCollection->rawCerts[i];
     432           0 :     nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::ConstructFromDER(
     433           0 :       BitwiseCast<char*, unsigned char*>(currItem->data), currItem->len);
     434           0 :     if (!cert) {
     435           0 :       return NS_ERROR_FAILURE;
     436             :     }
     437           0 :     nsresult rv = array->AppendElement(cert, false);
     438           0 :     if (NS_FAILED(rv)) {
     439           0 :       return rv;
     440             :     }
     441             :   }
     442             : 
     443           0 :   return handleCACertDownload(WrapNotNull(array), ctx, locker);
     444             : }
     445             : 
     446             : /**
     447             :  * Filters an array of certs by usage and imports them into temporary storage.
     448             :  *
     449             :  * @param numcerts
     450             :  *        Size of the |certs| array.
     451             :  * @param certs
     452             :  *        Pointer to array of certs to import.
     453             :  * @param usage
     454             :  *        Usage the certs should be filtered on.
     455             :  * @param caOnly
     456             :  *        Whether to import only CA certs.
     457             :  * @param filteredCerts
     458             :  *        List of certs that weren't filtered out and were successfully imported.
     459             :  */
     460             : static nsresult
     461           0 : ImportCertsIntoTempStorage(int numcerts, SECItem* certs,
     462             :                            const SECCertUsage usage, const bool caOnly,
     463             :                            const nsNSSShutDownPreventionLock& /*proofOfLock*/,
     464             :                    /*out*/ const UniqueCERTCertList& filteredCerts)
     465             : {
     466           0 :   NS_ENSURE_ARG_MIN(numcerts, 1);
     467           0 :   NS_ENSURE_ARG_POINTER(certs);
     468           0 :   NS_ENSURE_ARG_POINTER(filteredCerts.get());
     469             : 
     470             :   // CERT_ImportCerts() expects an array of *pointers* to SECItems, so we have
     471             :   // to convert |certs| to such a format first.
     472             :   SECItem** ptrArray =
     473           0 :     static_cast<SECItem**>(PORT_Alloc(sizeof(SECItem*) * numcerts));
     474           0 :   if (!ptrArray) {
     475           0 :     return NS_ERROR_OUT_OF_MEMORY;
     476             :   }
     477             : 
     478           0 :   for (int i = 0; i < numcerts; i++) {
     479           0 :     ptrArray[i] = &certs[i];
     480             :   }
     481             : 
     482           0 :   CERTCertificate** importedCerts = nullptr;
     483           0 :   SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), usage,
     484             :                                    numcerts, ptrArray, &importedCerts, false,
     485           0 :                                    caOnly, nullptr);
     486           0 :   PORT_Free(ptrArray);
     487           0 :   ptrArray = nullptr;
     488           0 :   if (srv != SECSuccess) {
     489           0 :     return NS_ERROR_FAILURE;
     490             :   }
     491             : 
     492           0 :   for (int i = 0; i < numcerts; i++) {
     493           0 :     if (!importedCerts[i]) {
     494           0 :       continue;
     495             :     }
     496             : 
     497           0 :     UniqueCERTCertificate cert(CERT_DupCertificate(importedCerts[i]));
     498           0 :     if (!cert) {
     499           0 :       continue;
     500             :     }
     501             : 
     502           0 :     if (CERT_AddCertToListTail(filteredCerts.get(), cert.get()) == SECSuccess) {
     503           0 :       Unused << cert.release();
     504             :     }
     505             :   }
     506             : 
     507           0 :   CERT_DestroyCertArray(importedCerts, numcerts);
     508             : 
     509             :   // CERT_ImportCerts() ignores its |usage| parameter, so we have to manually
     510             :   // filter out unwanted certs.
     511           0 :   if (CERT_FilterCertListByUsage(filteredCerts.get(), usage, caOnly)
     512             :         != SECSuccess) {
     513           0 :     return NS_ERROR_FAILURE;
     514             :   }
     515             : 
     516           0 :   return NS_OK;
     517             : }
     518             : 
     519             : static nsresult
     520           0 : ImportCertsIntoPermanentStorage(const UniqueCERTCertList& certChain)
     521             : {
     522           0 :   bool encounteredFailure = false;
     523           0 :   PRErrorCode savedErrorCode = 0;
     524           0 :   UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
     525           0 :   for (CERTCertListNode* chainNode = CERT_LIST_HEAD(certChain);
     526           0 :        !CERT_LIST_END(chainNode, certChain);
     527           0 :        chainNode = CERT_LIST_NEXT(chainNode)) {
     528           0 :     UniquePORTString nickname(CERT_MakeCANickname(chainNode->cert));
     529           0 :     SECStatus srv = PK11_ImportCert(slot.get(), chainNode->cert,
     530           0 :                                     CK_INVALID_HANDLE, nickname.get(),
     531           0 :                                     false); // this parameter is ignored by NSS
     532           0 :     if (srv != SECSuccess) {
     533           0 :       encounteredFailure = true;
     534           0 :       savedErrorCode = PR_GetError();
     535             :     }
     536             :   }
     537             : 
     538           0 :   if (encounteredFailure) {
     539           0 :     return GetXPCOMFromNSSError(savedErrorCode);
     540             :   }
     541             : 
     542           0 :   return NS_OK;
     543             : }
     544             : 
     545             : NS_IMETHODIMP
     546           0 : nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length,
     547             :                                            nsIInterfaceRequestor* ctx)
     548             : {
     549           0 :   nsNSSShutDownPreventionLock locker;
     550           0 :   if (isAlreadyShutDown()) {
     551           0 :     return NS_ERROR_NOT_AVAILABLE;
     552             :   }
     553             : 
     554           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     555           0 :   if (!arena) {
     556           0 :     return NS_ERROR_OUT_OF_MEMORY;
     557             :   }
     558             : 
     559           0 :   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
     560           0 :   if (!certCollection) {
     561           0 :     return NS_ERROR_FAILURE;
     562             :   }
     563             : 
     564           0 :   UniqueCERTCertList filteredCerts(CERT_NewCertList());
     565           0 :   if (!filteredCerts) {
     566           0 :     return NS_ERROR_FAILURE;
     567             :   }
     568             : 
     569           0 :   nsresult rv = ImportCertsIntoTempStorage(certCollection->numcerts,
     570             :                                            certCollection->rawCerts,
     571             :                                            certUsageEmailRecipient,
     572           0 :                                            false, locker, filteredCerts);
     573           0 :   if (NS_FAILED(rv)) {
     574           0 :     return rv;
     575             :   }
     576             : 
     577           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
     578           0 :   if (!certVerifier) {
     579           0 :     return NS_ERROR_UNEXPECTED;
     580             :   }
     581             : 
     582             :   // Iterate through the filtered cert list and import verified certs into
     583             :   // permanent storage.
     584             :   // Note: We verify the certs in order to prevent DoS attacks. See Bug 249004.
     585           0 :   for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get());
     586           0 :        !CERT_LIST_END(node, filteredCerts.get());
     587           0 :        node = CERT_LIST_NEXT(node)) {
     588           0 :     if (!node->cert) {
     589           0 :       continue;
     590             :     }
     591             : 
     592           0 :     UniqueCERTCertList certChain;
     593             :     mozilla::pkix::Result result =
     594           0 :       certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
     595           0 :                                mozilla::pkix::Now(), ctx, nullptr, certChain);
     596           0 :     if (result != mozilla::pkix::Success) {
     597           0 :       nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
     598           0 :       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker);
     599           0 :       continue;
     600             :     }
     601           0 :     rv = ImportCertsIntoPermanentStorage(certChain);
     602           0 :     if (NS_FAILED(rv)) {
     603           0 :       return rv;
     604             :     }
     605           0 :     CERT_SaveSMimeProfile(node->cert, nullptr, nullptr);
     606             :   }
     607             : 
     608           0 :   return NS_OK;
     609             : }
     610             : 
     611             : nsresult
     612           0 : nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem* caCerts,
     613             :                                        nsIInterfaceRequestor* ctx,
     614             :                                        const nsNSSShutDownPreventionLock& proofOfLock)
     615             : {
     616           0 :   UniqueCERTCertList filteredCerts(CERT_NewCertList());
     617           0 :   if (!filteredCerts) {
     618           0 :     return NS_ERROR_FAILURE;
     619             :   }
     620             : 
     621             :   nsresult rv = ImportCertsIntoTempStorage(numCACerts, caCerts, certUsageAnyCA,
     622           0 :                                            true, proofOfLock, filteredCerts);
     623           0 :   if (NS_FAILED(rv)) {
     624           0 :     return rv;
     625             :   }
     626             : 
     627           0 :   return ImportValidCACertsInList(filteredCerts, ctx, proofOfLock);
     628             : }
     629             : 
     630             : nsresult
     631           0 : nsNSSCertificateDB::ImportValidCACertsInList(const UniqueCERTCertList& filteredCerts,
     632             :                                              nsIInterfaceRequestor* ctx,
     633             :                                              const nsNSSShutDownPreventionLock& proofOfLock)
     634             : {
     635           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
     636           0 :   if (!certVerifier) {
     637           0 :     return NS_ERROR_UNEXPECTED;
     638             :   }
     639             : 
     640             :   // Iterate through the filtered cert list and import verified certs into
     641             :   // permanent storage.
     642             :   // Note: We verify the certs in order to prevent DoS attacks. See Bug 249004.
     643           0 :   for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get());
     644           0 :        !CERT_LIST_END(node, filteredCerts.get());
     645           0 :        node = CERT_LIST_NEXT(node)) {
     646           0 :     UniqueCERTCertList certChain;
     647             :     mozilla::pkix::Result result =
     648           0 :       certVerifier->VerifyCert(node->cert, certificateUsageVerifyCA,
     649           0 :                                mozilla::pkix::Now(), ctx, nullptr, certChain);
     650           0 :     if (result != mozilla::pkix::Success) {
     651           0 :       nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
     652           0 :       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock);
     653           0 :       continue;
     654             :     }
     655             : 
     656           0 :     nsresult rv = ImportCertsIntoPermanentStorage(certChain);
     657           0 :     if (NS_FAILED(rv)) {
     658           0 :       return rv;
     659             :     }
     660             :   }
     661             : 
     662           0 :   return NS_OK;
     663             : }
     664             : 
     665           0 : void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx,
     666             :                                                  const char *stringID,
     667             :                                                  nsIX509Cert *certToShow,
     668             :                                                  const nsNSSShutDownPreventionLock &/*proofOfLock*/)
     669             : {
     670             :   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     671             : 
     672           0 :   if (!NS_IsMainThread()) {
     673           0 :     NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread");
     674           0 :     return;
     675             :   }
     676             : 
     677           0 :   nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx;
     678           0 :   if (!my_ctx) {
     679           0 :     my_ctx = new PipUIContext();
     680             :   }
     681             : 
     682             :   // This shall be replaced by embedding ovverridable prompts
     683             :   // as discussed in bug 310446, and should make use of certToShow.
     684             : 
     685             :   nsresult rv;
     686           0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
     687           0 :   if (NS_SUCCEEDED(rv)) {
     688           0 :     nsAutoString tmpMessage;
     689           0 :     nssComponent->GetPIPNSSBundleString(stringID, tmpMessage);
     690             : 
     691           0 :     nsCOMPtr<nsIPrompt> prompt (do_GetInterface(my_ctx));
     692           0 :     if (!prompt) {
     693           0 :       return;
     694             :     }
     695             : 
     696           0 :     prompt->Alert(nullptr, tmpMessage.get());
     697             :   }
     698             : }
     699             : 
     700             : NS_IMETHODIMP
     701           0 : nsNSSCertificateDB::ImportUserCertificate(uint8_t* data, uint32_t length,
     702             :                                           nsIInterfaceRequestor* ctx)
     703             : {
     704           0 :   if (!NS_IsMainThread()) {
     705           0 :     NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
     706           0 :     return NS_ERROR_NOT_SAME_THREAD;
     707             :   }
     708             : 
     709           0 :   nsNSSShutDownPreventionLock locker;
     710           0 :   if (isAlreadyShutDown()) {
     711           0 :     return NS_ERROR_NOT_AVAILABLE;
     712             :   }
     713             : 
     714           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     715           0 :   if (!arena) {
     716           0 :     return NS_ERROR_OUT_OF_MEMORY;
     717             :   }
     718             : 
     719           0 :   CERTDERCerts* collectArgs = getCertsFromPackage(arena, data, length, locker);
     720           0 :   if (!collectArgs) {
     721           0 :     return NS_ERROR_FAILURE;
     722             :   }
     723             : 
     724             :   UniqueCERTCertificate cert(
     725             :     CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
     726           0 :                             nullptr, false, true));
     727           0 :   if (!cert) {
     728           0 :     return NS_ERROR_FAILURE;
     729             :   }
     730             : 
     731           0 :   UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert.get(), nullptr, ctx));
     732           0 :   if (!slot) {
     733           0 :     nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
     734           0 :     DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker);
     735           0 :     return NS_ERROR_FAILURE;
     736             :   }
     737           0 :   slot = nullptr;
     738             : 
     739             :   /* pick a nickname for the cert */
     740           0 :   nsAutoCString nickname;
     741           0 :   if (cert->nickname) {
     742           0 :     nickname = cert->nickname;
     743             :   } else {
     744           0 :     get_default_nickname(cert.get(), ctx, nickname, locker);
     745             :   }
     746             : 
     747             :   /* user wants to import the cert */
     748           0 :   slot.reset(PK11_ImportCertForKey(cert.get(), nickname.get(), ctx));
     749           0 :   if (!slot) {
     750           0 :     return NS_ERROR_FAILURE;
     751             :   }
     752           0 :   slot = nullptr;
     753             : 
     754             :   {
     755           0 :     nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
     756           0 :     DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker);
     757             :   }
     758             : 
     759           0 :   int numCACerts = collectArgs->numcerts - 1;
     760           0 :   if (numCACerts) {
     761           0 :     SECItem* caCerts = collectArgs->rawCerts + 1;
     762           0 :     return ImportValidCACerts(numCACerts, caCerts, ctx, locker);
     763             :   }
     764             : 
     765           0 :   return NS_OK;
     766             : }
     767             : 
     768             : NS_IMETHODIMP
     769           0 : nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
     770             : {
     771           0 :   NS_ENSURE_ARG_POINTER(aCert);
     772           0 :   nsNSSShutDownPreventionLock locker;
     773           0 :   if (isAlreadyShutDown()) {
     774           0 :     return NS_ERROR_NOT_AVAILABLE;
     775             :   }
     776           0 :   UniqueCERTCertificate cert(aCert->GetCert());
     777           0 :   if (!cert) {
     778           0 :     return NS_ERROR_FAILURE;
     779             :   }
     780           0 :   SECStatus srv = SECSuccess;
     781             : 
     782             :   uint32_t certType;
     783           0 :   aCert->GetCertType(&certType);
     784           0 :   if (NS_FAILED(aCert->MarkForPermDeletion()))
     785             :   {
     786           0 :     return NS_ERROR_FAILURE;
     787             :   }
     788             : 
     789           0 :   if (cert->slot && certType != nsIX509Cert::USER_CERT) {
     790             :     // To delete a cert of a slot (builtin, most likely), mark it as
     791             :     // completely untrusted.  This way we keep a copy cached in the
     792             :     // local database, and next time we try to load it off of the
     793             :     // external token/slot, we'll know not to trust it.  We don't
     794             :     // want to do that with user certs, because a user may  re-store
     795             :     // the cert onto the card again at which point we *will* want to
     796             :     // trust that cert if it chains up properly.
     797           0 :     nsNSSCertTrust trust(0, 0, 0);
     798           0 :     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
     799           0 :                                cert.get(), trust.GetTrust());
     800             :   }
     801           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("cert deleted: %d", srv));
     802           0 :   return (srv) ? NS_ERROR_FAILURE : NS_OK;
     803             : }
     804             : 
     805             : NS_IMETHODIMP
     806           0 : nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
     807             :                                  uint32_t type,
     808             :                                  uint32_t trusted)
     809             : {
     810           0 :   NS_ENSURE_ARG_POINTER(cert);
     811           0 :   nsNSSShutDownPreventionLock locker;
     812           0 :   if (isAlreadyShutDown()) {
     813           0 :     return NS_ERROR_NOT_AVAILABLE;
     814             :   }
     815           0 :   nsNSSCertTrust trust;
     816             :   nsresult rv;
     817           0 :   UniqueCERTCertificate nsscert(cert->GetCert());
     818             : 
     819           0 :   rv = attemptToLogInWithDefaultPassword();
     820           0 :   if (NS_WARN_IF(rv != NS_OK)) {
     821           0 :     return rv;
     822             :   }
     823             : 
     824             :   SECStatus srv;
     825           0 :   if (type == nsIX509Cert::CA_CERT) {
     826             :     // always start with untrusted and move up
     827           0 :     trust.SetValidCA();
     828           0 :     trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
     829           0 :                      !!(trusted & nsIX509CertDB::TRUSTED_EMAIL),
     830           0 :                      !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN));
     831           0 :     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
     832             :                                nsscert.get(),
     833           0 :                                trust.GetTrust());
     834           0 :   } else if (type == nsIX509Cert::SERVER_CERT) {
     835             :     // always start with untrusted and move up
     836           0 :     trust.SetValidPeer();
     837           0 :     trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
     838           0 :     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
     839             :                                nsscert.get(),
     840           0 :                                trust.GetTrust());
     841           0 :   } else if (type == nsIX509Cert::EMAIL_CERT) {
     842             :     // always start with untrusted and move up
     843           0 :     trust.SetValidPeer();
     844           0 :     trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0);
     845           0 :     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
     846             :                                nsscert.get(),
     847           0 :                                trust.GetTrust());
     848             :   } else {
     849             :     // ignore user certs
     850           0 :     return NS_OK;
     851             :   }
     852           0 :   return MapSECStatus(srv);
     853             : }
     854             : 
     855             : NS_IMETHODIMP
     856           0 : nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
     857             :                                   uint32_t certType,
     858             :                                   uint32_t trustType,
     859             :                                   bool *_isTrusted)
     860             : {
     861           0 :   NS_ENSURE_ARG_POINTER(_isTrusted);
     862           0 :   *_isTrusted = false;
     863             : 
     864           0 :   nsNSSShutDownPreventionLock locker;
     865           0 :   if (isAlreadyShutDown()) {
     866           0 :     return NS_ERROR_NOT_AVAILABLE;
     867             :   }
     868             :   SECStatus srv;
     869           0 :   UniqueCERTCertificate nsscert(cert->GetCert());
     870             :   CERTCertTrust nsstrust;
     871           0 :   srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
     872           0 :   if (srv != SECSuccess)
     873           0 :     return NS_ERROR_FAILURE;
     874             : 
     875           0 :   nsNSSCertTrust trust(&nsstrust);
     876           0 :   if (certType == nsIX509Cert::CA_CERT) {
     877           0 :     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
     878           0 :       *_isTrusted = trust.HasTrustedCA(true, false, false);
     879           0 :     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
     880           0 :       *_isTrusted = trust.HasTrustedCA(false, true, false);
     881           0 :     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
     882           0 :       *_isTrusted = trust.HasTrustedCA(false, false, true);
     883             :     } else {
     884           0 :       return NS_ERROR_FAILURE;
     885             :     }
     886           0 :   } else if (certType == nsIX509Cert::SERVER_CERT) {
     887           0 :     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
     888           0 :       *_isTrusted = trust.HasTrustedPeer(true, false, false);
     889           0 :     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
     890           0 :       *_isTrusted = trust.HasTrustedPeer(false, true, false);
     891           0 :     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
     892           0 :       *_isTrusted = trust.HasTrustedPeer(false, false, true);
     893             :     } else {
     894           0 :       return NS_ERROR_FAILURE;
     895             :     }
     896           0 :   } else if (certType == nsIX509Cert::EMAIL_CERT) {
     897           0 :     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
     898           0 :       *_isTrusted = trust.HasTrustedPeer(true, false, false);
     899           0 :     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
     900           0 :       *_isTrusted = trust.HasTrustedPeer(false, true, false);
     901           0 :     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
     902           0 :       *_isTrusted = trust.HasTrustedPeer(false, false, true);
     903             :     } else {
     904           0 :       return NS_ERROR_FAILURE;
     905             :     }
     906             :   } /* user: ignore */
     907           0 :   return NS_OK;
     908             : }
     909             : 
     910             : 
     911             : NS_IMETHODIMP
     912           0 : nsNSSCertificateDB::ImportCertsFromFile(nsIFile* aFile, uint32_t aType)
     913             : {
     914           0 :   nsNSSShutDownPreventionLock locker;
     915           0 :   if (isAlreadyShutDown()) {
     916           0 :     return NS_ERROR_NOT_AVAILABLE;
     917             :   }
     918             : 
     919           0 :   NS_ENSURE_ARG(aFile);
     920           0 :   switch (aType) {
     921             :     case nsIX509Cert::CA_CERT:
     922             :     case nsIX509Cert::EMAIL_CERT:
     923             :       // good
     924           0 :       break;
     925             : 
     926             :     default:
     927             :       // not supported (yet)
     928           0 :       return NS_ERROR_FAILURE;
     929             :   }
     930             : 
     931           0 :   PRFileDesc* fd = nullptr;
     932           0 :   nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
     933           0 :   if (NS_FAILED(rv)) {
     934           0 :     return rv;
     935             :   }
     936           0 :   if (!fd) {
     937           0 :     return NS_ERROR_FAILURE;
     938             :   }
     939             : 
     940             :   PRFileInfo fileInfo;
     941           0 :   if (PR_GetOpenFileInfo(fd, &fileInfo) != PR_SUCCESS) {
     942           0 :     return NS_ERROR_FAILURE;
     943             :   }
     944             : 
     945           0 :   auto buf = MakeUnique<unsigned char[]>(fileInfo.size);
     946           0 :   int32_t bytesObtained = PR_Read(fd, buf.get(), fileInfo.size);
     947           0 :   PR_Close(fd);
     948             : 
     949           0 :   if (bytesObtained != fileInfo.size) {
     950           0 :     return NS_ERROR_FAILURE;
     951             :   }
     952             : 
     953           0 :   nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
     954             : 
     955           0 :   switch (aType) {
     956             :     case nsIX509Cert::CA_CERT:
     957           0 :       return ImportCertificates(buf.get(), bytesObtained, aType, cxt);
     958             :     case nsIX509Cert::EMAIL_CERT:
     959           0 :       return ImportEmailCertificate(buf.get(), bytesObtained, cxt);
     960             :     default:
     961           0 :       MOZ_ASSERT(false, "Unsupported type should have been filtered out");
     962             :       break;
     963             :   }
     964             : 
     965             :   return NS_ERROR_FAILURE;
     966             : }
     967             : 
     968             : NS_IMETHODIMP
     969           0 : nsNSSCertificateDB::ImportPKCS12File(nsIFile* aFile)
     970             : {
     971           0 :   if (!NS_IsMainThread()) {
     972           0 :     return NS_ERROR_NOT_SAME_THREAD;
     973             :   }
     974           0 :   nsNSSShutDownPreventionLock locker;
     975           0 :   if (isAlreadyShutDown()) {
     976           0 :     return NS_ERROR_NOT_AVAILABLE;
     977             :   }
     978             : 
     979           0 :   NS_ENSURE_ARG(aFile);
     980           0 :   nsPKCS12Blob blob;
     981           0 :   return blob.ImportFromFile(aFile);
     982             : }
     983             : 
     984             : NS_IMETHODIMP
     985           0 : nsNSSCertificateDB::ExportPKCS12File(nsIFile* aFile, uint32_t count,
     986             :                                      nsIX509Cert** certs)
     987             : {
     988           0 :   if (!NS_IsMainThread()) {
     989           0 :     return NS_ERROR_NOT_SAME_THREAD;
     990             :   }
     991           0 :   nsNSSShutDownPreventionLock locker;
     992           0 :   if (isAlreadyShutDown()) {
     993           0 :     return NS_ERROR_NOT_AVAILABLE;
     994             :   }
     995             : 
     996           0 :   NS_ENSURE_ARG(aFile);
     997           0 :   if (count == 0) {
     998           0 :     return NS_OK;
     999             :   }
    1000           0 :   nsPKCS12Blob blob;
    1001           0 :   return blob.ExportToFile(aFile, certs, count);
    1002             : }
    1003             : 
    1004             : NS_IMETHODIMP
    1005           0 : nsNSSCertificateDB::FindCertByEmailAddress(const nsACString& aEmailAddress,
    1006             :                                            nsIX509Cert** _retval)
    1007             : {
    1008           0 :   nsNSSShutDownPreventionLock locker;
    1009           0 :   if (isAlreadyShutDown()) {
    1010           0 :     return NS_ERROR_NOT_AVAILABLE;
    1011             :   }
    1012             : 
    1013           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
    1014           0 :   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
    1015             : 
    1016           0 :   const nsCString& flatEmailAddress = PromiseFlatCString(aEmailAddress);
    1017             :   UniqueCERTCertList certlist(
    1018           0 :     PK11_FindCertsFromEmailAddress(flatEmailAddress.get(), nullptr));
    1019           0 :   if (!certlist)
    1020           0 :     return NS_ERROR_FAILURE;
    1021             : 
    1022             :   // certlist now contains certificates with the right email address,
    1023             :   // but they might not have the correct usage or might even be invalid
    1024             : 
    1025           0 :   if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
    1026           0 :     return NS_ERROR_FAILURE; // no certs found
    1027             : 
    1028             :   CERTCertListNode *node;
    1029             :   // search for a valid certificate
    1030           0 :   for (node = CERT_LIST_HEAD(certlist);
    1031           0 :        !CERT_LIST_END(node, certlist);
    1032           0 :        node = CERT_LIST_NEXT(node)) {
    1033             : 
    1034           0 :     UniqueCERTCertList unusedCertChain;
    1035             :     mozilla::pkix::Result result =
    1036           0 :       certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
    1037             :                                mozilla::pkix::Now(),
    1038             :                                nullptr /*XXX pinarg*/,
    1039             :                                nullptr /*hostname*/,
    1040           0 :                                unusedCertChain);
    1041           0 :     if (result == mozilla::pkix::Success) {
    1042           0 :       break;
    1043             :     }
    1044             :   }
    1045             : 
    1046           0 :   if (CERT_LIST_END(node, certlist)) {
    1047             :     // no valid cert found
    1048           0 :     return NS_ERROR_FAILURE;
    1049             :   }
    1050             : 
    1051             :   // node now contains the first valid certificate with correct usage
    1052           0 :   RefPtr<nsNSSCertificate> nssCert = nsNSSCertificate::Create(node->cert);
    1053           0 :   if (!nssCert)
    1054           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1055             : 
    1056           0 :   nssCert.forget(_retval);
    1057           0 :   return NS_OK;
    1058             : }
    1059             : 
    1060             : NS_IMETHODIMP
    1061           0 : nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64,
    1062             :                                     /*out*/ nsIX509Cert** _retval)
    1063             : {
    1064           0 :   nsNSSShutDownPreventionLock locker;
    1065           0 :   if (isAlreadyShutDown()) {
    1066           0 :     return NS_ERROR_NOT_AVAILABLE;
    1067             :   }
    1068           0 :   if (!_retval) {
    1069           0 :     return NS_ERROR_INVALID_POINTER;
    1070             :   }
    1071             : 
    1072             :   // Base64Decode() doesn't consider a zero length input as an error, and just
    1073             :   // returns the empty string. We don't want this behavior, so the below check
    1074             :   // catches this case.
    1075           0 :   if (base64.Length() < 1) {
    1076           0 :     return NS_ERROR_ILLEGAL_VALUE;
    1077             :   }
    1078             : 
    1079           0 :   nsAutoCString certDER;
    1080           0 :   nsresult rv = Base64Decode(base64, certDER);
    1081           0 :   if (NS_FAILED(rv)) {
    1082           0 :     return rv;
    1083             :   }
    1084             : 
    1085           0 :   return ConstructX509(certDER, _retval);
    1086             : }
    1087             : 
    1088             : NS_IMETHODIMP
    1089           0 : nsNSSCertificateDB::ConstructX509(const nsACString& certDER,
    1090             :                                   nsIX509Cert** _retval)
    1091             : {
    1092           0 :   nsNSSShutDownPreventionLock locker;
    1093           0 :   if (isAlreadyShutDown()) {
    1094           0 :     return NS_ERROR_NOT_AVAILABLE;
    1095             :   }
    1096           0 :   if (NS_WARN_IF(!_retval)) {
    1097           0 :     return NS_ERROR_INVALID_POINTER;
    1098             :   }
    1099             : 
    1100             :   SECItem certData;
    1101           0 :   certData.type = siDERCertBuffer;
    1102           0 :   certData.data = BitwiseCast<unsigned char*, const char*>(certDER.BeginReading());
    1103           0 :   certData.len = certDER.Length();
    1104             : 
    1105             :   UniqueCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
    1106             :                                                      &certData, nullptr,
    1107           0 :                                                      false, true));
    1108           0 :   if (!cert)
    1109           0 :     return (PORT_GetError() == SEC_ERROR_NO_MEMORY)
    1110           0 :       ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE;
    1111             : 
    1112           0 :   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
    1113           0 :   if (!nssCert) {
    1114           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1115             :   }
    1116           0 :   nssCert.forget(_retval);
    1117           0 :   return NS_OK;
    1118             : }
    1119             : 
    1120             : void
    1121           0 : nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
    1122             :                                          nsIInterfaceRequestor* ctx,
    1123             :                                          nsCString &nickname,
    1124             :                                          const nsNSSShutDownPreventionLock &/*proofOfLock*/)
    1125             : {
    1126             :   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
    1127             : 
    1128           0 :   nickname.Truncate();
    1129             : 
    1130             :   nsresult rv;
    1131             :   CK_OBJECT_HANDLE keyHandle;
    1132             : 
    1133           0 :   CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
    1134           0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
    1135           0 :   if (NS_FAILED(rv))
    1136           0 :     return;
    1137             : 
    1138           0 :   nsAutoCString username;
    1139           0 :   UniquePORTString tempCN(CERT_GetCommonName(&cert->subject));
    1140           0 :   if (tempCN) {
    1141           0 :     username = tempCN.get();
    1142             :   }
    1143             : 
    1144           0 :   nsAutoCString caname;
    1145           0 :   UniquePORTString tempIssuerOrg(CERT_GetOrgName(&cert->issuer));
    1146           0 :   if (tempIssuerOrg) {
    1147           0 :     caname = tempIssuerOrg.get();
    1148             :   }
    1149             : 
    1150           0 :   nsAutoString tmpNickFmt;
    1151           0 :   nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
    1152           0 :   NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
    1153             : 
    1154           0 :   nsAutoCString baseName;
    1155           0 :   baseName.AppendPrintf(nickFmt.get(), username.get(), caname.get());
    1156           0 :   if (baseName.IsEmpty()) {
    1157           0 :     return;
    1158             :   }
    1159             : 
    1160           0 :   nickname = baseName;
    1161             : 
    1162             :   /*
    1163             :    * We need to see if the private key exists on a token, if it does
    1164             :    * then we need to check for nicknames that already exist on the smart
    1165             :    * card.
    1166             :    */
    1167           0 :   UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx));
    1168           0 :   if (!slot)
    1169           0 :     return;
    1170             : 
    1171           0 :   if (!PK11_IsInternal(slot.get())) {
    1172           0 :     nsAutoCString tmp;
    1173           0 :     tmp.AppendPrintf("%s:%s", PK11_GetTokenName(slot.get()), baseName.get());
    1174           0 :     if (tmp.IsEmpty()) {
    1175           0 :       nickname.Truncate();
    1176           0 :       return;
    1177             :     }
    1178           0 :     baseName = tmp;
    1179           0 :     nickname = baseName;
    1180             :   }
    1181             : 
    1182           0 :   int count = 1;
    1183             :   while (true) {
    1184           0 :     if ( count > 1 ) {
    1185           0 :       nsAutoCString tmp;
    1186           0 :       tmp.AppendPrintf("%s #%d", baseName.get(), count);
    1187           0 :       if (tmp.IsEmpty()) {
    1188           0 :         nickname.Truncate();
    1189           0 :         return;
    1190             :       }
    1191           0 :       nickname = tmp;
    1192             :     }
    1193             : 
    1194           0 :     UniqueCERTCertificate dummycert;
    1195             : 
    1196           0 :     if (PK11_IsInternal(slot.get())) {
    1197             :       /* look up the nickname to make sure it isn't in use already */
    1198           0 :       dummycert.reset(CERT_FindCertByNickname(defaultcertdb, nickname.get()));
    1199             :     } else {
    1200             :       // Check the cert against others that already live on the smart card.
    1201           0 :       dummycert.reset(PK11_FindCertFromNickname(nickname.get(), ctx));
    1202           0 :       if (dummycert) {
    1203             :         // Make sure the subject names are different.
    1204           0 :         if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
    1205             :         {
    1206             :           /*
    1207             :            * There is another certificate with the same nickname and
    1208             :            * the same subject name on the smart card, so let's use this
    1209             :            * nickname.
    1210             :            */
    1211           0 :           dummycert = nullptr;
    1212             :         }
    1213             :       }
    1214             :     }
    1215           0 :     if (!dummycert) {
    1216           0 :       break;
    1217             :     }
    1218           0 :     count++;
    1219           0 :   }
    1220             : }
    1221             : 
    1222             : NS_IMETHODIMP
    1223           0 : nsNSSCertificateDB::AddCertFromBase64(const nsACString& aBase64,
    1224             :                                       const nsACString& aTrust,
    1225             :                                       nsIX509Cert** addedCertificate)
    1226             : {
    1227           0 :   MOZ_ASSERT(addedCertificate);
    1228           0 :   if (!addedCertificate) {
    1229           0 :     return NS_ERROR_INVALID_ARG;
    1230             :   }
    1231           0 :   *addedCertificate = nullptr;
    1232             : 
    1233           0 :   nsNSSShutDownPreventionLock locker;
    1234           0 :   if (isAlreadyShutDown()) {
    1235           0 :     return NS_ERROR_NOT_AVAILABLE;
    1236             :   }
    1237             : 
    1238           0 :   nsNSSCertTrust trust;
    1239           0 :   if (CERT_DecodeTrustString(trust.GetTrust(), PromiseFlatCString(aTrust).get())
    1240             :         != SECSuccess) {
    1241           0 :     return NS_ERROR_FAILURE;
    1242             :   }
    1243             : 
    1244           0 :   nsCOMPtr<nsIX509Cert> newCert;
    1245           0 :   nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
    1246           0 :   if (NS_FAILED(rv)) {
    1247           0 :     return rv;
    1248             :   }
    1249             : 
    1250           0 :   UniqueCERTCertificate tmpCert(newCert->GetCert());
    1251           0 :   if (!tmpCert) {
    1252           0 :     return NS_ERROR_FAILURE;
    1253             :   }
    1254             : 
    1255             :   // If there's already a certificate that matches this one in the database, we
    1256             :   // still want to set its trust to the given value.
    1257           0 :   if (tmpCert->isperm) {
    1258           0 :     rv = SetCertTrustFromString(newCert, aTrust);
    1259           0 :     if (NS_FAILED(rv)) {
    1260           0 :       return rv;
    1261             :     }
    1262           0 :     newCert.forget(addedCertificate);
    1263           0 :     return NS_OK;
    1264             :   }
    1265             : 
    1266           0 :   UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
    1267             : 
    1268           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get()));
    1269             : 
    1270           0 :   rv = attemptToLogInWithDefaultPassword();
    1271           0 :   if (NS_WARN_IF(rv != NS_OK)) {
    1272           0 :     return rv;
    1273             :   }
    1274             : 
    1275           0 :   UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
    1276           0 :   SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE,
    1277           0 :                                   nickname.get(),
    1278           0 :                                   false); // this parameter is ignored by NSS
    1279           0 :   if (srv != SECSuccess) {
    1280           0 :     return MapSECStatus(srv);
    1281             :   }
    1282             :   // NSS ignores the first argument to CERT_ChangeCertTrust
    1283           0 :   srv = CERT_ChangeCertTrust(nullptr, tmpCert.get(), trust.GetTrust());
    1284           0 :   if (srv != SECSuccess) {
    1285           0 :     return MapSECStatus(srv);
    1286             :   }
    1287           0 :   newCert.forget(addedCertificate);
    1288           0 :   return NS_OK;
    1289             : }
    1290             : 
    1291             : NS_IMETHODIMP
    1292           0 : nsNSSCertificateDB::AddCert(const nsACString& aCertDER,
    1293             :                             const nsACString& aTrust,
    1294             :                             nsIX509Cert** addedCertificate)
    1295             : {
    1296           0 :   nsCString base64;
    1297           0 :   nsresult rv = Base64Encode(aCertDER, base64);
    1298           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1299           0 :   return AddCertFromBase64(base64, aTrust, addedCertificate);
    1300             : }
    1301             : 
    1302             : NS_IMETHODIMP
    1303           0 : nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
    1304             :                                            const nsACString& trustString)
    1305             : {
    1306           0 :   NS_ENSURE_ARG(cert);
    1307             : 
    1308             :   CERTCertTrust trust;
    1309           0 :   SECStatus srv = CERT_DecodeTrustString(&trust,
    1310           0 :                                          PromiseFlatCString(trustString).get());
    1311           0 :   if (srv != SECSuccess) {
    1312           0 :     return MapSECStatus(srv);
    1313             :   }
    1314           0 :   UniqueCERTCertificate nssCert(cert->GetCert());
    1315             : 
    1316           0 :   nsresult rv = attemptToLogInWithDefaultPassword();
    1317           0 :   if (NS_WARN_IF(rv != NS_OK)) {
    1318           0 :     return rv;
    1319             :   }
    1320             : 
    1321           0 :   srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust);
    1322           0 :   return MapSECStatus(srv);
    1323             : }
    1324             : 
    1325             : NS_IMETHODIMP
    1326           0 : nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
    1327             : {
    1328           0 :   nsNSSShutDownPreventionLock locker;
    1329           0 :   if (isAlreadyShutDown()) {
    1330           0 :     return NS_ERROR_NOT_AVAILABLE;
    1331             :   }
    1332             : 
    1333           0 :   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
    1334           0 :   nsCOMPtr<nsIX509CertList> nssCertList;
    1335           0 :   UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx));
    1336             : 
    1337             :   // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
    1338             :   // (returns an empty list)
    1339           0 :   nssCertList = new nsNSSCertList(Move(certList), locker);
    1340             : 
    1341           0 :   nssCertList.forget(_retval);
    1342           0 :   return NS_OK;
    1343             : }
    1344             : 
    1345             : NS_IMETHODIMP
    1346           0 : nsNSSCertificateDB::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
    1347             : {
    1348           0 :   MOZ_ASSERT(NS_IsMainThread());
    1349           0 :   if (!NS_IsMainThread()) {
    1350           0 :     return NS_ERROR_NOT_SAME_THREAD;
    1351             :   }
    1352             : 
    1353           0 :   NS_ENSURE_ARG_POINTER(enterpriseRoots);
    1354             : 
    1355           0 :   nsNSSShutDownPreventionLock locker;
    1356           0 :   if (isAlreadyShutDown()) {
    1357           0 :     return NS_ERROR_NOT_AVAILABLE;
    1358             :   }
    1359             : 
    1360             : #ifdef XP_WIN
    1361             :   nsCOMPtr<nsINSSComponent> psm(do_GetService(PSM_COMPONENT_CONTRACTID));
    1362             :   if (!psm) {
    1363             :     return NS_ERROR_FAILURE;
    1364             :   }
    1365             :   return psm->GetEnterpriseRoots(enterpriseRoots);
    1366             : #else
    1367           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1368             : #endif
    1369             : }
    1370             : 
    1371             : nsresult
    1372           0 : VerifyCertAtTime(nsIX509Cert* aCert,
    1373             :                  int64_t /*SECCertificateUsage*/ aUsage,
    1374             :                  uint32_t aFlags,
    1375             :                  const nsACString& aHostname,
    1376             :                  mozilla::pkix::Time aTime,
    1377             :                  nsIX509CertList** aVerifiedChain,
    1378             :                  bool* aHasEVPolicy,
    1379             :                  int32_t* /*PRErrorCode*/ _retval,
    1380             :                  const nsNSSShutDownPreventionLock& locker)
    1381             : {
    1382           0 :   NS_ENSURE_ARG_POINTER(aCert);
    1383           0 :   NS_ENSURE_ARG_POINTER(aHasEVPolicy);
    1384           0 :   NS_ENSURE_ARG_POINTER(aVerifiedChain);
    1385           0 :   NS_ENSURE_ARG_POINTER(_retval);
    1386             : 
    1387           0 :   *aVerifiedChain = nullptr;
    1388           0 :   *aHasEVPolicy = false;
    1389           0 :   *_retval = PR_UNKNOWN_ERROR;
    1390             : 
    1391           0 :   UniqueCERTCertificate nssCert(aCert->GetCert());
    1392           0 :   if (!nssCert) {
    1393           0 :     return NS_ERROR_INVALID_ARG;
    1394             :   }
    1395             : 
    1396           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
    1397           0 :   NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
    1398             : 
    1399           0 :   UniqueCERTCertList resultChain;
    1400             :   SECOidTag evOidPolicy;
    1401             :   mozilla::pkix::Result result;
    1402             : 
    1403           0 :   if (!aHostname.IsVoid() && aUsage == certificateUsageSSLServer) {
    1404           0 :     result = certVerifier->VerifySSLServerCert(nssCert,
    1405             :                                                nullptr, // stapledOCSPResponse
    1406             :                                                nullptr, // sctsFromTLSExtension
    1407             :                                                aTime,
    1408             :                                                nullptr, // Assume no context
    1409             :                                                aHostname,
    1410             :                                                resultChain,
    1411             :                                                nullptr, // no peerCertChain
    1412             :                                                false, // don't save intermediates
    1413             :                                                aFlags,
    1414           0 :                                                OriginAttributes(),
    1415           0 :                                                &evOidPolicy);
    1416             :   } else {
    1417           0 :     const nsCString& flatHostname = PromiseFlatCString(aHostname);
    1418           0 :     result = certVerifier->VerifyCert(nssCert.get(), aUsage, aTime,
    1419             :                                       nullptr, // Assume no context
    1420           0 :                                       aHostname.IsVoid() ? nullptr
    1421             :                                                          : flatHostname.get(),
    1422             :                                       resultChain,
    1423             :                                       nullptr, // no peerCertChain
    1424             :                                       aFlags,
    1425             :                                       nullptr, // stapledOCSPResponse
    1426             :                                       nullptr, // sctsFromTLSExtension
    1427           0 :                                       OriginAttributes(),
    1428           0 :                                       &evOidPolicy);
    1429             :   }
    1430             : 
    1431           0 :   nsCOMPtr<nsIX509CertList> nssCertList;
    1432             :   // This adopts the list
    1433           0 :   nssCertList = new nsNSSCertList(Move(resultChain), locker);
    1434           0 :   NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE);
    1435             : 
    1436           0 :   *_retval = mozilla::pkix::MapResultToPRErrorCode(result);
    1437           0 :   if (result == mozilla::pkix::Success && evOidPolicy != SEC_OID_UNKNOWN) {
    1438           0 :     *aHasEVPolicy = true;
    1439             :   }
    1440           0 :   nssCertList.forget(aVerifiedChain);
    1441             : 
    1442           0 :   return NS_OK;
    1443             : }
    1444             : 
    1445             : NS_IMETHODIMP
    1446           0 : nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
    1447             :                                   int64_t /*SECCertificateUsage*/ aUsage,
    1448             :                                   uint32_t aFlags,
    1449             :                                   const nsACString& aHostname,
    1450             :                                   nsIX509CertList** aVerifiedChain,
    1451             :                                   bool* aHasEVPolicy,
    1452             :                                   int32_t* /*PRErrorCode*/ _retval)
    1453             : {
    1454           0 :   nsNSSShutDownPreventionLock locker;
    1455           0 :   if (isAlreadyShutDown()) {
    1456           0 :     return NS_ERROR_NOT_AVAILABLE;
    1457             :   }
    1458             : 
    1459           0 :   return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname,
    1460             :                             mozilla::pkix::Now(),
    1461           0 :                             aVerifiedChain, aHasEVPolicy, _retval, locker);
    1462             : }
    1463             : 
    1464             : NS_IMETHODIMP
    1465           0 : nsNSSCertificateDB::VerifyCertAtTime(nsIX509Cert* aCert,
    1466             :                                      int64_t /*SECCertificateUsage*/ aUsage,
    1467             :                                      uint32_t aFlags,
    1468             :                                      const nsACString& aHostname,
    1469             :                                      uint64_t aTime,
    1470             :                                      nsIX509CertList** aVerifiedChain,
    1471             :                                      bool* aHasEVPolicy,
    1472             :                                      int32_t* /*PRErrorCode*/ _retval)
    1473             : {
    1474           0 :   nsNSSShutDownPreventionLock locker;
    1475           0 :   if (isAlreadyShutDown()) {
    1476           0 :     return NS_ERROR_NOT_AVAILABLE;
    1477             :   }
    1478             : 
    1479           0 :   return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname,
    1480             :                             mozilla::pkix::TimeFromEpochInSeconds(aTime),
    1481           0 :                             aVerifiedChain, aHasEVPolicy, _retval, locker);
    1482             : }
    1483             : 
    1484           0 : class VerifyCertAtTimeTask final : public CryptoTask
    1485             : {
    1486             : public:
    1487           0 :   VerifyCertAtTimeTask(nsIX509Cert* aCert, int64_t aUsage, uint32_t aFlags,
    1488             :                        const nsACString& aHostname, uint64_t aTime,
    1489             :                        nsICertVerificationCallback* aCallback)
    1490           0 :     : mCert(aCert)
    1491             :     , mUsage(aUsage)
    1492             :     , mFlags(aFlags)
    1493             :     , mHostname(aHostname)
    1494             :     , mTime(aTime)
    1495             :     , mCallback(new nsMainThreadPtrHolder<nsICertVerificationCallback>(
    1496           0 :         "nsICertVerificationCallback", aCallback))
    1497             :     , mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE)
    1498             :     , mVerifiedCertList(nullptr)
    1499           0 :     , mHasEVPolicy(false)
    1500             :   {
    1501           0 :   }
    1502             : 
    1503             : private:
    1504           0 :   virtual nsresult CalculateResult() override
    1505             :   {
    1506           0 :     nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID);
    1507           0 :     if (!certDB) {
    1508           0 :       return NS_ERROR_FAILURE;
    1509             :     }
    1510           0 :     return certDB->VerifyCertAtTime(mCert, mUsage, mFlags, mHostname, mTime,
    1511           0 :                                     getter_AddRefs(mVerifiedCertList),
    1512           0 :                                     &mHasEVPolicy, &mPRErrorCode);
    1513             :   }
    1514             : 
    1515             :   // No NSS resources are directly held, so there is nothing to release.
    1516           0 :   virtual void ReleaseNSSResources() override { }
    1517             : 
    1518           0 :   virtual void CallCallback(nsresult rv) override
    1519             :   {
    1520           0 :     if (NS_FAILED(rv)) {
    1521           0 :       Unused << mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE,
    1522           0 :                                               nullptr, false);
    1523             :     } else {
    1524           0 :       Unused << mCallback->VerifyCertFinished(mPRErrorCode, mVerifiedCertList,
    1525           0 :                                               mHasEVPolicy);
    1526             :     }
    1527           0 :   }
    1528             : 
    1529             :   nsCOMPtr<nsIX509Cert> mCert;
    1530             :   int64_t mUsage;
    1531             :   uint32_t mFlags;
    1532             :   nsCString mHostname;
    1533             :   uint64_t mTime;
    1534             :   nsMainThreadPtrHandle<nsICertVerificationCallback> mCallback;
    1535             :   int32_t mPRErrorCode;
    1536             :   nsCOMPtr<nsIX509CertList> mVerifiedCertList;
    1537             :   bool mHasEVPolicy;
    1538             : };
    1539             : 
    1540             : NS_IMETHODIMP
    1541           0 : nsNSSCertificateDB::AsyncVerifyCertAtTime(nsIX509Cert* aCert,
    1542             :                                           int64_t /*SECCertificateUsage*/ aUsage,
    1543             :                                           uint32_t aFlags,
    1544             :                                           const nsACString& aHostname,
    1545             :                                           uint64_t aTime,
    1546             :                                           nsICertVerificationCallback* aCallback)
    1547             : {
    1548           0 :   nsNSSShutDownPreventionLock locker;
    1549           0 :   if (isAlreadyShutDown()) {
    1550           0 :     return NS_ERROR_NOT_AVAILABLE;
    1551             :   }
    1552             :   RefPtr<VerifyCertAtTimeTask> task(new VerifyCertAtTimeTask(aCert, aUsage,
    1553             :                                                              aFlags, aHostname,
    1554           0 :                                                              aTime, aCallback));
    1555           0 :   return task->Dispatch("VerifyCert");
    1556             : }
    1557             : 
    1558             : NS_IMETHODIMP
    1559           0 : nsNSSCertificateDB::ClearOCSPCache()
    1560             : {
    1561           0 :   nsNSSShutDownPreventionLock locker;
    1562           0 :   if (isAlreadyShutDown()) {
    1563           0 :     return NS_ERROR_NOT_AVAILABLE;
    1564             :   }
    1565             : 
    1566           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
    1567           0 :   NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
    1568           0 :   certVerifier->ClearOCSPCache();
    1569           0 :   return NS_OK;
    1570           9 : }

Generated by: LCOV version 1.13