Bug 452390 Tracemonkey will crash if the compiler doesn't have FASTCALL r=danderson
[wine-gecko.git] / security / manager / ssl / src / nsCertOverrideService.cpp
bloba697a270c58ee030c790b803e227c66efdc95b65
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Red Hat, Inc.
20 * Portions created by the Initial Developer are Copyright (C) 2006
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Kai Engert <kengert@redhat.com>
25 * Ehsan Akhgari <ehsan.akhgari@gmail.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsCertOverrideService.h"
42 #include "nsIX509Cert.h"
43 #include "nsNSSCertificate.h"
44 #include "nsCRT.h"
45 #include "nsAppDirectoryServiceDefs.h"
46 #include "nsStreamUtils.h"
47 #include "nsNetUtil.h"
48 #include "nsILineInputStream.h"
49 #include "nsIObserver.h"
50 #include "nsIObserverService.h"
51 #include "nsISupportsPrimitives.h"
52 #include "nsPromiseFlatString.h"
53 #include "nsProxiedService.h"
54 #include "nsStringBuffer.h"
55 #include "nsAutoLock.h"
56 #include "nsAutoPtr.h"
57 #include "nspr.h"
58 #include "pk11pub.h"
59 #include "certdb.h"
60 #include "sechash.h"
61 #include "ssl.h" // For SSL_ClearSessionCache
63 #include "nsNSSCleaner.h"
64 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
66 static const char kCertOverrideFileName[] = "cert_override.txt";
68 void
69 nsCertOverride::convertBitsToString(OverrideBits ob, nsACString &str)
71 str.Truncate();
73 if (ob & ob_Mismatch)
74 str.Append('M');
76 if (ob & ob_Untrusted)
77 str.Append('U');
79 if (ob & ob_Time_error)
80 str.Append('T');
83 void
84 nsCertOverride::convertStringToBits(const nsACString &str, OverrideBits &ob)
86 const nsPromiseFlatCString &flat = PromiseFlatCString(str);
87 const char *walk = flat.get();
89 ob = ob_None;
91 for ( ; *walk; ++walk)
93 switch (*walk)
95 case 'm':
96 case 'M':
97 ob = (OverrideBits)(ob | ob_Mismatch);
98 break;
100 case 'u':
101 case 'U':
102 ob = (OverrideBits)(ob | ob_Untrusted);
103 break;
105 case 't':
106 case 'T':
107 ob = (OverrideBits)(ob | ob_Time_error);
108 break;
110 default:
111 break;
116 NS_IMPL_THREADSAFE_ISUPPORTS3(nsCertOverrideService,
117 nsICertOverrideService,
118 nsIObserver,
119 nsISupportsWeakReference)
121 nsCertOverrideService::nsCertOverrideService()
123 monitor = PR_NewMonitor();
126 nsCertOverrideService::~nsCertOverrideService()
128 if (monitor)
129 PR_DestroyMonitor(monitor);
132 nsresult
133 nsCertOverrideService::Init()
135 if (!mSettingsTable.Init())
136 return NS_ERROR_OUT_OF_MEMORY;
138 mOidTagForStoringNewHashes = SEC_OID_SHA256;
140 SECOidData *od = SECOID_FindOIDByTag(mOidTagForStoringNewHashes);
141 if (!od)
142 return NS_ERROR_FAILURE;
144 char *dotted_oid = CERT_GetOidString(&od->oid);
145 if (!dotted_oid)
146 return NS_ERROR_FAILURE;
148 mDottedOidForStoringNewHashes = dotted_oid;
149 PR_smprintf_free(dotted_oid);
151 // cache mSettingsFile
152 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
153 if (mSettingsFile) {
154 mSettingsFile->AppendNative(NS_LITERAL_CSTRING(kCertOverrideFileName));
157 Read();
159 nsresult rv;
160 NS_WITH_ALWAYS_PROXIED_SERVICE(nsIObserverService, mObserverService,
161 "@mozilla.org/observer-service;1",
162 NS_PROXY_TO_MAIN_THREAD, &rv);
164 if (mObserverService) {
165 mObserverService->AddObserver(this, "profile-before-change", PR_TRUE);
166 mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
167 mObserverService->AddObserver(this, "shutdown-cleanse", PR_TRUE);
170 return NS_OK;
173 NS_IMETHODIMP
174 nsCertOverrideService::Observe(nsISupports *aSubject,
175 const char *aTopic,
176 const PRUnichar *aData)
178 // check the topic
179 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
180 // The profile is about to change,
181 // or is going away because the application is shutting down.
183 nsAutoMonitor lock(monitor);
185 if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
186 RemoveAllFromMemory();
187 // delete the storage file
188 if (mSettingsFile) {
189 mSettingsFile->Remove(PR_FALSE);
191 } else {
192 RemoveAllFromMemory();
195 } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
196 // The profile has already changed.
197 // Now read from the new profile location.
198 // we also need to update the cached file location
200 nsAutoMonitor lock(monitor);
202 nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
203 if (NS_SUCCEEDED(rv)) {
204 mSettingsFile->AppendNative(NS_LITERAL_CSTRING(kCertOverrideFileName));
206 Read();
210 return NS_OK;
213 void
214 nsCertOverrideService::RemoveAllFromMemory()
216 nsAutoMonitor lock(monitor);
217 mSettingsTable.Clear();
220 PR_STATIC_CALLBACK(PLDHashOperator)
221 RemoveTemporariesCallback(nsCertOverrideEntry *aEntry,
222 void *aArg)
224 if (aEntry && aEntry->mSettings.mIsTemporary) {
225 aEntry->mSettings.mCert = nsnull;
226 return PL_DHASH_REMOVE;
229 return PL_DHASH_NEXT;
232 void
233 nsCertOverrideService::RemoveAllTemporaryOverrides()
236 nsAutoMonitor lock(monitor);
237 mSettingsTable.EnumerateEntries(RemoveTemporariesCallback, nsnull);
238 // no need to write, as temporaries are never written to disk
242 nsresult
243 nsCertOverrideService::Read()
245 nsAutoMonitor lock(monitor);
247 nsresult rv;
248 nsCOMPtr<nsIInputStream> fileInputStream;
249 rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mSettingsFile);
250 if (NS_FAILED(rv)) {
251 return rv;
254 nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
255 if (NS_FAILED(rv)) {
256 return rv;
259 nsCAutoString buffer;
260 PRBool isMore = PR_TRUE;
261 PRInt32 hostIndex = 0, algoIndex, fingerprintIndex, overrideBitsIndex, dbKeyIndex;
263 /* file format is:
265 * host:port \t fingerprint-algorithm \t fingerprint \t override-mask \t dbKey
267 * where override-mask is a sequence of characters,
268 * M meaning hostname-Mismatch-override
269 * U meaning Untrusted-override
270 * T meaning Time-error-override (expired/not yet valid)
272 * if this format isn't respected we move onto the next line in the file.
275 while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
276 if (buffer.IsEmpty() || buffer.First() == '#') {
277 continue;
280 // this is a cheap, cheesy way of parsing a tab-delimited line into
281 // string indexes, which can be lopped off into substrings. just for
282 // purposes of obfuscation, it also checks that each token was found.
283 // todo: use iterators?
284 if ((algoIndex = buffer.FindChar('\t', hostIndex) + 1) == 0 ||
285 (fingerprintIndex = buffer.FindChar('\t', algoIndex) + 1) == 0 ||
286 (overrideBitsIndex = buffer.FindChar('\t', fingerprintIndex) + 1) == 0 ||
287 (dbKeyIndex = buffer.FindChar('\t', overrideBitsIndex) + 1) == 0) {
288 continue;
291 const nsASingleFragmentCString &tmp = Substring(buffer, hostIndex, algoIndex - hostIndex - 1);
292 const nsASingleFragmentCString &algo_string = Substring(buffer, algoIndex, fingerprintIndex - algoIndex - 1);
293 const nsASingleFragmentCString &fingerprint = Substring(buffer, fingerprintIndex, overrideBitsIndex - fingerprintIndex - 1);
294 const nsASingleFragmentCString &bits_string = Substring(buffer, overrideBitsIndex, dbKeyIndex - overrideBitsIndex - 1);
295 const nsASingleFragmentCString &db_key = Substring(buffer, dbKeyIndex, buffer.Length() - dbKeyIndex);
297 nsCAutoString host(tmp);
298 nsCertOverride::OverrideBits bits;
299 nsCertOverride::convertStringToBits(bits_string, bits);
301 PRInt32 port;
302 PRInt32 portIndex = host.RFindChar(':');
303 if (portIndex == kNotFound)
304 continue; // Ignore broken entries
306 PRInt32 portParseError;
307 nsCAutoString portString(Substring(host, portIndex+1));
308 port = portString.ToInteger(&portParseError);
309 if (portParseError)
310 continue; // Ignore broken entries
312 host.Truncate(portIndex);
314 AddEntryToList(host, port,
315 nsnull, // don't have the cert
316 PR_FALSE, // not temporary
317 algo_string, fingerprint, bits, db_key);
320 return NS_OK;
323 PR_STATIC_CALLBACK(PLDHashOperator)
324 WriteEntryCallback(nsCertOverrideEntry *aEntry,
325 void *aArg)
327 static const char kTab[] = "\t";
329 nsIOutputStream *rawStreamPtr = (nsIOutputStream *)aArg;
331 nsresult rv;
333 if (rawStreamPtr && aEntry)
335 const nsCertOverride &settings = aEntry->mSettings;
336 if (settings.mIsTemporary)
337 return PL_DHASH_NEXT;
339 nsCAutoString bits_string;
340 nsCertOverride::convertBitsToString(settings.mOverrideBits,
341 bits_string);
343 rawStreamPtr->Write(aEntry->mHostWithPort.get(), aEntry->mHostWithPort.Length(), &rv);
344 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
345 rawStreamPtr->Write(settings.mFingerprintAlgOID.get(),
346 settings.mFingerprintAlgOID.Length(), &rv);
347 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
348 rawStreamPtr->Write(settings.mFingerprint.get(),
349 settings.mFingerprint.Length(), &rv);
350 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
351 rawStreamPtr->Write(bits_string.get(),
352 bits_string.Length(), &rv);
353 rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
354 rawStreamPtr->Write(settings.mDBKey.get(), settings.mDBKey.Length(), &rv);
355 rawStreamPtr->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &rv);
358 return PL_DHASH_NEXT;
361 nsresult
362 nsCertOverrideService::Write()
364 nsAutoMonitor lock(monitor);
366 if (!mSettingsFile) {
367 return NS_ERROR_NULL_POINTER;
370 nsresult rv;
371 nsCOMPtr<nsIOutputStream> fileOutputStream;
372 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
373 mSettingsFile,
375 0600);
376 if (NS_FAILED(rv)) {
377 NS_ERROR("failed to open cert_warn_settings.txt for writing");
378 return rv;
381 // get a buffered output stream 4096 bytes big, to optimize writes
382 nsCOMPtr<nsIOutputStream> bufferedOutputStream;
383 rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), fileOutputStream, 4096);
384 if (NS_FAILED(rv)) {
385 return rv;
388 static const char kHeader[] =
389 "# PSM Certificate Override Settings file" NS_LINEBREAK
390 "# This is a generated file! Do not edit." NS_LINEBREAK;
392 /* see ::Read for file format */
394 bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &rv);
396 nsIOutputStream *rawStreamPtr = bufferedOutputStream;
397 mSettingsTable.EnumerateEntries(WriteEntryCallback, rawStreamPtr);
399 // All went ok. Maybe except for problems in Write(), but the stream detects
400 // that for us
401 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
402 NS_ASSERTION(safeStream, "expected a safe output stream!");
403 if (safeStream) {
404 rv = safeStream->Finish();
405 if (NS_FAILED(rv)) {
406 NS_WARNING("failed to save cert warn settings file! possible dataloss");
407 return rv;
411 return NS_OK;
414 static nsresult
415 GetCertFingerprintByOidTag(CERTCertificate* nsscert,
416 SECOidTag aOidTag,
417 nsCString &fp)
419 unsigned int hash_len = HASH_ResultLenByOidTag(aOidTag);
420 nsRefPtr<nsStringBuffer> fingerprint = nsStringBuffer::Alloc(hash_len);
421 if (!fingerprint)
422 return NS_ERROR_OUT_OF_MEMORY;
424 PK11_HashBuf(aOidTag, (unsigned char*)fingerprint->Data(),
425 nsscert->derCert.data, nsscert->derCert.len);
427 SECItem fpItem;
428 fpItem.data = (unsigned char*)fingerprint->Data();
429 fpItem.len = hash_len;
431 fp.Adopt(CERT_Hexify(&fpItem, 1));
432 return NS_OK;
435 static nsresult
436 GetCertFingerprintByOidTag(nsIX509Cert *aCert,
437 SECOidTag aOidTag,
438 nsCString &fp)
440 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
441 if (!cert2)
442 return NS_ERROR_FAILURE;
444 CERTCertificate* nsscert = cert2->GetCert();
445 if (!nsscert)
446 return NS_ERROR_FAILURE;
448 CERTCertificateCleaner nsscertCleaner(nsscert);
449 return GetCertFingerprintByOidTag(nsscert, aOidTag, fp);
452 static nsresult
453 GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
454 const nsCString &dottedOid,
455 nsCString &fp)
457 SECItem oid;
458 oid.data = nsnull;
459 oid.len = 0;
460 SECStatus srv = SEC_StringToOID(nsnull, &oid,
461 dottedOid.get(), dottedOid.Length());
462 if (srv != SECSuccess)
463 return NS_ERROR_FAILURE;
465 SECOidTag oid_tag = SECOID_FindOIDTag(&oid);
466 SECITEM_FreeItem(&oid, PR_FALSE);
468 if (oid_tag == SEC_OID_UNKNOWN)
469 return NS_ERROR_FAILURE;
471 return GetCertFingerprintByOidTag(nsscert, oid_tag, fp);
474 static nsresult
475 GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
476 const nsCString &dottedOid,
477 nsCString &fp)
479 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
480 if (!cert2)
481 return NS_ERROR_FAILURE;
483 CERTCertificate* nsscert = cert2->GetCert();
484 if (!nsscert)
485 return NS_ERROR_FAILURE;
487 CERTCertificateCleaner nsscertCleaner(nsscert);
488 return GetCertFingerprintByDottedOidString(nsscert, dottedOid, fp);
491 NS_IMETHODIMP
492 nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, PRInt32 aPort,
493 nsIX509Cert *aCert,
494 PRUint32 aOverrideBits,
495 PRBool aTemporary)
497 NS_ENSURE_ARG_POINTER(aCert);
498 if (aHostName.IsEmpty())
499 return NS_ERROR_INVALID_ARG;
500 if (aPort < -1)
501 return NS_ERROR_INVALID_ARG;
503 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
504 if (!cert2)
505 return NS_ERROR_FAILURE;
507 CERTCertificate* nsscert = cert2->GetCert();
508 if (!nsscert)
509 return NS_ERROR_FAILURE;
511 CERTCertificateCleaner nsscertCleaner(nsscert);
513 nsCAutoString nickname;
514 nickname = nsNSSCertificate::defaultServerNickname(nsscert);
515 if (!aTemporary && !nickname.IsEmpty())
517 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
518 if (!slot)
519 return NS_ERROR_FAILURE;
521 SECStatus srv = PK11_ImportCert(slot, nsscert, CK_INVALID_HANDLE,
522 const_cast<char*>(nickname.get()), PR_FALSE);
523 PK11_FreeSlot(slot);
525 if (srv != SECSuccess)
526 return NS_ERROR_FAILURE;
529 nsCAutoString fpStr;
530 nsresult rv = GetCertFingerprintByOidTag(nsscert,
531 mOidTagForStoringNewHashes, fpStr);
532 if (NS_FAILED(rv))
533 return rv;
535 char *dbkey = NULL;
536 rv = aCert->GetDbKey(&dbkey);
537 if (NS_FAILED(rv) || !dbkey)
538 return rv;
540 // change \n and \r to spaces in the possibly multi-line-base64-encoded key
541 for (char *dbkey_walk = dbkey;
542 *dbkey_walk;
543 ++dbkey_walk) {
544 char c = *dbkey_walk;
545 if (c == '\r' || c == '\n') {
546 *dbkey_walk = ' ';
551 nsAutoMonitor lock(monitor);
552 AddEntryToList(aHostName, aPort,
553 aTemporary ? aCert : nsnull,
554 // keep a reference to the cert for temporary overrides
555 aTemporary,
556 mDottedOidForStoringNewHashes, fpStr,
557 (nsCertOverride::OverrideBits)aOverrideBits,
558 nsDependentCString(dbkey));
559 Write();
562 PR_Free(dbkey);
563 return NS_OK;
566 NS_IMETHODIMP
567 nsCertOverrideService::HasMatchingOverride(const nsACString & aHostName, PRInt32 aPort,
568 nsIX509Cert *aCert,
569 PRUint32 *aOverrideBits,
570 PRBool *aIsTemporary,
571 PRBool *_retval)
573 if (aHostName.IsEmpty())
574 return NS_ERROR_INVALID_ARG;
575 if (aPort < -1)
576 return NS_ERROR_INVALID_ARG;
578 NS_ENSURE_ARG_POINTER(aCert);
579 NS_ENSURE_ARG_POINTER(aOverrideBits);
580 NS_ENSURE_ARG_POINTER(aIsTemporary);
581 NS_ENSURE_ARG_POINTER(_retval);
582 *_retval = PR_FALSE;
583 *aOverrideBits = nsCertOverride::ob_None;
585 nsCAutoString hostPort;
586 GetHostWithPort(aHostName, aPort, hostPort);
587 nsCertOverride settings;
590 nsAutoMonitor lock(monitor);
591 nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
593 if (!entry)
594 return NS_OK;
596 settings = entry->mSettings; // copy
599 *aOverrideBits = settings.mOverrideBits;
600 *aIsTemporary = settings.mIsTemporary;
602 nsCAutoString fpStr;
603 nsresult rv;
605 if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
606 rv = GetCertFingerprintByOidTag(aCert, mOidTagForStoringNewHashes, fpStr);
608 else {
609 rv = GetCertFingerprintByDottedOidString(aCert, settings.mFingerprintAlgOID, fpStr);
611 if (NS_FAILED(rv))
612 return rv;
614 *_retval = settings.mFingerprint.Equals(fpStr);
615 return NS_OK;
618 NS_IMETHODIMP
619 nsCertOverrideService::GetValidityOverride(const nsACString & aHostName, PRInt32 aPort,
620 nsACString & aHashAlg,
621 nsACString & aFingerprint,
622 PRUint32 *aOverrideBits,
623 PRBool *aIsTemporary,
624 PRBool *_found)
626 NS_ENSURE_ARG_POINTER(_found);
627 NS_ENSURE_ARG_POINTER(aIsTemporary);
628 NS_ENSURE_ARG_POINTER(aOverrideBits);
629 *_found = PR_FALSE;
630 *aOverrideBits = nsCertOverride::ob_None;
632 nsCAutoString hostPort;
633 GetHostWithPort(aHostName, aPort, hostPort);
634 nsCertOverride settings;
637 nsAutoMonitor lock(monitor);
638 nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
640 if (entry) {
641 *_found = PR_TRUE;
642 settings = entry->mSettings; // copy
646 if (*_found) {
647 *aOverrideBits = settings.mOverrideBits;
648 *aIsTemporary = settings.mIsTemporary;
649 aFingerprint = settings.mFingerprint;
650 aHashAlg = settings.mFingerprintAlgOID;
653 return NS_OK;
656 nsresult
657 nsCertOverrideService::AddEntryToList(const nsACString &aHostName, PRInt32 aPort,
658 nsIX509Cert *aCert,
659 const PRBool aIsTemporary,
660 const nsACString &fingerprintAlgOID,
661 const nsACString &fingerprint,
662 nsCertOverride::OverrideBits ob,
663 const nsACString &dbKey)
665 nsCAutoString hostPort;
666 GetHostWithPort(aHostName, aPort, hostPort);
669 nsAutoMonitor lock(monitor);
670 nsCertOverrideEntry *entry = mSettingsTable.PutEntry(hostPort.get());
672 if (!entry) {
673 NS_ERROR("can't insert a null entry!");
674 return NS_ERROR_OUT_OF_MEMORY;
677 entry->mHostWithPort = hostPort;
679 nsCertOverride &settings = entry->mSettings;
680 settings.mAsciiHost = aHostName;
681 settings.mPort = aPort;
682 settings.mIsTemporary = aIsTemporary;
683 settings.mFingerprintAlgOID = fingerprintAlgOID;
684 settings.mFingerprint = fingerprint;
685 settings.mOverrideBits = ob;
686 settings.mDBKey = dbKey;
687 settings.mCert = aCert;
690 return NS_OK;
693 NS_IMETHODIMP
694 nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, PRInt32 aPort)
696 nsCAutoString hostPort;
697 GetHostWithPort(aHostName, aPort, hostPort);
699 nsAutoMonitor lock(monitor);
700 mSettingsTable.RemoveEntry(hostPort.get());
701 Write();
703 SSL_ClearSessionCache();
704 return NS_OK;
707 NS_IMETHODIMP
708 nsCertOverrideService::GetAllOverrideHostsWithPorts(PRUint32 *aCount,
709 PRUnichar ***aHostsWithPortsArray)
711 return NS_ERROR_NOT_IMPLEMENTED;
714 static PRBool
715 matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
717 char *dbkey = NULL;
718 nsresult rv = cert->GetDbKey(&dbkey);
719 if (NS_FAILED(rv) || !dbkey)
720 return PR_FALSE;
722 PRBool found_mismatch = PR_FALSE;
723 const char *key1 = dbkey;
724 const char *key2 = match_dbkey;
726 // skip over any whitespace when comparing
727 while (*key1 && *key2) {
728 char c1 = *key1;
729 char c2 = *key2;
731 switch (c1) {
732 case ' ':
733 case '\t':
734 case '\n':
735 case '\r':
736 ++key1;
737 continue;
740 switch (c2) {
741 case ' ':
742 case '\t':
743 case '\n':
744 case '\r':
745 ++key2;
746 continue;
749 if (c1 != c2) {
750 found_mismatch = PR_TRUE;
751 break;
754 ++key1;
755 ++key2;
758 PR_Free(dbkey);
759 return !found_mismatch;
762 struct nsCertAndBoolsAndInt
764 nsIX509Cert *cert;
765 PRBool aCheckTemporaries;
766 PRBool aCheckPermanents;
767 PRUint32 counter;
769 SECOidTag mOidTagForStoringNewHashes;
770 nsCString mDottedOidForStoringNewHashes;
773 PR_STATIC_CALLBACK(PLDHashOperator)
774 FindMatchingCertCallback(nsCertOverrideEntry *aEntry,
775 void *aArg)
777 nsCertAndBoolsAndInt *cai = (nsCertAndBoolsAndInt *)aArg;
779 if (cai && aEntry)
781 const nsCertOverride &settings = aEntry->mSettings;
782 PRBool still_ok = PR_TRUE;
784 if ((settings.mIsTemporary && !cai->aCheckTemporaries)
786 (!settings.mIsTemporary && !cai->aCheckPermanents)) {
787 still_ok = PR_FALSE;
790 if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
791 nsCAutoString cert_fingerprint;
792 nsresult rv;
793 if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
794 rv = GetCertFingerprintByOidTag(cai->cert,
795 cai->mOidTagForStoringNewHashes, cert_fingerprint);
797 else {
798 rv = GetCertFingerprintByDottedOidString(cai->cert,
799 settings.mFingerprintAlgOID, cert_fingerprint);
801 if (NS_SUCCEEDED(rv) &&
802 settings.mFingerprint.Equals(cert_fingerprint)) {
803 cai->counter++;
808 return PL_DHASH_NEXT;
811 NS_IMETHODIMP
812 nsCertOverrideService::IsCertUsedForOverrides(nsIX509Cert *aCert,
813 PRBool aCheckTemporaries,
814 PRBool aCheckPermanents,
815 PRUint32 *_retval)
817 NS_ENSURE_ARG(aCert);
818 NS_ENSURE_ARG(_retval);
820 nsCertAndBoolsAndInt cai;
821 cai.cert = aCert;
822 cai.aCheckTemporaries = aCheckTemporaries;
823 cai.aCheckPermanents = aCheckPermanents;
824 cai.counter = 0;
825 cai.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
826 cai.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;
829 nsAutoMonitor lock(monitor);
830 mSettingsTable.EnumerateEntries(FindMatchingCertCallback, &cai);
832 *_retval = cai.counter;
833 return NS_OK;
836 struct nsCertAndPointerAndCallback
838 nsIX509Cert *cert;
839 void *userdata;
840 nsCertOverrideService::CertOverrideEnumerator enumerator;
842 SECOidTag mOidTagForStoringNewHashes;
843 nsCString mDottedOidForStoringNewHashes;
846 PR_STATIC_CALLBACK(PLDHashOperator)
847 EnumerateCertOverridesCallback(nsCertOverrideEntry *aEntry,
848 void *aArg)
850 nsCertAndPointerAndCallback *capac = (nsCertAndPointerAndCallback *)aArg;
852 if (capac && aEntry)
854 const nsCertOverride &settings = aEntry->mSettings;
856 if (!capac->cert) {
857 (*capac->enumerator)(settings, capac->userdata);
859 else {
860 if (matchesDBKey(capac->cert, settings.mDBKey.get())) {
861 nsCAutoString cert_fingerprint;
862 nsresult rv;
863 if (settings.mFingerprintAlgOID.Equals(capac->mDottedOidForStoringNewHashes)) {
864 rv = GetCertFingerprintByOidTag(capac->cert,
865 capac->mOidTagForStoringNewHashes, cert_fingerprint);
867 else {
868 rv = GetCertFingerprintByDottedOidString(capac->cert,
869 settings.mFingerprintAlgOID, cert_fingerprint);
871 if (NS_SUCCEEDED(rv) &&
872 settings.mFingerprint.Equals(cert_fingerprint)) {
873 (*capac->enumerator)(settings, capac->userdata);
879 return PL_DHASH_NEXT;
882 nsresult
883 nsCertOverrideService::EnumerateCertOverrides(nsIX509Cert *aCert,
884 CertOverrideEnumerator enumerator,
885 void *aUserData)
887 nsCertAndPointerAndCallback capac;
888 capac.cert = aCert;
889 capac.userdata = aUserData;
890 capac.enumerator = enumerator;
891 capac.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
892 capac.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;
895 nsAutoMonitor lock(monitor);
896 mSettingsTable.EnumerateEntries(EnumerateCertOverridesCallback, &capac);
898 return NS_OK;
901 void
902 nsCertOverrideService::GetHostWithPort(const nsACString & aHostName, PRInt32 aPort, nsACString& _retval)
904 nsCAutoString hostPort(aHostName);
905 if (aPort == -1)
906 aPort = 443;
907 hostPort.AppendLiteral(":");
908 hostPort.AppendInt(aPort);
910 _retval.Assign(hostPort);