12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 "nsNSSCertificate.h"
- #include "CertVerifier.h"
- #include "ExtendedValidation.h"
- #include "NSSCertDBTrustDomain.h"
- #include "certdb.h"
- #include "mozilla/Base64.h"
- #include "mozilla/Casting.h"
- #include "mozilla/NotNull.h"
- #include "mozilla/Unused.h"
- #include "nsArray.h"
- #include "nsCOMPtr.h"
- #include "nsCRT.h"
- #include "nsICertificateDialogs.h"
- #include "nsIClassInfoImpl.h"
- #include "nsIObjectInputStream.h"
- #include "nsIObjectOutputStream.h"
- #include "nsISupportsPrimitives.h"
- #include "nsIURI.h"
- #include "nsIX509Cert.h"
- #include "nsNSSASN1Object.h"
- #include "nsNSSCertHelper.h"
- #include "nsNSSCertValidity.h"
- #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
- #include "nsPK11TokenDB.h"
- #include "nsPKCS12Blob.h"
- #include "nsProxyRelease.h"
- #include "nsReadableUtils.h"
- #include "nsString.h"
- #include "nsThreadUtils.h"
- #include "nsUnicharUtils.h"
- #include "nsXULAppAPI.h"
- #include "nspr.h"
- #include "pkix/pkixnss.h"
- #include "pkix/pkixtypes.h"
- #include "pkix/Result.h"
- #include "prerror.h"
- #include "prmem.h"
- #include "prprf.h"
- #include "secasn1.h"
- #include "secder.h"
- #include "secerr.h"
- #include "ssl.h"
- #ifdef XP_WIN
- #include <winsock.h> // for htonl
- #endif
- using namespace mozilla;
- using namespace mozilla::psm;
- extern LazyLogModule gPIPNSSLog;
- // This is being stored in an uint32_t that can otherwise
- // only take values from nsIX509Cert's list of cert types.
- // As nsIX509Cert is frozen, we choose a value not contained
- // in the list to mean not yet initialized.
- #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
- NS_IMPL_ISUPPORTS(nsNSSCertificate,
- nsIX509Cert,
- nsISerializable,
- nsIClassInfo)
- static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
- /*static*/ nsNSSCertificate*
- nsNSSCertificate::Create(CERTCertificate* cert)
- {
- if (GeckoProcessType_Default != XRE_GetProcessType()) {
- NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
- return nullptr;
- }
- if (cert)
- return new nsNSSCertificate(cert);
- else
- return new nsNSSCertificate();
- }
- nsNSSCertificate*
- nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
- {
- // On non-chrome process prevent instantiation
- if (GeckoProcessType_Default != XRE_GetProcessType())
- return nullptr;
- nsNSSCertificate* newObject = nsNSSCertificate::Create();
- if (newObject && !newObject->InitFromDER(certDER, derLen)) {
- delete newObject;
- newObject = nullptr;
- }
- return newObject;
- }
- bool
- nsNSSCertificate::InitFromDER(char* certDER, int derLen)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return false;
- if (!certDER || !derLen)
- return false;
- CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
- if (!aCert)
- return false;
- if (!aCert->dbhandle)
- {
- aCert->dbhandle = CERT_GetDefaultCertDB();
- }
- mCert.reset(aCert);
- return true;
- }
- nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
- : mCert(nullptr)
- , mPermDelete(false)
- , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
- {
- #if defined(DEBUG)
- if (GeckoProcessType_Default != XRE_GetProcessType())
- NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
- #endif
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return;
- if (cert) {
- mCert.reset(CERT_DupCertificate(cert));
- }
- }
- nsNSSCertificate::nsNSSCertificate()
- : mCert(nullptr)
- , mPermDelete(false)
- , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
- {
- if (GeckoProcessType_Default != XRE_GetProcessType())
- NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
- }
- nsNSSCertificate::~nsNSSCertificate()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
- }
- void nsNSSCertificate::virtualDestroyNSSReference()
- {
- destructorSafeDestroyNSSReference();
- }
- void nsNSSCertificate::destructorSafeDestroyNSSReference()
- {
- if (mPermDelete) {
- if (mCertType == nsNSSCertificate::USER_CERT) {
- nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
- PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
- } else if (mCert->slot && !PK11_IsReadOnly(mCert->slot)) {
- // If the list of built-ins does contain a non-removable
- // copy of this certificate, our call will not remove
- // the certificate permanently, but rather remove all trust.
- SEC_DeletePermCertificate(mCert.get());
- }
- }
- mCert = nullptr;
- }
- nsresult
- nsNSSCertificate::GetCertType(uint32_t* aCertType)
- {
- if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
- // only determine cert type once and cache it
- mCertType = getCertType(mCert.get());
- }
- *aCertType = mCertType;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
- {
- NS_ENSURE_ARG(aIsSelfSigned);
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- *aIsSelfSigned = mCert->isRoot;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIsBuiltInRoot(bool* aIsBuiltInRoot)
- {
- NS_ENSURE_ARG(aIsBuiltInRoot);
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- pkix::Result rv = IsCertBuiltInRoot(mCert.get(), *aIsBuiltInRoot);
- if (rv != pkix::Result::Success) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- nsresult
- nsNSSCertificate::MarkForPermDeletion()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- // make sure user is logged in to the token
- nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
- if (mCert->slot && PK11_NeedLogin(mCert->slot) &&
- !PK11_NeedUserInit(mCert->slot) && !PK11_IsInternal(mCert->slot)) {
- if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) {
- return NS_ERROR_FAILURE;
- }
- }
- mPermDelete = true;
- return NS_OK;
- }
- /**
- * Appends a pipnss bundle string to the given string.
- *
- * @param nssComponent For accessing the string bundle.
- * @param bundleKey Key for the string to append.
- * @param currentText The text to append to, using commas as separators.
- */
- template<size_t N>
- void
- AppendBundleString(const NotNull<nsCOMPtr<nsINSSComponent>>& nssComponent,
- const char (&bundleKey)[N],
- /*in/out*/ nsAString& currentText)
- {
- nsAutoString bundleString;
- nsresult rv = nssComponent->GetPIPNSSBundleString(bundleKey, bundleString);
- if (NS_FAILED(rv)) {
- return;
- }
- if (!currentText.IsEmpty()) {
- currentText.Append(',');
- }
- currentText.Append(bundleString);
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetKeyUsages(nsAString& text)
- {
- text.Truncate();
- nsCOMPtr<nsINSSComponent> nssComponent = do_GetService(kNSSComponentCID);
- if (!nssComponent) {
- return NS_ERROR_FAILURE;
- }
- if (!mCert) {
- return NS_ERROR_FAILURE;
- }
- if (!mCert->extensions) {
- return NS_OK;
- }
- ScopedAutoSECItem keyUsageItem;
- if (CERT_FindKeyUsageExtension(mCert.get(), &keyUsageItem) != SECSuccess) {
- return PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND ? NS_OK
- : NS_ERROR_FAILURE;
- }
- unsigned char keyUsage = 0;
- if (keyUsageItem.len) {
- keyUsage = keyUsageItem.data[0];
- }
- NotNull<nsCOMPtr<nsINSSComponent>> wrappedNSSComponent =
- WrapNotNull(nssComponent);
- if (keyUsage & KU_DIGITAL_SIGNATURE) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUSign", text);
- }
- if (keyUsage & KU_NON_REPUDIATION) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUNonRep", text);
- }
- if (keyUsage & KU_KEY_ENCIPHERMENT) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUEnc", text);
- }
- if (keyUsage & KU_DATA_ENCIPHERMENT) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUDEnc", text);
- }
- if (keyUsage & KU_KEY_AGREEMENT) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUKA", text);
- }
- if (keyUsage & KU_KEY_CERT_SIGN) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUCertSign", text);
- }
- if (keyUsage & KU_CRL_SIGN) {
- AppendBundleString(wrappedNSSComponent, "CertDumpKUCRLSign", text);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetDbKey(nsACString& aDbKey)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return GetDbKey(mCert, aDbKey);
- }
- nsresult
- nsNSSCertificate::GetDbKey(const UniqueCERTCertificate& cert, nsACString& aDbKey)
- {
- static_assert(sizeof(uint64_t) == 8, "type size sanity check");
- static_assert(sizeof(uint32_t) == 4, "type size sanity check");
- // 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 buf;
- const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
- buf.Append(leadingZeroes, sizeof(leadingZeroes));
- uint32_t serialNumberLen = htonl(cert->serialNumber.len);
- buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
- sizeof(uint32_t));
- uint32_t issuerLen = htonl(cert->derIssuer.len);
- buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
- sizeof(uint32_t));
- buf.Append(BitwiseCast<char*, unsigned char*>(cert->serialNumber.data),
- cert->serialNumber.len);
- buf.Append(BitwiseCast<char*, unsigned char*>(cert->derIssuer.data),
- cert->derIssuer.len);
- return Base64Encode(buf, aDbKey);
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetWindowTitle(nsAString& aWindowTitle)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- aWindowTitle.Truncate();
- if (!mCert) {
- NS_ERROR("Somehow got nullptr for mCert in nsNSSCertificate.");
- return NS_ERROR_FAILURE;
- }
- UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
- const char* titleOptions[] = {
- mCert->nickname,
- commonName.get(),
- mCert->subjectName,
- mCert->emailAddr
- };
- nsAutoCString titleOption;
- for (size_t i = 0; i < ArrayLength(titleOptions); i++) {
- titleOption = titleOptions[i];
- if (titleOption.Length() > 0 && IsUTF8(titleOption)) {
- CopyUTF8toUTF16(titleOption, aWindowTitle);
- return NS_OK;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetNickname(nsAString& aNickname)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- if (mCert->nickname) {
- CopyUTF8toUTF16(mCert->nickname, aNickname);
- } else {
- nsresult rv;
- nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
- if (NS_FAILED(rv) || !nssComponent) {
- return NS_ERROR_FAILURE;
- }
- nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- if (mCert->emailAddr) {
- CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
- } else {
- nsresult rv;
- nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
- if (NS_FAILED(rv) || !nssComponent) {
- return NS_ERROR_FAILURE;
- }
- nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(aLength);
- NS_ENSURE_ARG(aAddresses);
- *aLength = 0;
- const char* aAddr;
- for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
- ;
- aAddr
- ;
- aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
- {
- ++(*aLength);
- }
- *aAddresses = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
- if (!*aAddresses)
- return NS_ERROR_OUT_OF_MEMORY;
- uint32_t iAddr;
- for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
- ;
- aAddr
- ;
- aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
- {
- (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
- bool* result)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(result);
- *result = false;
- const char* aAddr = nullptr;
- for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
- ;
- aAddr
- ;
- aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
- {
- NS_ConvertUTF8toUTF16 certAddr(aAddr);
- ToLowerCase(certAddr);
- nsAutoString testAddr(aEmailAddress);
- ToLowerCase(testAddr);
- if (certAddr == testAddr)
- {
- *result = true;
- break;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetCommonName(nsAString& aCommonName)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aCommonName.Truncate();
- if (mCert) {
- UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
- if (commonName) {
- aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetOrganization(nsAString& aOrganization)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aOrganization.Truncate();
- if (mCert) {
- UniquePORTString organization(CERT_GetOrgName(&mCert->subject));
- if (organization) {
- aOrganization = NS_ConvertUTF8toUTF16(organization.get());
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aCommonName.Truncate();
- if (mCert) {
- UniquePORTString commonName(CERT_GetCommonName(&mCert->issuer));
- if (commonName) {
- aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aOrganization.Truncate();
- if (mCert) {
- UniquePORTString organization(CERT_GetOrgName(&mCert->issuer));
- if (organization) {
- aOrganization = NS_ConvertUTF8toUTF16(organization.get());
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aOrganizationUnit.Truncate();
- if (mCert) {
- UniquePORTString organizationUnit(CERT_GetOrgUnitName(&mCert->issuer));
- if (organizationUnit) {
- aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit.get());
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(aIssuer);
- *aIssuer = nullptr;
- nsCOMPtr<nsIArray> chain;
- nsresult rv;
- rv = GetChain(getter_AddRefs(chain));
- NS_ENSURE_SUCCESS(rv, rv);
- uint32_t length;
- if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) {
- return NS_ERROR_UNEXPECTED;
- }
- if (length == 1) { // No known issuer
- return NS_OK;
- }
- nsCOMPtr<nsIX509Cert> cert;
- chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert));
- if (!cert) {
- return NS_ERROR_UNEXPECTED;
- }
- cert.forget(aIssuer);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aOrganizationalUnit.Truncate();
- if (mCert) {
- UniquePORTString orgunit(CERT_GetOrgUnitName(&mCert->subject));
- if (orgunit) {
- aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit.get());
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetChain(nsIArray** _rvChain)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(_rvChain);
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Getting chain for \"%s\"\n", mCert->nickname));
- mozilla::pkix::Time now(mozilla::pkix::Now());
- RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
- NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
- UniqueCERTCertList nssChain;
- // We want to test all usages, but we start with server because most of the
- // time Firefox users care about server certs.
- if (certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, now,
- nullptr, /*XXX fixme*/
- nullptr, /* hostname */
- nssChain,
- CertVerifier::FLAG_LOCAL_ONLY)
- != mozilla::pkix::Success) {
- nssChain = nullptr;
- // keep going
- }
- // This is the whitelist of all non-SSLServer usages that are supported by
- // verifycert.
- const int otherUsagesToTest = certificateUsageSSLClient |
- certificateUsageSSLCA |
- certificateUsageEmailSigner |
- certificateUsageEmailRecipient |
- certificateUsageObjectSigner |
- certificateUsageStatusResponder;
- for (int usage = certificateUsageSSLClient;
- usage < certificateUsageAnyCA && !nssChain;
- usage = usage << 1) {
- if ((usage & otherUsagesToTest) == 0) {
- continue;
- }
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("pipnss: PKIX attempting chain(%d) for '%s'\n",
- usage, mCert->nickname));
- if (certVerifier->VerifyCert(mCert.get(), usage, now,
- nullptr, /*XXX fixme*/
- nullptr, /*hostname*/
- nssChain,
- CertVerifier::FLAG_LOCAL_ONLY)
- != mozilla::pkix::Success) {
- nssChain = nullptr;
- // keep going
- }
- }
- if (!nssChain) {
- // There is not verified path for the chain, however we still want to
- // present to the user as much of a possible chain as possible, in the case
- // where there was a problem with the cert or the issuers.
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("pipnss: getchain :CertVerify failed to get chain for '%s'\n",
- mCert->nickname));
- nssChain = UniqueCERTCertList(
- CERT_GetCertChainFromCert(mCert.get(), PR_Now(), certUsageSSLClient));
- }
- if (!nssChain) {
- return NS_ERROR_FAILURE;
- }
- // enumerate the chain for scripting purposes
- nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
- if (!array) {
- return NS_ERROR_FAILURE;
- }
- CERTCertListNode* node;
- for (node = CERT_LIST_HEAD(nssChain.get());
- !CERT_LIST_END(node, nssChain.get());
- node = CERT_LIST_NEXT(node)) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("adding %s to chain\n", node->cert->nickname));
- nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
- array->AppendElement(cert, false);
- }
- *_rvChain = array;
- NS_IF_ADDREF(*_rvChain);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetAllTokenNames(uint32_t* aLength, char16_t*** aTokenNames)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(aLength);
- NS_ENSURE_ARG(aTokenNames);
- *aLength = 0;
- *aTokenNames = nullptr;
- // Get the slots from NSS
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Getting slots for \"%s\"\n", mCert->nickname));
- UniquePK11SlotList slots(PK11_GetAllSlotsForCert(mCert.get(), nullptr));
- if (!slots) {
- if (PORT_GetError() == SEC_ERROR_NO_TOKEN) {
- return NS_OK; // List of slots is empty, return empty array
- }
- return NS_ERROR_FAILURE;
- }
- // read the token names from slots
- PK11SlotListElement* le;
- for (le = slots->head; le; le = le->next) {
- ++(*aLength);
- }
- *aTokenNames = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
- if (!*aTokenNames) {
- *aLength = 0;
- return NS_ERROR_OUT_OF_MEMORY;
- }
- uint32_t iToken;
- for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) {
- char* token = PK11_GetTokenName(le->slot);
- (*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token));
- if (!(*aTokenNames)[iToken]) {
- NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames);
- *aLength = 0;
- *aTokenNames = nullptr;
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- _subjectName.Truncate();
- if (mCert->subjectName) {
- _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- _issuerName.Truncate();
- if (mCert->issuerName) {
- _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- _serialNumber.Truncate();
- UniquePORTString tmpstr(CERT_Hexify(&mCert->serialNumber, 1));
- if (tmpstr) {
- _serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
- return NS_OK;
- }
- return NS_ERROR_FAILURE;
- }
- nsresult
- nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- aFingerprint.Truncate();
- Digest digest;
- nsresult rv = digest.DigestBuf(aHashAlg, mCert->derCert.data,
- mCert->derCert.len);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // CERT_Hexify's second argument is an int that is interpreted as a boolean
- UniquePORTString fpStr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
- if (!fpStr) {
- return NS_ERROR_FAILURE;
- }
- aFingerprint.AssignASCII(fpStr.get());
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
- {
- return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
- {
- return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetTokenName(nsAString& aTokenName)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- aTokenName.Truncate();
- if (mCert) {
- // HACK alert
- // When the trust of a builtin cert is modified, NSS copies it into the
- // cert db. At this point, it is now "managed" by the user, and should
- // not be listed with the builtins. However, in the collection code
- // used by PK11_ListCerts, the cert is found in the temp db, where it
- // has been loaded from the token. Though the trust is correct (grabbed
- // from the cert db), the source is wrong. I believe this is a safe
- // way to work around this.
- if (mCert->slot) {
- char* token = PK11_GetTokenName(mCert->slot);
- if (token) {
- aTokenName = NS_ConvertUTF8toUTF16(token);
- }
- } else {
- nsresult rv;
- nsAutoString tok;
- nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
- if (NS_FAILED(rv)) return rv;
- rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
- if (NS_SUCCEEDED(rv))
- aTokenName = tok;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- aSha256SPKIDigest.Truncate();
- Digest digest;
- nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
- mCert->derPublicKey.len);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = Base64Encode(nsDependentCSubstring(
- BitwiseCast<char*, unsigned char*>(digest.get().data),
- digest.get().len),
- aSha256SPKIDigest);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- if (mCert) {
- *aArray = (uint8_t*)moz_xmalloc(mCert->derCert.len);
- if (*aArray) {
- memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
- *aLength = mCert->derCert.len;
- return NS_OK;
- }
- }
- *aLength = 0;
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
- uint32_t* aLength, uint8_t** aArray)
- {
- NS_ENSURE_ARG(aLength);
- NS_ENSURE_ARG(aArray);
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- if (!mCert)
- return NS_ERROR_FAILURE;
- switch (chainMode) {
- case nsIX509Cert::CMS_CHAIN_MODE_CertOnly:
- case nsIX509Cert::CMS_CHAIN_MODE_CertChain:
- case nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot:
- break;
- default:
- return NS_ERROR_INVALID_ARG;
- }
- UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
- if (!cmsg) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
- return NS_ERROR_OUT_OF_MEMORY;
- }
- // first, create SignedData with the certificate only (no chain)
- UniqueNSSCMSSignedData sigd(
- NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), mCert.get(), false));
- if (!sigd) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
- return NS_ERROR_FAILURE;
- }
- // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
- // to specify the inclusion of the root, but CERT_CertChainFromCert() does.
- // Since CERT_CertChainFromCert() also includes the certificate itself,
- // we have to start at the issuing cert (to avoid duplicate certs
- // in the SignedData).
- if (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChain ||
- chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot) {
- UniqueCERTCertificate issuerCert(
- CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
- // the issuerCert of a self signed root is the cert itself,
- // so make sure we're not adding duplicates, again
- if (issuerCert && issuerCert != mCert) {
- bool includeRoot =
- (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot);
- UniqueCERTCertificateList certChain(
- CERT_CertChainFromCert(issuerCert.get(), certUsageAnyCA, includeRoot));
- if (certChain) {
- if (NSS_CMSSignedData_AddCertList(sigd.get(), certChain.get())
- == SECSuccess) {
- Unused << certChain.release();
- }
- else {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
- return NS_ERROR_FAILURE;
- }
- }
- else {
- // try to add the issuerCert, at least
- if (NSS_CMSSignedData_AddCertificate(sigd.get(), issuerCert.get())
- == SECSuccess) {
- Unused << issuerCert.release();
- }
- else {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
- return NS_ERROR_FAILURE;
- }
- }
- }
- }
- NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get());
- if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get())
- == SECSuccess) {
- Unused << sigd.release();
- }
- else {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
- return NS_ERROR_FAILURE;
- }
- UniquePLArenaPool arena(PORT_NewArena(1024));
- if (!arena) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
- return NS_ERROR_OUT_OF_MEMORY;
- }
- SECItem certP7 = { siBuffer, nullptr, 0 };
- NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg.get(), nullptr, nullptr,
- &certP7, arena.get(), nullptr,
- nullptr, nullptr, nullptr,
- nullptr, nullptr);
- if (!ecx) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
- return NS_ERROR_FAILURE;
- }
- if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
- return NS_ERROR_FAILURE;
- }
- *aArray = (uint8_t*)moz_xmalloc(certP7.len);
- if (!*aArray)
- return NS_ERROR_OUT_OF_MEMORY;
- memcpy(*aArray, certP7.data, certP7.len);
- *aLength = certP7.len;
- return NS_OK;
- }
- CERTCertificate*
- nsNSSCertificate::GetCert()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return nullptr;
- return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(aValidity);
- if (!mCert) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIX509CertValidity> validity = new nsX509CertValidity(mCert);
- validity.forget(aValidity);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
- {
- NS_ENSURE_ARG_POINTER(aASN1Structure);
- return CreateASN1Struct(aASN1Structure);
- }
- NS_IMETHODIMP
- nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown())
- return NS_ERROR_NOT_AVAILABLE;
- NS_ENSURE_ARG(other);
- NS_ENSURE_ARG(result);
- UniqueCERTCertificate cert(other->GetCert());
- *result = (mCert.get() == cert.get());
- return NS_OK;
- }
- namespace mozilla {
- // TODO(bug 1036065): It seems like we only construct CERTCertLists for the
- // purpose of constructing nsNSSCertLists, so maybe we should change this
- // function to output an nsNSSCertList instead.
- SECStatus
- ConstructCERTCertListFromReversedDERArray(
- const mozilla::pkix::DERArray& certArray,
- /*out*/ UniqueCERTCertList& certList)
- {
- certList = UniqueCERTCertList(CERT_NewCertList());
- if (!certList) {
- return SECFailure;
- }
- CERTCertDBHandle* certDB(CERT_GetDefaultCertDB()); // non-owning
- size_t numCerts = certArray.GetLength();
- for (size_t i = 0; i < numCerts; ++i) {
- SECItem certDER(UnsafeMapInputToSECItem(*certArray.GetDER(i)));
- UniqueCERTCertificate cert(CERT_NewTempCertificate(certDB, &certDER,
- nullptr, false, true));
- if (!cert) {
- return SECFailure;
- }
- // certArray is ordered with the root first, but we want the resulting
- // certList to have the root last.
- if (CERT_AddCertToListHead(certList.get(), cert.get()) != SECSuccess) {
- return SECFailure;
- }
- Unused << cert.release(); // cert is now owned by certList.
- }
- return SECSuccess;
- }
- } // namespace mozilla
- NS_IMPL_CLASSINFO(nsNSSCertList,
- nullptr,
- // inferred from nsIX509Cert
- nsIClassInfo::THREADSAFE,
- NS_X509CERTLIST_CID)
- NS_IMPL_ISUPPORTS_CI(nsNSSCertList,
- nsIX509CertList,
- nsISerializable)
- nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList,
- const nsNSSShutDownPreventionLock& proofOfLock)
- {
- if (certList) {
- mCertList = Move(certList);
- } else {
- mCertList = UniqueCERTCertList(CERT_NewCertList());
- }
- }
- nsNSSCertList::nsNSSCertList()
- {
- mCertList = UniqueCERTCertList(CERT_NewCertList());
- }
- nsNSSCertList::~nsNSSCertList()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
- }
- void nsNSSCertList::virtualDestroyNSSReference()
- {
- destructorSafeDestroyNSSReference();
- }
- void nsNSSCertList::destructorSafeDestroyNSSReference()
- {
- mCertList = nullptr;
- }
- NS_IMETHODIMP
- nsNSSCertList::AddCert(nsIX509Cert* aCert)
- {
- if (!aCert) {
- return NS_ERROR_INVALID_ARG;
- }
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- CERTCertificate* cert = aCert->GetCert();
- if (!cert) {
- NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
- return NS_ERROR_FAILURE;
- }
- if (!mCertList) {
- NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
- return NS_ERROR_FAILURE;
- }
- // XXX: check return value!
- CERT_AddCertToListTail(mCertList.get(), cert);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- CERTCertificate* cert = aCert->GetCert();
- CERTCertListNode* node;
- if (!cert) {
- NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
- return NS_ERROR_FAILURE;
- }
- if (!mCertList) {
- NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
- return NS_ERROR_FAILURE;
- }
- for (node = CERT_LIST_HEAD(mCertList.get());
- !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) {
- if (node->cert == cert) {
- CERT_RemoveCertListNode(node);
- return NS_OK;
- }
- }
- return NS_OK; // XXX Should we fail if we couldn't find it?
- }
- UniqueCERTCertList
- nsNSSCertList::DupCertList(const UniqueCERTCertList& certList,
- const nsNSSShutDownPreventionLock& /*proofOfLock*/)
- {
- if (!certList) {
- return nullptr;
- }
- UniqueCERTCertList newList(CERT_NewCertList());
- if (!newList) {
- return nullptr;
- }
- for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
- !CERT_LIST_END(node, certList);
- node = CERT_LIST_NEXT(node)) {
- UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
- if (!cert) {
- return nullptr;
- }
- if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) {
- return nullptr;
- }
- Unused << cert.release(); // Ownership transferred to the cert list.
- }
- return newList;
- }
- CERTCertList*
- nsNSSCertList::GetRawCertList()
- {
- // This function should only be called after acquiring a
- // nsNSSShutDownPreventionLock. It's difficult to enforce this in code since
- // this is an implementation of an XPCOM interface function (albeit a
- // C++-only one), so we acquire the (reentrant) lock and check for shutdown
- // ourselves here. At the moment it appears that only nsCertTree uses this
- // function. When that gets removed and replaced by a more reasonable
- // implementation of the certificate manager, this function can be removed.
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return nullptr;
- }
- return mCertList.get();
- }
- NS_IMETHODIMP
- nsNSSCertList::Write(nsIObjectOutputStream* aStream)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_STATE(mCertList);
- nsresult rv = NS_OK;
- // First, enumerate the certs to get the length of the list
- uint32_t certListLen = 0;
- CERTCertListNode* node = nullptr;
- for (node = CERT_LIST_HEAD(mCertList);
- !CERT_LIST_END(node, mCertList);
- node = CERT_LIST_NEXT(node), ++certListLen) {
- }
- // Write the length of the list
- rv = aStream->Write32(certListLen);
- // Repeat the loop, and serialize each certificate
- node = nullptr;
- for (node = CERT_LIST_HEAD(mCertList);
- !CERT_LIST_END(node, mCertList);
- node = CERT_LIST_NEXT(node))
- {
- nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
- if (!cert) {
- rv = NS_ERROR_OUT_OF_MEMORY;
- break;
- }
- nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
- rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert), true);
- if (NS_FAILED(rv)) {
- break;
- }
- }
- return rv;
- }
- NS_IMETHODIMP
- nsNSSCertList::Read(nsIObjectInputStream* aStream)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_STATE(mCertList);
- nsresult rv = NS_OK;
- uint32_t certListLen;
- rv = aStream->Read32(&certListLen);
- if (NS_FAILED(rv)) {
- return rv;
- }
- for(uint32_t i = 0; i < certListLen; ++i) {
- nsCOMPtr<nsISupports> certSupports;
- rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
- if (!cert) {
- return NS_ERROR_UNEXPECTED;
- }
- rv = AddCert(cert);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- if (!mCertList) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsISimpleEnumerator> enumerator =
- new nsNSSCertListEnumerator(mCertList, locker);
- enumerator.forget(_retval);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertList::Equals(nsIX509CertList* other, bool* result)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_ARG(result);
- *result = true;
- nsresult rv;
- nsCOMPtr<nsISimpleEnumerator> selfEnumerator;
- rv = GetEnumerator(getter_AddRefs(selfEnumerator));
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCOMPtr<nsISimpleEnumerator> otherEnumerator;
- rv = other->GetEnumerator(getter_AddRefs(otherEnumerator));
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCOMPtr<nsISupports> selfSupports;
- nsCOMPtr<nsISupports> otherSupports;
- while (NS_SUCCEEDED(selfEnumerator->GetNext(getter_AddRefs(selfSupports)))) {
- if (NS_SUCCEEDED(otherEnumerator->GetNext(getter_AddRefs(otherSupports)))) {
- nsCOMPtr<nsIX509Cert> selfCert = do_QueryInterface(selfSupports);
- nsCOMPtr<nsIX509Cert> otherCert = do_QueryInterface(otherSupports);
- bool certsEqual = false;
- rv = selfCert->Equals(otherCert, &certsEqual);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!certsEqual) {
- *result = false;
- break;
- }
- } else {
- // other is shorter than self
- *result = false;
- break;
- }
- }
- // Make sure self is the same length as other
- bool otherHasMore = false;
- rv = otherEnumerator->HasMoreElements(&otherHasMore);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (otherHasMore) {
- *result = false;
- }
- return NS_OK;
- }
- NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
- nsNSSCertListEnumerator::nsNSSCertListEnumerator(
- const UniqueCERTCertList& certList,
- const nsNSSShutDownPreventionLock& proofOfLock)
- {
- MOZ_ASSERT(certList);
- mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
- }
- nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
- }
- void nsNSSCertListEnumerator::virtualDestroyNSSReference()
- {
- destructorSafeDestroyNSSReference();
- }
- void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference()
- {
- mCertList = nullptr;
- }
- NS_IMETHODIMP
- nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
- *_retval = !CERT_LIST_EMPTY(mCertList);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
- CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
- if (CERT_LIST_END(node, mCertList)) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
- if (!nssCert) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nssCert.forget(_retval);
- CERT_RemoveCertListNode(node);
- return NS_OK;
- }
- // NB: This serialization must match that of nsNSSCertificateFakeTransport.
- NS_IMETHODIMP
- nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
- {
- NS_ENSURE_STATE(mCert);
- // This field used to be the cached EV status, but it is no longer necessary.
- nsresult rv = aStream->Write32(0);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = aStream->Write32(mCert->derCert.len);
- if (NS_FAILED(rv)) {
- return rv;
- }
- return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
- }
- NS_IMETHODIMP
- nsNSSCertificate::Read(nsIObjectInputStream* aStream)
- {
- NS_ENSURE_STATE(!mCert);
- // This field is no longer used.
- uint32_t unusedCachedEVStatus;
- nsresult rv = aStream->Read32(&unusedCachedEVStatus);
- if (NS_FAILED(rv)) {
- return rv;
- }
- uint32_t len;
- rv = aStream->Read32(&len);
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsXPIDLCString str;
- rv = aStream->ReadBytes(len, getter_Copies(str));
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!InitFromDER(const_cast<char*>(str.get()), len)) {
- return NS_ERROR_UNEXPECTED;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
- {
- *count = 0;
- *array = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval)
- {
- *_retval = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetContractID(char** aContractID)
- {
- *aContractID = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetClassDescription(char** aClassDescription)
- {
- *aClassDescription = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetClassID(nsCID** aClassID)
- {
- *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
- if (!*aClassID)
- return NS_ERROR_OUT_OF_MEMORY;
- return GetClassIDNoAlloc(*aClassID);
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetFlags(uint32_t* aFlags)
- {
- *aFlags = nsIClassInfo::THREADSAFE;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
- {
- static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
- *aClassIDNoAlloc = kNSSCertificateCID;
- return NS_OK;
- }
|