Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
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/. */
7 #include "nsCertOverrideService.h"
9 #include "pkix/pkixtypes.h"
10 #include "nsIX509Cert.h"
11 #include "NSSCertDBTrustDomain.h"
12 #include "nsNSSCertificate.h"
13 #include "nsNSSCertHelper.h"
14 #include "nsCRT.h"
15 #include "nsAppDirectoryServiceDefs.h"
16 #include "nsStreamUtils.h"
17 #include "nsNetUtil.h"
18 #include "nsILineInputStream.h"
19 #include "nsIObserver.h"
20 #include "nsIObserverService.h"
21 #include "nsISupportsPrimitives.h"
22 #include "nsPromiseFlatString.h"
23 #include "nsThreadUtils.h"
24 #include "nsStringBuffer.h"
25 #include "ScopedNSSTypes.h"
26 #include "SharedSSLState.h"
28 #include "nspr.h"
29 #include "pk11pub.h"
30 #include "certdb.h"
31 #include "sechash.h"
32 #include "ssl.h" // For SSL_ClearSessionCache
34 using namespace mozilla;
35 using namespace mozilla::psm;
37 static const char kCertOverrideFileName[] = "cert_override.txt";
39 void
40 nsCertOverride::convertBitsToString(OverrideBits ob, nsACString &str)
41 {
42 str.Truncate();
44 if (ob & ob_Mismatch)
45 str.Append('M');
47 if (ob & ob_Untrusted)
48 str.Append('U');
50 if (ob & ob_Time_error)
51 str.Append('T');
52 }
54 void
55 nsCertOverride::convertStringToBits(const nsACString &str, OverrideBits &ob)
56 {
57 const nsPromiseFlatCString &flat = PromiseFlatCString(str);
58 const char *walk = flat.get();
60 ob = ob_None;
62 for ( ; *walk; ++walk)
63 {
64 switch (*walk)
65 {
66 case 'm':
67 case 'M':
68 ob = (OverrideBits)(ob | ob_Mismatch);
69 break;
71 case 'u':
72 case 'U':
73 ob = (OverrideBits)(ob | ob_Untrusted);
74 break;
76 case 't':
77 case 'T':
78 ob = (OverrideBits)(ob | ob_Time_error);
79 break;
81 default:
82 break;
83 }
84 }
85 }
87 NS_IMPL_ISUPPORTS(nsCertOverrideService,
88 nsICertOverrideService,
89 nsIObserver,
90 nsISupportsWeakReference)
92 nsCertOverrideService::nsCertOverrideService()
93 : monitor("nsCertOverrideService.monitor")
94 {
95 }
97 nsCertOverrideService::~nsCertOverrideService()
98 {
99 }
101 nsresult
102 nsCertOverrideService::Init()
103 {
104 if (!NS_IsMainThread()) {
105 NS_NOTREACHED("nsCertOverrideService initialized off main thread");
106 return NS_ERROR_NOT_SAME_THREAD;
107 }
109 mOidTagForStoringNewHashes = SEC_OID_SHA256;
111 SECOidData *od = SECOID_FindOIDByTag(mOidTagForStoringNewHashes);
112 if (!od)
113 return NS_ERROR_FAILURE;
115 char *dotted_oid = CERT_GetOidString(&od->oid);
116 if (!dotted_oid)
117 return NS_ERROR_FAILURE;
119 mDottedOidForStoringNewHashes = dotted_oid;
120 PR_smprintf_free(dotted_oid);
122 nsCOMPtr<nsIObserverService> observerService =
123 mozilla::services::GetObserverService();
125 // If we cannot add ourselves as a profile change observer, then we will not
126 // attempt to read/write any settings file. Otherwise, we would end up
127 // reading/writing the wrong settings file after a profile change.
128 if (observerService) {
129 observerService->AddObserver(this, "profile-before-change", true);
130 observerService->AddObserver(this, "profile-do-change", true);
131 // simulate a profile change so we read the current profile's settings file
132 Observe(nullptr, "profile-do-change", nullptr);
133 }
135 SharedSSLState::NoteCertOverrideServiceInstantiated();
136 return NS_OK;
137 }
139 NS_IMETHODIMP
140 nsCertOverrideService::Observe(nsISupports *,
141 const char *aTopic,
142 const char16_t *aData)
143 {
144 // check the topic
145 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
146 // The profile is about to change,
147 // or is going away because the application is shutting down.
149 ReentrantMonitorAutoEnter lock(monitor);
151 if (!nsCRT::strcmp(aData, MOZ_UTF16("shutdown-cleanse"))) {
152 RemoveAllFromMemory();
153 // delete the storage file
154 if (mSettingsFile) {
155 mSettingsFile->Remove(false);
156 }
157 } else {
158 RemoveAllFromMemory();
159 }
161 } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
162 // The profile has already changed.
163 // Now read from the new profile location.
164 // we also need to update the cached file location
166 ReentrantMonitorAutoEnter lock(monitor);
168 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
169 if (NS_SUCCEEDED(rv)) {
170 mSettingsFile->AppendNative(NS_LITERAL_CSTRING(kCertOverrideFileName));
171 } else {
172 mSettingsFile = nullptr;
173 }
174 Read();
176 }
178 return NS_OK;
179 }
181 void
182 nsCertOverrideService::RemoveAllFromMemory()
183 {
184 ReentrantMonitorAutoEnter lock(monitor);
185 mSettingsTable.Clear();
186 }
188 static PLDHashOperator
189 RemoveTemporariesCallback(nsCertOverrideEntry *aEntry,
190 void *aArg)
191 {
192 if (aEntry && aEntry->mSettings.mIsTemporary) {
193 aEntry->mSettings.mCert = nullptr;
194 return PL_DHASH_REMOVE;
195 }
197 return PL_DHASH_NEXT;
198 }
200 void
201 nsCertOverrideService::RemoveAllTemporaryOverrides()
202 {
203 {
204 ReentrantMonitorAutoEnter lock(monitor);
205 mSettingsTable.EnumerateEntries(RemoveTemporariesCallback, nullptr);
206 // no need to write, as temporaries are never written to disk
207 }
208 }
210 nsresult
211 nsCertOverrideService::Read()
212 {
213 ReentrantMonitorAutoEnter lock(monitor);
215 // If we don't have a profile, then we won't try to read any settings file.
216 if (!mSettingsFile)
217 return NS_OK;
219 nsresult rv;
220 nsCOMPtr<nsIInputStream> fileInputStream;
221 rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mSettingsFile);
222 if (NS_FAILED(rv)) {
223 return rv;
224 }
226 nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
227 if (NS_FAILED(rv)) {
228 return rv;
229 }
231 nsAutoCString buffer;
232 bool isMore = true;
233 int32_t hostIndex = 0, algoIndex, fingerprintIndex, overrideBitsIndex, dbKeyIndex;
235 /* file format is:
236 *
237 * host:port \t fingerprint-algorithm \t fingerprint \t override-mask \t dbKey
238 *
239 * where override-mask is a sequence of characters,
240 * M meaning hostname-Mismatch-override
241 * U meaning Untrusted-override
242 * T meaning Time-error-override (expired/not yet valid)
243 *
244 * if this format isn't respected we move onto the next line in the file.
245 */
247 while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
248 if (buffer.IsEmpty() || buffer.First() == '#') {
249 continue;
250 }
252 // this is a cheap, cheesy way of parsing a tab-delimited line into
253 // string indexes, which can be lopped off into substrings. just for
254 // purposes of obfuscation, it also checks that each token was found.
255 // todo: use iterators?
256 if ((algoIndex = buffer.FindChar('\t', hostIndex) + 1) == 0 ||
257 (fingerprintIndex = buffer.FindChar('\t', algoIndex) + 1) == 0 ||
258 (overrideBitsIndex = buffer.FindChar('\t', fingerprintIndex) + 1) == 0 ||
259 (dbKeyIndex = buffer.FindChar('\t', overrideBitsIndex) + 1) == 0) {
260 continue;
261 }
263 const nsASingleFragmentCString &tmp = Substring(buffer, hostIndex, algoIndex - hostIndex - 1);
264 const nsASingleFragmentCString &algo_string = Substring(buffer, algoIndex, fingerprintIndex - algoIndex - 1);
265 const nsASingleFragmentCString &fingerprint = Substring(buffer, fingerprintIndex, overrideBitsIndex - fingerprintIndex - 1);
266 const nsASingleFragmentCString &bits_string = Substring(buffer, overrideBitsIndex, dbKeyIndex - overrideBitsIndex - 1);
267 const nsASingleFragmentCString &db_key = Substring(buffer, dbKeyIndex, buffer.Length() - dbKeyIndex);
269 nsAutoCString host(tmp);
270 nsCertOverride::OverrideBits bits;
271 nsCertOverride::convertStringToBits(bits_string, bits);
273 int32_t port;
274 int32_t portIndex = host.RFindChar(':');
275 if (portIndex == kNotFound)
276 continue; // Ignore broken entries
278 nsresult portParseError;
279 nsAutoCString portString(Substring(host, portIndex+1));
280 port = portString.ToInteger(&portParseError);
281 if (NS_FAILED(portParseError))
282 continue; // Ignore broken entries
284 host.Truncate(portIndex);
286 AddEntryToList(host, port,
287 nullptr, // don't have the cert
288 false, // not temporary
289 algo_string, fingerprint, bits, db_key);
290 }
292 return NS_OK;
293 }
295 static PLDHashOperator
296 WriteEntryCallback(nsCertOverrideEntry *aEntry,
297 void *aArg)
298 {
299 static const char kTab[] = "\t";
301 nsIOutputStream *rawStreamPtr = (nsIOutputStream *)aArg;
303 uint32_t unused;
305 if (rawStreamPtr && aEntry)
306 {
307 const nsCertOverride &settings = aEntry->mSettings;
308 if (settings.mIsTemporary)
309 return PL_DHASH_NEXT;
311 nsAutoCString bits_string;
312 nsCertOverride::convertBitsToString(settings.mOverrideBits,
313 bits_string);
315 rawStreamPtr->Write(aEntry->mHostWithPort.get(), aEntry->mHostWithPort.Length(), &unused);
316 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &unused);
317 rawStreamPtr->Write(settings.mFingerprintAlgOID.get(),
318 settings.mFingerprintAlgOID.Length(), &unused);
319 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &unused);
320 rawStreamPtr->Write(settings.mFingerprint.get(),
321 settings.mFingerprint.Length(), &unused);
322 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &unused);
323 rawStreamPtr->Write(bits_string.get(),
324 bits_string.Length(), &unused);
325 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &unused);
326 rawStreamPtr->Write(settings.mDBKey.get(), settings.mDBKey.Length(), &unused);
327 rawStreamPtr->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &unused);
328 }
330 return PL_DHASH_NEXT;
331 }
333 nsresult
334 nsCertOverrideService::Write()
335 {
336 ReentrantMonitorAutoEnter lock(monitor);
338 // If we don't have any profile, then we won't try to write any file
339 if (!mSettingsFile) {
340 return NS_OK;
341 }
343 nsresult rv;
344 nsCOMPtr<nsIOutputStream> fileOutputStream;
345 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
346 mSettingsFile,
347 -1,
348 0600);
349 if (NS_FAILED(rv)) {
350 NS_ERROR("failed to open cert_warn_settings.txt for writing");
351 return rv;
352 }
354 // get a buffered output stream 4096 bytes big, to optimize writes
355 nsCOMPtr<nsIOutputStream> bufferedOutputStream;
356 rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), fileOutputStream, 4096);
357 if (NS_FAILED(rv)) {
358 return rv;
359 }
361 static const char kHeader[] =
362 "# PSM Certificate Override Settings file" NS_LINEBREAK
363 "# This is a generated file! Do not edit." NS_LINEBREAK;
365 /* see ::Read for file format */
367 uint32_t unused;
368 bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &unused);
370 nsIOutputStream *rawStreamPtr = bufferedOutputStream;
371 mSettingsTable.EnumerateEntries(WriteEntryCallback, rawStreamPtr);
373 // All went ok. Maybe except for problems in Write(), but the stream detects
374 // that for us
375 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
376 NS_ASSERTION(safeStream, "expected a safe output stream!");
377 if (safeStream) {
378 rv = safeStream->Finish();
379 if (NS_FAILED(rv)) {
380 NS_WARNING("failed to save cert warn settings file! possible dataloss");
381 return rv;
382 }
383 }
385 return NS_OK;
386 }
388 static nsresult
389 GetCertFingerprintByOidTag(nsIX509Cert *aCert,
390 SECOidTag aOidTag,
391 nsCString &fp)
392 {
393 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
394 if (!cert2)
395 return NS_ERROR_FAILURE;
397 mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
398 if (!nsscert)
399 return NS_ERROR_FAILURE;
401 return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
402 }
404 static nsresult
405 GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
406 const nsCString &dottedOid,
407 nsCString &fp)
408 {
409 SECItem oid;
410 oid.data = nullptr;
411 oid.len = 0;
412 SECStatus srv = SEC_StringToOID(nullptr, &oid,
413 dottedOid.get(), dottedOid.Length());
414 if (srv != SECSuccess)
415 return NS_ERROR_FAILURE;
417 SECOidTag oid_tag = SECOID_FindOIDTag(&oid);
418 SECITEM_FreeItem(&oid, false);
420 if (oid_tag == SEC_OID_UNKNOWN)
421 return NS_ERROR_FAILURE;
423 return GetCertFingerprintByOidTag(nsscert, oid_tag, fp);
424 }
426 static nsresult
427 GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
428 const nsCString &dottedOid,
429 nsCString &fp)
430 {
431 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
432 if (!cert2)
433 return NS_ERROR_FAILURE;
435 mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
436 if (!nsscert)
437 return NS_ERROR_FAILURE;
439 return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
440 }
442 NS_IMETHODIMP
443 nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, int32_t aPort,
444 nsIX509Cert *aCert,
445 uint32_t aOverrideBits,
446 bool aTemporary)
447 {
448 NS_ENSURE_ARG_POINTER(aCert);
449 if (aHostName.IsEmpty())
450 return NS_ERROR_INVALID_ARG;
451 if (aPort < -1)
452 return NS_ERROR_INVALID_ARG;
454 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
455 if (!cert2)
456 return NS_ERROR_FAILURE;
458 mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
459 if (!nsscert)
460 return NS_ERROR_FAILURE;
462 char* nickname = DefaultServerNicknameForCert(nsscert.get());
463 if (!aTemporary && nickname && *nickname)
464 {
465 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
466 if (!slot) {
467 PR_Free(nickname);
468 return NS_ERROR_FAILURE;
469 }
471 SECStatus srv = PK11_ImportCert(slot, nsscert.get(), CK_INVALID_HANDLE,
472 nickname, false);
473 if (srv != SECSuccess) {
474 PR_Free(nickname);
475 return NS_ERROR_FAILURE;
476 }
477 }
478 PR_FREEIF(nickname);
480 nsAutoCString fpStr;
481 nsresult rv = GetCertFingerprintByOidTag(nsscert.get(),
482 mOidTagForStoringNewHashes, fpStr);
483 if (NS_FAILED(rv))
484 return rv;
486 char *dbkey = nullptr;
487 rv = aCert->GetDbKey(&dbkey);
488 if (NS_FAILED(rv) || !dbkey)
489 return rv;
491 // change \n and \r to spaces in the possibly multi-line-base64-encoded key
492 for (char *dbkey_walk = dbkey;
493 *dbkey_walk;
494 ++dbkey_walk) {
495 char c = *dbkey_walk;
496 if (c == '\r' || c == '\n') {
497 *dbkey_walk = ' ';
498 }
499 }
501 {
502 ReentrantMonitorAutoEnter lock(monitor);
503 AddEntryToList(aHostName, aPort,
504 aTemporary ? aCert : nullptr,
505 // keep a reference to the cert for temporary overrides
506 aTemporary,
507 mDottedOidForStoringNewHashes, fpStr,
508 (nsCertOverride::OverrideBits)aOverrideBits,
509 nsDependentCString(dbkey));
510 Write();
511 }
513 PR_Free(dbkey);
514 return NS_OK;
515 }
517 NS_IMETHODIMP
518 nsCertOverrideService::HasMatchingOverride(const nsACString & aHostName, int32_t aPort,
519 nsIX509Cert *aCert,
520 uint32_t *aOverrideBits,
521 bool *aIsTemporary,
522 bool *_retval)
523 {
524 if (aHostName.IsEmpty())
525 return NS_ERROR_INVALID_ARG;
526 if (aPort < -1)
527 return NS_ERROR_INVALID_ARG;
529 NS_ENSURE_ARG_POINTER(aCert);
530 NS_ENSURE_ARG_POINTER(aOverrideBits);
531 NS_ENSURE_ARG_POINTER(aIsTemporary);
532 NS_ENSURE_ARG_POINTER(_retval);
533 *_retval = false;
534 *aOverrideBits = nsCertOverride::ob_None;
536 nsAutoCString hostPort;
537 GetHostWithPort(aHostName, aPort, hostPort);
538 nsCertOverride settings;
540 {
541 ReentrantMonitorAutoEnter lock(monitor);
542 nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
544 if (!entry)
545 return NS_OK;
547 settings = entry->mSettings; // copy
548 }
550 *aOverrideBits = settings.mOverrideBits;
551 *aIsTemporary = settings.mIsTemporary;
553 nsAutoCString fpStr;
554 nsresult rv;
556 if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
557 rv = GetCertFingerprintByOidTag(aCert, mOidTagForStoringNewHashes, fpStr);
558 }
559 else {
560 rv = GetCertFingerprintByDottedOidString(aCert, settings.mFingerprintAlgOID, fpStr);
561 }
562 if (NS_FAILED(rv))
563 return rv;
565 *_retval = settings.mFingerprint.Equals(fpStr);
566 return NS_OK;
567 }
569 NS_IMETHODIMP
570 nsCertOverrideService::GetValidityOverride(const nsACString & aHostName, int32_t aPort,
571 nsACString & aHashAlg,
572 nsACString & aFingerprint,
573 uint32_t *aOverrideBits,
574 bool *aIsTemporary,
575 bool *_found)
576 {
577 NS_ENSURE_ARG_POINTER(_found);
578 NS_ENSURE_ARG_POINTER(aIsTemporary);
579 NS_ENSURE_ARG_POINTER(aOverrideBits);
580 *_found = false;
581 *aOverrideBits = nsCertOverride::ob_None;
583 nsAutoCString hostPort;
584 GetHostWithPort(aHostName, aPort, hostPort);
585 nsCertOverride settings;
587 {
588 ReentrantMonitorAutoEnter lock(monitor);
589 nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
591 if (entry) {
592 *_found = true;
593 settings = entry->mSettings; // copy
594 }
595 }
597 if (*_found) {
598 *aOverrideBits = settings.mOverrideBits;
599 *aIsTemporary = settings.mIsTemporary;
600 aFingerprint = settings.mFingerprint;
601 aHashAlg = settings.mFingerprintAlgOID;
602 }
604 return NS_OK;
605 }
607 nsresult
608 nsCertOverrideService::AddEntryToList(const nsACString &aHostName, int32_t aPort,
609 nsIX509Cert *aCert,
610 const bool aIsTemporary,
611 const nsACString &fingerprintAlgOID,
612 const nsACString &fingerprint,
613 nsCertOverride::OverrideBits ob,
614 const nsACString &dbKey)
615 {
616 nsAutoCString hostPort;
617 GetHostWithPort(aHostName, aPort, hostPort);
619 {
620 ReentrantMonitorAutoEnter lock(monitor);
621 nsCertOverrideEntry *entry = mSettingsTable.PutEntry(hostPort.get());
623 if (!entry) {
624 NS_ERROR("can't insert a null entry!");
625 return NS_ERROR_OUT_OF_MEMORY;
626 }
628 entry->mHostWithPort = hostPort;
630 nsCertOverride &settings = entry->mSettings;
631 settings.mAsciiHost = aHostName;
632 settings.mPort = aPort;
633 settings.mIsTemporary = aIsTemporary;
634 settings.mFingerprintAlgOID = fingerprintAlgOID;
635 settings.mFingerprint = fingerprint;
636 settings.mOverrideBits = ob;
637 settings.mDBKey = dbKey;
638 settings.mCert = aCert;
639 }
641 return NS_OK;
642 }
644 NS_IMETHODIMP
645 nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, int32_t aPort)
646 {
647 if (aPort == 0 &&
648 aHostName.EqualsLiteral("all:temporary-certificates")) {
649 RemoveAllTemporaryOverrides();
650 return NS_OK;
651 }
652 nsAutoCString hostPort;
653 GetHostWithPort(aHostName, aPort, hostPort);
654 {
655 ReentrantMonitorAutoEnter lock(monitor);
656 mSettingsTable.RemoveEntry(hostPort.get());
657 Write();
658 }
659 SSL_ClearSessionCache();
660 return NS_OK;
661 }
663 NS_IMETHODIMP
664 nsCertOverrideService::GetAllOverrideHostsWithPorts(uint32_t *aCount,
665 char16_t ***aHostsWithPortsArray)
666 {
667 return NS_ERROR_NOT_IMPLEMENTED;
668 }
670 static bool
671 matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
672 {
673 char *dbkey = nullptr;
674 nsresult rv = cert->GetDbKey(&dbkey);
675 if (NS_FAILED(rv) || !dbkey)
676 return false;
678 bool found_mismatch = false;
679 const char *key1 = dbkey;
680 const char *key2 = match_dbkey;
682 // skip over any whitespace when comparing
683 while (*key1 && *key2) {
684 char c1 = *key1;
685 char c2 = *key2;
687 switch (c1) {
688 case ' ':
689 case '\t':
690 case '\n':
691 case '\r':
692 ++key1;
693 continue;
694 }
696 switch (c2) {
697 case ' ':
698 case '\t':
699 case '\n':
700 case '\r':
701 ++key2;
702 continue;
703 }
705 if (c1 != c2) {
706 found_mismatch = true;
707 break;
708 }
710 ++key1;
711 ++key2;
712 }
714 PR_Free(dbkey);
715 return !found_mismatch;
716 }
718 struct nsCertAndBoolsAndInt
719 {
720 nsIX509Cert *cert;
721 bool aCheckTemporaries;
722 bool aCheckPermanents;
723 uint32_t counter;
725 SECOidTag mOidTagForStoringNewHashes;
726 nsCString mDottedOidForStoringNewHashes;
727 };
729 static PLDHashOperator
730 FindMatchingCertCallback(nsCertOverrideEntry *aEntry,
731 void *aArg)
732 {
733 nsCertAndBoolsAndInt *cai = (nsCertAndBoolsAndInt *)aArg;
735 if (cai && aEntry)
736 {
737 const nsCertOverride &settings = aEntry->mSettings;
738 bool still_ok = true;
740 if ((settings.mIsTemporary && !cai->aCheckTemporaries)
741 ||
742 (!settings.mIsTemporary && !cai->aCheckPermanents)) {
743 still_ok = false;
744 }
746 if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
747 nsAutoCString cert_fingerprint;
748 nsresult rv;
749 if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
750 rv = GetCertFingerprintByOidTag(cai->cert,
751 cai->mOidTagForStoringNewHashes, cert_fingerprint);
752 }
753 else {
754 rv = GetCertFingerprintByDottedOidString(cai->cert,
755 settings.mFingerprintAlgOID, cert_fingerprint);
756 }
757 if (NS_SUCCEEDED(rv) &&
758 settings.mFingerprint.Equals(cert_fingerprint)) {
759 cai->counter++;
760 }
761 }
762 }
764 return PL_DHASH_NEXT;
765 }
767 NS_IMETHODIMP
768 nsCertOverrideService::IsCertUsedForOverrides(nsIX509Cert *aCert,
769 bool aCheckTemporaries,
770 bool aCheckPermanents,
771 uint32_t *_retval)
772 {
773 NS_ENSURE_ARG(aCert);
774 NS_ENSURE_ARG(_retval);
776 nsCertAndBoolsAndInt cai;
777 cai.cert = aCert;
778 cai.aCheckTemporaries = aCheckTemporaries;
779 cai.aCheckPermanents = aCheckPermanents;
780 cai.counter = 0;
781 cai.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
782 cai.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;
784 {
785 ReentrantMonitorAutoEnter lock(monitor);
786 mSettingsTable.EnumerateEntries(FindMatchingCertCallback, &cai);
787 }
788 *_retval = cai.counter;
789 return NS_OK;
790 }
792 struct nsCertAndPointerAndCallback
793 {
794 nsIX509Cert *cert;
795 void *userdata;
796 nsCertOverrideService::CertOverrideEnumerator enumerator;
798 SECOidTag mOidTagForStoringNewHashes;
799 nsCString mDottedOidForStoringNewHashes;
800 };
802 static PLDHashOperator
803 EnumerateCertOverridesCallback(nsCertOverrideEntry *aEntry,
804 void *aArg)
805 {
806 nsCertAndPointerAndCallback *capac = (nsCertAndPointerAndCallback *)aArg;
808 if (capac && aEntry)
809 {
810 const nsCertOverride &settings = aEntry->mSettings;
812 if (!capac->cert) {
813 (*capac->enumerator)(settings, capac->userdata);
814 }
815 else {
816 if (matchesDBKey(capac->cert, settings.mDBKey.get())) {
817 nsAutoCString cert_fingerprint;
818 nsresult rv;
819 if (settings.mFingerprintAlgOID.Equals(capac->mDottedOidForStoringNewHashes)) {
820 rv = GetCertFingerprintByOidTag(capac->cert,
821 capac->mOidTagForStoringNewHashes, cert_fingerprint);
822 }
823 else {
824 rv = GetCertFingerprintByDottedOidString(capac->cert,
825 settings.mFingerprintAlgOID, cert_fingerprint);
826 }
827 if (NS_SUCCEEDED(rv) &&
828 settings.mFingerprint.Equals(cert_fingerprint)) {
829 (*capac->enumerator)(settings, capac->userdata);
830 }
831 }
832 }
833 }
835 return PL_DHASH_NEXT;
836 }
838 nsresult
839 nsCertOverrideService::EnumerateCertOverrides(nsIX509Cert *aCert,
840 CertOverrideEnumerator enumerator,
841 void *aUserData)
842 {
843 nsCertAndPointerAndCallback capac;
844 capac.cert = aCert;
845 capac.userdata = aUserData;
846 capac.enumerator = enumerator;
847 capac.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
848 capac.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;
850 {
851 ReentrantMonitorAutoEnter lock(monitor);
852 mSettingsTable.EnumerateEntries(EnumerateCertOverridesCallback, &capac);
853 }
854 return NS_OK;
855 }
857 void
858 nsCertOverrideService::GetHostWithPort(const nsACString & aHostName, int32_t aPort, nsACString& _retval)
859 {
860 nsAutoCString hostPort(aHostName);
861 if (aPort == -1) {
862 aPort = 443;
863 }
864 if (!hostPort.IsEmpty()) {
865 hostPort.AppendLiteral(":");
866 hostPort.AppendInt(aPort);
867 }
868 _retval.Assign(hostPort);
869 }