security/manager/ssl/src/nsNSSCertificate.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/manager/ssl/src/nsNSSCertificate.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1900 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsNSSCertificate.h"
    1.10 +
    1.11 +#include "prmem.h"
    1.12 +#include "prerror.h"
    1.13 +#include "prprf.h"
    1.14 +#include "CertVerifier.h"
    1.15 +#include "ExtendedValidation.h"
    1.16 +#include "pkix/pkixtypes.h"
    1.17 +#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
    1.18 +#include "nsNSSCleaner.h"
    1.19 +#include "nsCOMPtr.h"
    1.20 +#include "nsIMutableArray.h"
    1.21 +#include "nsNSSCertValidity.h"
    1.22 +#include "nsPKCS12Blob.h"
    1.23 +#include "nsPK11TokenDB.h"
    1.24 +#include "nsIX509Cert.h"
    1.25 +#include "nsIX509Cert3.h"
    1.26 +#include "nsISMimeCert.h"
    1.27 +#include "nsNSSASN1Object.h"
    1.28 +#include "nsString.h"
    1.29 +#include "nsXPIDLString.h"
    1.30 +#include "nsReadableUtils.h"
    1.31 +#include "nsIURI.h"
    1.32 +#include "nsCRT.h"
    1.33 +#include "nsUsageArrayHelper.h"
    1.34 +#include "nsICertificateDialogs.h"
    1.35 +#include "nsNSSCertHelper.h"
    1.36 +#include "nsISupportsPrimitives.h"
    1.37 +#include "nsUnicharUtils.h"
    1.38 +#include "nsThreadUtils.h"
    1.39 +#include "nsCertVerificationThread.h"
    1.40 +#include "nsIObjectOutputStream.h"
    1.41 +#include "nsIObjectInputStream.h"
    1.42 +#include "nsIProgrammingLanguage.h"
    1.43 +#include "nsXULAppAPI.h"
    1.44 +#include "ScopedNSSTypes.h"
    1.45 +#include "nsProxyRelease.h"
    1.46 +#include "mozilla/Base64.h"
    1.47 +
    1.48 +#include "nspr.h"
    1.49 +#include "certdb.h"
    1.50 +#include "secerr.h"
    1.51 +#include "nssb64.h"
    1.52 +#include "secasn1.h"
    1.53 +#include "secder.h"
    1.54 +#include "ssl.h"
    1.55 +#include "ocsp.h"
    1.56 +#include "plbase64.h"
    1.57 +
    1.58 +using namespace mozilla;
    1.59 +using namespace mozilla::psm;
    1.60 +
    1.61 +#ifdef PR_LOGGING
    1.62 +extern PRLogModuleInfo* gPIPNSSLog;
    1.63 +#endif
    1.64 +
    1.65 +NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
    1.66 +
    1.67 +// This is being stored in an uint32_t that can otherwise
    1.68 +// only take values from nsIX509Cert's list of cert types.
    1.69 +// As nsIX509Cert is frozen, we choose a value not contained
    1.70 +// in the list to mean not yet initialized.
    1.71 +#define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
    1.72 +
    1.73 +NS_IMPL_ISUPPORTS(nsNSSCertificate,
    1.74 +                  nsIX509Cert,
    1.75 +                  nsIX509Cert2,
    1.76 +                  nsIX509Cert3,
    1.77 +                  nsIIdentityInfo,
    1.78 +                  nsISMimeCert,
    1.79 +                  nsISerializable,
    1.80 +                  nsIClassInfo)
    1.81 +
    1.82 +/*static*/ nsNSSCertificate*
    1.83 +nsNSSCertificate::Create(CERTCertificate* cert, SECOidTag* evOidPolicy)
    1.84 +{
    1.85 +  if (GeckoProcessType_Default != XRE_GetProcessType()) {
    1.86 +    NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
    1.87 +    return nullptr;
    1.88 +  }
    1.89 +  if (cert)
    1.90 +    return new nsNSSCertificate(cert, evOidPolicy);
    1.91 +  else
    1.92 +    return new nsNSSCertificate();
    1.93 +}
    1.94 +
    1.95 +nsNSSCertificate*
    1.96 +nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
    1.97 +{
    1.98 +  // On non-chrome process prevent instantiation
    1.99 +  if (GeckoProcessType_Default != XRE_GetProcessType())
   1.100 +    return nullptr;
   1.101 +
   1.102 +  nsNSSCertificate* newObject = nsNSSCertificate::Create();
   1.103 +  if (newObject && !newObject->InitFromDER(certDER, derLen)) {
   1.104 +    delete newObject;
   1.105 +    newObject = nullptr;
   1.106 +  }
   1.107 +
   1.108 +  return newObject;
   1.109 +}
   1.110 +
   1.111 +bool
   1.112 +nsNSSCertificate::InitFromDER(char* certDER, int derLen)
   1.113 +{
   1.114 +  nsNSSShutDownPreventionLock locker;
   1.115 +  if (isAlreadyShutDown())
   1.116 +    return false;
   1.117 +
   1.118 +  if (!certDER || !derLen)
   1.119 +    return false;
   1.120 +
   1.121 +  CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
   1.122 +
   1.123 +  if (!aCert)
   1.124 +    return false;
   1.125 +
   1.126 +  if (!aCert->dbhandle)
   1.127 +  {
   1.128 +    aCert->dbhandle = CERT_GetDefaultCertDB();
   1.129 +  }
   1.130 +
   1.131 +  mCert = aCert;
   1.132 +  return true;
   1.133 +}
   1.134 +
   1.135 +nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert,
   1.136 +                                   SECOidTag* evOidPolicy)
   1.137 +  : mCert(nullptr)
   1.138 +  , mPermDelete(false)
   1.139 +  , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
   1.140 +  , mCachedEVStatus(ev_status_unknown)
   1.141 +{
   1.142 +#if defined(DEBUG)
   1.143 +  if (GeckoProcessType_Default != XRE_GetProcessType())
   1.144 +    NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
   1.145 +#endif
   1.146 +
   1.147 +  nsNSSShutDownPreventionLock locker;
   1.148 +  if (isAlreadyShutDown())
   1.149 +    return;
   1.150 +
   1.151 +  if (cert) {
   1.152 +    mCert = CERT_DupCertificate(cert);
   1.153 +    if (evOidPolicy) {
   1.154 +      if (*evOidPolicy == SEC_OID_UNKNOWN) {
   1.155 +        mCachedEVStatus =  ev_status_invalid;
   1.156 +      }
   1.157 +      else {
   1.158 +        mCachedEVStatus = ev_status_valid;
   1.159 +      }
   1.160 +      mCachedEVOidTag = *evOidPolicy;
   1.161 +    }
   1.162 +  }
   1.163 +}
   1.164 +
   1.165 +nsNSSCertificate::nsNSSCertificate() :
   1.166 +  mCert(nullptr),
   1.167 +  mPermDelete(false),
   1.168 +  mCertType(CERT_TYPE_NOT_YET_INITIALIZED),
   1.169 +  mCachedEVStatus(ev_status_unknown)
   1.170 +{
   1.171 +  if (GeckoProcessType_Default != XRE_GetProcessType())
   1.172 +    NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
   1.173 +}
   1.174 +
   1.175 +nsNSSCertificate::~nsNSSCertificate()
   1.176 +{
   1.177 +  nsNSSShutDownPreventionLock locker;
   1.178 +  if (isAlreadyShutDown()) {
   1.179 +    return;
   1.180 +  }
   1.181 +  destructorSafeDestroyNSSReference();
   1.182 +  shutdown(calledFromObject);
   1.183 +}
   1.184 +
   1.185 +void nsNSSCertificate::virtualDestroyNSSReference()
   1.186 +{
   1.187 +  destructorSafeDestroyNSSReference();
   1.188 +}
   1.189 +
   1.190 +void nsNSSCertificate::destructorSafeDestroyNSSReference()
   1.191 +{
   1.192 +  if (mPermDelete) {
   1.193 +    if (mCertType == nsNSSCertificate::USER_CERT) {
   1.194 +      nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
   1.195 +      PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
   1.196 +    } else if (!PK11_IsReadOnly(mCert->slot)) {
   1.197 +      // If the list of built-ins does contain a non-removable
   1.198 +      // copy of this certificate, our call will not remove
   1.199 +      // the certificate permanently, but rather remove all trust.
   1.200 +      SEC_DeletePermCertificate(mCert.get());
   1.201 +    }
   1.202 +  }
   1.203 +
   1.204 +  mCert = nullptr;
   1.205 +}
   1.206 +
   1.207 +nsresult
   1.208 +nsNSSCertificate::GetCertType(uint32_t* aCertType)
   1.209 +{
   1.210 +  if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
   1.211 +     // only determine cert type once and cache it
   1.212 +     mCertType = getCertType(mCert.get());
   1.213 +  }
   1.214 +  *aCertType = mCertType;
   1.215 +  return NS_OK;
   1.216 +}
   1.217 +
   1.218 +NS_IMETHODIMP
   1.219 +nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
   1.220 +{
   1.221 +  NS_ENSURE_ARG(aIsSelfSigned);
   1.222 +
   1.223 +  nsNSSShutDownPreventionLock locker;
   1.224 +  if (isAlreadyShutDown())
   1.225 +    return NS_ERROR_NOT_AVAILABLE;
   1.226 +
   1.227 +  *aIsSelfSigned = mCert->isRoot;
   1.228 +  return NS_OK;
   1.229 +}
   1.230 +
   1.231 +nsresult
   1.232 +nsNSSCertificate::MarkForPermDeletion()
   1.233 +{
   1.234 +  nsNSSShutDownPreventionLock locker;
   1.235 +  if (isAlreadyShutDown())
   1.236 +    return NS_ERROR_NOT_AVAILABLE;
   1.237 +
   1.238 +  // make sure user is logged in to the token
   1.239 +  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
   1.240 +
   1.241 +  if (PK11_NeedLogin(mCert->slot)
   1.242 +      && !PK11_NeedUserInit(mCert->slot)
   1.243 +      && !PK11_IsInternal(mCert->slot))
   1.244 +  {
   1.245 +    if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx))
   1.246 +    {
   1.247 +      return NS_ERROR_FAILURE;
   1.248 +    }
   1.249 +  }
   1.250 +
   1.251 +  mPermDelete = true;
   1.252 +  return NS_OK;
   1.253 +}
   1.254 +
   1.255 +nsresult
   1.256 +GetKeyUsagesString(CERTCertificate* cert, nsINSSComponent* nssComponent,
   1.257 +                   nsString& text)
   1.258 +{
   1.259 +  text.Truncate();
   1.260 +
   1.261 +  SECItem keyUsageItem;
   1.262 +  keyUsageItem.data = nullptr;
   1.263 +
   1.264 +  SECStatus srv;
   1.265 +
   1.266 +  // There is no extension, v1 or v2 certificate
   1.267 +  if (!cert->extensions)
   1.268 +    return NS_OK;
   1.269 +
   1.270 +
   1.271 +  srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
   1.272 +  if (srv == SECFailure) {
   1.273 +    if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND)
   1.274 +      return NS_OK;
   1.275 +    else
   1.276 +      return NS_ERROR_FAILURE;
   1.277 +  }
   1.278 +
   1.279 +  unsigned char keyUsage = keyUsageItem.data[0];
   1.280 +  nsAutoString local;
   1.281 +  nsresult rv;
   1.282 +  const char16_t comma = ',';
   1.283 +
   1.284 +  if (keyUsage & KU_DIGITAL_SIGNATURE) {
   1.285 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local);
   1.286 +    if (NS_SUCCEEDED(rv)) {
   1.287 +      if (!text.IsEmpty()) text.Append(comma);
   1.288 +      text.Append(local.get());
   1.289 +    }
   1.290 +  }
   1.291 +  if (keyUsage & KU_NON_REPUDIATION) {
   1.292 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local);
   1.293 +    if (NS_SUCCEEDED(rv)) {
   1.294 +      if (!text.IsEmpty()) text.Append(comma);
   1.295 +      text.Append(local.get());
   1.296 +    }
   1.297 +  }
   1.298 +  if (keyUsage & KU_KEY_ENCIPHERMENT) {
   1.299 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local);
   1.300 +    if (NS_SUCCEEDED(rv)) {
   1.301 +      if (!text.IsEmpty()) text.Append(comma);
   1.302 +      text.Append(local.get());
   1.303 +    }
   1.304 +  }
   1.305 +  if (keyUsage & KU_DATA_ENCIPHERMENT) {
   1.306 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local);
   1.307 +    if (NS_SUCCEEDED(rv)) {
   1.308 +      if (!text.IsEmpty()) text.Append(comma);
   1.309 +      text.Append(local.get());
   1.310 +    }
   1.311 +  }
   1.312 +  if (keyUsage & KU_KEY_AGREEMENT) {
   1.313 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local);
   1.314 +    if (NS_SUCCEEDED(rv)) {
   1.315 +      if (!text.IsEmpty()) text.Append(comma);
   1.316 +      text.Append(local.get());
   1.317 +    }
   1.318 +  }
   1.319 +  if (keyUsage & KU_KEY_CERT_SIGN) {
   1.320 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local);
   1.321 +    if (NS_SUCCEEDED(rv)) {
   1.322 +      if (!text.IsEmpty()) text.Append(comma);
   1.323 +      text.Append(local.get());
   1.324 +    }
   1.325 +  }
   1.326 +  if (keyUsage & KU_CRL_SIGN) {
   1.327 +    rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local);
   1.328 +    if (NS_SUCCEEDED(rv)) {
   1.329 +      if (!text.IsEmpty()) text.Append(comma);
   1.330 +      text.Append(local.get());
   1.331 +    }
   1.332 +  }
   1.333 +
   1.334 +  PORT_Free (keyUsageItem.data);
   1.335 +  return NS_OK;
   1.336 +}
   1.337 +
   1.338 +nsresult
   1.339 +nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname,
   1.340 +                                  nsAutoString& nickWithSerial,
   1.341 +                                  nsAutoString& details)
   1.342 +{
   1.343 +  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.344 +
   1.345 +  if (!NS_IsMainThread()) {
   1.346 +    NS_ERROR("nsNSSCertificate::FormatUIStrings called off the main thread");
   1.347 +    return NS_ERROR_NOT_SAME_THREAD;
   1.348 +  }
   1.349 +
   1.350 +  nsresult rv = NS_OK;
   1.351 +
   1.352 +  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   1.353 +
   1.354 +  if (NS_FAILED(rv) || !nssComponent) {
   1.355 +    return NS_ERROR_FAILURE;
   1.356 +  }
   1.357 +
   1.358 +  nsAutoString info;
   1.359 +  nsAutoString temp1;
   1.360 +
   1.361 +  nickWithSerial.Append(nickname);
   1.362 +
   1.363 +  if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) {
   1.364 +    details.Append(info);
   1.365 +    details.Append(char16_t(' '));
   1.366 +    if (NS_SUCCEEDED(GetSubjectName(temp1)) && !temp1.IsEmpty()) {
   1.367 +      details.Append(temp1);
   1.368 +    }
   1.369 +    details.Append(char16_t('\n'));
   1.370 +  }
   1.371 +
   1.372 +  if (NS_SUCCEEDED(GetSerialNumber(temp1)) && !temp1.IsEmpty()) {
   1.373 +    details.AppendLiteral("  ");
   1.374 +    if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) {
   1.375 +      details.Append(info);
   1.376 +      details.AppendLiteral(": ");
   1.377 +    }
   1.378 +    details.Append(temp1);
   1.379 +
   1.380 +    nickWithSerial.AppendLiteral(" [");
   1.381 +    nickWithSerial.Append(temp1);
   1.382 +    nickWithSerial.Append(char16_t(']'));
   1.383 +
   1.384 +    details.Append(char16_t('\n'));
   1.385 +  }
   1.386 +
   1.387 +  nsCOMPtr<nsIX509CertValidity> validity;
   1.388 +  rv = GetValidity(getter_AddRefs(validity));
   1.389 +  if (NS_SUCCEEDED(rv) && validity) {
   1.390 +    details.AppendLiteral("  ");
   1.391 +    if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) {
   1.392 +      details.Append(info);
   1.393 +    }
   1.394 +
   1.395 +    if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) {
   1.396 +      details.Append(char16_t(' '));
   1.397 +      if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) {
   1.398 +        details.Append(info);
   1.399 +        details.Append(char16_t(' '));
   1.400 +      }
   1.401 +      details.Append(temp1);
   1.402 +    }
   1.403 +
   1.404 +    if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) {
   1.405 +      details.Append(char16_t(' '));
   1.406 +      if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) {
   1.407 +        details.Append(info);
   1.408 +        details.Append(char16_t(' '));
   1.409 +      }
   1.410 +      details.Append(temp1);
   1.411 +    }
   1.412 +
   1.413 +    details.Append(char16_t('\n'));
   1.414 +  }
   1.415 +
   1.416 +  if (NS_SUCCEEDED(GetKeyUsagesString(mCert.get(), nssComponent, temp1)) &&
   1.417 +      !temp1.IsEmpty()) {
   1.418 +    details.AppendLiteral("  ");
   1.419 +    if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) {
   1.420 +      details.Append(info);
   1.421 +      details.AppendLiteral(": ");
   1.422 +    }
   1.423 +    details.Append(temp1);
   1.424 +    details.Append(char16_t('\n'));
   1.425 +  }
   1.426 +
   1.427 +  nsAutoString firstEmail;
   1.428 +  const char* aWalkAddr;
   1.429 +  for (aWalkAddr = CERT_GetFirstEmailAddress(mCert.get())
   1.430 +        ;
   1.431 +        aWalkAddr
   1.432 +        ;
   1.433 +        aWalkAddr = CERT_GetNextEmailAddress(mCert.get(), aWalkAddr))
   1.434 +  {
   1.435 +    NS_ConvertUTF8toUTF16 email(aWalkAddr);
   1.436 +    if (email.IsEmpty())
   1.437 +      continue;
   1.438 +
   1.439 +    if (firstEmail.IsEmpty()) {
   1.440 +      // If the first email address from the subject DN is also present
   1.441 +      // in the subjectAltName extension, GetEmailAddresses() will return
   1.442 +      // it twice (as received from NSS). Remember the first address so that
   1.443 +      // we can filter out duplicates later on.
   1.444 +      firstEmail = email;
   1.445 +
   1.446 +      details.AppendLiteral("  ");
   1.447 +      if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoEmail", info))) {
   1.448 +        details.Append(info);
   1.449 +        details.AppendLiteral(": ");
   1.450 +      }
   1.451 +      details.Append(email);
   1.452 +    }
   1.453 +    else {
   1.454 +      // Append current address if it's different from the first one.
   1.455 +      if (!firstEmail.Equals(email)) {
   1.456 +        details.AppendLiteral(", ");
   1.457 +        details.Append(email);
   1.458 +      }
   1.459 +    }
   1.460 +  }
   1.461 +
   1.462 +  if (!firstEmail.IsEmpty()) {
   1.463 +    // We got at least one email address, so we want a newline
   1.464 +    details.Append(char16_t('\n'));
   1.465 +  }
   1.466 +
   1.467 +  if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) {
   1.468 +    details.Append(info);
   1.469 +    details.Append(char16_t(' '));
   1.470 +
   1.471 +    if (NS_SUCCEEDED(GetIssuerName(temp1)) && !temp1.IsEmpty()) {
   1.472 +      details.Append(temp1);
   1.473 +    }
   1.474 +
   1.475 +    details.Append(char16_t('\n'));
   1.476 +  }
   1.477 +
   1.478 +  if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) {
   1.479 +    details.Append(info);
   1.480 +    details.Append(char16_t(' '));
   1.481 +
   1.482 +    if (NS_SUCCEEDED(GetTokenName(temp1)) && !temp1.IsEmpty()) {
   1.483 +      details.Append(temp1);
   1.484 +    }
   1.485 +  }
   1.486 +
   1.487 +  // the above produces the following output:
   1.488 +  //
   1.489 +  //   Issued to: $subjectName
   1.490 +  //   Serial number: $serialNumber
   1.491 +  //   Valid from: $starting_date to $expiration_date
   1.492 +  //   Certificate Key usage: $usages
   1.493 +  //   Email: $address(es)
   1.494 +  //   Issued by: $issuerName
   1.495 +  //   Stored in: $token
   1.496 +
   1.497 +  return rv;
   1.498 +}
   1.499 +
   1.500 +NS_IMETHODIMP
   1.501 +nsNSSCertificate::GetDbKey(char** aDbKey)
   1.502 +{
   1.503 +  nsNSSShutDownPreventionLock locker;
   1.504 +  if (isAlreadyShutDown())
   1.505 +    return NS_ERROR_NOT_AVAILABLE;
   1.506 +
   1.507 +  SECItem key;
   1.508 +
   1.509 +  NS_ENSURE_ARG(aDbKey);
   1.510 +  *aDbKey = nullptr;
   1.511 +  key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
   1.512 +  key.data = (unsigned char*) nsMemory::Alloc(key.len);
   1.513 +  if (!key.data)
   1.514 +    return NS_ERROR_OUT_OF_MEMORY;
   1.515 +  NS_NSS_PUT_LONG(0,key.data); // later put moduleID
   1.516 +  NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID
   1.517 +  NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
   1.518 +  NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
   1.519 +  memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data,
   1.520 +         mCert->serialNumber.len);
   1.521 +  memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len],
   1.522 +         mCert->derIssuer.data, mCert->derIssuer.len);
   1.523 +
   1.524 +  *aDbKey = NSSBase64_EncodeItem(nullptr, nullptr, 0, &key);
   1.525 +  nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
   1.526 +  return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
   1.527 +}
   1.528 +
   1.529 +NS_IMETHODIMP
   1.530 +nsNSSCertificate::GetWindowTitle(char** aWindowTitle)
   1.531 +{
   1.532 +  nsNSSShutDownPreventionLock locker;
   1.533 +  if (isAlreadyShutDown())
   1.534 +    return NS_ERROR_NOT_AVAILABLE;
   1.535 +
   1.536 +  NS_ENSURE_ARG(aWindowTitle);
   1.537 +  if (mCert) {
   1.538 +    if (mCert->nickname) {
   1.539 +      *aWindowTitle = PL_strdup(mCert->nickname);
   1.540 +    } else {
   1.541 +      *aWindowTitle = CERT_GetCommonName(&mCert->subject);
   1.542 +      if (!*aWindowTitle) {
   1.543 +        if (mCert->subjectName) {
   1.544 +          *aWindowTitle = PL_strdup(mCert->subjectName);
   1.545 +        } else if (mCert->emailAddr) {
   1.546 +          *aWindowTitle = PL_strdup(mCert->emailAddr);
   1.547 +        } else {
   1.548 +          *aWindowTitle = PL_strdup("");
   1.549 +        }
   1.550 +      }
   1.551 +    }
   1.552 +  } else {
   1.553 +    NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
   1.554 +    *aWindowTitle = nullptr;
   1.555 +  }
   1.556 +  return NS_OK;
   1.557 +}
   1.558 +
   1.559 +NS_IMETHODIMP
   1.560 +nsNSSCertificate::GetNickname(nsAString& aNickname)
   1.561 +{
   1.562 +  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.563 +
   1.564 +  nsNSSShutDownPreventionLock locker;
   1.565 +  if (isAlreadyShutDown())
   1.566 +    return NS_ERROR_NOT_AVAILABLE;
   1.567 +
   1.568 +  if (mCert->nickname) {
   1.569 +    CopyUTF8toUTF16(mCert->nickname, aNickname);
   1.570 +  } else {
   1.571 +    nsresult rv;
   1.572 +    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   1.573 +    if (NS_FAILED(rv) || !nssComponent) {
   1.574 +      return NS_ERROR_FAILURE;
   1.575 +    }
   1.576 +    nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
   1.577 +  }
   1.578 +  return NS_OK;
   1.579 +}
   1.580 +
   1.581 +NS_IMETHODIMP
   1.582 +nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
   1.583 +{
   1.584 +  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.585 +
   1.586 +  nsNSSShutDownPreventionLock locker;
   1.587 +  if (isAlreadyShutDown())
   1.588 +    return NS_ERROR_NOT_AVAILABLE;
   1.589 +
   1.590 +  if (mCert->emailAddr) {
   1.591 +    CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
   1.592 +  } else {
   1.593 +    nsresult rv;
   1.594 +    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   1.595 +    if (NS_FAILED(rv) || !nssComponent) {
   1.596 +      return NS_ERROR_FAILURE;
   1.597 +    }
   1.598 +    nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
   1.599 +  }
   1.600 +  return NS_OK;
   1.601 +}
   1.602 +
   1.603 +NS_IMETHODIMP
   1.604 +nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
   1.605 +{
   1.606 +  nsNSSShutDownPreventionLock locker;
   1.607 +  if (isAlreadyShutDown())
   1.608 +    return NS_ERROR_NOT_AVAILABLE;
   1.609 +
   1.610 +  NS_ENSURE_ARG(aLength);
   1.611 +  NS_ENSURE_ARG(aAddresses);
   1.612 +
   1.613 +  *aLength = 0;
   1.614 +
   1.615 +  const char* aAddr;
   1.616 +  for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
   1.617 +       ;
   1.618 +       aAddr
   1.619 +       ;
   1.620 +       aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
   1.621 +  {
   1.622 +    ++(*aLength);
   1.623 +  }
   1.624 +
   1.625 +  *aAddresses = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength));
   1.626 +  if (!*aAddresses)
   1.627 +    return NS_ERROR_OUT_OF_MEMORY;
   1.628 +
   1.629 +  uint32_t iAddr;
   1.630 +  for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
   1.631 +       ;
   1.632 +       aAddr
   1.633 +       ;
   1.634 +       aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
   1.635 +  {
   1.636 +    (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
   1.637 +  }
   1.638 +
   1.639 +  return NS_OK;
   1.640 +}
   1.641 +
   1.642 +NS_IMETHODIMP
   1.643 +nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
   1.644 +                                       bool* result)
   1.645 +{
   1.646 +  nsNSSShutDownPreventionLock locker;
   1.647 +  if (isAlreadyShutDown())
   1.648 +    return NS_ERROR_NOT_AVAILABLE;
   1.649 +
   1.650 +  NS_ENSURE_ARG(result);
   1.651 +  *result = false;
   1.652 +
   1.653 +  const char* aAddr = nullptr;
   1.654 +  for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
   1.655 +       ;
   1.656 +       aAddr
   1.657 +       ;
   1.658 +       aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
   1.659 +  {
   1.660 +    NS_ConvertUTF8toUTF16 certAddr(aAddr);
   1.661 +    ToLowerCase(certAddr);
   1.662 +
   1.663 +    nsAutoString testAddr(aEmailAddress);
   1.664 +    ToLowerCase(testAddr);
   1.665 +
   1.666 +    if (certAddr == testAddr)
   1.667 +    {
   1.668 +      *result = true;
   1.669 +      break;
   1.670 +    }
   1.671 +
   1.672 +  }
   1.673 +
   1.674 +  return NS_OK;
   1.675 +}
   1.676 +
   1.677 +NS_IMETHODIMP
   1.678 +nsNSSCertificate::GetCommonName(nsAString& aCommonName)
   1.679 +{
   1.680 +  nsNSSShutDownPreventionLock locker;
   1.681 +  if (isAlreadyShutDown())
   1.682 +    return NS_ERROR_NOT_AVAILABLE;
   1.683 +
   1.684 +  aCommonName.Truncate();
   1.685 +  if (mCert) {
   1.686 +    char* commonName = CERT_GetCommonName(&mCert->subject);
   1.687 +    if (commonName) {
   1.688 +      aCommonName = NS_ConvertUTF8toUTF16(commonName);
   1.689 +      PORT_Free(commonName);
   1.690 +    }
   1.691 +  }
   1.692 +  return NS_OK;
   1.693 +}
   1.694 +
   1.695 +NS_IMETHODIMP
   1.696 +nsNSSCertificate::GetOrganization(nsAString& aOrganization)
   1.697 +{
   1.698 +  nsNSSShutDownPreventionLock locker;
   1.699 +  if (isAlreadyShutDown())
   1.700 +    return NS_ERROR_NOT_AVAILABLE;
   1.701 +
   1.702 +  aOrganization.Truncate();
   1.703 +  if (mCert) {
   1.704 +    char* organization = CERT_GetOrgName(&mCert->subject);
   1.705 +    if (organization) {
   1.706 +      aOrganization = NS_ConvertUTF8toUTF16(organization);
   1.707 +      PORT_Free(organization);
   1.708 +    }
   1.709 +  }
   1.710 +  return NS_OK;
   1.711 +}
   1.712 +
   1.713 +NS_IMETHODIMP
   1.714 +nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
   1.715 +{
   1.716 +  nsNSSShutDownPreventionLock locker;
   1.717 +  if (isAlreadyShutDown())
   1.718 +    return NS_ERROR_NOT_AVAILABLE;
   1.719 +
   1.720 +  aCommonName.Truncate();
   1.721 +  if (mCert) {
   1.722 +    char* commonName = CERT_GetCommonName(&mCert->issuer);
   1.723 +    if (commonName) {
   1.724 +      aCommonName = NS_ConvertUTF8toUTF16(commonName);
   1.725 +      PORT_Free(commonName);
   1.726 +    }
   1.727 +  }
   1.728 +  return NS_OK;
   1.729 +}
   1.730 +
   1.731 +NS_IMETHODIMP
   1.732 +nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
   1.733 +{
   1.734 +  nsNSSShutDownPreventionLock locker;
   1.735 +  if (isAlreadyShutDown())
   1.736 +    return NS_ERROR_NOT_AVAILABLE;
   1.737 +
   1.738 +  aOrganization.Truncate();
   1.739 +  if (mCert) {
   1.740 +    char* organization = CERT_GetOrgName(&mCert->issuer);
   1.741 +    if (organization) {
   1.742 +      aOrganization = NS_ConvertUTF8toUTF16(organization);
   1.743 +      PORT_Free(organization);
   1.744 +    } else {
   1.745 +      return GetIssuerCommonName(aOrganization);
   1.746 +    }
   1.747 +  }
   1.748 +  return NS_OK;
   1.749 +}
   1.750 +
   1.751 +NS_IMETHODIMP
   1.752 +nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
   1.753 +{
   1.754 +  nsNSSShutDownPreventionLock locker;
   1.755 +  if (isAlreadyShutDown())
   1.756 +    return NS_ERROR_NOT_AVAILABLE;
   1.757 +
   1.758 +  aOrganizationUnit.Truncate();
   1.759 +  if (mCert) {
   1.760 +    char* organizationUnit = CERT_GetOrgUnitName(&mCert->issuer);
   1.761 +    if (organizationUnit) {
   1.762 +      aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit);
   1.763 +      PORT_Free(organizationUnit);
   1.764 +    }
   1.765 +  }
   1.766 +  return NS_OK;
   1.767 +}
   1.768 +
   1.769 +NS_IMETHODIMP
   1.770 +nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer)
   1.771 +{
   1.772 +  nsNSSShutDownPreventionLock locker;
   1.773 +  if (isAlreadyShutDown())
   1.774 +    return NS_ERROR_NOT_AVAILABLE;
   1.775 +
   1.776 +  NS_ENSURE_ARG(aIssuer);
   1.777 +  *aIssuer = nullptr;
   1.778 +
   1.779 +  nsCOMPtr<nsIArray> chain;
   1.780 +  nsresult rv;
   1.781 +  rv = GetChain(getter_AddRefs(chain));
   1.782 +  NS_ENSURE_SUCCESS(rv, rv);
   1.783 +  uint32_t length;
   1.784 +  if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) {
   1.785 +    return NS_ERROR_UNEXPECTED;
   1.786 +  }
   1.787 +  if (length == 1) { // No known issuer
   1.788 +    return NS_OK;
   1.789 +  }
   1.790 +  nsCOMPtr<nsIX509Cert> cert;
   1.791 +  chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert));
   1.792 +  if (!cert) {
   1.793 +    return NS_ERROR_UNEXPECTED;
   1.794 +  }
   1.795 +  *aIssuer = cert;
   1.796 +  NS_ADDREF(*aIssuer);
   1.797 +  return NS_OK;
   1.798 +}
   1.799 +
   1.800 +NS_IMETHODIMP
   1.801 +nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
   1.802 +{
   1.803 +  nsNSSShutDownPreventionLock locker;
   1.804 +  if (isAlreadyShutDown())
   1.805 +    return NS_ERROR_NOT_AVAILABLE;
   1.806 +
   1.807 +  aOrganizationalUnit.Truncate();
   1.808 +  if (mCert) {
   1.809 +    char* orgunit = CERT_GetOrgUnitName(&mCert->subject);
   1.810 +    if (orgunit) {
   1.811 +      aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit);
   1.812 +      PORT_Free(orgunit);
   1.813 +    }
   1.814 +  }
   1.815 +  return NS_OK;
   1.816 +}
   1.817 +
   1.818 +NS_IMETHODIMP
   1.819 +nsNSSCertificate::GetChain(nsIArray** _rvChain)
   1.820 +{
   1.821 +  nsNSSShutDownPreventionLock locker;
   1.822 +  if (isAlreadyShutDown())
   1.823 +    return NS_ERROR_NOT_AVAILABLE;
   1.824 +
   1.825 +  NS_ENSURE_ARG(_rvChain);
   1.826 +  nsresult rv;
   1.827 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
   1.828 +
   1.829 +  ::mozilla::pkix::ScopedCERTCertList nssChain;
   1.830 +  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
   1.831 +  NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
   1.832 +
   1.833 +  // We want to test all usages, but we start with server because most of the
   1.834 +  // time Firefox users care about server certs.
   1.835 +  certVerifier->VerifyCert(mCert.get(),
   1.836 +                           certificateUsageSSLServer, PR_Now(),
   1.837 +                           nullptr, /*XXX fixme*/
   1.838 +                           nullptr, /* hostname */
   1.839 +                           CertVerifier::FLAG_LOCAL_ONLY,
   1.840 +                           nullptr, /* stapledOCSPResponse */
   1.841 +                           &nssChain);
   1.842 +  // This is the whitelist of all non-SSLServer usages that are supported by
   1.843 +  // verifycert.
   1.844 +  const int otherUsagesToTest = certificateUsageSSLClient |
   1.845 +                                certificateUsageSSLCA |
   1.846 +                                certificateUsageEmailSigner |
   1.847 +                                certificateUsageEmailRecipient |
   1.848 +                                certificateUsageObjectSigner |
   1.849 +                                certificateUsageStatusResponder;
   1.850 +  for (int usage = certificateUsageSSLClient;
   1.851 +       usage < certificateUsageAnyCA && !nssChain;
   1.852 +       usage = usage << 1) {
   1.853 +    if ((usage & otherUsagesToTest) == 0) {
   1.854 +      continue;
   1.855 +    }
   1.856 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.857 +           ("pipnss: PKIX attempting chain(%d) for '%s'\n",
   1.858 +            usage, mCert->nickname));
   1.859 +    certVerifier->VerifyCert(mCert.get(),
   1.860 +                             usage, PR_Now(),
   1.861 +                             nullptr, /*XXX fixme*/
   1.862 +                             nullptr, /*hostname*/
   1.863 +                             CertVerifier::FLAG_LOCAL_ONLY,
   1.864 +                             nullptr, /* stapledOCSPResponse */
   1.865 +                             &nssChain);
   1.866 +  }
   1.867 +
   1.868 +  if (!nssChain) {
   1.869 +    // There is not verified path for the chain, howeever we still want to 
   1.870 +    // present to the user as much of a possible chain as possible, in the case
   1.871 +    // where there was a problem with the cert or the issuers.
   1.872 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.873 +           ("pipnss: getchain :CertVerify failed to get chain for '%s'\n",
   1.874 +            mCert->nickname));
   1.875 +    nssChain = CERT_GetCertChainFromCert(mCert.get(), PR_Now(),
   1.876 +                                         certUsageSSLClient);
   1.877 +  } 
   1.878 +
   1.879 +  if (!nssChain) {
   1.880 +    return NS_ERROR_FAILURE;
   1.881 +  }
   1.882 +
   1.883 +  // enumerate the chain for scripting purposes
   1.884 +  nsCOMPtr<nsIMutableArray> array =
   1.885 +    do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   1.886 +  if (NS_FAILED(rv)) {
   1.887 +    goto done;
   1.888 +  }
   1.889 +  CERTCertListNode* node;
   1.890 +  for (node = CERT_LIST_HEAD(nssChain.get());
   1.891 +       !CERT_LIST_END(node, nssChain.get());
   1.892 +       node = CERT_LIST_NEXT(node)) {
   1.893 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.894 +           ("adding %s to chain\n", node->cert->nickname));
   1.895 +    nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
   1.896 +    array->AppendElement(cert, false);
   1.897 +  }
   1.898 +  *_rvChain = array;
   1.899 +  NS_IF_ADDREF(*_rvChain);
   1.900 +  rv = NS_OK;
   1.901 +done:
   1.902 +  return rv;
   1.903 +}
   1.904 +
   1.905 +NS_IMETHODIMP
   1.906 +nsNSSCertificate::GetAllTokenNames(uint32_t* aLength, char16_t*** aTokenNames)
   1.907 +{
   1.908 +  nsNSSShutDownPreventionLock locker;
   1.909 +  if (isAlreadyShutDown())
   1.910 +    return NS_ERROR_NOT_AVAILABLE;
   1.911 +
   1.912 +  NS_ENSURE_ARG(aLength);
   1.913 +  NS_ENSURE_ARG(aTokenNames);
   1.914 +  *aLength = 0;
   1.915 +  *aTokenNames = nullptr;
   1.916 +
   1.917 +  // Get the slots from NSS
   1.918 +  ScopedPK11SlotList slots;
   1.919 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting slots for \"%s\"\n", mCert->nickname));
   1.920 +  slots = PK11_GetAllSlotsForCert(mCert.get(), nullptr);
   1.921 +  if (!slots) {
   1.922 +    if (PORT_GetError() == SEC_ERROR_NO_TOKEN)
   1.923 +      return NS_OK; // List of slots is empty, return empty array
   1.924 +    else
   1.925 +      return NS_ERROR_FAILURE;
   1.926 +  }
   1.927 +
   1.928 +  // read the token names from slots
   1.929 +  PK11SlotListElement* le;
   1.930 +
   1.931 +  for (le = slots->head; le; le = le->next) {
   1.932 +    ++(*aLength);
   1.933 +  }
   1.934 +
   1.935 +  *aTokenNames = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength));
   1.936 +  if (!*aTokenNames) {
   1.937 +    *aLength = 0;
   1.938 +    return NS_ERROR_OUT_OF_MEMORY;
   1.939 +  }
   1.940 +
   1.941 +  uint32_t iToken;
   1.942 +  for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) {
   1.943 +    char* token = PK11_GetTokenName(le->slot);
   1.944 +    (*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token));
   1.945 +    if (!(*aTokenNames)[iToken]) {
   1.946 +      NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames);
   1.947 +      *aLength = 0;
   1.948 +      *aTokenNames = nullptr;
   1.949 +      return NS_ERROR_OUT_OF_MEMORY;
   1.950 +    }
   1.951 +  }
   1.952 +
   1.953 +  return NS_OK;
   1.954 +}
   1.955 +
   1.956 +NS_IMETHODIMP
   1.957 +nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
   1.958 +{
   1.959 +  nsNSSShutDownPreventionLock locker;
   1.960 +  if (isAlreadyShutDown())
   1.961 +    return NS_ERROR_NOT_AVAILABLE;
   1.962 +
   1.963 +  _subjectName.Truncate();
   1.964 +  if (mCert->subjectName) {
   1.965 +    _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
   1.966 +    return NS_OK;
   1.967 +  }
   1.968 +  return NS_ERROR_FAILURE;
   1.969 +}
   1.970 +
   1.971 +NS_IMETHODIMP
   1.972 +nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
   1.973 +{
   1.974 +  nsNSSShutDownPreventionLock locker;
   1.975 +  if (isAlreadyShutDown())
   1.976 +    return NS_ERROR_NOT_AVAILABLE;
   1.977 +
   1.978 +  _issuerName.Truncate();
   1.979 +  if (mCert->issuerName) {
   1.980 +    _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
   1.981 +    return NS_OK;
   1.982 +  }
   1.983 +  return NS_ERROR_FAILURE;
   1.984 +}
   1.985 +
   1.986 +NS_IMETHODIMP
   1.987 +nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
   1.988 +{
   1.989 +  nsNSSShutDownPreventionLock locker;
   1.990 +  if (isAlreadyShutDown())
   1.991 +    return NS_ERROR_NOT_AVAILABLE;
   1.992 +
   1.993 +  _serialNumber.Truncate();
   1.994 +  char* tmpstr = CERT_Hexify(&mCert->serialNumber, 1);
   1.995 +  if (tmpstr) {
   1.996 +    _serialNumber = NS_ConvertASCIItoUTF16(tmpstr);
   1.997 +    PORT_Free(tmpstr);
   1.998 +    return NS_OK;
   1.999 +  }
  1.1000 +  return NS_ERROR_FAILURE;
  1.1001 +}
  1.1002 +
  1.1003 +NS_IMETHODIMP
  1.1004 +nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
  1.1005 +{
  1.1006 +  nsNSSShutDownPreventionLock locker;
  1.1007 +  if (isAlreadyShutDown())
  1.1008 +    return NS_ERROR_NOT_AVAILABLE;
  1.1009 +
  1.1010 +  _sha1Fingerprint.Truncate();
  1.1011 +  unsigned char fingerprint[20];
  1.1012 +  SECItem fpItem;
  1.1013 +  memset(fingerprint, 0, sizeof fingerprint);
  1.1014 +  PK11_HashBuf(SEC_OID_SHA1, fingerprint,
  1.1015 +               mCert->derCert.data, mCert->derCert.len);
  1.1016 +  fpItem.data = fingerprint;
  1.1017 +  fpItem.len = SHA1_LENGTH;
  1.1018 +  char* fpStr = CERT_Hexify(&fpItem, 1);
  1.1019 +  if (fpStr) {
  1.1020 +    _sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
  1.1021 +    PORT_Free(fpStr);
  1.1022 +    return NS_OK;
  1.1023 +  }
  1.1024 +  return NS_ERROR_FAILURE;
  1.1025 +}
  1.1026 +
  1.1027 +NS_IMETHODIMP
  1.1028 +nsNSSCertificate::GetMd5Fingerprint(nsAString& _md5Fingerprint)
  1.1029 +{
  1.1030 +  nsNSSShutDownPreventionLock locker;
  1.1031 +  if (isAlreadyShutDown())
  1.1032 +    return NS_ERROR_NOT_AVAILABLE;
  1.1033 +
  1.1034 +  _md5Fingerprint.Truncate();
  1.1035 +  unsigned char fingerprint[20];
  1.1036 +  SECItem fpItem;
  1.1037 +  memset(fingerprint, 0, sizeof fingerprint);
  1.1038 +  PK11_HashBuf(SEC_OID_MD5, fingerprint,
  1.1039 +               mCert->derCert.data, mCert->derCert.len);
  1.1040 +  fpItem.data = fingerprint;
  1.1041 +  fpItem.len = MD5_LENGTH;
  1.1042 +  char* fpStr = CERT_Hexify(&fpItem, 1);
  1.1043 +  if (fpStr) {
  1.1044 +    _md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
  1.1045 +    PORT_Free(fpStr);
  1.1046 +    return NS_OK;
  1.1047 +  }
  1.1048 +  return NS_ERROR_FAILURE;
  1.1049 +}
  1.1050 +
  1.1051 +NS_IMETHODIMP
  1.1052 +nsNSSCertificate::GetTokenName(nsAString& aTokenName)
  1.1053 +{
  1.1054 +  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  1.1055 +
  1.1056 +  nsNSSShutDownPreventionLock locker;
  1.1057 +  if (isAlreadyShutDown())
  1.1058 +    return NS_ERROR_NOT_AVAILABLE;
  1.1059 +
  1.1060 +  aTokenName.Truncate();
  1.1061 +  if (mCert) {
  1.1062 +    // HACK alert
  1.1063 +    // When the trust of a builtin cert is modified, NSS copies it into the
  1.1064 +    // cert db.  At this point, it is now "managed" by the user, and should
  1.1065 +    // not be listed with the builtins.  However, in the collection code
  1.1066 +    // used by PK11_ListCerts, the cert is found in the temp db, where it
  1.1067 +    // has been loaded from the token.  Though the trust is correct (grabbed
  1.1068 +    // from the cert db), the source is wrong.  I believe this is a safe
  1.1069 +    // way to work around this.
  1.1070 +    if (mCert->slot) {
  1.1071 +      char* token = PK11_GetTokenName(mCert->slot);
  1.1072 +      if (token) {
  1.1073 +        aTokenName = NS_ConvertUTF8toUTF16(token);
  1.1074 +      }
  1.1075 +    } else {
  1.1076 +      nsresult rv;
  1.1077 +      nsAutoString tok;
  1.1078 +      nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  1.1079 +      if (NS_FAILED(rv)) return rv;
  1.1080 +      rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
  1.1081 +      if (NS_SUCCEEDED(rv))
  1.1082 +        aTokenName = tok;
  1.1083 +    }
  1.1084 +  }
  1.1085 +  return NS_OK;
  1.1086 +}
  1.1087 +
  1.1088 +NS_IMETHODIMP
  1.1089 +nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
  1.1090 +{
  1.1091 +  nsNSSShutDownPreventionLock locker;
  1.1092 +  if (isAlreadyShutDown()) {
  1.1093 +    return NS_ERROR_NOT_AVAILABLE;
  1.1094 +  }
  1.1095 +
  1.1096 +  aSha256SPKIDigest.Truncate();
  1.1097 +  Digest digest;
  1.1098 +  nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
  1.1099 +                                 mCert->derPublicKey.len);
  1.1100 +  if (NS_WARN_IF(NS_FAILED(rv))) {
  1.1101 +    return rv;
  1.1102 +  }
  1.1103 +  rv = Base64Encode(nsDependentCSubstring(
  1.1104 +                      reinterpret_cast<const char*> (digest.get().data),
  1.1105 +                      digest.get().len),
  1.1106 +                    aSha256SPKIDigest);
  1.1107 +  if (NS_WARN_IF(NS_FAILED(rv))) {
  1.1108 +    return rv;
  1.1109 +  }
  1.1110 +  return NS_OK;
  1.1111 +}
  1.1112 +
  1.1113 +NS_IMETHODIMP
  1.1114 +nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
  1.1115 +{
  1.1116 +  nsNSSShutDownPreventionLock locker;
  1.1117 +  if (isAlreadyShutDown())
  1.1118 +    return NS_ERROR_NOT_AVAILABLE;
  1.1119 +
  1.1120 +  if (mCert) {
  1.1121 +    *aArray = (uint8_t*)nsMemory::Alloc(mCert->derCert.len);
  1.1122 +    if (*aArray) {
  1.1123 +      memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
  1.1124 +      *aLength = mCert->derCert.len;
  1.1125 +      return NS_OK;
  1.1126 +    }
  1.1127 +  }
  1.1128 +  *aLength = 0;
  1.1129 +  return NS_ERROR_FAILURE;
  1.1130 +}
  1.1131 +
  1.1132 +NS_IMETHODIMP
  1.1133 +nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
  1.1134 +                              uint32_t* aLength, uint8_t** aArray)
  1.1135 +{
  1.1136 +  NS_ENSURE_ARG(aLength);
  1.1137 +  NS_ENSURE_ARG(aArray);
  1.1138 +
  1.1139 +  nsNSSShutDownPreventionLock locker;
  1.1140 +  if (isAlreadyShutDown())
  1.1141 +    return NS_ERROR_NOT_AVAILABLE;
  1.1142 +
  1.1143 +  if (!mCert)
  1.1144 +    return NS_ERROR_FAILURE;
  1.1145 +
  1.1146 +  switch (chainMode) {
  1.1147 +    case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
  1.1148 +    case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
  1.1149 +    case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
  1.1150 +      break;
  1.1151 +    default:
  1.1152 +      return NS_ERROR_INVALID_ARG;
  1.1153 +  };
  1.1154 +
  1.1155 +  PLArenaPool* arena = PORT_NewArena(1024);
  1.1156 +  PLArenaPoolCleanerFalseParam arenaCleaner(arena);
  1.1157 +  if (!arena) {
  1.1158 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1159 +           ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
  1.1160 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1161 +  }
  1.1162 +
  1.1163 +  ScopedNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
  1.1164 +  if (!cmsg) {
  1.1165 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1166 +           ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
  1.1167 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1168 +  }
  1.1169 +
  1.1170 +  // first, create SignedData with the certificate only (no chain)
  1.1171 +  ScopedNSSCMSSignedData sigd(
  1.1172 +    NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert.get(), false));
  1.1173 +  if (!sigd) {
  1.1174 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1175 +           ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
  1.1176 +    return NS_ERROR_FAILURE;
  1.1177 +  }
  1.1178 +
  1.1179 +  // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
  1.1180 +  // to specify the inclusion of the root, but CERT_CertChainFromCert() does.
  1.1181 +  // Since CERT_CertChainFromCert() also includes the certificate itself,
  1.1182 +  // we have to start at the issuing cert (to avoid duplicate certs
  1.1183 +  // in the SignedData).
  1.1184 +  if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
  1.1185 +      chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
  1.1186 +    ScopedCERTCertificate issuerCert(
  1.1187 +        CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
  1.1188 +    // the issuerCert of a self signed root is the cert itself,
  1.1189 +    // so make sure we're not adding duplicates, again
  1.1190 +    if (issuerCert && issuerCert != mCert.get()) {
  1.1191 +      bool includeRoot =
  1.1192 +        (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
  1.1193 +      ScopedCERTCertificateList certChain(
  1.1194 +          CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot));
  1.1195 +      if (certChain) {
  1.1196 +        if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) {
  1.1197 +          certChain.forget();
  1.1198 +        }
  1.1199 +        else {
  1.1200 +          PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1201 +                 ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
  1.1202 +          return NS_ERROR_FAILURE;
  1.1203 +        }
  1.1204 +      }
  1.1205 +      else {
  1.1206 +        // try to add the issuerCert, at least
  1.1207 +        if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert)
  1.1208 +            == SECSuccess) {
  1.1209 +          issuerCert.forget();
  1.1210 +        }
  1.1211 +        else {
  1.1212 +          PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1213 +                 ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
  1.1214 +          return NS_ERROR_FAILURE;
  1.1215 +        }
  1.1216 +      }
  1.1217 +    }
  1.1218 +  }
  1.1219 +
  1.1220 +  NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  1.1221 +  if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
  1.1222 +       == SECSuccess) {
  1.1223 +    sigd.forget();
  1.1224 +  }
  1.1225 +  else {
  1.1226 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1227 +           ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
  1.1228 +    return NS_ERROR_FAILURE;
  1.1229 +  }
  1.1230 +
  1.1231 +  SECItem certP7 = { siBuffer, nullptr, 0 };
  1.1232 +  NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr,
  1.1233 +                                                   &certP7, arena, nullptr,
  1.1234 +                                                   nullptr, nullptr, nullptr,
  1.1235 +                                                   nullptr, nullptr);
  1.1236 +  if (!ecx) {
  1.1237 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1238 +           ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
  1.1239 +    return NS_ERROR_FAILURE;
  1.1240 +  }
  1.1241 +
  1.1242 +  if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
  1.1243 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1244 +           ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
  1.1245 +    return NS_ERROR_FAILURE;
  1.1246 +  }
  1.1247 +
  1.1248 +  *aArray = (uint8_t*)nsMemory::Alloc(certP7.len);
  1.1249 +  if (!*aArray)
  1.1250 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1251 +
  1.1252 +  memcpy(*aArray, certP7.data, certP7.len);
  1.1253 +  *aLength = certP7.len;
  1.1254 +  return NS_OK;
  1.1255 +}
  1.1256 +
  1.1257 +CERTCertificate*
  1.1258 +nsNSSCertificate::GetCert()
  1.1259 +{
  1.1260 +  nsNSSShutDownPreventionLock locker;
  1.1261 +  if (isAlreadyShutDown())
  1.1262 +    return nullptr;
  1.1263 +
  1.1264 +  return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
  1.1265 +}
  1.1266 +
  1.1267 +NS_IMETHODIMP
  1.1268 +nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
  1.1269 +{
  1.1270 +  nsNSSShutDownPreventionLock locker;
  1.1271 +  if (isAlreadyShutDown())
  1.1272 +    return NS_ERROR_NOT_AVAILABLE;
  1.1273 +
  1.1274 +  NS_ENSURE_ARG(aValidity);
  1.1275 +  nsX509CertValidity* validity = new nsX509CertValidity(mCert.get());
  1.1276 +
  1.1277 +  NS_ADDREF(validity);
  1.1278 +  *aValidity = static_cast<nsIX509CertValidity*>(validity);
  1.1279 +  return NS_OK;
  1.1280 +}
  1.1281 +
  1.1282 +NS_IMETHODIMP
  1.1283 +nsNSSCertificate::GetUsagesArray(bool localOnly,
  1.1284 +                                 uint32_t* _verified,
  1.1285 +                                 uint32_t* _count,
  1.1286 +                                 char16_t*** _usages)
  1.1287 +{
  1.1288 +  nsNSSShutDownPreventionLock locker;
  1.1289 +  if (isAlreadyShutDown())
  1.1290 +    return NS_ERROR_NOT_AVAILABLE;
  1.1291 +
  1.1292 +  nsresult rv;
  1.1293 +  const int max_usages = 13;
  1.1294 +  char16_t* tmpUsages[max_usages];
  1.1295 +  const char* suffix = "";
  1.1296 +  uint32_t tmpCount;
  1.1297 +  nsUsageArrayHelper uah(mCert.get());
  1.1298 +  rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount,
  1.1299 +                          tmpUsages);
  1.1300 +  NS_ENSURE_SUCCESS(rv,rv);
  1.1301 +  if (tmpCount > 0) {
  1.1302 +    *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * tmpCount);
  1.1303 +    if (!*_usages)
  1.1304 +      return NS_ERROR_OUT_OF_MEMORY;
  1.1305 +    for (uint32_t i=0; i<tmpCount; i++) {
  1.1306 +      (*_usages)[i] = tmpUsages[i];
  1.1307 +    }
  1.1308 +    *_count = tmpCount;
  1.1309 +    return NS_OK;
  1.1310 +  }
  1.1311 +  *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*));
  1.1312 +  if (!*_usages)
  1.1313 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1314 +  *_count = 0;
  1.1315 +  return NS_OK;
  1.1316 +}
  1.1317 +
  1.1318 +NS_IMETHODIMP
  1.1319 +nsNSSCertificate::RequestUsagesArrayAsync(
  1.1320 +  nsICertVerificationListener* aResultListener)
  1.1321 +{
  1.1322 +  NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
  1.1323 +
  1.1324 +  if (!aResultListener)
  1.1325 +    return NS_ERROR_FAILURE;
  1.1326 +
  1.1327 +  nsCertVerificationJob* job = new nsCertVerificationJob;
  1.1328 +
  1.1329 +  job->mCert = this;
  1.1330 +  job->mListener =
  1.1331 +    new nsMainThreadPtrHolder<nsICertVerificationListener>(aResultListener);
  1.1332 +
  1.1333 +  nsresult rv = nsCertVerificationThread::addJob(job);
  1.1334 +  if (NS_FAILED(rv))
  1.1335 +    delete job;
  1.1336 +
  1.1337 +  return rv;
  1.1338 +}
  1.1339 +
  1.1340 +NS_IMETHODIMP
  1.1341 +nsNSSCertificate::GetUsagesString(bool localOnly, uint32_t* _verified,
  1.1342 +                                  nsAString& _usages)
  1.1343 +{
  1.1344 +  nsNSSShutDownPreventionLock locker;
  1.1345 +  if (isAlreadyShutDown())
  1.1346 +    return NS_ERROR_NOT_AVAILABLE;
  1.1347 +
  1.1348 +  nsresult rv;
  1.1349 +  const int max_usages = 13;
  1.1350 +  char16_t* tmpUsages[max_usages];
  1.1351 +  const char* suffix = "_p";
  1.1352 +  uint32_t tmpCount;
  1.1353 +  nsUsageArrayHelper uah(mCert.get());
  1.1354 +  rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount,
  1.1355 +                          tmpUsages);
  1.1356 +  NS_ENSURE_SUCCESS(rv,rv);
  1.1357 +  _usages.Truncate();
  1.1358 +  for (uint32_t i=0; i<tmpCount; i++) {
  1.1359 +    if (i>0) _usages.AppendLiteral(",");
  1.1360 +    _usages.Append(tmpUsages[i]);
  1.1361 +    nsMemory::Free(tmpUsages[i]);
  1.1362 +  }
  1.1363 +  return NS_OK;
  1.1364 +}
  1.1365 +
  1.1366 +#if defined(DEBUG_javi) || defined(DEBUG_jgmyers)
  1.1367 +void
  1.1368 +DumpASN1Object(nsIASN1Object* object, unsigned int level)
  1.1369 +{
  1.1370 +  nsAutoString dispNameU, dispValU;
  1.1371 +  unsigned int i;
  1.1372 +  nsCOMPtr<nsIMutableArray> asn1Objects;
  1.1373 +  nsCOMPtr<nsISupports> isupports;
  1.1374 +  nsCOMPtr<nsIASN1Object> currObject;
  1.1375 +  bool processObjects;
  1.1376 +  uint32_t numObjects;
  1.1377 +
  1.1378 +  for (i=0; i<level; i++)
  1.1379 +    printf ("  ");
  1.1380 +
  1.1381 +  object->GetDisplayName(dispNameU);
  1.1382 +  nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
  1.1383 +  if (sequence) {
  1.1384 +    printf ("%s ", NS_ConvertUTF16toUTF8(dispNameU).get());
  1.1385 +    sequence->GetIsValidContainer(&processObjects);
  1.1386 +    if (processObjects) {
  1.1387 +      printf("\n");
  1.1388 +      sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
  1.1389 +      asn1Objects->GetLength(&numObjects);
  1.1390 +      for (i=0; i<numObjects;i++) {
  1.1391 +        asn1Objects->QueryElementAt(i, NS_GET_IID(nsISupports),
  1.1392 +                                    getter_AddRefs(currObject));
  1.1393 +        DumpASN1Object(currObject, level+1);
  1.1394 +      }
  1.1395 +    } else {
  1.1396 +      object->GetDisplayValue(dispValU);
  1.1397 +      printf("= %s\n", NS_ConvertUTF16toUTF8(dispValU).get());
  1.1398 +    }
  1.1399 +  } else {
  1.1400 +    object->GetDisplayValue(dispValU);
  1.1401 +    printf("%s = %s\n",NS_ConvertUTF16toUTF8(dispNameU).get(),
  1.1402 +                       NS_ConvertUTF16toUTF8(dispValU).get());
  1.1403 +  }
  1.1404 +}
  1.1405 +#endif
  1.1406 +
  1.1407 +NS_IMETHODIMP
  1.1408 +nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
  1.1409 +{
  1.1410 +  nsNSSShutDownPreventionLock locker;
  1.1411 +  nsresult rv = NS_OK;
  1.1412 +  NS_ENSURE_ARG_POINTER(aASN1Structure);
  1.1413 +  // First create the recursive structure os ASN1Objects
  1.1414 +  // which tells us the layout of the cert.
  1.1415 +  rv = CreateASN1Struct(aASN1Structure);
  1.1416 +  if (NS_FAILED(rv)) {
  1.1417 +    return rv;
  1.1418 +  }
  1.1419 +#ifdef DEBUG_javi
  1.1420 +  DumpASN1Object(*aASN1Structure, 0);
  1.1421 +#endif
  1.1422 +  return rv;
  1.1423 +}
  1.1424 +
  1.1425 +NS_IMETHODIMP
  1.1426 +nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
  1.1427 +{
  1.1428 +  nsNSSShutDownPreventionLock locker;
  1.1429 +  if (isAlreadyShutDown())
  1.1430 +    return NS_ERROR_NOT_AVAILABLE;
  1.1431 +
  1.1432 +  NS_ENSURE_ARG(other);
  1.1433 +  NS_ENSURE_ARG(result);
  1.1434 +
  1.1435 +  nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other);
  1.1436 +  if (!other2)
  1.1437 +    return NS_ERROR_FAILURE;
  1.1438 +
  1.1439 +  ScopedCERTCertificate cert(other2->GetCert());
  1.1440 +  *result = (mCert.get() == cert.get());
  1.1441 +  return NS_OK;
  1.1442 +}
  1.1443 +
  1.1444 +NS_IMETHODIMP
  1.1445 +nsNSSCertificate::SaveSMimeProfile()
  1.1446 +{
  1.1447 +  nsNSSShutDownPreventionLock locker;
  1.1448 +  if (isAlreadyShutDown())
  1.1449 +    return NS_ERROR_NOT_AVAILABLE;
  1.1450 +
  1.1451 +  if (SECSuccess != CERT_SaveSMimeProfile(mCert.get(), nullptr, nullptr))
  1.1452 +    return NS_ERROR_FAILURE;
  1.1453 +  else
  1.1454 +    return NS_OK;
  1.1455 +}
  1.1456 +
  1.1457 +#ifndef MOZ_NO_EV_CERTS
  1.1458 +
  1.1459 +nsresult
  1.1460 +nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
  1.1461 +{
  1.1462 +  nsNSSShutDownPreventionLock locker;
  1.1463 +  if (isAlreadyShutDown())
  1.1464 +    return NS_ERROR_NOT_AVAILABLE;
  1.1465 +
  1.1466 +  EnsureIdentityInfoLoaded();
  1.1467 +
  1.1468 +  RefPtr<mozilla::psm::SharedCertVerifier>
  1.1469 +    certVerifier(mozilla::psm::GetDefaultCertVerifier());
  1.1470 +  NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
  1.1471 +
  1.1472 +  validEV = false;
  1.1473 +  resultOidTag = SEC_OID_UNKNOWN;
  1.1474 +
  1.1475 +  uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY |
  1.1476 +    mozilla::psm::CertVerifier::FLAG_MUST_BE_EV;
  1.1477 +  SECStatus rv = certVerifier->VerifyCert(mCert.get(),
  1.1478 +    certificateUsageSSLServer, PR_Now(),
  1.1479 +    nullptr /* XXX pinarg */,
  1.1480 +    nullptr /* hostname */,
  1.1481 +    flags, nullptr /* stapledOCSPResponse */ , nullptr, &resultOidTag);
  1.1482 +
  1.1483 +  if (rv != SECSuccess) {
  1.1484 +    resultOidTag = SEC_OID_UNKNOWN;
  1.1485 +  }
  1.1486 +  if (resultOidTag != SEC_OID_UNKNOWN) {
  1.1487 +    validEV = true;
  1.1488 +  }
  1.1489 +  return NS_OK;
  1.1490 +}
  1.1491 +
  1.1492 +nsresult
  1.1493 +nsNSSCertificate::getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
  1.1494 +{
  1.1495 +  if (mCachedEVStatus != ev_status_unknown) {
  1.1496 +    validEV = (mCachedEVStatus == ev_status_valid);
  1.1497 +    if (validEV) {
  1.1498 +      resultOidTag = mCachedEVOidTag;
  1.1499 +    }
  1.1500 +    return NS_OK;
  1.1501 +  }
  1.1502 +
  1.1503 +  nsresult rv = hasValidEVOidTag(resultOidTag, validEV);
  1.1504 +  if (NS_SUCCEEDED(rv)) {
  1.1505 +    if (validEV) {
  1.1506 +      mCachedEVOidTag = resultOidTag;
  1.1507 +    }
  1.1508 +    mCachedEVStatus = validEV ? ev_status_valid : ev_status_invalid;
  1.1509 +  }
  1.1510 +  return rv;
  1.1511 +}
  1.1512 +
  1.1513 +#endif // MOZ_NO_EV_CERTS
  1.1514 +
  1.1515 +NS_IMETHODIMP
  1.1516 +nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV)
  1.1517 +{
  1.1518 +#ifdef MOZ_NO_EV_CERTS
  1.1519 +  *aIsEV = false;
  1.1520 +  return NS_OK;
  1.1521 +#else
  1.1522 +  nsNSSShutDownPreventionLock locker;
  1.1523 +  if (isAlreadyShutDown()) {
  1.1524 +    return NS_ERROR_NOT_AVAILABLE;
  1.1525 +  }
  1.1526 +
  1.1527 +  NS_ENSURE_ARG(aIsEV);
  1.1528 +  *aIsEV = false;
  1.1529 +
  1.1530 +  if (mCachedEVStatus != ev_status_unknown) {
  1.1531 +    *aIsEV = (mCachedEVStatus == ev_status_valid);
  1.1532 +    return NS_OK;
  1.1533 +  }
  1.1534 +
  1.1535 +  SECOidTag oid_tag;
  1.1536 +  return getValidEVOidTag(oid_tag, *aIsEV);
  1.1537 +#endif
  1.1538 +}
  1.1539 +
  1.1540 +NS_IMETHODIMP
  1.1541 +nsNSSCertificate::GetValidEVPolicyOid(nsACString& outDottedOid)
  1.1542 +{
  1.1543 +  outDottedOid.Truncate();
  1.1544 +
  1.1545 +#ifndef MOZ_NO_EV_CERTS
  1.1546 +  nsNSSShutDownPreventionLock locker;
  1.1547 +  if (isAlreadyShutDown()) {
  1.1548 +    return NS_ERROR_NOT_AVAILABLE;
  1.1549 +  }
  1.1550 +
  1.1551 +  SECOidTag oid_tag;
  1.1552 +  bool valid;
  1.1553 +  nsresult rv = getValidEVOidTag(oid_tag, valid);
  1.1554 +  if (NS_FAILED(rv)) {
  1.1555 +    return rv;
  1.1556 +  }
  1.1557 +
  1.1558 +  if (valid) {
  1.1559 +    SECOidData* oid_data = SECOID_FindOIDByTag(oid_tag);
  1.1560 +    if (!oid_data) {
  1.1561 +      return NS_ERROR_FAILURE;
  1.1562 +    }
  1.1563 +
  1.1564 +    char* oid_str = CERT_GetOidString(&oid_data->oid);
  1.1565 +    if (!oid_str) {
  1.1566 +      return NS_ERROR_FAILURE;
  1.1567 +    }
  1.1568 +
  1.1569 +    outDottedOid.Assign(oid_str);
  1.1570 +    PR_smprintf_free(oid_str);
  1.1571 +  }
  1.1572 +#endif
  1.1573 +
  1.1574 +  return NS_OK;
  1.1575 +}
  1.1576 +
  1.1577 +NS_IMPL_ISUPPORTS(nsNSSCertList, nsIX509CertList)
  1.1578 +
  1.1579 +nsNSSCertList::nsNSSCertList(mozilla::pkix::ScopedCERTCertList& certList,
  1.1580 +                             const nsNSSShutDownPreventionLock& proofOfLock)
  1.1581 +{
  1.1582 +  if (certList) {
  1.1583 +    mCertList = certList.release();
  1.1584 +  } else {
  1.1585 +    mCertList = CERT_NewCertList();
  1.1586 +  }
  1.1587 +}
  1.1588 +
  1.1589 +nsNSSCertList::nsNSSCertList()
  1.1590 +{
  1.1591 +  mCertList = CERT_NewCertList();
  1.1592 +}
  1.1593 +
  1.1594 +nsNSSCertList::~nsNSSCertList()
  1.1595 +{
  1.1596 +  nsNSSShutDownPreventionLock locker;
  1.1597 +  if (isAlreadyShutDown()) {
  1.1598 +    return;
  1.1599 +  }
  1.1600 +  destructorSafeDestroyNSSReference();
  1.1601 +  shutdown(calledFromObject);
  1.1602 +}
  1.1603 +
  1.1604 +void nsNSSCertList::virtualDestroyNSSReference()
  1.1605 +{
  1.1606 +  destructorSafeDestroyNSSReference();
  1.1607 +}
  1.1608 +
  1.1609 +void nsNSSCertList::destructorSafeDestroyNSSReference()
  1.1610 +{
  1.1611 +  if (mCertList) {
  1.1612 +    mCertList = nullptr;
  1.1613 +  }
  1.1614 +}
  1.1615 +
  1.1616 +NS_IMETHODIMP
  1.1617 +nsNSSCertList::AddCert(nsIX509Cert* aCert)
  1.1618 +{
  1.1619 +  nsNSSShutDownPreventionLock locker;
  1.1620 +  if (isAlreadyShutDown()) {
  1.1621 +    return NS_ERROR_NOT_AVAILABLE;
  1.1622 +  }
  1.1623 +  nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
  1.1624 +  CERTCertificate* cert;
  1.1625 +
  1.1626 +  cert = nssCert->GetCert();
  1.1627 +  if (!cert) {
  1.1628 +    NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
  1.1629 +    return NS_ERROR_FAILURE;
  1.1630 +  }
  1.1631 +
  1.1632 +  if (!mCertList) {
  1.1633 +    NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
  1.1634 +    return NS_ERROR_FAILURE;
  1.1635 +  }
  1.1636 +  // XXX: check return value!
  1.1637 +  CERT_AddCertToListTail(mCertList.get(), cert);
  1.1638 +  return NS_OK;
  1.1639 +}
  1.1640 +
  1.1641 +NS_IMETHODIMP
  1.1642 +nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
  1.1643 +{
  1.1644 +  nsNSSShutDownPreventionLock locker;
  1.1645 +  if (isAlreadyShutDown()) {
  1.1646 +    return NS_ERROR_NOT_AVAILABLE;
  1.1647 +  }
  1.1648 +  nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
  1.1649 +  CERTCertificate* cert = nssCert->GetCert();
  1.1650 +  CERTCertListNode* node;
  1.1651 +
  1.1652 +  if (!cert) {
  1.1653 +    NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
  1.1654 +    return NS_ERROR_FAILURE;
  1.1655 +  }
  1.1656 +
  1.1657 +  if (!mCertList) {
  1.1658 +    NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
  1.1659 +    return NS_ERROR_FAILURE;
  1.1660 +  }
  1.1661 +
  1.1662 +  for (node = CERT_LIST_HEAD(mCertList.get());
  1.1663 +       !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) {
  1.1664 +    if (node->cert == cert) {
  1.1665 +	CERT_RemoveCertListNode(node);
  1.1666 +        return NS_OK;
  1.1667 +    }
  1.1668 +  }
  1.1669 +  return NS_OK; // XXX Should we fail if we couldn't find it?
  1.1670 +}
  1.1671 +
  1.1672 +CERTCertList*
  1.1673 +nsNSSCertList::DupCertList(CERTCertList* aCertList,
  1.1674 +                           const nsNSSShutDownPreventionLock& /*proofOfLock*/)
  1.1675 +{
  1.1676 +  if (!aCertList)
  1.1677 +    return nullptr;
  1.1678 +
  1.1679 +  CERTCertList* newList = CERT_NewCertList();
  1.1680 +
  1.1681 +  if (!newList) {
  1.1682 +    return nullptr;
  1.1683 +  }
  1.1684 +
  1.1685 +  CERTCertListNode* node;
  1.1686 +  for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList);
  1.1687 +                                              node = CERT_LIST_NEXT(node)) {
  1.1688 +    CERTCertificate* cert = CERT_DupCertificate(node->cert);
  1.1689 +    CERT_AddCertToListTail(newList, cert);
  1.1690 +  }
  1.1691 +  return newList;
  1.1692 +}
  1.1693 +
  1.1694 +void*
  1.1695 +nsNSSCertList::GetRawCertList()
  1.1696 +{
  1.1697 +  // This function should only be called after adquiring a
  1.1698 +  // nsNSSShutDownPreventionLock
  1.1699 +  return mCertList.get();
  1.1700 +}
  1.1701 +
  1.1702 +NS_IMETHODIMP
  1.1703 +nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
  1.1704 +{
  1.1705 +  nsNSSShutDownPreventionLock locker;
  1.1706 +  if (isAlreadyShutDown()) {
  1.1707 +    return NS_ERROR_NOT_AVAILABLE;
  1.1708 +  }
  1.1709 +  nsCOMPtr<nsISimpleEnumerator> enumerator =
  1.1710 +    new nsNSSCertListEnumerator(mCertList.get(), locker);
  1.1711 +
  1.1712 +  *_retval = enumerator;
  1.1713 +  NS_ADDREF(*_retval);
  1.1714 +  return NS_OK;
  1.1715 +}
  1.1716 +
  1.1717 +NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
  1.1718 +
  1.1719 +nsNSSCertListEnumerator::nsNSSCertListEnumerator(
  1.1720 +  CERTCertList* certList, const nsNSSShutDownPreventionLock& proofOfLock)
  1.1721 +{
  1.1722 +  mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
  1.1723 +}
  1.1724 +
  1.1725 +nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
  1.1726 +{
  1.1727 +  nsNSSShutDownPreventionLock locker;
  1.1728 +  if (isAlreadyShutDown()) {
  1.1729 +    return;
  1.1730 +  }
  1.1731 +  destructorSafeDestroyNSSReference();
  1.1732 +  shutdown(calledFromObject);
  1.1733 +}
  1.1734 +
  1.1735 +void nsNSSCertListEnumerator::virtualDestroyNSSReference()
  1.1736 +{
  1.1737 +  destructorSafeDestroyNSSReference();
  1.1738 +}
  1.1739 +
  1.1740 +void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference()
  1.1741 +{
  1.1742 +  if (mCertList) {
  1.1743 +    mCertList = nullptr;
  1.1744 +  }
  1.1745 +}
  1.1746 +
  1.1747 +NS_IMETHODIMP
  1.1748 +nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
  1.1749 +{
  1.1750 +  nsNSSShutDownPreventionLock locker;
  1.1751 +  if (isAlreadyShutDown()) {
  1.1752 +    return NS_ERROR_NOT_AVAILABLE;
  1.1753 +  }
  1.1754 +
  1.1755 +  NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
  1.1756 +
  1.1757 +  *_retval = !CERT_LIST_EMPTY(mCertList);
  1.1758 +  return NS_OK;
  1.1759 +}
  1.1760 +
  1.1761 +NS_IMETHODIMP
  1.1762 +nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
  1.1763 +{
  1.1764 +  nsNSSShutDownPreventionLock locker;
  1.1765 +  if (isAlreadyShutDown()) {
  1.1766 +    return NS_ERROR_NOT_AVAILABLE;
  1.1767 +  }
  1.1768 +
  1.1769 +  NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
  1.1770 +
  1.1771 +  CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
  1.1772 +  if (CERT_LIST_END(node, mCertList)) {
  1.1773 +    return NS_ERROR_FAILURE;
  1.1774 +  }
  1.1775 +
  1.1776 +  nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
  1.1777 +  if (!nssCert) {
  1.1778 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1779 +  }
  1.1780 +
  1.1781 +  *_retval = nssCert;
  1.1782 +  NS_ADDREF(*_retval);
  1.1783 +
  1.1784 +  CERT_RemoveCertListNode(node);
  1.1785 +  return NS_OK;
  1.1786 +}
  1.1787 +
  1.1788 +// NB: This serialization must match that of nsNSSCertificateFakeTransport.
  1.1789 +NS_IMETHODIMP
  1.1790 +nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
  1.1791 +{
  1.1792 +  NS_ENSURE_STATE(mCert);
  1.1793 +  nsresult rv = aStream->Write32(static_cast<uint32_t>(mCachedEVStatus));
  1.1794 +  if (NS_FAILED(rv)) {
  1.1795 +    return rv;
  1.1796 +  }
  1.1797 +  rv = aStream->Write32(mCert->derCert.len);
  1.1798 +  if (NS_FAILED(rv)) {
  1.1799 +    return rv;
  1.1800 +  }
  1.1801 +  return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
  1.1802 +}
  1.1803 +
  1.1804 +NS_IMETHODIMP
  1.1805 +nsNSSCertificate::Read(nsIObjectInputStream* aStream)
  1.1806 +{
  1.1807 +  NS_ENSURE_STATE(!mCert);
  1.1808 +
  1.1809 +  uint32_t cachedEVStatus;
  1.1810 +  nsresult rv = aStream->Read32(&cachedEVStatus);
  1.1811 +  if (NS_FAILED(rv)) {
  1.1812 +    return rv;
  1.1813 +  }
  1.1814 +  if (cachedEVStatus == static_cast<uint32_t>(ev_status_unknown)) {
  1.1815 +    mCachedEVStatus = ev_status_unknown;
  1.1816 +  } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_valid)) {
  1.1817 +    mCachedEVStatus = ev_status_valid;
  1.1818 +  } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_invalid)) {
  1.1819 +    mCachedEVStatus = ev_status_invalid;
  1.1820 +  } else {
  1.1821 +    return NS_ERROR_UNEXPECTED;
  1.1822 +  }
  1.1823 +
  1.1824 +  uint32_t len;
  1.1825 +  rv = aStream->Read32(&len);
  1.1826 +  if (NS_FAILED(rv)) {
  1.1827 +    return rv;
  1.1828 +  }
  1.1829 +
  1.1830 +  nsXPIDLCString str;
  1.1831 +  rv = aStream->ReadBytes(len, getter_Copies(str));
  1.1832 +  if (NS_FAILED(rv)) {
  1.1833 +    return rv;
  1.1834 +  }
  1.1835 +
  1.1836 +  if (!InitFromDER(const_cast<char*>(str.get()), len)) {
  1.1837 +    return NS_ERROR_UNEXPECTED;
  1.1838 +  }
  1.1839 +
  1.1840 +  return NS_OK;
  1.1841 +}
  1.1842 +
  1.1843 +NS_IMETHODIMP
  1.1844 +nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
  1.1845 +{
  1.1846 +  *count = 0;
  1.1847 +  *array = nullptr;
  1.1848 +  return NS_OK;
  1.1849 +}
  1.1850 +
  1.1851 +NS_IMETHODIMP
  1.1852 +nsNSSCertificate::GetHelperForLanguage(uint32_t language,
  1.1853 +                                       nsISupports** _retval)
  1.1854 +{
  1.1855 +  *_retval = nullptr;
  1.1856 +  return NS_OK;
  1.1857 +}
  1.1858 +
  1.1859 +NS_IMETHODIMP
  1.1860 +nsNSSCertificate::GetContractID(char** aContractID)
  1.1861 +{
  1.1862 +  *aContractID = nullptr;
  1.1863 +  return NS_OK;
  1.1864 +}
  1.1865 +
  1.1866 +NS_IMETHODIMP
  1.1867 +nsNSSCertificate::GetClassDescription(char** aClassDescription)
  1.1868 +{
  1.1869 +  *aClassDescription = nullptr;
  1.1870 +  return NS_OK;
  1.1871 +}
  1.1872 +
  1.1873 +NS_IMETHODIMP
  1.1874 +nsNSSCertificate::GetClassID(nsCID** aClassID)
  1.1875 +{
  1.1876 +  *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
  1.1877 +  if (!*aClassID)
  1.1878 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1879 +  return GetClassIDNoAlloc(*aClassID);
  1.1880 +}
  1.1881 +
  1.1882 +NS_IMETHODIMP
  1.1883 +nsNSSCertificate::GetImplementationLanguage(uint32_t* aImplementationLanguage)
  1.1884 +{
  1.1885 +  *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
  1.1886 +  return NS_OK;
  1.1887 +}
  1.1888 +
  1.1889 +NS_IMETHODIMP
  1.1890 +nsNSSCertificate::GetFlags(uint32_t* aFlags)
  1.1891 +{
  1.1892 +  *aFlags = nsIClassInfo::THREADSAFE;
  1.1893 +  return NS_OK;
  1.1894 +}
  1.1895 +
  1.1896 +NS_IMETHODIMP
  1.1897 +nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
  1.1898 +{
  1.1899 +  static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
  1.1900 +
  1.1901 +  *aClassIDNoAlloc = kNSSCertificateCID;
  1.1902 +  return NS_OK;
  1.1903 +}

mercurial