LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNSSCertificate.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 789 0.1 %
Date: 2017-07-14 16:53:18 Functions: 0 89 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 "nsNSSComponent.h" // for PIPNSS string bundle calls.
      30             : #include "nsPK11TokenDB.h"
      31             : #include "nsPKCS12Blob.h"
      32             : #include "nsProxyRelease.h"
      33             : #include "nsReadableUtils.h"
      34             : #include "nsString.h"
      35             : #include "nsThreadUtils.h"
      36             : #include "nsUnicharUtils.h"
      37             : #include "nspr.h"
      38             : #include "pkix/pkixnss.h"
      39             : #include "pkix/pkixtypes.h"
      40             : #include "pkix/Result.h"
      41             : #include "prerror.h"
      42             : #include "secasn1.h"
      43             : #include "secder.h"
      44             : #include "secerr.h"
      45             : #include "ssl.h"
      46             : 
      47             : #ifdef XP_WIN
      48             : #include <winsock.h> // for htonl
      49             : #endif
      50             : 
      51             : using namespace mozilla;
      52             : using namespace mozilla::psm;
      53             : 
      54             : extern LazyLogModule gPIPNSSLog;
      55             : 
      56             : // This is being stored in an uint32_t that can otherwise
      57             : // only take values from nsIX509Cert's list of cert types.
      58             : // As nsIX509Cert is frozen, we choose a value not contained
      59             : // in the list to mean not yet initialized.
      60             : #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
      61             : 
      62           0 : NS_IMPL_ISUPPORTS(nsNSSCertificate,
      63             :                   nsIX509Cert,
      64             :                   nsISerializable,
      65             :                   nsIClassInfo)
      66             : 
      67             : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
      68             : 
      69             : /*static*/ nsNSSCertificate*
      70           0 : nsNSSCertificate::Create(CERTCertificate* cert)
      71             : {
      72           0 :   if (cert)
      73           0 :     return new nsNSSCertificate(cert);
      74             :   else
      75           0 :     return new nsNSSCertificate();
      76             : }
      77             : 
      78             : nsNSSCertificate*
      79           0 : nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
      80             : {
      81           0 :   nsNSSCertificate* newObject = nsNSSCertificate::Create();
      82           0 :   if (newObject && !newObject->InitFromDER(certDER, derLen)) {
      83           0 :     delete newObject;
      84           0 :     newObject = nullptr;
      85             :   }
      86             : 
      87           0 :   return newObject;
      88             : }
      89             : 
      90             : bool
      91           0 : nsNSSCertificate::InitFromDER(char* certDER, int derLen)
      92             : {
      93           0 :   nsNSSShutDownPreventionLock locker;
      94           0 :   if (isAlreadyShutDown())
      95           0 :     return false;
      96             : 
      97           0 :   if (!certDER || !derLen)
      98           0 :     return false;
      99             : 
     100           0 :   CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
     101             : 
     102           0 :   if (!aCert)
     103           0 :     return false;
     104             : 
     105           0 :   if (!aCert->dbhandle)
     106             :   {
     107           0 :     aCert->dbhandle = CERT_GetDefaultCertDB();
     108             :   }
     109             : 
     110           0 :   mCert.reset(aCert);
     111           0 :   return true;
     112             : }
     113             : 
     114           0 : nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
     115             :   : mCert(nullptr)
     116             :   , mPermDelete(false)
     117           0 :   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
     118             : {
     119           0 :   nsNSSShutDownPreventionLock locker;
     120           0 :   if (isAlreadyShutDown())
     121           0 :     return;
     122             : 
     123           0 :   if (cert) {
     124           0 :     mCert.reset(CERT_DupCertificate(cert));
     125             :   }
     126             : }
     127             : 
     128           0 : nsNSSCertificate::nsNSSCertificate()
     129             :   : mCert(nullptr)
     130             :   , mPermDelete(false)
     131           0 :   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
     132             : {
     133           0 : }
     134             : 
     135           0 : nsNSSCertificate::~nsNSSCertificate()
     136             : {
     137           0 :   nsNSSShutDownPreventionLock locker;
     138           0 :   if (isAlreadyShutDown()) {
     139           0 :     return;
     140             :   }
     141           0 :   destructorSafeDestroyNSSReference();
     142           0 :   shutdown(ShutdownCalledFrom::Object);
     143           0 : }
     144             : 
     145           0 : void nsNSSCertificate::virtualDestroyNSSReference()
     146             : {
     147           0 :   destructorSafeDestroyNSSReference();
     148           0 : }
     149             : 
     150           0 : void nsNSSCertificate::destructorSafeDestroyNSSReference()
     151             : {
     152           0 :   if (mPermDelete) {
     153           0 :     if (mCertType == nsNSSCertificate::USER_CERT) {
     154           0 :       nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
     155           0 :       PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
     156           0 :     } else if (mCert->slot && !PK11_IsReadOnly(mCert->slot)) {
     157             :       // If the list of built-ins does contain a non-removable
     158             :       // copy of this certificate, our call will not remove
     159             :       // the certificate permanently, but rather remove all trust.
     160           0 :       SEC_DeletePermCertificate(mCert.get());
     161             :     }
     162             :   }
     163             : 
     164           0 :   mCert = nullptr;
     165           0 : }
     166             : 
     167             : nsresult
     168           0 : nsNSSCertificate::GetCertType(uint32_t* aCertType)
     169             : {
     170           0 :   if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
     171             :      // only determine cert type once and cache it
     172           0 :      mCertType = getCertType(mCert.get());
     173             :   }
     174           0 :   *aCertType = mCertType;
     175           0 :   return NS_OK;
     176             : }
     177             : 
     178             : NS_IMETHODIMP
     179           0 : nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
     180             : {
     181           0 :   NS_ENSURE_ARG(aIsSelfSigned);
     182             : 
     183           0 :   nsNSSShutDownPreventionLock locker;
     184           0 :   if (isAlreadyShutDown())
     185           0 :     return NS_ERROR_NOT_AVAILABLE;
     186             : 
     187           0 :   *aIsSelfSigned = mCert->isRoot;
     188           0 :   return NS_OK;
     189             : }
     190             : 
     191             : NS_IMETHODIMP
     192           0 : nsNSSCertificate::GetIsBuiltInRoot(bool* aIsBuiltInRoot)
     193             : {
     194           0 :   NS_ENSURE_ARG(aIsBuiltInRoot);
     195             : 
     196           0 :   nsNSSShutDownPreventionLock locker;
     197           0 :   if (isAlreadyShutDown()) {
     198           0 :     return NS_ERROR_NOT_AVAILABLE;
     199             :   }
     200           0 :   pkix::Result rv = IsCertBuiltInRoot(mCert.get(), *aIsBuiltInRoot);
     201           0 :   if (rv != pkix::Result::Success) {
     202           0 :     return NS_ERROR_FAILURE;
     203             :   }
     204           0 :   return NS_OK;
     205             : }
     206             : 
     207             : nsresult
     208           0 : nsNSSCertificate::MarkForPermDeletion()
     209             : {
     210           0 :   nsNSSShutDownPreventionLock locker;
     211           0 :   if (isAlreadyShutDown())
     212           0 :     return NS_ERROR_NOT_AVAILABLE;
     213             : 
     214             :   // make sure user is logged in to the token
     215           0 :   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
     216             : 
     217           0 :   if (mCert->slot && PK11_NeedLogin(mCert->slot) &&
     218           0 :       !PK11_NeedUserInit(mCert->slot) && !PK11_IsInternal(mCert->slot)) {
     219           0 :     if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) {
     220           0 :       return NS_ERROR_FAILURE;
     221             :     }
     222             :   }
     223             : 
     224           0 :   mPermDelete = true;
     225           0 :   return NS_OK;
     226             : }
     227             : 
     228             : /**
     229             :  * Appends a pipnss bundle string to the given string.
     230             :  *
     231             :  * @param nssComponent For accessing the string bundle.
     232             :  * @param bundleKey Key for the string to append.
     233             :  * @param currentText The text to append to, using commas as separators.
     234             :  */
     235             : template<size_t N>
     236             : void
     237           0 : AppendBundleString(const NotNull<nsCOMPtr<nsINSSComponent>>& nssComponent,
     238             :                    const char (&bundleKey)[N],
     239             :         /*in/out*/ nsAString& currentText)
     240             : {
     241           0 :   nsAutoString bundleString;
     242           0 :   nsresult rv = nssComponent->GetPIPNSSBundleString(bundleKey, bundleString);
     243           0 :   if (NS_FAILED(rv)) {
     244           0 :     return;
     245             :   }
     246             : 
     247           0 :   if (!currentText.IsEmpty()) {
     248           0 :     currentText.Append(',');
     249             :   }
     250           0 :   currentText.Append(bundleString);
     251             : }
     252             : 
     253             : NS_IMETHODIMP
     254           0 : nsNSSCertificate::GetKeyUsages(nsAString& text)
     255             : {
     256           0 :   text.Truncate();
     257             : 
     258           0 :   nsCOMPtr<nsINSSComponent> nssComponent = do_GetService(kNSSComponentCID);
     259           0 :   if (!nssComponent) {
     260           0 :     return NS_ERROR_FAILURE;
     261             :   }
     262             : 
     263           0 :   if (!mCert) {
     264           0 :     return NS_ERROR_FAILURE;
     265             :   }
     266             : 
     267           0 :   if (!mCert->extensions) {
     268           0 :     return NS_OK;
     269             :   }
     270             : 
     271           0 :   ScopedAutoSECItem keyUsageItem;
     272           0 :   if (CERT_FindKeyUsageExtension(mCert.get(), &keyUsageItem) != SECSuccess) {
     273           0 :     return PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND ? NS_OK
     274           0 :                                                             : NS_ERROR_FAILURE;
     275             :   }
     276             : 
     277           0 :   unsigned char keyUsage = 0;
     278           0 :   if (keyUsageItem.len) {
     279           0 :     keyUsage = keyUsageItem.data[0];
     280             :   }
     281             : 
     282             :   NotNull<nsCOMPtr<nsINSSComponent>> wrappedNSSComponent =
     283           0 :     WrapNotNull(nssComponent);
     284           0 :   if (keyUsage & KU_DIGITAL_SIGNATURE) {
     285           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUSign", text);
     286             :   }
     287           0 :   if (keyUsage & KU_NON_REPUDIATION) {
     288           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUNonRep", text);
     289             :   }
     290           0 :   if (keyUsage & KU_KEY_ENCIPHERMENT) {
     291           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUEnc", text);
     292             :   }
     293           0 :   if (keyUsage & KU_DATA_ENCIPHERMENT) {
     294           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUDEnc", text);
     295             :   }
     296           0 :   if (keyUsage & KU_KEY_AGREEMENT) {
     297           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUKA", text);
     298             :   }
     299           0 :   if (keyUsage & KU_KEY_CERT_SIGN) {
     300           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUCertSign", text);
     301             :   }
     302           0 :   if (keyUsage & KU_CRL_SIGN) {
     303           0 :     AppendBundleString(wrappedNSSComponent, "CertDumpKUCRLSign", text);
     304             :   }
     305             : 
     306           0 :   return NS_OK;
     307             : }
     308             : 
     309             : NS_IMETHODIMP
     310           0 : nsNSSCertificate::GetDbKey(nsACString& aDbKey)
     311             : {
     312           0 :   nsNSSShutDownPreventionLock locker;
     313           0 :   if (isAlreadyShutDown()) {
     314           0 :     return NS_ERROR_NOT_AVAILABLE;
     315             :   }
     316           0 :   return GetDbKey(mCert, aDbKey);
     317             : }
     318             : 
     319             : nsresult
     320           0 : nsNSSCertificate::GetDbKey(const UniqueCERTCertificate& cert, nsACString& aDbKey)
     321             : {
     322             :   static_assert(sizeof(uint64_t) == 8, "type size sanity check");
     323             :   static_assert(sizeof(uint32_t) == 4, "type size sanity check");
     324             :   // The format of the key is the base64 encoding of the following:
     325             :   // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
     326             :   //                        never implemented)
     327             :   // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
     328             :   //                        never implemented)
     329             :   // 4 bytes: <serial number length in big-endian order>
     330             :   // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
     331             :   // n bytes: <bytes of serial number>
     332             :   // m bytes: <DER-encoded issuer distinguished name>
     333           0 :   nsAutoCString buf;
     334           0 :   const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
     335           0 :   buf.Append(leadingZeroes, sizeof(leadingZeroes));
     336           0 :   uint32_t serialNumberLen = htonl(cert->serialNumber.len);
     337           0 :   buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
     338           0 :              sizeof(uint32_t));
     339           0 :   uint32_t issuerLen = htonl(cert->derIssuer.len);
     340           0 :   buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
     341           0 :              sizeof(uint32_t));
     342           0 :   buf.Append(BitwiseCast<char*, unsigned char*>(cert->serialNumber.data),
     343           0 :              cert->serialNumber.len);
     344           0 :   buf.Append(BitwiseCast<char*, unsigned char*>(cert->derIssuer.data),
     345           0 :              cert->derIssuer.len);
     346             : 
     347           0 :   return Base64Encode(buf, aDbKey);
     348             : }
     349             : 
     350             : NS_IMETHODIMP
     351           0 : nsNSSCertificate::GetDisplayName(nsAString& aDisplayName)
     352             : {
     353           0 :   nsNSSShutDownPreventionLock locker;
     354           0 :   if (isAlreadyShutDown()) {
     355           0 :     return NS_ERROR_NOT_AVAILABLE;
     356             :   }
     357             : 
     358           0 :   aDisplayName.Truncate();
     359             : 
     360           0 :   MOZ_ASSERT(mCert, "mCert should not be null in GetDisplayName");
     361           0 :   if (!mCert) {
     362           0 :     return NS_ERROR_FAILURE;
     363             :   }
     364             : 
     365           0 :   UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
     366           0 :   UniquePORTString organizationalUnitName(CERT_GetOrgUnitName(&mCert->subject));
     367           0 :   UniquePORTString organizationName(CERT_GetOrgName(&mCert->subject));
     368             : 
     369             :   bool isBuiltInRoot;
     370           0 :   nsresult rv = GetIsBuiltInRoot(&isBuiltInRoot);
     371           0 :   if (NS_FAILED(rv)) {
     372           0 :     return rv;
     373             :   }
     374             : 
     375             :   // Only use the nickname for built-in roots where we already have a hard-coded
     376             :   // reasonable display name (unfortunately we have to strip off the leading
     377             :   // slot identifier followed by a ':'). Otherwise, attempt to use the following
     378             :   // in order:
     379             :   //  - the common name, if present
     380             :   //  - an organizational unit name, if present
     381             :   //  - an organization name, if present
     382             :   //  - the entire subject distinguished name, if non-empty
     383             :   //  - an email address, if one can be found
     384             :   // In the unlikely event that none of these fields are present and non-empty
     385             :   // (the subject really shouldn't be empty), an empty string is returned.
     386           0 :   nsAutoCString builtInRootNickname;
     387           0 :   if (isBuiltInRoot) {
     388           0 :     nsAutoCString fullNickname(mCert->nickname);
     389           0 :     int32_t index = fullNickname.Find(":");
     390           0 :     if (index != kNotFound) {
     391             :       // Substring will gracefully handle the case where index is the last
     392             :       // character in the string (that is, if the nickname is just
     393             :       // "Builtin Object Token:"). In that case, we'll get an empty string.
     394           0 :       builtInRootNickname = Substring(fullNickname,
     395           0 :                                       AssertedCast<uint32_t>(index + 1));
     396             :     }
     397             :   }
     398             :   const char* nameOptions[] = {
     399           0 :     builtInRootNickname.get(),
     400           0 :     commonName.get(),
     401           0 :     organizationalUnitName.get(),
     402           0 :     organizationName.get(),
     403           0 :     mCert->subjectName,
     404           0 :     mCert->emailAddr
     405           0 :   };
     406             : 
     407           0 :   nsAutoCString nameOption;
     408           0 :   for (auto nameOptionPtr : nameOptions) {
     409           0 :     nameOption.Assign(nameOptionPtr);
     410           0 :     if (nameOption.Length() > 0 && IsUTF8(nameOption)) {
     411           0 :       CopyUTF8toUTF16(nameOption, aDisplayName);
     412           0 :       return NS_OK;
     413             :     }
     414             :   }
     415             : 
     416           0 :   return NS_OK;
     417             : }
     418             : 
     419             : NS_IMETHODIMP
     420           0 : nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
     421             : {
     422           0 :   nsNSSShutDownPreventionLock locker;
     423           0 :   if (isAlreadyShutDown())
     424           0 :     return NS_ERROR_NOT_AVAILABLE;
     425             : 
     426           0 :   if (mCert->emailAddr) {
     427           0 :     CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
     428             :   } else {
     429             :     nsresult rv;
     430           0 :     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
     431           0 :     if (NS_FAILED(rv) || !nssComponent) {
     432           0 :       return NS_ERROR_FAILURE;
     433             :     }
     434           0 :     nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
     435             :   }
     436           0 :   return NS_OK;
     437             : }
     438             : 
     439             : NS_IMETHODIMP
     440           0 : nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
     441             : {
     442           0 :   nsNSSShutDownPreventionLock locker;
     443           0 :   if (isAlreadyShutDown())
     444           0 :     return NS_ERROR_NOT_AVAILABLE;
     445             : 
     446           0 :   NS_ENSURE_ARG(aLength);
     447           0 :   NS_ENSURE_ARG(aAddresses);
     448             : 
     449           0 :   *aLength = 0;
     450             : 
     451             :   const char* aAddr;
     452           0 :   for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
     453           0 :        ;
     454           0 :        aAddr
     455             :        ;
     456           0 :        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
     457             :   {
     458           0 :     ++(*aLength);
     459             :   }
     460             : 
     461           0 :   *aAddresses = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
     462           0 :   if (!*aAddresses)
     463           0 :     return NS_ERROR_OUT_OF_MEMORY;
     464             : 
     465             :   uint32_t iAddr;
     466           0 :   for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
     467           0 :        ;
     468           0 :        aAddr
     469             :        ;
     470           0 :        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
     471             :   {
     472           0 :     (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
     473             :   }
     474             : 
     475           0 :   return NS_OK;
     476             : }
     477             : 
     478             : NS_IMETHODIMP
     479           0 : nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
     480             :                                        bool* result)
     481             : {
     482           0 :   nsNSSShutDownPreventionLock locker;
     483           0 :   if (isAlreadyShutDown())
     484           0 :     return NS_ERROR_NOT_AVAILABLE;
     485             : 
     486           0 :   NS_ENSURE_ARG(result);
     487           0 :   *result = false;
     488             : 
     489           0 :   const char* aAddr = nullptr;
     490           0 :   for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
     491           0 :        ;
     492           0 :        aAddr
     493             :        ;
     494           0 :        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
     495             :   {
     496           0 :     NS_ConvertUTF8toUTF16 certAddr(aAddr);
     497           0 :     ToLowerCase(certAddr);
     498             : 
     499           0 :     nsAutoString testAddr(aEmailAddress);
     500           0 :     ToLowerCase(testAddr);
     501             : 
     502           0 :     if (certAddr == testAddr)
     503             :     {
     504           0 :       *result = true;
     505           0 :       break;
     506             :     }
     507             : 
     508             :   }
     509             : 
     510           0 :   return NS_OK;
     511             : }
     512             : 
     513             : NS_IMETHODIMP
     514           0 : nsNSSCertificate::GetCommonName(nsAString& aCommonName)
     515             : {
     516           0 :   nsNSSShutDownPreventionLock locker;
     517           0 :   if (isAlreadyShutDown())
     518           0 :     return NS_ERROR_NOT_AVAILABLE;
     519             : 
     520           0 :   aCommonName.Truncate();
     521           0 :   if (mCert) {
     522           0 :     UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
     523           0 :     if (commonName) {
     524           0 :       aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
     525             :     }
     526             :   }
     527           0 :   return NS_OK;
     528             : }
     529             : 
     530             : NS_IMETHODIMP
     531           0 : nsNSSCertificate::GetOrganization(nsAString& aOrganization)
     532             : {
     533           0 :   nsNSSShutDownPreventionLock locker;
     534           0 :   if (isAlreadyShutDown())
     535           0 :     return NS_ERROR_NOT_AVAILABLE;
     536             : 
     537           0 :   aOrganization.Truncate();
     538           0 :   if (mCert) {
     539           0 :     UniquePORTString organization(CERT_GetOrgName(&mCert->subject));
     540           0 :     if (organization) {
     541           0 :       aOrganization = NS_ConvertUTF8toUTF16(organization.get());
     542             :     }
     543             :   }
     544           0 :   return NS_OK;
     545             : }
     546             : 
     547             : NS_IMETHODIMP
     548           0 : nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
     549             : {
     550           0 :   nsNSSShutDownPreventionLock locker;
     551           0 :   if (isAlreadyShutDown())
     552           0 :     return NS_ERROR_NOT_AVAILABLE;
     553             : 
     554           0 :   aCommonName.Truncate();
     555           0 :   if (mCert) {
     556           0 :     UniquePORTString commonName(CERT_GetCommonName(&mCert->issuer));
     557           0 :     if (commonName) {
     558           0 :       aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
     559             :     }
     560             :   }
     561           0 :   return NS_OK;
     562             : }
     563             : 
     564             : NS_IMETHODIMP
     565           0 : nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
     566             : {
     567           0 :   nsNSSShutDownPreventionLock locker;
     568           0 :   if (isAlreadyShutDown())
     569           0 :     return NS_ERROR_NOT_AVAILABLE;
     570             : 
     571           0 :   aOrganization.Truncate();
     572           0 :   if (mCert) {
     573           0 :     UniquePORTString organization(CERT_GetOrgName(&mCert->issuer));
     574           0 :     if (organization) {
     575           0 :       aOrganization = NS_ConvertUTF8toUTF16(organization.get());
     576             :     }
     577             :   }
     578           0 :   return NS_OK;
     579             : }
     580             : 
     581             : NS_IMETHODIMP
     582           0 : nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
     583             : {
     584           0 :   nsNSSShutDownPreventionLock locker;
     585           0 :   if (isAlreadyShutDown())
     586           0 :     return NS_ERROR_NOT_AVAILABLE;
     587             : 
     588           0 :   aOrganizationUnit.Truncate();
     589           0 :   if (mCert) {
     590           0 :     UniquePORTString organizationUnit(CERT_GetOrgUnitName(&mCert->issuer));
     591           0 :     if (organizationUnit) {
     592           0 :       aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit.get());
     593             :     }
     594             :   }
     595           0 :   return NS_OK;
     596             : }
     597             : 
     598             : NS_IMETHODIMP
     599           0 : nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer)
     600             : {
     601           0 :   nsNSSShutDownPreventionLock locker;
     602           0 :   if (isAlreadyShutDown())
     603           0 :     return NS_ERROR_NOT_AVAILABLE;
     604             : 
     605           0 :   NS_ENSURE_ARG(aIssuer);
     606           0 :   *aIssuer = nullptr;
     607             : 
     608           0 :   nsCOMPtr<nsIArray> chain;
     609             :   nsresult rv;
     610           0 :   rv = GetChain(getter_AddRefs(chain));
     611           0 :   NS_ENSURE_SUCCESS(rv, rv);
     612             :   uint32_t length;
     613           0 :   if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) {
     614           0 :     return NS_ERROR_UNEXPECTED;
     615             :   }
     616           0 :   if (length == 1) { // No known issuer
     617           0 :     return NS_OK;
     618             :   }
     619           0 :   nsCOMPtr<nsIX509Cert> cert;
     620           0 :   chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert));
     621           0 :   if (!cert) {
     622           0 :     return NS_ERROR_UNEXPECTED;
     623             :   }
     624           0 :   cert.forget(aIssuer);
     625           0 :   return NS_OK;
     626             : }
     627             : 
     628             : NS_IMETHODIMP
     629           0 : nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
     630             : {
     631           0 :   nsNSSShutDownPreventionLock locker;
     632           0 :   if (isAlreadyShutDown())
     633           0 :     return NS_ERROR_NOT_AVAILABLE;
     634             : 
     635           0 :   aOrganizationalUnit.Truncate();
     636           0 :   if (mCert) {
     637           0 :     UniquePORTString orgunit(CERT_GetOrgUnitName(&mCert->subject));
     638           0 :     if (orgunit) {
     639           0 :       aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit.get());
     640             :     }
     641             :   }
     642           0 :   return NS_OK;
     643             : }
     644             : 
     645             : NS_IMETHODIMP
     646           0 : nsNSSCertificate::GetChain(nsIArray** _rvChain)
     647             : {
     648           0 :   nsNSSShutDownPreventionLock locker;
     649           0 :   if (isAlreadyShutDown())
     650           0 :     return NS_ERROR_NOT_AVAILABLE;
     651             : 
     652           0 :   NS_ENSURE_ARG(_rvChain);
     653             : 
     654           0 :   mozilla::pkix::Time now(mozilla::pkix::Now());
     655             : 
     656           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
     657           0 :   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
     658             : 
     659           0 :   UniqueCERTCertList nssChain;
     660             :   // We want to test all usages, but we start with server because most of the
     661             :   // time Firefox users care about server certs.
     662           0 :   if (certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, now,
     663             :                                nullptr, /*XXX fixme*/
     664             :                                nullptr, /* hostname */
     665             :                                nssChain,
     666             :                                nullptr, // no peerCertChain
     667             :                                CertVerifier::FLAG_LOCAL_ONLY)
     668             :         != mozilla::pkix::Success) {
     669           0 :     nssChain = nullptr;
     670             :     // keep going
     671             :   }
     672             : 
     673             :   // This is the whitelist of all non-SSLServer usages that are supported by
     674             :   // verifycert.
     675             :   const int otherUsagesToTest = certificateUsageSSLClient |
     676             :                                 certificateUsageSSLCA |
     677             :                                 certificateUsageEmailSigner |
     678             :                                 certificateUsageEmailRecipient |
     679             :                                 certificateUsageObjectSigner |
     680           0 :                                 certificateUsageStatusResponder;
     681           0 :   for (int usage = certificateUsageSSLClient;
     682           0 :        usage < certificateUsageAnyCA && !nssChain;
     683           0 :        usage = usage << 1) {
     684           0 :     if ((usage & otherUsagesToTest) == 0) {
     685           0 :       continue;
     686             :     }
     687           0 :     if (certVerifier->VerifyCert(mCert.get(), usage, now,
     688             :                                  nullptr, /*XXX fixme*/
     689             :                                  nullptr, /*hostname*/
     690             :                                  nssChain,
     691             :                                  nullptr, // no peerCertChain
     692             :                                  CertVerifier::FLAG_LOCAL_ONLY)
     693             :           != mozilla::pkix::Success) {
     694           0 :       nssChain = nullptr;
     695             :       // keep going
     696             :     }
     697             :   }
     698             : 
     699           0 :   if (!nssChain) {
     700             :     // There is not verified path for the chain, however we still want to
     701             :     // present to the user as much of a possible chain as possible, in the case
     702             :     // where there was a problem with the cert or the issuers.
     703           0 :     nssChain = UniqueCERTCertList(
     704           0 :       CERT_GetCertChainFromCert(mCert.get(), PR_Now(), certUsageSSLClient));
     705             :   }
     706           0 :   if (!nssChain) {
     707           0 :     return NS_ERROR_FAILURE;
     708             :   }
     709             : 
     710             :   // enumerate the chain for scripting purposes
     711           0 :   nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
     712           0 :   if (!array) {
     713           0 :     return NS_ERROR_FAILURE;
     714             :   }
     715             :   CERTCertListNode* node;
     716           0 :   for (node = CERT_LIST_HEAD(nssChain.get());
     717           0 :        !CERT_LIST_END(node, nssChain.get());
     718           0 :        node = CERT_LIST_NEXT(node)) {
     719           0 :     nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
     720           0 :     array->AppendElement(cert, false);
     721             :   }
     722           0 :   *_rvChain = array;
     723           0 :   NS_IF_ADDREF(*_rvChain);
     724           0 :   return NS_OK;
     725             : }
     726             : 
     727             : NS_IMETHODIMP
     728           0 : nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
     729             : {
     730           0 :   nsNSSShutDownPreventionLock locker;
     731           0 :   if (isAlreadyShutDown())
     732           0 :     return NS_ERROR_NOT_AVAILABLE;
     733             : 
     734           0 :   _subjectName.Truncate();
     735           0 :   if (mCert->subjectName) {
     736           0 :     _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
     737             :   }
     738           0 :   return NS_OK;
     739             : }
     740             : 
     741             : NS_IMETHODIMP
     742           0 : nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
     743             : {
     744           0 :   nsNSSShutDownPreventionLock locker;
     745           0 :   if (isAlreadyShutDown())
     746           0 :     return NS_ERROR_NOT_AVAILABLE;
     747             : 
     748           0 :   _issuerName.Truncate();
     749           0 :   if (mCert->issuerName) {
     750           0 :     _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
     751             :   }
     752           0 :   return NS_OK;
     753             : }
     754             : 
     755             : NS_IMETHODIMP
     756           0 : nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
     757             : {
     758           0 :   nsNSSShutDownPreventionLock locker;
     759           0 :   if (isAlreadyShutDown())
     760           0 :     return NS_ERROR_NOT_AVAILABLE;
     761             : 
     762           0 :   _serialNumber.Truncate();
     763           0 :   UniquePORTString tmpstr(CERT_Hexify(&mCert->serialNumber, 1));
     764           0 :   if (tmpstr) {
     765           0 :     _serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
     766           0 :     return NS_OK;
     767             :   }
     768           0 :   return NS_ERROR_FAILURE;
     769             : }
     770             : 
     771             : nsresult
     772           0 : nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg)
     773             : {
     774           0 :   nsNSSShutDownPreventionLock locker;
     775           0 :   if (isAlreadyShutDown()) {
     776           0 :     return NS_ERROR_NOT_AVAILABLE;
     777             :   }
     778             : 
     779           0 :   aFingerprint.Truncate();
     780           0 :   Digest digest;
     781           0 :   nsresult rv = digest.DigestBuf(aHashAlg, mCert->derCert.data,
     782           0 :                                  mCert->derCert.len);
     783           0 :   if (NS_FAILED(rv)) {
     784           0 :     return rv;
     785             :   }
     786             : 
     787             :   // CERT_Hexify's second argument is an int that is interpreted as a boolean
     788           0 :   UniquePORTString fpStr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
     789           0 :   if (!fpStr) {
     790           0 :     return NS_ERROR_FAILURE;
     791             :   }
     792             : 
     793           0 :   aFingerprint.AssignASCII(fpStr.get());
     794           0 :   return NS_OK;
     795             : }
     796             : 
     797             : NS_IMETHODIMP
     798           0 : nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
     799             : {
     800           0 :   return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
     801             : }
     802             : 
     803             : NS_IMETHODIMP
     804           0 : nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
     805             : {
     806           0 :   return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
     807             : }
     808             : 
     809             : NS_IMETHODIMP
     810           0 : nsNSSCertificate::GetTokenName(nsAString& aTokenName)
     811             : {
     812           0 :   nsNSSShutDownPreventionLock locker;
     813           0 :   if (isAlreadyShutDown())
     814           0 :     return NS_ERROR_NOT_AVAILABLE;
     815             : 
     816           0 :   aTokenName.Truncate();
     817           0 :   if (mCert) {
     818             :     // HACK alert
     819             :     // When the trust of a builtin cert is modified, NSS copies it into the
     820             :     // cert db.  At this point, it is now "managed" by the user, and should
     821             :     // not be listed with the builtins.  However, in the collection code
     822             :     // used by PK11_ListCerts, the cert is found in the temp db, where it
     823             :     // has been loaded from the token.  Though the trust is correct (grabbed
     824             :     // from the cert db), the source is wrong.  I believe this is a safe
     825             :     // way to work around this.
     826           0 :     if (mCert->slot) {
     827           0 :       char* token = PK11_GetTokenName(mCert->slot);
     828           0 :       if (token) {
     829           0 :         aTokenName = NS_ConvertUTF8toUTF16(token);
     830             :       }
     831             :     } else {
     832             :       nsresult rv;
     833           0 :       nsAutoString tok;
     834           0 :       nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
     835           0 :       if (NS_FAILED(rv)) return rv;
     836           0 :       rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
     837           0 :       if (NS_SUCCEEDED(rv))
     838           0 :         aTokenName = tok;
     839             :     }
     840             :   }
     841           0 :   return NS_OK;
     842             : }
     843             : 
     844             : NS_IMETHODIMP
     845           0 : nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
     846             : {
     847           0 :   nsNSSShutDownPreventionLock locker;
     848           0 :   if (isAlreadyShutDown()) {
     849           0 :     return NS_ERROR_NOT_AVAILABLE;
     850             :   }
     851             : 
     852           0 :   aSha256SPKIDigest.Truncate();
     853           0 :   Digest digest;
     854           0 :   nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
     855           0 :                                  mCert->derPublicKey.len);
     856           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     857           0 :     return rv;
     858             :   }
     859           0 :   rv = Base64Encode(nsDependentCSubstring(
     860           0 :                       BitwiseCast<char*, unsigned char*>(digest.get().data),
     861           0 :                       digest.get().len),
     862           0 :                     aSha256SPKIDigest);
     863           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     864           0 :     return rv;
     865             :   }
     866           0 :   return NS_OK;
     867             : }
     868             : 
     869             : NS_IMETHODIMP
     870           0 : nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
     871             : {
     872           0 :   nsNSSShutDownPreventionLock locker;
     873           0 :   if (isAlreadyShutDown())
     874           0 :     return NS_ERROR_NOT_AVAILABLE;
     875             : 
     876           0 :   if (mCert) {
     877           0 :     *aArray = (uint8_t*)moz_xmalloc(mCert->derCert.len);
     878           0 :     if (*aArray) {
     879           0 :       memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
     880           0 :       *aLength = mCert->derCert.len;
     881           0 :       return NS_OK;
     882             :     }
     883             :   }
     884           0 :   *aLength = 0;
     885           0 :   return NS_ERROR_FAILURE;
     886             : }
     887             : 
     888             : NS_IMETHODIMP
     889           0 : nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
     890             :                               uint32_t* aLength, uint8_t** aArray)
     891             : {
     892           0 :   NS_ENSURE_ARG(aLength);
     893           0 :   NS_ENSURE_ARG(aArray);
     894             : 
     895           0 :   nsNSSShutDownPreventionLock locker;
     896           0 :   if (isAlreadyShutDown())
     897           0 :     return NS_ERROR_NOT_AVAILABLE;
     898             : 
     899           0 :   if (!mCert)
     900           0 :     return NS_ERROR_FAILURE;
     901             : 
     902           0 :   switch (chainMode) {
     903             :     case nsIX509Cert::CMS_CHAIN_MODE_CertOnly:
     904             :     case nsIX509Cert::CMS_CHAIN_MODE_CertChain:
     905             :     case nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot:
     906           0 :       break;
     907             :     default:
     908           0 :       return NS_ERROR_INVALID_ARG;
     909             :   }
     910             : 
     911           0 :   UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
     912           0 :   if (!cmsg) {
     913           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     914             :            ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
     915           0 :     return NS_ERROR_OUT_OF_MEMORY;
     916             :   }
     917             : 
     918             :   // first, create SignedData with the certificate only (no chain)
     919             :   UniqueNSSCMSSignedData sigd(
     920           0 :     NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), mCert.get(), false));
     921           0 :   if (!sigd) {
     922           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     923             :            ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
     924           0 :     return NS_ERROR_FAILURE;
     925             :   }
     926             : 
     927             :   // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
     928             :   // to specify the inclusion of the root, but CERT_CertChainFromCert() does.
     929             :   // Since CERT_CertChainFromCert() also includes the certificate itself,
     930             :   // we have to start at the issuing cert (to avoid duplicate certs
     931             :   // in the SignedData).
     932           0 :   if (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChain ||
     933             :       chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot) {
     934             :     UniqueCERTCertificate issuerCert(
     935           0 :       CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
     936             :     // the issuerCert of a self signed root is the cert itself,
     937             :     // so make sure we're not adding duplicates, again
     938           0 :     if (issuerCert && issuerCert != mCert) {
     939             :       bool includeRoot =
     940           0 :         (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot);
     941             :       UniqueCERTCertificateList certChain(
     942           0 :         CERT_CertChainFromCert(issuerCert.get(), certUsageAnyCA, includeRoot));
     943           0 :       if (certChain) {
     944           0 :         if (NSS_CMSSignedData_AddCertList(sigd.get(), certChain.get())
     945             :               == SECSuccess) {
     946           0 :           Unused << certChain.release();
     947             :         }
     948             :         else {
     949           0 :           MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     950             :                  ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
     951           0 :           return NS_ERROR_FAILURE;
     952             :         }
     953             :       }
     954             :       else {
     955             :         // try to add the issuerCert, at least
     956           0 :         if (NSS_CMSSignedData_AddCertificate(sigd.get(), issuerCert.get())
     957             :               == SECSuccess) {
     958           0 :           Unused << issuerCert.release();
     959             :         }
     960             :         else {
     961           0 :           MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     962             :                  ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
     963           0 :           return NS_ERROR_FAILURE;
     964             :         }
     965             :       }
     966             :     }
     967             :   }
     968             : 
     969           0 :   NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get());
     970           0 :   if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get())
     971             :        == SECSuccess) {
     972           0 :     Unused << sigd.release();
     973             :   }
     974             :   else {
     975           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     976             :            ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
     977           0 :     return NS_ERROR_FAILURE;
     978             :   }
     979             : 
     980           0 :   UniquePLArenaPool arena(PORT_NewArena(1024));
     981           0 :   if (!arena) {
     982           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     983             :            ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
     984           0 :     return NS_ERROR_OUT_OF_MEMORY;
     985             :   }
     986             : 
     987           0 :   SECItem certP7 = { siBuffer, nullptr, 0 };
     988           0 :   NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg.get(), nullptr, nullptr,
     989             :                                                    &certP7, arena.get(), nullptr,
     990             :                                                    nullptr, nullptr, nullptr,
     991           0 :                                                    nullptr, nullptr);
     992           0 :   if (!ecx) {
     993           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     994             :            ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
     995           0 :     return NS_ERROR_FAILURE;
     996             :   }
     997             : 
     998           0 :   if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
     999           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1000             :            ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
    1001           0 :     return NS_ERROR_FAILURE;
    1002             :   }
    1003             : 
    1004           0 :   *aArray = (uint8_t*)moz_xmalloc(certP7.len);
    1005           0 :   if (!*aArray)
    1006           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1007             : 
    1008           0 :   memcpy(*aArray, certP7.data, certP7.len);
    1009           0 :   *aLength = certP7.len;
    1010           0 :   return NS_OK;
    1011             : }
    1012             : 
    1013             : CERTCertificate*
    1014           0 : nsNSSCertificate::GetCert()
    1015             : {
    1016           0 :   nsNSSShutDownPreventionLock locker;
    1017           0 :   if (isAlreadyShutDown())
    1018           0 :     return nullptr;
    1019             : 
    1020           0 :   return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
    1021             : }
    1022             : 
    1023             : NS_IMETHODIMP
    1024           0 : nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
    1025             : {
    1026           0 :   nsNSSShutDownPreventionLock locker;
    1027           0 :   if (isAlreadyShutDown())
    1028           0 :     return NS_ERROR_NOT_AVAILABLE;
    1029             : 
    1030           0 :   NS_ENSURE_ARG(aValidity);
    1031             : 
    1032           0 :   if (!mCert) {
    1033           0 :     return NS_ERROR_FAILURE;
    1034             :   }
    1035             : 
    1036           0 :   nsCOMPtr<nsIX509CertValidity> validity = new nsX509CertValidity(mCert);
    1037           0 :   validity.forget(aValidity);
    1038           0 :   return NS_OK;
    1039             : }
    1040             : 
    1041             : NS_IMETHODIMP
    1042           0 : nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
    1043             : {
    1044           0 :   NS_ENSURE_ARG_POINTER(aASN1Structure);
    1045           0 :   if (!NS_IsMainThread()) {
    1046           0 :     return NS_ERROR_NOT_SAME_THREAD;
    1047             :   }
    1048           0 :   return CreateASN1Struct(aASN1Structure);
    1049             : }
    1050             : 
    1051             : NS_IMETHODIMP
    1052           0 : nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
    1053             : {
    1054           0 :   nsNSSShutDownPreventionLock locker;
    1055           0 :   if (isAlreadyShutDown())
    1056           0 :     return NS_ERROR_NOT_AVAILABLE;
    1057             : 
    1058           0 :   NS_ENSURE_ARG(other);
    1059           0 :   NS_ENSURE_ARG(result);
    1060             : 
    1061           0 :   UniqueCERTCertificate cert(other->GetCert());
    1062           0 :   *result = (mCert.get() == cert.get());
    1063           0 :   return NS_OK;
    1064             : }
    1065             : 
    1066             : namespace mozilla {
    1067             : 
    1068             : // TODO(bug 1036065): It seems like we only construct CERTCertLists for the
    1069             : // purpose of constructing nsNSSCertLists, so maybe we should change this
    1070             : // function to output an nsNSSCertList instead.
    1071             : SECStatus
    1072           0 : ConstructCERTCertListFromReversedDERArray(
    1073             :   const mozilla::pkix::DERArray& certArray,
    1074             :   /*out*/ UniqueCERTCertList& certList)
    1075             : {
    1076           0 :   certList = UniqueCERTCertList(CERT_NewCertList());
    1077           0 :   if (!certList) {
    1078           0 :     return SECFailure;
    1079             :   }
    1080             : 
    1081           0 :   CERTCertDBHandle* certDB(CERT_GetDefaultCertDB()); // non-owning
    1082             : 
    1083           0 :   size_t numCerts = certArray.GetLength();
    1084           0 :   for (size_t i = 0; i < numCerts; ++i) {
    1085           0 :     SECItem certDER(UnsafeMapInputToSECItem(*certArray.GetDER(i)));
    1086             :     UniqueCERTCertificate cert(CERT_NewTempCertificate(certDB, &certDER,
    1087           0 :                                                        nullptr, false, true));
    1088           0 :     if (!cert) {
    1089           0 :       return SECFailure;
    1090             :     }
    1091             :     // certArray is ordered with the root first, but we want the resulting
    1092             :     // certList to have the root last.
    1093           0 :     if (CERT_AddCertToListHead(certList.get(), cert.get()) != SECSuccess) {
    1094           0 :       return SECFailure;
    1095             :     }
    1096           0 :     Unused << cert.release(); // cert is now owned by certList.
    1097             :   }
    1098             : 
    1099           0 :   return SECSuccess;
    1100             : }
    1101             : 
    1102             : } // namespace mozilla
    1103             : 
    1104           3 : NS_IMPL_CLASSINFO(nsNSSCertList,
    1105             :                   nullptr,
    1106             :                   // inferred from nsIX509Cert
    1107             :                   nsIClassInfo::THREADSAFE,
    1108             :                   NS_X509CERTLIST_CID)
    1109             : 
    1110           0 : NS_IMPL_ISUPPORTS_CI(nsNSSCertList,
    1111             :                      nsIX509CertList,
    1112             :                      nsISerializable)
    1113             : 
    1114           0 : nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList,
    1115           0 :                              const nsNSSShutDownPreventionLock& proofOfLock)
    1116             : {
    1117           0 :   if (certList) {
    1118           0 :     mCertList = Move(certList);
    1119             :   } else {
    1120           0 :     mCertList = UniqueCERTCertList(CERT_NewCertList());
    1121             :   }
    1122           0 : }
    1123             : 
    1124           0 : nsNSSCertList::nsNSSCertList()
    1125             : {
    1126           0 :   mCertList = UniqueCERTCertList(CERT_NewCertList());
    1127           0 : }
    1128             : 
    1129           0 : nsNSSCertList::~nsNSSCertList()
    1130             : {
    1131           0 :   nsNSSShutDownPreventionLock locker;
    1132           0 :   if (isAlreadyShutDown()) {
    1133           0 :     return;
    1134             :   }
    1135           0 :   destructorSafeDestroyNSSReference();
    1136           0 :   shutdown(ShutdownCalledFrom::Object);
    1137           0 : }
    1138             : 
    1139           0 : void nsNSSCertList::virtualDestroyNSSReference()
    1140             : {
    1141           0 :   destructorSafeDestroyNSSReference();
    1142           0 : }
    1143             : 
    1144           0 : void nsNSSCertList::destructorSafeDestroyNSSReference()
    1145             : {
    1146           0 :   mCertList = nullptr;
    1147           0 : }
    1148             : 
    1149             : NS_IMETHODIMP
    1150           0 : nsNSSCertList::AddCert(nsIX509Cert* aCert)
    1151             : {
    1152           0 :   nsNSSShutDownPreventionLock locker;
    1153           0 :   if (isAlreadyShutDown()) {
    1154           0 :     return NS_ERROR_NOT_AVAILABLE;
    1155             :   }
    1156           0 :   CERTCertificate* cert = aCert->GetCert();
    1157           0 :   if (!cert) {
    1158           0 :     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
    1159           0 :     return NS_ERROR_FAILURE;
    1160             :   }
    1161             : 
    1162           0 :   if (!mCertList) {
    1163           0 :     NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
    1164           0 :     return NS_ERROR_FAILURE;
    1165             :   }
    1166             :   // XXX: check return value!
    1167           0 :   CERT_AddCertToListTail(mCertList.get(), cert);
    1168           0 :   return NS_OK;
    1169             : }
    1170             : 
    1171             : NS_IMETHODIMP
    1172           0 : nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
    1173             : {
    1174           0 :   nsNSSShutDownPreventionLock locker;
    1175           0 :   if (isAlreadyShutDown()) {
    1176           0 :     return NS_ERROR_NOT_AVAILABLE;
    1177             :   }
    1178           0 :   CERTCertificate* cert = aCert->GetCert();
    1179             :   CERTCertListNode* node;
    1180             : 
    1181           0 :   if (!cert) {
    1182           0 :     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
    1183           0 :     return NS_ERROR_FAILURE;
    1184             :   }
    1185             : 
    1186           0 :   if (!mCertList) {
    1187           0 :     NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
    1188           0 :     return NS_ERROR_FAILURE;
    1189             :   }
    1190             : 
    1191           0 :   for (node = CERT_LIST_HEAD(mCertList.get());
    1192           0 :        !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) {
    1193           0 :     if (node->cert == cert) {
    1194           0 :         CERT_RemoveCertListNode(node);
    1195           0 :         return NS_OK;
    1196             :     }
    1197             :   }
    1198           0 :   return NS_OK; // XXX Should we fail if we couldn't find it?
    1199             : }
    1200             : 
    1201             : UniqueCERTCertList
    1202           0 : nsNSSCertList::DupCertList(const UniqueCERTCertList& certList,
    1203             :                            const nsNSSShutDownPreventionLock& /*proofOfLock*/)
    1204             : {
    1205           0 :   if (!certList) {
    1206           0 :     return nullptr;
    1207             :   }
    1208             : 
    1209           0 :   UniqueCERTCertList newList(CERT_NewCertList());
    1210           0 :   if (!newList) {
    1211           0 :     return nullptr;
    1212             :   }
    1213             : 
    1214           0 :   for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
    1215           0 :        !CERT_LIST_END(node, certList);
    1216           0 :        node = CERT_LIST_NEXT(node)) {
    1217           0 :     UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
    1218           0 :     if (!cert) {
    1219           0 :       return nullptr;
    1220             :     }
    1221             : 
    1222           0 :     if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) {
    1223           0 :       return nullptr;
    1224             :     }
    1225             : 
    1226           0 :     Unused << cert.release(); // Ownership transferred to the cert list.
    1227             :   }
    1228           0 :   return newList;
    1229             : }
    1230             : 
    1231             : CERTCertList*
    1232           0 : nsNSSCertList::GetRawCertList()
    1233             : {
    1234             :   // This function should only be called after acquiring a
    1235             :   // nsNSSShutDownPreventionLock. It's difficult to enforce this in code since
    1236             :   // this is an implementation of an XPCOM interface function (albeit a
    1237             :   // C++-only one), so we acquire the (reentrant) lock and check for shutdown
    1238             :   // ourselves here. At the moment it appears that only nsCertTree uses this
    1239             :   // function. When that gets removed and replaced by a more reasonable
    1240             :   // implementation of the certificate manager, this function can be removed.
    1241           0 :   nsNSSShutDownPreventionLock locker;
    1242           0 :   if (isAlreadyShutDown()) {
    1243           0 :     return nullptr;
    1244             :   }
    1245           0 :   return mCertList.get();
    1246             : }
    1247             : 
    1248             : NS_IMETHODIMP
    1249           0 : nsNSSCertList::Write(nsIObjectOutputStream* aStream)
    1250             : {
    1251           0 :   nsNSSShutDownPreventionLock locker;
    1252           0 :   if (isAlreadyShutDown()) {
    1253           0 :     return NS_ERROR_NOT_AVAILABLE;
    1254             :   }
    1255             : 
    1256           0 :   NS_ENSURE_STATE(mCertList);
    1257           0 :   nsresult rv = NS_OK;
    1258             : 
    1259             :   // First, enumerate the certs to get the length of the list
    1260           0 :   uint32_t certListLen = 0;
    1261           0 :   CERTCertListNode* node = nullptr;
    1262           0 :   for (node = CERT_LIST_HEAD(mCertList);
    1263           0 :        !CERT_LIST_END(node, mCertList);
    1264           0 :        node = CERT_LIST_NEXT(node), ++certListLen) {
    1265             :   }
    1266             : 
    1267             :   // Write the length of the list
    1268           0 :   rv = aStream->Write32(certListLen);
    1269             : 
    1270             :   // Repeat the loop, and serialize each certificate
    1271           0 :   node = nullptr;
    1272           0 :   for (node = CERT_LIST_HEAD(mCertList);
    1273           0 :        !CERT_LIST_END(node, mCertList);
    1274           0 :        node = CERT_LIST_NEXT(node))
    1275             :   {
    1276           0 :     nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
    1277           0 :     if (!cert) {
    1278           0 :       rv = NS_ERROR_OUT_OF_MEMORY;
    1279           0 :       break;
    1280             :     }
    1281             : 
    1282           0 :     nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
    1283           0 :     rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert), true);
    1284           0 :     if (NS_FAILED(rv)) {
    1285           0 :       break;
    1286             :     }
    1287             :   }
    1288             : 
    1289           0 :   return rv;
    1290             : }
    1291             : 
    1292             : NS_IMETHODIMP
    1293           0 : nsNSSCertList::Read(nsIObjectInputStream* aStream)
    1294             : {
    1295           0 :   nsNSSShutDownPreventionLock locker;
    1296           0 :   if (isAlreadyShutDown()) {
    1297           0 :     return NS_ERROR_NOT_AVAILABLE;
    1298             :   }
    1299             : 
    1300           0 :   NS_ENSURE_STATE(mCertList);
    1301           0 :   nsresult rv = NS_OK;
    1302             : 
    1303             :   uint32_t certListLen;
    1304           0 :   rv = aStream->Read32(&certListLen);
    1305           0 :   if (NS_FAILED(rv)) {
    1306           0 :     return rv;
    1307             :   }
    1308             : 
    1309           0 :   for(uint32_t i = 0; i < certListLen; ++i) {
    1310           0 :     nsCOMPtr<nsISupports> certSupports;
    1311           0 :     rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
    1312           0 :     if (NS_FAILED(rv)) {
    1313           0 :       break;
    1314             :     }
    1315             : 
    1316           0 :     nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
    1317           0 :     rv = AddCert(cert);
    1318           0 :     if (NS_FAILED(rv)) {
    1319           0 :       break;
    1320             :     }
    1321             :   }
    1322             : 
    1323           0 :   return rv;
    1324             : }
    1325             : 
    1326             : NS_IMETHODIMP
    1327           0 : nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
    1328             : {
    1329           0 :   nsNSSShutDownPreventionLock locker;
    1330           0 :   if (isAlreadyShutDown()) {
    1331           0 :     return NS_ERROR_NOT_AVAILABLE;
    1332             :   }
    1333             : 
    1334           0 :   if (!mCertList) {
    1335           0 :     return NS_ERROR_FAILURE;
    1336             :   }
    1337             : 
    1338             :   nsCOMPtr<nsISimpleEnumerator> enumerator =
    1339           0 :     new nsNSSCertListEnumerator(mCertList, locker);
    1340             : 
    1341           0 :   enumerator.forget(_retval);
    1342           0 :   return NS_OK;
    1343             : }
    1344             : 
    1345             : NS_IMETHODIMP
    1346           0 : nsNSSCertList::Equals(nsIX509CertList* other, bool* result)
    1347             : {
    1348           0 :   nsNSSShutDownPreventionLock locker;
    1349           0 :   if (isAlreadyShutDown()) {
    1350           0 :     return NS_ERROR_NOT_AVAILABLE;
    1351             :   }
    1352             : 
    1353           0 :   NS_ENSURE_ARG(result);
    1354           0 :   *result = true;
    1355             : 
    1356             :   nsresult rv;
    1357             : 
    1358           0 :   nsCOMPtr<nsISimpleEnumerator> selfEnumerator;
    1359           0 :   rv = GetEnumerator(getter_AddRefs(selfEnumerator));
    1360           0 :   if (NS_FAILED(rv)) {
    1361           0 :     return rv;
    1362             :   }
    1363             : 
    1364           0 :   nsCOMPtr<nsISimpleEnumerator> otherEnumerator;
    1365           0 :   rv = other->GetEnumerator(getter_AddRefs(otherEnumerator));
    1366           0 :   if (NS_FAILED(rv)) {
    1367           0 :     return rv;
    1368             :   }
    1369             : 
    1370           0 :   nsCOMPtr<nsISupports> selfSupports;
    1371           0 :   nsCOMPtr<nsISupports> otherSupports;
    1372           0 :   while (NS_SUCCEEDED(selfEnumerator->GetNext(getter_AddRefs(selfSupports)))) {
    1373           0 :     if (NS_SUCCEEDED(otherEnumerator->GetNext(getter_AddRefs(otherSupports)))) {
    1374           0 :       nsCOMPtr<nsIX509Cert> selfCert = do_QueryInterface(selfSupports);
    1375           0 :       nsCOMPtr<nsIX509Cert> otherCert = do_QueryInterface(otherSupports);
    1376             : 
    1377           0 :       bool certsEqual = false;
    1378           0 :       rv = selfCert->Equals(otherCert, &certsEqual);
    1379           0 :       if (NS_FAILED(rv)) {
    1380           0 :         return rv;
    1381             :       }
    1382           0 :       if (!certsEqual) {
    1383           0 :         *result = false;
    1384           0 :         break;
    1385             :       }
    1386             :     } else {
    1387             :       // other is shorter than self
    1388           0 :       *result = false;
    1389           0 :       break;
    1390             :     }
    1391             :   }
    1392             : 
    1393             :   // Make sure self is the same length as other
    1394           0 :   bool otherHasMore = false;
    1395           0 :   rv = otherEnumerator->HasMoreElements(&otherHasMore);
    1396           0 :   if (NS_FAILED(rv)) {
    1397           0 :     return rv;
    1398             :   }
    1399           0 :   if (otherHasMore) {
    1400           0 :     *result = false;
    1401             :   }
    1402             : 
    1403           0 :   return NS_OK;
    1404             : }
    1405             : 
    1406           0 : NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
    1407             : 
    1408           0 : nsNSSCertListEnumerator::nsNSSCertListEnumerator(
    1409             :   const UniqueCERTCertList& certList,
    1410           0 :   const nsNSSShutDownPreventionLock& proofOfLock)
    1411             : {
    1412           0 :   MOZ_ASSERT(certList);
    1413           0 :   mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
    1414           0 : }
    1415             : 
    1416           0 : nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
    1417             : {
    1418           0 :   nsNSSShutDownPreventionLock locker;
    1419           0 :   if (isAlreadyShutDown()) {
    1420           0 :     return;
    1421             :   }
    1422           0 :   destructorSafeDestroyNSSReference();
    1423           0 :   shutdown(ShutdownCalledFrom::Object);
    1424           0 : }
    1425             : 
    1426           0 : void nsNSSCertListEnumerator::virtualDestroyNSSReference()
    1427             : {
    1428           0 :   destructorSafeDestroyNSSReference();
    1429           0 : }
    1430             : 
    1431           0 : void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference()
    1432             : {
    1433           0 :   mCertList = nullptr;
    1434           0 : }
    1435             : 
    1436             : NS_IMETHODIMP
    1437           0 : nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
    1438             : {
    1439           0 :   nsNSSShutDownPreventionLock locker;
    1440           0 :   if (isAlreadyShutDown()) {
    1441           0 :     return NS_ERROR_NOT_AVAILABLE;
    1442             :   }
    1443             : 
    1444           0 :   NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
    1445             : 
    1446           0 :   *_retval = !CERT_LIST_EMPTY(mCertList);
    1447           0 :   return NS_OK;
    1448             : }
    1449             : 
    1450             : NS_IMETHODIMP
    1451           0 : nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
    1452             : {
    1453           0 :   nsNSSShutDownPreventionLock locker;
    1454           0 :   if (isAlreadyShutDown()) {
    1455           0 :     return NS_ERROR_NOT_AVAILABLE;
    1456             :   }
    1457             : 
    1458           0 :   NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
    1459             : 
    1460           0 :   CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
    1461           0 :   if (CERT_LIST_END(node, mCertList)) {
    1462           0 :     return NS_ERROR_FAILURE;
    1463             :   }
    1464             : 
    1465           0 :   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
    1466           0 :   if (!nssCert) {
    1467           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1468             :   }
    1469             : 
    1470           0 :   nssCert.forget(_retval);
    1471             : 
    1472           0 :   CERT_RemoveCertListNode(node);
    1473           0 :   return NS_OK;
    1474             : }
    1475             : 
    1476             : NS_IMETHODIMP
    1477           0 : nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
    1478             : {
    1479           0 :   NS_ENSURE_STATE(mCert);
    1480             :   // This field used to be the cached EV status, but it is no longer necessary.
    1481           0 :   nsresult rv = aStream->Write32(0);
    1482           0 :   if (NS_FAILED(rv)) {
    1483           0 :     return rv;
    1484             :   }
    1485           0 :   rv = aStream->Write32(mCert->derCert.len);
    1486           0 :   if (NS_FAILED(rv)) {
    1487           0 :     return rv;
    1488             :   }
    1489           0 :   return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
    1490             : }
    1491             : 
    1492             : NS_IMETHODIMP
    1493           0 : nsNSSCertificate::Read(nsIObjectInputStream* aStream)
    1494             : {
    1495           0 :   NS_ENSURE_STATE(!mCert);
    1496             : 
    1497             :   // This field is no longer used.
    1498             :   uint32_t unusedCachedEVStatus;
    1499           0 :   nsresult rv = aStream->Read32(&unusedCachedEVStatus);
    1500           0 :   if (NS_FAILED(rv)) {
    1501           0 :     return rv;
    1502             :   }
    1503             : 
    1504             :   uint32_t len;
    1505           0 :   rv = aStream->Read32(&len);
    1506           0 :   if (NS_FAILED(rv)) {
    1507           0 :     return rv;
    1508             :   }
    1509             : 
    1510           0 :   nsXPIDLCString str;
    1511           0 :   rv = aStream->ReadBytes(len, getter_Copies(str));
    1512           0 :   if (NS_FAILED(rv)) {
    1513           0 :     return rv;
    1514             :   }
    1515             : 
    1516           0 :   if (!InitFromDER(const_cast<char*>(str.get()), len)) {
    1517           0 :     return NS_ERROR_UNEXPECTED;
    1518             :   }
    1519             : 
    1520           0 :   return NS_OK;
    1521             : }
    1522             : 
    1523             : NS_IMETHODIMP
    1524           0 : nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
    1525             : {
    1526           0 :   *count = 0;
    1527           0 :   *array = nullptr;
    1528           0 :   return NS_OK;
    1529             : }
    1530             : 
    1531             : NS_IMETHODIMP
    1532           0 : nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval)
    1533             : {
    1534           0 :   *_retval = nullptr;
    1535           0 :   return NS_OK;
    1536             : }
    1537             : 
    1538             : NS_IMETHODIMP
    1539           0 : nsNSSCertificate::GetContractID(char** aContractID)
    1540             : {
    1541           0 :   *aContractID = nullptr;
    1542           0 :   return NS_OK;
    1543             : }
    1544             : 
    1545             : NS_IMETHODIMP
    1546           0 : nsNSSCertificate::GetClassDescription(char** aClassDescription)
    1547             : {
    1548           0 :   *aClassDescription = nullptr;
    1549           0 :   return NS_OK;
    1550             : }
    1551             : 
    1552             : NS_IMETHODIMP
    1553           0 : nsNSSCertificate::GetClassID(nsCID** aClassID)
    1554             : {
    1555           0 :   *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
    1556           0 :   if (!*aClassID)
    1557           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1558           0 :   return GetClassIDNoAlloc(*aClassID);
    1559             : }
    1560             : 
    1561             : NS_IMETHODIMP
    1562           0 : nsNSSCertificate::GetFlags(uint32_t* aFlags)
    1563             : {
    1564           0 :   *aFlags = nsIClassInfo::THREADSAFE;
    1565           0 :   return NS_OK;
    1566             : }
    1567             : 
    1568             : NS_IMETHODIMP
    1569           0 : nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
    1570             : {
    1571             :   static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
    1572             : 
    1573           0 :   *aClassIDNoAlloc = kNSSCertificateCID;
    1574           0 :   return NS_OK;
    1575             : }

Generated by: LCOV version 1.13