nsCertOverrideService.cpp 21 KB

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