LCOV - code coverage report
Current view: directory - security/manager/ssl/src - nsCertOverrideService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 421 56 13.3 %
Date: 2012-06-02 Functions: 37 11 29.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       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/
      10                 :  *
      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.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      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.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Kai Engert <kengert@redhat.com>
      25                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      26                 :  *
      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.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      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 "nsThreadUtils.h"
      54                 : #include "nsStringBuffer.h"
      55                 : #include "nsAutoPtr.h"
      56                 : #include "nspr.h"
      57                 : #include "pk11pub.h"
      58                 : #include "certdb.h"
      59                 : #include "sechash.h"
      60                 : #include "ssl.h" // For SSL_ClearSessionCache
      61                 : 
      62                 : #include "nsNSSCleaner.h"
      63               0 : NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
      64                 : 
      65                 : using namespace mozilla;
      66                 : 
      67                 : static const char kCertOverrideFileName[] = "cert_override.txt";
      68                 : 
      69                 : void
      70               0 : nsCertOverride::convertBitsToString(OverrideBits ob, nsACString &str)
      71                 : {
      72               0 :   str.Truncate();
      73                 : 
      74               0 :   if (ob & ob_Mismatch)
      75               0 :     str.Append('M');
      76                 : 
      77               0 :   if (ob & ob_Untrusted)
      78               0 :     str.Append('U');
      79                 : 
      80               0 :   if (ob & ob_Time_error)
      81               0 :     str.Append('T');
      82               0 : }
      83                 : 
      84                 : void
      85               0 : nsCertOverride::convertStringToBits(const nsACString &str, OverrideBits &ob)
      86                 : {
      87               0 :   const nsPromiseFlatCString &flat = PromiseFlatCString(str);
      88               0 :   const char *walk = flat.get();
      89                 : 
      90               0 :   ob = ob_None;
      91                 : 
      92               0 :   for ( ; *walk; ++walk)
      93                 :   {
      94               0 :     switch (*walk)
      95                 :     {
      96                 :       case 'm':
      97                 :       case 'M':
      98               0 :         ob = (OverrideBits)(ob | ob_Mismatch);
      99               0 :         break;
     100                 : 
     101                 :       case 'u':
     102                 :       case 'U':
     103               0 :         ob = (OverrideBits)(ob | ob_Untrusted);
     104               0 :         break;
     105                 : 
     106                 :       case 't':
     107                 :       case 'T':
     108               0 :         ob = (OverrideBits)(ob | ob_Time_error);
     109               0 :         break;
     110                 : 
     111                 :       default:
     112               0 :         break;
     113                 :     }
     114                 :   }
     115               0 : }
     116                 : 
     117            1335 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsCertOverrideService, 
     118                 :                               nsICertOverrideService,
     119                 :                               nsIObserver,
     120                 :                               nsISupportsWeakReference)
     121                 : 
     122              35 : nsCertOverrideService::nsCertOverrideService()
     123              35 :   : monitor("nsCertOverrideService.monitor")
     124                 : {
     125              35 : }
     126                 : 
     127              35 : nsCertOverrideService::~nsCertOverrideService()
     128                 : {
     129              35 : }
     130                 : 
     131                 : nsresult
     132              35 : nsCertOverrideService::Init()
     133                 : {
     134              35 :   if (!NS_IsMainThread()) {
     135               0 :     NS_NOTREACHED("nsCertOverrideService initialized off main thread");
     136               0 :     return NS_ERROR_NOT_SAME_THREAD;
     137                 :   }
     138                 : 
     139              35 :   if (!mSettingsTable.Init())
     140               0 :     return NS_ERROR_OUT_OF_MEMORY;
     141                 : 
     142              35 :   mOidTagForStoringNewHashes = SEC_OID_SHA256;
     143                 : 
     144              35 :   SECOidData *od = SECOID_FindOIDByTag(mOidTagForStoringNewHashes);
     145              35 :   if (!od)
     146               0 :     return NS_ERROR_FAILURE;
     147                 : 
     148              35 :   char *dotted_oid = CERT_GetOidString(&od->oid);
     149              35 :   if (!dotted_oid)
     150               0 :     return NS_ERROR_FAILURE;
     151                 : 
     152              35 :   mDottedOidForStoringNewHashes = dotted_oid;
     153              35 :   PR_smprintf_free(dotted_oid);
     154                 : 
     155                 :   nsCOMPtr<nsIObserverService> observerService =
     156              70 :       mozilla::services::GetObserverService();
     157                 : 
     158                 :   // If we cannot add ourselves as a profile change observer, then we will not
     159                 :   // attempt to read/write any settings file. Otherwise, we would end up
     160                 :   // reading/writing the wrong settings file after a profile change.
     161              35 :   if (observerService) {
     162              35 :     observerService->AddObserver(this, "profile-before-change", true);
     163              35 :     observerService->AddObserver(this, "profile-do-change", true);
     164                 :     // simulate a profile change so we read the current profile's settings file
     165              35 :     Observe(nsnull, "profile-do-change", nsnull);
     166                 :   }
     167                 : 
     168              35 :   return NS_OK;
     169                 : }
     170                 : 
     171                 : NS_IMETHODIMP
     172              65 : nsCertOverrideService::Observe(nsISupports     *,
     173                 :                                const char      *aTopic,
     174                 :                                const PRUnichar *aData)
     175                 : {
     176                 :   // check the topic
     177              65 :   if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
     178                 :     // The profile is about to change,
     179                 :     // or is going away because the application is shutting down.
     180                 : 
     181              60 :     ReentrantMonitorAutoEnter lock(monitor);
     182                 : 
     183              30 :     if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
     184               0 :       RemoveAllFromMemory();
     185                 :       // delete the storage file
     186               0 :       if (mSettingsFile) {
     187               0 :         mSettingsFile->Remove(false);
     188                 :       }
     189                 :     } else {
     190              30 :       RemoveAllFromMemory();
     191                 :     }
     192                 : 
     193              35 :   } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
     194                 :     // The profile has already changed.
     195                 :     // Now read from the new profile location.
     196                 :     // we also need to update the cached file location
     197                 : 
     198              70 :     ReentrantMonitorAutoEnter lock(monitor);
     199                 : 
     200              35 :     nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mSettingsFile));
     201              35 :     if (NS_SUCCEEDED(rv)) {
     202              32 :       mSettingsFile->AppendNative(NS_LITERAL_CSTRING(kCertOverrideFileName));
     203                 :     } else {
     204               3 :       mSettingsFile = nsnull;
     205                 :     }
     206              35 :     Read();
     207                 : 
     208                 :   }
     209                 : 
     210              65 :   return NS_OK;
     211                 : }
     212                 : 
     213                 : void
     214              30 : nsCertOverrideService::RemoveAllFromMemory()
     215                 : {
     216              60 :   ReentrantMonitorAutoEnter lock(monitor);
     217              30 :   mSettingsTable.Clear();
     218              30 : }
     219                 : 
     220                 : PR_STATIC_CALLBACK(PLDHashOperator)
     221               0 : RemoveTemporariesCallback(nsCertOverrideEntry *aEntry,
     222                 :                           void *aArg)
     223                 : {
     224               0 :   if (aEntry && aEntry->mSettings.mIsTemporary) {
     225               0 :     aEntry->mSettings.mCert = nsnull;
     226               0 :     return PL_DHASH_REMOVE;
     227                 :   }
     228                 : 
     229               0 :   return PL_DHASH_NEXT;
     230                 : }
     231                 : 
     232                 : void
     233             142 : nsCertOverrideService::RemoveAllTemporaryOverrides()
     234                 : {
     235                 :   {
     236             284 :     ReentrantMonitorAutoEnter lock(monitor);
     237             142 :     mSettingsTable.EnumerateEntries(RemoveTemporariesCallback, nsnull);
     238                 :     // no need to write, as temporaries are never written to disk
     239                 :   }
     240             142 : }
     241                 : 
     242                 : nsresult
     243              35 : nsCertOverrideService::Read()
     244                 : {
     245              70 :   ReentrantMonitorAutoEnter lock(monitor);
     246                 : 
     247                 :   // If we don't have a profile, then we won't try to read any settings file.
     248              35 :   if (!mSettingsFile)
     249               3 :     return NS_OK;
     250                 : 
     251                 :   nsresult rv;
     252              64 :   nsCOMPtr<nsIInputStream> fileInputStream;
     253              32 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mSettingsFile);
     254              32 :   if (NS_FAILED(rv)) {
     255              32 :     return rv;
     256                 :   }
     257                 : 
     258               0 :   nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
     259               0 :   if (NS_FAILED(rv)) {
     260               0 :     return rv;
     261                 :   }
     262                 : 
     263               0 :   nsCAutoString buffer;
     264               0 :   bool isMore = true;
     265               0 :   PRInt32 hostIndex = 0, algoIndex, fingerprintIndex, overrideBitsIndex, dbKeyIndex;
     266                 : 
     267                 :   /* file format is:
     268                 :    *
     269                 :    * host:port \t fingerprint-algorithm \t fingerprint \t override-mask \t dbKey
     270                 :    *
     271                 :    *   where override-mask is a sequence of characters,
     272                 :    *     M meaning hostname-Mismatch-override
     273                 :    *     U meaning Untrusted-override
     274                 :    *     T meaning Time-error-override (expired/not yet valid) 
     275                 :    *
     276                 :    * if this format isn't respected we move onto the next line in the file.
     277                 :    */
     278                 : 
     279               0 :   while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
     280               0 :     if (buffer.IsEmpty() || buffer.First() == '#') {
     281               0 :       continue;
     282                 :     }
     283                 : 
     284                 :     // this is a cheap, cheesy way of parsing a tab-delimited line into
     285                 :     // string indexes, which can be lopped off into substrings. just for
     286                 :     // purposes of obfuscation, it also checks that each token was found.
     287                 :     // todo: use iterators?
     288               0 :     if ((algoIndex         = buffer.FindChar('\t', hostIndex)         + 1) == 0 ||
     289               0 :         (fingerprintIndex  = buffer.FindChar('\t', algoIndex)         + 1) == 0 ||
     290               0 :         (overrideBitsIndex = buffer.FindChar('\t', fingerprintIndex)  + 1) == 0 ||
     291               0 :         (dbKeyIndex        = buffer.FindChar('\t', overrideBitsIndex) + 1) == 0) {
     292               0 :       continue;
     293                 :     }
     294                 : 
     295               0 :     const nsASingleFragmentCString &tmp = Substring(buffer, hostIndex, algoIndex - hostIndex - 1);
     296               0 :     const nsASingleFragmentCString &algo_string = Substring(buffer, algoIndex, fingerprintIndex - algoIndex - 1);
     297               0 :     const nsASingleFragmentCString &fingerprint = Substring(buffer, fingerprintIndex, overrideBitsIndex - fingerprintIndex - 1);
     298               0 :     const nsASingleFragmentCString &bits_string = Substring(buffer, overrideBitsIndex, dbKeyIndex - overrideBitsIndex - 1);
     299               0 :     const nsASingleFragmentCString &db_key = Substring(buffer, dbKeyIndex, buffer.Length() - dbKeyIndex);
     300                 : 
     301               0 :     nsCAutoString host(tmp);
     302                 :     nsCertOverride::OverrideBits bits;
     303               0 :     nsCertOverride::convertStringToBits(bits_string, bits);
     304                 : 
     305                 :     PRInt32 port;
     306               0 :     PRInt32 portIndex = host.RFindChar(':');
     307               0 :     if (portIndex == kNotFound)
     308               0 :       continue; // Ignore broken entries
     309                 : 
     310                 :     PRInt32 portParseError;
     311               0 :     nsCAutoString portString(Substring(host, portIndex+1));
     312               0 :     port = portString.ToInteger(&portParseError);
     313               0 :     if (portParseError)
     314               0 :       continue; // Ignore broken entries
     315                 : 
     316               0 :     host.Truncate(portIndex);
     317                 :     
     318                 :     AddEntryToList(host, port, 
     319                 :                    nsnull, // don't have the cert
     320                 :                    false, // not temporary
     321               0 :                    algo_string, fingerprint, bits, db_key);
     322                 :   }
     323                 : 
     324               0 :   return NS_OK;
     325                 : }
     326                 : 
     327                 : PR_STATIC_CALLBACK(PLDHashOperator)
     328               0 : WriteEntryCallback(nsCertOverrideEntry *aEntry,
     329                 :                    void *aArg)
     330                 : {
     331                 :   static const char kTab[] = "\t";
     332                 : 
     333               0 :   nsIOutputStream *rawStreamPtr = (nsIOutputStream *)aArg;
     334                 : 
     335                 :   nsresult rv;
     336                 : 
     337               0 :   if (rawStreamPtr && aEntry)
     338                 :   {
     339               0 :     const nsCertOverride &settings = aEntry->mSettings;
     340               0 :     if (settings.mIsTemporary)
     341               0 :       return PL_DHASH_NEXT;
     342                 : 
     343               0 :     nsCAutoString bits_string;
     344                 :     nsCertOverride::convertBitsToString(settings.mOverrideBits, 
     345               0 :                                             bits_string);
     346                 : 
     347               0 :     rawStreamPtr->Write(aEntry->mHostWithPort.get(), aEntry->mHostWithPort.Length(), &rv);
     348               0 :     rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
     349                 :     rawStreamPtr->Write(settings.mFingerprintAlgOID.get(), 
     350               0 :                         settings.mFingerprintAlgOID.Length(), &rv);
     351               0 :     rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
     352                 :     rawStreamPtr->Write(settings.mFingerprint.get(), 
     353               0 :                         settings.mFingerprint.Length(), &rv);
     354               0 :     rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
     355                 :     rawStreamPtr->Write(bits_string.get(), 
     356               0 :                         bits_string.Length(), &rv);
     357               0 :     rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
     358               0 :     rawStreamPtr->Write(settings.mDBKey.get(), settings.mDBKey.Length(), &rv);
     359               0 :     rawStreamPtr->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &rv);
     360                 :   }
     361                 : 
     362               0 :   return PL_DHASH_NEXT;
     363                 : }
     364                 : 
     365                 : nsresult
     366               0 : nsCertOverrideService::Write()
     367                 : {
     368               0 :   ReentrantMonitorAutoEnter lock(monitor);
     369                 : 
     370                 :   // If we don't have any profile, then we won't try to write any file
     371               0 :   if (!mSettingsFile) {
     372               0 :     return NS_OK;
     373                 :   }
     374                 : 
     375                 :   nsresult rv;
     376               0 :   nsCOMPtr<nsIOutputStream> fileOutputStream;
     377               0 :   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
     378                 :                                        mSettingsFile,
     379                 :                                        -1,
     380               0 :                                        0600);
     381               0 :   if (NS_FAILED(rv)) {
     382               0 :     NS_ERROR("failed to open cert_warn_settings.txt for writing");
     383               0 :     return rv;
     384                 :   }
     385                 : 
     386                 :   // get a buffered output stream 4096 bytes big, to optimize writes
     387               0 :   nsCOMPtr<nsIOutputStream> bufferedOutputStream;
     388               0 :   rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), fileOutputStream, 4096);
     389               0 :   if (NS_FAILED(rv)) {
     390               0 :     return rv;
     391                 :   }
     392                 : 
     393                 :   static const char kHeader[] =
     394                 :       "# PSM Certificate Override Settings file" NS_LINEBREAK
     395                 :       "# This is a generated file!  Do not edit." NS_LINEBREAK;
     396                 : 
     397                 :   /* see ::Read for file format */
     398                 : 
     399               0 :   bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &rv);
     400                 : 
     401               0 :   nsIOutputStream *rawStreamPtr = bufferedOutputStream;
     402               0 :   mSettingsTable.EnumerateEntries(WriteEntryCallback, rawStreamPtr);
     403                 : 
     404                 :   // All went ok. Maybe except for problems in Write(), but the stream detects
     405                 :   // that for us
     406               0 :   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
     407               0 :   NS_ASSERTION(safeStream, "expected a safe output stream!");
     408               0 :   if (safeStream) {
     409               0 :     rv = safeStream->Finish();
     410               0 :     if (NS_FAILED(rv)) {
     411               0 :       NS_WARNING("failed to save cert warn settings file! possible dataloss");
     412               0 :       return rv;
     413                 :     }
     414                 :   }
     415                 : 
     416               0 :   return NS_OK;
     417                 : }
     418                 : 
     419                 : static nsresult
     420               0 : GetCertFingerprintByOidTag(CERTCertificate* nsscert,
     421                 :                            SECOidTag aOidTag, 
     422                 :                            nsCString &fp)
     423                 : {
     424               0 :   unsigned int hash_len = HASH_ResultLenByOidTag(aOidTag);
     425               0 :   nsStringBuffer* fingerprint = nsStringBuffer::Alloc(hash_len);
     426               0 :   if (!fingerprint)
     427               0 :     return NS_ERROR_OUT_OF_MEMORY;
     428                 : 
     429               0 :   PK11_HashBuf(aOidTag, (unsigned char*)fingerprint->Data(), 
     430               0 :                nsscert->derCert.data, nsscert->derCert.len);
     431                 : 
     432                 :   SECItem fpItem;
     433               0 :   fpItem.data = (unsigned char*)fingerprint->Data();
     434               0 :   fpItem.len = hash_len;
     435                 : 
     436               0 :   char *tmpstr = CERT_Hexify(&fpItem, 1);
     437               0 :   fp.Assign(tmpstr);
     438               0 :   PORT_Free(tmpstr);
     439               0 :   fingerprint->Release();
     440               0 :   return NS_OK;
     441                 : }
     442                 : 
     443                 : static nsresult
     444               0 : GetCertFingerprintByOidTag(nsIX509Cert *aCert,
     445                 :                            SECOidTag aOidTag, 
     446                 :                            nsCString &fp)
     447                 : {
     448               0 :   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
     449               0 :   if (!cert2)
     450               0 :     return NS_ERROR_FAILURE;
     451                 : 
     452               0 :   CERTCertificate* nsscert = cert2->GetCert();
     453               0 :   if (!nsscert)
     454               0 :     return NS_ERROR_FAILURE;
     455                 : 
     456               0 :   CERTCertificateCleaner nsscertCleaner(nsscert);
     457               0 :   return GetCertFingerprintByOidTag(nsscert, aOidTag, fp);
     458                 : }
     459                 : 
     460                 : static nsresult
     461               0 : GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
     462                 :                                     const nsCString &dottedOid, 
     463                 :                                     nsCString &fp)
     464                 : {
     465                 :   SECItem oid;
     466               0 :   oid.data = nsnull;
     467               0 :   oid.len = 0;
     468                 :   SECStatus srv = SEC_StringToOID(nsnull, &oid, 
     469               0 :                     dottedOid.get(), dottedOid.Length());
     470               0 :   if (srv != SECSuccess)
     471               0 :     return NS_ERROR_FAILURE;
     472                 : 
     473               0 :   SECOidTag oid_tag = SECOID_FindOIDTag(&oid);
     474               0 :   SECITEM_FreeItem(&oid, false);
     475                 : 
     476               0 :   if (oid_tag == SEC_OID_UNKNOWN)
     477               0 :     return NS_ERROR_FAILURE;
     478                 : 
     479               0 :   return GetCertFingerprintByOidTag(nsscert, oid_tag, fp);
     480                 : }
     481                 : 
     482                 : static nsresult
     483               0 : GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
     484                 :                                     const nsCString &dottedOid, 
     485                 :                                     nsCString &fp)
     486                 : {
     487               0 :   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
     488               0 :   if (!cert2)
     489               0 :     return NS_ERROR_FAILURE;
     490                 : 
     491               0 :   CERTCertificate* nsscert = cert2->GetCert();
     492               0 :   if (!nsscert)
     493               0 :     return NS_ERROR_FAILURE;
     494                 : 
     495               0 :   CERTCertificateCleaner nsscertCleaner(nsscert);
     496               0 :   return GetCertFingerprintByDottedOidString(nsscert, dottedOid, fp);
     497                 : }
     498                 : 
     499                 : NS_IMETHODIMP
     500               0 : nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, PRInt32 aPort, 
     501                 :                                                 nsIX509Cert *aCert,
     502                 :                                                 PRUint32 aOverrideBits, 
     503                 :                                                 bool aTemporary)
     504                 : {
     505               0 :   NS_ENSURE_ARG_POINTER(aCert);
     506               0 :   if (aHostName.IsEmpty())
     507               0 :     return NS_ERROR_INVALID_ARG;
     508               0 :   if (aPort < -1)
     509               0 :     return NS_ERROR_INVALID_ARG;
     510                 : 
     511               0 :   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
     512               0 :   if (!cert2)
     513               0 :     return NS_ERROR_FAILURE;
     514                 : 
     515               0 :   CERTCertificate* nsscert = cert2->GetCert();
     516               0 :   if (!nsscert)
     517               0 :     return NS_ERROR_FAILURE;
     518                 : 
     519               0 :   CERTCertificateCleaner nsscertCleaner(nsscert);
     520                 : 
     521               0 :   char* nickname = nsNSSCertificate::defaultServerNickname(nsscert);
     522               0 :   if (!aTemporary && nickname && *nickname)
     523                 :   {
     524               0 :     PK11SlotInfo *slot = PK11_GetInternalKeySlot();
     525               0 :     if (!slot) {
     526               0 :       PR_Free(nickname);
     527               0 :       return NS_ERROR_FAILURE;
     528                 :     }
     529                 :   
     530                 :     SECStatus srv = PK11_ImportCert(slot, nsscert, CK_INVALID_HANDLE, 
     531               0 :                                     nickname, false);
     532               0 :     PK11_FreeSlot(slot);
     533                 :   
     534               0 :     if (srv != SECSuccess) {
     535               0 :       PR_Free(nickname);
     536               0 :       return NS_ERROR_FAILURE;
     537                 :     }
     538                 :   }
     539               0 :   PR_FREEIF(nickname);
     540                 : 
     541               0 :   nsCAutoString fpStr;
     542                 :   nsresult rv = GetCertFingerprintByOidTag(nsscert, 
     543               0 :                   mOidTagForStoringNewHashes, fpStr);
     544               0 :   if (NS_FAILED(rv))
     545               0 :     return rv;
     546                 : 
     547               0 :   char *dbkey = NULL;
     548               0 :   rv = aCert->GetDbKey(&dbkey);
     549               0 :   if (NS_FAILED(rv) || !dbkey)
     550               0 :     return rv;
     551                 : 
     552                 :   // change \n and \r to spaces in the possibly multi-line-base64-encoded key
     553               0 :   for (char *dbkey_walk = dbkey;
     554                 :        *dbkey_walk;
     555                 :       ++dbkey_walk) {
     556               0 :     char c = *dbkey_walk;
     557               0 :     if (c == '\r' || c == '\n') {
     558               0 :       *dbkey_walk = ' ';
     559                 :     }
     560                 :   }
     561                 : 
     562                 :   {
     563               0 :     ReentrantMonitorAutoEnter lock(monitor);
     564                 :     AddEntryToList(aHostName, aPort,
     565                 :                    aTemporary ? aCert : nsnull,
     566                 :                      // keep a reference to the cert for temporary overrides
     567                 :                    aTemporary, 
     568                 :                    mDottedOidForStoringNewHashes, fpStr, 
     569                 :                    (nsCertOverride::OverrideBits)aOverrideBits, 
     570               0 :                    nsDependentCString(dbkey));
     571               0 :     Write();
     572                 :   }
     573                 : 
     574               0 :   PR_Free(dbkey);
     575               0 :   return NS_OK;
     576                 : }
     577                 : 
     578                 : NS_IMETHODIMP
     579               0 : nsCertOverrideService::HasMatchingOverride(const nsACString & aHostName, PRInt32 aPort,
     580                 :                                            nsIX509Cert *aCert, 
     581                 :                                            PRUint32 *aOverrideBits,
     582                 :                                            bool *aIsTemporary,
     583                 :                                            bool *_retval)
     584                 : {
     585               0 :   if (aHostName.IsEmpty())
     586               0 :     return NS_ERROR_INVALID_ARG;
     587               0 :   if (aPort < -1)
     588               0 :     return NS_ERROR_INVALID_ARG;
     589                 : 
     590               0 :   NS_ENSURE_ARG_POINTER(aCert);
     591               0 :   NS_ENSURE_ARG_POINTER(aOverrideBits);
     592               0 :   NS_ENSURE_ARG_POINTER(aIsTemporary);
     593               0 :   NS_ENSURE_ARG_POINTER(_retval);
     594               0 :   *_retval = false;
     595               0 :   *aOverrideBits = nsCertOverride::ob_None;
     596                 : 
     597               0 :   nsCAutoString hostPort;
     598               0 :   GetHostWithPort(aHostName, aPort, hostPort);
     599               0 :   nsCertOverride settings;
     600                 : 
     601                 :   {
     602               0 :     ReentrantMonitorAutoEnter lock(monitor);
     603               0 :     nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
     604                 :   
     605               0 :     if (!entry)
     606               0 :       return NS_OK;
     607                 :   
     608               0 :     settings = entry->mSettings; // copy
     609                 :   }
     610                 : 
     611               0 :   *aOverrideBits = settings.mOverrideBits;
     612               0 :   *aIsTemporary = settings.mIsTemporary;
     613                 : 
     614               0 :   nsCAutoString fpStr;
     615                 :   nsresult rv;
     616                 : 
     617               0 :   if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
     618               0 :     rv = GetCertFingerprintByOidTag(aCert, mOidTagForStoringNewHashes, fpStr);
     619                 :   }
     620                 :   else {
     621               0 :     rv = GetCertFingerprintByDottedOidString(aCert, settings.mFingerprintAlgOID, fpStr);
     622                 :   }
     623               0 :   if (NS_FAILED(rv))
     624               0 :     return rv;
     625                 : 
     626               0 :   *_retval = settings.mFingerprint.Equals(fpStr);
     627               0 :   return NS_OK;
     628                 : }
     629                 : 
     630                 : NS_IMETHODIMP
     631               0 : nsCertOverrideService::GetValidityOverride(const nsACString & aHostName, PRInt32 aPort,
     632                 :                                            nsACString & aHashAlg, 
     633                 :                                            nsACString & aFingerprint, 
     634                 :                                            PRUint32 *aOverrideBits,
     635                 :                                            bool *aIsTemporary,
     636                 :                                            bool *_found)
     637                 : {
     638               0 :   NS_ENSURE_ARG_POINTER(_found);
     639               0 :   NS_ENSURE_ARG_POINTER(aIsTemporary);
     640               0 :   NS_ENSURE_ARG_POINTER(aOverrideBits);
     641               0 :   *_found = false;
     642               0 :   *aOverrideBits = nsCertOverride::ob_None;
     643                 : 
     644               0 :   nsCAutoString hostPort;
     645               0 :   GetHostWithPort(aHostName, aPort, hostPort);
     646               0 :   nsCertOverride settings;
     647                 : 
     648                 :   {
     649               0 :     ReentrantMonitorAutoEnter lock(monitor);
     650               0 :     nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
     651                 :   
     652               0 :     if (entry) {
     653               0 :       *_found = true;
     654               0 :       settings = entry->mSettings; // copy
     655                 :     }
     656                 :   }
     657                 : 
     658               0 :   if (*_found) {
     659               0 :     *aOverrideBits = settings.mOverrideBits;
     660               0 :     *aIsTemporary = settings.mIsTemporary;
     661               0 :     aFingerprint = settings.mFingerprint;
     662               0 :     aHashAlg = settings.mFingerprintAlgOID;
     663                 :   }
     664                 : 
     665               0 :   return NS_OK;
     666                 : }
     667                 : 
     668                 : nsresult
     669               0 : nsCertOverrideService::AddEntryToList(const nsACString &aHostName, PRInt32 aPort,
     670                 :                                       nsIX509Cert *aCert,
     671                 :                                       const bool aIsTemporary,
     672                 :                                       const nsACString &fingerprintAlgOID, 
     673                 :                                       const nsACString &fingerprint,
     674                 :                                       nsCertOverride::OverrideBits ob,
     675                 :                                       const nsACString &dbKey)
     676                 : {
     677               0 :   nsCAutoString hostPort;
     678               0 :   GetHostWithPort(aHostName, aPort, hostPort);
     679                 : 
     680                 :   {
     681               0 :     ReentrantMonitorAutoEnter lock(monitor);
     682               0 :     nsCertOverrideEntry *entry = mSettingsTable.PutEntry(hostPort.get());
     683                 : 
     684               0 :     if (!entry) {
     685               0 :       NS_ERROR("can't insert a null entry!");
     686               0 :       return NS_ERROR_OUT_OF_MEMORY;
     687                 :     }
     688                 : 
     689               0 :     entry->mHostWithPort = hostPort;
     690                 : 
     691               0 :     nsCertOverride &settings = entry->mSettings;
     692               0 :     settings.mAsciiHost = aHostName;
     693               0 :     settings.mPort = aPort;
     694               0 :     settings.mIsTemporary = aIsTemporary;
     695               0 :     settings.mFingerprintAlgOID = fingerprintAlgOID;
     696               0 :     settings.mFingerprint = fingerprint;
     697               0 :     settings.mOverrideBits = ob;
     698               0 :     settings.mDBKey = dbKey;
     699               0 :     settings.mCert = aCert;
     700                 :   }
     701                 : 
     702               0 :   return NS_OK;
     703                 : }
     704                 : 
     705                 : NS_IMETHODIMP
     706             142 : nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, PRInt32 aPort)
     707                 : {
     708             284 :   if (aPort == 0 &&
     709             142 :       aHostName.EqualsLiteral("all:temporary-certificates")) {
     710             142 :     RemoveAllTemporaryOverrides();
     711             142 :     return NS_OK;
     712                 :   }
     713               0 :   nsCAutoString hostPort;
     714               0 :   GetHostWithPort(aHostName, aPort, hostPort);
     715                 :   {
     716               0 :     ReentrantMonitorAutoEnter lock(monitor);
     717               0 :     mSettingsTable.RemoveEntry(hostPort.get());
     718               0 :     Write();
     719                 :   }
     720               0 :   SSL_ClearSessionCache();
     721               0 :   return NS_OK;
     722                 : }
     723                 : 
     724                 : NS_IMETHODIMP
     725               0 : nsCertOverrideService::GetAllOverrideHostsWithPorts(PRUint32 *aCount, 
     726                 :                                                         PRUnichar ***aHostsWithPortsArray)
     727                 : {
     728               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     729                 : }
     730                 : 
     731                 : static bool
     732               0 : matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
     733                 : {
     734               0 :   char *dbkey = NULL;
     735               0 :   nsresult rv = cert->GetDbKey(&dbkey);
     736               0 :   if (NS_FAILED(rv) || !dbkey)
     737               0 :     return false;
     738                 : 
     739               0 :   bool found_mismatch = false;
     740               0 :   const char *key1 = dbkey;
     741               0 :   const char *key2 = match_dbkey;
     742                 : 
     743                 :   // skip over any whitespace when comparing
     744               0 :   while (*key1 && *key2) {
     745               0 :     char c1 = *key1;
     746               0 :     char c2 = *key2;
     747                 :     
     748               0 :     switch (c1) {
     749                 :       case ' ':
     750                 :       case '\t':
     751                 :       case '\n':
     752                 :       case '\r':
     753               0 :         ++key1;
     754               0 :         continue;
     755                 :     }
     756                 : 
     757               0 :     switch (c2) {
     758                 :       case ' ':
     759                 :       case '\t':
     760                 :       case '\n':
     761                 :       case '\r':
     762               0 :         ++key2;
     763               0 :         continue;
     764                 :     }
     765                 : 
     766               0 :     if (c1 != c2) {
     767               0 :       found_mismatch = true;
     768               0 :       break;
     769                 :     }
     770                 : 
     771               0 :     ++key1;
     772               0 :     ++key2;
     773                 :   }
     774                 : 
     775               0 :   PR_Free(dbkey);
     776               0 :   return !found_mismatch;
     777                 : }
     778                 : 
     779                 : struct nsCertAndBoolsAndInt
     780               0 : {
     781                 :   nsIX509Cert *cert;
     782                 :   bool aCheckTemporaries;
     783                 :   bool aCheckPermanents;
     784                 :   PRUint32 counter;
     785                 : 
     786                 :   SECOidTag mOidTagForStoringNewHashes;
     787                 :   nsCString mDottedOidForStoringNewHashes;
     788                 : };
     789                 : 
     790                 : PR_STATIC_CALLBACK(PLDHashOperator)
     791               0 : FindMatchingCertCallback(nsCertOverrideEntry *aEntry,
     792                 :                          void *aArg)
     793                 : {
     794               0 :   nsCertAndBoolsAndInt *cai = (nsCertAndBoolsAndInt *)aArg;
     795                 : 
     796               0 :   if (cai && aEntry)
     797                 :   {
     798               0 :     const nsCertOverride &settings = aEntry->mSettings;
     799               0 :     bool still_ok = true;
     800                 : 
     801               0 :     if ((settings.mIsTemporary && !cai->aCheckTemporaries)
     802                 :         ||
     803               0 :         (!settings.mIsTemporary && !cai->aCheckPermanents)) {
     804               0 :       still_ok = false;
     805                 :     }
     806                 : 
     807               0 :     if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
     808               0 :       nsCAutoString cert_fingerprint;
     809                 :       nsresult rv;
     810               0 :       if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
     811                 :         rv = GetCertFingerprintByOidTag(cai->cert,
     812               0 :                cai->mOidTagForStoringNewHashes, cert_fingerprint);
     813                 :       }
     814                 :       else {
     815                 :         rv = GetCertFingerprintByDottedOidString(cai->cert,
     816               0 :                settings.mFingerprintAlgOID, cert_fingerprint);
     817                 :       }
     818               0 :       if (NS_SUCCEEDED(rv) &&
     819               0 :           settings.mFingerprint.Equals(cert_fingerprint)) {
     820               0 :         cai->counter++;
     821                 :       }
     822                 :     }
     823                 :   }
     824                 : 
     825               0 :   return PL_DHASH_NEXT;
     826                 : }
     827                 : 
     828                 : NS_IMETHODIMP
     829               0 : nsCertOverrideService::IsCertUsedForOverrides(nsIX509Cert *aCert, 
     830                 :                                               bool aCheckTemporaries,
     831                 :                                               bool aCheckPermanents,
     832                 :                                               PRUint32 *_retval)
     833                 : {
     834               0 :   NS_ENSURE_ARG(aCert);
     835               0 :   NS_ENSURE_ARG(_retval);
     836                 : 
     837               0 :   nsCertAndBoolsAndInt cai;
     838               0 :   cai.cert = aCert;
     839               0 :   cai.aCheckTemporaries = aCheckTemporaries;
     840               0 :   cai.aCheckPermanents = aCheckPermanents;
     841               0 :   cai.counter = 0;
     842               0 :   cai.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
     843               0 :   cai.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;
     844                 : 
     845                 :   {
     846               0 :     ReentrantMonitorAutoEnter lock(monitor);
     847               0 :     mSettingsTable.EnumerateEntries(FindMatchingCertCallback, &cai);
     848                 :   }
     849               0 :   *_retval = cai.counter;
     850               0 :   return NS_OK;
     851                 : }
     852                 : 
     853                 : struct nsCertAndPointerAndCallback
     854               0 : {
     855                 :   nsIX509Cert *cert;
     856                 :   void *userdata;
     857                 :   nsCertOverrideService::CertOverrideEnumerator enumerator;
     858                 : 
     859                 :   SECOidTag mOidTagForStoringNewHashes;
     860                 :   nsCString mDottedOidForStoringNewHashes;
     861                 : };
     862                 : 
     863                 : PR_STATIC_CALLBACK(PLDHashOperator)
     864               0 : EnumerateCertOverridesCallback(nsCertOverrideEntry *aEntry,
     865                 :                                void *aArg)
     866                 : {
     867               0 :   nsCertAndPointerAndCallback *capac = (nsCertAndPointerAndCallback *)aArg;
     868                 : 
     869               0 :   if (capac && aEntry)
     870                 :   {
     871               0 :     const nsCertOverride &settings = aEntry->mSettings;
     872                 : 
     873               0 :     if (!capac->cert) {
     874               0 :       (*capac->enumerator)(settings, capac->userdata);
     875                 :     }
     876                 :     else {
     877               0 :       if (matchesDBKey(capac->cert, settings.mDBKey.get())) {
     878               0 :         nsCAutoString cert_fingerprint;
     879                 :         nsresult rv;
     880               0 :         if (settings.mFingerprintAlgOID.Equals(capac->mDottedOidForStoringNewHashes)) {
     881                 :           rv = GetCertFingerprintByOidTag(capac->cert,
     882               0 :                  capac->mOidTagForStoringNewHashes, cert_fingerprint);
     883                 :         }
     884                 :         else {
     885                 :           rv = GetCertFingerprintByDottedOidString(capac->cert,
     886               0 :                  settings.mFingerprintAlgOID, cert_fingerprint);
     887                 :         }
     888               0 :         if (NS_SUCCEEDED(rv) &&
     889               0 :             settings.mFingerprint.Equals(cert_fingerprint)) {
     890               0 :           (*capac->enumerator)(settings, capac->userdata);
     891                 :         }
     892                 :       }
     893                 :     }
     894                 :   }
     895                 : 
     896               0 :   return PL_DHASH_NEXT;
     897                 : }
     898                 : 
     899                 : nsresult 
     900               0 : nsCertOverrideService::EnumerateCertOverrides(nsIX509Cert *aCert,
     901                 :                          CertOverrideEnumerator enumerator,
     902                 :                          void *aUserData)
     903                 : {
     904               0 :   nsCertAndPointerAndCallback capac;
     905               0 :   capac.cert = aCert;
     906               0 :   capac.userdata = aUserData;
     907               0 :   capac.enumerator = enumerator;
     908               0 :   capac.mOidTagForStoringNewHashes = mOidTagForStoringNewHashes;
     909               0 :   capac.mDottedOidForStoringNewHashes = mDottedOidForStoringNewHashes;
     910                 : 
     911                 :   {
     912               0 :     ReentrantMonitorAutoEnter lock(monitor);
     913               0 :     mSettingsTable.EnumerateEntries(EnumerateCertOverridesCallback, &capac);
     914                 :   }
     915               0 :   return NS_OK;
     916                 : }
     917                 : 
     918                 : void
     919               0 : nsCertOverrideService::GetHostWithPort(const nsACString & aHostName, PRInt32 aPort, nsACString& _retval)
     920                 : {
     921               0 :   nsCAutoString hostPort(aHostName);
     922               0 :   if (aPort == -1) {
     923               0 :     aPort = 443;
     924                 :   }
     925               0 :   if (!hostPort.IsEmpty()) {
     926               0 :     hostPort.AppendLiteral(":");
     927               0 :     hostPort.AppendInt(aPort);
     928                 :   }
     929               0 :   _retval.Assign(hostPort);
     930               0 : }
     931                 : 

Generated by: LCOV version 1.7