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