LCOV - code coverage report
Current view: top level - security/manager/ssl - TransportSecurityInfo.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 493 0.8 %
Date: 2017-07-14 16:53:18 Functions: 3 52 5.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "TransportSecurityInfo.h"
       8             : 
       9             : #include "DateTimeFormat.h"
      10             : #include "PSMRunnable.h"
      11             : #include "mozilla/Casting.h"
      12             : #include "nsComponentManagerUtils.h"
      13             : #include "nsIArray.h"
      14             : #include "nsICertOverrideService.h"
      15             : #include "nsIObjectInputStream.h"
      16             : #include "nsIObjectOutputStream.h"
      17             : #include "nsIWebProgressListener.h"
      18             : #include "nsIX509CertValidity.h"
      19             : #include "nsNSSCertHelper.h"
      20             : #include "nsNSSCertificate.h"
      21             : #include "nsNSSComponent.h"
      22             : #include "nsReadableUtils.h"
      23             : #include "nsServiceManagerUtils.h"
      24             : #include "nsXULAppAPI.h"
      25             : #include "pkix/pkixtypes.h"
      26             : #include "secerr.h"
      27             : 
      28             : //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
      29             :                             //reports when doing SSL read/write
      30             : 
      31             : //#define DUMP_BUFFER  //Enable this define along with
      32             :                        //DEBUG_SSL_VERBOSE to dump SSL
      33             :                        //read/write buffer to a log.
      34             :                        //Uses PR_LOG except on Mac where
      35             :                        //we always write out to our own
      36             :                        //file.
      37             : 
      38             : namespace mozilla { namespace psm {
      39             : 
      40           0 : TransportSecurityInfo::TransportSecurityInfo()
      41             :   : mMutex("TransportSecurityInfo::mMutex")
      42             :   , mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE)
      43             :   , mSubRequestsBrokenSecurity(0)
      44             :   , mSubRequestsNoSecurity(0)
      45             :   , mErrorCode(0)
      46             :   , mErrorMessageType(SSLErrorMessageType::Plain)
      47           0 :   , mPort(0)
      48             : {
      49           0 : }
      50             : 
      51           0 : TransportSecurityInfo::~TransportSecurityInfo()
      52             : {
      53           0 :   nsNSSShutDownPreventionLock locker;
      54           0 :   if (isAlreadyShutDown())
      55           0 :     return;
      56             : 
      57           0 :   shutdown(ShutdownCalledFrom::Object);
      58           0 : }
      59             : 
      60             : void
      61           0 : TransportSecurityInfo::virtualDestroyNSSReference()
      62             : {
      63           0 : }
      64             : 
      65           0 : NS_IMPL_ISUPPORTS(TransportSecurityInfo,
      66             :                   nsITransportSecurityInfo,
      67             :                   nsIInterfaceRequestor,
      68             :                   nsISSLStatusProvider,
      69             :                   nsIAssociatedContentSecurity,
      70             :                   nsISerializable,
      71             :                   nsIClassInfo)
      72             : 
      73             : void
      74           0 : TransportSecurityInfo::SetHostName(const char* host)
      75             : {
      76           0 :   mHostName.Assign(host);
      77           0 : }
      78             : 
      79             : void
      80           0 : TransportSecurityInfo::SetPort(int32_t aPort)
      81             : {
      82           0 :   mPort = aPort;
      83           0 : }
      84             : 
      85             : void
      86           0 : TransportSecurityInfo::SetOriginAttributes(
      87             :   const OriginAttributes& aOriginAttributes)
      88             : {
      89           0 :   mOriginAttributes = aOriginAttributes;
      90           0 : }
      91             : 
      92             : PRErrorCode
      93           0 : TransportSecurityInfo::GetErrorCode() const
      94             : {
      95           0 :   MutexAutoLock lock(mMutex);
      96             : 
      97           0 :   return mErrorCode;
      98             : }
      99             : 
     100             : void
     101           0 : TransportSecurityInfo::SetCanceled(PRErrorCode errorCode,
     102             :                                    SSLErrorMessageType errorMessageType)
     103             : {
     104           0 :   MutexAutoLock lock(mMutex);
     105             : 
     106           0 :   mErrorCode = errorCode;
     107           0 :   mErrorMessageType = errorMessageType;
     108           0 :   mErrorMessageCached.Truncate();
     109           0 : }
     110             : 
     111             : NS_IMETHODIMP
     112           0 : TransportSecurityInfo::GetSecurityState(uint32_t* state)
     113             : {
     114           0 :   *state = mSecurityState;
     115           0 :   return NS_OK;
     116             : }
     117             : 
     118             : void
     119           0 : TransportSecurityInfo::SetSecurityState(uint32_t aState)
     120             : {
     121           0 :   mSecurityState = aState;
     122           0 : }
     123             : 
     124             : NS_IMETHODIMP
     125           0 : TransportSecurityInfo::GetCountSubRequestsBrokenSecurity(
     126             :   int32_t *aSubRequestsBrokenSecurity)
     127             : {
     128           0 :   *aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
     129           0 :   return NS_OK;
     130             : }
     131             : 
     132             : NS_IMETHODIMP
     133           0 : TransportSecurityInfo::SetCountSubRequestsBrokenSecurity(
     134             :   int32_t aSubRequestsBrokenSecurity)
     135             : {
     136           0 :   mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
     137           0 :   return NS_OK;
     138             : }
     139             : 
     140             : NS_IMETHODIMP
     141           0 : TransportSecurityInfo::GetCountSubRequestsNoSecurity(
     142             :   int32_t *aSubRequestsNoSecurity)
     143             : {
     144           0 :   *aSubRequestsNoSecurity = mSubRequestsNoSecurity;
     145           0 :   return NS_OK;
     146             : }
     147             : 
     148             : NS_IMETHODIMP
     149           0 : TransportSecurityInfo::SetCountSubRequestsNoSecurity(
     150             :   int32_t aSubRequestsNoSecurity)
     151             : {
     152           0 :   mSubRequestsNoSecurity = aSubRequestsNoSecurity;
     153           0 :   return NS_OK;
     154             : }
     155             : 
     156             : NS_IMETHODIMP
     157           0 : TransportSecurityInfo::Flush()
     158             : {
     159           0 :   return NS_OK;
     160             : }
     161             : 
     162             : NS_IMETHODIMP
     163           0 : TransportSecurityInfo::GetErrorMessage(char16_t** aText)
     164             : {
     165           0 :   NS_ENSURE_ARG_POINTER(aText);
     166           0 :   *aText = nullptr;
     167             : 
     168           0 :   if (!NS_IsMainThread()) {
     169           0 :     NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
     170           0 :     return NS_ERROR_NOT_SAME_THREAD;
     171             :   }
     172             : 
     173           0 :   MutexAutoLock lock(mMutex);
     174             : 
     175           0 :   if (mErrorMessageCached.IsEmpty()) {
     176           0 :     nsresult rv = formatErrorMessage(lock,
     177             :                                      mErrorCode, mErrorMessageType,
     178           0 :                                      true, true, mErrorMessageCached);
     179           0 :     NS_ENSURE_SUCCESS(rv, rv);
     180             :   }
     181             : 
     182           0 :   *aText = ToNewUnicode(mErrorMessageCached);
     183           0 :   return *aText ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     184             : }
     185             : 
     186             : void
     187           0 : TransportSecurityInfo::GetErrorLogMessage(PRErrorCode errorCode,
     188             :                                           SSLErrorMessageType errorMessageType,
     189             :                                           nsString &result)
     190             : {
     191           0 :   if (!NS_IsMainThread()) {
     192           0 :     NS_ERROR("nsNSSSocketInfo::GetErrorLogMessage called off the main thread");
     193           0 :     return;
     194             :   }
     195             : 
     196           0 :   MutexAutoLock lock(mMutex);
     197             :   (void) formatErrorMessage(lock, errorCode, errorMessageType,
     198           0 :                             false, false, result);
     199             : }
     200             : 
     201             : static nsresult
     202             : formatPlainErrorMessage(const nsCString& host, int32_t port,
     203             :                         PRErrorCode err,
     204             :                         bool suppressPort443,
     205             :                 /*out*/ nsString& returnedMessage);
     206             : 
     207             : static nsresult
     208             : formatOverridableCertErrorMessage(nsISSLStatus& sslStatus,
     209             :                                   PRErrorCode errorCodeToReport,
     210             :                                   const nsCString& host, int32_t port,
     211             :                                   bool suppressPort443,
     212             :                                   bool wantsHtml,
     213             :                           /*out*/ nsString& returnedMessage);
     214             : 
     215             : // XXX: uses nsNSSComponent string bundles off the main thread when called by
     216             : //      nsNSSSocketInfo::Write().
     217             : nsresult
     218           0 : TransportSecurityInfo::formatErrorMessage(const MutexAutoLock& /*proofOfLock*/,
     219             :                                           PRErrorCode errorCode,
     220             :                                           SSLErrorMessageType errorMessageType,
     221             :                                           bool wantsHtml, bool suppressPort443,
     222             :                                   /*out*/ nsString& result)
     223             : {
     224           0 :   result.Truncate();
     225           0 :   if (errorCode == 0) {
     226           0 :     return NS_OK;
     227             :   }
     228             : 
     229           0 :   if (!XRE_IsParentProcess()) {
     230           0 :     return NS_ERROR_UNEXPECTED;
     231             :   }
     232             : 
     233             :   nsresult rv;
     234           0 :   MOZ_ASSERT(errorMessageType != SSLErrorMessageType::OverridableCert ||
     235             :                (mSSLStatus && mSSLStatus->HasServerCert() &&
     236             :                 mSSLStatus->mHaveCertErrorBits),
     237             :              "formatErrorMessage() called for cert error without cert");
     238           0 :   if (errorMessageType == SSLErrorMessageType::OverridableCert &&
     239           0 :       mSSLStatus && mSSLStatus->HasServerCert()) {
     240           0 :     rv = formatOverridableCertErrorMessage(*mSSLStatus, errorCode,
     241             :                                            mHostName, mPort,
     242             :                                            suppressPort443,
     243             :                                            wantsHtml,
     244           0 :                                            result);
     245             :   } else {
     246           0 :     rv = formatPlainErrorMessage(mHostName, mPort,
     247             :                                  errorCode,
     248             :                                  suppressPort443,
     249           0 :                                  result);
     250             :   }
     251             : 
     252           0 :   if (NS_FAILED(rv)) {
     253           0 :     result.Truncate();
     254             :   }
     255             : 
     256           0 :   return rv;
     257             : }
     258             : 
     259             : NS_IMETHODIMP
     260           0 : TransportSecurityInfo::GetErrorCode(int32_t* state)
     261             : {
     262           0 :   *state = GetErrorCode();
     263           0 :   return NS_OK;
     264             : }
     265             : 
     266             : NS_IMETHODIMP
     267           0 : TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result)
     268             : {
     269           0 :   if (!NS_IsMainThread()) {
     270           0 :     NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
     271           0 :     return NS_ERROR_NOT_SAME_THREAD;
     272             :   }
     273             : 
     274             :   nsresult rv;
     275           0 :   if (!mCallbacks) {
     276           0 :     nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
     277           0 :     rv = ir->GetInterface(uuid, result);
     278             :   } else {
     279           0 :     rv = mCallbacks->GetInterface(uuid, result);
     280             :   }
     281           0 :   return rv;
     282             : }
     283             : 
     284             : // This is a new magic value. However, it re-uses the first 4 bytes
     285             : // of the previous value. This is so when older versions attempt to
     286             : // read a newer serialized TransportSecurityInfo, they will actually
     287             : // fail and return NS_ERROR_FAILURE instead of silently failing.
     288             : #define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x1faa, 0x4169, \
     289             :   { 0xb0, 0xd2, 0x81, 0x29, 0xec, 0x7c, 0xb1, 0xde } }
     290             : static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
     291             : 
     292             : NS_IMETHODIMP
     293           0 : TransportSecurityInfo::Write(nsIObjectOutputStream* stream)
     294             : {
     295           0 :   nsresult rv = stream->WriteID(kTransportSecurityInfoMagic);
     296           0 :   if (NS_FAILED(rv)) {
     297           0 :     return rv;
     298             :   }
     299             : 
     300           0 :   MutexAutoLock lock(mMutex);
     301             : 
     302           0 :   rv = stream->Write32(mSecurityState);
     303           0 :   if (NS_FAILED(rv)) {
     304           0 :     return rv;
     305             :   }
     306           0 :   rv = stream->Write32(mSubRequestsBrokenSecurity);
     307           0 :   if (NS_FAILED(rv)) {
     308           0 :     return rv;
     309             :   }
     310           0 :   rv = stream->Write32(mSubRequestsNoSecurity);
     311           0 :   if (NS_FAILED(rv)) {
     312           0 :     return rv;
     313             :   }
     314           0 :   rv = stream->Write32(static_cast<uint32_t>(mErrorCode));
     315           0 :   if (NS_FAILED(rv)) {
     316           0 :     return rv;
     317             :   }
     318           0 :   if (mErrorMessageCached.IsEmpty()) {
     319             :     // XXX: uses nsNSSComponent string bundles off the main thread
     320           0 :     rv = formatErrorMessage(lock, mErrorCode, mErrorMessageType,
     321           0 :                             true, true, mErrorMessageCached);
     322           0 :     if (NS_FAILED(rv)) {
     323           0 :       return rv;
     324             :     }
     325             :   }
     326           0 :   rv = stream->WriteWStringZ(mErrorMessageCached.get());
     327           0 :   if (NS_FAILED(rv)) {
     328           0 :     return rv;
     329             :   }
     330             : 
     331             :   // For successful connections and for connections with overridable errors,
     332             :   // mSSLStatus will be non-null. However, for connections with non-overridable
     333             :   // errors, it will be null.
     334           0 :   nsCOMPtr<nsISerializable> serializable(mSSLStatus);
     335             :   rv = NS_WriteOptionalCompoundObject(stream,
     336             :                                       serializable,
     337             :                                       NS_GET_IID(nsISSLStatus),
     338           0 :                                       true);
     339           0 :   if (NS_FAILED(rv)) {
     340           0 :     return rv;
     341             :   }
     342             : 
     343             :   rv = NS_WriteOptionalCompoundObject(stream,
     344             :                                       mFailedCertChain,
     345             :                                       NS_GET_IID(nsIX509CertList),
     346           0 :                                       true);
     347           0 :   if (NS_FAILED(rv)) {
     348           0 :     return rv;
     349             :   }
     350             : 
     351           0 :   return NS_OK;
     352             : }
     353             : 
     354             : NS_IMETHODIMP
     355           0 : TransportSecurityInfo::Read(nsIObjectInputStream* stream)
     356             : {
     357             :   nsID id;
     358           0 :   nsresult rv = stream->ReadID(&id);
     359           0 :   if (NS_FAILED(rv)) {
     360           0 :     return rv;
     361             :   }
     362           0 :   if (!id.Equals(kTransportSecurityInfoMagic)) {
     363           0 :     return NS_ERROR_UNEXPECTED;
     364             :   }
     365             : 
     366           0 :   MutexAutoLock lock(mMutex);
     367             : 
     368           0 :   rv = stream->Read32(&mSecurityState);
     369           0 :   if (NS_FAILED(rv)) {
     370           0 :     return rv;
     371             :   }
     372             :   uint32_t subRequestsBrokenSecurity;
     373           0 :   rv = stream->Read32(&subRequestsBrokenSecurity);
     374           0 :   if (NS_FAILED(rv)) {
     375           0 :     return rv;
     376             :   }
     377           0 :   if (subRequestsBrokenSecurity >
     378           0 :       static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
     379           0 :     return NS_ERROR_UNEXPECTED;
     380             :   }
     381           0 :   mSubRequestsBrokenSecurity = subRequestsBrokenSecurity;
     382             :   uint32_t subRequestsNoSecurity;
     383           0 :   rv = stream->Read32(&subRequestsNoSecurity);
     384           0 :   if (NS_FAILED(rv)) {
     385           0 :     return rv;
     386             :   }
     387           0 :   if (subRequestsNoSecurity >
     388           0 :       static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
     389           0 :     return NS_ERROR_UNEXPECTED;
     390             :   }
     391           0 :   mSubRequestsNoSecurity = subRequestsNoSecurity;
     392             :   uint32_t errorCode;
     393           0 :   rv = stream->Read32(&errorCode);
     394           0 :   if (NS_FAILED(rv)) {
     395           0 :     return rv;
     396             :   }
     397             :   // PRErrorCode will be a negative value
     398           0 :   mErrorCode = static_cast<PRErrorCode>(errorCode);
     399             : 
     400           0 :   rv = stream->ReadString(mErrorMessageCached);
     401           0 :   if (NS_FAILED(rv)) {
     402           0 :     return rv;
     403             :   }
     404             : 
     405             :   // For successful connections and for connections with overridable errors,
     406             :   // mSSLStatus will be non-null. For connections with non-overridable errors,
     407             :   // it will be null.
     408           0 :   nsCOMPtr<nsISupports> supports;
     409           0 :   rv = NS_ReadOptionalObject(stream, true, getter_AddRefs(supports));
     410           0 :   if (NS_FAILED(rv)) {
     411           0 :     return rv;
     412             :   }
     413           0 :   mSSLStatus = BitwiseCast<nsSSLStatus*, nsISupports*>(supports.get());
     414             : 
     415           0 :   nsCOMPtr<nsISupports> failedCertChainSupports;
     416           0 :   rv = NS_ReadOptionalObject(stream, true, getter_AddRefs(failedCertChainSupports));
     417           0 :   if (NS_FAILED(rv)) {
     418           0 :     return rv;
     419             :   }
     420           0 :   mFailedCertChain = do_QueryInterface(failedCertChainSupports);
     421             : 
     422           0 :   return NS_OK;
     423             : }
     424             : 
     425             : NS_IMETHODIMP
     426           0 : TransportSecurityInfo::GetInterfaces(uint32_t *count, nsIID * **array)
     427             : {
     428           0 :   *count = 0;
     429           0 :   *array = nullptr;
     430           0 :   return NS_OK;
     431             : }
     432             : 
     433             : NS_IMETHODIMP
     434           0 : TransportSecurityInfo::GetScriptableHelper(nsIXPCScriptable **_retval)
     435             : {
     436           0 :   *_retval = nullptr;
     437           0 :   return NS_OK;
     438             : }
     439             : 
     440             : NS_IMETHODIMP
     441           0 : TransportSecurityInfo::GetContractID(char * *aContractID)
     442             : {
     443           0 :   *aContractID = nullptr;
     444           0 :   return NS_OK;
     445             : }
     446             : 
     447             : NS_IMETHODIMP
     448           0 : TransportSecurityInfo::GetClassDescription(char * *aClassDescription)
     449             : {
     450           0 :   *aClassDescription = nullptr;
     451           0 :   return NS_OK;
     452             : }
     453             : 
     454             : NS_IMETHODIMP
     455           0 : TransportSecurityInfo::GetClassID(nsCID * *aClassID)
     456             : {
     457           0 :   *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
     458           0 :   if (!*aClassID)
     459           0 :     return NS_ERROR_OUT_OF_MEMORY;
     460           0 :   return GetClassIDNoAlloc(*aClassID);
     461             : }
     462             : 
     463             : NS_IMETHODIMP
     464           0 : TransportSecurityInfo::GetFlags(uint32_t *aFlags)
     465             : {
     466           0 :   *aFlags = 0;
     467           0 :   return NS_OK;
     468             : }
     469             : 
     470             : static NS_DEFINE_CID(kNSSSocketInfoCID, TRANSPORTSECURITYINFO_CID);
     471             : 
     472             : NS_IMETHODIMP
     473           0 : TransportSecurityInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
     474             : {
     475           0 :   *aClassIDNoAlloc = kNSSSocketInfoCID;
     476           0 :   return NS_OK;
     477             : }
     478             : 
     479             : nsresult
     480           0 : TransportSecurityInfo::GetSSLStatus(nsISSLStatus** _result)
     481             : {
     482           0 :   NS_ENSURE_ARG_POINTER(_result);
     483             : 
     484           0 :   *_result = mSSLStatus;
     485           0 :   NS_IF_ADDREF(*_result);
     486             : 
     487           0 :   return NS_OK;
     488             : }
     489             : 
     490             : void
     491           0 : TransportSecurityInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
     492             : {
     493           0 :   mSSLStatus = aSSLStatus;
     494           0 : }
     495             : 
     496             : /* Formats an error message for non-certificate-related SSL errors
     497             :  * and non-overridable certificate errors (both are of type
     498             :  * PlainErrormMessage). Use formatOverridableCertErrorMessage
     499             :  * for overridable cert errors.
     500             :  */
     501             : static nsresult
     502           0 : formatPlainErrorMessage(const nsCString& host, int32_t port,
     503             :                         PRErrorCode err,
     504             :                         bool suppressPort443,
     505             :                 /*out*/ nsString& returnedMessage)
     506             : {
     507             :   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     508             : 
     509             :   const char16_t *params[1];
     510             :   nsresult rv;
     511             : 
     512           0 :   nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
     513           0 :   NS_ENSURE_SUCCESS(rv, rv);
     514             : 
     515           0 :   if (host.Length())
     516             :   {
     517             :     // For now, hide port when it's 443 and we're reporting the error.
     518             :     // In the future a better mechanism should be used
     519             :     // to make a decision about showing the port number, possibly by requiring
     520             :     // the context object to implement a specific interface.
     521             :     // The motivation is that Mozilla browser would like to hide the port number
     522             :     // in error pages in the common case.
     523             : 
     524           0 :     NS_ConvertASCIItoUTF16 hostWithPort(host);
     525           0 :     if (!suppressPort443 || port != 443) {
     526           0 :       hostWithPort.Append(':');
     527           0 :       hostWithPort.AppendInt(port);
     528             :     }
     529           0 :     params[0] = hostWithPort.get();
     530             : 
     531           0 :     nsString formattedString;
     532           0 :     rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix",
     533           0 :                                                   params, 1, formattedString);
     534           0 :     if (NS_SUCCEEDED(rv))
     535             :     {
     536           0 :       returnedMessage.Append(formattedString);
     537           0 :       returnedMessage.AppendLiteral("\n\n");
     538             :     }
     539             :   }
     540             : 
     541           0 :   nsString explanation;
     542           0 :   rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
     543           0 :   if (NS_SUCCEEDED(rv))
     544           0 :     returnedMessage.Append(explanation);
     545             : 
     546           0 :   return NS_OK;
     547             : }
     548             : 
     549             : static void
     550           0 : AppendErrorTextUntrusted(PRErrorCode errTrust,
     551             :                          const nsString &host,
     552             :                          nsIX509Cert* ix509,
     553             :                          nsINSSComponent *component,
     554             :                          nsString &returnedMessage)
     555             : {
     556           0 :   const char* errorID = nullptr;
     557           0 :   const char* errorID2 = nullptr;
     558           0 :   const char* errorID3 = nullptr;
     559             :   bool isSelfSigned;
     560           0 :   if (NS_SUCCEEDED(ix509->GetIsSelfSigned(&isSelfSigned)) && isSelfSigned) {
     561           0 :     errorID = "certErrorTrust_SelfSigned";
     562             :   }
     563             : 
     564           0 :   if (!errorID) {
     565           0 :     switch (errTrust) {
     566             :       case SEC_ERROR_UNKNOWN_ISSUER:
     567           0 :         errorID = "certErrorTrust_UnknownIssuer";
     568           0 :         errorID2 = "certErrorTrust_UnknownIssuer2";
     569           0 :         errorID3 = "certErrorTrust_UnknownIssuer3";
     570           0 :         break;
     571             :       case SEC_ERROR_CA_CERT_INVALID:
     572           0 :         errorID = "certErrorTrust_CaInvalid";
     573           0 :         break;
     574             :       case SEC_ERROR_UNTRUSTED_ISSUER:
     575           0 :         errorID = "certErrorTrust_Issuer";
     576           0 :         break;
     577             :       case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
     578           0 :         errorID = "certErrorTrust_SignatureAlgorithmDisabled";
     579           0 :         break;
     580             :       case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
     581           0 :         errorID = "certErrorTrust_ExpiredIssuer";
     582           0 :         break;
     583             :       case SEC_ERROR_UNTRUSTED_CERT:
     584             :       default:
     585           0 :         errorID = "certErrorTrust_Untrusted";
     586           0 :         break;
     587             :     }
     588             :   }
     589             : 
     590           0 :   const char* errorIDs[] = { errorID, errorID2, errorID3 };
     591           0 :   for (size_t i = 0; i < ArrayLength(errorIDs); i++) {
     592           0 :     if (!errorIDs[i]) {
     593           0 :       break;
     594             :     }
     595             : 
     596           0 :     nsString formattedString;
     597           0 :     nsresult rv = component->GetPIPNSSBundleString(errorIDs[i], formattedString);
     598           0 :     if (NS_SUCCEEDED(rv)) {
     599           0 :       returnedMessage.Append(formattedString);
     600           0 :       returnedMessage.Append('\n');
     601             :     }
     602             :   }
     603           0 : }
     604             : 
     605             : // Returns the number of dNSName or iPAddress entries encountered in the
     606             : // subject alternative name extension of the certificate.
     607             : // Returns zero if the extension is not present, could not be decoded, or if it
     608             : // does not contain any dNSName or iPAddress entries.
     609             : static uint32_t
     610           0 : GetSubjectAltNames(CERTCertificate* nssCert, nsString& allNames)
     611             : {
     612           0 :   allNames.Truncate();
     613             : 
     614           0 :   ScopedAutoSECItem altNameExtension;
     615             :   SECStatus rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
     616           0 :                                         &altNameExtension);
     617           0 :   if (rv != SECSuccess) {
     618           0 :     return 0;
     619             :   }
     620           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     621           0 :   if (!arena) {
     622           0 :     return 0;
     623             :   }
     624           0 :   CERTGeneralName* sanNameList(CERT_DecodeAltNameExtension(arena.get(),
     625           0 :                                                            &altNameExtension));
     626           0 :   if (!sanNameList) {
     627           0 :     return 0;
     628             :   }
     629             : 
     630           0 :   uint32_t nameCount = 0;
     631           0 :   CERTGeneralName* current = sanNameList;
     632           0 :   do {
     633           0 :     nsAutoString name;
     634           0 :     switch (current->type) {
     635             :       case certDNSName:
     636             :         {
     637           0 :           nsDependentCSubstring nameFromCert(BitwiseCast<char*, unsigned char*>(
     638             :                                                current->name.other.data),
     639           0 :                                              current->name.other.len);
     640             :           // dNSName fields are defined as type IA5String and thus should
     641             :           // be limited to ASCII characters.
     642           0 :           if (IsASCII(nameFromCert)) {
     643           0 :             name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
     644           0 :             if (!allNames.IsEmpty()) {
     645           0 :               allNames.AppendLiteral(", ");
     646             :             }
     647           0 :             ++nameCount;
     648           0 :             allNames.Append(name);
     649             :           }
     650             :         }
     651           0 :         break;
     652             : 
     653             :       case certIPAddress:
     654             :         {
     655             :           char buf[INET6_ADDRSTRLEN];
     656             :           PRNetAddr addr;
     657           0 :           if (current->name.other.len == 4) {
     658           0 :             addr.inet.family = PR_AF_INET;
     659           0 :             memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
     660           0 :             PR_NetAddrToString(&addr, buf, sizeof(buf));
     661           0 :             name.AssignASCII(buf);
     662           0 :           } else if (current->name.other.len == 16) {
     663           0 :             addr.ipv6.family = PR_AF_INET6;
     664           0 :             memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
     665           0 :             PR_NetAddrToString(&addr, buf, sizeof(buf));
     666           0 :             name.AssignASCII(buf);
     667             :           } else {
     668             :             /* invalid IP address */
     669             :           }
     670           0 :           if (!name.IsEmpty()) {
     671           0 :             if (!allNames.IsEmpty()) {
     672           0 :               allNames.AppendLiteral(", ");
     673             :             }
     674           0 :             ++nameCount;
     675           0 :             allNames.Append(name);
     676             :           }
     677           0 :           break;
     678             :         }
     679             : 
     680             :       default: // all other types of names are ignored
     681           0 :         break;
     682             :     }
     683           0 :     current = CERT_GetNextGeneralName(current);
     684           0 :   } while (current != sanNameList); // double linked
     685             : 
     686           0 :   return nameCount;
     687             : }
     688             : 
     689             : static nsresult
     690           0 : AppendErrorTextMismatch(const nsString& host, nsIX509Cert* ix509,
     691             :                         nsINSSComponent* component, bool wantsHtml,
     692             :                         nsString& returnedMessage)
     693             : {
     694             :   // Prepare a default "not valid for <hostname>" string in case anything
     695             :   // goes wrong (or in case the certificate is not valid for any hostnames).
     696           0 :   nsAutoString notValidForHostnameString;
     697             :   const char16_t* params[1];
     698           0 :   params[0] = host.get();
     699             :   nsresult rv = component->PIPBundleFormatStringFromName(
     700           0 :     "certErrorMismatch", params, 1, notValidForHostnameString);
     701           0 :   if (NS_FAILED(rv)) {
     702           0 :     return rv;
     703             :   }
     704           0 :   notValidForHostnameString.Append('\n');
     705             : 
     706           0 :   UniqueCERTCertificate nssCert(ix509->GetCert());
     707           0 :   if (!nssCert) {
     708           0 :     returnedMessage.Append(notValidForHostnameString);
     709           0 :     return NS_OK;
     710             :   }
     711             : 
     712           0 :   nsAutoString allNames;
     713           0 :   uint32_t nameCount = GetSubjectAltNames(nssCert.get(), allNames);
     714           0 :   if (nameCount == 0) {
     715           0 :     returnedMessage.Append(notValidForHostnameString);
     716           0 :   } else if (nameCount > 1) {
     717           0 :     nsString message;
     718           0 :     rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple", message);
     719           0 :     if (NS_FAILED(rv)) {
     720           0 :       return rv;
     721             :     }
     722           0 :     returnedMessage.Append(message);
     723           0 :     returnedMessage.AppendLiteral("\n  ");
     724           0 :     returnedMessage.Append(allNames);
     725           0 :     returnedMessage.AppendLiteral("  \n");
     726           0 :   } else if (nameCount == 1) {
     727           0 :     params[0] = allNames.get();
     728             : 
     729           0 :     const char* stringID = wantsHtml ? "certErrorMismatchSingle2"
     730           0 :                                      : "certErrorMismatchSinglePlain";
     731           0 :     nsAutoString formattedString;
     732             :     rv = component->PIPBundleFormatStringFromName(stringID, params, 1,
     733           0 :                                                   formattedString);
     734           0 :     if (NS_FAILED(rv)) {
     735           0 :       return rv;
     736             :     }
     737           0 :     returnedMessage.Append(formattedString);
     738           0 :     returnedMessage.Append('\n');
     739             :   }
     740             : 
     741           0 :   return NS_OK;
     742             : }
     743             : 
     744             : static void
     745           0 : GetDateBoundary(nsIX509Cert* ix509,
     746             :                 nsString &formattedDate,
     747             :                 nsString &nowDate,
     748             :                 bool &trueExpired_falseNotYetValid)
     749             : {
     750           0 :   trueExpired_falseNotYetValid = true;
     751           0 :   formattedDate.Truncate();
     752             : 
     753             :   PRTime notAfter, notBefore, timeToUse;
     754           0 :   nsCOMPtr<nsIX509CertValidity> validity;
     755             :   nsresult rv;
     756             : 
     757           0 :   rv = ix509->GetValidity(getter_AddRefs(validity));
     758           0 :   if (NS_FAILED(rv))
     759           0 :     return;
     760             : 
     761           0 :   rv = validity->GetNotAfter(&notAfter);
     762           0 :   if (NS_FAILED(rv))
     763           0 :     return;
     764             : 
     765           0 :   rv = validity->GetNotBefore(&notBefore);
     766           0 :   if (NS_FAILED(rv))
     767           0 :     return;
     768             : 
     769           0 :   PRTime now = PR_Now();
     770           0 :   if (now > notAfter) {
     771           0 :     timeToUse = notAfter;
     772             :   } else {
     773           0 :     timeToUse = notBefore;
     774           0 :     trueExpired_falseNotYetValid = false;
     775             :   }
     776             : 
     777           0 :   DateTimeFormat::FormatPRTime(kDateFormatLong, kTimeFormatNoSeconds,
     778           0 :                                timeToUse, formattedDate);
     779           0 :   DateTimeFormat::FormatPRTime(kDateFormatLong, kTimeFormatNoSeconds,
     780           0 :                                now, nowDate);
     781             : }
     782             : 
     783             : static void
     784           0 : AppendErrorTextTime(nsIX509Cert* ix509,
     785             :                     nsINSSComponent *component,
     786             :                     nsString &returnedMessage)
     787             : {
     788           0 :   nsAutoString formattedDate, nowDate;
     789             :   bool trueExpired_falseNotYetValid;
     790           0 :   GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
     791             : 
     792             :   const char16_t *params[2];
     793           0 :   params[0] = formattedDate.get(); // might be empty, if helper function had a problem
     794           0 :   params[1] = nowDate.get();
     795             : 
     796           0 :   const char *key = trueExpired_falseNotYetValid ?
     797           0 :                     "certErrorExpiredNow" : "certErrorNotYetValidNow";
     798             :   nsresult rv;
     799           0 :   nsString formattedString;
     800           0 :   rv = component->PIPBundleFormatStringFromName(
     801             :            key,
     802             :            params,
     803           0 :            ArrayLength(params),
     804           0 :            formattedString);
     805           0 :   if (NS_SUCCEEDED(rv))
     806             :   {
     807           0 :     returnedMessage.Append(formattedString);
     808           0 :     returnedMessage.Append('\n');
     809             :   }
     810           0 : }
     811             : 
     812             : static void
     813           0 : AppendErrorTextCode(PRErrorCode errorCodeToReport,
     814             :                     nsINSSComponent *component,
     815             :                     nsString &returnedMessage)
     816             : {
     817           0 :   const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
     818           0 :   if (codeName)
     819             :   {
     820           0 :     nsCString error_id(codeName);
     821           0 :     NS_ConvertASCIItoUTF16 idU(error_id);
     822             : 
     823             :     const char16_t *params[1];
     824           0 :     params[0] = idU.get();
     825             : 
     826           0 :     nsString formattedString;
     827             :     nsresult rv;
     828             :     rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2",
     829             :                                                   params, 1,
     830           0 :                                                   formattedString);
     831           0 :     if (NS_SUCCEEDED(rv)) {
     832           0 :       returnedMessage.Append('\n');
     833           0 :       returnedMessage.Append(formattedString);
     834           0 :       returnedMessage.Append('\n');
     835             :     }
     836             :     else {
     837           0 :       returnedMessage.AppendLiteral(" (");
     838           0 :       returnedMessage.Append(idU);
     839           0 :       returnedMessage.Append(')');
     840             :     }
     841             :   }
     842           0 : }
     843             : 
     844             : /* Formats an error message for overridable certificate errors (of type
     845             :  * OverridableCertErrorMessage). Use formatPlainErrorMessage to format
     846             :  * non-overridable cert errors and non-cert-related errors.
     847             :  */
     848             : static nsresult
     849           0 : formatOverridableCertErrorMessage(nsISSLStatus& sslStatus,
     850             :                                   PRErrorCode errorCodeToReport,
     851             :                                   const nsCString& host, int32_t port,
     852             :                                   bool suppressPort443,
     853             :                                   bool wantsHtml,
     854             :                           /*out*/ nsString& returnedMessage)
     855             : {
     856             :   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     857             : 
     858             :   const char16_t *params[1];
     859             :   nsresult rv;
     860           0 :   NS_ConvertASCIItoUTF16 hostWithPort(host);
     861           0 :   NS_ConvertASCIItoUTF16 hostWithoutPort(host);
     862             : 
     863             :   // For now, hide port when it's 443 and we're reporting the error.
     864             :   // In the future a better mechanism should be used
     865             :   // to make a decision about showing the port number, possibly by requiring
     866             :   // the context object to implement a specific interface.
     867             :   // The motivation is that Mozilla browser would like to hide the port number
     868             :   // in error pages in the common case.
     869           0 :   if (suppressPort443 && port == 443) {
     870           0 :     params[0] = hostWithoutPort.get();
     871             :   } else {
     872           0 :     hostWithPort.Append(':');
     873           0 :     hostWithPort.AppendInt(port);
     874           0 :     params[0] = hostWithPort.get();
     875             :   }
     876             : 
     877           0 :   nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
     878           0 :   NS_ENSURE_SUCCESS(rv, rv);
     879             : 
     880           0 :   returnedMessage.Truncate();
     881           0 :   rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
     882           0 :                                                 returnedMessage);
     883           0 :   NS_ENSURE_SUCCESS(rv, rv);
     884             : 
     885           0 :   returnedMessage.AppendLiteral("\n\n");
     886             : 
     887           0 :   RefPtr<nsIX509Cert> ix509;
     888           0 :   rv = sslStatus.GetServerCert(getter_AddRefs(ix509));
     889           0 :   NS_ENSURE_SUCCESS(rv, rv);
     890             : 
     891             :   bool isUntrusted;
     892           0 :   rv = sslStatus.GetIsUntrusted(&isUntrusted);
     893           0 :   NS_ENSURE_SUCCESS(rv, rv);
     894           0 :   if (isUntrusted) {
     895           0 :     AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509,
     896           0 :                              component, returnedMessage);
     897             :   }
     898             : 
     899             :   bool isDomainMismatch;
     900           0 :   rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
     901           0 :   NS_ENSURE_SUCCESS(rv, rv);
     902           0 :   if (isDomainMismatch) {
     903           0 :     rv = AppendErrorTextMismatch(hostWithoutPort, ix509, component, wantsHtml,
     904             :                                  returnedMessage);
     905           0 :     NS_ENSURE_SUCCESS(rv, rv);
     906             :   }
     907             : 
     908             :   bool isNotValidAtThisTime;
     909           0 :   rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
     910           0 :   NS_ENSURE_SUCCESS(rv, rv);
     911           0 :   if (isNotValidAtThisTime) {
     912           0 :     AppendErrorTextTime(ix509, component, returnedMessage);
     913             :   }
     914             : 
     915           0 :   AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
     916             : 
     917           0 :   return NS_OK;
     918             : }
     919             : 
     920             : // RememberCertErrorsTable
     921             : 
     922             : /*static*/ RememberCertErrorsTable*
     923             : RememberCertErrorsTable::sInstance = nullptr;
     924             : 
     925           1 : RememberCertErrorsTable::RememberCertErrorsTable()
     926             :   : mErrorHosts()
     927           1 :   , mMutex("RememberCertErrorsTable::mMutex")
     928             : {
     929           1 : }
     930             : 
     931             : static nsresult
     932           0 : GetHostPortKey(TransportSecurityInfo* infoObject, /*out*/ nsCString& result)
     933             : {
     934           0 :   MOZ_ASSERT(infoObject);
     935           0 :   NS_ENSURE_ARG(infoObject);
     936             : 
     937           0 :   result.Truncate();
     938             : 
     939           0 :   result.Assign(infoObject->GetHostName());
     940           0 :   result.Append(':');
     941           0 :   result.AppendInt(infoObject->GetPort());
     942             : 
     943           0 :   return NS_OK;
     944             : }
     945             : 
     946             : void
     947           0 : RememberCertErrorsTable::RememberCertHasError(TransportSecurityInfo* infoObject,
     948             :                                               nsSSLStatus* status,
     949             :                                               SECStatus certVerificationResult)
     950             : {
     951             :   nsresult rv;
     952             : 
     953           0 :   nsAutoCString hostPortKey;
     954           0 :   rv = GetHostPortKey(infoObject, hostPortKey);
     955           0 :   if (NS_FAILED(rv))
     956           0 :     return;
     957             : 
     958           0 :   if (certVerificationResult != SECSuccess) {
     959           0 :     MOZ_ASSERT(status, "Must have nsSSLStatus object when remembering flags");
     960             : 
     961           0 :     if (!status)
     962           0 :       return;
     963             : 
     964             :     CertStateBits bits;
     965           0 :     bits.mIsDomainMismatch = status->mIsDomainMismatch;
     966           0 :     bits.mIsNotValidAtThisTime = status->mIsNotValidAtThisTime;
     967           0 :     bits.mIsUntrusted = status->mIsUntrusted;
     968             : 
     969           0 :     MutexAutoLock lock(mMutex);
     970           0 :     mErrorHosts.Put(hostPortKey, bits);
     971             :   }
     972             :   else {
     973           0 :     MutexAutoLock lock(mMutex);
     974           0 :     mErrorHosts.Remove(hostPortKey);
     975             :   }
     976             : }
     977             : 
     978             : void
     979           0 : RememberCertErrorsTable::LookupCertErrorBits(TransportSecurityInfo* infoObject,
     980             :                                              nsSSLStatus* status)
     981             : {
     982             :   // Get remembered error bits from our cache, because of SSL session caching
     983             :   // the NSS library potentially hasn't notified us for this socket.
     984           0 :   if (status->mHaveCertErrorBits)
     985             :     // Rather do not modify bits if already set earlier
     986           0 :     return;
     987             : 
     988             :   nsresult rv;
     989             : 
     990           0 :   nsAutoCString hostPortKey;
     991           0 :   rv = GetHostPortKey(infoObject, hostPortKey);
     992           0 :   if (NS_FAILED(rv))
     993           0 :     return;
     994             : 
     995             :   CertStateBits bits;
     996             :   {
     997           0 :     MutexAutoLock lock(mMutex);
     998           0 :     if (!mErrorHosts.Get(hostPortKey, &bits))
     999             :       // No record was found, this host had no cert errors
    1000           0 :       return;
    1001             :   }
    1002             : 
    1003             :   // This host had cert errors, update the bits correctly
    1004           0 :   status->mHaveCertErrorBits = true;
    1005           0 :   status->mIsDomainMismatch = bits.mIsDomainMismatch;
    1006           0 :   status->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
    1007           0 :   status->mIsUntrusted = bits.mIsUntrusted;
    1008             : }
    1009             : 
    1010             : void
    1011           0 : TransportSecurityInfo::SetStatusErrorBits(nsNSSCertificate* cert,
    1012             :                                           uint32_t collected_errors)
    1013             : {
    1014           0 :   MutexAutoLock lock(mMutex);
    1015             : 
    1016           0 :   if (!mSSLStatus) {
    1017           0 :     mSSLStatus = new nsSSLStatus();
    1018             :   }
    1019             : 
    1020           0 :   mSSLStatus->SetServerCert(cert, EVStatus::NotEV);
    1021             : 
    1022           0 :   mSSLStatus->mHaveCertErrorBits = true;
    1023           0 :   mSSLStatus->mIsDomainMismatch =
    1024           0 :     collected_errors & nsICertOverrideService::ERROR_MISMATCH;
    1025           0 :   mSSLStatus->mIsNotValidAtThisTime =
    1026           0 :     collected_errors & nsICertOverrideService::ERROR_TIME;
    1027           0 :   mSSLStatus->mIsUntrusted =
    1028           0 :     collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
    1029             : 
    1030           0 :   RememberCertErrorsTable::GetInstance().RememberCertHasError(this,
    1031             :                                                               mSSLStatus,
    1032           0 :                                                               SECFailure);
    1033           0 : }
    1034             : 
    1035             : NS_IMETHODIMP
    1036           0 : TransportSecurityInfo::GetFailedCertChain(nsIX509CertList** _result)
    1037             : {
    1038           0 :   MOZ_ASSERT(_result);
    1039             : 
    1040           0 :   *_result = mFailedCertChain;
    1041           0 :   NS_IF_ADDREF(*_result);
    1042             : 
    1043           0 :   return NS_OK;
    1044             : }
    1045             : 
    1046             : nsresult
    1047           0 : TransportSecurityInfo::SetFailedCertChain(UniqueCERTCertList certList)
    1048             : {
    1049           0 :   nsNSSShutDownPreventionLock lock;
    1050           0 :   if (isAlreadyShutDown()) {
    1051           0 :     return NS_ERROR_NOT_AVAILABLE;
    1052             :   }
    1053             : 
    1054             :   // nsNSSCertList takes ownership of certList
    1055           0 :   mFailedCertChain = new nsNSSCertList(Move(certList), lock);
    1056             : 
    1057           0 :   return NS_OK;
    1058             : }
    1059             : 
    1060           9 : } } // namespace mozilla::psm

Generated by: LCOV version 1.13