Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/CertBlocklist.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; 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 "CertBlocklist.h"
8
9
#include "mozilla/Assertions.h"
10
#include "mozilla/Base64.h"
11
#include "mozilla/Casting.h"
12
#include "mozilla/IntegerPrintfMacros.h"
13
#include "mozilla/Logging.h"
14
#include "mozilla/Preferences.h"
15
#include "mozilla/Unused.h"
16
#include "nsAppDirectoryServiceDefs.h"
17
#include "nsDependentString.h"
18
#include "nsDirectoryServiceUtils.h"
19
#include "nsICryptoHash.h"
20
#include "nsIFileStreams.h"
21
#include "nsILineInputStream.h"
22
#include "nsISafeOutputStream.h"
23
#include "nsIX509Cert.h"
24
#include "nsNetCID.h"
25
#include "nsNetUtil.h"
26
#include "nsPromiseFlatString.h"
27
#include "nsTHashtable.h"
28
#include "nsThreadUtils.h"
29
#include "pkix/Input.h"
30
#include "prtime.h"
31
32
NS_IMPL_ISUPPORTS(CertBlocklist, nsICertBlocklist)
33
34
using namespace mozilla;
35
using namespace mozilla::pkix;
36
37
#define PREF_BACKGROUND_UPDATE_TIMER "app.update.lastUpdateTime.blocklist-background-update-timer"
38
0
#define PREF_BLOCKLIST_ONECRL_CHECKED "services.blocklist.onecrl.checked"
39
0
#define PREF_MAX_STALENESS_IN_SECONDS "security.onecrl.maximum_staleness_in_seconds"
40
41
static LazyLogModule gCertBlockPRLog("CertBlock");
42
43
uint32_t CertBlocklist::sLastBlocklistUpdate = 0U;
44
uint32_t CertBlocklist::sMaxStaleness = 0U;
45
46
CertBlocklistItem::CertBlocklistItem(const uint8_t* DNData,
47
                                     size_t DNLength,
48
                                     const uint8_t* otherData,
49
                                     size_t otherLength,
50
                                     CertBlocklistItemMechanism itemMechanism)
51
  : mIsCurrent(false)
52
  , mItemMechanism(itemMechanism)
53
0
{
54
0
  mDNData = new uint8_t[DNLength];
55
0
  memcpy(mDNData, DNData, DNLength);
56
0
  mDNLength = DNLength;
57
0
58
0
  mOtherData = new uint8_t[otherLength];
59
0
  memcpy(mOtherData, otherData, otherLength);
60
0
  mOtherLength = otherLength;
61
0
}
62
63
CertBlocklistItem::CertBlocklistItem(const CertBlocklistItem& aItem)
64
0
{
65
0
  mDNLength = aItem.mDNLength;
66
0
  mDNData = new uint8_t[mDNLength];
67
0
  memcpy(mDNData, aItem.mDNData, mDNLength);
68
0
69
0
  mOtherLength = aItem.mOtherLength;
70
0
  mOtherData = new uint8_t[mOtherLength];
71
0
  memcpy(mOtherData, aItem.mOtherData, mOtherLength);
72
0
73
0
  mItemMechanism = aItem.mItemMechanism;
74
0
75
0
  mIsCurrent = aItem.mIsCurrent;
76
0
}
77
78
CertBlocklistItem::~CertBlocklistItem()
79
0
{
80
0
  delete[] mDNData;
81
0
  delete[] mOtherData;
82
0
}
83
84
nsresult
85
CertBlocklistItem::ToBase64(nsACString& b64DNOut, nsACString& b64OtherOut)
86
0
{
87
0
  nsDependentCSubstring DNString(BitwiseCast<char*, uint8_t*>(mDNData),
88
0
                                 mDNLength);
89
0
  nsDependentCSubstring otherString(BitwiseCast<char*, uint8_t*>(mOtherData),
90
0
                                    mOtherLength);
91
0
  nsresult rv = Base64Encode(DNString, b64DNOut);
92
0
  if (NS_FAILED(rv)) {
93
0
    return rv;
94
0
  }
95
0
  rv = Base64Encode(otherString, b64OtherOut);
96
0
  return rv;
97
0
}
98
99
bool
100
CertBlocklistItem::operator==(const CertBlocklistItem& aItem) const
101
0
{
102
0
  if (aItem.mItemMechanism != mItemMechanism) {
103
0
    return false;
104
0
  }
105
0
  if (aItem.mDNLength != mDNLength ||
106
0
      aItem.mOtherLength != mOtherLength) {
107
0
    return false;
108
0
  }
109
0
  return memcmp(aItem.mDNData, mDNData, mDNLength) == 0 &&
110
0
         memcmp(aItem.mOtherData, mOtherData, mOtherLength) == 0;
111
0
}
112
113
uint32_t
114
CertBlocklistItem::Hash() const
115
0
{
116
0
  uint32_t hash;
117
0
  // there's no requirement for a serial to be as large as the size of the hash
118
0
  // key; if it's smaller, fall back to the first octet (otherwise, the last
119
0
  // four)
120
0
  if (mItemMechanism == BlockByIssuerAndSerial &&
121
0
      mOtherLength >= sizeof(hash)) {
122
0
    memcpy(&hash, mOtherData + mOtherLength - sizeof(hash), sizeof(hash));
123
0
  } else {
124
0
    hash = *mOtherData;
125
0
  }
126
0
  return hash;
127
0
}
128
129
CertBlocklist::CertBlocklist()
130
  : mMutex("CertBlocklist::mMutex")
131
  , mModified(false)
132
  , mBackingFileIsInitialized(false)
133
  , mBackingFile(nullptr)
134
0
{
135
0
}
136
137
CertBlocklist::~CertBlocklist()
138
0
{
139
0
  Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
140
0
                                  PREF_MAX_STALENESS_IN_SECONDS,
141
0
                                  this);
142
0
  Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
143
0
                                  PREF_BLOCKLIST_ONECRL_CHECKED,
144
0
                                  this);
145
0
}
146
147
nsresult
148
CertBlocklist::Init()
149
0
{
150
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug, ("CertBlocklist::Init"));
151
0
152
0
  // Init must be on main thread for getting the profile directory
153
0
  if (!NS_IsMainThread()) {
154
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
155
0
           ("CertBlocklist::Init - called off main thread"));
156
0
    return NS_ERROR_NOT_SAME_THREAD;
157
0
  }
158
0
159
0
  // Register preference callbacks
160
0
  nsresult rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
161
0
                                            PREF_MAX_STALENESS_IN_SECONDS,
162
0
                                            this);
163
0
  if (NS_FAILED(rv)) {
164
0
    return rv;
165
0
  }
166
0
  rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
167
0
                                            PREF_BLOCKLIST_ONECRL_CHECKED,
168
0
                                            this);
169
0
  if (NS_FAILED(rv)) {
170
0
    return rv;
171
0
  }
172
0
173
0
  // Get the profile directory
174
0
  rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
175
0
                              getter_AddRefs(mBackingFile));
176
0
  if (NS_FAILED(rv) || !mBackingFile) {
177
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
178
0
           ("CertBlocklist::Init - couldn't get profile dir"));
179
0
    // Since we're returning NS_OK here, set mBackingFile to a safe value.
180
0
    // (We need initialization to succeed and CertBlocklist to be in a
181
0
    // well-defined state if the profile directory doesn't exist.)
182
0
    mBackingFile = nullptr;
183
0
    return NS_OK;
184
0
  }
185
0
  rv = mBackingFile->Append(NS_LITERAL_STRING("revocations.txt"));
186
0
  if (NS_FAILED(rv)) {
187
0
    return rv;
188
0
  }
189
0
  nsAutoCString path;
190
0
  rv = mBackingFile->GetPersistentDescriptor(path);
191
0
  if (NS_FAILED(rv)) {
192
0
    return rv;
193
0
  }
194
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
195
0
         ("CertBlocklist::Init certList path: %s", path.get()));
196
0
197
0
  return NS_OK;
198
0
}
199
200
nsresult
201
CertBlocklist::EnsureBackingFileInitialized(MutexAutoLock& lock)
202
0
{
203
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
204
0
         ("CertBlocklist::EnsureBackingFileInitialized"));
205
0
  if (mBackingFileIsInitialized || !mBackingFile) {
206
0
    return NS_OK;
207
0
  }
208
0
209
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
210
0
         ("CertBlocklist::EnsureBackingFileInitialized - not initialized"));
211
0
212
0
  bool exists = false;
213
0
  nsresult rv = mBackingFile->Exists(&exists);
214
0
  if (NS_FAILED(rv)) {
215
0
    return rv;
216
0
  }
217
0
  if (!exists) {
218
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
219
0
           ("CertBlocklist::EnsureBackingFileInitialized no revocations file"));
220
0
    return NS_OK;
221
0
  }
222
0
223
0
  // Load the revocations file into the cert blocklist
224
0
  nsCOMPtr<nsIFileInputStream> fileStream(
225
0
      do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
226
0
  if (NS_FAILED(rv)) {
227
0
    return rv;
228
0
  }
229
0
230
0
  rv = fileStream->Init(mBackingFile, -1, -1, false);
231
0
  if (NS_FAILED(rv)) {
232
0
    return rv;
233
0
  }
234
0
235
0
  nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
236
0
  nsAutoCString line;
237
0
  nsAutoCString DN;
238
0
  nsAutoCString other;
239
0
  CertBlocklistItemMechanism mechanism;
240
0
  // read in the revocations file. The file format is as follows: each line
241
0
  // contains a comment, base64 encoded DER for a DN, base64 encoded DER for a
242
0
  // serial number or a Base64 encoded SHA256 hash of a public key. Comment
243
0
  // lines start with '#', serial number lines, ' ' (a space), public key hashes
244
0
  // with '\t' (a tab) and anything else is assumed to be a DN.
245
0
  bool more = true;
246
0
  do {
247
0
    rv = lineStream->ReadLine(line, &more);
248
0
    if (NS_FAILED(rv)) {
249
0
      break;
250
0
    }
251
0
    // ignore comments and empty lines
252
0
    if (line.IsEmpty() || line.First() == '#') {
253
0
      continue;
254
0
    }
255
0
    if (line.First() != ' ' && line.First() != '\t') {
256
0
      DN = line;
257
0
      continue;
258
0
    }
259
0
    other = line;
260
0
    if (line.First() == ' ') {
261
0
      mechanism = BlockByIssuerAndSerial;
262
0
    } else {
263
0
      mechanism = BlockBySubjectAndPubKey;
264
0
    }
265
0
    other.Trim(" \t", true, false, false);
266
0
    // Serial numbers and public key hashes 'belong' to the last DN line seen;
267
0
    // if no DN has been seen, the serial number or public key hash is ignored.
268
0
    if (DN.IsEmpty() || other.IsEmpty()) {
269
0
      continue;
270
0
    }
271
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
272
0
           ("CertBlocklist::EnsureBackingFileInitialized adding: %s %s",
273
0
            DN.get(), other.get()));
274
0
275
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
276
0
           ("CertBlocklist::EnsureBackingFileInitialized - pre-decode"));
277
0
278
0
    rv = AddRevokedCertInternal(DN, other, mechanism, CertOldFromLocalCache,
279
0
                                lock);
280
0
281
0
    if (NS_FAILED(rv)) {
282
0
      // we warn here, rather than abandoning, since we need to
283
0
      // ensure that as many items as possible are read
284
0
      MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
285
0
             ("CertBlocklist::EnsureBackingFileInitialized adding revoked cert "
286
0
              "failed"));
287
0
    }
288
0
  } while (more);
289
0
  mBackingFileIsInitialized = true;
290
0
  return NS_OK;
291
0
}
292
293
NS_IMETHODIMP
294
CertBlocklist::RevokeCertBySubjectAndPubKey(const nsACString& aSubject,
295
                                            const nsACString& aPubKeyHash)
296
0
{
297
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
298
0
         ("CertBlocklist::RevokeCertBySubjectAndPubKey - subject is: %s and pubKeyHash: %s",
299
0
          PromiseFlatCString(aSubject).get(),
300
0
          PromiseFlatCString(aPubKeyHash).get()));
301
0
  MutexAutoLock lock(mMutex);
302
0
303
0
  return AddRevokedCertInternal(aSubject, aPubKeyHash,
304
0
                                BlockBySubjectAndPubKey,
305
0
                                CertNewFromBlocklist, lock);
306
0
}
307
308
NS_IMETHODIMP
309
CertBlocklist::RevokeCertByIssuerAndSerial(const nsACString& aIssuer,
310
                                           const nsACString& aSerialNumber)
311
0
{
312
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
313
0
         ("CertBlocklist::RevokeCertByIssuerAndSerial - issuer is: %s and serial: %s",
314
0
          PromiseFlatCString(aIssuer).get(),
315
0
          PromiseFlatCString(aSerialNumber).get()));
316
0
  MutexAutoLock lock(mMutex);
317
0
318
0
  return AddRevokedCertInternal(aIssuer, aSerialNumber,
319
0
                                BlockByIssuerAndSerial,
320
0
                                CertNewFromBlocklist, lock);
321
0
}
322
323
nsresult
324
CertBlocklist::AddRevokedCertInternal(const nsACString& aEncodedDN,
325
                                      const nsACString& aEncodedOther,
326
                                      CertBlocklistItemMechanism aMechanism,
327
                                      CertBlocklistItemState aItemState,
328
                                      MutexAutoLock& /*proofOfLock*/)
329
0
{
330
0
  nsCString decodedDN;
331
0
  nsCString decodedOther;
332
0
333
0
  nsresult rv = Base64Decode(aEncodedDN, decodedDN);
334
0
  if (NS_FAILED(rv)) {
335
0
    return rv;
336
0
  }
337
0
  rv = Base64Decode(aEncodedOther, decodedOther);
338
0
  if (NS_FAILED(rv)) {
339
0
    return rv;
340
0
  }
341
0
342
0
  CertBlocklistItem item(
343
0
    BitwiseCast<const uint8_t*, const char*>(decodedDN.get()),
344
0
    decodedDN.Length(),
345
0
    BitwiseCast<const uint8_t*, const char*>(decodedOther.get()),
346
0
    decodedOther.Length(),
347
0
    aMechanism);
348
0
349
0
  if (aItemState == CertNewFromBlocklist) {
350
0
    // We want SaveEntries to be a no-op if no new entries are added.
351
0
    nsGenericHashKey<CertBlocklistItem>* entry = mBlocklist.GetEntry(item);
352
0
    if (!entry) {
353
0
      mModified = true;
354
0
    } else {
355
0
      // Ensure that any existing item is replaced by a fresh one so we can
356
0
      // use mIsCurrent to decide which entries to write out.
357
0
      mBlocklist.RemoveEntry(entry);
358
0
    }
359
0
    item.mIsCurrent = true;
360
0
  }
361
0
  mBlocklist.PutEntry(item);
362
0
363
0
  return NS_OK;
364
0
}
365
366
// Write a line for a given string in the output stream
367
nsresult
368
WriteLine(nsIOutputStream* outputStream, const nsACString& string)
369
0
{
370
0
  nsAutoCString line(string);
371
0
  line.Append('\n');
372
0
373
0
  const char* data = line.get();
374
0
  uint32_t length = line.Length();
375
0
  nsresult rv = NS_OK;
376
0
  while (NS_SUCCEEDED(rv) && length) {
377
0
    uint32_t bytesWritten = 0;
378
0
    rv = outputStream->Write(data, length, &bytesWritten);
379
0
    if (NS_FAILED(rv)) {
380
0
      return rv;
381
0
    }
382
0
    // if no data is written, something is wrong
383
0
    if (!bytesWritten) {
384
0
      return NS_ERROR_FAILURE;
385
0
    }
386
0
    length -= bytesWritten;
387
0
    data += bytesWritten;
388
0
  }
389
0
  return rv;
390
0
}
391
392
// void saveEntries();
393
// Store the blockist in a text file containing base64 encoded issuers and
394
// serial numbers.
395
//
396
// Each item is stored on a separate line; each issuer is followed by its
397
// revoked serial numbers, indented by one space.
398
//
399
// lines starting with a # character are ignored
400
NS_IMETHODIMP
401
CertBlocklist::SaveEntries()
402
0
{
403
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
404
0
      ("CertBlocklist::SaveEntries - not initialized"));
405
0
  MutexAutoLock lock(mMutex);
406
0
  if (!mModified) {
407
0
    return NS_OK;
408
0
  }
409
0
410
0
  nsresult rv = EnsureBackingFileInitialized(lock);
411
0
  if (NS_FAILED(rv)) {
412
0
    return rv;
413
0
  }
414
0
415
0
  if (!mBackingFile) {
416
0
    // We allow this to succeed with no profile directory for tests
417
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
418
0
           ("CertBlocklist::SaveEntries no file in profile to write to"));
419
0
    return NS_OK;
420
0
  }
421
0
422
0
  // Data needed for writing blocklist items out to the revocations file
423
0
  IssuerTable issuerTable;
424
0
  BlocklistStringSet issuers;
425
0
  nsCOMPtr<nsIOutputStream> outputStream;
426
0
427
0
  rv = NS_NewAtomicFileOutputStream(getter_AddRefs(outputStream),
428
0
                                    mBackingFile, -1, -1, 0);
429
0
  if (NS_FAILED(rv)) {
430
0
    return rv;
431
0
  }
432
0
433
0
  rv = WriteLine(outputStream,
434
0
                 NS_LITERAL_CSTRING("# Auto generated contents. Do not edit."));
435
0
  if (NS_FAILED(rv)) {
436
0
    return rv;
437
0
  }
438
0
439
0
  // Sort blocklist items into lists of serials for each issuer
440
0
  for (auto iter = mBlocklist.Iter(); !iter.Done(); iter.Next()) {
441
0
    CertBlocklistItem item = iter.Get()->GetKey();
442
0
    if (!item.mIsCurrent) {
443
0
      continue;
444
0
    }
445
0
446
0
    nsAutoCString encDN;
447
0
    nsAutoCString encOther;
448
0
449
0
    nsresult rv = item.ToBase64(encDN, encOther);
450
0
    if (NS_FAILED(rv)) {
451
0
      MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
452
0
             ("CertBlocklist::SaveEntries writing revocation data failed"));
453
0
      return NS_ERROR_FAILURE;
454
0
    }
455
0
456
0
    // If it's a subject / public key block, write it straight out
457
0
    if (item.mItemMechanism == BlockBySubjectAndPubKey) {
458
0
      WriteLine(outputStream, encDN);
459
0
      WriteLine(outputStream, NS_LITERAL_CSTRING("\t") + encOther);
460
0
      continue;
461
0
    }
462
0
463
0
    // Otherwise, we have to group entries by issuer
464
0
    issuers.PutEntry(encDN);
465
0
    BlocklistStringSet* issuerSet = issuerTable.Get(encDN);
466
0
    if (!issuerSet) {
467
0
      issuerSet = new BlocklistStringSet();
468
0
      issuerTable.Put(encDN, issuerSet);
469
0
    }
470
0
    issuerSet->PutEntry(encOther);
471
0
  }
472
0
473
0
  for (auto iter = issuers.Iter(); !iter.Done(); iter.Next()) {
474
0
    nsCStringHashKey* hashKey = iter.Get();
475
0
    nsAutoPtr<BlocklistStringSet> issuerSet;
476
0
    issuerTable.Remove(hashKey->GetKey(), &issuerSet);
477
0
478
0
    nsresult rv = WriteLine(outputStream, hashKey->GetKey());
479
0
    if (NS_FAILED(rv)) {
480
0
      break;
481
0
    }
482
0
483
0
    // Write serial data to the output stream
484
0
    for (auto iter = issuerSet->Iter(); !iter.Done(); iter.Next()) {
485
0
      nsresult rv = WriteLine(outputStream,
486
0
                              NS_LITERAL_CSTRING(" ") + iter.Get()->GetKey());
487
0
      if (NS_FAILED(rv)) {
488
0
        MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
489
0
               ("CertBlocklist::SaveEntries writing revocation data failed"));
490
0
        return NS_ERROR_FAILURE;
491
0
      }
492
0
    }
493
0
  }
494
0
495
0
  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outputStream);
496
0
  MOZ_ASSERT(safeStream, "expected a safe output stream!");
497
0
  if (!safeStream) {
498
0
    return NS_ERROR_FAILURE;
499
0
  }
500
0
  rv = safeStream->Finish();
501
0
  if (NS_FAILED(rv)) {
502
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
503
0
           ("CertBlocklist::SaveEntries saving revocation data failed"));
504
0
    return rv;
505
0
  }
506
0
  mModified = false;
507
0
  return NS_OK;
508
0
}
509
510
NS_IMETHODIMP
511
CertBlocklist::IsCertRevoked(const uint8_t* aIssuer,
512
                             uint32_t aIssuerLength,
513
                             const uint8_t* aSerial,
514
                             uint32_t aSerialLength,
515
                             const uint8_t* aSubject,
516
                             uint32_t aSubjectLength,
517
                             const uint8_t* aPubKey,
518
                             uint32_t aPubKeyLength,
519
                             bool* _retval)
520
0
{
521
0
  MutexAutoLock lock(mMutex);
522
0
523
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
524
0
          ("CertBlocklist::IsCertRevoked?"));
525
0
  nsresult rv = EnsureBackingFileInitialized(lock);
526
0
  if (NS_FAILED(rv)) {
527
0
    return rv;
528
0
  }
529
0
530
0
  Input issuer;
531
0
  Input serial;
532
0
  if (issuer.Init(aIssuer, aIssuerLength) != Success) {
533
0
    return NS_ERROR_FAILURE;
534
0
  }
535
0
  if (serial.Init(aSerial, aSerialLength) != Success) {
536
0
    return NS_ERROR_FAILURE;
537
0
  }
538
0
539
0
  CertBlocklistItem issuerSerial(aIssuer, aIssuerLength, aSerial, aSerialLength,
540
0
                                 BlockByIssuerAndSerial);
541
0
542
0
  nsAutoCString encDN;
543
0
  nsAutoCString encOther;
544
0
545
0
  issuerSerial.ToBase64(encDN, encOther);
546
0
  if (NS_FAILED(rv)) {
547
0
    return rv;
548
0
  }
549
0
550
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
551
0
          ("CertBlocklist::IsCertRevoked issuer %s - serial %s",
552
0
           encDN.get(), encOther.get()));
553
0
554
0
  *_retval = mBlocklist.Contains(issuerSerial);
555
0
556
0
  if (*_retval) {
557
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
558
0
            ("certblocklist::IsCertRevoked found by issuer / serial"));
559
0
    return NS_OK;
560
0
  }
561
0
562
0
  nsCOMPtr<nsICryptoHash> crypto;
563
0
  crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
564
0
565
0
  rv = crypto->Init(nsICryptoHash::SHA256);
566
0
  if (NS_FAILED(rv)) {
567
0
    return rv;
568
0
  }
569
0
570
0
  rv = crypto->Update(aPubKey, aPubKeyLength);
571
0
  if (NS_FAILED(rv)) {
572
0
    return rv;
573
0
  }
574
0
575
0
  nsCString hashString;
576
0
  rv = crypto->Finish(false, hashString);
577
0
  if (NS_FAILED(rv)) {
578
0
    return rv;
579
0
  }
580
0
581
0
  CertBlocklistItem subjectPubKey(
582
0
    aSubject,
583
0
    static_cast<size_t>(aSubjectLength),
584
0
    BitwiseCast<const uint8_t*, const char*>(hashString.get()),
585
0
    hashString.Length(),
586
0
    BlockBySubjectAndPubKey);
587
0
588
0
  rv = subjectPubKey.ToBase64(encDN, encOther);
589
0
  if (NS_FAILED(rv)) {
590
0
    return rv;
591
0
  }
592
0
593
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
594
0
          ("CertBlocklist::IsCertRevoked subject %s - pubKey hash %s",
595
0
           encDN.get(), encOther.get()));
596
0
  *_retval = mBlocklist.Contains(subjectPubKey);
597
0
598
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
599
0
          ("CertBlocklist::IsCertRevoked by subject / pubkey? %s",
600
0
           *_retval ? "true" : "false"));
601
0
602
0
  return NS_OK;
603
0
}
604
605
NS_IMETHODIMP
606
CertBlocklist::IsBlocklistFresh(bool* _retval)
607
0
{
608
0
  MutexAutoLock lock(mMutex);
609
0
  *_retval = false;
610
0
611
0
  uint32_t now = uint32_t(PR_Now() / PR_USEC_PER_SEC);
612
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
613
0
          ("CertBlocklist::IsBlocklistFresh ? lastUpdate is %i",
614
0
           sLastBlocklistUpdate));
615
0
616
0
  if (now > sLastBlocklistUpdate) {
617
0
    int64_t interval = now - sLastBlocklistUpdate;
618
0
    MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
619
0
           ("CertBlocklist::IsBlocklistFresh we're after the last BlocklistUpdate "
620
0
            "interval is %" PRId64 ", staleness %u", interval, sMaxStaleness));
621
0
    *_retval = sMaxStaleness > interval;
622
0
  }
623
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
624
0
         ("CertBlocklist::IsBlocklistFresh ? %s", *_retval ? "true" : "false"));
625
0
  return NS_OK;
626
0
}
627
628
629
/* static */
630
void
631
CertBlocklist::PreferenceChanged(const char* aPref, CertBlocklist* aBlocklist)
632
633
0
{
634
0
  MutexAutoLock lock(aBlocklist->mMutex);
635
0
636
0
  MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
637
0
         ("CertBlocklist::PreferenceChanged %s changed", aPref));
638
0
  if (strcmp(aPref, PREF_BLOCKLIST_ONECRL_CHECKED) == 0) {
639
0
    sLastBlocklistUpdate = Preferences::GetUint(PREF_BLOCKLIST_ONECRL_CHECKED,
640
0
                                                uint32_t(0));
641
0
  } else if (strcmp(aPref, PREF_MAX_STALENESS_IN_SECONDS) == 0) {
642
0
    sMaxStaleness = Preferences::GetUint(PREF_MAX_STALENESS_IN_SECONDS,
643
0
                                         uint32_t(0));
644
0
  }
645
0
}