security/manager/ssl/src/nsNSSCertificateDB.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 // XXX: This must be done prior to including cert.h (directly or indirectly).
     6 // CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm, but it is
     7 // only exported so PSM can use it for this specific purpose.
     8 #define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
    10 #include "nsNSSComponent.h"
    11 #include "nsNSSCertificateDB.h"
    13 #include "CertVerifier.h"
    14 #include "ExtendedValidation.h"
    15 #include "NSSCertDBTrustDomain.h"
    16 #include "pkix/pkixtypes.h"
    17 #include "nsNSSComponent.h"
    18 #include "mozilla/Base64.h"
    19 #include "nsCOMPtr.h"
    20 #include "nsNSSCertificate.h"
    21 #include "nsNSSHelper.h"
    22 #include "nsNSSCertHelper.h"
    23 #include "nsNSSCertCache.h"
    24 #include "nsCRT.h"
    25 #include "nsICertificateDialogs.h"
    26 #include "nsNSSCertTrust.h"
    27 #include "nsIFile.h"
    28 #include "nsPKCS12Blob.h"
    29 #include "nsPK11TokenDB.h"
    30 #include "nsReadableUtils.h"
    31 #include "nsIMutableArray.h"
    32 #include "nsArrayUtils.h"
    33 #include "nsNSSShutDown.h"
    34 #include "nsIPrefService.h"
    35 #include "nsIPrefBranch.h"
    36 #include "nsComponentManagerUtils.h"
    37 #include "nsIPrompt.h"
    38 #include "nsThreadUtils.h"
    39 #include "nsIObserverService.h"
    40 #include "nsRecentBadCerts.h"
    41 #include "SharedSSLState.h"
    43 #include "nspr.h"
    44 #include "certdb.h"
    45 #include "secerr.h"
    46 #include "nssb64.h"
    47 #include "secasn1.h"
    48 #include "secder.h"
    49 #include "ssl.h"
    50 #include "ocsp.h"
    51 #include "plbase64.h"
    53 using namespace mozilla;
    54 using namespace mozilla::psm;
    55 using mozilla::psm::SharedSSLState;
    57 #ifdef PR_LOGGING
    58 extern PRLogModuleInfo* gPIPNSSLog;
    59 #endif
    61 static nsresult
    62 attemptToLogInWithDefaultPassword()
    63 {
    64 #ifdef NSS_DISABLE_DBM
    65   // The SQL NSS DB requires the user to be authenticated to set certificate
    66   // trust settings, even if the user's password is empty. To maintain
    67   // compatibility with the DBM-based database, try to log in with the
    68   // default empty password. This will allow, at least, tests that need to
    69   // change certificate trust to pass on all platforms. TODO(bug 978120): Do
    70   // proper testing and/or implement a better solution so that we are confident
    71   // that this does the correct thing outside of xpcshell tests too.
    72   ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    73   if (!slot) {
    74     return MapSECStatus(SECFailure);
    75   }
    76   if (PK11_NeedUserInit(slot)) {
    77     // Ignore the return value. Presumably PK11_InitPin will fail if the user
    78     // has a non-default password.
    79     (void) PK11_InitPin(slot, nullptr, nullptr);
    80   }
    81 #endif
    83   return NS_OK;
    84 }
    86 NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
    88 nsNSSCertificateDB::nsNSSCertificateDB()
    89 : mBadCertsLock("nsNSSCertificateDB::mBadCertsLock")
    90 {
    91   SharedSSLState::NoteCertDBServiceInstantiated();
    92 }
    94 nsNSSCertificateDB::~nsNSSCertificateDB()
    95 {
    96   nsNSSShutDownPreventionLock locker;
    97   if (isAlreadyShutDown()) {
    98     return;
    99   }
   101   shutdown(calledFromObject);
   102 }
   104 NS_IMETHODIMP
   105 nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken,
   106                                       const nsAString &nickname,
   107                                       nsIX509Cert **_rvCert)
   108 {
   109   NS_ENSURE_ARG_POINTER(_rvCert);
   110   *_rvCert = nullptr;
   112   nsNSSShutDownPreventionLock locker;
   113   if (isAlreadyShutDown()) {
   114     return NS_ERROR_NOT_AVAILABLE;
   115   }
   116   mozilla::pkix::ScopedCERTCertificate cert;
   117   char *asciiname = nullptr;
   118   NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname);
   119   asciiname = const_cast<char*>(aUtf8Nickname.get());
   120   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
   121   cert = PK11_FindCertFromNickname(asciiname, nullptr);
   122   if (!cert) {
   123     cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
   124   }
   125   if (cert) {
   126     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));
   127     nsCOMPtr<nsIX509Cert> pCert = nsNSSCertificate::Create(cert.get());
   128     if (pCert) {
   129       pCert.forget(_rvCert);
   130       return NS_OK;
   131     }
   132   }
   133   return NS_ERROR_FAILURE;
   134 }
   136 NS_IMETHODIMP 
   137 nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken,
   138                                    nsIX509Cert **_cert)
   139 {
   140   NS_ENSURE_ARG_POINTER(aDBkey);
   141   NS_ENSURE_ARG(aDBkey[0]);
   142   NS_ENSURE_ARG_POINTER(_cert);
   143   *_cert = nullptr;
   145   nsNSSShutDownPreventionLock locker;
   146   if (isAlreadyShutDown()) {
   147     return NS_ERROR_NOT_AVAILABLE;
   148   }
   150   SECItem keyItem = {siBuffer, nullptr, 0};
   151   SECItem *dummy;
   152   CERTIssuerAndSN issuerSN;
   153   //unsigned long moduleID,slotID;
   155   dummy = NSSBase64_DecodeBuffer(nullptr, &keyItem, aDBkey,
   156                                  (uint32_t)strlen(aDBkey)); 
   157   if (!dummy || keyItem.len < NS_NSS_LONG*4) {
   158     PR_FREEIF(keyItem.data);
   159     return NS_ERROR_INVALID_ARG;
   160   }
   162   mozilla::pkix::ScopedCERTCertificate cert;
   163   // someday maybe we can speed up the search using the moduleID and slotID
   164   // moduleID = NS_NSS_GET_LONG(keyItem.data);
   165   // slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
   167   // build the issuer/SN structure
   168   issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
   169   issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
   170   if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0
   171       || issuerSN.serialNumber.len + issuerSN.derIssuer.len
   172          != keyItem.len - NS_NSS_LONG*4) {
   173     PR_FREEIF(keyItem.data);
   174     return NS_ERROR_INVALID_ARG;
   175   }
   176   issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
   177   issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
   178                                               issuerSN.serialNumber.len];
   180   cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
   181   PR_FREEIF(keyItem.data);
   182   if (cert) {
   183     nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
   184     if (!nssCert)
   185       return NS_ERROR_OUT_OF_MEMORY;
   186     nssCert.forget(_cert);
   187   }
   188   return NS_OK;
   189 }
   191 NS_IMETHODIMP 
   192 nsNSSCertificateDB::FindCertNicknames(nsISupports *aToken, 
   193                                      uint32_t      aType,
   194                                      uint32_t     *_count,
   195                                      char16_t  ***_certNames)
   196 {
   197   nsNSSShutDownPreventionLock locker;
   198   if (isAlreadyShutDown()) {
   199     return NS_ERROR_NOT_AVAILABLE;
   200   }
   202   nsresult rv = NS_ERROR_FAILURE;
   203   /*
   204    * obtain the cert list from NSS
   205    */
   206   mozilla::pkix::ScopedCERTCertList certList;
   207   certList = PK11_ListCerts(PK11CertListUnique, nullptr);
   208   if (!certList)
   209     goto cleanup;
   210   /*
   211    * get list of cert names from list of certs
   212    * XXX also cull the list (NSS only distinguishes based on user/non-user
   213    */
   214   getCertNames(certList.get(), aType, _count, _certNames, locker);
   215   rv = NS_OK;
   216   /*
   217    * finish up
   218    */
   219 cleanup:
   220   return rv;
   221 }
   223 SECStatus
   224 collect_certs(void *arg, SECItem **certs, int numcerts)
   225 {
   226   CERTDERCerts *collectArgs;
   227   SECItem *cert;
   228   SECStatus rv;
   230   collectArgs = (CERTDERCerts *)arg;
   232   collectArgs->numcerts = numcerts;
   233   collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
   234                                            sizeof(SECItem) * numcerts);
   235   if (!collectArgs->rawCerts)
   236     return(SECFailure);
   238   cert = collectArgs->rawCerts;
   240   while ( numcerts-- ) {
   241     rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
   242     if ( rv == SECFailure )
   243       return(SECFailure);
   244     cert++;
   245     certs++;
   246   }
   248   return (SECSuccess);
   249 }
   251 CERTDERCerts*
   252 nsNSSCertificateDB::getCertsFromPackage(PLArenaPool *arena, uint8_t *data, 
   253                                         uint32_t length,
   254                                         const nsNSSShutDownPreventionLock &/*proofOfLock*/)
   255 {
   256   CERTDERCerts *collectArgs = 
   257                (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
   258   if (!collectArgs)
   259     return nullptr;
   261   collectArgs->arena = arena;
   262   SECStatus sec_rv = CERT_DecodeCertPackage(reinterpret_cast<char *>(data), 
   263                                             length, collect_certs, 
   264                                             (void *)collectArgs);
   265   if (sec_rv != SECSuccess)
   266     return nullptr;
   268   return collectArgs;
   269 }
   271 nsresult
   272 nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs,
   273                                          nsIInterfaceRequestor *ctx,
   274                                          const nsNSSShutDownPreventionLock &proofOfLock)
   275 {
   276   // First thing we have to do is figure out which certificate we're 
   277   // gonna present to the user.  The CA may have sent down a list of 
   278   // certs which may or may not be a chained list of certs.  Until
   279   // the day we can design some solid UI for the general case, we'll
   280   // code to the > 90% case.  That case is where a CA sends down a
   281   // list that is a hierarchy whose root is either the first or 
   282   // the last cert.  What we're gonna do is compare the first 
   283   // 2 entries, if the second was signed by the first, we assume
   284   // the root cert is the first cert and display it.  Otherwise,
   285   // we compare the last 2 entries, if the second to last cert was
   286   // signed by the last cert, then we assume the last cert is the
   287   // root and display it.
   289   uint32_t numCerts;
   291   x509Certs->GetLength(&numCerts);
   292   NS_ASSERTION(numCerts > 0, "Didn't get any certs to import.");
   293   if (numCerts == 0)
   294     return NS_OK; // Nothing to import, so nothing to do.
   296   nsCOMPtr<nsIX509Cert> certToShow;
   297   nsCOMPtr<nsISupports> isupports;
   298   uint32_t selCertIndex;
   299   if (numCerts == 1) {
   300     // There's only one cert, so let's show it.
   301     selCertIndex = 0;
   302     certToShow = do_QueryElementAt(x509Certs, selCertIndex);
   303   } else {
   304     nsCOMPtr<nsIX509Cert> cert0;    // first cert
   305     nsCOMPtr<nsIX509Cert> cert1;    // second cert
   306     nsCOMPtr<nsIX509Cert> certn_2;  // second to last cert
   307     nsCOMPtr<nsIX509Cert> certn_1;  // last cert
   309     cert0 = do_QueryElementAt(x509Certs, 0);
   310     cert1 = do_QueryElementAt(x509Certs, 1);
   311     certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
   312     certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
   314     nsXPIDLString cert0SubjectName;
   315     nsXPIDLString cert1IssuerName;
   316     nsXPIDLString certn_2IssuerName;
   317     nsXPIDLString certn_1SubjectName;
   319     cert0->GetSubjectName(cert0SubjectName);
   320     cert1->GetIssuerName(cert1IssuerName);
   321     certn_2->GetIssuerName(certn_2IssuerName);
   322     certn_1->GetSubjectName(certn_1SubjectName);
   324     if (cert1IssuerName.Equals(cert0SubjectName)) {
   325       // In this case, the first cert in the list signed the second,
   326       // so the first cert is the root.  Let's display it. 
   327       selCertIndex = 0;
   328       certToShow = cert0;
   329     } else 
   330     if (certn_2IssuerName.Equals(certn_1SubjectName)) { 
   331       // In this case the last cert has signed the second to last cert.
   332       // The last cert is the root, so let's display it.
   333       selCertIndex = numCerts-1;
   334       certToShow = certn_1;
   335     } else {
   336       // It's not a chain, so let's just show the first one in the 
   337       // downloaded list.
   338       selCertIndex = 0;
   339       certToShow = cert0;
   340     }
   341   }
   343   if (!certToShow)
   344     return NS_ERROR_FAILURE;
   346   nsCOMPtr<nsICertificateDialogs> dialogs;
   347   nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), 
   348                                 NS_GET_IID(nsICertificateDialogs),
   349                                 NS_CERTIFICATEDIALOGS_CONTRACTID);
   351   if (NS_FAILED(rv))
   352     return rv;
   354   SECItem der;
   355   rv=certToShow->GetRawDER(&der.len, (uint8_t **)&der.data);
   357   if (NS_FAILED(rv))
   358     return rv;
   360   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
   361   mozilla::pkix::ScopedCERTCertificate tmpCert;
   362   CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
   363   tmpCert = CERT_FindCertByDERCert(certdb, &der);
   364   if (!tmpCert) {
   365     tmpCert = CERT_NewTempCertificate(certdb, &der,
   366                                       nullptr, false, true);
   367   }
   368   nsMemory::Free(der.data);
   369   der.data = nullptr;
   370   der.len = 0;
   372   if (!tmpCert) {
   373     NS_ERROR("Couldn't create cert from DER blob");
   374     return NS_ERROR_FAILURE;
   375   }
   377   if (!CERT_IsCACert(tmpCert.get(), nullptr)) {
   378     DisplayCertificateAlert(ctx, "NotACACert", certToShow, proofOfLock);
   379     return NS_ERROR_FAILURE;
   380   }
   382   if (tmpCert->isperm) {
   383     DisplayCertificateAlert(ctx, "CaCertExists", certToShow, proofOfLock);
   384     return NS_ERROR_FAILURE;
   385   }
   387   uint32_t trustBits;
   388   bool allows;
   389   rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
   390   if (NS_FAILED(rv))
   391     return rv;
   393   if (!allows)
   394     return NS_ERROR_NOT_AVAILABLE;
   396   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));
   397   nsXPIDLCString nickname;
   398   nickname.Adopt(CERT_MakeCANickname(tmpCert.get()));
   400   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
   402   nsNSSCertTrust trust;
   403   trust.SetValidCA();
   404   trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
   405                    !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL),
   406                    !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN));
   408   SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(),
   409                                            const_cast<char*>(nickname.get()),
   410                                            trust.GetTrust());
   412   if (srv != SECSuccess)
   413     return NS_ERROR_FAILURE;
   415   // Import additional delivered certificates that can be verified.
   417   // build a CertList for filtering
   418   mozilla::pkix::ScopedCERTCertList certList(CERT_NewCertList());
   419   if (!certList) {
   420     return NS_ERROR_FAILURE;
   421   }
   423   // get all remaining certs into temp store
   425   for (uint32_t i=0; i<numCerts; i++) {
   426     if (i == selCertIndex) {
   427       // we already processed that one
   428       continue;
   429     }
   431     certToShow = do_QueryElementAt(x509Certs, i);
   432     certToShow->GetRawDER(&der.len, (uint8_t **)&der.data);
   434     CERTCertificate *tmpCert2 = 
   435       CERT_NewTempCertificate(certdb, &der, nullptr, false, true);
   437     nsMemory::Free(der.data);
   438     der.data = nullptr;
   439     der.len = 0;
   441     if (!tmpCert2) {
   442       NS_ERROR("Couldn't create temp cert from DER blob");
   443       continue;  // Let's try to import the rest of 'em
   444     }
   446     CERT_AddCertToListTail(certList.get(), tmpCert2);
   447   }
   449   return ImportValidCACertsInList(certList.get(), ctx, proofOfLock);
   450 }
   452 /*
   453  *  [noscript] void importCertificates(in charPtr data, in unsigned long length,
   454  *                                     in unsigned long type, 
   455  *                                     in nsIInterfaceRequestor ctx);
   456  */
   457 NS_IMETHODIMP 
   458 nsNSSCertificateDB::ImportCertificates(uint8_t * data, uint32_t length, 
   459                                        uint32_t type, 
   460                                        nsIInterfaceRequestor *ctx)
   462 {
   463   nsNSSShutDownPreventionLock locker;
   464   if (isAlreadyShutDown()) {
   465     return NS_ERROR_NOT_AVAILABLE;
   466   }
   468   nsresult nsrv;
   470   PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   471   if (!arena)
   472     return NS_ERROR_OUT_OF_MEMORY;
   474   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
   475   if (!certCollection) {
   476     PORT_FreeArena(arena, false);
   477     return NS_ERROR_FAILURE;
   478   }
   479   nsCOMPtr<nsIMutableArray> array =
   480     do_CreateInstance(NS_ARRAY_CONTRACTID, &nsrv);
   481   if (NS_FAILED(nsrv)) {
   482     PORT_FreeArena(arena, false);
   483     return nsrv;
   484   }
   486   // Now let's create some certs to work with
   487   nsCOMPtr<nsIX509Cert> x509Cert;
   488   nsNSSCertificate *nssCert;
   489   SECItem *currItem;
   490   for (int i=0; i<certCollection->numcerts; i++) {
   491      currItem = &certCollection->rawCerts[i];
   492      nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len);
   493      if (!nssCert)
   494        return NS_ERROR_FAILURE;
   495      x509Cert = do_QueryInterface((nsIX509Cert*)nssCert);
   496      array->AppendElement(x509Cert, false);
   497   }
   498   switch (type) {
   499   case nsIX509Cert::CA_CERT:
   500     nsrv = handleCACertDownload(array, ctx, locker);
   501     break;
   502   default:
   503     // We only deal with import CA certs in this method currently.
   504      nsrv = NS_ERROR_FAILURE;
   505      break;
   506   }  
   507   PORT_FreeArena(arena, false);
   508   return nsrv;
   509 }
   511 static 
   512 SECStatus 
   513 ImportCertsIntoPermanentStorage(
   514   const mozilla::pkix::ScopedCERTCertList& certChain,
   515   const SECCertUsage usage, const PRBool caOnly)
   516 {
   517   CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
   519   int chainLen = 0;
   520   for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
   521        !CERT_LIST_END(chainNode, certChain);
   522        chainNode = CERT_LIST_NEXT(chainNode)) {
   523     chainLen++;
   524   }
   526   SECItem **rawArray;
   527   rawArray = (SECItem **) PORT_Alloc(chainLen * sizeof(SECItem *));
   528   if (!rawArray) {
   529     return SECFailure;
   530   }
   532   int i = 0;
   533   for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
   534        !CERT_LIST_END(chainNode, certChain);
   535        chainNode = CERT_LIST_NEXT(chainNode), i++) {
   536     rawArray[i] = &chainNode->cert->derCert;
   537   }
   538   SECStatus srv = CERT_ImportCerts(certdb, usage, chainLen, rawArray,
   539                                    nullptr, true, caOnly, nullptr);
   541   PORT_Free(rawArray);
   542   return srv;
   543 } 
   546 /*
   547  *  [noscript] void importEmailCertificates(in charPtr data, in unsigned long length,
   548  *                                     in nsIInterfaceRequestor ctx);
   549  */
   550 NS_IMETHODIMP
   551 nsNSSCertificateDB::ImportEmailCertificate(uint8_t * data, uint32_t length, 
   552                                        nsIInterfaceRequestor *ctx)
   554 {
   555   nsNSSShutDownPreventionLock locker;
   556   if (isAlreadyShutDown()) {
   557     return NS_ERROR_NOT_AVAILABLE;
   558   }
   560   SECStatus srv = SECFailure;
   561   nsresult nsrv = NS_OK;
   562   CERTCertDBHandle *certdb;
   563   CERTCertificate **certArray = nullptr;
   564   mozilla::pkix::ScopedCERTCertList certList;
   565   CERTCertListNode *node;
   566   SECItem **rawArray;
   567   int numcerts;
   568   int i;
   570   PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   571   if (!arena)
   572     return NS_ERROR_OUT_OF_MEMORY;
   574   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
   575   if (!certCollection) {
   576     PORT_FreeArena(arena, false);
   577     return NS_ERROR_FAILURE;
   578   }
   580   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
   581   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
   583   certdb = CERT_GetDefaultCertDB();
   584   const PRTime now = PR_Now();
   586   numcerts = certCollection->numcerts;
   588   rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
   589   if ( !rawArray ) {
   590     nsrv = NS_ERROR_FAILURE;
   591     goto loser;
   592   }
   594   for (i=0; i < numcerts; i++) {
   595     rawArray[i] = &certCollection->rawCerts[i];
   596   }
   598   srv = CERT_ImportCerts(certdb, certUsageEmailRecipient, numcerts, rawArray,
   599                          &certArray, false, false, nullptr);
   601   PORT_Free(rawArray);
   602   rawArray = nullptr;
   604   if (srv != SECSuccess) {
   605     nsrv = NS_ERROR_FAILURE;
   606     goto loser;
   607   }
   609   // build a CertList for filtering
   610   certList = CERT_NewCertList();
   611   if (!certList) {
   612     nsrv = NS_ERROR_FAILURE;
   613     goto loser;
   614   }
   615   for (i=0; i < numcerts; i++) {
   616     CERTCertificate *cert = certArray[i];
   617     if (cert)
   618       cert = CERT_DupCertificate(cert);
   619     if (cert)
   620       CERT_AddCertToListTail(certList.get(), cert);
   621   }
   623   /* go down the remaining list of certs and verify that they have
   624    * valid chains, then import them.
   625    */
   627   for (node = CERT_LIST_HEAD(certList);
   628        !CERT_LIST_END(node,certList);
   629        node = CERT_LIST_NEXT(node)) {
   631     if (!node->cert) {
   632       continue;
   633     }
   635     mozilla::pkix::ScopedCERTCertList certChain;
   637     SECStatus rv = certVerifier->VerifyCert(node->cert,
   638                                             certificateUsageEmailRecipient,
   639                                             now, ctx, nullptr, 0,
   640                                             nullptr, &certChain);
   642     if (rv != SECSuccess) {
   643       nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
   644       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker);
   645       continue;
   646     }
   647     rv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient,
   648                                          false);
   649     if (rv != SECSuccess) {
   650       goto loser;
   651     } 
   652     CERT_SaveSMimeProfile(node->cert, nullptr, nullptr);
   654   }
   656 loser:
   657   if (certArray) {
   658     CERT_DestroyCertArray(certArray, numcerts);
   659   }
   660   if (arena) 
   661     PORT_FreeArena(arena, true);
   662   return nsrv;
   663 }
   665 NS_IMETHODIMP
   666 nsNSSCertificateDB::ImportServerCertificate(uint8_t * data, uint32_t length, 
   667                                             nsIInterfaceRequestor *ctx)
   669 {
   670   nsNSSShutDownPreventionLock locker;
   671   if (isAlreadyShutDown()) {
   672     return NS_ERROR_NOT_AVAILABLE;
   673   }
   675   SECStatus srv = SECFailure;
   676   nsresult nsrv = NS_OK;
   677   mozilla::pkix::ScopedCERTCertificate cert;
   678   SECItem **rawCerts = nullptr;
   679   int numcerts;
   680   int i;
   681   nsNSSCertTrust trust;
   682   char *serverNickname = nullptr;
   684   PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   685   if (!arena)
   686     return NS_ERROR_OUT_OF_MEMORY;
   688   CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
   689   if (!certCollection) {
   690     PORT_FreeArena(arena, false);
   691     return NS_ERROR_FAILURE;
   692   }
   693   cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts,
   694                                  nullptr, false, true);
   695   if (!cert) {
   696     nsrv = NS_ERROR_FAILURE;
   697     goto loser;
   698   }
   699   numcerts = certCollection->numcerts;
   700   rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
   701   if ( !rawCerts ) {
   702     nsrv = NS_ERROR_FAILURE;
   703     goto loser;
   704   }
   706   for ( i = 0; i < numcerts; i++ ) {
   707     rawCerts[i] = &certCollection->rawCerts[i];
   708   }
   710   serverNickname = DefaultServerNicknameForCert(cert.get());
   711   srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer,
   712              numcerts, rawCerts, nullptr, true, false,
   713              serverNickname);
   714   PR_FREEIF(serverNickname);
   715   if ( srv != SECSuccess ) {
   716     nsrv = NS_ERROR_FAILURE;
   717     goto loser;
   718   }
   720   trust.SetValidServerPeer();
   721   srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert.get(),
   722                              trust.GetTrust());
   723   if ( srv != SECSuccess ) {
   724     nsrv = NS_ERROR_FAILURE;
   725     goto loser;
   726   }
   727 loser:
   728   PORT_Free(rawCerts);
   729   if (arena) 
   730     PORT_FreeArena(arena, true);
   731   return nsrv;
   732 }
   734 nsresult
   735 nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx,  const nsNSSShutDownPreventionLock &proofOfLock)
   736 {
   737   ScopedCERTCertList certList;
   738   SECItem **rawArray;
   740   // build a CertList for filtering
   741   certList = CERT_NewCertList();
   742   if (!certList) {
   743     return NS_ERROR_FAILURE;
   744   }
   746   // get all certs into temp store
   747   SECStatus srv = SECFailure;
   748   CERTCertificate **certArray = nullptr;
   750   rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts);
   751   if ( !rawArray ) {
   752     return NS_ERROR_FAILURE;
   753   }
   755   for (int i=0; i < numCACerts; i++) {
   756     rawArray[i] = &CACerts[i];
   757   }
   759   srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray, 
   760                          &certArray, false, true, nullptr);
   762   PORT_Free(rawArray);
   763   rawArray = nullptr;
   765   if (srv != SECSuccess) {
   766     return NS_ERROR_FAILURE;
   767   }
   769   for (int i2=0; i2 < numCACerts; i2++) {
   770     CERTCertificate *cacert = certArray[i2];
   771     if (cacert)
   772       cacert = CERT_DupCertificate(cacert);
   773     if (cacert)
   774       CERT_AddCertToListTail(certList, cacert);
   775   }
   777   CERT_DestroyCertArray(certArray, numCACerts);
   779   return ImportValidCACertsInList(certList, ctx, proofOfLock);
   780 }
   782 nsresult
   783 nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx,
   784                                              const nsNSSShutDownPreventionLock &proofOfLock)
   785 {
   786   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
   787   if (!certVerifier)
   788     return NS_ERROR_UNEXPECTED;
   790   /* filter out the certs we don't want */
   791   SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, true);
   792   if (srv != SECSuccess) {
   793     return NS_ERROR_FAILURE;
   794   }
   796   /* go down the remaining list of certs and verify that they have
   797    * valid chains, if yes, then import.
   798    */
   799   CERTCertListNode *node;
   801   for (node = CERT_LIST_HEAD(certList);
   802        !CERT_LIST_END(node,certList);
   803        node = CERT_LIST_NEXT(node)) {
   804     mozilla::pkix::ScopedCERTCertList certChain;
   805     SECStatus rv = certVerifier->VerifyCert(node->cert,
   806                                             certificateUsageVerifyCA,
   807                                             PR_Now(), ctx, nullptr, 0, nullptr,
   808                                             &certChain);
   809     if (rv != SECSuccess) {
   810       nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
   811       DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock);
   812       continue;
   813     }
   815     rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true);
   816     if (rv != SECSuccess) {
   817       return NS_ERROR_FAILURE;
   818     }
   819   }
   821   return NS_OK;
   822 }
   824 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx, 
   825                                                  const char *stringID, 
   826                                                  nsIX509Cert *certToShow,
   827                                                  const nsNSSShutDownPreventionLock &/*proofOfLock*/)
   828 {
   829   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   831   if (!NS_IsMainThread()) {
   832     NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread");
   833     return;
   834   }
   836   nsPSMUITracker tracker;
   837   if (!tracker.isUIForbidden()) {
   839     nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx;
   840     if (!my_ctx)
   841       my_ctx = new PipUIContext();
   843     // This shall be replaced by embedding ovverridable prompts
   844     // as discussed in bug 310446, and should make use of certToShow.
   846     nsresult rv;
   847     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   848     if (NS_SUCCEEDED(rv)) {
   849       nsAutoString tmpMessage;
   850       nssComponent->GetPIPNSSBundleString(stringID, tmpMessage);
   852       nsCOMPtr<nsIPrompt> prompt (do_GetInterface(my_ctx));
   853       if (!prompt)
   854         return;
   856       prompt->Alert(nullptr, tmpMessage.get());
   857     }
   858   }
   859 }
   862 NS_IMETHODIMP 
   863 nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx)
   864 {
   865   if (!NS_IsMainThread()) {
   866     NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
   867     return NS_ERROR_NOT_SAME_THREAD;
   868   }
   870   nsNSSShutDownPreventionLock locker;
   871   if (isAlreadyShutDown()) {
   872     return NS_ERROR_NOT_AVAILABLE;
   873   }
   875   ScopedPK11SlotInfo slot;
   876   nsAutoCString nickname;
   877   nsresult rv = NS_ERROR_FAILURE;
   878   int numCACerts;
   879   SECItem *CACerts;
   880   CERTDERCerts * collectArgs;
   881   PLArenaPool *arena;
   882   mozilla::pkix::ScopedCERTCertificate cert;
   884   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   885   if (!arena) {
   886     goto loser;
   887   }
   889   collectArgs = getCertsFromPackage(arena, data, length, locker);
   890   if (!collectArgs) {
   891     goto loser;
   892   }
   894   cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
   895                                  nullptr, false, true);
   896   if (!cert) {
   897     goto loser;
   898   }
   900   slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx);
   901   if (!slot) {
   902     nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
   903     DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker);
   904     goto loser;
   905   }
   906   slot = nullptr;
   908   /* pick a nickname for the cert */
   909   if (cert->nickname) {
   910 	/* sigh, we need a call to look up other certs with this subject and
   911 	 * identify nicknames from them. We can no longer walk down internal
   912 	 * database structures  rjr */
   913   	nickname = cert->nickname;
   914   }
   915   else {
   916     get_default_nickname(cert.get(), ctx, nickname, locker);
   917   }
   919   /* user wants to import the cert */
   920   {
   921     char *cast_const_away = const_cast<char*>(nickname.get());
   922     slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx);
   923   }
   924   if (!slot) {
   925     goto loser;
   926   }
   927   slot = nullptr;
   929   {
   930     nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
   931     DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker);
   932   }
   933   rv = NS_OK;
   935   numCACerts = collectArgs->numcerts - 1;
   936   if (numCACerts) {
   937     CACerts = collectArgs->rawCerts+1;
   938     rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker);
   939   }
   941 loser:
   942   if (arena) {
   943     PORT_FreeArena(arena, false);
   944   }
   945   return rv;
   946 }
   948 /*
   949  * void deleteCertificate(in nsIX509Cert aCert);
   950  */
   951 NS_IMETHODIMP 
   952 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
   953 {
   954   nsNSSShutDownPreventionLock locker;
   955   if (isAlreadyShutDown()) {
   956     return NS_ERROR_NOT_AVAILABLE;
   957   }
   958   nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
   959   mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert());
   960   if (!cert) return NS_ERROR_FAILURE;
   961   SECStatus srv = SECSuccess;
   963   uint32_t certType;
   964   nssCert->GetCertType(&certType);
   965   if (NS_FAILED(nssCert->MarkForPermDeletion()))
   966   {
   967     return NS_ERROR_FAILURE;
   968   }
   970   if (cert->slot && certType != nsIX509Cert::USER_CERT) {
   971     // To delete a cert of a slot (builtin, most likely), mark it as
   972     // completely untrusted.  This way we keep a copy cached in the
   973     // local database, and next time we try to load it off of the 
   974     // external token/slot, we'll know not to trust it.  We don't 
   975     // want to do that with user certs, because a user may  re-store
   976     // the cert onto the card again at which point we *will* want to 
   977     // trust that cert if it chains up properly.
   978     nsNSSCertTrust trust(0, 0, 0);
   979     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
   980                                cert.get(), trust.GetTrust());
   981   }
   982   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));
   983   return (srv) ? NS_ERROR_FAILURE : NS_OK;
   984 }
   986 /*
   987  * void setCertTrust(in nsIX509Cert cert,
   988  *                   in unsigned long type,
   989  *                   in unsigned long trust);
   990  */
   991 NS_IMETHODIMP 
   992 nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert, 
   993                                  uint32_t type,
   994                                  uint32_t trusted)
   995 {
   996   nsNSSShutDownPreventionLock locker;
   997   if (isAlreadyShutDown()) {
   998     return NS_ERROR_NOT_AVAILABLE;
   999   }
  1000   nsNSSCertTrust trust;
  1001   nsresult rv;
  1002   nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert, &rv);
  1003   if (!pipCert) {
  1004     return rv;
  1006   mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
  1008   rv = attemptToLogInWithDefaultPassword();
  1009   if (NS_WARN_IF(rv != NS_OK)) {
  1010     return rv;
  1013   SECStatus srv;
  1014   if (type == nsIX509Cert::CA_CERT) {
  1015     // always start with untrusted and move up
  1016     trust.SetValidCA();
  1017     trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
  1018                      !!(trusted & nsIX509CertDB::TRUSTED_EMAIL),
  1019                      !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN));
  1020     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
  1021                                nsscert.get(),
  1022                                trust.GetTrust());
  1023   } else if (type == nsIX509Cert::SERVER_CERT) {
  1024     // always start with untrusted and move up
  1025     trust.SetValidPeer();
  1026     trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
  1027     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
  1028                                nsscert.get(),
  1029                                trust.GetTrust());
  1030   } else if (type == nsIX509Cert::EMAIL_CERT) {
  1031     // always start with untrusted and move up
  1032     trust.SetValidPeer();
  1033     trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0);
  1034     srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), 
  1035                                nsscert.get(),
  1036                                trust.GetTrust());
  1037   } else {
  1038     // ignore user certs
  1039     return NS_OK;
  1041   return MapSECStatus(srv);
  1044 NS_IMETHODIMP 
  1045 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert, 
  1046                                   uint32_t certType,
  1047                                   uint32_t trustType,
  1048                                   bool *_isTrusted)
  1050   NS_ENSURE_ARG_POINTER(_isTrusted);
  1051   *_isTrusted = false;
  1053   nsNSSShutDownPreventionLock locker;
  1054   if (isAlreadyShutDown()) {
  1055     return NS_ERROR_NOT_AVAILABLE;
  1057   SECStatus srv;
  1058   nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
  1059   mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
  1060   CERTCertTrust nsstrust;
  1061   srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
  1062   if (srv != SECSuccess)
  1063     return NS_ERROR_FAILURE;
  1065   nsNSSCertTrust trust(&nsstrust);
  1066   if (certType == nsIX509Cert::CA_CERT) {
  1067     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
  1068       *_isTrusted = trust.HasTrustedCA(true, false, false);
  1069     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
  1070       *_isTrusted = trust.HasTrustedCA(false, true, false);
  1071     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
  1072       *_isTrusted = trust.HasTrustedCA(false, false, true);
  1073     } else {
  1074       return NS_ERROR_FAILURE;
  1076   } else if (certType == nsIX509Cert::SERVER_CERT) {
  1077     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
  1078       *_isTrusted = trust.HasTrustedPeer(true, false, false);
  1079     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
  1080       *_isTrusted = trust.HasTrustedPeer(false, true, false);
  1081     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
  1082       *_isTrusted = trust.HasTrustedPeer(false, false, true);
  1083     } else {
  1084       return NS_ERROR_FAILURE;
  1086   } else if (certType == nsIX509Cert::EMAIL_CERT) {
  1087     if (trustType & nsIX509CertDB::TRUSTED_SSL) {
  1088       *_isTrusted = trust.HasTrustedPeer(true, false, false);
  1089     } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
  1090       *_isTrusted = trust.HasTrustedPeer(false, true, false);
  1091     } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
  1092       *_isTrusted = trust.HasTrustedPeer(false, false, true);
  1093     } else {
  1094       return NS_ERROR_FAILURE;
  1096   } /* user: ignore */
  1097   return NS_OK;
  1101 NS_IMETHODIMP 
  1102 nsNSSCertificateDB::ImportCertsFromFile(nsISupports *aToken, 
  1103                                         nsIFile *aFile,
  1104                                         uint32_t aType)
  1106   nsNSSShutDownPreventionLock locker;
  1107   if (isAlreadyShutDown()) {
  1108     return NS_ERROR_NOT_AVAILABLE;
  1111   NS_ENSURE_ARG(aFile);
  1112   switch (aType) {
  1113     case nsIX509Cert::CA_CERT:
  1114     case nsIX509Cert::EMAIL_CERT:
  1115     case nsIX509Cert::SERVER_CERT:
  1116       // good
  1117       break;
  1119     default:
  1120       // not supported (yet)
  1121       return NS_ERROR_FAILURE;
  1124   nsresult rv;
  1125   PRFileDesc *fd = nullptr;
  1127   rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
  1129   if (NS_FAILED(rv))
  1130     return rv;
  1132   if (!fd)
  1133     return NS_ERROR_FAILURE;
  1135   PRFileInfo file_info;
  1136   if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &file_info))
  1137     return NS_ERROR_FAILURE;
  1139   unsigned char *buf = new unsigned char[file_info.size];
  1141   int32_t bytes_obtained = PR_Read(fd, buf, file_info.size);
  1142   PR_Close(fd);
  1144   if (bytes_obtained != file_info.size)
  1145     rv = NS_ERROR_FAILURE;
  1146   else {
  1147 	  nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
  1149     switch (aType) {
  1150       case nsIX509Cert::CA_CERT:
  1151         rv = ImportCertificates(buf, bytes_obtained, aType, cxt);
  1152         break;
  1154       case nsIX509Cert::SERVER_CERT:
  1155         rv = ImportServerCertificate(buf, bytes_obtained, cxt);
  1156         break;
  1158       case nsIX509Cert::EMAIL_CERT:
  1159         rv = ImportEmailCertificate(buf, bytes_obtained, cxt);
  1160         break;
  1162       default:
  1163         break;
  1167   delete [] buf;
  1168   return rv;  
  1171 NS_IMETHODIMP 
  1172 nsNSSCertificateDB::ImportPKCS12File(nsISupports *aToken, 
  1173                                      nsIFile *aFile)
  1175   nsNSSShutDownPreventionLock locker;
  1176   if (isAlreadyShutDown()) {
  1177     return NS_ERROR_NOT_AVAILABLE;
  1180   NS_ENSURE_ARG(aFile);
  1181   nsPKCS12Blob blob;
  1182   nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken);
  1183   if (token) {
  1184     blob.SetToken(token);
  1186   return blob.ImportFromFile(aFile);
  1189 NS_IMETHODIMP 
  1190 nsNSSCertificateDB::ExportPKCS12File(nsISupports     *aToken, 
  1191                                      nsIFile          *aFile,
  1192                                      uint32_t          count,
  1193                                      nsIX509Cert     **certs)
  1194                                      //const char16_t **aCertNames)
  1196   nsNSSShutDownPreventionLock locker;
  1197   if (isAlreadyShutDown()) {
  1198     return NS_ERROR_NOT_AVAILABLE;
  1201   NS_ENSURE_ARG(aFile);
  1202   nsPKCS12Blob blob;
  1203   if (count == 0) return NS_OK;
  1204   nsCOMPtr<nsIPK11Token> localRef;
  1205   if (!aToken) {
  1206     ScopedPK11SlotInfo keySlot(PK11_GetInternalKeySlot());
  1207     NS_ASSERTION(keySlot,"Failed to get the internal key slot");
  1208     localRef = new nsPK11Token(keySlot);
  1210   else {
  1211     localRef = do_QueryInterface(aToken);
  1213   blob.SetToken(localRef);
  1214   //blob.LoadCerts(aCertNames, count);
  1215   //return blob.ExportToFile(aFile);
  1216   return blob.ExportToFile(aFile, certs, count);
  1219 /*
  1220  * NSS Helper Routines (private to nsNSSCertificateDB)
  1221  */
  1223 #define DELIM '\001'
  1225 /*
  1226  * GetSortedNameList
  1228  * Converts a CERTCertList to a list of certificate names
  1229  */
  1230 void
  1231 nsNSSCertificateDB::getCertNames(CERTCertList *certList,
  1232                                  uint32_t      type, 
  1233                                  uint32_t     *_count,
  1234                                  char16_t  ***_certNames,
  1235                                  const nsNSSShutDownPreventionLock &/*proofOfLock*/)
  1237   CERTCertListNode *node;
  1238   uint32_t numcerts = 0, i=0;
  1239   char16_t **tmpArray = nullptr;
  1241   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type));
  1242   for (node = CERT_LIST_HEAD(certList);
  1243        !CERT_LIST_END(node, certList);
  1244        node = CERT_LIST_NEXT(node)) {
  1245     if (getCertType(node->cert) == type) {
  1246       numcerts++;
  1249   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts));
  1250   int nc = (numcerts == 0) ? 1 : numcerts;
  1251   tmpArray = (char16_t **)nsMemory::Alloc(sizeof(char16_t *) * nc);
  1252   if (numcerts == 0) goto finish;
  1253   for (node = CERT_LIST_HEAD(certList);
  1254        !CERT_LIST_END(node, certList);
  1255        node = CERT_LIST_NEXT(node)) {
  1256     if (getCertType(node->cert) == type) {
  1257       nsNSSCertificate pipCert(node->cert);
  1258       char *dbkey = nullptr;
  1259       char *namestr = nullptr;
  1260       nsAutoString certstr;
  1261       pipCert.GetDbKey(&dbkey);
  1262       nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey);
  1263       PR_FREEIF(dbkey);
  1264       if (type == nsIX509Cert::EMAIL_CERT) {
  1265         namestr = node->cert->emailAddr;
  1266       } else {
  1267         namestr = node->cert->nickname;
  1268         if (namestr) {
  1269           char *sc = strchr(namestr, ':');
  1270           if (sc) *sc = DELIM;
  1273       nsAutoString certname = NS_ConvertASCIItoUTF16(namestr ? namestr : "");
  1274       certstr.Append(char16_t(DELIM));
  1275       certstr += certname;
  1276       certstr.Append(char16_t(DELIM));
  1277       certstr += keystr;
  1278       tmpArray[i++] = ToNewUnicode(certstr);
  1281 finish:
  1282   *_count = numcerts;
  1283   *_certNames = tmpArray;
  1286 /* nsIX509Cert getDefaultEmailEncryptionCert (); */
  1287 NS_IMETHODIMP
  1288 nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval)
  1290   NS_ENSURE_ARG_POINTER(_retval);
  1291   *_retval = nullptr;
  1293   if (aNickname.IsEmpty())
  1294     return NS_OK;
  1296   nsNSSShutDownPreventionLock locker;
  1297   if (isAlreadyShutDown()) {
  1298     return NS_ERROR_NOT_AVAILABLE;
  1301   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
  1302   char *asciiname = nullptr;
  1303   NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
  1304   asciiname = const_cast<char*>(aUtf8Nickname.get());
  1306   /* Find a good cert in the user's database */
  1307   mozilla::pkix::ScopedCERTCertificate cert;
  1308   cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, 
  1309            certUsageEmailRecipient, true, ctx);
  1310   if (!cert) {
  1311     return NS_OK;
  1314   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
  1315   if (!nssCert) {
  1316     return NS_ERROR_OUT_OF_MEMORY;
  1318   nssCert.forget(_retval);
  1319   return NS_OK;
  1322 /* nsIX509Cert getDefaultEmailSigningCert (); */
  1323 NS_IMETHODIMP
  1324 nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval)
  1326   NS_ENSURE_ARG_POINTER(_retval);
  1327   *_retval = nullptr;
  1329   if (aNickname.IsEmpty())
  1330     return NS_OK;
  1332   nsNSSShutDownPreventionLock locker;
  1333   if (isAlreadyShutDown()) {
  1334     return NS_ERROR_NOT_AVAILABLE;
  1337   mozilla::pkix::ScopedCERTCertificate cert;
  1338   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
  1339   char *asciiname = nullptr;
  1340   NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
  1341   asciiname = const_cast<char*>(aUtf8Nickname.get());
  1343   /* Find a good cert in the user's database */
  1344   cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname, 
  1345            certUsageEmailSigner, true, ctx);
  1346   if (!cert) {
  1347     return NS_OK;
  1350   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
  1351   if (!nssCert) {
  1352     return NS_ERROR_OUT_OF_MEMORY;
  1354   nssCert.forget(_retval);
  1355   return NS_OK;
  1358 NS_IMETHODIMP
  1359 nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval)
  1361   nsNSSShutDownPreventionLock locker;
  1362   if (isAlreadyShutDown()) {
  1363     return NS_ERROR_NOT_AVAILABLE;
  1366   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  1367   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
  1369   ScopedCERTCertList certlist(
  1370       PK11_FindCertsFromEmailAddress(aEmailAddress, nullptr));
  1371   if (!certlist)
  1372     return NS_ERROR_FAILURE;  
  1374   // certlist now contains certificates with the right email address,
  1375   // but they might not have the correct usage or might even be invalid
  1377   if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
  1378     return NS_ERROR_FAILURE; // no certs found
  1380   CERTCertListNode *node;
  1381   // search for a valid certificate
  1382   for (node = CERT_LIST_HEAD(certlist);
  1383        !CERT_LIST_END(node, certlist);
  1384        node = CERT_LIST_NEXT(node)) {
  1386     SECStatus srv = certVerifier->VerifyCert(node->cert,
  1387                                              certificateUsageEmailRecipient,
  1388                                              PR_Now(), nullptr /*XXX pinarg*/,
  1389                                              nullptr /*hostname*/);
  1390     if (srv == SECSuccess) {
  1391       break;
  1395   if (CERT_LIST_END(node, certlist)) {
  1396     // no valid cert found
  1397     return NS_ERROR_FAILURE;
  1400   // node now contains the first valid certificate with correct usage 
  1401   nsNSSCertificate *nssCert = nsNSSCertificate::Create(node->cert);
  1402   if (!nssCert)
  1403     return NS_ERROR_OUT_OF_MEMORY;
  1405   NS_ADDREF(nssCert);
  1406   *_retval = static_cast<nsIX509Cert*>(nssCert);
  1407   return NS_OK;
  1410 /* nsIX509Cert constructX509FromBase64 (in string base64); */
  1411 NS_IMETHODIMP
  1412 nsNSSCertificateDB::ConstructX509FromBase64(const char *base64,
  1413                                             nsIX509Cert **_retval)
  1415   nsNSSShutDownPreventionLock locker;
  1416   if (isAlreadyShutDown()) {
  1417     return NS_ERROR_NOT_AVAILABLE;
  1419   if (NS_WARN_IF(!_retval)) {
  1420     return NS_ERROR_INVALID_POINTER;
  1423   // sure would be nice to have a smart pointer class for PL_ allocations
  1424   // unfortunately, we cannot distinguish out-of-memory from bad-input here
  1425   uint32_t len = base64 ? strlen(base64) : 0;
  1426   char *certDER = PL_Base64Decode(base64, len, nullptr);
  1427   if (!certDER)
  1428     return NS_ERROR_ILLEGAL_VALUE;
  1429   if (!*certDER) {
  1430     PL_strfree(certDER);
  1431     return NS_ERROR_ILLEGAL_VALUE;
  1434   // If we get to this point, we know we had well-formed base64 input;
  1435   // therefore the input string cannot have been less than two
  1436   // characters long.  Compute the unpadded length of the decoded data.
  1437   uint32_t lengthDER = (len * 3) / 4;
  1438   if (base64[len-1] == '=') {
  1439     lengthDER--;
  1440     if (base64[len-2] == '=')
  1441       lengthDER--;
  1444   nsresult rv = ConstructX509(certDER, lengthDER, _retval);
  1445   PL_strfree(certDER);
  1446   return rv;
  1449 /* nsIX509Cert constructX509 (in string certDER, unsigned long len); */
  1450 NS_IMETHODIMP
  1451 nsNSSCertificateDB::ConstructX509(const char* certDER,
  1452                                   uint32_t lengthDER,
  1453                                   nsIX509Cert** _retval)
  1455   nsNSSShutDownPreventionLock locker;
  1456   if (isAlreadyShutDown()) {
  1457     return NS_ERROR_NOT_AVAILABLE;
  1459   if (NS_WARN_IF(!_retval)) {
  1460     return NS_ERROR_INVALID_POINTER;
  1463   SECItem secitem_cert;
  1464   secitem_cert.type = siDERCertBuffer;
  1465   secitem_cert.data = (unsigned char*)certDER;
  1466   secitem_cert.len = lengthDER;
  1468   mozilla::pkix::ScopedCERTCertificate cert;
  1469   cert =
  1470     CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert,
  1471                             nullptr, false, true);
  1472   if (!cert)
  1473     return (PORT_GetError() == SEC_ERROR_NO_MEMORY)
  1474       ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE;
  1476   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
  1477   if (!nssCert) {
  1478     return NS_ERROR_OUT_OF_MEMORY;
  1480   nssCert.forget(_retval);
  1481   return NS_OK;
  1484 void
  1485 nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, 
  1486                                          nsIInterfaceRequestor* ctx,
  1487                                          nsCString &nickname,
  1488                                          const nsNSSShutDownPreventionLock &/*proofOfLock*/)
  1490   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1492   nickname.Truncate();
  1494   nsresult rv;
  1495   CK_OBJECT_HANDLE keyHandle;
  1497   CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
  1498   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1499   if (NS_FAILED(rv))
  1500     return;
  1502   nsAutoCString username;
  1503   char *temp_un = CERT_GetCommonName(&cert->subject);
  1504   if (temp_un) {
  1505     username = temp_un;
  1506     PORT_Free(temp_un);
  1507     temp_un = nullptr;
  1510   nsAutoCString caname;
  1511   char *temp_ca = CERT_GetOrgName(&cert->issuer);
  1512   if (temp_ca) {
  1513     caname = temp_ca;
  1514     PORT_Free(temp_ca);
  1515     temp_ca = nullptr;
  1518   nsAutoString tmpNickFmt;
  1519   nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
  1520   NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
  1522   nsAutoCString baseName;
  1523   char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get());
  1524   if (!temp_nn) {
  1525     return;
  1526   } else {
  1527     baseName = temp_nn;
  1528     PR_smprintf_free(temp_nn);
  1529     temp_nn = nullptr;
  1532   nickname = baseName;
  1534   /*
  1535    * We need to see if the private key exists on a token, if it does
  1536    * then we need to check for nicknames that already exist on the smart
  1537    * card.
  1538    */
  1539   ScopedPK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx));
  1540   if (!slot)
  1541     return;
  1543   if (!PK11_IsInternal(slot)) {
  1544     char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get());
  1545     if (!tmp) {
  1546       nickname.Truncate();
  1547       return;
  1549     baseName = tmp;
  1550     PR_smprintf_free(tmp);
  1552     nickname = baseName;
  1555   int count = 1;
  1556   while (true) {
  1557     if ( count > 1 ) {
  1558       char *tmp = PR_smprintf("%s #%d", baseName.get(), count);
  1559       if (!tmp) {
  1560         nickname.Truncate();
  1561         return;
  1563       nickname = tmp;
  1564       PR_smprintf_free(tmp);
  1567     mozilla::pkix::ScopedCERTCertificate dummycert;
  1569     if (PK11_IsInternal(slot)) {
  1570       /* look up the nickname to make sure it isn't in use already */
  1571       dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get());
  1573     } else {
  1574       /*
  1575        * Check the cert against others that already live on the smart 
  1576        * card.
  1577        */
  1578       dummycert = PK11_FindCertFromNickname(nickname.get(), ctx);
  1579       if (dummycert) {
  1580 	/*
  1581 	 * Make sure the subject names are different.
  1582 	 */ 
  1583 	if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
  1585 	  /*
  1586 	   * There is another certificate with the same nickname and
  1587 	   * the same subject name on the smart card, so let's use this
  1588 	   * nickname.
  1589 	   */
  1590 	  dummycert = nullptr;
  1594     if (!dummycert) 
  1595       break;
  1597     count++;
  1601 NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName)
  1603   NS_ENSURE_ARG_POINTER(aBase64);
  1604   nsCOMPtr <nsIX509Cert> newCert;
  1606   nsNSSShutDownPreventionLock locker;
  1607   if (isAlreadyShutDown()) {
  1608     return NS_ERROR_NOT_AVAILABLE;
  1611   nsNSSCertTrust trust;
  1613   // need to calculate the trust bits from the aTrust string.
  1614   SECStatus stat = CERT_DecodeTrustString(trust.GetTrust(),
  1615     /* this is const, but not declared that way */(char *) aTrust);
  1616   NS_ENSURE_STATE(stat == SECSuccess); // if bad trust passed in, return error.
  1619   nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
  1620   NS_ENSURE_SUCCESS(rv, rv);
  1622   SECItem der;
  1623   rv = newCert->GetRawDER(&der.len, (uint8_t **)&der.data);
  1624   NS_ENSURE_SUCCESS(rv, rv);
  1626   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
  1627   CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
  1628   mozilla::pkix::ScopedCERTCertificate tmpCert(CERT_FindCertByDERCert(certdb, &der));
  1629   if (!tmpCert)
  1630     tmpCert = CERT_NewTempCertificate(certdb, &der,
  1631                                       nullptr, false, true);
  1632   nsMemory::Free(der.data);
  1633   der.data = nullptr;
  1634   der.len = 0;
  1636   if (!tmpCert) {
  1637     NS_ERROR("Couldn't create cert from DER blob");
  1638     return MapSECStatus(SECFailure);
  1641   if (tmpCert->isperm) {
  1642     return NS_OK;
  1645   nsXPIDLCString nickname;
  1646   nickname.Adopt(CERT_MakeCANickname(tmpCert.get()));
  1648   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
  1650   rv = attemptToLogInWithDefaultPassword();
  1651   if (NS_WARN_IF(rv != NS_OK)) {
  1652     return rv;
  1655   SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(),
  1656                                            const_cast<char*>(nickname.get()),
  1657                                            trust.GetTrust());
  1658   return MapSECStatus(srv);
  1661 NS_IMETHODIMP
  1662 nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust,
  1663                             const char *aName)
  1665   nsCString base64;
  1666   nsresult rv = Base64Encode(aCertDER, base64);
  1667   NS_ENSURE_SUCCESS(rv, rv);
  1668   return AddCertFromBase64(base64.get(), aTrust, aName);
  1671 NS_IMETHODIMP
  1672 nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert,
  1673                                            const char* trustString)
  1675   CERTCertTrust trust;
  1677   // need to calculate the trust bits from the aTrust string.
  1678   SECStatus srv = CERT_DecodeTrustString(&trust,
  1679                                          const_cast<char *>(trustString));
  1680   if (srv != SECSuccess) {
  1681     return MapSECStatus(SECFailure);
  1683   mozilla::pkix::ScopedCERTCertificate nssCert(cert->GetCert());
  1685   nsresult rv = attemptToLogInWithDefaultPassword();
  1686   if (NS_WARN_IF(rv != NS_OK)) {
  1687     return rv;
  1690   srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust);
  1691   return MapSECStatus(srv);
  1694 NS_IMETHODIMP 
  1695 nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
  1697   nsNSSShutDownPreventionLock locker;
  1698   if (isAlreadyShutDown()) {
  1699     return NS_ERROR_NOT_AVAILABLE;
  1702   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
  1703   nsCOMPtr<nsIX509CertList> nssCertList;
  1704   mozilla::pkix::ScopedCERTCertList certList(
  1705     PK11_ListCerts(PK11CertListUnique, ctx));
  1707   // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
  1708   // (returns an empty list) 
  1709   nssCertList = new nsNSSCertList(certList, locker);
  1711   *_retval = nssCertList;
  1712   NS_ADDREF(*_retval);
  1713   return NS_OK;
  1716 NS_IMETHODIMP
  1717 nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result)
  1719   nsNSSShutDownPreventionLock locker;
  1720   if (isAlreadyShutDown()) {
  1721     return NS_ERROR_NOT_AVAILABLE;
  1724   MutexAutoLock lock(mBadCertsLock);
  1725   if (isPrivate) {
  1726     if (!mPrivateRecentBadCerts) {
  1727       mPrivateRecentBadCerts = new nsRecentBadCerts;
  1729     NS_ADDREF(*result = mPrivateRecentBadCerts);
  1730   } else {
  1731     if (!mPublicRecentBadCerts) {
  1732       mPublicRecentBadCerts = new nsRecentBadCerts;
  1734     NS_ADDREF(*result = mPublicRecentBadCerts);
  1736   return NS_OK;
  1739 NS_IMETHODIMP
  1740 nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
  1741                                   int64_t /*SECCertificateUsage*/ aUsage,
  1742                                   uint32_t aFlags,
  1743                                   nsIX509CertList** verifiedChain,
  1744                                   bool* aHasEVPolicy,
  1745                                   int32_t* /*PRErrorCode*/ _retval )
  1747   NS_ENSURE_ARG_POINTER(aCert);
  1748   NS_ENSURE_ARG_POINTER(aHasEVPolicy);
  1749   NS_ENSURE_ARG_POINTER(verifiedChain);
  1750   NS_ENSURE_ARG_POINTER(_retval);
  1752   *verifiedChain = nullptr;
  1753   *aHasEVPolicy = false;
  1754   *_retval = PR_UNKNOWN_ERROR;
  1756   nsNSSShutDownPreventionLock locker;
  1757   if (isAlreadyShutDown()) {
  1758     return NS_ERROR_NOT_AVAILABLE;
  1761 #ifndef MOZ_NO_EV_CERTS
  1762   EnsureIdentityInfoLoaded();
  1763 #endif
  1765   nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert);
  1766   if (!x509Cert) {
  1767     return NS_ERROR_INVALID_ARG;
  1769   ScopedCERTCertificate nssCert(x509Cert->GetCert());
  1771   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  1772   NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
  1774   mozilla::pkix::ScopedCERTCertList resultChain;
  1775   SECOidTag evOidPolicy;
  1776   SECStatus srv;
  1778   srv = certVerifier->VerifyCert(nssCert,
  1779                                  aUsage, PR_Now(),
  1780                                  nullptr, // Assume no context
  1781                                  nullptr, // hostname
  1782                                  aFlags,
  1783                                  nullptr, // stapledOCSPResponse
  1784                                  &resultChain,
  1785                                  &evOidPolicy);
  1787   PRErrorCode error = PR_GetError();
  1789   nsCOMPtr<nsIX509CertList> nssCertList;
  1790   // This adopts the list
  1791   nssCertList = new nsNSSCertList(resultChain, locker);
  1792   NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE);
  1794   if (srv == SECSuccess) {
  1795     if (evOidPolicy != SEC_OID_UNKNOWN) {
  1796       *aHasEVPolicy = true;
  1798     *_retval = 0;
  1799   } else {
  1800     NS_ENSURE_TRUE(evOidPolicy == SEC_OID_UNKNOWN, NS_ERROR_FAILURE);
  1801     NS_ENSURE_TRUE(error != 0, NS_ERROR_FAILURE);
  1802     *_retval = error;
  1804   nssCertList.forget(verifiedChain);
  1806   return NS_OK;
  1809 NS_IMETHODIMP
  1810 nsNSSCertificateDB::ClearOCSPCache()
  1812   nsNSSShutDownPreventionLock locker;
  1813   if (isAlreadyShutDown()) {
  1814     return NS_ERROR_NOT_AVAILABLE;
  1817   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  1818   NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
  1819   if (certVerifier->mImplementation == CertVerifier::mozillapkix) {
  1820     certVerifier->ClearOCSPCache();
  1821   } else {
  1822     SECStatus srv = CERT_ClearOCSPCache();
  1823     if (srv != SECSuccess) {
  1824       return MapSECStatus(srv);
  1828   return NS_OK;

mercurial