LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNSSCertificate.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 79 591 13.4 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsNSSCertificate.h"
       7             : 
       8             : #include "CertVerifier.h"
       9             : #include "ExtendedValidation.h"
      10             : #include "NSSCertDBTrustDomain.h"
      11             : #include "certdb.h"
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/Base64.h"
      14             : #include "mozilla/Casting.h"
      15             : #include "mozilla/NotNull.h"
      16             : #include "mozilla/Unused.h"
      17             : #include "nsArray.h"
      18             : #include "nsCOMPtr.h"
      19             : #include "nsICertificateDialogs.h"
      20             : #include "nsIClassInfoImpl.h"
      21             : #include "nsIObjectInputStream.h"
      22             : #include "nsIObjectOutputStream.h"
      23             : #include "nsISupportsPrimitives.h"
      24             : #include "nsIURI.h"
      25             : #include "nsIX509Cert.h"
      26             : #include "nsNSSASN1Object.h"
      27             : #include "nsNSSCertHelper.h"
      28             : #include "nsNSSCertValidity.h"
      29             : #include "nsPK11TokenDB.h"
      30             : #include "nsPKCS12Blob.h"
      31             : #include "nsProxyRelease.h"
      32             : #include "nsReadableUtils.h"
      33             : #include "nsString.h"
      34             : #include "nsThreadUtils.h"
      35             : #include "nsUnicharUtils.h"
      36             : #include "nspr.h"
      37             : #include "pkix/pkixnss.h"
      38             : #include "pkix/pkixtypes.h"
      39             : #include "pkix/Result.h"
      40             : #include "prerror.h"
      41             : #include "secasn1.h"
      42             : #include "secder.h"
      43             : #include "secerr.h"
      44             : #include "ssl.h"
      45             : 
      46             : #ifdef XP_WIN
      47             : #include <winsock.h> // for htonl
      48             : #endif
      49             : 
      50             : using namespace mozilla;
      51             : using namespace mozilla::psm;
      52             : 
      53             : extern LazyLogModule gPIPNSSLog;
      54             : 
      55             : // This is being stored in an uint32_t that can otherwise
      56             : // only take values from nsIX509Cert's list of cert types.
      57             : // As nsIX509Cert is frozen, we choose a value not contained
      58             : // in the list to mean not yet initialized.
      59             : #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
      60             : 
      61         152 : NS_IMPL_ISUPPORTS(nsNSSCertificate,
      62             :                   nsIX509Cert,
      63             :                   nsISerializable,
      64             :                   nsIClassInfo)
      65             : 
      66             : /*static*/ nsNSSCertificate*
      67          12 : nsNSSCertificate::Create(CERTCertificate* cert)
      68             : {
      69          12 :   if (cert)
      70           0 :     return new nsNSSCertificate(cert);
      71             :   else
      72           0 :     return new nsNSSCertificate();
      73             : }
      74             : 
      75             : nsNSSCertificate*
      76           0 : nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
      77             : {
      78           0 :   nsNSSCertificate* newObject = nsNSSCertificate::Create();
      79           0 :   if (newObject && !newObject->InitFromDER(certDER, derLen)) {
      80           0 :     delete newObject;
      81             :     newObject = nullptr;
      82             :   }
      83             : 
      84           0 :   return newObject;
      85             : }
      86             : 
      87             : bool
      88           0 : nsNSSCertificate::InitFromDER(char* certDER, int derLen)
      89             : {
      90           0 :   if (!certDER || !derLen)
      91             :     return false;
      92             : 
      93           0 :   CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
      94             : 
      95           0 :   if (!aCert)
      96             :     return false;
      97             : 
      98           0 :   if (!aCert->dbhandle)
      99             :   {
     100           0 :     aCert->dbhandle = CERT_GetDefaultCertDB();
     101             :   }
     102             : 
     103           0 :   mCert.reset(aCert);
     104           0 :   GetSubjectAltNames();
     105           0 :   return true;
     106             : }
     107             : 
     108           0 : nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
     109             :   : mCert(nullptr)
     110             :   , mPermDelete(false)
     111             :   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
     112          84 :   , mSubjectAltNames()
     113             : {
     114          12 :   if (cert) {
     115           0 :     mCert.reset(CERT_DupCertificate(cert));
     116          12 :     GetSubjectAltNames();
     117             :   }
     118           0 : }
     119             : 
     120           0 : nsNSSCertificate::nsNSSCertificate()
     121             :   : mCert(nullptr)
     122             :   , mPermDelete(false)
     123             :   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
     124           0 :   , mSubjectAltNames()
     125             : {
     126           0 : }
     127             : 
     128          36 : nsNSSCertificate::~nsNSSCertificate()
     129             : {
     130          12 :   if (mPermDelete) {
     131           0 :     if (mCertType == nsNSSCertificate::USER_CERT) {
     132           0 :       nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
     133           0 :       PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
     134           0 :     } else if (mCert->slot && !PK11_IsReadOnly(mCert->slot)) {
     135             :       // If the list of built-ins does contain a non-removable
     136             :       // copy of this certificate, our call will not remove
     137             :       // the certificate permanently, but rather remove all trust.
     138           0 :       SEC_DeletePermCertificate(mCert.get());
     139             :     }
     140             :   }
     141           0 : }
     142             : 
     143             : nsresult
     144           0 : nsNSSCertificate::GetCertType(uint32_t* aCertType)
     145             : {
     146           0 :   if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
     147             :      // only determine cert type once and cache it
     148           0 :      mCertType = getCertType(mCert.get());
     149             :   }
     150           0 :   *aCertType = mCertType;
     151           0 :   return NS_OK;
     152             : }
     153             : 
     154             : NS_IMETHODIMP
     155           0 : nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
     156             : {
     157           0 :   NS_ENSURE_ARG(aIsSelfSigned);
     158             : 
     159           0 :   *aIsSelfSigned = mCert->isRoot;
     160           0 :   return NS_OK;
     161             : }
     162             : 
     163             : NS_IMETHODIMP
     164           2 : nsNSSCertificate::GetIsBuiltInRoot(bool* aIsBuiltInRoot)
     165             : {
     166           2 :   NS_ENSURE_ARG(aIsBuiltInRoot);
     167             : 
     168           4 :   pkix::Result rv = IsCertBuiltInRoot(mCert.get(), *aIsBuiltInRoot);
     169           0 :   if (rv != pkix::Result::Success) {
     170             :     return NS_ERROR_FAILURE;
     171             :   }
     172           0 :   return NS_OK;
     173             : }
     174             : 
     175             : nsresult
     176           0 : nsNSSCertificate::MarkForPermDeletion()
     177             : {
     178             :   // make sure user is logged in to the token
     179           0 :   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
     180             : 
     181           0 :   if (mCert->slot && PK11_NeedLogin(mCert->slot) &&
     182           0 :       !PK11_NeedUserInit(mCert->slot) && !PK11_IsInternal(mCert->slot)) {
     183           0 :     if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) {
     184             :       return NS_ERROR_FAILURE;
     185             :     }
     186             :   }
     187             : 
     188           0 :   mPermDelete = true;
     189           0 :   return NS_OK;
     190             : }
     191             : 
     192             : /**
     193             :  * Appends a pipnss bundle string to the given string.
     194             :  *
     195             :  * @param bundleKey Key for the string to append.
     196             :  * @param currentText The text to append to, using commas as separators.
     197             :  */
     198             : template<size_t N>
     199             : void
     200           0 : AppendBundleStringCommaSeparated(const char (&bundleKey)[N],
     201             :                       /*in/out*/ nsAString& currentText)
     202             : {
     203           0 :   nsAutoString bundleString;
     204           0 :   nsresult rv = GetPIPNSSBundleString(bundleKey, bundleString);
     205           0 :   if (NS_FAILED(rv)) {
     206           0 :     return;
     207             :   }
     208             : 
     209           0 :   if (!currentText.IsEmpty()) {
     210           0 :     currentText.Append(',');
     211             :   }
     212           0 :   currentText.Append(bundleString);
     213             : }
     214             : 
     215             : NS_IMETHODIMP
     216           0 : nsNSSCertificate::GetKeyUsages(nsAString& text)
     217             : {
     218           0 :   text.Truncate();
     219             : 
     220           0 :   if (!mCert) {
     221             :     return NS_ERROR_FAILURE;
     222             :   }
     223             : 
     224           0 :   if (!mCert->extensions) {
     225             :     return NS_OK;
     226             :   }
     227             : 
     228           0 :   ScopedAutoSECItem keyUsageItem;
     229           0 :   if (CERT_FindKeyUsageExtension(mCert.get(), &keyUsageItem) != SECSuccess) {
     230           0 :     return PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND ? NS_OK
     231             :                                                             : NS_ERROR_FAILURE;
     232             :   }
     233             : 
     234           0 :   unsigned char keyUsage = 0;
     235           0 :   if (keyUsageItem.len) {
     236           0 :     keyUsage = keyUsageItem.data[0];
     237             :   }
     238             : 
     239           0 :   if (keyUsage & KU_DIGITAL_SIGNATURE) {
     240           0 :     AppendBundleStringCommaSeparated("CertDumpKUSign", text);
     241             :   }
     242           0 :   if (keyUsage & KU_NON_REPUDIATION) {
     243           0 :     AppendBundleStringCommaSeparated("CertDumpKUNonRep", text);
     244             :   }
     245           0 :   if (keyUsage & KU_KEY_ENCIPHERMENT) {
     246           0 :     AppendBundleStringCommaSeparated("CertDumpKUEnc", text);
     247             :   }
     248           0 :   if (keyUsage & KU_DATA_ENCIPHERMENT) {
     249           0 :     AppendBundleStringCommaSeparated("CertDumpKUDEnc", text);
     250             :   }
     251           0 :   if (keyUsage & KU_KEY_AGREEMENT) {
     252           0 :     AppendBundleStringCommaSeparated("CertDumpKUKA", text);
     253             :   }
     254           0 :   if (keyUsage & KU_KEY_CERT_SIGN) {
     255           0 :     AppendBundleStringCommaSeparated("CertDumpKUCertSign", text);
     256             :   }
     257           0 :   if (keyUsage & KU_CRL_SIGN) {
     258           0 :     AppendBundleStringCommaSeparated("CertDumpKUCRLSign", text);
     259             :   }
     260             : 
     261             :   return NS_OK;
     262             : }
     263             : 
     264             : NS_IMETHODIMP
     265           0 : nsNSSCertificate::GetDbKey(nsACString& aDbKey)
     266             : {
     267           0 :   return GetDbKey(mCert, aDbKey);
     268             : }
     269             : 
     270             : nsresult
     271           0 : nsNSSCertificate::GetDbKey(const UniqueCERTCertificate& cert, nsACString& aDbKey)
     272             : {
     273             :   static_assert(sizeof(uint64_t) == 8, "type size sanity check");
     274             :   static_assert(sizeof(uint32_t) == 4, "type size sanity check");
     275             :   // The format of the key is the base64 encoding of the following:
     276             :   // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
     277             :   //                        never implemented)
     278             :   // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
     279             :   //                        never implemented)
     280             :   // 4 bytes: <serial number length in big-endian order>
     281             :   // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
     282             :   // n bytes: <bytes of serial number>
     283             :   // m bytes: <DER-encoded issuer distinguished name>
     284           0 :   nsAutoCString buf;
     285           0 :   const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
     286           0 :   buf.Append(leadingZeroes, sizeof(leadingZeroes));
     287           0 :   uint32_t serialNumberLen = htonl(cert->serialNumber.len);
     288           0 :   buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
     289           0 :              sizeof(uint32_t));
     290           0 :   uint32_t issuerLen = htonl(cert->derIssuer.len);
     291           0 :   buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
     292           0 :              sizeof(uint32_t));
     293           0 :   buf.Append(BitwiseCast<char*, unsigned char*>(cert->serialNumber.data),
     294           0 :              cert->serialNumber.len);
     295           0 :   buf.Append(BitwiseCast<char*, unsigned char*>(cert->derIssuer.data),
     296           0 :              cert->derIssuer.len);
     297             : 
     298           0 :   return Base64Encode(buf, aDbKey);
     299             : }
     300             : 
     301             : NS_IMETHODIMP
     302           0 : nsNSSCertificate::GetDisplayName(nsAString& aDisplayName)
     303             : {
     304           0 :   aDisplayName.Truncate();
     305             : 
     306           0 :   MOZ_ASSERT(mCert, "mCert should not be null in GetDisplayName");
     307           0 :   if (!mCert) {
     308             :     return NS_ERROR_FAILURE;
     309             :   }
     310             : 
     311           0 :   UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
     312           0 :   UniquePORTString organizationalUnitName(CERT_GetOrgUnitName(&mCert->subject));
     313           0 :   UniquePORTString organizationName(CERT_GetOrgName(&mCert->subject));
     314             : 
     315             :   bool isBuiltInRoot;
     316           0 :   nsresult rv = GetIsBuiltInRoot(&isBuiltInRoot);
     317           0 :   if (NS_FAILED(rv)) {
     318             :     return rv;
     319             :   }
     320             : 
     321             :   // Only use the nickname for built-in roots where we already have a hard-coded
     322             :   // reasonable display name (unfortunately we have to strip off the leading
     323             :   // slot identifier followed by a ':'). Otherwise, attempt to use the following
     324             :   // in order:
     325             :   //  - the common name, if present
     326             :   //  - an organizational unit name, if present
     327             :   //  - an organization name, if present
     328             :   //  - the entire subject distinguished name, if non-empty
     329             :   //  - an email address, if one can be found
     330             :   // In the unlikely event that none of these fields are present and non-empty
     331             :   // (the subject really shouldn't be empty), an empty string is returned.
     332           0 :   nsAutoCString builtInRootNickname;
     333           0 :   if (isBuiltInRoot) {
     334           0 :     nsAutoCString fullNickname(mCert->nickname);
     335           0 :     int32_t index = fullNickname.Find(":");
     336           0 :     if (index != kNotFound) {
     337             :       // Substring will gracefully handle the case where index is the last
     338             :       // character in the string (that is, if the nickname is just
     339             :       // "Builtin Object Token:"). In that case, we'll get an empty string.
     340           0 :       builtInRootNickname = Substring(fullNickname,
     341           0 :                                       AssertedCast<uint32_t>(index + 1));
     342             :     }
     343             :   }
     344             :   const char* nameOptions[] = {
     345           0 :     builtInRootNickname.get(),
     346           0 :     commonName.get(),
     347           0 :     organizationalUnitName.get(),
     348           0 :     organizationName.get(),
     349           0 :     mCert->subjectName,
     350           0 :     mCert->emailAddr
     351           0 :   };
     352             : 
     353           0 :   for (auto nameOption : nameOptions) {
     354           0 :     if (nameOption) {
     355           0 :       size_t len = strlen(nameOption);
     356           0 :       if (len > 0) {
     357           0 :         LossyUTF8ToUTF16(nameOption, len, aDisplayName);
     358           0 :         return NS_OK;
     359             :       }
     360             :     }
     361             :   }
     362             : 
     363             :   return NS_OK;
     364             : }
     365             : 
     366             : NS_IMETHODIMP
     367           0 : nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
     368             : {
     369           0 :   if (mCert->emailAddr) {
     370           0 :     LossyUTF8ToUTF16(mCert->emailAddr, strlen(mCert->emailAddr), aEmailAddress);
     371             :   } else {
     372           0 :     GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
     373             :   }
     374           0 :   return NS_OK;
     375             : }
     376             : 
     377             : NS_IMETHODIMP
     378           0 : nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
     379             : {
     380           0 :   NS_ENSURE_ARG(aLength);
     381           0 :   NS_ENSURE_ARG(aAddresses);
     382             : 
     383           0 :   *aLength = 0;
     384             : 
     385           0 :   for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
     386           0 :        aAddr;
     387           0 :        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
     388           0 :     ++(*aLength);
     389             :   }
     390             : 
     391           0 :   *aAddresses = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
     392           0 :   if (!*aAddresses) {
     393             :     return NS_ERROR_OUT_OF_MEMORY;
     394             :   }
     395             : 
     396           0 :   uint32_t iAddr = 0;
     397           0 :   for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
     398           0 :        aAddr;
     399           0 :        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
     400           0 :     (*aAddresses)[iAddr] = ToNewUnicode(nsDependentCString(aAddr));
     401           0 :     iAddr++;
     402             :   }
     403             : 
     404             :   return NS_OK;
     405             : }
     406             : 
     407             : NS_IMETHODIMP
     408           0 : nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
     409             :                                        bool* result)
     410             : {
     411           0 :   NS_ENSURE_ARG(result);
     412           0 :   *result = false;
     413             : 
     414           0 :   for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
     415           0 :        aAddr;
     416           0 :        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
     417           0 :     nsAutoString certAddr;
     418           0 :     LossyUTF8ToUTF16(aAddr, strlen(aAddr), certAddr);
     419           0 :     ToLowerCase(certAddr);
     420             : 
     421           0 :     nsAutoString testAddr(aEmailAddress);
     422           0 :     ToLowerCase(testAddr);
     423             : 
     424           0 :     if (certAddr == testAddr) {
     425           0 :       *result = true;
     426           0 :       break;
     427             :     }
     428             :   }
     429             : 
     430             :   return NS_OK;
     431             : }
     432             : 
     433             : NS_IMETHODIMP
     434           0 : nsNSSCertificate::GetCommonName(nsAString& aCommonName)
     435             : {
     436           0 :   aCommonName.Truncate();
     437           0 :   if (mCert) {
     438           0 :     UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
     439           0 :     if (commonName) {
     440           0 :       LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
     441             :     }
     442             :   }
     443           0 :   return NS_OK;
     444             : }
     445             : 
     446             : NS_IMETHODIMP
     447           0 : nsNSSCertificate::GetOrganization(nsAString& aOrganization)
     448             : {
     449           0 :   aOrganization.Truncate();
     450           0 :   if (mCert) {
     451           0 :     UniquePORTString organization(CERT_GetOrgName(&mCert->subject));
     452           0 :     if (organization) {
     453           0 :       LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
     454           0 :                        aOrganization);
     455             :     }
     456             :   }
     457           0 :   return NS_OK;
     458             : }
     459             : 
     460             : NS_IMETHODIMP
     461           0 : nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
     462             : {
     463           0 :   aCommonName.Truncate();
     464           0 :   if (mCert) {
     465           0 :     UniquePORTString commonName(CERT_GetCommonName(&mCert->issuer));
     466           0 :     if (commonName) {
     467           0 :       LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
     468             :     }
     469             :   }
     470           0 :   return NS_OK;
     471             : }
     472             : 
     473             : NS_IMETHODIMP
     474           0 : nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
     475             : {
     476           0 :   aOrganization.Truncate();
     477           0 :   if (mCert) {
     478           0 :     UniquePORTString organization(CERT_GetOrgName(&mCert->issuer));
     479           0 :     if (organization) {
     480           0 :       LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
     481           0 :                        aOrganization);
     482             :     }
     483             :   }
     484           0 :   return NS_OK;
     485             : }
     486             : 
     487             : NS_IMETHODIMP
     488           0 : nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
     489             : {
     490           0 :   aOrganizationUnit.Truncate();
     491           0 :   if (mCert) {
     492           0 :     UniquePORTString organizationUnit(CERT_GetOrgUnitName(&mCert->issuer));
     493           0 :     if (organizationUnit) {
     494           0 :       LossyUTF8ToUTF16(organizationUnit.get(), strlen(organizationUnit.get()),
     495           0 :                        aOrganizationUnit);
     496             :     }
     497             :   }
     498           0 :   return NS_OK;
     499             : }
     500             : 
     501             : NS_IMETHODIMP
     502           0 : nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
     503             : {
     504           0 :   aOrganizationalUnit.Truncate();
     505           0 :   if (mCert) {
     506           0 :     UniquePORTString orgunit(CERT_GetOrgUnitName(&mCert->subject));
     507           0 :     if (orgunit) {
     508           0 :       LossyUTF8ToUTF16(orgunit.get(), strlen(orgunit.get()),
     509           0 :                        aOrganizationalUnit);
     510             :     }
     511             :   }
     512           0 :   return NS_OK;
     513             : }
     514             : 
     515             : NS_IMETHODIMP
     516           0 : nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
     517             : {
     518           0 :   _subjectName.Truncate();
     519           0 :   if (mCert->subjectName) {
     520           0 :     LossyUTF8ToUTF16(mCert->subjectName, strlen(mCert->subjectName),
     521           0 :                      _subjectName);
     522             :   }
     523           0 :   return NS_OK;
     524             : }
     525             : 
     526             : // Reads dNSName and iPAddress entries encountered in the subject alternative
     527             : // name extension of the certificate and stores them in mSubjectAltNames.
     528             : void
     529           0 : nsNSSCertificate::GetSubjectAltNames()
     530             : {
     531          12 :   mSubjectAltNames.clear();
     532             : 
     533           0 :   ScopedAutoSECItem altNameExtension;
     534          24 :   SECStatus rv = CERT_FindCertExtension(mCert.get(),
     535             :                                         SEC_OID_X509_SUBJECT_ALT_NAME,
     536           0 :                                         &altNameExtension);
     537           0 :   if (rv != SECSuccess) {
     538             :     return;
     539             :   }
     540           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     541           2 :   if (!arena) {
     542             :     return;
     543             :   }
     544           2 :   CERTGeneralName* sanNameList(CERT_DecodeAltNameExtension(arena.get(),
     545           2 :                                                            &altNameExtension));
     546           0 :   if (!sanNameList) {
     547             :     return;
     548             :   }
     549             : 
     550             :   CERTGeneralName* current = sanNameList;
     551             :   do {
     552           4 :     nsAutoString name;
     553           0 :     switch (current->type) {
     554             :       case certDNSName:
     555             :         {
     556           2 :           nsDependentCSubstring nameFromCert(BitwiseCast<char*, unsigned char*>(
     557             :                                              current->name.other.data),
     558           0 :                                              current->name.other.len);
     559             :           // dNSName fields are defined as type IA5String and thus should
     560             :           // be limited to ASCII characters.
     561           0 :           if (IsASCII(nameFromCert)) {
     562           0 :             name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
     563           0 :             mSubjectAltNames.push_back(name);
     564             :           }
     565             :         }
     566           2 :         break;
     567             : 
     568             :       case certIPAddress:
     569             :         {
     570             :           char buf[INET6_ADDRSTRLEN];
     571             :           PRNetAddr addr;
     572           0 :           if (current->name.other.len == 4) {
     573           0 :             addr.inet.family = PR_AF_INET;
     574           0 :             memcpy(&addr.inet.ip, current->name.other.data,
     575           0 :                    current->name.other.len);
     576           0 :             PR_NetAddrToString(&addr, buf, sizeof(buf));
     577           0 :             name.AssignASCII(buf);
     578           0 :           } else if (current->name.other.len == 16) {
     579           0 :             addr.ipv6.family = PR_AF_INET6;
     580           0 :             memcpy(&addr.ipv6.ip, current->name.other.data,
     581           0 :                    current->name.other.len);
     582           0 :             PR_NetAddrToString(&addr, buf, sizeof(buf));
     583           0 :             name.AssignASCII(buf);
     584             :           } else {
     585             :             /* invalid IP address */
     586             :           }
     587           0 :           if (!name.IsEmpty()) {
     588           0 :             mSubjectAltNames.push_back(name);
     589             :           }
     590             :           break;
     591             :         }
     592             : 
     593             :       default: // all other types of names are ignored
     594             :         break;
     595             :     }
     596           1 :     current = CERT_GetNextGeneralName(current);
     597           1 :   } while (current != sanNameList); // double linked
     598             : 
     599             :   return;
     600             : }
     601             : 
     602             : NS_IMETHODIMP
     603           0 : nsNSSCertificate::GetSubjectAltNames(nsAString& _subjectAltNames)
     604             : {
     605           0 :   _subjectAltNames.Truncate();
     606             : 
     607           0 :   for (auto altName : mSubjectAltNames) {
     608           0 :     if (!_subjectAltNames.IsEmpty()) {
     609           0 :       _subjectAltNames.Append(',');
     610             :     }
     611           0 :     _subjectAltNames.Append(altName);
     612             :   }
     613           0 :   return NS_OK;
     614             : }
     615             : 
     616             : NS_IMETHODIMP
     617           0 : nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
     618             : {
     619           0 :   _issuerName.Truncate();
     620           0 :   if (mCert->issuerName) {
     621           0 :     LossyUTF8ToUTF16(mCert->issuerName, strlen(mCert->issuerName), _issuerName);
     622             :   }
     623           0 :   return NS_OK;
     624             : }
     625             : 
     626             : NS_IMETHODIMP
     627           0 : nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
     628             : {
     629           0 :   _serialNumber.Truncate();
     630           0 :   UniquePORTString tmpstr(CERT_Hexify(&mCert->serialNumber, 1));
     631           0 :   if (tmpstr) {
     632           0 :     _serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
     633           0 :     return NS_OK;
     634             :   }
     635             :   return NS_ERROR_FAILURE;
     636             : }
     637             : 
     638             : nsresult
     639           2 : nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg)
     640             : {
     641           2 :   aFingerprint.Truncate();
     642           2 :   Digest digest;
     643           4 :   nsresult rv = digest.DigestBuf(aHashAlg, mCert->derCert.data,
     644           0 :                                  mCert->derCert.len);
     645           2 :   if (NS_FAILED(rv)) {
     646             :     return rv;
     647             :   }
     648             : 
     649             :   // CERT_Hexify's second argument is an int that is interpreted as a boolean
     650           0 :   UniquePORTString fpStr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
     651           2 :   if (!fpStr) {
     652             :     return NS_ERROR_FAILURE;
     653             :   }
     654             : 
     655           2 :   aFingerprint.AssignASCII(fpStr.get());
     656           0 :   return NS_OK;
     657             : }
     658             : 
     659             : NS_IMETHODIMP
     660           0 : nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
     661             : {
     662           0 :   return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
     663             : }
     664             : 
     665             : NS_IMETHODIMP
     666           0 : nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
     667             : {
     668           0 :   return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
     669             : }
     670             : 
     671             : NS_IMETHODIMP
     672           0 : nsNSSCertificate::GetTokenName(nsAString& aTokenName)
     673             : {
     674           0 :   MOZ_ASSERT(mCert);
     675           0 :   if (!mCert) {
     676             :     return NS_ERROR_FAILURE;
     677             :   }
     678           0 :   UniquePK11SlotInfo internalSlot(PK11_GetInternalSlot());
     679           0 :   if (!internalSlot) {
     680             :     return NS_ERROR_FAILURE;
     681             :   }
     682             :   nsCOMPtr<nsIPK11Token> token(
     683           0 :     new nsPK11Token(mCert->slot ? mCert->slot : internalSlot.get()));
     684           0 :   nsAutoCString tmp;
     685           0 :   nsresult rv = token->GetTokenName(tmp);
     686           0 :   if (NS_FAILED(rv)) {
     687             :     return rv;
     688             :   }
     689           0 :   aTokenName.Assign(NS_ConvertUTF8toUTF16(tmp));
     690           0 :   return NS_OK;
     691             : }
     692             : 
     693             : NS_IMETHODIMP
     694           0 : nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
     695             : {
     696           0 :   aSha256SPKIDigest.Truncate();
     697           0 :   Digest digest;
     698           0 :   nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
     699           0 :                                  mCert->derPublicKey.len);
     700           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     701             :     return rv;
     702             :   }
     703           0 :   rv = Base64Encode(nsDependentCSubstring(
     704           0 :                       BitwiseCast<char*, unsigned char*>(digest.get().data),
     705           0 :                       digest.get().len),
     706           0 :                     aSha256SPKIDigest);
     707           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     708             :     return rv;
     709             :   }
     710           0 :   return NS_OK;
     711             : }
     712             : 
     713             : NS_IMETHODIMP
     714           0 : nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
     715             : {
     716           0 :   if (mCert) {
     717           0 :     *aArray = (uint8_t*)moz_xmalloc(mCert->derCert.len);
     718           0 :     if (*aArray) {
     719           0 :       memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
     720           0 :       *aLength = mCert->derCert.len;
     721           0 :       return NS_OK;
     722             :     }
     723             :   }
     724           0 :   *aLength = 0;
     725           0 :   return NS_ERROR_FAILURE;
     726             : }
     727             : 
     728             : CERTCertificate*
     729           0 : nsNSSCertificate::GetCert()
     730             : {
     731           0 :   return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
     732             : }
     733             : 
     734             : NS_IMETHODIMP
     735           0 : nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
     736             : {
     737           0 :   NS_ENSURE_ARG(aValidity);
     738             : 
     739           0 :   if (!mCert) {
     740             :     return NS_ERROR_FAILURE;
     741             :   }
     742             : 
     743           0 :   nsCOMPtr<nsIX509CertValidity> validity = new nsX509CertValidity(mCert);
     744           0 :   validity.forget(aValidity);
     745             :   return NS_OK;
     746             : }
     747             : 
     748             : NS_IMETHODIMP
     749           0 : nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
     750             : {
     751           0 :   NS_ENSURE_ARG_POINTER(aASN1Structure);
     752           0 :   if (!NS_IsMainThread()) {
     753             :     return NS_ERROR_NOT_SAME_THREAD;
     754             :   }
     755           0 :   return CreateASN1Struct(aASN1Structure);
     756             : }
     757             : 
     758             : NS_IMETHODIMP
     759           0 : nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
     760             : {
     761           0 :   NS_ENSURE_ARG(other);
     762           0 :   NS_ENSURE_ARG(result);
     763             : 
     764           0 :   UniqueCERTCertificate cert(other->GetCert());
     765           0 :   *result = (mCert.get() == cert.get());
     766             :   return NS_OK;
     767             : }
     768             : 
     769             : namespace mozilla {
     770             : 
     771             : // TODO(bug 1036065): It seems like we only construct CERTCertLists for the
     772             : // purpose of constructing nsNSSCertLists, so maybe we should change this
     773             : // function to output an nsNSSCertList instead.
     774             : SECStatus
     775           0 : ConstructCERTCertListFromReversedDERArray(
     776             :   const mozilla::pkix::DERArray& certArray,
     777             :   /*out*/ UniqueCERTCertList& certList)
     778             : {
     779           4 :   certList = UniqueCERTCertList(CERT_NewCertList());
     780           2 :   if (!certList) {
     781             :     return SECFailure;
     782             :   }
     783             : 
     784           2 :   CERTCertDBHandle* certDB(CERT_GetDefaultCertDB()); // non-owning
     785             : 
     786           2 :   size_t numCerts = certArray.GetLength();
     787           0 :   for (size_t i = 0; i < numCerts; ++i) {
     788           0 :     SECItem certDER(UnsafeMapInputToSECItem(*certArray.GetDER(i)));
     789             :     UniqueCERTCertificate cert(CERT_NewTempCertificate(certDB, &certDER,
     790           0 :                                                        nullptr, false, true));
     791           0 :     if (!cert) {
     792           0 :       return SECFailure;
     793             :     }
     794             :     // certArray is ordered with the root first, but we want the resulting
     795             :     // certList to have the root last.
     796          12 :     if (CERT_AddCertToListHead(certList.get(), cert.get()) != SECSuccess) {
     797             :       return SECFailure;
     798             :     }
     799           6 :     Unused << cert.release(); // cert is now owned by certList.
     800             :   }
     801             : 
     802             :   return SECSuccess;
     803             : }
     804             : 
     805             : } // namespace mozilla
     806             : 
     807             : NS_IMPL_CLASSINFO(nsNSSCertList,
     808             :                   nullptr,
     809             :                   // inferred from nsIX509Cert
     810             :                   nsIClassInfo::THREADSAFE,
     811             :                   NS_X509CERTLIST_CID)
     812             : 
     813           0 : NS_IMPL_ISUPPORTS_CI(nsNSSCertList,
     814             :                      nsIX509CertList,
     815             :                      nsISerializable)
     816             : 
     817           0 : nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList)
     818             : {
     819           2 :   if (certList) {
     820           2 :     mCertList = std::move(certList);
     821             :   } else {
     822           0 :     mCertList = UniqueCERTCertList(CERT_NewCertList());
     823             :   }
     824           2 : }
     825             : 
     826           0 : nsNSSCertList::nsNSSCertList()
     827             : {
     828           0 :   mCertList = UniqueCERTCertList(CERT_NewCertList());
     829           0 : }
     830             : 
     831             : nsNSSCertList*
     832           0 : nsNSSCertList::GetCertList()
     833             : {
     834           0 :   return this;
     835             : }
     836             : 
     837             : NS_IMETHODIMP
     838           0 : nsNSSCertList::AddCert(nsIX509Cert* aCert)
     839             : {
     840             :   // We need an owning handle when calling nsIX509Cert::GetCert().
     841           0 :   UniqueCERTCertificate cert(aCert->GetCert());
     842           0 :   if (!cert) {
     843           0 :     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
     844           0 :     return NS_ERROR_FAILURE;
     845             :   }
     846             : 
     847           0 :   if (!mCertList) {
     848           0 :     NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
     849           0 :     return NS_ERROR_FAILURE;
     850             :   }
     851           0 :   if (CERT_AddCertToListTail(mCertList.get(), cert.get()) != SECSuccess) {
     852             :     return NS_ERROR_OUT_OF_MEMORY;
     853             :   }
     854           0 :   Unused << cert.release(); // Ownership transferred to the cert list.
     855           0 :   return NS_OK;
     856             : }
     857             : 
     858             : UniqueCERTCertList
     859           6 : nsNSSCertList::DupCertList(const UniqueCERTCertList& certList)
     860             : {
     861           6 :   if (!certList) {
     862           0 :     return nullptr;
     863             :   }
     864             : 
     865          18 :   UniqueCERTCertList newList(CERT_NewCertList());
     866           6 :   if (!newList) {
     867           0 :     return nullptr;
     868             :   }
     869             : 
     870           1 :   for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
     871          22 :        !CERT_LIST_END(node, certList);
     872          16 :        node = CERT_LIST_NEXT(node)) {
     873           0 :     UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
     874           1 :     if (!cert) {
     875           0 :       return nullptr;
     876             :     }
     877             : 
     878          32 :     if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) {
     879           0 :       return nullptr;
     880             :     }
     881             : 
     882          16 :     Unused << cert.release(); // Ownership transferred to the cert list.
     883             :   }
     884             :   return newList;
     885             : }
     886             : 
     887             : CERTCertList*
     888           0 : nsNSSCertList::GetRawCertList()
     889             : {
     890           0 :   return mCertList.get();
     891             : }
     892             : 
     893             : NS_IMETHODIMP
     894           0 : nsNSSCertList::AsPKCS7Blob(/*out*/ nsACString& result)
     895             : {
     896           0 :   MOZ_ASSERT(mCertList);
     897           0 :   if (!mCertList) {
     898             :     return NS_ERROR_FAILURE;
     899             :   }
     900             : 
     901           0 :   UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
     902           0 :   if (!cmsg) {
     903           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     904             :             ("nsNSSCertList::AsPKCS7Blob - can't create CMS message"));
     905             :     return NS_ERROR_OUT_OF_MEMORY;
     906             :   }
     907             : 
     908           0 :   UniqueNSSCMSSignedData sigd(nullptr);
     909           0 :   nsresult rv = ForEachCertificateInChain(
     910             :     [&cmsg, &sigd] (nsCOMPtr<nsIX509Cert> aCert, bool /*unused*/,
     911           0 :             /*out*/ bool& /*unused*/) {
     912             :       // We need an owning handle when calling nsIX509Cert::GetCert().
     913           0 :       UniqueCERTCertificate nssCert(aCert->GetCert());
     914           0 :       if (!sigd) {
     915           0 :         sigd.reset(NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), nssCert.get(),
     916           0 :                                                      false));
     917           0 :         if (!sigd) {
     918           0 :           MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     919             :                   ("nsNSSCertList::AsPKCS7Blob - can't create SignedData"));
     920             :           return NS_ERROR_FAILURE;
     921             :         }
     922           0 :       } else if (NSS_CMSSignedData_AddCertificate(sigd.get(), nssCert.get())
     923             :                    != SECSuccess) {
     924           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     925             :                 ("nsNSSCertList::AsPKCS7Blob - can't add cert"));
     926             :         return NS_ERROR_FAILURE;
     927             :       }
     928             :       return NS_OK;
     929           0 :   });
     930           0 :   if (NS_FAILED(rv)) {
     931             :     return rv;
     932             :   }
     933             : 
     934           0 :   NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get());
     935           0 :   if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get())
     936             :         != SECSuccess) {
     937           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     938             :             ("nsNSSCertList::AsPKCS7Blob - can't attach SignedData"));
     939             :     return NS_ERROR_FAILURE;
     940             :   }
     941             :   // cmsg owns sigd now.
     942           0 :   Unused << sigd.release();
     943             : 
     944           0 :   UniquePLArenaPool arena(PORT_NewArena(1024));
     945           0 :   if (!arena) {
     946           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     947             :             ("nsNSSCertList::AsPKCS7Blob - out of memory"));
     948             :     return NS_ERROR_OUT_OF_MEMORY;
     949             :   }
     950             : 
     951           0 :   SECItem certP7 = { siBuffer, nullptr, 0 };
     952           0 :   NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg.get(), nullptr, nullptr,
     953             :                                                    &certP7, arena.get(), nullptr,
     954             :                                                    nullptr, nullptr, nullptr,
     955           0 :                                                    nullptr, nullptr);
     956           0 :   if (!ecx) {
     957           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     958             :             ("nsNSSCertList::AsPKCS7Blob - can't create encoder"));
     959             :     return NS_ERROR_FAILURE;
     960             :   }
     961             : 
     962           0 :   if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
     963           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     964             :             ("nsNSSCertList::AsPKCS7Blob - failed to add encoded data"));
     965             :     return NS_ERROR_FAILURE;
     966             :   }
     967             : 
     968           0 :   result.Assign(nsDependentCSubstring(reinterpret_cast<const char*>(certP7.data),
     969           0 :                                       certP7.len));
     970           0 :   return NS_OK;
     971             : }
     972             : 
     973             : NS_IMETHODIMP
     974           0 : nsNSSCertList::Write(nsIObjectOutputStream* aStream)
     975             : {
     976           0 :   NS_ENSURE_STATE(mCertList);
     977           0 :   nsresult rv = NS_OK;
     978             : 
     979             :   // First, enumerate the certs to get the length of the list
     980           0 :   uint32_t certListLen = 0;
     981           0 :   CERTCertListNode* node = nullptr;
     982           0 :   for (node = CERT_LIST_HEAD(mCertList);
     983           0 :        !CERT_LIST_END(node, mCertList);
     984           0 :        node = CERT_LIST_NEXT(node), ++certListLen) {
     985             :   }
     986             : 
     987             :   // Write the length of the list
     988           0 :   rv = aStream->Write32(certListLen);
     989             : 
     990             :   // Repeat the loop, and serialize each certificate
     991           0 :   node = nullptr;
     992           0 :   for (node = CERT_LIST_HEAD(mCertList);
     993           0 :        !CERT_LIST_END(node, mCertList);
     994           0 :        node = CERT_LIST_NEXT(node))
     995             :   {
     996           0 :     nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
     997           0 :     if (!cert) {
     998             :       rv = NS_ERROR_OUT_OF_MEMORY;
     999           0 :       break;
    1000             :     }
    1001             : 
    1002           0 :     nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
    1003           0 :     rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert), true);
    1004           0 :     if (NS_FAILED(rv)) {
    1005             :       break;
    1006             :     }
    1007             :   }
    1008             : 
    1009             :   return rv;
    1010             : }
    1011             : 
    1012             : NS_IMETHODIMP
    1013           0 : nsNSSCertList::Read(nsIObjectInputStream* aStream)
    1014             : {
    1015           0 :   NS_ENSURE_STATE(mCertList);
    1016           0 :   nsresult rv = NS_OK;
    1017             : 
    1018             :   uint32_t certListLen;
    1019           0 :   rv = aStream->Read32(&certListLen);
    1020           0 :   if (NS_FAILED(rv)) {
    1021             :     return rv;
    1022             :   }
    1023             : 
    1024           0 :   for(uint32_t i = 0; i < certListLen; ++i) {
    1025           0 :     nsCOMPtr<nsISupports> certSupports;
    1026           0 :     rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
    1027           0 :     if (NS_FAILED(rv)) {
    1028             :       break;
    1029             :     }
    1030             : 
    1031           0 :     nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
    1032           0 :     rv = AddCert(cert);
    1033           0 :     if (NS_FAILED(rv)) {
    1034             :       break;
    1035             :     }
    1036             :   }
    1037             : 
    1038             :   return rv;
    1039             : }
    1040             : 
    1041             : NS_IMETHODIMP
    1042           0 : nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
    1043             : {
    1044           4 :   if (!mCertList) {
    1045             :     return NS_ERROR_FAILURE;
    1046             :   }
    1047             : 
    1048             :   nsCOMPtr<nsISimpleEnumerator> enumerator =
    1049           4 :     new nsNSSCertListEnumerator(mCertList);
    1050             : 
    1051           0 :   enumerator.forget(_retval);
    1052             :   return NS_OK;
    1053             : }
    1054             : 
    1055             : NS_IMETHODIMP
    1056           0 : nsNSSCertList::Equals(nsIX509CertList* other, bool* result)
    1057             : {
    1058           0 :   NS_ENSURE_ARG(result);
    1059           0 :   *result = true;
    1060             : 
    1061             :   nsresult rv;
    1062             : 
    1063           0 :   nsCOMPtr<nsISimpleEnumerator> selfEnumerator;
    1064           0 :   rv = GetEnumerator(getter_AddRefs(selfEnumerator));
    1065           0 :   if (NS_FAILED(rv)) {
    1066             :     return rv;
    1067             :   }
    1068             : 
    1069           0 :   nsCOMPtr<nsISimpleEnumerator> otherEnumerator;
    1070           0 :   rv = other->GetEnumerator(getter_AddRefs(otherEnumerator));
    1071           0 :   if (NS_FAILED(rv)) {
    1072             :     return rv;
    1073             :   }
    1074             : 
    1075           0 :   nsCOMPtr<nsISupports> selfSupports;
    1076           0 :   nsCOMPtr<nsISupports> otherSupports;
    1077           0 :   while (NS_SUCCEEDED(selfEnumerator->GetNext(getter_AddRefs(selfSupports)))) {
    1078           0 :     if (NS_SUCCEEDED(otherEnumerator->GetNext(getter_AddRefs(otherSupports)))) {
    1079           0 :       nsCOMPtr<nsIX509Cert> selfCert = do_QueryInterface(selfSupports);
    1080           0 :       nsCOMPtr<nsIX509Cert> otherCert = do_QueryInterface(otherSupports);
    1081             : 
    1082           0 :       bool certsEqual = false;
    1083           0 :       rv = selfCert->Equals(otherCert, &certsEqual);
    1084           0 :       if (NS_FAILED(rv)) {
    1085           0 :         return rv;
    1086             :       }
    1087           0 :       if (!certsEqual) {
    1088           0 :         *result = false;
    1089           0 :         break;
    1090             :       }
    1091             :     } else {
    1092             :       // other is shorter than self
    1093           0 :       *result = false;
    1094           0 :       break;
    1095             :     }
    1096             :   }
    1097             : 
    1098             :   // Make sure self is the same length as other
    1099           0 :   bool otherHasMore = false;
    1100           0 :   rv = otherEnumerator->HasMoreElements(&otherHasMore);
    1101           0 :   if (NS_FAILED(rv)) {
    1102             :     return rv;
    1103             :   }
    1104           0 :   if (otherHasMore) {
    1105           0 :     *result = false;
    1106             :   }
    1107             : 
    1108             :   return NS_OK;
    1109             : }
    1110             : 
    1111             : nsresult
    1112           2 : nsNSSCertList::ForEachCertificateInChain(ForEachCertOperation& aOperation)
    1113             : {
    1114           1 :   nsCOMPtr<nsISimpleEnumerator> chainElt;
    1115           1 :   nsresult rv = GetEnumerator(getter_AddRefs(chainElt));
    1116           2 :   if (NS_FAILED(rv)) {
    1117             :     return rv;
    1118             :   }
    1119             : 
    1120             :   // Each chain may have multiple certificates.
    1121           2 :   bool hasMore = false;
    1122           2 :   rv = chainElt->HasMoreElements(&hasMore);
    1123           2 :   if (NS_FAILED(rv)) {
    1124             :     return rv;
    1125             :   }
    1126             : 
    1127           0 :   if (!hasMore) {
    1128             :     return NS_OK; // Empty lists are fine
    1129             :   }
    1130             : 
    1131           1 :   do {
    1132          10 :     nsCOMPtr<nsISupports> certSupports;
    1133          12 :     rv = chainElt->GetNext(getter_AddRefs(certSupports));
    1134           6 :     if (NS_FAILED(rv)) {
    1135           2 :       return rv;
    1136             :     }
    1137             : 
    1138           0 :     nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports, &rv);
    1139           6 :     if (NS_FAILED(rv)) {
    1140           0 :       return rv;
    1141             :     }
    1142             : 
    1143           6 :     rv = chainElt->HasMoreElements(&hasMore);
    1144           6 :     if (NS_FAILED(rv)) {
    1145             :       return rv;
    1146             :     }
    1147             : 
    1148           0 :     bool continueLoop = true;
    1149           0 :     rv = aOperation(cert, hasMore, continueLoop);
    1150           6 :     if (NS_FAILED(rv) || !continueLoop) {
    1151             :       return rv;
    1152             :     }
    1153             :   } while (hasMore);
    1154             : 
    1155             :   return NS_OK;
    1156             : }
    1157             : 
    1158             : nsresult
    1159           0 : nsNSSCertList::SegmentCertificateChain(/* out */ nsCOMPtr<nsIX509Cert>& aRoot,
    1160             :                           /* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
    1161             :                           /* out */ nsCOMPtr<nsIX509Cert>& aEndEntity)
    1162             : {
    1163           0 :   if (aRoot || aIntermediates || aEndEntity) {
    1164             :     // All passed-in nsCOMPtrs should be empty for the state machine to work
    1165             :     return NS_ERROR_UNEXPECTED;
    1166             :   }
    1167             : 
    1168           0 :   aIntermediates = new nsNSSCertList();
    1169             : 
    1170           0 :   nsresult rv = ForEachCertificateInChain(
    1171             :     [&aRoot, &aIntermediates, &aEndEntity] (nsCOMPtr<nsIX509Cert> aCert,
    1172           0 :                                             bool hasMore, bool& aContinue) {
    1173           0 :       if (!aEndEntity) {
    1174             :         // This is the end entity
    1175           0 :         aEndEntity = aCert;
    1176           0 :       } else if (!hasMore) {
    1177             :         // This is the root
    1178           0 :         aRoot = aCert;
    1179             :       } else {
    1180             :         // One of (potentially many) intermediates
    1181           0 :         if (NS_FAILED(aIntermediates->AddCert(aCert))) {
    1182             :           return NS_ERROR_OUT_OF_MEMORY;
    1183             :         }
    1184             :       }
    1185             : 
    1186             :       return NS_OK;
    1187           0 :   });
    1188             : 
    1189           0 :   if (NS_FAILED(rv)) {
    1190             :     return rv;
    1191             :   }
    1192             : 
    1193           0 :   if (!aRoot || !aEndEntity) {
    1194             :     // No self-signed (or empty) chains allowed
    1195             :     return NS_ERROR_INVALID_ARG;
    1196             :   }
    1197             : 
    1198           0 :   return NS_OK;
    1199             : }
    1200             : 
    1201             : nsresult
    1202           0 : nsNSSCertList::GetRootCertificate(/* out */ nsCOMPtr<nsIX509Cert>& aRoot)
    1203             : {
    1204           0 :   if (aRoot) {
    1205             :     return NS_ERROR_UNEXPECTED;
    1206             :   }
    1207           0 :   CERTCertListNode* rootNode = CERT_LIST_TAIL(mCertList);
    1208           4 :   if (!rootNode) {
    1209             :     return NS_ERROR_UNEXPECTED;
    1210             :   }
    1211           8 :   if (CERT_LIST_END(rootNode, mCertList)) {
    1212             :     // Empty list, leave aRoot empty
    1213             :     return NS_OK;
    1214             :   }
    1215             :   // Duplicates the certificate
    1216           4 :   aRoot = nsNSSCertificate::Create(rootNode->cert);
    1217           4 :   if (!aRoot) {
    1218             :     return NS_ERROR_OUT_OF_MEMORY;
    1219             :   }
    1220           4 :   return NS_OK;
    1221             : }
    1222             : 
    1223          28 : NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
    1224             : 
    1225           2 : nsNSSCertListEnumerator::nsNSSCertListEnumerator(
    1226           8 :   const UniqueCERTCertList& certList)
    1227             : {
    1228           0 :   MOZ_ASSERT(certList);
    1229           2 :   mCertList = nsNSSCertList::DupCertList(certList);
    1230           0 : }
    1231             : 
    1232             : NS_IMETHODIMP
    1233           0 : nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
    1234             : {
    1235          16 :   NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
    1236             : 
    1237           0 :   *_retval = !CERT_LIST_EMPTY(mCertList);
    1238           8 :   return NS_OK;
    1239             : }
    1240             : 
    1241             : NS_IMETHODIMP
    1242           0 : nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
    1243             : {
    1244          12 :   NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
    1245             : 
    1246           0 :   CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
    1247          12 :   if (CERT_LIST_END(node, mCertList)) {
    1248             :     return NS_ERROR_FAILURE;
    1249             :   }
    1250             : 
    1251           0 :   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
    1252           0 :   if (!nssCert) {
    1253             :     return NS_ERROR_OUT_OF_MEMORY;
    1254             :   }
    1255             : 
    1256           0 :   nssCert.forget(_retval);
    1257             : 
    1258           6 :   CERT_RemoveCertListNode(node);
    1259           0 :   return NS_OK;
    1260             : }
    1261             : 
    1262             : NS_IMETHODIMP
    1263           0 : nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
    1264             : {
    1265           0 :   NS_ENSURE_STATE(mCert);
    1266             :   // This field used to be the cached EV status, but it is no longer necessary.
    1267           0 :   nsresult rv = aStream->Write32(0);
    1268           0 :   if (NS_FAILED(rv)) {
    1269             :     return rv;
    1270             :   }
    1271           0 :   rv = aStream->Write32(mCert->derCert.len);
    1272           0 :   if (NS_FAILED(rv)) {
    1273             :     return rv;
    1274             :   }
    1275           0 :   return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
    1276             : }
    1277             : 
    1278             : NS_IMETHODIMP
    1279           0 : nsNSSCertificate::Read(nsIObjectInputStream* aStream)
    1280             : {
    1281           0 :   NS_ENSURE_STATE(!mCert);
    1282             : 
    1283             :   // This field is no longer used.
    1284             :   uint32_t unusedCachedEVStatus;
    1285           0 :   nsresult rv = aStream->Read32(&unusedCachedEVStatus);
    1286           0 :   if (NS_FAILED(rv)) {
    1287             :     return rv;
    1288             :   }
    1289             : 
    1290             :   uint32_t len;
    1291           0 :   rv = aStream->Read32(&len);
    1292           0 :   if (NS_FAILED(rv)) {
    1293             :     return rv;
    1294             :   }
    1295             : 
    1296           0 :   nsCString str;
    1297           0 :   rv = aStream->ReadBytes(len, getter_Copies(str));
    1298           0 :   if (NS_FAILED(rv)) {
    1299             :     return rv;
    1300             :   }
    1301             : 
    1302           0 :   if (!InitFromDER(const_cast<char*>(str.get()), len)) {
    1303             :     return NS_ERROR_UNEXPECTED;
    1304             :   }
    1305             : 
    1306           0 :   return NS_OK;
    1307             : }
    1308             : 
    1309             : NS_IMETHODIMP
    1310           0 : nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
    1311             : {
    1312           0 :   *count = 0;
    1313           0 :   *array = nullptr;
    1314           0 :   return NS_OK;
    1315             : }
    1316             : 
    1317             : NS_IMETHODIMP
    1318           0 : nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval)
    1319             : {
    1320           0 :   *_retval = nullptr;
    1321           0 :   return NS_OK;
    1322             : }
    1323             : 
    1324             : NS_IMETHODIMP
    1325           0 : nsNSSCertificate::GetContractID(nsACString& aContractID)
    1326             : {
    1327           0 :   aContractID.SetIsVoid(true);
    1328           0 :   return NS_OK;
    1329             : }
    1330             : 
    1331             : NS_IMETHODIMP
    1332           0 : nsNSSCertificate::GetClassDescription(nsACString& aClassDescription)
    1333             : {
    1334           0 :   aClassDescription.SetIsVoid(true);
    1335           0 :   return NS_OK;
    1336             : }
    1337             : 
    1338             : NS_IMETHODIMP
    1339           0 : nsNSSCertificate::GetClassID(nsCID** aClassID)
    1340             : {
    1341           0 :   *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
    1342           0 :   if (!*aClassID)
    1343             :     return NS_ERROR_OUT_OF_MEMORY;
    1344           0 :   return GetClassIDNoAlloc(*aClassID);
    1345             : }
    1346             : 
    1347             : NS_IMETHODIMP
    1348           0 : nsNSSCertificate::GetFlags(uint32_t* aFlags)
    1349             : {
    1350           0 :   *aFlags = nsIClassInfo::THREADSAFE;
    1351           0 :   return NS_OK;
    1352             : }
    1353             : 
    1354             : NS_IMETHODIMP
    1355           0 : nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
    1356             : {
    1357             :   static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
    1358             : 
    1359           0 :   *aClassIDNoAlloc = kNSSCertificateCID;
    1360           0 :   return NS_OK;
    1361             : }

Generated by: LCOV version 1.13-14-ga5dd952