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