summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/CertBlocklist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/CertBlocklist.cpp')
-rw-r--r--security/manager/ssl/CertBlocklist.cpp671
1 files changed, 671 insertions, 0 deletions
diff --git a/security/manager/ssl/CertBlocklist.cpp b/security/manager/ssl/CertBlocklist.cpp
new file mode 100644
index 000000000..56473eca3
--- /dev/null
+++ b/security/manager/ssl/CertBlocklist.cpp
@@ -0,0 +1,671 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CertBlocklist.h"
+
+#include "mozilla/Base64.h"
+#include "mozilla/Casting.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsCRTGlue.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsICryptoHash.h"
+#include "nsIFileStreams.h"
+#include "nsILineInputStream.h"
+#include "nsISafeOutputStream.h"
+#include "nsIX509Cert.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nsTHashtable.h"
+#include "nsThreadUtils.h"
+#include "pkix/Input.h"
+#include "prtime.h"
+
+NS_IMPL_ISUPPORTS(CertBlocklist, nsICertBlocklist)
+
+using namespace mozilla;
+using namespace mozilla::pkix;
+
+#define PREF_BACKGROUND_UPDATE_TIMER "app.update.lastUpdateTime.blocklist-background-update-timer"
+#define PREF_BLOCKLIST_ONECRL_CHECKED "services.blocklist.onecrl.checked"
+#define PREF_MAX_STALENESS_IN_SECONDS "security.onecrl.maximum_staleness_in_seconds"
+#define PREF_ONECRL_VIA_AMO "security.onecrl.via.amo"
+
+static LazyLogModule gCertBlockPRLog("CertBlock");
+
+uint32_t CertBlocklist::sLastBlocklistUpdate = 0U;
+uint32_t CertBlocklist::sLastKintoUpdate = 0U;
+uint32_t CertBlocklist::sMaxStaleness = 0U;
+bool CertBlocklist::sUseAMO = true;
+
+CertBlocklistItem::CertBlocklistItem(const uint8_t* DNData,
+ size_t DNLength,
+ const uint8_t* otherData,
+ size_t otherLength,
+ CertBlocklistItemMechanism itemMechanism)
+ : mIsCurrent(false)
+ , mItemMechanism(itemMechanism)
+{
+ mDNData = new uint8_t[DNLength];
+ memcpy(mDNData, DNData, DNLength);
+ mDNLength = DNLength;
+
+ mOtherData = new uint8_t[otherLength];
+ memcpy(mOtherData, otherData, otherLength);
+ mOtherLength = otherLength;
+}
+
+CertBlocklistItem::CertBlocklistItem(const CertBlocklistItem& aItem)
+{
+ mDNLength = aItem.mDNLength;
+ mDNData = new uint8_t[mDNLength];
+ memcpy(mDNData, aItem.mDNData, mDNLength);
+
+ mOtherLength = aItem.mOtherLength;
+ mOtherData = new uint8_t[mOtherLength];
+ memcpy(mOtherData, aItem.mOtherData, mOtherLength);
+
+ mItemMechanism = aItem.mItemMechanism;
+
+ mIsCurrent = aItem.mIsCurrent;
+}
+
+CertBlocklistItem::~CertBlocklistItem()
+{
+ delete[] mDNData;
+ delete[] mOtherData;
+}
+
+nsresult
+CertBlocklistItem::ToBase64(nsACString& b64DNOut, nsACString& b64OtherOut)
+{
+ nsDependentCSubstring DNString(BitwiseCast<char*, uint8_t*>(mDNData),
+ mDNLength);
+ nsDependentCSubstring otherString(BitwiseCast<char*, uint8_t*>(mOtherData),
+ mOtherLength);
+ nsresult rv = Base64Encode(DNString, b64DNOut);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Base64Encode(otherString, b64OtherOut);
+ return rv;
+}
+
+bool
+CertBlocklistItem::operator==(const CertBlocklistItem& aItem) const
+{
+ if (aItem.mItemMechanism != mItemMechanism) {
+ return false;
+ }
+ if (aItem.mDNLength != mDNLength ||
+ aItem.mOtherLength != mOtherLength) {
+ return false;
+ }
+ return memcmp(aItem.mDNData, mDNData, mDNLength) == 0 &&
+ memcmp(aItem.mOtherData, mOtherData, mOtherLength) == 0;
+}
+
+uint32_t
+CertBlocklistItem::Hash() const
+{
+ uint32_t hash;
+ // there's no requirement for a serial to be as large as the size of the hash
+ // key; if it's smaller, fall back to the first octet (otherwise, the last
+ // four)
+ if (mItemMechanism == BlockByIssuerAndSerial &&
+ mOtherLength >= sizeof(hash)) {
+ memcpy(&hash, mOtherData + mOtherLength - sizeof(hash), sizeof(hash));
+ } else {
+ hash = *mOtherData;
+ }
+ return hash;
+}
+
+CertBlocklist::CertBlocklist()
+ : mMutex("CertBlocklist::mMutex")
+ , mModified(false)
+ , mBackingFileIsInitialized(false)
+ , mBackingFile(nullptr)
+{
+}
+
+CertBlocklist::~CertBlocklist()
+{
+ Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
+ PREF_BACKGROUND_UPDATE_TIMER,
+ this);
+ Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
+ PREF_MAX_STALENESS_IN_SECONDS,
+ this);
+ Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
+ PREF_ONECRL_VIA_AMO,
+ this);
+ Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
+ PREF_BLOCKLIST_ONECRL_CHECKED,
+ this);
+}
+
+nsresult
+CertBlocklist::Init()
+{
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug, ("CertBlocklist::Init"));
+
+ // Init must be on main thread for getting the profile directory
+ if (!NS_IsMainThread()) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::Init - called off main thread"));
+ return NS_ERROR_NOT_SAME_THREAD;
+ }
+
+ // Register preference callbacks
+ nsresult rv =
+ Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
+ PREF_BACKGROUND_UPDATE_TIMER,
+ this);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
+ PREF_MAX_STALENESS_IN_SECONDS,
+ this);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
+ PREF_ONECRL_VIA_AMO,
+ this);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
+ PREF_BLOCKLIST_ONECRL_CHECKED,
+ this);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // Get the profile directory
+ rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+ getter_AddRefs(mBackingFile));
+ if (NS_FAILED(rv) || !mBackingFile) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::Init - couldn't get profile dir"));
+ // Since we're returning NS_OK here, set mBackingFile to a safe value.
+ // (We need initialization to succeed and CertBlocklist to be in a
+ // well-defined state if the profile directory doesn't exist.)
+ mBackingFile = nullptr;
+ return NS_OK;
+ }
+ rv = mBackingFile->Append(NS_LITERAL_STRING("revocations.txt"));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsAutoCString path;
+ rv = mBackingFile->GetNativePath(path);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::Init certList path: %s", path.get()));
+
+ return NS_OK;
+}
+
+nsresult
+CertBlocklist::EnsureBackingFileInitialized(MutexAutoLock& lock)
+{
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::EnsureBackingFileInitialized"));
+ if (mBackingFileIsInitialized || !mBackingFile) {
+ return NS_OK;
+ }
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::EnsureBackingFileInitialized - not initialized"));
+
+ bool exists = false;
+ nsresult rv = mBackingFile->Exists(&exists);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!exists) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::EnsureBackingFileInitialized no revocations file"));
+ return NS_OK;
+ }
+
+ // Load the revocations file into the cert blocklist
+ nsCOMPtr<nsIFileInputStream> fileStream(
+ do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = fileStream->Init(mBackingFile, -1, -1, false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
+ nsAutoCString line;
+ nsAutoCString DN;
+ nsAutoCString other;
+ CertBlocklistItemMechanism mechanism;
+ // read in the revocations file. The file format is as follows: each line
+ // contains a comment, base64 encoded DER for a DN, base64 encoded DER for a
+ // serial number or a Base64 encoded SHA256 hash of a public key. Comment
+ // lines start with '#', serial number lines, ' ' (a space), public key hashes
+ // with '\t' (a tab) and anything else is assumed to be a DN.
+ bool more = true;
+ do {
+ rv = lineStream->ReadLine(line, &more);
+ if (NS_FAILED(rv)) {
+ break;
+ }
+ // ignore comments and empty lines
+ if (line.IsEmpty() || line.First() == '#') {
+ continue;
+ }
+ if (line.First() != ' ' && line.First() != '\t') {
+ DN = line;
+ continue;
+ }
+ other = line;
+ if (line.First() == ' ') {
+ mechanism = BlockByIssuerAndSerial;
+ } else {
+ mechanism = BlockBySubjectAndPubKey;
+ }
+ other.Trim(" \t", true, false, false);
+ // Serial numbers and public key hashes 'belong' to the last DN line seen;
+ // if no DN has been seen, the serial number or public key hash is ignored.
+ if (DN.IsEmpty() || other.IsEmpty()) {
+ continue;
+ }
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::EnsureBackingFileInitialized adding: %s %s",
+ DN.get(), other.get()));
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::EnsureBackingFileInitialized - pre-decode"));
+
+ rv = AddRevokedCertInternal(DN, other, mechanism, CertOldFromLocalCache,
+ lock);
+
+ if (NS_FAILED(rv)) {
+ // we warn here, rather than abandoning, since we need to
+ // ensure that as many items as possible are read
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::EnsureBackingFileInitialized adding revoked cert "
+ "failed"));
+ }
+ } while (more);
+ mBackingFileIsInitialized = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+CertBlocklist::RevokeCertBySubjectAndPubKey(const char* aSubject,
+ const char* aPubKeyHash)
+{
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::RevokeCertBySubjectAndPubKey - subject is: %s and pubKeyHash: %s",
+ aSubject, aPubKeyHash));
+ MutexAutoLock lock(mMutex);
+
+ return AddRevokedCertInternal(nsDependentCString(aSubject),
+ nsDependentCString(aPubKeyHash),
+ BlockBySubjectAndPubKey,
+ CertNewFromBlocklist, lock);
+}
+
+NS_IMETHODIMP
+CertBlocklist::RevokeCertByIssuerAndSerial(const char* aIssuer,
+ const char* aSerialNumber)
+{
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::RevokeCertByIssuerAndSerial - issuer is: %s and serial: %s",
+ aIssuer, aSerialNumber));
+ MutexAutoLock lock(mMutex);
+
+ return AddRevokedCertInternal(nsDependentCString(aIssuer),
+ nsDependentCString(aSerialNumber),
+ BlockByIssuerAndSerial,
+ CertNewFromBlocklist, lock);
+}
+
+nsresult
+CertBlocklist::AddRevokedCertInternal(const nsACString& aEncodedDN,
+ const nsACString& aEncodedOther,
+ CertBlocklistItemMechanism aMechanism,
+ CertBlocklistItemState aItemState,
+ MutexAutoLock& /*proofOfLock*/)
+{
+ nsCString decodedDN;
+ nsCString decodedOther;
+
+ nsresult rv = Base64Decode(aEncodedDN, decodedDN);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Base64Decode(aEncodedOther, decodedOther);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ CertBlocklistItem item(
+ BitwiseCast<const uint8_t*, const char*>(decodedDN.get()),
+ decodedDN.Length(),
+ BitwiseCast<const uint8_t*, const char*>(decodedOther.get()),
+ decodedOther.Length(),
+ aMechanism);
+
+ if (aItemState == CertNewFromBlocklist) {
+ // We want SaveEntries to be a no-op if no new entries are added.
+ nsGenericHashKey<CertBlocklistItem>* entry = mBlocklist.GetEntry(item);
+ if (!entry) {
+ mModified = true;
+ } else {
+ // Ensure that any existing item is replaced by a fresh one so we can
+ // use mIsCurrent to decide which entries to write out.
+ mBlocklist.RemoveEntry(entry);
+ }
+ item.mIsCurrent = true;
+ }
+ mBlocklist.PutEntry(item);
+
+ return NS_OK;
+}
+
+// Write a line for a given string in the output stream
+nsresult
+WriteLine(nsIOutputStream* outputStream, const nsACString& string)
+{
+ nsAutoCString line(string);
+ line.Append('\n');
+
+ const char* data = line.get();
+ uint32_t length = line.Length();
+ nsresult rv = NS_OK;
+ while (NS_SUCCEEDED(rv) && length) {
+ uint32_t bytesWritten = 0;
+ rv = outputStream->Write(data, length, &bytesWritten);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // if no data is written, something is wrong
+ if (!bytesWritten) {
+ return NS_ERROR_FAILURE;
+ }
+ length -= bytesWritten;
+ data += bytesWritten;
+ }
+ return rv;
+}
+
+// void saveEntries();
+// Store the blockist in a text file containing base64 encoded issuers and
+// serial numbers.
+//
+// Each item is stored on a separate line; each issuer is followed by its
+// revoked serial numbers, indented by one space.
+//
+// lines starting with a # character are ignored
+NS_IMETHODIMP
+CertBlocklist::SaveEntries()
+{
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
+ ("CertBlocklist::SaveEntries - not initialized"));
+ MutexAutoLock lock(mMutex);
+ if (!mModified) {
+ return NS_OK;
+ }
+
+ nsresult rv = EnsureBackingFileInitialized(lock);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ if (!mBackingFile) {
+ // We allow this to succeed with no profile directory for tests
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::SaveEntries no file in profile to write to"));
+ return NS_OK;
+ }
+
+ // Data needed for writing blocklist items out to the revocations file
+ IssuerTable issuerTable;
+ BlocklistStringSet issuers;
+ nsCOMPtr<nsIOutputStream> outputStream;
+
+ rv = NS_NewAtomicFileOutputStream(getter_AddRefs(outputStream),
+ mBackingFile, -1, -1, 0);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = WriteLine(outputStream,
+ NS_LITERAL_CSTRING("# Auto generated contents. Do not edit."));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // Sort blocklist items into lists of serials for each issuer
+ for (auto iter = mBlocklist.Iter(); !iter.Done(); iter.Next()) {
+ CertBlocklistItem item = iter.Get()->GetKey();
+ if (!item.mIsCurrent) {
+ continue;
+ }
+
+ nsAutoCString encDN;
+ nsAutoCString encOther;
+
+ nsresult rv = item.ToBase64(encDN, encOther);
+ if (NS_FAILED(rv)) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::SaveEntries writing revocation data failed"));
+ return NS_ERROR_FAILURE;
+ }
+
+ // If it's a subject / public key block, write it straight out
+ if (item.mItemMechanism == BlockBySubjectAndPubKey) {
+ WriteLine(outputStream, encDN);
+ WriteLine(outputStream, NS_LITERAL_CSTRING("\t") + encOther);
+ continue;
+ }
+
+ // Otherwise, we have to group entries by issuer
+ issuers.PutEntry(encDN);
+ BlocklistStringSet* issuerSet = issuerTable.Get(encDN);
+ if (!issuerSet) {
+ issuerSet = new BlocklistStringSet();
+ issuerTable.Put(encDN, issuerSet);
+ }
+ issuerSet->PutEntry(encOther);
+ }
+
+ for (auto iter = issuers.Iter(); !iter.Done(); iter.Next()) {
+ nsCStringHashKey* hashKey = iter.Get();
+ nsAutoPtr<BlocklistStringSet> issuerSet;
+ issuerTable.RemoveAndForget(hashKey->GetKey(), issuerSet);
+
+ nsresult rv = WriteLine(outputStream, hashKey->GetKey());
+ if (NS_FAILED(rv)) {
+ break;
+ }
+
+ // Write serial data to the output stream
+ for (auto iter = issuerSet->Iter(); !iter.Done(); iter.Next()) {
+ nsresult rv = WriteLine(outputStream,
+ NS_LITERAL_CSTRING(" ") + iter.Get()->GetKey());
+ if (NS_FAILED(rv)) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::SaveEntries writing revocation data failed"));
+ return NS_ERROR_FAILURE;
+ }
+ }
+ }
+
+ nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outputStream);
+ NS_ASSERTION(safeStream, "expected a safe output stream!");
+ if (!safeStream) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = safeStream->Finish();
+ if (NS_FAILED(rv)) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::SaveEntries saving revocation data failed"));
+ return rv;
+ }
+ mModified = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+CertBlocklist::IsCertRevoked(const uint8_t* aIssuer,
+ uint32_t aIssuerLength,
+ const uint8_t* aSerial,
+ uint32_t aSerialLength,
+ const uint8_t* aSubject,
+ uint32_t aSubjectLength,
+ const uint8_t* aPubKey,
+ uint32_t aPubKeyLength,
+ bool* _retval)
+{
+ MutexAutoLock lock(mMutex);
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsCertRevoked?"));
+ nsresult rv = EnsureBackingFileInitialized(lock);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ Input issuer;
+ Input serial;
+ if (issuer.Init(aIssuer, aIssuerLength) != Success) {
+ return NS_ERROR_FAILURE;
+ }
+ if (serial.Init(aSerial, aSerialLength) != Success) {
+ return NS_ERROR_FAILURE;
+ }
+
+ CertBlocklistItem issuerSerial(aIssuer, aIssuerLength, aSerial, aSerialLength,
+ BlockByIssuerAndSerial);
+
+ nsAutoCString encDN;
+ nsAutoCString encOther;
+
+ issuerSerial.ToBase64(encDN, encOther);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsCertRevoked issuer %s - serial %s",
+ encDN.get(), encOther.get()));
+
+ *_retval = mBlocklist.Contains(issuerSerial);
+
+ if (*_retval) {
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("certblocklist::IsCertRevoked found by issuer / serial"));
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsICryptoHash> crypto;
+ crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
+
+ rv = crypto->Init(nsICryptoHash::SHA256);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = crypto->Update(aPubKey, aPubKeyLength);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ nsCString hashString;
+ rv = crypto->Finish(false, hashString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ CertBlocklistItem subjectPubKey(
+ aSubject,
+ static_cast<size_t>(aSubjectLength),
+ BitwiseCast<const uint8_t*, const char*>(hashString.get()),
+ hashString.Length(),
+ BlockBySubjectAndPubKey);
+
+ rv = subjectPubKey.ToBase64(encDN, encOther);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsCertRevoked subject %s - pubKey hash %s",
+ encDN.get(), encOther.get()));
+ *_retval = mBlocklist.Contains(subjectPubKey);
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsCertRevoked by subject / pubkey? %s",
+ *_retval ? "true" : "false"));
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+CertBlocklist::IsBlocklistFresh(bool* _retval)
+{
+ MutexAutoLock lock(mMutex);
+ *_retval = false;
+
+ uint32_t now = uint32_t(PR_Now() / PR_USEC_PER_SEC);
+ uint32_t lastUpdate = sUseAMO ? sLastBlocklistUpdate : sLastKintoUpdate;
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsBlocklistFresh using AMO? %i lastUpdate is %i",
+ sUseAMO, lastUpdate));
+
+ if (now > lastUpdate) {
+ int64_t interval = now - lastUpdate;
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsBlocklistFresh we're after the last BlocklistUpdate "
+ "interval is %i, staleness %u", interval, sMaxStaleness));
+ *_retval = sMaxStaleness > interval;
+ }
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::IsBlocklistFresh ? %s", *_retval ? "true" : "false"));
+ return NS_OK;
+}
+
+
+/* static */
+void
+CertBlocklist::PreferenceChanged(const char* aPref, void* aClosure)
+
+{
+ auto blocklist = static_cast<CertBlocklist*>(aClosure);
+ MutexAutoLock lock(blocklist->mMutex);
+
+ MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
+ ("CertBlocklist::PreferenceChanged %s changed", aPref));
+ if (strcmp(aPref, PREF_BACKGROUND_UPDATE_TIMER) == 0) {
+ sLastBlocklistUpdate = Preferences::GetUint(PREF_BACKGROUND_UPDATE_TIMER,
+ uint32_t(0));
+ } else if (strcmp(aPref, PREF_BLOCKLIST_ONECRL_CHECKED) == 0) {
+ sLastKintoUpdate = Preferences::GetUint(PREF_BLOCKLIST_ONECRL_CHECKED,
+ uint32_t(0));
+ } else if (strcmp(aPref, PREF_MAX_STALENESS_IN_SECONDS) == 0) {
+ sMaxStaleness = Preferences::GetUint(PREF_MAX_STALENESS_IN_SECONDS,
+ uint32_t(0));
+ } else if (strcmp(aPref, PREF_ONECRL_VIA_AMO) == 0) {
+ sUseAMO = Preferences::GetBool(PREF_ONECRL_VIA_AMO, true);
+ }
+}