security/manager/ssl/src/nsNSSCertificate.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 #include "nsNSSCertificate.h"
     8 #include "prmem.h"
     9 #include "prerror.h"
    10 #include "prprf.h"
    11 #include "CertVerifier.h"
    12 #include "ExtendedValidation.h"
    13 #include "pkix/pkixtypes.h"
    14 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
    15 #include "nsNSSCleaner.h"
    16 #include "nsCOMPtr.h"
    17 #include "nsIMutableArray.h"
    18 #include "nsNSSCertValidity.h"
    19 #include "nsPKCS12Blob.h"
    20 #include "nsPK11TokenDB.h"
    21 #include "nsIX509Cert.h"
    22 #include "nsIX509Cert3.h"
    23 #include "nsISMimeCert.h"
    24 #include "nsNSSASN1Object.h"
    25 #include "nsString.h"
    26 #include "nsXPIDLString.h"
    27 #include "nsReadableUtils.h"
    28 #include "nsIURI.h"
    29 #include "nsCRT.h"
    30 #include "nsUsageArrayHelper.h"
    31 #include "nsICertificateDialogs.h"
    32 #include "nsNSSCertHelper.h"
    33 #include "nsISupportsPrimitives.h"
    34 #include "nsUnicharUtils.h"
    35 #include "nsThreadUtils.h"
    36 #include "nsCertVerificationThread.h"
    37 #include "nsIObjectOutputStream.h"
    38 #include "nsIObjectInputStream.h"
    39 #include "nsIProgrammingLanguage.h"
    40 #include "nsXULAppAPI.h"
    41 #include "ScopedNSSTypes.h"
    42 #include "nsProxyRelease.h"
    43 #include "mozilla/Base64.h"
    45 #include "nspr.h"
    46 #include "certdb.h"
    47 #include "secerr.h"
    48 #include "nssb64.h"
    49 #include "secasn1.h"
    50 #include "secder.h"
    51 #include "ssl.h"
    52 #include "ocsp.h"
    53 #include "plbase64.h"
    55 using namespace mozilla;
    56 using namespace mozilla::psm;
    58 #ifdef PR_LOGGING
    59 extern PRLogModuleInfo* gPIPNSSLog;
    60 #endif
    62 NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
    64 // This is being stored in an uint32_t that can otherwise
    65 // only take values from nsIX509Cert's list of cert types.
    66 // As nsIX509Cert is frozen, we choose a value not contained
    67 // in the list to mean not yet initialized.
    68 #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
    70 NS_IMPL_ISUPPORTS(nsNSSCertificate,
    71                   nsIX509Cert,
    72                   nsIX509Cert2,
    73                   nsIX509Cert3,
    74                   nsIIdentityInfo,
    75                   nsISMimeCert,
    76                   nsISerializable,
    77                   nsIClassInfo)
    79 /*static*/ nsNSSCertificate*
    80 nsNSSCertificate::Create(CERTCertificate* cert, SECOidTag* evOidPolicy)
    81 {
    82   if (GeckoProcessType_Default != XRE_GetProcessType()) {
    83     NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
    84     return nullptr;
    85   }
    86   if (cert)
    87     return new nsNSSCertificate(cert, evOidPolicy);
    88   else
    89     return new nsNSSCertificate();
    90 }
    92 nsNSSCertificate*
    93 nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
    94 {
    95   // On non-chrome process prevent instantiation
    96   if (GeckoProcessType_Default != XRE_GetProcessType())
    97     return nullptr;
    99   nsNSSCertificate* newObject = nsNSSCertificate::Create();
   100   if (newObject && !newObject->InitFromDER(certDER, derLen)) {
   101     delete newObject;
   102     newObject = nullptr;
   103   }
   105   return newObject;
   106 }
   108 bool
   109 nsNSSCertificate::InitFromDER(char* certDER, int derLen)
   110 {
   111   nsNSSShutDownPreventionLock locker;
   112   if (isAlreadyShutDown())
   113     return false;
   115   if (!certDER || !derLen)
   116     return false;
   118   CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
   120   if (!aCert)
   121     return false;
   123   if (!aCert->dbhandle)
   124   {
   125     aCert->dbhandle = CERT_GetDefaultCertDB();
   126   }
   128   mCert = aCert;
   129   return true;
   130 }
   132 nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert,
   133                                    SECOidTag* evOidPolicy)
   134   : mCert(nullptr)
   135   , mPermDelete(false)
   136   , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
   137   , mCachedEVStatus(ev_status_unknown)
   138 {
   139 #if defined(DEBUG)
   140   if (GeckoProcessType_Default != XRE_GetProcessType())
   141     NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
   142 #endif
   144   nsNSSShutDownPreventionLock locker;
   145   if (isAlreadyShutDown())
   146     return;
   148   if (cert) {
   149     mCert = CERT_DupCertificate(cert);
   150     if (evOidPolicy) {
   151       if (*evOidPolicy == SEC_OID_UNKNOWN) {
   152         mCachedEVStatus =  ev_status_invalid;
   153       }
   154       else {
   155         mCachedEVStatus = ev_status_valid;
   156       }
   157       mCachedEVOidTag = *evOidPolicy;
   158     }
   159   }
   160 }
   162 nsNSSCertificate::nsNSSCertificate() :
   163   mCert(nullptr),
   164   mPermDelete(false),
   165   mCertType(CERT_TYPE_NOT_YET_INITIALIZED),
   166   mCachedEVStatus(ev_status_unknown)
   167 {
   168   if (GeckoProcessType_Default != XRE_GetProcessType())
   169     NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
   170 }
   172 nsNSSCertificate::~nsNSSCertificate()
   173 {
   174   nsNSSShutDownPreventionLock locker;
   175   if (isAlreadyShutDown()) {
   176     return;
   177   }
   178   destructorSafeDestroyNSSReference();
   179   shutdown(calledFromObject);
   180 }
   182 void nsNSSCertificate::virtualDestroyNSSReference()
   183 {
   184   destructorSafeDestroyNSSReference();
   185 }
   187 void nsNSSCertificate::destructorSafeDestroyNSSReference()
   188 {
   189   if (mPermDelete) {
   190     if (mCertType == nsNSSCertificate::USER_CERT) {
   191       nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
   192       PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
   193     } else if (!PK11_IsReadOnly(mCert->slot)) {
   194       // If the list of built-ins does contain a non-removable
   195       // copy of this certificate, our call will not remove
   196       // the certificate permanently, but rather remove all trust.
   197       SEC_DeletePermCertificate(mCert.get());
   198     }
   199   }
   201   mCert = nullptr;
   202 }
   204 nsresult
   205 nsNSSCertificate::GetCertType(uint32_t* aCertType)
   206 {
   207   if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
   208      // only determine cert type once and cache it
   209      mCertType = getCertType(mCert.get());
   210   }
   211   *aCertType = mCertType;
   212   return NS_OK;
   213 }
   215 NS_IMETHODIMP
   216 nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
   217 {
   218   NS_ENSURE_ARG(aIsSelfSigned);
   220   nsNSSShutDownPreventionLock locker;
   221   if (isAlreadyShutDown())
   222     return NS_ERROR_NOT_AVAILABLE;
   224   *aIsSelfSigned = mCert->isRoot;
   225   return NS_OK;
   226 }
   228 nsresult
   229 nsNSSCertificate::MarkForPermDeletion()
   230 {
   231   nsNSSShutDownPreventionLock locker;
   232   if (isAlreadyShutDown())
   233     return NS_ERROR_NOT_AVAILABLE;
   235   // make sure user is logged in to the token
   236   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
   238   if (PK11_NeedLogin(mCert->slot)
   239       && !PK11_NeedUserInit(mCert->slot)
   240       && !PK11_IsInternal(mCert->slot))
   241   {
   242     if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx))
   243     {
   244       return NS_ERROR_FAILURE;
   245     }
   246   }
   248   mPermDelete = true;
   249   return NS_OK;
   250 }
   252 nsresult
   253 GetKeyUsagesString(CERTCertificate* cert, nsINSSComponent* nssComponent,
   254                    nsString& text)
   255 {
   256   text.Truncate();
   258   SECItem keyUsageItem;
   259   keyUsageItem.data = nullptr;
   261   SECStatus srv;
   263   // There is no extension, v1 or v2 certificate
   264   if (!cert->extensions)
   265     return NS_OK;
   268   srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
   269   if (srv == SECFailure) {
   270     if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND)
   271       return NS_OK;
   272     else
   273       return NS_ERROR_FAILURE;
   274   }
   276   unsigned char keyUsage = keyUsageItem.data[0];
   277   nsAutoString local;
   278   nsresult rv;
   279   const char16_t comma = ',';
   281   if (keyUsage & KU_DIGITAL_SIGNATURE) {
   282     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local);
   283     if (NS_SUCCEEDED(rv)) {
   284       if (!text.IsEmpty()) text.Append(comma);
   285       text.Append(local.get());
   286     }
   287   }
   288   if (keyUsage & KU_NON_REPUDIATION) {
   289     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local);
   290     if (NS_SUCCEEDED(rv)) {
   291       if (!text.IsEmpty()) text.Append(comma);
   292       text.Append(local.get());
   293     }
   294   }
   295   if (keyUsage & KU_KEY_ENCIPHERMENT) {
   296     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local);
   297     if (NS_SUCCEEDED(rv)) {
   298       if (!text.IsEmpty()) text.Append(comma);
   299       text.Append(local.get());
   300     }
   301   }
   302   if (keyUsage & KU_DATA_ENCIPHERMENT) {
   303     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local);
   304     if (NS_SUCCEEDED(rv)) {
   305       if (!text.IsEmpty()) text.Append(comma);
   306       text.Append(local.get());
   307     }
   308   }
   309   if (keyUsage & KU_KEY_AGREEMENT) {
   310     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local);
   311     if (NS_SUCCEEDED(rv)) {
   312       if (!text.IsEmpty()) text.Append(comma);
   313       text.Append(local.get());
   314     }
   315   }
   316   if (keyUsage & KU_KEY_CERT_SIGN) {
   317     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local);
   318     if (NS_SUCCEEDED(rv)) {
   319       if (!text.IsEmpty()) text.Append(comma);
   320       text.Append(local.get());
   321     }
   322   }
   323   if (keyUsage & KU_CRL_SIGN) {
   324     rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local);
   325     if (NS_SUCCEEDED(rv)) {
   326       if (!text.IsEmpty()) text.Append(comma);
   327       text.Append(local.get());
   328     }
   329   }
   331   PORT_Free (keyUsageItem.data);
   332   return NS_OK;
   333 }
   335 nsresult
   336 nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname,
   337                                   nsAutoString& nickWithSerial,
   338                                   nsAutoString& details)
   339 {
   340   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   342   if (!NS_IsMainThread()) {
   343     NS_ERROR("nsNSSCertificate::FormatUIStrings called off the main thread");
   344     return NS_ERROR_NOT_SAME_THREAD;
   345   }
   347   nsresult rv = NS_OK;
   349   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   351   if (NS_FAILED(rv) || !nssComponent) {
   352     return NS_ERROR_FAILURE;
   353   }
   355   nsAutoString info;
   356   nsAutoString temp1;
   358   nickWithSerial.Append(nickname);
   360   if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) {
   361     details.Append(info);
   362     details.Append(char16_t(' '));
   363     if (NS_SUCCEEDED(GetSubjectName(temp1)) && !temp1.IsEmpty()) {
   364       details.Append(temp1);
   365     }
   366     details.Append(char16_t('\n'));
   367   }
   369   if (NS_SUCCEEDED(GetSerialNumber(temp1)) && !temp1.IsEmpty()) {
   370     details.AppendLiteral("  ");
   371     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) {
   372       details.Append(info);
   373       details.AppendLiteral(": ");
   374     }
   375     details.Append(temp1);
   377     nickWithSerial.AppendLiteral(" [");
   378     nickWithSerial.Append(temp1);
   379     nickWithSerial.Append(char16_t(']'));
   381     details.Append(char16_t('\n'));
   382   }
   384   nsCOMPtr<nsIX509CertValidity> validity;
   385   rv = GetValidity(getter_AddRefs(validity));
   386   if (NS_SUCCEEDED(rv) && validity) {
   387     details.AppendLiteral("  ");
   388     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) {
   389       details.Append(info);
   390     }
   392     if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) {
   393       details.Append(char16_t(' '));
   394       if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) {
   395         details.Append(info);
   396         details.Append(char16_t(' '));
   397       }
   398       details.Append(temp1);
   399     }
   401     if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) {
   402       details.Append(char16_t(' '));
   403       if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) {
   404         details.Append(info);
   405         details.Append(char16_t(' '));
   406       }
   407       details.Append(temp1);
   408     }
   410     details.Append(char16_t('\n'));
   411   }
   413   if (NS_SUCCEEDED(GetKeyUsagesString(mCert.get(), nssComponent, temp1)) &&
   414       !temp1.IsEmpty()) {
   415     details.AppendLiteral("  ");
   416     if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) {
   417       details.Append(info);
   418       details.AppendLiteral(": ");
   419     }
   420     details.Append(temp1);
   421     details.Append(char16_t('\n'));
   422   }
   424   nsAutoString firstEmail;
   425   const char* aWalkAddr;
   426   for (aWalkAddr = CERT_GetFirstEmailAddress(mCert.get())
   427         ;
   428         aWalkAddr
   429         ;
   430         aWalkAddr = CERT_GetNextEmailAddress(mCert.get(), aWalkAddr))
   431   {
   432     NS_ConvertUTF8toUTF16 email(aWalkAddr);
   433     if (email.IsEmpty())
   434       continue;
   436     if (firstEmail.IsEmpty()) {
   437       // If the first email address from the subject DN is also present
   438       // in the subjectAltName extension, GetEmailAddresses() will return
   439       // it twice (as received from NSS). Remember the first address so that
   440       // we can filter out duplicates later on.
   441       firstEmail = email;
   443       details.AppendLiteral("  ");
   444       if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoEmail", info))) {
   445         details.Append(info);
   446         details.AppendLiteral(": ");
   447       }
   448       details.Append(email);
   449     }
   450     else {
   451       // Append current address if it's different from the first one.
   452       if (!firstEmail.Equals(email)) {
   453         details.AppendLiteral(", ");
   454         details.Append(email);
   455       }
   456     }
   457   }
   459   if (!firstEmail.IsEmpty()) {
   460     // We got at least one email address, so we want a newline
   461     details.Append(char16_t('\n'));
   462   }
   464   if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) {
   465     details.Append(info);
   466     details.Append(char16_t(' '));
   468     if (NS_SUCCEEDED(GetIssuerName(temp1)) && !temp1.IsEmpty()) {
   469       details.Append(temp1);
   470     }
   472     details.Append(char16_t('\n'));
   473   }
   475   if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) {
   476     details.Append(info);
   477     details.Append(char16_t(' '));
   479     if (NS_SUCCEEDED(GetTokenName(temp1)) && !temp1.IsEmpty()) {
   480       details.Append(temp1);
   481     }
   482   }
   484   // the above produces the following output:
   485   //
   486   //   Issued to: $subjectName
   487   //   Serial number: $serialNumber
   488   //   Valid from: $starting_date to $expiration_date
   489   //   Certificate Key usage: $usages
   490   //   Email: $address(es)
   491   //   Issued by: $issuerName
   492   //   Stored in: $token
   494   return rv;
   495 }
   497 NS_IMETHODIMP
   498 nsNSSCertificate::GetDbKey(char** aDbKey)
   499 {
   500   nsNSSShutDownPreventionLock locker;
   501   if (isAlreadyShutDown())
   502     return NS_ERROR_NOT_AVAILABLE;
   504   SECItem key;
   506   NS_ENSURE_ARG(aDbKey);
   507   *aDbKey = nullptr;
   508   key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
   509   key.data = (unsigned char*) nsMemory::Alloc(key.len);
   510   if (!key.data)
   511     return NS_ERROR_OUT_OF_MEMORY;
   512   NS_NSS_PUT_LONG(0,key.data); // later put moduleID
   513   NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID
   514   NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
   515   NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
   516   memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data,
   517          mCert->serialNumber.len);
   518   memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len],
   519          mCert->derIssuer.data, mCert->derIssuer.len);
   521   *aDbKey = NSSBase64_EncodeItem(nullptr, nullptr, 0, &key);
   522   nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
   523   return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
   524 }
   526 NS_IMETHODIMP
   527 nsNSSCertificate::GetWindowTitle(char** aWindowTitle)
   528 {
   529   nsNSSShutDownPreventionLock locker;
   530   if (isAlreadyShutDown())
   531     return NS_ERROR_NOT_AVAILABLE;
   533   NS_ENSURE_ARG(aWindowTitle);
   534   if (mCert) {
   535     if (mCert->nickname) {
   536       *aWindowTitle = PL_strdup(mCert->nickname);
   537     } else {
   538       *aWindowTitle = CERT_GetCommonName(&mCert->subject);
   539       if (!*aWindowTitle) {
   540         if (mCert->subjectName) {
   541           *aWindowTitle = PL_strdup(mCert->subjectName);
   542         } else if (mCert->emailAddr) {
   543           *aWindowTitle = PL_strdup(mCert->emailAddr);
   544         } else {
   545           *aWindowTitle = PL_strdup("");
   546         }
   547       }
   548     }
   549   } else {
   550     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
   551     *aWindowTitle = nullptr;
   552   }
   553   return NS_OK;
   554 }
   556 NS_IMETHODIMP
   557 nsNSSCertificate::GetNickname(nsAString& aNickname)
   558 {
   559   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   561   nsNSSShutDownPreventionLock locker;
   562   if (isAlreadyShutDown())
   563     return NS_ERROR_NOT_AVAILABLE;
   565   if (mCert->nickname) {
   566     CopyUTF8toUTF16(mCert->nickname, aNickname);
   567   } else {
   568     nsresult rv;
   569     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   570     if (NS_FAILED(rv) || !nssComponent) {
   571       return NS_ERROR_FAILURE;
   572     }
   573     nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
   574   }
   575   return NS_OK;
   576 }
   578 NS_IMETHODIMP
   579 nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
   580 {
   581   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   583   nsNSSShutDownPreventionLock locker;
   584   if (isAlreadyShutDown())
   585     return NS_ERROR_NOT_AVAILABLE;
   587   if (mCert->emailAddr) {
   588     CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
   589   } else {
   590     nsresult rv;
   591     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   592     if (NS_FAILED(rv) || !nssComponent) {
   593       return NS_ERROR_FAILURE;
   594     }
   595     nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
   596   }
   597   return NS_OK;
   598 }
   600 NS_IMETHODIMP
   601 nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
   602 {
   603   nsNSSShutDownPreventionLock locker;
   604   if (isAlreadyShutDown())
   605     return NS_ERROR_NOT_AVAILABLE;
   607   NS_ENSURE_ARG(aLength);
   608   NS_ENSURE_ARG(aAddresses);
   610   *aLength = 0;
   612   const char* aAddr;
   613   for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
   614        ;
   615        aAddr
   616        ;
   617        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
   618   {
   619     ++(*aLength);
   620   }
   622   *aAddresses = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength));
   623   if (!*aAddresses)
   624     return NS_ERROR_OUT_OF_MEMORY;
   626   uint32_t iAddr;
   627   for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
   628        ;
   629        aAddr
   630        ;
   631        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
   632   {
   633     (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
   634   }
   636   return NS_OK;
   637 }
   639 NS_IMETHODIMP
   640 nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
   641                                        bool* result)
   642 {
   643   nsNSSShutDownPreventionLock locker;
   644   if (isAlreadyShutDown())
   645     return NS_ERROR_NOT_AVAILABLE;
   647   NS_ENSURE_ARG(result);
   648   *result = false;
   650   const char* aAddr = nullptr;
   651   for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
   652        ;
   653        aAddr
   654        ;
   655        aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
   656   {
   657     NS_ConvertUTF8toUTF16 certAddr(aAddr);
   658     ToLowerCase(certAddr);
   660     nsAutoString testAddr(aEmailAddress);
   661     ToLowerCase(testAddr);
   663     if (certAddr == testAddr)
   664     {
   665       *result = true;
   666       break;
   667     }
   669   }
   671   return NS_OK;
   672 }
   674 NS_IMETHODIMP
   675 nsNSSCertificate::GetCommonName(nsAString& aCommonName)
   676 {
   677   nsNSSShutDownPreventionLock locker;
   678   if (isAlreadyShutDown())
   679     return NS_ERROR_NOT_AVAILABLE;
   681   aCommonName.Truncate();
   682   if (mCert) {
   683     char* commonName = CERT_GetCommonName(&mCert->subject);
   684     if (commonName) {
   685       aCommonName = NS_ConvertUTF8toUTF16(commonName);
   686       PORT_Free(commonName);
   687     }
   688   }
   689   return NS_OK;
   690 }
   692 NS_IMETHODIMP
   693 nsNSSCertificate::GetOrganization(nsAString& aOrganization)
   694 {
   695   nsNSSShutDownPreventionLock locker;
   696   if (isAlreadyShutDown())
   697     return NS_ERROR_NOT_AVAILABLE;
   699   aOrganization.Truncate();
   700   if (mCert) {
   701     char* organization = CERT_GetOrgName(&mCert->subject);
   702     if (organization) {
   703       aOrganization = NS_ConvertUTF8toUTF16(organization);
   704       PORT_Free(organization);
   705     }
   706   }
   707   return NS_OK;
   708 }
   710 NS_IMETHODIMP
   711 nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
   712 {
   713   nsNSSShutDownPreventionLock locker;
   714   if (isAlreadyShutDown())
   715     return NS_ERROR_NOT_AVAILABLE;
   717   aCommonName.Truncate();
   718   if (mCert) {
   719     char* commonName = CERT_GetCommonName(&mCert->issuer);
   720     if (commonName) {
   721       aCommonName = NS_ConvertUTF8toUTF16(commonName);
   722       PORT_Free(commonName);
   723     }
   724   }
   725   return NS_OK;
   726 }
   728 NS_IMETHODIMP
   729 nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
   730 {
   731   nsNSSShutDownPreventionLock locker;
   732   if (isAlreadyShutDown())
   733     return NS_ERROR_NOT_AVAILABLE;
   735   aOrganization.Truncate();
   736   if (mCert) {
   737     char* organization = CERT_GetOrgName(&mCert->issuer);
   738     if (organization) {
   739       aOrganization = NS_ConvertUTF8toUTF16(organization);
   740       PORT_Free(organization);
   741     } else {
   742       return GetIssuerCommonName(aOrganization);
   743     }
   744   }
   745   return NS_OK;
   746 }
   748 NS_IMETHODIMP
   749 nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
   750 {
   751   nsNSSShutDownPreventionLock locker;
   752   if (isAlreadyShutDown())
   753     return NS_ERROR_NOT_AVAILABLE;
   755   aOrganizationUnit.Truncate();
   756   if (mCert) {
   757     char* organizationUnit = CERT_GetOrgUnitName(&mCert->issuer);
   758     if (organizationUnit) {
   759       aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit);
   760       PORT_Free(organizationUnit);
   761     }
   762   }
   763   return NS_OK;
   764 }
   766 NS_IMETHODIMP
   767 nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer)
   768 {
   769   nsNSSShutDownPreventionLock locker;
   770   if (isAlreadyShutDown())
   771     return NS_ERROR_NOT_AVAILABLE;
   773   NS_ENSURE_ARG(aIssuer);
   774   *aIssuer = nullptr;
   776   nsCOMPtr<nsIArray> chain;
   777   nsresult rv;
   778   rv = GetChain(getter_AddRefs(chain));
   779   NS_ENSURE_SUCCESS(rv, rv);
   780   uint32_t length;
   781   if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) {
   782     return NS_ERROR_UNEXPECTED;
   783   }
   784   if (length == 1) { // No known issuer
   785     return NS_OK;
   786   }
   787   nsCOMPtr<nsIX509Cert> cert;
   788   chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert));
   789   if (!cert) {
   790     return NS_ERROR_UNEXPECTED;
   791   }
   792   *aIssuer = cert;
   793   NS_ADDREF(*aIssuer);
   794   return NS_OK;
   795 }
   797 NS_IMETHODIMP
   798 nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
   799 {
   800   nsNSSShutDownPreventionLock locker;
   801   if (isAlreadyShutDown())
   802     return NS_ERROR_NOT_AVAILABLE;
   804   aOrganizationalUnit.Truncate();
   805   if (mCert) {
   806     char* orgunit = CERT_GetOrgUnitName(&mCert->subject);
   807     if (orgunit) {
   808       aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit);
   809       PORT_Free(orgunit);
   810     }
   811   }
   812   return NS_OK;
   813 }
   815 NS_IMETHODIMP
   816 nsNSSCertificate::GetChain(nsIArray** _rvChain)
   817 {
   818   nsNSSShutDownPreventionLock locker;
   819   if (isAlreadyShutDown())
   820     return NS_ERROR_NOT_AVAILABLE;
   822   NS_ENSURE_ARG(_rvChain);
   823   nsresult rv;
   824   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
   826   ::mozilla::pkix::ScopedCERTCertList nssChain;
   827   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
   828   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
   830   // We want to test all usages, but we start with server because most of the
   831   // time Firefox users care about server certs.
   832   certVerifier->VerifyCert(mCert.get(),
   833                            certificateUsageSSLServer, PR_Now(),
   834                            nullptr, /*XXX fixme*/
   835                            nullptr, /* hostname */
   836                            CertVerifier::FLAG_LOCAL_ONLY,
   837                            nullptr, /* stapledOCSPResponse */
   838                            &nssChain);
   839   // This is the whitelist of all non-SSLServer usages that are supported by
   840   // verifycert.
   841   const int otherUsagesToTest = certificateUsageSSLClient |
   842                                 certificateUsageSSLCA |
   843                                 certificateUsageEmailSigner |
   844                                 certificateUsageEmailRecipient |
   845                                 certificateUsageObjectSigner |
   846                                 certificateUsageStatusResponder;
   847   for (int usage = certificateUsageSSLClient;
   848        usage < certificateUsageAnyCA && !nssChain;
   849        usage = usage << 1) {
   850     if ((usage & otherUsagesToTest) == 0) {
   851       continue;
   852     }
   853     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   854            ("pipnss: PKIX attempting chain(%d) for '%s'\n",
   855             usage, mCert->nickname));
   856     certVerifier->VerifyCert(mCert.get(),
   857                              usage, PR_Now(),
   858                              nullptr, /*XXX fixme*/
   859                              nullptr, /*hostname*/
   860                              CertVerifier::FLAG_LOCAL_ONLY,
   861                              nullptr, /* stapledOCSPResponse */
   862                              &nssChain);
   863   }
   865   if (!nssChain) {
   866     // There is not verified path for the chain, howeever we still want to 
   867     // present to the user as much of a possible chain as possible, in the case
   868     // where there was a problem with the cert or the issuers.
   869     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   870            ("pipnss: getchain :CertVerify failed to get chain for '%s'\n",
   871             mCert->nickname));
   872     nssChain = CERT_GetCertChainFromCert(mCert.get(), PR_Now(),
   873                                          certUsageSSLClient);
   874   } 
   876   if (!nssChain) {
   877     return NS_ERROR_FAILURE;
   878   }
   880   // enumerate the chain for scripting purposes
   881   nsCOMPtr<nsIMutableArray> array =
   882     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   883   if (NS_FAILED(rv)) {
   884     goto done;
   885   }
   886   CERTCertListNode* node;
   887   for (node = CERT_LIST_HEAD(nssChain.get());
   888        !CERT_LIST_END(node, nssChain.get());
   889        node = CERT_LIST_NEXT(node)) {
   890     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   891            ("adding %s to chain\n", node->cert->nickname));
   892     nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
   893     array->AppendElement(cert, false);
   894   }
   895   *_rvChain = array;
   896   NS_IF_ADDREF(*_rvChain);
   897   rv = NS_OK;
   898 done:
   899   return rv;
   900 }
   902 NS_IMETHODIMP
   903 nsNSSCertificate::GetAllTokenNames(uint32_t* aLength, char16_t*** aTokenNames)
   904 {
   905   nsNSSShutDownPreventionLock locker;
   906   if (isAlreadyShutDown())
   907     return NS_ERROR_NOT_AVAILABLE;
   909   NS_ENSURE_ARG(aLength);
   910   NS_ENSURE_ARG(aTokenNames);
   911   *aLength = 0;
   912   *aTokenNames = nullptr;
   914   // Get the slots from NSS
   915   ScopedPK11SlotList slots;
   916   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting slots for \"%s\"\n", mCert->nickname));
   917   slots = PK11_GetAllSlotsForCert(mCert.get(), nullptr);
   918   if (!slots) {
   919     if (PORT_GetError() == SEC_ERROR_NO_TOKEN)
   920       return NS_OK; // List of slots is empty, return empty array
   921     else
   922       return NS_ERROR_FAILURE;
   923   }
   925   // read the token names from slots
   926   PK11SlotListElement* le;
   928   for (le = slots->head; le; le = le->next) {
   929     ++(*aLength);
   930   }
   932   *aTokenNames = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength));
   933   if (!*aTokenNames) {
   934     *aLength = 0;
   935     return NS_ERROR_OUT_OF_MEMORY;
   936   }
   938   uint32_t iToken;
   939   for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) {
   940     char* token = PK11_GetTokenName(le->slot);
   941     (*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token));
   942     if (!(*aTokenNames)[iToken]) {
   943       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames);
   944       *aLength = 0;
   945       *aTokenNames = nullptr;
   946       return NS_ERROR_OUT_OF_MEMORY;
   947     }
   948   }
   950   return NS_OK;
   951 }
   953 NS_IMETHODIMP
   954 nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
   955 {
   956   nsNSSShutDownPreventionLock locker;
   957   if (isAlreadyShutDown())
   958     return NS_ERROR_NOT_AVAILABLE;
   960   _subjectName.Truncate();
   961   if (mCert->subjectName) {
   962     _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
   963     return NS_OK;
   964   }
   965   return NS_ERROR_FAILURE;
   966 }
   968 NS_IMETHODIMP
   969 nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
   970 {
   971   nsNSSShutDownPreventionLock locker;
   972   if (isAlreadyShutDown())
   973     return NS_ERROR_NOT_AVAILABLE;
   975   _issuerName.Truncate();
   976   if (mCert->issuerName) {
   977     _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
   978     return NS_OK;
   979   }
   980   return NS_ERROR_FAILURE;
   981 }
   983 NS_IMETHODIMP
   984 nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
   985 {
   986   nsNSSShutDownPreventionLock locker;
   987   if (isAlreadyShutDown())
   988     return NS_ERROR_NOT_AVAILABLE;
   990   _serialNumber.Truncate();
   991   char* tmpstr = CERT_Hexify(&mCert->serialNumber, 1);
   992   if (tmpstr) {
   993     _serialNumber = NS_ConvertASCIItoUTF16(tmpstr);
   994     PORT_Free(tmpstr);
   995     return NS_OK;
   996   }
   997   return NS_ERROR_FAILURE;
   998 }
  1000 NS_IMETHODIMP
  1001 nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
  1003   nsNSSShutDownPreventionLock locker;
  1004   if (isAlreadyShutDown())
  1005     return NS_ERROR_NOT_AVAILABLE;
  1007   _sha1Fingerprint.Truncate();
  1008   unsigned char fingerprint[20];
  1009   SECItem fpItem;
  1010   memset(fingerprint, 0, sizeof fingerprint);
  1011   PK11_HashBuf(SEC_OID_SHA1, fingerprint,
  1012                mCert->derCert.data, mCert->derCert.len);
  1013   fpItem.data = fingerprint;
  1014   fpItem.len = SHA1_LENGTH;
  1015   char* fpStr = CERT_Hexify(&fpItem, 1);
  1016   if (fpStr) {
  1017     _sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
  1018     PORT_Free(fpStr);
  1019     return NS_OK;
  1021   return NS_ERROR_FAILURE;
  1024 NS_IMETHODIMP
  1025 nsNSSCertificate::GetMd5Fingerprint(nsAString& _md5Fingerprint)
  1027   nsNSSShutDownPreventionLock locker;
  1028   if (isAlreadyShutDown())
  1029     return NS_ERROR_NOT_AVAILABLE;
  1031   _md5Fingerprint.Truncate();
  1032   unsigned char fingerprint[20];
  1033   SECItem fpItem;
  1034   memset(fingerprint, 0, sizeof fingerprint);
  1035   PK11_HashBuf(SEC_OID_MD5, fingerprint,
  1036                mCert->derCert.data, mCert->derCert.len);
  1037   fpItem.data = fingerprint;
  1038   fpItem.len = MD5_LENGTH;
  1039   char* fpStr = CERT_Hexify(&fpItem, 1);
  1040   if (fpStr) {
  1041     _md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
  1042     PORT_Free(fpStr);
  1043     return NS_OK;
  1045   return NS_ERROR_FAILURE;
  1048 NS_IMETHODIMP
  1049 nsNSSCertificate::GetTokenName(nsAString& aTokenName)
  1051   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1053   nsNSSShutDownPreventionLock locker;
  1054   if (isAlreadyShutDown())
  1055     return NS_ERROR_NOT_AVAILABLE;
  1057   aTokenName.Truncate();
  1058   if (mCert) {
  1059     // HACK alert
  1060     // When the trust of a builtin cert is modified, NSS copies it into the
  1061     // cert db.  At this point, it is now "managed" by the user, and should
  1062     // not be listed with the builtins.  However, in the collection code
  1063     // used by PK11_ListCerts, the cert is found in the temp db, where it
  1064     // has been loaded from the token.  Though the trust is correct (grabbed
  1065     // from the cert db), the source is wrong.  I believe this is a safe
  1066     // way to work around this.
  1067     if (mCert->slot) {
  1068       char* token = PK11_GetTokenName(mCert->slot);
  1069       if (token) {
  1070         aTokenName = NS_ConvertUTF8toUTF16(token);
  1072     } else {
  1073       nsresult rv;
  1074       nsAutoString tok;
  1075       nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1076       if (NS_FAILED(rv)) return rv;
  1077       rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
  1078       if (NS_SUCCEEDED(rv))
  1079         aTokenName = tok;
  1082   return NS_OK;
  1085 NS_IMETHODIMP
  1086 nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
  1088   nsNSSShutDownPreventionLock locker;
  1089   if (isAlreadyShutDown()) {
  1090     return NS_ERROR_NOT_AVAILABLE;
  1093   aSha256SPKIDigest.Truncate();
  1094   Digest digest;
  1095   nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
  1096                                  mCert->derPublicKey.len);
  1097   if (NS_WARN_IF(NS_FAILED(rv))) {
  1098     return rv;
  1100   rv = Base64Encode(nsDependentCSubstring(
  1101                       reinterpret_cast<const char*> (digest.get().data),
  1102                       digest.get().len),
  1103                     aSha256SPKIDigest);
  1104   if (NS_WARN_IF(NS_FAILED(rv))) {
  1105     return rv;
  1107   return NS_OK;
  1110 NS_IMETHODIMP
  1111 nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
  1113   nsNSSShutDownPreventionLock locker;
  1114   if (isAlreadyShutDown())
  1115     return NS_ERROR_NOT_AVAILABLE;
  1117   if (mCert) {
  1118     *aArray = (uint8_t*)nsMemory::Alloc(mCert->derCert.len);
  1119     if (*aArray) {
  1120       memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
  1121       *aLength = mCert->derCert.len;
  1122       return NS_OK;
  1125   *aLength = 0;
  1126   return NS_ERROR_FAILURE;
  1129 NS_IMETHODIMP
  1130 nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
  1131                               uint32_t* aLength, uint8_t** aArray)
  1133   NS_ENSURE_ARG(aLength);
  1134   NS_ENSURE_ARG(aArray);
  1136   nsNSSShutDownPreventionLock locker;
  1137   if (isAlreadyShutDown())
  1138     return NS_ERROR_NOT_AVAILABLE;
  1140   if (!mCert)
  1141     return NS_ERROR_FAILURE;
  1143   switch (chainMode) {
  1144     case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
  1145     case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
  1146     case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
  1147       break;
  1148     default:
  1149       return NS_ERROR_INVALID_ARG;
  1150   };
  1152   PLArenaPool* arena = PORT_NewArena(1024);
  1153   PLArenaPoolCleanerFalseParam arenaCleaner(arena);
  1154   if (!arena) {
  1155     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1156            ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
  1157     return NS_ERROR_OUT_OF_MEMORY;
  1160   ScopedNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
  1161   if (!cmsg) {
  1162     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1163            ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
  1164     return NS_ERROR_OUT_OF_MEMORY;
  1167   // first, create SignedData with the certificate only (no chain)
  1168   ScopedNSSCMSSignedData sigd(
  1169     NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert.get(), false));
  1170   if (!sigd) {
  1171     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1172            ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
  1173     return NS_ERROR_FAILURE;
  1176   // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
  1177   // to specify the inclusion of the root, but CERT_CertChainFromCert() does.
  1178   // Since CERT_CertChainFromCert() also includes the certificate itself,
  1179   // we have to start at the issuing cert (to avoid duplicate certs
  1180   // in the SignedData).
  1181   if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
  1182       chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
  1183     ScopedCERTCertificate issuerCert(
  1184         CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
  1185     // the issuerCert of a self signed root is the cert itself,
  1186     // so make sure we're not adding duplicates, again
  1187     if (issuerCert && issuerCert != mCert.get()) {
  1188       bool includeRoot =
  1189         (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
  1190       ScopedCERTCertificateList certChain(
  1191           CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot));
  1192       if (certChain) {
  1193         if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) {
  1194           certChain.forget();
  1196         else {
  1197           PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1198                  ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
  1199           return NS_ERROR_FAILURE;
  1202       else {
  1203         // try to add the issuerCert, at least
  1204         if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert)
  1205             == SECSuccess) {
  1206           issuerCert.forget();
  1208         else {
  1209           PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1210                  ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
  1211           return NS_ERROR_FAILURE;
  1217   NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  1218   if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
  1219        == SECSuccess) {
  1220     sigd.forget();
  1222   else {
  1223     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1224            ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
  1225     return NS_ERROR_FAILURE;
  1228   SECItem certP7 = { siBuffer, nullptr, 0 };
  1229   NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr,
  1230                                                    &certP7, arena, nullptr,
  1231                                                    nullptr, nullptr, nullptr,
  1232                                                    nullptr, nullptr);
  1233   if (!ecx) {
  1234     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1235            ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
  1236     return NS_ERROR_FAILURE;
  1239   if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
  1240     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1241            ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
  1242     return NS_ERROR_FAILURE;
  1245   *aArray = (uint8_t*)nsMemory::Alloc(certP7.len);
  1246   if (!*aArray)
  1247     return NS_ERROR_OUT_OF_MEMORY;
  1249   memcpy(*aArray, certP7.data, certP7.len);
  1250   *aLength = certP7.len;
  1251   return NS_OK;
  1254 CERTCertificate*
  1255 nsNSSCertificate::GetCert()
  1257   nsNSSShutDownPreventionLock locker;
  1258   if (isAlreadyShutDown())
  1259     return nullptr;
  1261   return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
  1264 NS_IMETHODIMP
  1265 nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
  1267   nsNSSShutDownPreventionLock locker;
  1268   if (isAlreadyShutDown())
  1269     return NS_ERROR_NOT_AVAILABLE;
  1271   NS_ENSURE_ARG(aValidity);
  1272   nsX509CertValidity* validity = new nsX509CertValidity(mCert.get());
  1274   NS_ADDREF(validity);
  1275   *aValidity = static_cast<nsIX509CertValidity*>(validity);
  1276   return NS_OK;
  1279 NS_IMETHODIMP
  1280 nsNSSCertificate::GetUsagesArray(bool localOnly,
  1281                                  uint32_t* _verified,
  1282                                  uint32_t* _count,
  1283                                  char16_t*** _usages)
  1285   nsNSSShutDownPreventionLock locker;
  1286   if (isAlreadyShutDown())
  1287     return NS_ERROR_NOT_AVAILABLE;
  1289   nsresult rv;
  1290   const int max_usages = 13;
  1291   char16_t* tmpUsages[max_usages];
  1292   const char* suffix = "";
  1293   uint32_t tmpCount;
  1294   nsUsageArrayHelper uah(mCert.get());
  1295   rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount,
  1296                           tmpUsages);
  1297   NS_ENSURE_SUCCESS(rv,rv);
  1298   if (tmpCount > 0) {
  1299     *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * tmpCount);
  1300     if (!*_usages)
  1301       return NS_ERROR_OUT_OF_MEMORY;
  1302     for (uint32_t i=0; i<tmpCount; i++) {
  1303       (*_usages)[i] = tmpUsages[i];
  1305     *_count = tmpCount;
  1306     return NS_OK;
  1308   *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*));
  1309   if (!*_usages)
  1310     return NS_ERROR_OUT_OF_MEMORY;
  1311   *_count = 0;
  1312   return NS_OK;
  1315 NS_IMETHODIMP
  1316 nsNSSCertificate::RequestUsagesArrayAsync(
  1317   nsICertVerificationListener* aResultListener)
  1319   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
  1321   if (!aResultListener)
  1322     return NS_ERROR_FAILURE;
  1324   nsCertVerificationJob* job = new nsCertVerificationJob;
  1326   job->mCert = this;
  1327   job->mListener =
  1328     new nsMainThreadPtrHolder<nsICertVerificationListener>(aResultListener);
  1330   nsresult rv = nsCertVerificationThread::addJob(job);
  1331   if (NS_FAILED(rv))
  1332     delete job;
  1334   return rv;
  1337 NS_IMETHODIMP
  1338 nsNSSCertificate::GetUsagesString(bool localOnly, uint32_t* _verified,
  1339                                   nsAString& _usages)
  1341   nsNSSShutDownPreventionLock locker;
  1342   if (isAlreadyShutDown())
  1343     return NS_ERROR_NOT_AVAILABLE;
  1345   nsresult rv;
  1346   const int max_usages = 13;
  1347   char16_t* tmpUsages[max_usages];
  1348   const char* suffix = "_p";
  1349   uint32_t tmpCount;
  1350   nsUsageArrayHelper uah(mCert.get());
  1351   rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount,
  1352                           tmpUsages);
  1353   NS_ENSURE_SUCCESS(rv,rv);
  1354   _usages.Truncate();
  1355   for (uint32_t i=0; i<tmpCount; i++) {
  1356     if (i>0) _usages.AppendLiteral(",");
  1357     _usages.Append(tmpUsages[i]);
  1358     nsMemory::Free(tmpUsages[i]);
  1360   return NS_OK;
  1363 #if defined(DEBUG_javi) || defined(DEBUG_jgmyers)
  1364 void
  1365 DumpASN1Object(nsIASN1Object* object, unsigned int level)
  1367   nsAutoString dispNameU, dispValU;
  1368   unsigned int i;
  1369   nsCOMPtr<nsIMutableArray> asn1Objects;
  1370   nsCOMPtr<nsISupports> isupports;
  1371   nsCOMPtr<nsIASN1Object> currObject;
  1372   bool processObjects;
  1373   uint32_t numObjects;
  1375   for (i=0; i<level; i++)
  1376     printf ("  ");
  1378   object->GetDisplayName(dispNameU);
  1379   nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
  1380   if (sequence) {
  1381     printf ("%s ", NS_ConvertUTF16toUTF8(dispNameU).get());
  1382     sequence->GetIsValidContainer(&processObjects);
  1383     if (processObjects) {
  1384       printf("\n");
  1385       sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
  1386       asn1Objects->GetLength(&numObjects);
  1387       for (i=0; i<numObjects;i++) {
  1388         asn1Objects->QueryElementAt(i, NS_GET_IID(nsISupports),
  1389                                     getter_AddRefs(currObject));
  1390         DumpASN1Object(currObject, level+1);
  1392     } else {
  1393       object->GetDisplayValue(dispValU);
  1394       printf("= %s\n", NS_ConvertUTF16toUTF8(dispValU).get());
  1396   } else {
  1397     object->GetDisplayValue(dispValU);
  1398     printf("%s = %s\n",NS_ConvertUTF16toUTF8(dispNameU).get(),
  1399                        NS_ConvertUTF16toUTF8(dispValU).get());
  1402 #endif
  1404 NS_IMETHODIMP
  1405 nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
  1407   nsNSSShutDownPreventionLock locker;
  1408   nsresult rv = NS_OK;
  1409   NS_ENSURE_ARG_POINTER(aASN1Structure);
  1410   // First create the recursive structure os ASN1Objects
  1411   // which tells us the layout of the cert.
  1412   rv = CreateASN1Struct(aASN1Structure);
  1413   if (NS_FAILED(rv)) {
  1414     return rv;
  1416 #ifdef DEBUG_javi
  1417   DumpASN1Object(*aASN1Structure, 0);
  1418 #endif
  1419   return rv;
  1422 NS_IMETHODIMP
  1423 nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
  1425   nsNSSShutDownPreventionLock locker;
  1426   if (isAlreadyShutDown())
  1427     return NS_ERROR_NOT_AVAILABLE;
  1429   NS_ENSURE_ARG(other);
  1430   NS_ENSURE_ARG(result);
  1432   nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other);
  1433   if (!other2)
  1434     return NS_ERROR_FAILURE;
  1436   ScopedCERTCertificate cert(other2->GetCert());
  1437   *result = (mCert.get() == cert.get());
  1438   return NS_OK;
  1441 NS_IMETHODIMP
  1442 nsNSSCertificate::SaveSMimeProfile()
  1444   nsNSSShutDownPreventionLock locker;
  1445   if (isAlreadyShutDown())
  1446     return NS_ERROR_NOT_AVAILABLE;
  1448   if (SECSuccess != CERT_SaveSMimeProfile(mCert.get(), nullptr, nullptr))
  1449     return NS_ERROR_FAILURE;
  1450   else
  1451     return NS_OK;
  1454 #ifndef MOZ_NO_EV_CERTS
  1456 nsresult
  1457 nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
  1459   nsNSSShutDownPreventionLock locker;
  1460   if (isAlreadyShutDown())
  1461     return NS_ERROR_NOT_AVAILABLE;
  1463   EnsureIdentityInfoLoaded();
  1465   RefPtr<mozilla::psm::SharedCertVerifier>
  1466     certVerifier(mozilla::psm::GetDefaultCertVerifier());
  1467   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
  1469   validEV = false;
  1470   resultOidTag = SEC_OID_UNKNOWN;
  1472   uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY |
  1473     mozilla::psm::CertVerifier::FLAG_MUST_BE_EV;
  1474   SECStatus rv = certVerifier->VerifyCert(mCert.get(),
  1475     certificateUsageSSLServer, PR_Now(),
  1476     nullptr /* XXX pinarg */,
  1477     nullptr /* hostname */,
  1478     flags, nullptr /* stapledOCSPResponse */ , nullptr, &resultOidTag);
  1480   if (rv != SECSuccess) {
  1481     resultOidTag = SEC_OID_UNKNOWN;
  1483   if (resultOidTag != SEC_OID_UNKNOWN) {
  1484     validEV = true;
  1486   return NS_OK;
  1489 nsresult
  1490 nsNSSCertificate::getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
  1492   if (mCachedEVStatus != ev_status_unknown) {
  1493     validEV = (mCachedEVStatus == ev_status_valid);
  1494     if (validEV) {
  1495       resultOidTag = mCachedEVOidTag;
  1497     return NS_OK;
  1500   nsresult rv = hasValidEVOidTag(resultOidTag, validEV);
  1501   if (NS_SUCCEEDED(rv)) {
  1502     if (validEV) {
  1503       mCachedEVOidTag = resultOidTag;
  1505     mCachedEVStatus = validEV ? ev_status_valid : ev_status_invalid;
  1507   return rv;
  1510 #endif // MOZ_NO_EV_CERTS
  1512 NS_IMETHODIMP
  1513 nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV)
  1515 #ifdef MOZ_NO_EV_CERTS
  1516   *aIsEV = false;
  1517   return NS_OK;
  1518 #else
  1519   nsNSSShutDownPreventionLock locker;
  1520   if (isAlreadyShutDown()) {
  1521     return NS_ERROR_NOT_AVAILABLE;
  1524   NS_ENSURE_ARG(aIsEV);
  1525   *aIsEV = false;
  1527   if (mCachedEVStatus != ev_status_unknown) {
  1528     *aIsEV = (mCachedEVStatus == ev_status_valid);
  1529     return NS_OK;
  1532   SECOidTag oid_tag;
  1533   return getValidEVOidTag(oid_tag, *aIsEV);
  1534 #endif
  1537 NS_IMETHODIMP
  1538 nsNSSCertificate::GetValidEVPolicyOid(nsACString& outDottedOid)
  1540   outDottedOid.Truncate();
  1542 #ifndef MOZ_NO_EV_CERTS
  1543   nsNSSShutDownPreventionLock locker;
  1544   if (isAlreadyShutDown()) {
  1545     return NS_ERROR_NOT_AVAILABLE;
  1548   SECOidTag oid_tag;
  1549   bool valid;
  1550   nsresult rv = getValidEVOidTag(oid_tag, valid);
  1551   if (NS_FAILED(rv)) {
  1552     return rv;
  1555   if (valid) {
  1556     SECOidData* oid_data = SECOID_FindOIDByTag(oid_tag);
  1557     if (!oid_data) {
  1558       return NS_ERROR_FAILURE;
  1561     char* oid_str = CERT_GetOidString(&oid_data->oid);
  1562     if (!oid_str) {
  1563       return NS_ERROR_FAILURE;
  1566     outDottedOid.Assign(oid_str);
  1567     PR_smprintf_free(oid_str);
  1569 #endif
  1571   return NS_OK;
  1574 NS_IMPL_ISUPPORTS(nsNSSCertList, nsIX509CertList)
  1576 nsNSSCertList::nsNSSCertList(mozilla::pkix::ScopedCERTCertList& certList,
  1577                              const nsNSSShutDownPreventionLock& proofOfLock)
  1579   if (certList) {
  1580     mCertList = certList.release();
  1581   } else {
  1582     mCertList = CERT_NewCertList();
  1586 nsNSSCertList::nsNSSCertList()
  1588   mCertList = CERT_NewCertList();
  1591 nsNSSCertList::~nsNSSCertList()
  1593   nsNSSShutDownPreventionLock locker;
  1594   if (isAlreadyShutDown()) {
  1595     return;
  1597   destructorSafeDestroyNSSReference();
  1598   shutdown(calledFromObject);
  1601 void nsNSSCertList::virtualDestroyNSSReference()
  1603   destructorSafeDestroyNSSReference();
  1606 void nsNSSCertList::destructorSafeDestroyNSSReference()
  1608   if (mCertList) {
  1609     mCertList = nullptr;
  1613 NS_IMETHODIMP
  1614 nsNSSCertList::AddCert(nsIX509Cert* aCert)
  1616   nsNSSShutDownPreventionLock locker;
  1617   if (isAlreadyShutDown()) {
  1618     return NS_ERROR_NOT_AVAILABLE;
  1620   nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
  1621   CERTCertificate* cert;
  1623   cert = nssCert->GetCert();
  1624   if (!cert) {
  1625     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
  1626     return NS_ERROR_FAILURE;
  1629   if (!mCertList) {
  1630     NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
  1631     return NS_ERROR_FAILURE;
  1633   // XXX: check return value!
  1634   CERT_AddCertToListTail(mCertList.get(), cert);
  1635   return NS_OK;
  1638 NS_IMETHODIMP
  1639 nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
  1641   nsNSSShutDownPreventionLock locker;
  1642   if (isAlreadyShutDown()) {
  1643     return NS_ERROR_NOT_AVAILABLE;
  1645   nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
  1646   CERTCertificate* cert = nssCert->GetCert();
  1647   CERTCertListNode* node;
  1649   if (!cert) {
  1650     NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
  1651     return NS_ERROR_FAILURE;
  1654   if (!mCertList) {
  1655     NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
  1656     return NS_ERROR_FAILURE;
  1659   for (node = CERT_LIST_HEAD(mCertList.get());
  1660        !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) {
  1661     if (node->cert == cert) {
  1662 	CERT_RemoveCertListNode(node);
  1663         return NS_OK;
  1666   return NS_OK; // XXX Should we fail if we couldn't find it?
  1669 CERTCertList*
  1670 nsNSSCertList::DupCertList(CERTCertList* aCertList,
  1671                            const nsNSSShutDownPreventionLock& /*proofOfLock*/)
  1673   if (!aCertList)
  1674     return nullptr;
  1676   CERTCertList* newList = CERT_NewCertList();
  1678   if (!newList) {
  1679     return nullptr;
  1682   CERTCertListNode* node;
  1683   for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList);
  1684                                               node = CERT_LIST_NEXT(node)) {
  1685     CERTCertificate* cert = CERT_DupCertificate(node->cert);
  1686     CERT_AddCertToListTail(newList, cert);
  1688   return newList;
  1691 void*
  1692 nsNSSCertList::GetRawCertList()
  1694   // This function should only be called after adquiring a
  1695   // nsNSSShutDownPreventionLock
  1696   return mCertList.get();
  1699 NS_IMETHODIMP
  1700 nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
  1702   nsNSSShutDownPreventionLock locker;
  1703   if (isAlreadyShutDown()) {
  1704     return NS_ERROR_NOT_AVAILABLE;
  1706   nsCOMPtr<nsISimpleEnumerator> enumerator =
  1707     new nsNSSCertListEnumerator(mCertList.get(), locker);
  1709   *_retval = enumerator;
  1710   NS_ADDREF(*_retval);
  1711   return NS_OK;
  1714 NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
  1716 nsNSSCertListEnumerator::nsNSSCertListEnumerator(
  1717   CERTCertList* certList, const nsNSSShutDownPreventionLock& proofOfLock)
  1719   mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
  1722 nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
  1724   nsNSSShutDownPreventionLock locker;
  1725   if (isAlreadyShutDown()) {
  1726     return;
  1728   destructorSafeDestroyNSSReference();
  1729   shutdown(calledFromObject);
  1732 void nsNSSCertListEnumerator::virtualDestroyNSSReference()
  1734   destructorSafeDestroyNSSReference();
  1737 void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference()
  1739   if (mCertList) {
  1740     mCertList = nullptr;
  1744 NS_IMETHODIMP
  1745 nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
  1747   nsNSSShutDownPreventionLock locker;
  1748   if (isAlreadyShutDown()) {
  1749     return NS_ERROR_NOT_AVAILABLE;
  1752   NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
  1754   *_retval = !CERT_LIST_EMPTY(mCertList);
  1755   return NS_OK;
  1758 NS_IMETHODIMP
  1759 nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
  1761   nsNSSShutDownPreventionLock locker;
  1762   if (isAlreadyShutDown()) {
  1763     return NS_ERROR_NOT_AVAILABLE;
  1766   NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
  1768   CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
  1769   if (CERT_LIST_END(node, mCertList)) {
  1770     return NS_ERROR_FAILURE;
  1773   nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
  1774   if (!nssCert) {
  1775     return NS_ERROR_OUT_OF_MEMORY;
  1778   *_retval = nssCert;
  1779   NS_ADDREF(*_retval);
  1781   CERT_RemoveCertListNode(node);
  1782   return NS_OK;
  1785 // NB: This serialization must match that of nsNSSCertificateFakeTransport.
  1786 NS_IMETHODIMP
  1787 nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
  1789   NS_ENSURE_STATE(mCert);
  1790   nsresult rv = aStream->Write32(static_cast<uint32_t>(mCachedEVStatus));
  1791   if (NS_FAILED(rv)) {
  1792     return rv;
  1794   rv = aStream->Write32(mCert->derCert.len);
  1795   if (NS_FAILED(rv)) {
  1796     return rv;
  1798   return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
  1801 NS_IMETHODIMP
  1802 nsNSSCertificate::Read(nsIObjectInputStream* aStream)
  1804   NS_ENSURE_STATE(!mCert);
  1806   uint32_t cachedEVStatus;
  1807   nsresult rv = aStream->Read32(&cachedEVStatus);
  1808   if (NS_FAILED(rv)) {
  1809     return rv;
  1811   if (cachedEVStatus == static_cast<uint32_t>(ev_status_unknown)) {
  1812     mCachedEVStatus = ev_status_unknown;
  1813   } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_valid)) {
  1814     mCachedEVStatus = ev_status_valid;
  1815   } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_invalid)) {
  1816     mCachedEVStatus = ev_status_invalid;
  1817   } else {
  1818     return NS_ERROR_UNEXPECTED;
  1821   uint32_t len;
  1822   rv = aStream->Read32(&len);
  1823   if (NS_FAILED(rv)) {
  1824     return rv;
  1827   nsXPIDLCString str;
  1828   rv = aStream->ReadBytes(len, getter_Copies(str));
  1829   if (NS_FAILED(rv)) {
  1830     return rv;
  1833   if (!InitFromDER(const_cast<char*>(str.get()), len)) {
  1834     return NS_ERROR_UNEXPECTED;
  1837   return NS_OK;
  1840 NS_IMETHODIMP
  1841 nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
  1843   *count = 0;
  1844   *array = nullptr;
  1845   return NS_OK;
  1848 NS_IMETHODIMP
  1849 nsNSSCertificate::GetHelperForLanguage(uint32_t language,
  1850                                        nsISupports** _retval)
  1852   *_retval = nullptr;
  1853   return NS_OK;
  1856 NS_IMETHODIMP
  1857 nsNSSCertificate::GetContractID(char** aContractID)
  1859   *aContractID = nullptr;
  1860   return NS_OK;
  1863 NS_IMETHODIMP
  1864 nsNSSCertificate::GetClassDescription(char** aClassDescription)
  1866   *aClassDescription = nullptr;
  1867   return NS_OK;
  1870 NS_IMETHODIMP
  1871 nsNSSCertificate::GetClassID(nsCID** aClassID)
  1873   *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
  1874   if (!*aClassID)
  1875     return NS_ERROR_OUT_OF_MEMORY;
  1876   return GetClassIDNoAlloc(*aClassID);
  1879 NS_IMETHODIMP
  1880 nsNSSCertificate::GetImplementationLanguage(uint32_t* aImplementationLanguage)
  1882   *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
  1883   return NS_OK;
  1886 NS_IMETHODIMP
  1887 nsNSSCertificate::GetFlags(uint32_t* aFlags)
  1889   *aFlags = nsIClassInfo::THREADSAFE;
  1890   return NS_OK;
  1893 NS_IMETHODIMP
  1894 nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
  1896   static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
  1898   *aClassIDNoAlloc = kNSSCertificateCID;
  1899   return NS_OK;

mercurial