security/manager/ssl/src/nsCertOverrideService.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial