CertBlocklist.cpp 20 KB

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