tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsNSSCertificate.cpp (20779B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "nsNSSCertificate.h"
      7 
      8 #include "CertVerifier.h"
      9 #include "ExtendedValidation.h"
     10 #include "NSSCertDBTrustDomain.h"
     11 #include "X509CertValidity.h"
     12 #include "certdb.h"
     13 #include "ipc/IPCMessageUtils.h"
     14 #include "ipc/IPCMessageUtilsSpecializations.h"
     15 #include "mozilla/Base64.h"
     16 #include "mozilla/Casting.h"
     17 #include "mozilla/Span.h"
     18 #include "mozilla/ipc/TransportSecurityInfoUtils.h"
     19 #include "mozilla/net/DNS.h"
     20 #include "mozpkix/Result.h"
     21 #include "mozpkix/pkixnss.h"
     22 #include "mozpkix/pkixtypes.h"
     23 #include "mozpkix/pkixutil.h"
     24 #include "nsArray.h"
     25 #include "nsCOMPtr.h"
     26 #include "nsIClassInfoImpl.h"
     27 #include "nsIObjectInputStream.h"
     28 #include "nsIObjectOutputStream.h"
     29 #include "nsIX509Cert.h"
     30 #include "nsNSSCertHelper.h"
     31 #include "nsNSSCertTrust.h"
     32 #include "nsPK11TokenDB.h"
     33 #include "nsPKCS12Blob.h"
     34 #include "nsProxyRelease.h"
     35 #include "nsReadableUtils.h"
     36 #include "nsString.h"
     37 #include "nsThreadUtils.h"
     38 #include "nsUnicharUtils.h"
     39 #include "nspr.h"
     40 #include "prerror.h"
     41 #include "secasn1.h"
     42 #include "secder.h"
     43 #include "secerr.h"
     44 #include "ssl.h"
     45 
     46 #ifdef XP_WIN
     47 #  include <winsock.h>  // for htonl
     48 #endif
     49 
     50 using namespace mozilla;
     51 using namespace mozilla::psm;
     52 
     53 extern LazyLogModule gPIPNSSLog;
     54 
     55 NS_IMPL_ISUPPORTS(nsNSSCertificate, nsIX509Cert, nsISerializable, nsIClassInfo)
     56 
     57 nsNSSCertificate::nsNSSCertificate() : mCert("nsNSSCertificate::mCert") {}
     58 
     59 nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
     60    : mCert("nsNSSCertificate::mCert") {
     61  if (cert) {
     62    mDER.AppendElements(cert->derCert.data, cert->derCert.len);
     63    auto lock = mCert.Lock();
     64    auto& maybeCert = lock.ref();
     65    maybeCert.emplace(UniqueCERTCertificate(CERT_DupCertificate(cert)));
     66  }
     67 }
     68 
     69 nsNSSCertificate::nsNSSCertificate(nsTArray<uint8_t>&& der)
     70    : mDER(std::move(der)), mCert("nsNSSCertificate::mCert") {}
     71 
     72 UniqueCERTCertificate nsNSSCertificate::GetOrInstantiateCert() {
     73  auto lock = mCert.Lock();
     74  auto& maybeCert = lock.ref();
     75  if (maybeCert.isSome()) {
     76    return UniqueCERTCertificate(CERT_DupCertificate((*maybeCert).get()));
     77  }
     78 
     79  if (!EnsureNSSInitializedChromeOrContent()) {
     80    return nullptr;
     81  }
     82 
     83  SECItem derItem = {siBuffer, mDER.Elements(),
     84                     static_cast<unsigned int>(mDER.Length())};
     85  UniqueCERTCertificate cert(CERT_NewTempCertificate(
     86      CERT_GetDefaultCertDB(), &derItem, nullptr, false, true));
     87  if (!cert) {
     88    return nullptr;
     89  }
     90  maybeCert.emplace(std::move(cert));
     91 
     92  return UniqueCERTCertificate(CERT_DupCertificate((*maybeCert).get()));
     93 }
     94 
     95 nsresult nsNSSCertificate::GetCertType(uint32_t* aCertType) {
     96  UniqueCERTCertificate cert(GetOrInstantiateCert());
     97  if (!cert) {
     98    return NS_ERROR_FAILURE;
     99  }
    100  CERTCertTrust certTrust{0, 0, 0};
    101  // If there is no stored trust information, CERT_GetCertTrust will return
    102  // SECFailure. This isn't a failure. In this case, all trust bits will remain
    103  // unset.
    104  (void)CERT_GetCertTrust(cert.get(), &certTrust);
    105  nsNSSCertTrust trust(&certTrust);
    106  if (cert->nickname && trust.HasAnyUser()) {
    107    *aCertType = nsIX509Cert::USER_CERT;
    108    return NS_OK;
    109  }
    110  if (trust.HasAnyCA()) {
    111    *aCertType = nsIX509Cert::CA_CERT;
    112    return NS_OK;
    113  }
    114  if (trust.HasPeer(true, false)) {
    115    *aCertType = nsIX509Cert::SERVER_CERT;
    116    return NS_OK;
    117  }
    118  if (trust.HasPeer(false, true) && cert->emailAddr) {
    119    *aCertType = nsIX509Cert::EMAIL_CERT;
    120    return NS_OK;
    121  }
    122  if (CERT_IsCACert(cert.get(), nullptr)) {
    123    *aCertType = nsIX509Cert::CA_CERT;
    124    return NS_OK;
    125  }
    126  if (cert->emailAddr) {
    127    *aCertType = nsIX509Cert::EMAIL_CERT;
    128    return NS_OK;
    129  }
    130  *aCertType = nsIX509Cert::UNKNOWN_CERT;
    131  return NS_OK;
    132 }
    133 
    134 NS_IMETHODIMP
    135 nsNSSCertificate::GetDbKey(nsACString& aDbKey) {
    136  static_assert(sizeof(uint64_t) == 8, "type size consistency check");
    137  static_assert(sizeof(uint32_t) == 4, "type size consistency check");
    138 
    139  pkix::Input certInput;
    140  pkix::Result result = certInput.Init(mDER.Elements(), mDER.Length());
    141  if (result != pkix::Result::Success) {
    142    return NS_ERROR_INVALID_ARG;
    143  }
    144  // NB: since we're not building a trust path, the endEntityOrCA parameter is
    145  // irrelevant.
    146  pkix::BackCert cert(certInput, pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
    147  result = cert.Init();
    148  if (result != pkix::Result::Success) {
    149    return NS_ERROR_INVALID_ARG;
    150  }
    151 
    152  // The format of the key is the base64 encoding of the following:
    153  // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
    154  //                        never implemented)
    155  // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
    156  //                        never implemented)
    157  // 4 bytes: <serial number length in big-endian order>
    158  // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
    159  // n bytes: <bytes of serial number>
    160  // m bytes: <DER-encoded issuer distinguished name>
    161  nsAutoCString buf;
    162  const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
    163  buf.Append(leadingZeroes, sizeof(leadingZeroes));
    164  uint32_t serialNumberLen = htonl(cert.GetSerialNumber().GetLength());
    165  buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
    166             sizeof(uint32_t));
    167  uint32_t issuerLen = htonl(cert.GetIssuer().GetLength());
    168  buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
    169             sizeof(uint32_t));
    170  buf.Append(BitwiseCast<const char*, const unsigned char*>(
    171                 cert.GetSerialNumber().UnsafeGetData()),
    172             cert.GetSerialNumber().GetLength());
    173  buf.Append(BitwiseCast<const char*, const unsigned char*>(
    174                 cert.GetIssuer().UnsafeGetData()),
    175             cert.GetIssuer().GetLength());
    176 
    177  return Base64Encode(buf, aDbKey);
    178 }
    179 
    180 NS_IMETHODIMP
    181 nsNSSCertificate::GetDisplayName(nsAString& aDisplayName) {
    182  aDisplayName.Truncate();
    183 
    184  UniqueCERTCertificate cert(GetOrInstantiateCert());
    185  if (!cert) {
    186    return NS_ERROR_FAILURE;
    187  }
    188 
    189  UniquePORTString commonName(CERT_GetCommonName(&cert->subject));
    190  UniquePORTString organizationalUnitName(CERT_GetOrgUnitName(&cert->subject));
    191  UniquePORTString organizationName(CERT_GetOrgName(&cert->subject));
    192 
    193  // Only use the nickname for built-in roots where we already have a hard-coded
    194  // reasonable display name (unfortunately we have to strip off the leading
    195  // slot identifier followed by a ':'). Otherwise, attempt to use the following
    196  // in order:
    197  //  - the common name, if present
    198  //  - an organizational unit name, if present
    199  //  - an organization name, if present
    200  //  - the entire subject distinguished name, if non-empty
    201  //  - an email address, if one can be found
    202  // In the unlikely event that none of these fields are present and non-empty
    203  // (the subject really shouldn't be empty), an empty string is returned.
    204  nsAutoCString builtInRootNickname;
    205  nsAutoCString fullNickname(cert->nickname);
    206  static const nsLiteralCString kBuiltinObjectTokenPrefix =
    207      "Builtin Object Token:"_ns;
    208  if (StringBeginsWith(fullNickname, kBuiltinObjectTokenPrefix)) {
    209    // Substring will gracefully handle the case where index is the last
    210    // character in the string (that is, if the nickname is just
    211    // "Builtin Object Token:"). In that case, we'll get an empty string.
    212    builtInRootNickname =
    213        Substring(fullNickname, kBuiltinObjectTokenPrefix.Length());
    214  }
    215  const char* nameOptions[] = {builtInRootNickname.get(),
    216                               commonName.get(),
    217                               organizationalUnitName.get(),
    218                               organizationName.get(),
    219                               cert->subjectName,
    220                               cert->emailAddr};
    221 
    222  for (auto nameOption : nameOptions) {
    223    if (nameOption) {
    224      size_t len = strlen(nameOption);
    225      if (len > 0) {
    226        LossyUTF8ToUTF16(nameOption, len, aDisplayName);
    227        return NS_OK;
    228      }
    229    }
    230  }
    231 
    232  return NS_OK;
    233 }
    234 
    235 NS_IMETHODIMP
    236 nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress) {
    237  UniqueCERTCertificate cert(GetOrInstantiateCert());
    238  if (!cert) {
    239    return NS_ERROR_FAILURE;
    240  }
    241  if (cert->emailAddr) {
    242    CopyUTF8toUTF16(MakeStringSpan(cert->emailAddr), aEmailAddress);
    243  } else {
    244    GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
    245  }
    246  return NS_OK;
    247 }
    248 
    249 NS_IMETHODIMP
    250 nsNSSCertificate::GetEmailAddresses(nsTArray<nsString>& aAddresses) {
    251  UniqueCERTCertificate cert(GetOrInstantiateCert());
    252  if (!cert) {
    253    return NS_ERROR_FAILURE;
    254  }
    255  uint32_t length = 0;
    256  for (const char* aAddr = CERT_GetFirstEmailAddress(cert.get()); aAddr;
    257       aAddr = CERT_GetNextEmailAddress(cert.get(), aAddr)) {
    258    ++(length);
    259  }
    260 
    261  aAddresses.SetCapacity(length);
    262 
    263  for (const char* aAddr = CERT_GetFirstEmailAddress(cert.get()); aAddr;
    264       aAddr = CERT_GetNextEmailAddress(cert.get(), aAddr)) {
    265    CopyASCIItoUTF16(MakeStringSpan(aAddr), *aAddresses.AppendElement());
    266  }
    267 
    268  return NS_OK;
    269 }
    270 
    271 NS_IMETHODIMP
    272 nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
    273                                       bool* result) {
    274  NS_ENSURE_ARG(result);
    275  *result = false;
    276 
    277  UniqueCERTCertificate cert(GetOrInstantiateCert());
    278  if (!cert) {
    279    return NS_ERROR_FAILURE;
    280  }
    281  for (const char* aAddr = CERT_GetFirstEmailAddress(cert.get()); aAddr;
    282       aAddr = CERT_GetNextEmailAddress(cert.get(), aAddr)) {
    283    nsAutoString certAddr;
    284    LossyUTF8ToUTF16(aAddr, strlen(aAddr), certAddr);
    285    ToLowerCase(certAddr);
    286 
    287    nsAutoString testAddr(aEmailAddress);
    288    ToLowerCase(testAddr);
    289 
    290    if (certAddr == testAddr) {
    291      *result = true;
    292      break;
    293    }
    294  }
    295 
    296  return NS_OK;
    297 }
    298 
    299 NS_IMETHODIMP
    300 nsNSSCertificate::GetCommonName(nsAString& aCommonName) {
    301  aCommonName.Truncate();
    302  UniqueCERTCertificate cert(GetOrInstantiateCert());
    303  if (!cert) {
    304    return NS_ERROR_FAILURE;
    305  }
    306  UniquePORTString commonName(CERT_GetCommonName(&cert->subject));
    307  if (commonName) {
    308    LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
    309  }
    310  return NS_OK;
    311 }
    312 
    313 NS_IMETHODIMP
    314 nsNSSCertificate::GetOrganization(nsAString& aOrganization) {
    315  aOrganization.Truncate();
    316  UniqueCERTCertificate cert(GetOrInstantiateCert());
    317  if (!cert) {
    318    return NS_ERROR_FAILURE;
    319  }
    320  UniquePORTString organization(CERT_GetOrgName(&cert->subject));
    321  if (organization) {
    322    LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
    323                     aOrganization);
    324  }
    325  return NS_OK;
    326 }
    327 
    328 NS_IMETHODIMP
    329 nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName) {
    330  aCommonName.Truncate();
    331  UniqueCERTCertificate cert(GetOrInstantiateCert());
    332  if (!cert) {
    333    return NS_ERROR_FAILURE;
    334  }
    335  UniquePORTString commonName(CERT_GetCommonName(&cert->issuer));
    336  if (commonName) {
    337    LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
    338  }
    339  return NS_OK;
    340 }
    341 
    342 NS_IMETHODIMP
    343 nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization) {
    344  aOrganization.Truncate();
    345  UniqueCERTCertificate cert(GetOrInstantiateCert());
    346  if (!cert) {
    347    return NS_ERROR_FAILURE;
    348  }
    349  UniquePORTString organization(CERT_GetOrgName(&cert->issuer));
    350  if (organization) {
    351    LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
    352                     aOrganization);
    353  }
    354  return NS_OK;
    355 }
    356 
    357 NS_IMETHODIMP
    358 nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit) {
    359  aOrganizationUnit.Truncate();
    360  UniqueCERTCertificate cert(GetOrInstantiateCert());
    361  if (!cert) {
    362    return NS_ERROR_FAILURE;
    363  }
    364  UniquePORTString organizationUnit(CERT_GetOrgUnitName(&cert->issuer));
    365  if (organizationUnit) {
    366    LossyUTF8ToUTF16(organizationUnit.get(), strlen(organizationUnit.get()),
    367                     aOrganizationUnit);
    368  }
    369  return NS_OK;
    370 }
    371 
    372 NS_IMETHODIMP
    373 nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit) {
    374  aOrganizationalUnit.Truncate();
    375  UniqueCERTCertificate cert(GetOrInstantiateCert());
    376  if (!cert) {
    377    return NS_ERROR_FAILURE;
    378  }
    379  UniquePORTString orgunit(CERT_GetOrgUnitName(&cert->subject));
    380  if (orgunit) {
    381    LossyUTF8ToUTF16(orgunit.get(), strlen(orgunit.get()), aOrganizationalUnit);
    382  }
    383  return NS_OK;
    384 }
    385 
    386 NS_IMETHODIMP
    387 nsNSSCertificate::GetSubjectName(nsAString& _subjectName) {
    388  _subjectName.Truncate();
    389  UniqueCERTCertificate cert(GetOrInstantiateCert());
    390  if (!cert) {
    391    return NS_ERROR_FAILURE;
    392  }
    393  if (cert->subjectName) {
    394    LossyUTF8ToUTF16(cert->subjectName, strlen(cert->subjectName),
    395                     _subjectName);
    396  }
    397  return NS_OK;
    398 }
    399 
    400 NS_IMETHODIMP
    401 nsNSSCertificate::GetIssuerName(nsAString& _issuerName) {
    402  _issuerName.Truncate();
    403  UniqueCERTCertificate cert(GetOrInstantiateCert());
    404  if (!cert) {
    405    return NS_ERROR_FAILURE;
    406  }
    407  if (cert->issuerName) {
    408    LossyUTF8ToUTF16(cert->issuerName, strlen(cert->issuerName), _issuerName);
    409  }
    410  return NS_OK;
    411 }
    412 
    413 NS_IMETHODIMP
    414 nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber) {
    415  _serialNumber.Truncate();
    416  UniqueCERTCertificate cert(GetOrInstantiateCert());
    417  if (!cert) {
    418    return NS_ERROR_FAILURE;
    419  }
    420  UniquePORTString tmpstr(
    421      CERT_Hexify(&cert->serialNumber, true /* use colon delimiters */));
    422  if (tmpstr) {
    423    _serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
    424    return NS_OK;
    425  }
    426  return NS_ERROR_FAILURE;
    427 }
    428 
    429 nsresult nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint,
    430                                              SECOidTag aHashAlg) {
    431  aFingerprint.Truncate();
    432 
    433  if (!EnsureNSSInitializedChromeOrContent()) {
    434    return NS_ERROR_NOT_AVAILABLE;
    435  }
    436 
    437  nsTArray<uint8_t> digestArray;
    438  nsresult rv =
    439      Digest::DigestBuf(aHashAlg, mDER.Elements(), mDER.Length(), digestArray);
    440  if (NS_FAILED(rv)) {
    441    return rv;
    442  }
    443  SECItem digestItem = {siBuffer, digestArray.Elements(),
    444                        static_cast<unsigned int>(digestArray.Length())};
    445 
    446  UniquePORTString fpStr(
    447      CERT_Hexify(&digestItem, true /* use colon delimiters */));
    448  if (!fpStr) {
    449    return NS_ERROR_FAILURE;
    450  }
    451 
    452  aFingerprint.AssignASCII(fpStr.get());
    453  return NS_OK;
    454 }
    455 
    456 NS_IMETHODIMP
    457 nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint) {
    458  return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
    459 }
    460 
    461 NS_IMETHODIMP
    462 nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint) {
    463  return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
    464 }
    465 
    466 NS_IMETHODIMP
    467 nsNSSCertificate::GetTokenName(nsAString& aTokenName) {
    468  UniqueCERTCertificate cert(GetOrInstantiateCert());
    469  if (!cert) {
    470    return NS_ERROR_FAILURE;
    471  }
    472  UniquePK11SlotInfo internalSlot(PK11_GetInternalSlot());
    473  if (!internalSlot) {
    474    return NS_ERROR_FAILURE;
    475  }
    476  nsCOMPtr<nsIPK11Token> token(
    477      new nsPK11Token(cert->slot ? cert->slot : internalSlot.get()));
    478  nsAutoCString tmp;
    479  nsresult rv = token->GetTokenName(tmp);
    480  if (NS_FAILED(rv)) {
    481    return rv;
    482  }
    483  aTokenName.Assign(NS_ConvertUTF8toUTF16(tmp));
    484  return NS_OK;
    485 }
    486 
    487 NS_IMETHODIMP
    488 nsNSSCertificate::GetSubjectPublicKeyInfo(nsTArray<uint8_t>& aSPKI) {
    489  aSPKI.Clear();
    490 
    491  pkix::Input certInput;
    492  pkix::Result result = certInput.Init(mDER.Elements(), mDER.Length());
    493  if (result != pkix::Result::Success) {
    494    return NS_ERROR_INVALID_ARG;
    495  }
    496  // NB: since we're not building a trust path, the endEntityOrCA parameter is
    497  // irrelevant.
    498  pkix::BackCert cert(certInput, pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
    499  result = cert.Init();
    500  if (result != pkix::Result::Success) {
    501    return NS_ERROR_INVALID_ARG;
    502  }
    503  pkix::Input spki = cert.GetSubjectPublicKeyInfo();
    504  aSPKI.AppendElements(spki.UnsafeGetData(), spki.GetLength());
    505  return NS_OK;
    506 }
    507 
    508 NS_IMETHODIMP
    509 nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(
    510    nsACString& aSha256SPKIDigest) {
    511  aSha256SPKIDigest.Truncate();
    512 
    513  if (!EnsureNSSInitializedChromeOrContent()) {
    514    return NS_ERROR_NOT_AVAILABLE;
    515  }
    516 
    517  pkix::Input certInput;
    518  pkix::Result result = certInput.Init(mDER.Elements(), mDER.Length());
    519  if (result != pkix::Result::Success) {
    520    return NS_ERROR_INVALID_ARG;
    521  }
    522  // NB: since we're not building a trust path, the endEntityOrCA parameter is
    523  // irrelevant.
    524  pkix::BackCert cert(certInput, pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
    525  result = cert.Init();
    526  if (result != pkix::Result::Success) {
    527    return NS_ERROR_INVALID_ARG;
    528  }
    529  pkix::Input derPublicKey = cert.GetSubjectPublicKeyInfo();
    530  nsTArray<uint8_t> digestArray;
    531  nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, derPublicKey.UnsafeGetData(),
    532                                  derPublicKey.GetLength(), digestArray);
    533  if (NS_FAILED(rv)) {
    534    return rv;
    535  }
    536  rv = Base64Encode(nsDependentCSubstring(
    537                        reinterpret_cast<const char*>(digestArray.Elements()),
    538                        digestArray.Length()),
    539                    aSha256SPKIDigest);
    540  if (NS_WARN_IF(NS_FAILED(rv))) {
    541    return rv;
    542  }
    543  return NS_OK;
    544 }
    545 
    546 NS_IMETHODIMP
    547 nsNSSCertificate::GetRawDER(nsTArray<uint8_t>& aArray) {
    548  aArray.SetLength(mDER.Length());
    549  memcpy(aArray.Elements(), mDER.Elements(), mDER.Length());
    550  return NS_OK;
    551 }
    552 
    553 NS_IMETHODIMP
    554 nsNSSCertificate::GetBase64DERString(nsACString& base64DERString) {
    555  nsDependentCSubstring derString(
    556      reinterpret_cast<const char*>(mDER.Elements()), mDER.Length());
    557  nsresult rv = Base64Encode(derString, base64DERString);
    558  if (NS_FAILED(rv)) {
    559    return rv;
    560  }
    561  return NS_OK;
    562 }
    563 
    564 CERTCertificate* nsNSSCertificate::GetCert() {
    565  UniqueCERTCertificate cert(GetOrInstantiateCert());
    566  return cert.release();  // caller takes ownership
    567 }
    568 
    569 NS_IMETHODIMP
    570 nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity) {
    571  NS_ENSURE_ARG(aValidity);
    572  pkix::Input certInput;
    573  pkix::Result rv = certInput.Init(mDER.Elements(), mDER.Length());
    574  if (rv != pkix::Success) {
    575    return NS_ERROR_FAILURE;
    576  }
    577  nsCOMPtr<nsIX509CertValidity> validity = new X509CertValidity(certInput);
    578  validity.forget(aValidity);
    579  return NS_OK;
    580 }
    581 
    582 // NB: Any updates (except disk-only fields) must be kept in sync with
    583 //     |SerializeToIPC|.
    584 NS_IMETHODIMP
    585 nsNSSCertificate::Write(nsIObjectOutputStream* aStream) {
    586  // This field used to be the cached EV status, but it is no longer necessary.
    587  nsresult rv = aStream->Write32(0);
    588  if (NS_FAILED(rv)) {
    589    return rv;
    590  }
    591  rv = aStream->Write32(mDER.Length());
    592  if (NS_FAILED(rv)) {
    593    return rv;
    594  }
    595  return aStream->WriteBytes(Span(mDER));
    596 }
    597 
    598 // NB: Any updates (except disk-only fields) must be kept in sync with
    599 //     |DeserializeFromIPC|.
    600 NS_IMETHODIMP
    601 nsNSSCertificate::Read(nsIObjectInputStream* aStream) {
    602  auto lock = mCert.Lock();
    603  auto& maybeCert = lock.ref();
    604  if (!mDER.IsEmpty() || maybeCert.isSome()) {
    605    return NS_ERROR_ALREADY_INITIALIZED;
    606  }
    607 
    608  // This field is no longer used.
    609  uint32_t unusedCachedEVStatus;
    610  nsresult rv = aStream->Read32(&unusedCachedEVStatus);
    611  if (NS_FAILED(rv)) {
    612    return rv;
    613  }
    614 
    615  uint32_t len;
    616  rv = aStream->Read32(&len);
    617  if (NS_FAILED(rv)) {
    618    return rv;
    619  }
    620 
    621  rv = aStream->ReadByteArray(len, mDER);
    622  if (NS_FAILED(rv)) {
    623    return rv;
    624  }
    625  return NS_OK;
    626 }
    627 
    628 void nsNSSCertificate::SerializeToIPC(IPC::MessageWriter* aWriter) {
    629  bool hasCert = !mDER.IsEmpty();
    630  WriteParam(aWriter, hasCert);
    631 
    632  if (!hasCert) {
    633    return;
    634  }
    635 
    636  WriteParam(aWriter, mDER);
    637 }
    638 
    639 bool nsNSSCertificate::DeserializeFromIPC(IPC::MessageReader* aReader) {
    640  auto lock = mCert.Lock();
    641  auto& maybeCert = lock.ref();
    642  if (!mDER.IsEmpty() || maybeCert.isSome()) {
    643    return false;
    644  }
    645 
    646  bool hasCert = false;
    647  if (!ReadParam(aReader, &hasCert)) {
    648    return false;
    649  }
    650 
    651  if (!hasCert) {
    652    return true;
    653  }
    654 
    655  if (!ReadParam(aReader, &mDER)) {
    656    return false;
    657  }
    658  return true;
    659 }
    660 
    661 NS_IMETHODIMP
    662 nsNSSCertificate::GetInterfaces(nsTArray<nsIID>& array) {
    663  array.Clear();
    664  return NS_OK;
    665 }
    666 
    667 NS_IMETHODIMP
    668 nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval) {
    669  *_retval = nullptr;
    670  return NS_OK;
    671 }
    672 
    673 NS_IMETHODIMP
    674 nsNSSCertificate::GetContractID(nsACString& aContractID) {
    675  aContractID.SetIsVoid(true);
    676  return NS_OK;
    677 }
    678 
    679 NS_IMETHODIMP
    680 nsNSSCertificate::GetClassDescription(nsACString& aClassDescription) {
    681  aClassDescription.SetIsVoid(true);
    682  return NS_OK;
    683 }
    684 
    685 NS_IMETHODIMP
    686 nsNSSCertificate::GetClassID(nsCID** aClassID) {
    687  *aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID));
    688  return GetClassIDNoAlloc(*aClassID);
    689 }
    690 
    691 NS_IMETHODIMP
    692 nsNSSCertificate::GetFlags(uint32_t* aFlags) {
    693  *aFlags = nsIClassInfo::THREADSAFE;
    694  return NS_OK;
    695 }
    696 
    697 NS_IMETHODIMP
    698 nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
    699  static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
    700 
    701  *aClassIDNoAlloc = kNSSCertificateCID;
    702  return NS_OK;
    703 }