mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
b564bd67d3
- Use CompositorWidgetProxy for dispatching vsync to the compositor. (bug 1269037 part 1, r=mchang) (c8b7a4240c) - Remove unused null widget checks. (bug 1269037 part 2, r=mchang) (4f4cc9952b) - Bug 1269422: Wrap Gonk widget in |CompositorWidgetProxyWrapper|. r=dvander (4513035cbf) - Remove nsBaseWidget::NewCompositorBridgeParent. (bug 1272472 part 1, r=kats) (ca813c1f2b) - Use IPDL to schedule composites on GTK. (bug 1272472 part 2, r=nical) (7402cf834e) - Use IPC to schedule composites on Windows. (bug 1272472 part 3, r=jimm) (e5d7281dd7) - Don't use nsIWidget to check APZ in LayerManagerComposite. (bug 1269653 part 1, r=kats) (79a1644111) - Restrict SetDispAcquireFence's nsIWidget access to Gonk. (bug 1269653 part 2, r=kats) (72110b7bc7) - Bug 1264764 - Move PTexture under PCompositorBridge r=nical,dvander (17e6ec7fc1) - Move CompositorThreadHolder into its own file. (bug 1273017 part 1, r=mattwoodrow) (464ede8be1) - Move CompositorBridgeParent::CompositorLoop to CompositorThreadHolder. (bug 1273017 part 2, r=mattwoodrow) (85708f3cde) - Bug 1268313: Part 1 - Be explicit about which NewRunnableMethod callers want to be able to cancel. r=froydnj (faa07aa139) - Bug 1268313: Part 2 - Replace some NewRunnableMethods with NS_NewNonOwningRunnableMethod. r=froydnj (010c43d000) - Bug 1268313: Part 3 - Replace some NewCancelableRunnableMethod with NS_NewNonOwningCancelableRunnableMethod. r=froydnj (55018ef234) - Bug 1268313: Part 4 - Replace NewCancelableRunnableMethod with NS_NewCancelableRunnableMethod. r=froydnj (c22711b35d) - Bug 1268313: Part 5 - Make NS_NewRunnableMethod able to call const functions. r=froydnj (b0f60963a3) - Bug 1268313: Part 6 - Replace NewRunnableMethod with NS_NewRunnableMethod. r=froydnj (18d40def2c) - Bug 1260950 - Set mInitialSizeFound to true when the initial size id found. r=jesup, r=pehrsons a=kwierso (5d6abe57e0) - Bug 1237176 - Notify synth start if we get a finished event without a blocking-changed event. r=roc (c1aebe903a) - Bug 911546, use a runnable so that popups don't rollup during a grab, r=karlt (a06bd44e6c) - Bug 1237617 - Call nsWindow::ForcePresent during going active r=bas.schouten (066cad8f89) - Bug 1268313: Part 7 - Move NS_NewRunnableMethod and friends to mozilla::NewRunnableMethod. r=froydnj (8b4bf34961) - Bug 1266595: Followup to fix IPDL tests. r=billm (216f2dcff5) - Bug 1268313: Fix up IPDL tests. r=billm (228348d642) - Add WinCompositorWidgetProxy. (bug 1265975 part 1, r=jimm) (bfafe7a8e2) - Implement WinCompositorWidgetProxy::GetClientSize. (bug 1265975 part 2, r=jimm) (a8710a3259) - Move the WM_SETTEXT present lock to CompositorWidgetProxy. (bug 1265975 part 3, r=jimm) (297ce28c8a) - Move transparency handling to WinCompositorWigetProxy. (bug 1265975 part 4, r=jimm) (46ba0c6d01) - Remove Windows-specific compositor calls to nsIWidget. (bug 1265975 part 5, r=jimm) (3ef157c160) - Remove plugin-related CompositorBridgeParent use of nsIWidget. (bug 1265975 part 6, r=jimm) (6d80cdd6fd) - Hide top-level CompositorBridgeParents behind a new API. (bug 1272472 part 4, r=mattwoodrow,kats,gwagner) (228c0efdb7) - Bug 1253424 - part 1 - add a already_AddRefed nsTransactionStack::Push overload; r=erahm (7059e20914) - Bug 1253424 - part 2 - add nsTransactionStack::IsEmpty; r=erahm (7e9764a146) - Bug 1254618 - modify nsTransactionStack to use nsDeque rather than std::deque; r=ehsan (5e47ea431e) - Bug 1136857 - Make DOMStorageCache::mLoaded flag atomic to prevent potential races, r=nfroyd (39aaea1de3) - Bug 1265408 - Add webidl for IIRFilterNode; r=smaug (040ce9aa43) - Bug 1265408 - Implement IIRFilterNode; r=padenot (6bf569a412) - Bug 1265408 - Import IIRFilter from blink; r=padenot (71b28c0ad2) - Bug 1265408 - Use IIRFilter from blink; r=padenot (5d058d8568) - Bug 1265408 - Add buffersAreZero to IIRFilter; r=karlt (45edba3e13) - Bug 1265408 - Avoid subnormals in IIRFilter; r=karlt (0e1ae93f0b) - Bug 1265408 - Add LogToDeveloperConsole to WebAudioUtils; r=padenot (88d5f0222a) - Bug 1268984 - Store GMPStorage on GMPServiceParent so that it persists inside the same PB session. r=gerald (17d4d0abaf) - Bug 1267905 - Replace uses of ScopedCERTCertList with UniqueCERTCertList. r=keeler (783bf11b2a) - Bug 1270005 - Replace uses of ScopedPK11SlotInfo with UniquePK11SlotInfo in PSM. r=keeler (ea9a4011aa) - Bug 1271501 - Remove unnecessary uses of reinterpret_cast in PSM. r=keeler (6be40f0a85) - Bug 1271501 - Downgrade unnecessarily strong reinterpret_casts in PSM. r=keeler (95245f00ce) - Bug 1082346 - 01. Convert PKCS12 password endian using copyAndSwapToBigEndian. r=keeler (9cc58fc550) - Bug 1082346 - 02. Test case. r=keeler r=Cykesiopka (7fb0e8abc4) - Bug 160122 - Stop using PR_smprintf in PSM. r=keeler (1e5b68819c) - Bug 1271501 - Use mozilla::BitwiseCast instead of reinterpret_cast in PSM. r=keeler (894966a2ef) - Bug 1273855: TraceLogger - Include PID in the log names in order to support browser with e10s, r=bbouvier (8cf2233db3) - Bug 1274189. Part 1 - rename some functions to be consistent with other MediaDataDecoder sub-classes. r=jya. (4511b3d3f7) - Bug 1274189. Part 2 - remove use of FlushableTaskQueue::Flush(). r=jya. (77e745fdd1) - Bug 1274189. Part 3 - remove use of FlushableTaskQueue. r=jya (aac61dcd02) - Bug 1269963. Part 1 - Add a SyncRunnable::DispatchToThread() overload for AbstractThread. r=bobbyholley. (839752aff4) - Bug 1269672 - part1 : revert sampling rate changing of the bug1235612. (9015782e13) - Bug 1270698 - check if we need to enter buffering periodically to ensure we start buffering when running out of decoded audio/video data. r=cpearce. (16734549b7) - Bug 1271581 - use newCurrentTime, instead of GetMediaTime() to decide the nextState; r=jwwang (9c5075eada) - Bug 1224973 - Part 1: Remove MediaDecoderOwner->IsHidden(). r=cpearce,jwwang (4fde3ede5a) - Bug 1224973 - Part 2: Set MediaDecoder visibility via NotifyOwnerActivityChanged. r=cpearce,jwwang (be917202eb) - Bug 1224973 - Part 3: Plumb element visibility into MDSM. r=jya,jwwang (9ec83fa243) - Bug 1224973 - Part 4: Pref media.suspend-bkgnd-video.enabled. r=cpearce,jwwang (43413a025f) - Bug 1269408: P1. Retry InternalSeek if previous attempt failed once more data is available. r=gerald (05db58dc7c) - crude fix (0097068989) - Bug 1269408: P2. Update mochitest. r=gerald (464b4c0724) - Bug 1269408: P3. Ensure a new seek request will cancel the previous internal seek. r=gerald (6ed4b8dc95) - Bug 1269408: P4. Ensure the decoders are flushed prior performing an internal seek. r=gerald (074234067b) - Bug 1269408: P5. Only drop the seek target if it's exactly the seek target. r=gerald (88701eb05a) - Bug 1269408: P6. Add debugging information, useful when a mochitest timeout. r=gerald (ef0270ab0d) - Bug 1269408: P7. Start skip to next keyframe logic when resume point is behind current time. r=gerald (bd40ebf3bc) - Bug 1269408: P8. Add debugging log. r=gerald (e6dbd1f0a6) - Bug 1269408: P9. Move handling logic of skip to next keyframe to its own function. r=gerald (3c8039e417) - Bug 1269408: P10. Reject promise early if in error state. r=me (8af54c574e) - Bug 1224973 - Part 5: Implement suspend decoding for background video. r=cpearce,jwwang,jya (22081521e3) - Bug 1242874 - part1 : create suspened types. r=baku (d3ac9548e5) - Bug 1242874 - part2 : window's suspend attribute. r=baku, r=ehsan (1fd9dc2647) - remove allowscirpted (39ab523036) - Bug 1242874 - part3 : implement different suspended methods. r=baku, r=jwwang (25d1f27a03) - Bug 1242874 - part4 : wrap the volume/mute/suspend for notifyStartedPlaying. r=baku (b8ba3238c2) - bug 1242874 - part5 : add test. r=baku, r=ehsan (f840139b5a) - Bug 1235612 - Part 1: Implement notify media-playback. r=baku (b5ec29da20) - Bug 1235612 - Part 2: Notify audible state in NotifyStartedPlaying. r=baku (dc38583a62) - Bug 1235612 - Part 3: Implement the logic of audible state notification for agent owners. r=baku (f65b3952fa) - Bug 1235612 - Part 4: Modify check audible method. r=jwwang (73457e39eb) - Bug 1269672 - part2 : move audible data checking from MDSM to DecodedAudioDataSink. (d2c3b6874c) - Bug 1269936 - Introduce and call a runtime-wide servo initialization hook. r=heycam (d4d505d4c2) - Bug 1263778 - Rename a bunch of low-level [[Prototype]] access methods to make their interactions with statically-known and dynamically-computed [[Prototype]]s clearer. r=efaust (66bbe8e7db) - Bug 888969 - Permit a cyclic [[Prototype]] chain to be created through a Location object. r=bz, r=efaust (3e3b9cbb16) - re-apply Bug 1054906 - Implement ES6 Symbol.hasInstance 2/2; r=jandem (8d5c7573ff) - Bug 1054906 - Implement ES6 Symbol.hasInstance 1/2; r=evilpie,bz (a836904e5d) - fix misspatch (54a5f2d708) - Bug 1270349 part 1. Add IDL parser support for [LegacyUnenumerableNamedProperties]. r=peterv (8c836bc74a) - Bug 1270349 part 2. Add [LegacyUnenumerableNamedProperties] to the interfaces that specify it in DOM and HTML. r=peterv (25d3cc1377) - Bug 1270349 part 3. Add a way to ask an interface descriptor for a proxy whether its named props should be enumerable. r=peterv (0a9f804867) - Bug 1270349 part 4. Use LegacyUnenumerableNamedProperties instead of NameIsEnumerable() calls to determine whether named props on DOM proxies should be enumerable. r=peterv (82f5158963) - Bug 1270349 part 5. Use LegacyUnenumerableNamedProperties instead of passing flags to GetSupportedNames to determine whether named props on DOM proxies should be reflected in ownPropertyKeys. r=peterv (3984176834) - Bug 1270349 followup to address a review comment. r=peterv (b49f4c5335)
671 lines
21 KiB
C++
671 lines
21 KiB
C++
/* -*- 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_KINTO_ONECRL_CHECKED "services.kinto.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_KINTO_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_KINTO_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_KINTO_ONECRL_CHECKED) == 0) {
|
|
sLastKintoUpdate = Preferences::GetUint(PREF_KINTO_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);
|
|
}
|
|
}
|