Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsCertOverrideService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsCertOverrideService.h"
8
9
#include "NSSCertDBTrustDomain.h"
10
#include "ScopedNSSTypes.h"
11
#include "SharedSSLState.h"
12
#include "mozilla/Assertions.h"
13
#include "mozilla/Telemetry.h"
14
#include "mozilla/Unused.h"
15
#include "nsAppDirectoryServiceDefs.h"
16
#include "nsCRT.h"
17
#include "nsILineInputStream.h"
18
#include "nsIObserver.h"
19
#include "nsIObserverService.h"
20
#include "nsIOutputStream.h"
21
#include "nsISafeOutputStream.h"
22
#include "nsIX509Cert.h"
23
#include "nsNSSCertHelper.h"
24
#include "nsNSSCertificate.h"
25
#include "nsNSSComponent.h"
26
#include "nsNetUtil.h"
27
#include "nsStreamUtils.h"
28
#include "nsStringBuffer.h"
29
#include "nsThreadUtils.h"
30
#include "ssl.h" // For SSL_ClearSessionCache
31
32
using namespace mozilla;
33
using namespace mozilla::psm;
34
35
#define CERT_OVERRIDE_FILE_NAME "cert_override.txt"
36
37
void
38
nsCertOverride::convertBitsToString(OverrideBits ob, /*out*/ nsACString& str)
39
0
{
40
0
  str.Truncate();
41
0
42
0
  if (ob & OverrideBits::Mismatch) {
43
0
    str.Append('M');
44
0
  }
45
0
46
0
  if (ob & OverrideBits::Untrusted) {
47
0
    str.Append('U');
48
0
  }
49
0
50
0
  if (ob & OverrideBits::Time) {
51
0
    str.Append('T');
52
0
  }
53
0
}
54
55
void
56
nsCertOverride::convertStringToBits(const nsACString& str,
57
                            /*out*/ OverrideBits& ob)
58
0
{
59
0
  ob = OverrideBits::None;
60
0
61
0
  for (uint32_t i = 0; i < str.Length(); i++) {
62
0
    switch (str.CharAt(i)) {
63
0
      case 'm':
64
0
      case 'M':
65
0
        ob |= OverrideBits::Mismatch;
66
0
        break;
67
0
68
0
      case 'u':
69
0
      case 'U':
70
0
        ob |= OverrideBits::Untrusted;
71
0
        break;
72
0
73
0
      case 't':
74
0
      case 'T':
75
0
        ob |= OverrideBits::Time;
76
0
        break;
77
0
78
0
      default:
79
0
        break;
80
0
    }
81
0
  }
82
0
}
83
84
NS_IMPL_ISUPPORTS(nsCertOverrideService,
85
                  nsICertOverrideService,
86
                  nsIObserver,
87
                  nsISupportsWeakReference)
88
89
nsCertOverrideService::nsCertOverrideService()
90
  : mMutex("nsCertOverrideService.mutex")
91
0
{
92
0
}
93
94
nsCertOverrideService::~nsCertOverrideService()
95
0
{
96
0
}
97
98
nsresult
99
nsCertOverrideService::Init()
100
0
{
101
0
  if (!NS_IsMainThread()) {
102
0
    MOZ_ASSERT_UNREACHABLE("nsCertOverrideService initialized off main thread");
103
0
    return NS_ERROR_NOT_SAME_THREAD;
104
0
  }
105
0
106
0
  nsCOMPtr<nsIObserverService> observerService =
107
0
      mozilla::services::GetObserverService();
108
0
109
0
  // If we cannot add ourselves as a profile change observer, then we will not
110
0
  // attempt to read/write any settings file. Otherwise, we would end up
111
0
  // reading/writing the wrong settings file after a profile change.
112
0
  if (observerService) {
113
0
    observerService->AddObserver(this, "profile-before-change", true);
114
0
    observerService->AddObserver(this, "profile-do-change", true);
115
0
    // simulate a profile change so we read the current profile's settings file
116
0
    Observe(nullptr, "profile-do-change", nullptr);
117
0
  }
118
0
119
0
  SharedSSLState::NoteCertOverrideServiceInstantiated();
120
0
  return NS_OK;
121
0
}
122
123
NS_IMETHODIMP
124
nsCertOverrideService::Observe(nsISupports     *,
125
                               const char      *aTopic,
126
                               const char16_t *aData)
127
0
{
128
0
  // check the topic
129
0
  if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
130
0
    // The profile is about to change,
131
0
    // or is going away because the application is shutting down.
132
0
133
0
    RemoveAllFromMemory();
134
0
  } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
135
0
    // The profile has already changed.
136
0
    // Now read from the new profile location.
137
0
    // we also need to update the cached file location
138
0
139
0
    MutexAutoLock lock(mMutex);
140
0
141
0
    nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
142
0
    if (NS_SUCCEEDED(rv)) {
143
0
      mSettingsFile->AppendNative(NS_LITERAL_CSTRING(CERT_OVERRIDE_FILE_NAME));
144
0
    } else {
145
0
      mSettingsFile = nullptr;
146
0
    }
147
0
    Read(lock);
148
0
    CountPermanentOverrideTelemetry(lock);
149
0
  }
150
0
151
0
  return NS_OK;
152
0
}
153
154
void
155
nsCertOverrideService::RemoveAllFromMemory()
156
0
{
157
0
  MutexAutoLock lock(mMutex);
158
0
  mSettingsTable.Clear();
159
0
}
160
161
void
162
nsCertOverrideService::RemoveAllTemporaryOverrides()
163
0
{
164
0
  MutexAutoLock lock(mMutex);
165
0
  for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
166
0
    nsCertOverrideEntry *entry = iter.Get();
167
0
    if (entry->mSettings.mIsTemporary) {
168
0
      entry->mSettings.mCert = nullptr;
169
0
      iter.Remove();
170
0
    }
171
0
  }
172
0
  // no need to write, as temporaries are never written to disk
173
0
}
174
175
nsresult
176
nsCertOverrideService::Read(const MutexAutoLock& aProofOfLock)
177
0
{
178
0
  // If we don't have a profile, then we won't try to read any settings file.
179
0
  if (!mSettingsFile)
180
0
    return NS_OK;
181
0
182
0
  nsresult rv;
183
0
  nsCOMPtr<nsIInputStream> fileInputStream;
184
0
  rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mSettingsFile);
185
0
  if (NS_FAILED(rv)) {
186
0
    return rv;
187
0
  }
188
0
189
0
  nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
190
0
  if (NS_FAILED(rv)) {
191
0
    return rv;
192
0
  }
193
0
194
0
  nsAutoCString buffer;
195
0
  bool isMore = true;
196
0
  int32_t hostIndex = 0, algoIndex, fingerprintIndex, overrideBitsIndex, dbKeyIndex;
197
0
198
0
  /* file format is:
199
0
   *
200
0
   * host:port \t fingerprint-algorithm \t fingerprint \t override-mask \t dbKey
201
0
   *
202
0
   *   where override-mask is a sequence of characters,
203
0
   *     M meaning hostname-Mismatch-override
204
0
   *     U meaning Untrusted-override
205
0
   *     T meaning Time-error-override (expired/not yet valid)
206
0
   *
207
0
   * if this format isn't respected we move onto the next line in the file.
208
0
   */
209
0
210
0
  while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
211
0
    if (buffer.IsEmpty() || buffer.First() == '#') {
212
0
      continue;
213
0
    }
214
0
215
0
    // this is a cheap, cheesy way of parsing a tab-delimited line into
216
0
    // string indexes, which can be lopped off into substrings. just for
217
0
    // purposes of obfuscation, it also checks that each token was found.
218
0
    // todo: use iterators?
219
0
    if ((algoIndex         = buffer.FindChar('\t', hostIndex)         + 1) == 0 ||
220
0
        (fingerprintIndex  = buffer.FindChar('\t', algoIndex)         + 1) == 0 ||
221
0
        (overrideBitsIndex = buffer.FindChar('\t', fingerprintIndex)  + 1) == 0 ||
222
0
        (dbKeyIndex        = buffer.FindChar('\t', overrideBitsIndex) + 1) == 0) {
223
0
      continue;
224
0
    }
225
0
226
0
    const nsACString& tmp = Substring(buffer, hostIndex, algoIndex - hostIndex - 1);
227
0
    // We just ignore the algorithm string.
228
0
    const nsACString& fingerprint = Substring(buffer, fingerprintIndex, overrideBitsIndex - fingerprintIndex - 1);
229
0
    const nsACString& bits_string = Substring(buffer, overrideBitsIndex, dbKeyIndex - overrideBitsIndex - 1);
230
0
    const nsACString& db_key = Substring(buffer, dbKeyIndex, buffer.Length() - dbKeyIndex);
231
0
232
0
    nsAutoCString host(tmp);
233
0
    nsCertOverride::OverrideBits bits;
234
0
    nsCertOverride::convertStringToBits(bits_string, bits);
235
0
236
0
    int32_t port;
237
0
    int32_t portIndex = host.RFindChar(':');
238
0
    if (portIndex == kNotFound)
239
0
      continue; // Ignore broken entries
240
0
241
0
    nsresult portParseError;
242
0
    nsAutoCString portString(Substring(host, portIndex+1));
243
0
    port = portString.ToInteger(&portParseError);
244
0
    if (NS_FAILED(portParseError))
245
0
      continue; // Ignore broken entries
246
0
247
0
    host.Truncate(portIndex);
248
0
249
0
    AddEntryToList(host, port,
250
0
                   nullptr, // don't have the cert
251
0
                   false, // not temporary
252
0
                   fingerprint, bits, db_key, aProofOfLock);
253
0
  }
254
0
255
0
  return NS_OK;
256
0
}
257
258
static const char sSHA256OIDString[] = "OID.2.16.840.1.101.3.4.2.1";
259
nsresult
260
nsCertOverrideService::Write(const MutexAutoLock& aProofOfLock)
261
0
{
262
0
  // If we don't have any profile, then we won't try to write any file
263
0
  if (!mSettingsFile) {
264
0
    return NS_OK;
265
0
  }
266
0
267
0
  nsresult rv;
268
0
  nsCOMPtr<nsIOutputStream> fileOutputStream;
269
0
  rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
270
0
                                       mSettingsFile,
271
0
                                       -1,
272
0
                                       0600);
273
0
  if (NS_FAILED(rv)) {
274
0
    NS_ERROR("failed to open cert_warn_settings.txt for writing");
275
0
    return rv;
276
0
  }
277
0
278
0
  // get a buffered output stream 4096 bytes big, to optimize writes
279
0
  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
280
0
  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
281
0
                                  fileOutputStream.forget(), 4096);
282
0
  if (NS_FAILED(rv)) {
283
0
    return rv;
284
0
  }
285
0
286
0
  static const char kHeader[] =
287
0
      "# PSM Certificate Override Settings file" NS_LINEBREAK
288
0
      "# This is a generated file!  Do not edit." NS_LINEBREAK;
289
0
290
0
  /* see ::Read for file format */
291
0
292
0
  uint32_t unused;
293
0
  bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &unused);
294
0
295
0
  static const char kTab[] = "\t";
296
0
  for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
297
0
    nsCertOverrideEntry *entry = iter.Get();
298
0
299
0
    const nsCertOverride &settings = entry->mSettings;
300
0
    if (settings.mIsTemporary) {
301
0
      continue;
302
0
    }
303
0
304
0
    nsAutoCString bits_string;
305
0
    nsCertOverride::convertBitsToString(settings.mOverrideBits, bits_string);
306
0
307
0
    bufferedOutputStream->Write(entry->mHostWithPort.get(),
308
0
                                entry->mHostWithPort.Length(), &unused);
309
0
    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &unused);
310
0
    bufferedOutputStream->Write(sSHA256OIDString, sizeof(sSHA256OIDString) - 1,
311
0
                                &unused);
312
0
    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &unused);
313
0
    bufferedOutputStream->Write(settings.mFingerprint.get(),
314
0
                                settings.mFingerprint.Length(), &unused);
315
0
    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &unused);
316
0
    bufferedOutputStream->Write(bits_string.get(),
317
0
                                bits_string.Length(), &unused);
318
0
    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &unused);
319
0
    bufferedOutputStream->Write(settings.mDBKey.get(),
320
0
                                settings.mDBKey.Length(), &unused);
321
0
    bufferedOutputStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &unused);
322
0
  }
323
0
324
0
  // All went ok. Maybe except for problems in Write(), but the stream detects
325
0
  // that for us
326
0
  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
327
0
  MOZ_ASSERT(safeStream, "Expected a safe output stream!");
328
0
  if (safeStream) {
329
0
    rv = safeStream->Finish();
330
0
    if (NS_FAILED(rv)) {
331
0
      NS_WARNING("failed to save cert warn settings file! possible dataloss");
332
0
      return rv;
333
0
    }
334
0
  }
335
0
336
0
  return NS_OK;
337
0
}
338
339
static nsresult
340
GetCertFingerprintByOidTag(nsIX509Cert *aCert,
341
                           SECOidTag aOidTag,
342
                           nsCString &fp)
343
0
{
344
0
  UniqueCERTCertificate nsscert(aCert->GetCert());
345
0
  if (!nsscert) {
346
0
    return NS_ERROR_FAILURE;
347
0
  }
348
0
  return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
349
0
}
350
351
NS_IMETHODIMP
352
nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
353
                                                int32_t aPort,
354
                                                nsIX509Cert* aCert,
355
                                                uint32_t aOverrideBits,
356
                                                bool aTemporary)
357
0
{
358
0
  NS_ENSURE_ARG_POINTER(aCert);
359
0
  if (aHostName.IsEmpty())
360
0
    return NS_ERROR_INVALID_ARG;
361
0
  if (aPort < -1)
362
0
    return NS_ERROR_INVALID_ARG;
363
0
364
0
  UniqueCERTCertificate nsscert(aCert->GetCert());
365
0
  if (!nsscert) {
366
0
    return NS_ERROR_FAILURE;
367
0
  }
368
0
369
0
  nsAutoCString nickname;
370
0
  nsresult rv = DefaultServerNicknameForCert(nsscert.get(), nickname);
371
0
  if (!aTemporary && NS_SUCCEEDED(rv)) {
372
0
    UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
373
0
    if (!slot) {
374
0
      return NS_ERROR_FAILURE;
375
0
    }
376
0
377
0
    // This can fail (for example, if we're in read-only mode). Luckily, we
378
0
    // don't even need it to succeed - we always match on the stored hash of the
379
0
    // certificate rather than the full certificate. It makes the display a bit
380
0
    // less informative (since we won't have a certificate to display), but it's
381
0
    // better than failing the entire operation.
382
0
    Unused << PK11_ImportCert(slot.get(), nsscert.get(), CK_INVALID_HANDLE,
383
0
                              nickname.get(), false);
384
0
  }
385
0
386
0
  nsAutoCString fpStr;
387
0
  rv = GetCertFingerprintByOidTag(nsscert.get(), SEC_OID_SHA256, fpStr);
388
0
  if (NS_FAILED(rv))
389
0
    return rv;
390
0
391
0
  nsAutoCString dbkey;
392
0
  rv = aCert->GetDbKey(dbkey);
393
0
  if (NS_FAILED(rv)) {
394
0
    return rv;
395
0
  }
396
0
397
0
  {
398
0
    MutexAutoLock lock(mMutex);
399
0
    AddEntryToList(aHostName, aPort,
400
0
                   aTemporary ? aCert : nullptr,
401
0
                     // keep a reference to the cert for temporary overrides
402
0
                   aTemporary,
403
0
                   fpStr,
404
0
                   (nsCertOverride::OverrideBits)aOverrideBits,
405
0
                   dbkey, lock);
406
0
    if (!aTemporary) {
407
0
      Write(lock);
408
0
    }
409
0
  }
410
0
411
0
  return NS_OK;
412
0
}
413
414
NS_IMETHODIMP
415
nsCertOverrideService::RememberTemporaryValidityOverrideUsingFingerprint(
416
  const nsACString& aHostName,
417
  int32_t aPort,
418
  const nsACString& aCertFingerprint,
419
  uint32_t aOverrideBits)
420
0
{
421
0
  if(aCertFingerprint.IsEmpty() || aHostName.IsEmpty() || (aPort < -1)) {
422
0
    return NS_ERROR_INVALID_ARG;
423
0
  }
424
0
425
0
  MutexAutoLock lock(mMutex);
426
0
  AddEntryToList(aHostName, aPort,
427
0
                 nullptr, // No cert to keep alive
428
0
                 true, // temporary
429
0
                 aCertFingerprint,
430
0
                 (nsCertOverride::OverrideBits)aOverrideBits,
431
0
                 EmptyCString(),  // dbkey
432
0
                 lock);
433
0
434
0
  return NS_OK;
435
0
}
436
437
NS_IMETHODIMP
438
nsCertOverrideService::HasMatchingOverride(const nsACString & aHostName, int32_t aPort,
439
                                           nsIX509Cert *aCert,
440
                                           uint32_t *aOverrideBits,
441
                                           bool *aIsTemporary,
442
                                           bool *_retval)
443
0
{
444
0
  if (aHostName.IsEmpty())
445
0
    return NS_ERROR_INVALID_ARG;
446
0
  if (aPort < -1)
447
0
    return NS_ERROR_INVALID_ARG;
448
0
449
0
  NS_ENSURE_ARG_POINTER(aCert);
450
0
  NS_ENSURE_ARG_POINTER(aOverrideBits);
451
0
  NS_ENSURE_ARG_POINTER(aIsTemporary);
452
0
  NS_ENSURE_ARG_POINTER(_retval);
453
0
  *_retval = false;
454
0
  *aOverrideBits = static_cast<uint32_t>(nsCertOverride::OverrideBits::None);
455
0
456
0
  nsAutoCString hostPort;
457
0
  GetHostWithPort(aHostName, aPort, hostPort);
458
0
  nsCertOverride settings;
459
0
460
0
  {
461
0
    MutexAutoLock lock(mMutex);
462
0
    nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
463
0
464
0
    if (!entry)
465
0
      return NS_OK;
466
0
467
0
    settings = entry->mSettings; // copy
468
0
  }
469
0
470
0
  *aOverrideBits = static_cast<uint32_t>(settings.mOverrideBits);
471
0
  *aIsTemporary = settings.mIsTemporary;
472
0
473
0
  nsAutoCString fpStr;
474
0
  nsresult rv;
475
0
476
0
  rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256, fpStr);
477
0
  if (NS_FAILED(rv)) {
478
0
    return rv;
479
0
  }
480
0
481
0
  *_retval = settings.mFingerprint.Equals(fpStr);
482
0
  return NS_OK;
483
0
}
484
485
nsresult
486
nsCertOverrideService::AddEntryToList(const nsACString &aHostName, int32_t aPort,
487
                                      nsIX509Cert *aCert,
488
                                      const bool aIsTemporary,
489
                                      const nsACString &fingerprint,
490
                                      nsCertOverride::OverrideBits ob,
491
                                      const nsACString &dbKey,
492
                                      const MutexAutoLock& aProofOfLock)
493
0
{
494
0
  nsAutoCString hostPort;
495
0
  GetHostWithPort(aHostName, aPort, hostPort);
496
0
497
0
  nsCertOverrideEntry *entry = mSettingsTable.PutEntry(hostPort.get());
498
0
499
0
  if (!entry) {
500
0
    NS_ERROR("can't insert a null entry!");
501
0
    return NS_ERROR_OUT_OF_MEMORY;
502
0
  }
503
0
504
0
  entry->mHostWithPort = hostPort;
505
0
506
0
  nsCertOverride &settings = entry->mSettings;
507
0
  settings.mAsciiHost = aHostName;
508
0
  settings.mPort = aPort;
509
0
  settings.mIsTemporary = aIsTemporary;
510
0
  settings.mFingerprint = fingerprint;
511
0
  settings.mOverrideBits = ob;
512
0
  settings.mDBKey = dbKey;
513
0
  // remove whitespace from stored dbKey for backwards compatibility
514
0
  settings.mDBKey.StripWhitespace();
515
0
  settings.mCert = aCert;
516
0
517
0
  return NS_OK;
518
0
}
519
520
NS_IMETHODIMP
521
nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, int32_t aPort)
522
0
{
523
0
  if (!NS_IsMainThread()) {
524
0
    return NS_ERROR_NOT_SAME_THREAD;
525
0
  }
526
0
527
0
  if (aPort == 0 && aHostName.EqualsLiteral("all:temporary-certificates")) {
528
0
    RemoveAllTemporaryOverrides();
529
0
    return NS_OK;
530
0
  }
531
0
  nsAutoCString hostPort;
532
0
  GetHostWithPort(aHostName, aPort, hostPort);
533
0
  {
534
0
    MutexAutoLock lock(mMutex);
535
0
    mSettingsTable.RemoveEntry(hostPort.get());
536
0
    Write(lock);
537
0
  }
538
0
539
0
  nsCOMPtr<nsINSSComponent> nss(do_GetService(PSM_COMPONENT_CONTRACTID));
540
0
  if (nss) {
541
0
    SSL_ClearSessionCache();
542
0
  } else {
543
0
    return NS_ERROR_NOT_AVAILABLE;
544
0
  }
545
0
546
0
  return NS_OK;
547
0
}
548
549
void
550
nsCertOverrideService::CountPermanentOverrideTelemetry(const MutexAutoLock& aProofOfLock)
551
0
{
552
0
  uint32_t overrideCount = 0;
553
0
  for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
554
0
    if (!iter.Get()->mSettings.mIsTemporary) {
555
0
      overrideCount++;
556
0
    }
557
0
  }
558
0
  Telemetry::Accumulate(Telemetry::SSL_PERMANENT_CERT_ERROR_OVERRIDES,
559
0
                        overrideCount);
560
0
}
561
562
static bool
563
matchesDBKey(nsIX509Cert* cert, const nsCString& matchDbKey)
564
0
{
565
0
  nsAutoCString dbKey;
566
0
  nsresult rv = cert->GetDbKey(dbKey);
567
0
  if (NS_FAILED(rv)) {
568
0
    return false;
569
0
  }
570
0
  return dbKey.Equals(matchDbKey);
571
0
}
572
573
NS_IMETHODIMP
574
nsCertOverrideService::IsCertUsedForOverrides(nsIX509Cert *aCert,
575
                                              bool aCheckTemporaries,
576
                                              bool aCheckPermanents,
577
                                              uint32_t *_retval)
578
0
{
579
0
  NS_ENSURE_ARG(aCert);
580
0
  NS_ENSURE_ARG(_retval);
581
0
582
0
  uint32_t counter = 0;
583
0
  {
584
0
    MutexAutoLock lock(mMutex);
585
0
    for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
586
0
      const nsCertOverride &settings = iter.Get()->mSettings;
587
0
588
0
      if (( settings.mIsTemporary && !aCheckTemporaries) ||
589
0
          (!settings.mIsTemporary && !aCheckPermanents)) {
590
0
        continue;
591
0
      }
592
0
593
0
      if (matchesDBKey(aCert, settings.mDBKey)) {
594
0
        nsAutoCString cert_fingerprint;
595
0
        nsresult rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256,
596
0
                                                 cert_fingerprint);
597
0
        if (NS_SUCCEEDED(rv) &&
598
0
            settings.mFingerprint.Equals(cert_fingerprint)) {
599
0
          counter++;
600
0
        }
601
0
      }
602
0
    }
603
0
  }
604
0
  *_retval = counter;
605
0
  return NS_OK;
606
0
}
607
608
nsresult
609
nsCertOverrideService::EnumerateCertOverrides(nsIX509Cert *aCert,
610
                         CertOverrideEnumerator aEnumerator,
611
                         void *aUserData)
612
0
{
613
0
  MutexAutoLock lock(mMutex);
614
0
  for (auto iter = mSettingsTable.Iter(); !iter.Done(); iter.Next()) {
615
0
    const nsCertOverride &settings = iter.Get()->mSettings;
616
0
617
0
    if (!aCert) {
618
0
      aEnumerator(settings, aUserData);
619
0
    } else {
620
0
      if (matchesDBKey(aCert, settings.mDBKey)) {
621
0
        nsAutoCString cert_fingerprint;
622
0
        nsresult rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256,
623
0
                                                 cert_fingerprint);
624
0
        if (NS_SUCCEEDED(rv) &&
625
0
            settings.mFingerprint.Equals(cert_fingerprint)) {
626
0
          aEnumerator(settings, aUserData);
627
0
        }
628
0
      }
629
0
    }
630
0
  }
631
0
  return NS_OK;
632
0
}
633
634
void
635
nsCertOverrideService::GetHostWithPort(const nsACString & aHostName, int32_t aPort, nsACString& _retval)
636
0
{
637
0
  nsAutoCString hostPort(aHostName);
638
0
  if (aPort == -1) {
639
0
    aPort = 443;
640
0
  }
641
0
  if (!hostPort.IsEmpty()) {
642
0
    hostPort.Append(':');
643
0
    hostPort.AppendInt(aPort);
644
0
  }
645
0
  _retval.Assign(hostPort);
646
0
}