123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsNSSCertificateDB.h"
- #include "CertVerifier.h"
- #include "CryptoTask.h"
- #include "ExtendedValidation.h"
- #include "NSSCertDBTrustDomain.h"
- #include "SharedSSLState.h"
- #include "certdb.h"
- #include "mozilla/Base64.h"
- #include "mozilla/Casting.h"
- #include "mozilla/Unused.h"
- #include "nsArray.h"
- #include "nsArrayUtils.h"
- #include "nsCOMPtr.h"
- #include "nsCRT.h"
- #include "nsComponentManagerUtils.h"
- #include "nsICertificateDialogs.h"
- #include "nsIFile.h"
- #include "nsIMutableArray.h"
- #include "nsIObserverService.h"
- #include "nsIPrefBranch.h"
- #include "nsIPrefService.h"
- #include "nsIPrompt.h"
- #include "nsNSSCertHelper.h"
- #include "nsNSSCertTrust.h"
- #include "nsNSSCertificate.h"
- #include "nsNSSComponent.h"
- #include "nsNSSHelper.h"
- #include "nsNSSShutDown.h"
- #include "nsPK11TokenDB.h"
- #include "nsPKCS12Blob.h"
- #include "nsPromiseFlatString.h"
- #include "nsProxyRelease.h"
- #include "nsReadableUtils.h"
- #include "nsThreadUtils.h"
- #include "nspr.h"
- #include "pkix/Time.h"
- #include "pkix/pkixnss.h"
- #include "pkix/pkixtypes.h"
- #include "secasn1.h"
- #include "secder.h"
- #include "secerr.h"
- #include "ssl.h"
- #ifdef XP_WIN
- #include <winsock.h> // for ntohl
- #endif
- using namespace mozilla;
- using namespace mozilla::psm;
- using mozilla::psm::SharedSSLState;
- extern LazyLogModule gPIPNSSLog;
- static nsresult
- attemptToLogInWithDefaultPassword()
- {
- #ifdef NSS_DISABLE_DBM
- // The SQL NSS DB requires the user to be authenticated to set certificate
- // trust settings, even if the user's password is empty. To maintain
- // compatibility with the DBM-based database, try to log in with the
- // default empty password. This will allow, at least, tests that need to
- // change certificate trust to pass on all platforms. TODO(bug 978120): Do
- // proper testing and/or implement a better solution so that we are confident
- // that this does the correct thing outside of xpcshell tests too.
- UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
- if (!slot) {
- return MapSECStatus(SECFailure);
- }
- if (PK11_NeedUserInit(slot.get())) {
- // Ignore the return value. Presumably PK11_InitPin will fail if the user
- // has a non-default password.
- Unused << PK11_InitPin(slot.get(), nullptr, nullptr);
- }
- #endif
- return NS_OK;
- }
- NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
- nsNSSCertificateDB::~nsNSSCertificateDB()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- shutdown(ShutdownCalledFrom::Object);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::FindCertByNickname(const nsAString& nickname,
- nsIX509Cert** _rvCert)
- {
- NS_ENSURE_ARG_POINTER(_rvCert);
- *_rvCert = nullptr;
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- char *asciiname = nullptr;
- NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname);
- asciiname = const_cast<char*>(aUtf8Nickname.get());
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Getting \"%s\"\n", asciiname));
- UniqueCERTCertificate cert(PK11_FindCertFromNickname(asciiname, nullptr));
- if (!cert) {
- cert.reset(CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname));
- }
- if (cert) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("got it\n"));
- nsCOMPtr<nsIX509Cert> pCert = nsNSSCertificate::Create(cert.get());
- if (pCert) {
- pCert.forget(_rvCert);
- return NS_OK;
- }
- }
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::FindCertByDBKey(const char* aDBKey,nsIX509Cert** _cert)
- {
- NS_ENSURE_ARG_POINTER(aDBKey);
- NS_ENSURE_ARG(aDBKey[0]);
- NS_ENSURE_ARG_POINTER(_cert);
- *_cert = nullptr;
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- UniqueCERTCertificate cert;
- nsresult rv = FindCertByDBKey(aDBKey, cert);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // If we can't find the certificate, that's not an error. Just return null.
- if (!cert) {
- return NS_OK;
- }
- nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
- if (!nssCert) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nssCert.forget(_cert);
- return NS_OK;
- }
- nsresult
- nsNSSCertificateDB::FindCertByDBKey(const char* aDBKey,
- UniqueCERTCertificate& cert)
- {
- static_assert(sizeof(uint64_t) == 8, "type size sanity check");
- static_assert(sizeof(uint32_t) == 4, "type size sanity check");
- // (From nsNSSCertificate::GetDbKey)
- // The format of the key is the base64 encoding of the following:
- // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
- // never implemented)
- // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
- // never implemented)
- // 4 bytes: <serial number length in big-endian order>
- // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
- // n bytes: <bytes of serial number>
- // m bytes: <DER-encoded issuer distinguished name>
- nsAutoCString decoded;
- nsAutoCString tmpDBKey(aDBKey);
- // Filter out any whitespace for backwards compatibility.
- tmpDBKey.StripWhitespace();
- nsresult rv = Base64Decode(tmpDBKey, decoded);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (decoded.Length() < 16) {
- return NS_ERROR_ILLEGAL_INPUT;
- }
- const char* reader = decoded.BeginReading();
- uint64_t zeroes = *BitwiseCast<const uint64_t*, const char*>(reader);
- if (zeroes != 0) {
- return NS_ERROR_ILLEGAL_INPUT;
- }
- reader += sizeof(uint64_t);
- // Note: We surround the ntohl() argument with parentheses to stop the macro
- // from thinking two arguments were passed.
- uint32_t serialNumberLen = ntohl(
- (*BitwiseCast<const uint32_t*, const char*>(reader)));
- reader += sizeof(uint32_t);
- uint32_t issuerLen = ntohl(
- (*BitwiseCast<const uint32_t*, const char*>(reader)));
- reader += sizeof(uint32_t);
- if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) {
- return NS_ERROR_ILLEGAL_INPUT;
- }
- CERTIssuerAndSN issuerSN;
- issuerSN.serialNumber.len = serialNumberLen;
- issuerSN.serialNumber.data = BitwiseCast<unsigned char*, const char*>(reader);
- reader += serialNumberLen;
- issuerSN.derIssuer.len = issuerLen;
- issuerSN.derIssuer.data = BitwiseCast<unsigned char*, const char*>(reader);
- reader += issuerLen;
- MOZ_ASSERT(reader == decoded.EndReading());
- cert.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
- return NS_OK;
- }
- SECStatus
- collect_certs(void *arg, SECItem **certs, int numcerts)
- {
- CERTDERCerts *collectArgs;
- SECItem *cert;
- SECStatus rv;
- collectArgs = (CERTDERCerts *)arg;
- collectArgs->numcerts = numcerts;
- collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
- sizeof(SECItem) * numcerts);
- if (!collectArgs->rawCerts)
- return(SECFailure);
- cert = collectArgs->rawCerts;
- while ( numcerts-- ) {
- rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
- if ( rv == SECFailure )
- return(SECFailure);
- cert++;
- certs++;
- }
- return (SECSuccess);
- }
- CERTDERCerts*
- nsNSSCertificateDB::getCertsFromPackage(const UniquePLArenaPool& arena,
- uint8_t* data, uint32_t length,
- const nsNSSShutDownPreventionLock& /*proofOfLock*/)
- {
- CERTDERCerts* collectArgs = PORT_ArenaZNew(arena.get(), CERTDERCerts);
- if (!collectArgs) {
- return nullptr;
- }
- collectArgs->arena = arena.get();
- if (CERT_DecodeCertPackage(BitwiseCast<char*, uint8_t*>(data), length,
- collect_certs, collectArgs) != SECSuccess) {
- return nullptr;
- }
- return collectArgs;
- }
- nsresult
- nsNSSCertificateDB::handleCACertDownload(NotNull<nsIArray*> x509Certs,
- nsIInterfaceRequestor *ctx,
- const nsNSSShutDownPreventionLock &proofOfLock)
- {
- // First thing we have to do is figure out which certificate we're
- // gonna present to the user. The CA may have sent down a list of
- // certs which may or may not be a chained list of certs. Until
- // the day we can design some solid UI for the general case, we'll
- // code to the > 90% case. That case is where a CA sends down a
- // list that is a hierarchy whose root is either the first or
- // the last cert. What we're gonna do is compare the first
- // 2 entries, if the second was signed by the first, we assume
- // the root cert is the first cert and display it. Otherwise,
- // we compare the last 2 entries, if the second to last cert was
- // signed by the last cert, then we assume the last cert is the
- // root and display it.
- uint32_t numCerts;
- x509Certs->GetLength(&numCerts);
- NS_ASSERTION(numCerts > 0, "Didn't get any certs to import.");
- if (numCerts == 0)
- return NS_OK; // Nothing to import, so nothing to do.
- nsCOMPtr<nsIX509Cert> certToShow;
- uint32_t selCertIndex;
- if (numCerts == 1) {
- // There's only one cert, so let's show it.
- selCertIndex = 0;
- certToShow = do_QueryElementAt(x509Certs, selCertIndex);
- } else {
- nsCOMPtr<nsIX509Cert> cert0; // first cert
- nsCOMPtr<nsIX509Cert> cert1; // second cert
- nsCOMPtr<nsIX509Cert> certn_2; // second to last cert
- nsCOMPtr<nsIX509Cert> certn_1; // last cert
- cert0 = do_QueryElementAt(x509Certs, 0);
- cert1 = do_QueryElementAt(x509Certs, 1);
- certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
- certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
- nsXPIDLString cert0SubjectName;
- nsXPIDLString cert1IssuerName;
- nsXPIDLString certn_2IssuerName;
- nsXPIDLString certn_1SubjectName;
- cert0->GetSubjectName(cert0SubjectName);
- cert1->GetIssuerName(cert1IssuerName);
- certn_2->GetIssuerName(certn_2IssuerName);
- certn_1->GetSubjectName(certn_1SubjectName);
- if (cert1IssuerName.Equals(cert0SubjectName)) {
- // In this case, the first cert in the list signed the second,
- // so the first cert is the root. Let's display it.
- selCertIndex = 0;
- certToShow = cert0;
- } else
- if (certn_2IssuerName.Equals(certn_1SubjectName)) {
- // In this case the last cert has signed the second to last cert.
- // The last cert is the root, so let's display it.
- selCertIndex = numCerts-1;
- certToShow = certn_1;
- } else {
- // It's not a chain, so let's just show the first one in the
- // downloaded list.
- selCertIndex = 0;
- certToShow = cert0;
- }
- }
- if (!certToShow)
- return NS_ERROR_FAILURE;
- nsCOMPtr<nsICertificateDialogs> dialogs;
- nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
- NS_GET_IID(nsICertificateDialogs),
- NS_CERTIFICATEDIALOGS_CONTRACTID);
- if (NS_FAILED(rv)) {
- return rv;
- }
- UniqueCERTCertificate tmpCert(certToShow->GetCert());
- if (!tmpCert) {
- return NS_ERROR_FAILURE;
- }
- if (!CERT_IsCACert(tmpCert.get(), nullptr)) {
- DisplayCertificateAlert(ctx, "NotACACert", certToShow, proofOfLock);
- return NS_ERROR_FAILURE;
- }
- if (tmpCert->isperm) {
- DisplayCertificateAlert(ctx, "CaCertExists", certToShow, proofOfLock);
- return NS_ERROR_FAILURE;
- }
- uint32_t trustBits;
- bool allows;
- rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
- if (NS_FAILED(rv))
- return rv;
- if (!allows)
- return NS_ERROR_NOT_AVAILABLE;
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trust is %d\n", trustBits));
- UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get()));
- nsNSSCertTrust trust;
- trust.SetValidCA();
- trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
- !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL),
- !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN));
- if (CERT_AddTempCertToPerm(tmpCert.get(), nickname.get(),
- trust.GetTrust()) != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- // Import additional delivered certificates that can be verified.
- // build a CertList for filtering
- UniqueCERTCertList certList(CERT_NewCertList());
- if (!certList) {
- return NS_ERROR_FAILURE;
- }
- // get all remaining certs into temp store
- for (uint32_t i=0; i<numCerts; i++) {
- if (i == selCertIndex) {
- // we already processed that one
- continue;
- }
- nsCOMPtr<nsIX509Cert> remainingCert = do_QueryElementAt(x509Certs, i);
- if (!remainingCert) {
- continue;
- }
- UniqueCERTCertificate tmpCert2(remainingCert->GetCert());
- if (!tmpCert2) {
- continue; // Let's try to import the rest of 'em
- }
- if (CERT_AddCertToListTail(certList.get(), tmpCert2.get()) != SECSuccess) {
- continue;
- }
- Unused << tmpCert2.release();
- }
- return ImportValidCACertsInList(certList, ctx, proofOfLock);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length,
- uint32_t type,
- nsIInterfaceRequestor* ctx)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- // We currently only handle CA certificates.
- if (type != nsIX509Cert::CA_CERT) {
- return NS_ERROR_FAILURE;
- }
- UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- if (!arena) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- CERTDERCerts* certCollection = getCertsFromPackage(arena, data, length,
- locker);
- if (!certCollection) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
- if (!array) {
- return NS_ERROR_FAILURE;
- }
- // Now let's create some certs to work with
- for (int i = 0; i < certCollection->numcerts; i++) {
- SECItem* currItem = &certCollection->rawCerts[i];
- nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::ConstructFromDER(
- BitwiseCast<char*, unsigned char*>(currItem->data), currItem->len);
- if (!cert) {
- return NS_ERROR_FAILURE;
- }
- nsresult rv = array->AppendElement(cert, false);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- return handleCACertDownload(WrapNotNull(array), ctx, locker);
- }
- /**
- * Filters an array of certs by usage and imports them into temporary storage.
- *
- * @param numcerts
- * Size of the |certs| array.
- * @param certs
- * Pointer to array of certs to import.
- * @param usage
- * Usage the certs should be filtered on.
- * @param caOnly
- * Whether to import only CA certs.
- * @param filteredCerts
- * List of certs that weren't filtered out and were successfully imported.
- */
- static nsresult
- ImportCertsIntoTempStorage(int numcerts, SECItem* certs,
- const SECCertUsage usage, const bool caOnly,
- const nsNSSShutDownPreventionLock& /*proofOfLock*/,
- /*out*/ const UniqueCERTCertList& filteredCerts)
- {
- NS_ENSURE_ARG_MIN(numcerts, 1);
- NS_ENSURE_ARG_POINTER(certs);
- NS_ENSURE_ARG_POINTER(filteredCerts.get());
- // CERT_ImportCerts() expects an array of *pointers* to SECItems, so we have
- // to convert |certs| to such a format first.
- SECItem** ptrArray =
- static_cast<SECItem**>(PORT_Alloc(sizeof(SECItem*) * numcerts));
- if (!ptrArray) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- for (int i = 0; i < numcerts; i++) {
- ptrArray[i] = &certs[i];
- }
- CERTCertificate** importedCerts = nullptr;
- SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), usage,
- numcerts, ptrArray, &importedCerts, false,
- caOnly, nullptr);
- PORT_Free(ptrArray);
- ptrArray = nullptr;
- if (srv != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- for (int i = 0; i < numcerts; i++) {
- if (!importedCerts[i]) {
- continue;
- }
- UniqueCERTCertificate cert(CERT_DupCertificate(importedCerts[i]));
- if (!cert) {
- continue;
- }
- if (CERT_AddCertToListTail(filteredCerts.get(), cert.get()) == SECSuccess) {
- Unused << cert.release();
- }
- }
- CERT_DestroyCertArray(importedCerts, numcerts);
- // CERT_ImportCerts() ignores its |usage| parameter, so we have to manually
- // filter out unwanted certs.
- if (CERT_FilterCertListByUsage(filteredCerts.get(), usage, caOnly)
- != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- static SECStatus
- ImportCertsIntoPermanentStorage(const UniqueCERTCertList& certChain,
- const SECCertUsage usage, const bool caOnly)
- {
- int chainLen = 0;
- for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
- !CERT_LIST_END(chainNode, certChain);
- chainNode = CERT_LIST_NEXT(chainNode)) {
- chainLen++;
- }
- SECItem **rawArray;
- rawArray = (SECItem **) PORT_Alloc(chainLen * sizeof(SECItem *));
- if (!rawArray) {
- return SECFailure;
- }
- int i = 0;
- for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
- !CERT_LIST_END(chainNode, certChain);
- chainNode = CERT_LIST_NEXT(chainNode), i++) {
- rawArray[i] = &chainNode->cert->derCert;
- }
- SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), usage, chainLen,
- rawArray, nullptr, true, caOnly, nullptr);
- PORT_Free(rawArray);
- return srv;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length,
- nsIInterfaceRequestor* ctx)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- if (!arena) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
- if (!certCollection) {
- return NS_ERROR_FAILURE;
- }
- UniqueCERTCertList filteredCerts(CERT_NewCertList());
- if (!filteredCerts) {
- return NS_ERROR_FAILURE;
- }
- nsresult rv = ImportCertsIntoTempStorage(certCollection->numcerts,
- certCollection->rawCerts,
- certUsageEmailRecipient,
- false, locker, filteredCerts);
- if (NS_FAILED(rv)) {
- return rv;
- }
- RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
- if (!certVerifier) {
- return NS_ERROR_UNEXPECTED;
- }
- // Iterate through the filtered cert list and import verified certs into
- // permanent storage.
- // Note: We verify the certs in order to prevent DoS attacks. See Bug 249004.
- for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get());
- !CERT_LIST_END(node, filteredCerts.get());
- node = CERT_LIST_NEXT(node)) {
- if (!node->cert) {
- continue;
- }
- UniqueCERTCertList certChain;
- mozilla::pkix::Result result =
- certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
- mozilla::pkix::Now(), ctx, nullptr, certChain);
- if (result != mozilla::pkix::Success) {
- nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
- DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker);
- continue;
- }
- SECStatus srv = ImportCertsIntoPermanentStorage(certChain,
- certUsageEmailRecipient,
- false);
- if (srv != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- CERT_SaveSMimeProfile(node->cert, nullptr, nullptr);
- }
- return NS_OK;
- }
- nsresult
- nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem* caCerts,
- nsIInterfaceRequestor* ctx,
- const nsNSSShutDownPreventionLock& proofOfLock)
- {
- UniqueCERTCertList filteredCerts(CERT_NewCertList());
- if (!filteredCerts) {
- return NS_ERROR_FAILURE;
- }
- nsresult rv = ImportCertsIntoTempStorage(numCACerts, caCerts, certUsageAnyCA,
- true, proofOfLock, filteredCerts);
- if (NS_FAILED(rv)) {
- return rv;
- }
- return ImportValidCACertsInList(filteredCerts, ctx, proofOfLock);
- }
- nsresult
- nsNSSCertificateDB::ImportValidCACertsInList(const UniqueCERTCertList& filteredCerts,
- nsIInterfaceRequestor* ctx,
- const nsNSSShutDownPreventionLock& proofOfLock)
- {
- RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
- if (!certVerifier) {
- return NS_ERROR_UNEXPECTED;
- }
- // Iterate through the filtered cert list and import verified certs into
- // permanent storage.
- // Note: We verify the certs in order to prevent DoS attacks. See Bug 249004.
- for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get());
- !CERT_LIST_END(node, filteredCerts.get());
- node = CERT_LIST_NEXT(node)) {
- UniqueCERTCertList certChain;
- mozilla::pkix::Result result =
- certVerifier->VerifyCert(node->cert, certificateUsageVerifyCA,
- mozilla::pkix::Now(), ctx, nullptr, certChain);
- if (result != mozilla::pkix::Success) {
- nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
- DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock);
- continue;
- }
- SECStatus srv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA,
- true);
- if (srv != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- }
- return NS_OK;
- }
- void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx,
- const char *stringID,
- nsIX509Cert *certToShow,
- const nsNSSShutDownPreventionLock &/*proofOfLock*/)
- {
- static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
- if (!NS_IsMainThread()) {
- NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread");
- return;
- }
- nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx;
- if (!my_ctx) {
- my_ctx = new PipUIContext();
- }
- // This shall be replaced by embedding ovverridable prompts
- // as discussed in bug 310446, and should make use of certToShow.
- nsresult rv;
- nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
- if (NS_SUCCEEDED(rv)) {
- nsAutoString tmpMessage;
- nssComponent->GetPIPNSSBundleString(stringID, tmpMessage);
- nsCOMPtr<nsIPrompt> prompt (do_GetInterface(my_ctx));
- if (!prompt) {
- return;
- }
- prompt->Alert(nullptr, tmpMessage.get());
- }
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ImportUserCertificate(uint8_t* data, uint32_t length,
- nsIInterfaceRequestor* ctx)
- {
- if (!NS_IsMainThread()) {
- NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
- return NS_ERROR_NOT_SAME_THREAD;
- }
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
- if (!arena) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- CERTDERCerts* collectArgs = getCertsFromPackage(arena, data, length, locker);
- if (!collectArgs) {
- return NS_ERROR_FAILURE;
- }
- UniqueCERTCertificate cert(
- CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
- nullptr, false, true));
- if (!cert) {
- return NS_ERROR_FAILURE;
- }
- UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert.get(), nullptr, ctx));
- if (!slot) {
- nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
- DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker);
- return NS_ERROR_FAILURE;
- }
- slot = nullptr;
- /* pick a nickname for the cert */
- nsAutoCString nickname;
- if (cert->nickname) {
- nickname = cert->nickname;
- } else {
- get_default_nickname(cert.get(), ctx, nickname, locker);
- }
- /* user wants to import the cert */
- slot.reset(PK11_ImportCertForKey(cert.get(), nickname.get(), ctx));
- if (!slot) {
- return NS_ERROR_FAILURE;
- }
- slot = nullptr;
- {
- nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
- DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker);
- }
- int numCACerts = collectArgs->numcerts - 1;
- if (numCACerts) {
- SECItem* caCerts = collectArgs->rawCerts + 1;
- return ImportValidCACerts(numCACerts, caCerts, ctx, locker);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
- {
- NS_ENSURE_ARG_POINTER(aCert);
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- UniqueCERTCertificate cert(aCert->GetCert());
- if (!cert) {
- return NS_ERROR_FAILURE;
- }
- SECStatus srv = SECSuccess;
- uint32_t certType;
- aCert->GetCertType(&certType);
- if (NS_FAILED(aCert->MarkForPermDeletion()))
- {
- return NS_ERROR_FAILURE;
- }
- if (cert->slot && certType != nsIX509Cert::USER_CERT) {
- // To delete a cert of a slot (builtin, most likely), mark it as
- // completely untrusted. This way we keep a copy cached in the
- // local database, and next time we try to load it off of the
- // external token/slot, we'll know not to trust it. We don't
- // want to do that with user certs, because a user may re-store
- // the cert onto the card again at which point we *will* want to
- // trust that cert if it chains up properly.
- nsNSSCertTrust trust(0, 0, 0);
- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
- cert.get(), trust.GetTrust());
- }
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("cert deleted: %d", srv));
- return (srv) ? NS_ERROR_FAILURE : NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
- uint32_t type,
- uint32_t trusted)
- {
- NS_ENSURE_ARG_POINTER(cert);
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsNSSCertTrust trust;
- nsresult rv;
- UniqueCERTCertificate nsscert(cert->GetCert());
- rv = attemptToLogInWithDefaultPassword();
- if (NS_WARN_IF(rv != NS_OK)) {
- return rv;
- }
- SECStatus srv;
- if (type == nsIX509Cert::CA_CERT) {
- // always start with untrusted and move up
- trust.SetValidCA();
- trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
- !!(trusted & nsIX509CertDB::TRUSTED_EMAIL),
- !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN));
- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
- nsscert.get(),
- trust.GetTrust());
- } else if (type == nsIX509Cert::SERVER_CERT) {
- // always start with untrusted and move up
- trust.SetValidPeer();
- trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
- nsscert.get(),
- trust.GetTrust());
- } else if (type == nsIX509Cert::EMAIL_CERT) {
- // always start with untrusted and move up
- trust.SetValidPeer();
- trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0);
- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
- nsscert.get(),
- trust.GetTrust());
- } else {
- // ignore user certs
- return NS_OK;
- }
- return MapSECStatus(srv);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
- uint32_t certType,
- uint32_t trustType,
- bool *_isTrusted)
- {
- NS_ENSURE_ARG_POINTER(_isTrusted);
- *_isTrusted = false;
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- SECStatus srv;
- UniqueCERTCertificate nsscert(cert->GetCert());
- CERTCertTrust nsstrust;
- srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
- if (srv != SECSuccess)
- return NS_ERROR_FAILURE;
- nsNSSCertTrust trust(&nsstrust);
- if (certType == nsIX509Cert::CA_CERT) {
- if (trustType & nsIX509CertDB::TRUSTED_SSL) {
- *_isTrusted = trust.HasTrustedCA(true, false, false);
- } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
- *_isTrusted = trust.HasTrustedCA(false, true, false);
- } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
- *_isTrusted = trust.HasTrustedCA(false, false, true);
- } else {
- return NS_ERROR_FAILURE;
- }
- } else if (certType == nsIX509Cert::SERVER_CERT) {
- if (trustType & nsIX509CertDB::TRUSTED_SSL) {
- *_isTrusted = trust.HasTrustedPeer(true, false, false);
- } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
- *_isTrusted = trust.HasTrustedPeer(false, true, false);
- } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
- *_isTrusted = trust.HasTrustedPeer(false, false, true);
- } else {
- return NS_ERROR_FAILURE;
- }
- } else if (certType == nsIX509Cert::EMAIL_CERT) {
- if (trustType & nsIX509CertDB::TRUSTED_SSL) {
- *_isTrusted = trust.HasTrustedPeer(true, false, false);
- } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
- *_isTrusted = trust.HasTrustedPeer(false, true, false);
- } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
- *_isTrusted = trust.HasTrustedPeer(false, false, true);
- } else {
- return NS_ERROR_FAILURE;
- }
- } /* user: ignore */
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ImportCertsFromFile(nsIFile* aFile, uint32_t aType)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_ARG(aFile);
- switch (aType) {
- case nsIX509Cert::CA_CERT:
- case nsIX509Cert::EMAIL_CERT:
- // good
- break;
- default:
- // not supported (yet)
- return NS_ERROR_FAILURE;
- }
- PRFileDesc* fd = nullptr;
- nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!fd) {
- return NS_ERROR_FAILURE;
- }
- PRFileInfo fileInfo;
- if (PR_GetOpenFileInfo(fd, &fileInfo) != PR_SUCCESS) {
- return NS_ERROR_FAILURE;
- }
- auto buf = MakeUnique<unsigned char[]>(fileInfo.size);
- int32_t bytesObtained = PR_Read(fd, buf.get(), fileInfo.size);
- PR_Close(fd);
- if (bytesObtained != fileInfo.size) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
- switch (aType) {
- case nsIX509Cert::CA_CERT:
- return ImportCertificates(buf.get(), bytesObtained, aType, cxt);
- case nsIX509Cert::EMAIL_CERT:
- return ImportEmailCertificate(buf.get(), bytesObtained, cxt);
- default:
- MOZ_ASSERT(false, "Unsupported type should have been filtered out");
- break;
- }
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ImportPKCS12File(nsISupports* aToken, nsIFile* aFile)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_ARG(aFile);
- nsPKCS12Blob blob;
- nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken);
- if (token) {
- blob.SetToken(token);
- }
- return blob.ImportFromFile(aFile);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ExportPKCS12File(nsISupports* aToken,
- nsIFile* aFile,
- uint32_t count,
- nsIX509Cert** certs)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_ARG(aFile);
- nsPKCS12Blob blob;
- if (count == 0) return NS_OK;
- nsCOMPtr<nsIPK11Token> localRef;
- if (!aToken) {
- UniquePK11SlotInfo keySlot(PK11_GetInternalKeySlot());
- if (!keySlot) {
- return NS_ERROR_FAILURE;
- }
- localRef = new nsPK11Token(keySlot.get());
- } else {
- localRef = do_QueryInterface(aToken);
- }
- blob.SetToken(localRef);
- return blob.ExportToFile(aFile, certs, count);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString& aNickname,
- nsIX509Cert** _retval)
- {
- NS_ENSURE_ARG_POINTER(_retval);
- *_retval = nullptr;
- if (aNickname.IsEmpty())
- return NS_OK;
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
- char *asciiname = nullptr;
- NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
- asciiname = const_cast<char*>(aUtf8Nickname.get());
- /* Find a good cert in the user's database */
- UniqueCERTCertificate cert(CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
- asciiname,
- certUsageEmailRecipient,
- true, ctx));
- if (!cert) {
- return NS_OK;
- }
- nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
- if (!nssCert) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nssCert.forget(_retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::FindEmailSigningCert(const nsAString& aNickname,
- nsIX509Cert** _retval)
- {
- NS_ENSURE_ARG_POINTER(_retval);
- *_retval = nullptr;
- if (aNickname.IsEmpty())
- return NS_OK;
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
- char *asciiname = nullptr;
- NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
- asciiname = const_cast<char*>(aUtf8Nickname.get());
- /* Find a good cert in the user's database */
- UniqueCERTCertificate cert(CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
- asciiname,
- certUsageEmailSigner,
- true, ctx));
- if (!cert) {
- return NS_OK;
- }
- nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
- if (!nssCert) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nssCert.forget(_retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::FindCertByEmailAddress(const char* aEmailAddress,
- nsIX509Cert** _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
- NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
- UniqueCERTCertList certlist(
- PK11_FindCertsFromEmailAddress(aEmailAddress, nullptr));
- if (!certlist)
- return NS_ERROR_FAILURE;
- // certlist now contains certificates with the right email address,
- // but they might not have the correct usage or might even be invalid
- if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
- return NS_ERROR_FAILURE; // no certs found
- CERTCertListNode *node;
- // search for a valid certificate
- for (node = CERT_LIST_HEAD(certlist);
- !CERT_LIST_END(node, certlist);
- node = CERT_LIST_NEXT(node)) {
- UniqueCERTCertList unusedCertChain;
- mozilla::pkix::Result result =
- certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient,
- mozilla::pkix::Now(),
- nullptr /*XXX pinarg*/,
- nullptr /*hostname*/,
- unusedCertChain);
- if (result == mozilla::pkix::Success) {
- break;
- }
- }
- if (CERT_LIST_END(node, certlist)) {
- // no valid cert found
- return NS_ERROR_FAILURE;
- }
- // node now contains the first valid certificate with correct usage
- RefPtr<nsNSSCertificate> nssCert = nsNSSCertificate::Create(node->cert);
- if (!nssCert)
- return NS_ERROR_OUT_OF_MEMORY;
- nssCert.forget(_retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64,
- /*out*/ nsIX509Cert** _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- if (!_retval) {
- return NS_ERROR_INVALID_POINTER;
- }
- // Base64Decode() doesn't consider a zero length input as an error, and just
- // returns the empty string. We don't want this behavior, so the below check
- // catches this case.
- if (base64.Length() < 1) {
- return NS_ERROR_ILLEGAL_VALUE;
- }
- nsAutoCString certDER;
- nsresult rv = Base64Decode(base64, certDER);
- if (NS_FAILED(rv)) {
- return rv;
- }
- return ConstructX509(certDER.get(), certDER.Length(), _retval);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ConstructX509(const char* certDER,
- uint32_t lengthDER,
- nsIX509Cert** _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- if (NS_WARN_IF(!_retval)) {
- return NS_ERROR_INVALID_POINTER;
- }
- SECItem secitem_cert;
- secitem_cert.type = siDERCertBuffer;
- secitem_cert.data = (unsigned char*)certDER;
- secitem_cert.len = lengthDER;
- UniqueCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
- &secitem_cert, nullptr,
- false, true));
- if (!cert)
- return (PORT_GetError() == SEC_ERROR_NO_MEMORY)
- ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE;
- nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
- if (!nssCert) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nssCert.forget(_retval);
- return NS_OK;
- }
- void
- nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
- nsIInterfaceRequestor* ctx,
- nsCString &nickname,
- const nsNSSShutDownPreventionLock &/*proofOfLock*/)
- {
- static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
- nickname.Truncate();
- nsresult rv;
- CK_OBJECT_HANDLE keyHandle;
- CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
- nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
- if (NS_FAILED(rv))
- return;
- nsAutoCString username;
- UniquePORTString tempCN(CERT_GetCommonName(&cert->subject));
- if (tempCN) {
- username = tempCN.get();
- }
- nsAutoCString caname;
- UniquePORTString tempIssuerOrg(CERT_GetOrgName(&cert->issuer));
- if (tempIssuerOrg) {
- caname = tempIssuerOrg.get();
- }
- nsAutoString tmpNickFmt;
- nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
- NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
- nsAutoCString baseName;
- baseName.AppendPrintf(nickFmt.get(), username.get(), caname.get());
- if (baseName.IsEmpty()) {
- return;
- }
- nickname = baseName;
- /*
- * We need to see if the private key exists on a token, if it does
- * then we need to check for nicknames that already exist on the smart
- * card.
- */
- UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx));
- if (!slot)
- return;
- if (!PK11_IsInternal(slot.get())) {
- nsAutoCString tmp;
- tmp.AppendPrintf("%s:%s", PK11_GetTokenName(slot.get()), baseName.get());
- if (tmp.IsEmpty()) {
- nickname.Truncate();
- return;
- }
- baseName = tmp;
- nickname = baseName;
- }
- int count = 1;
- while (true) {
- if ( count > 1 ) {
- nsAutoCString tmp;
- tmp.AppendPrintf("%s #%d", baseName.get(), count);
- if (tmp.IsEmpty()) {
- nickname.Truncate();
- return;
- }
- nickname = tmp;
- }
- UniqueCERTCertificate dummycert;
- if (PK11_IsInternal(slot.get())) {
- /* look up the nickname to make sure it isn't in use already */
- dummycert.reset(CERT_FindCertByNickname(defaultcertdb, nickname.get()));
- } else {
- // Check the cert against others that already live on the smart card.
- dummycert.reset(PK11_FindCertFromNickname(nickname.get(), ctx));
- if (dummycert) {
- // Make sure the subject names are different.
- if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
- {
- /*
- * There is another certificate with the same nickname and
- * the same subject name on the smart card, so let's use this
- * nickname.
- */
- dummycert = nullptr;
- }
- }
- }
- if (!dummycert) {
- break;
- }
- count++;
- }
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::AddCertFromBase64(const nsACString& aBase64,
- const nsACString& aTrust,
- const nsACString& /*aName*/)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsNSSCertTrust trust;
- if (CERT_DecodeTrustString(trust.GetTrust(), PromiseFlatCString(aTrust).get())
- != SECSuccess) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIX509Cert> newCert;
- nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
- if (NS_FAILED(rv)) {
- return rv;
- }
- UniqueCERTCertificate tmpCert(newCert->GetCert());
- if (!tmpCert) {
- return NS_ERROR_FAILURE;
- }
- // If there's already a certificate that matches this one in the database, we
- // still want to set its trust to the given value.
- if (tmpCert->isperm) {
- return SetCertTrustFromString(newCert, aTrust);
- }
- UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get()));
- rv = attemptToLogInWithDefaultPassword();
- if (NS_WARN_IF(rv != NS_OK)) {
- return rv;
- }
- SECStatus srv = CERT_AddTempCertToPerm(tmpCert.get(), nickname.get(),
- trust.GetTrust());
- return MapSECStatus(srv);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::AddCert(const nsACString& aCertDER, const nsACString& aTrust,
- const nsACString& aName)
- {
- nsCString base64;
- nsresult rv = Base64Encode(aCertDER, base64);
- NS_ENSURE_SUCCESS(rv, rv);
- return AddCertFromBase64(base64, aTrust, aName);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
- const nsACString& trustString)
- {
- NS_ENSURE_ARG(cert);
- CERTCertTrust trust;
- SECStatus srv = CERT_DecodeTrustString(&trust,
- PromiseFlatCString(trustString).get());
- if (srv != SECSuccess) {
- return MapSECStatus(srv);
- }
- UniqueCERTCertificate nssCert(cert->GetCert());
- nsresult rv = attemptToLogInWithDefaultPassword();
- if (NS_WARN_IF(rv != NS_OK)) {
- return rv;
- }
- srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust);
- return MapSECStatus(srv);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
- nsCOMPtr<nsIX509CertList> nssCertList;
- UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx));
- // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
- // (returns an empty list)
- nssCertList = new nsNSSCertList(Move(certList), locker);
- nssCertList.forget(_retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (!NS_IsMainThread()) {
- return NS_ERROR_NOT_SAME_THREAD;
- }
- NS_ENSURE_ARG_POINTER(enterpriseRoots);
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- #ifdef XP_WIN
- nsCOMPtr<nsINSSComponent> psm(do_GetService(PSM_COMPONENT_CONTRACTID));
- if (!psm) {
- return NS_ERROR_FAILURE;
- }
- return psm->GetEnterpriseRoots(enterpriseRoots);
- #else
- return NS_ERROR_NOT_IMPLEMENTED;
- #endif
- }
- nsresult
- VerifyCertAtTime(nsIX509Cert* aCert,
- int64_t /*SECCertificateUsage*/ aUsage,
- uint32_t aFlags,
- const char* aHostname,
- mozilla::pkix::Time aTime,
- nsIX509CertList** aVerifiedChain,
- bool* aHasEVPolicy,
- int32_t* /*PRErrorCode*/ _retval,
- const nsNSSShutDownPreventionLock& locker)
- {
- NS_ENSURE_ARG_POINTER(aCert);
- NS_ENSURE_ARG_POINTER(aHasEVPolicy);
- NS_ENSURE_ARG_POINTER(aVerifiedChain);
- NS_ENSURE_ARG_POINTER(_retval);
- *aVerifiedChain = nullptr;
- *aHasEVPolicy = false;
- *_retval = PR_UNKNOWN_ERROR;
- UniqueCERTCertificate nssCert(aCert->GetCert());
- if (!nssCert) {
- return NS_ERROR_INVALID_ARG;
- }
- RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
- NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
- UniqueCERTCertList resultChain;
- SECOidTag evOidPolicy;
- mozilla::pkix::Result result;
- if (aHostname && aUsage == certificateUsageSSLServer) {
- result = certVerifier->VerifySSLServerCert(nssCert,
- nullptr, // stapledOCSPResponse
- nullptr, // sctsFromTLSExtension
- aTime,
- nullptr, // Assume no context
- aHostname,
- resultChain,
- false, // don't save intermediates
- aFlags,
- NeckoOriginAttributes(),
- &evOidPolicy);
- } else {
- result = certVerifier->VerifyCert(nssCert.get(), aUsage, aTime,
- nullptr, // Assume no context
- aHostname,
- resultChain,
- aFlags,
- nullptr, // stapledOCSPResponse
- nullptr, // sctsFromTLSExtension
- NeckoOriginAttributes(),
- &evOidPolicy);
- }
- nsCOMPtr<nsIX509CertList> nssCertList;
- // This adopts the list
- nssCertList = new nsNSSCertList(Move(resultChain), locker);
- NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE);
- *_retval = mozilla::pkix::MapResultToPRErrorCode(result);
- if (result == mozilla::pkix::Success && evOidPolicy != SEC_OID_UNKNOWN) {
- *aHasEVPolicy = true;
- }
- nssCertList.forget(aVerifiedChain);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
- int64_t /*SECCertificateUsage*/ aUsage,
- uint32_t aFlags,
- const char* aHostname,
- nsIX509CertList** aVerifiedChain,
- bool* aHasEVPolicy,
- int32_t* /*PRErrorCode*/ _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname,
- mozilla::pkix::Now(),
- aVerifiedChain, aHasEVPolicy, _retval, locker);
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::VerifyCertAtTime(nsIX509Cert* aCert,
- int64_t /*SECCertificateUsage*/ aUsage,
- uint32_t aFlags,
- const char* aHostname,
- uint64_t aTime,
- nsIX509CertList** aVerifiedChain,
- bool* aHasEVPolicy,
- int32_t* /*PRErrorCode*/ _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return ::VerifyCertAtTime(aCert, aUsage, aFlags, aHostname,
- mozilla::pkix::TimeFromEpochInSeconds(aTime),
- aVerifiedChain, aHasEVPolicy, _retval, locker);
- }
- class VerifyCertAtTimeTask final : public CryptoTask
- {
- public:
- VerifyCertAtTimeTask(nsIX509Cert* aCert, int64_t aUsage, uint32_t aFlags,
- const char* aHostname, uint64_t aTime,
- nsICertVerificationCallback* aCallback)
- : mCert(aCert)
- , mUsage(aUsage)
- , mFlags(aFlags)
- , mHostname(aHostname)
- , mTime(aTime)
- , mCallback(new nsMainThreadPtrHolder<nsICertVerificationCallback>(aCallback))
- , mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE)
- , mVerifiedCertList(nullptr)
- , mHasEVPolicy(false)
- {
- }
- private:
- virtual nsresult CalculateResult() override
- {
- nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID);
- if (!certDB) {
- return NS_ERROR_FAILURE;
- }
- // Unfortunately mHostname will have made the empty string out of a null
- // pointer passed in the constructor. If we pass the empty string on to
- // VerifyCertAtTime with the usage certificateUsageSSLServer, it will call
- // VerifySSLServerCert, which expects a non-empty hostname. To avoid this,
- // check the length and use nullptr if appropriate.
- const char* hostname = mHostname.Length() > 0 ? mHostname.get() : nullptr;
- return certDB->VerifyCertAtTime(mCert, mUsage, mFlags, hostname, mTime,
- getter_AddRefs(mVerifiedCertList),
- &mHasEVPolicy, &mPRErrorCode);
- }
- // No NSS resources are directly held, so there is nothing to release.
- virtual void ReleaseNSSResources() override { }
- virtual void CallCallback(nsresult rv) override
- {
- if (NS_FAILED(rv)) {
- Unused << mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE,
- nullptr, false);
- } else {
- Unused << mCallback->VerifyCertFinished(mPRErrorCode, mVerifiedCertList,
- mHasEVPolicy);
- }
- }
- nsCOMPtr<nsIX509Cert> mCert;
- int64_t mUsage;
- uint32_t mFlags;
- nsCString mHostname;
- uint64_t mTime;
- nsMainThreadPtrHandle<nsICertVerificationCallback> mCallback;
- int32_t mPRErrorCode;
- nsCOMPtr<nsIX509CertList> mVerifiedCertList;
- bool mHasEVPolicy;
- };
- NS_IMETHODIMP
- nsNSSCertificateDB::AsyncVerifyCertAtTime(nsIX509Cert* aCert,
- int64_t /*SECCertificateUsage*/ aUsage,
- uint32_t aFlags,
- const char* aHostname,
- uint64_t aTime,
- nsICertVerificationCallback* aCallback)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- RefPtr<VerifyCertAtTimeTask> task(new VerifyCertAtTimeTask(aCert, aUsage,
- aFlags, aHostname,
- aTime, aCallback));
- return task->Dispatch("VerifyCert");
- }
- NS_IMETHODIMP
- nsNSSCertificateDB::ClearOCSPCache()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
- NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
- certVerifier->ClearOCSPCache();
- return NS_OK;
- }
|