Coverage Report

Created: 2018-09-25 14:53

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