security/manager/ssl/src/TransportSecurityInfo.cpp

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

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

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "TransportSecurityInfo.h"
     9 #include "pkix/pkixtypes.h"
    10 #include "nsNSSComponent.h"
    11 #include "nsIWebProgressListener.h"
    12 #include "nsNSSCertificate.h"
    13 #include "nsIX509CertValidity.h"
    14 #include "nsIDateTimeFormat.h"
    15 #include "nsDateTimeFormatCID.h"
    16 #include "nsICertOverrideService.h"
    17 #include "nsIObjectInputStream.h"
    18 #include "nsIObjectOutputStream.h"
    19 #include "nsNSSCertHelper.h"
    20 #include "nsIProgrammingLanguage.h"
    21 #include "nsIArray.h"
    22 #include "nsComponentManagerUtils.h"
    23 #include "nsReadableUtils.h"
    24 #include "nsServiceManagerUtils.h"
    25 #include "PSMRunnable.h"
    27 #include "secerr.h"
    29 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal 
    30                             //reports when doing SSL read/write
    32 //#define DUMP_BUFFER  //Enable this define along with
    33                        //DEBUG_SSL_VERBOSE to dump SSL
    34                        //read/write buffer to a log.
    35                        //Uses PR_LOG except on Mac where
    36                        //we always write out to our own
    37                        //file.
    39 namespace mozilla { namespace psm {
    41 TransportSecurityInfo::TransportSecurityInfo()
    42   : mMutex("TransportSecurityInfo::mMutex"),
    43     mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
    44     mSubRequestsBrokenSecurity(0),
    45     mSubRequestsNoSecurity(0),
    46     mErrorCode(0),
    47     mErrorMessageType(PlainErrorMessage),
    48     mPort(0)
    49 {
    50 }
    52 TransportSecurityInfo::~TransportSecurityInfo()
    53 {
    54   nsNSSShutDownPreventionLock locker;
    55   if (isAlreadyShutDown())
    56     return;
    58   shutdown(calledFromObject);
    59 }
    61 void
    62 TransportSecurityInfo::virtualDestroyNSSReference()
    63 {
    64 }
    66 NS_IMPL_ISUPPORTS(TransportSecurityInfo,
    67                   nsITransportSecurityInfo,
    68                   nsIInterfaceRequestor,
    69                   nsISSLStatusProvider,
    70                   nsIAssociatedContentSecurity,
    71                   nsISerializable,
    72                   nsIClassInfo)
    74 nsresult
    75 TransportSecurityInfo::SetHostName(const char* host)
    76 {
    77   mHostName.Adopt(host ? NS_strdup(host) : 0);
    78   return NS_OK;
    79 }
    81 nsresult
    82 TransportSecurityInfo::GetHostName(char **host)
    83 {
    84   *host = (mHostName) ? NS_strdup(mHostName) : nullptr;
    85   return NS_OK;
    86 }
    88 nsresult
    89 TransportSecurityInfo::SetPort(int32_t aPort)
    90 {
    91   mPort = aPort;
    92   return NS_OK;
    93 }
    95 nsresult
    96 TransportSecurityInfo::GetPort(int32_t *aPort)
    97 {
    98   *aPort = mPort;
    99   return NS_OK;
   100 }
   102 PRErrorCode
   103 TransportSecurityInfo::GetErrorCode() const
   104 {
   105   MutexAutoLock lock(mMutex);
   107   return mErrorCode;
   108 }
   110 void
   111 TransportSecurityInfo::SetCanceled(PRErrorCode errorCode,
   112                                    SSLErrorMessageType errorMessageType)
   113 {
   114   MutexAutoLock lock(mMutex);
   116   mErrorCode = errorCode;
   117   mErrorMessageType = errorMessageType;
   118   mErrorMessageCached.Truncate();
   119 }
   121 NS_IMETHODIMP
   122 TransportSecurityInfo::GetSecurityState(uint32_t* state)
   123 {
   124   *state = mSecurityState;
   125   return NS_OK;
   126 }
   128 nsresult
   129 TransportSecurityInfo::SetSecurityState(uint32_t aState)
   130 {
   131   mSecurityState = aState;
   132   return NS_OK;
   133 }
   135 /* attribute unsigned long countSubRequestsBrokenSecurity; */
   136 NS_IMETHODIMP
   137 TransportSecurityInfo::GetCountSubRequestsBrokenSecurity(
   138   int32_t *aSubRequestsBrokenSecurity)
   139 {
   140   *aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
   141   return NS_OK;
   142 }
   144 NS_IMETHODIMP
   145 TransportSecurityInfo::SetCountSubRequestsBrokenSecurity(
   146   int32_t aSubRequestsBrokenSecurity)
   147 {
   148   mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
   149   return NS_OK;
   150 }
   152 /* attribute unsigned long countSubRequestsNoSecurity; */
   153 NS_IMETHODIMP
   154 TransportSecurityInfo::GetCountSubRequestsNoSecurity(
   155   int32_t *aSubRequestsNoSecurity)
   156 {
   157   *aSubRequestsNoSecurity = mSubRequestsNoSecurity;
   158   return NS_OK;
   159 }
   161 NS_IMETHODIMP
   162 TransportSecurityInfo::SetCountSubRequestsNoSecurity(
   163   int32_t aSubRequestsNoSecurity)
   164 {
   165   mSubRequestsNoSecurity = aSubRequestsNoSecurity;
   166   return NS_OK;
   167 }
   169 NS_IMETHODIMP
   170 TransportSecurityInfo::Flush()
   171 {
   172   return NS_OK;
   173 }
   175 NS_IMETHODIMP
   176 TransportSecurityInfo::GetErrorMessage(char16_t** aText)
   177 {
   178   NS_ENSURE_ARG_POINTER(aText);
   179   *aText = nullptr;
   181   if (!NS_IsMainThread()) {
   182     NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
   183     return NS_ERROR_NOT_SAME_THREAD;
   184   }
   186   MutexAutoLock lock(mMutex);
   188   if (mErrorMessageCached.IsEmpty()) {
   189     nsresult rv = formatErrorMessage(lock, 
   190                                      mErrorCode, mErrorMessageType,
   191                                      true, true, mErrorMessageCached);
   192     NS_ENSURE_SUCCESS(rv, rv);
   193   }
   195   *aText = ToNewUnicode(mErrorMessageCached);
   196   return *aText ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   197 }
   199 void
   200 TransportSecurityInfo::GetErrorLogMessage(PRErrorCode errorCode,
   201                                           SSLErrorMessageType errorMessageType,
   202                                           nsString &result)
   203 {
   204   if (!NS_IsMainThread()) {
   205     NS_ERROR("nsNSSSocketInfo::GetErrorLogMessage called off the main thread");
   206     return;
   207   }
   209   MutexAutoLock lock(mMutex);
   210   (void) formatErrorMessage(lock, errorCode, errorMessageType,
   211                             false, false, result);
   212 }
   214 static nsresult
   215 formatPlainErrorMessage(nsXPIDLCString const & host, int32_t port,
   216                         PRErrorCode err, 
   217                         bool suppressPort443,
   218                         nsString &returnedMessage);
   220 static nsresult
   221 formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
   222                                   PRErrorCode errorCodeToReport, 
   223                                   const nsXPIDLCString & host, int32_t port,
   224                                   bool suppressPort443,
   225                                   bool wantsHtml,
   226                                   nsString & returnedMessage);
   228 // XXX: uses nsNSSComponent string bundles off the main thread when called by
   229 //      nsNSSSocketInfo::Write().
   230 nsresult
   231 TransportSecurityInfo::formatErrorMessage(MutexAutoLock const & proofOfLock, 
   232                                           PRErrorCode errorCode,
   233                                           SSLErrorMessageType errorMessageType,
   234                                           bool wantsHtml, bool suppressPort443, 
   235                                           nsString &result)
   236 {
   237   if (errorCode == 0) {
   238     result.Truncate();
   239     return NS_OK;
   240   }
   242   nsresult rv;
   243   NS_ConvertASCIItoUTF16 hostNameU(mHostName);
   244   NS_ASSERTION(errorMessageType != OverridableCertErrorMessage || 
   245                 (mSSLStatus && mSSLStatus->mServerCert &&
   246                  mSSLStatus->mHaveCertErrorBits),
   247                 "GetErrorLogMessage called for cert error without cert");
   248   if (errorMessageType == OverridableCertErrorMessage && 
   249       mSSLStatus && mSSLStatus->mServerCert) {
   250     rv = formatOverridableCertErrorMessage(*mSSLStatus, errorCode,
   251                                            mHostName, mPort,
   252                                            suppressPort443,
   253                                            wantsHtml,
   254                                            result);
   255   } else {
   256     rv = formatPlainErrorMessage(mHostName, mPort, 
   257                                  errorCode,
   258                                  suppressPort443,
   259                                  result);
   260   }
   262   if (NS_FAILED(rv)) {
   263     result.Truncate();
   264   }
   266   return rv;
   267 }
   269 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
   270 NS_IMETHODIMP
   271 TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result)
   272 {
   273   if (!NS_IsMainThread()) {
   274     NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
   275     return NS_ERROR_NOT_SAME_THREAD;
   276   }
   278   nsresult rv;
   279   if (!mCallbacks) {
   280     nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
   281     rv = ir->GetInterface(uuid, result);
   282   } else {
   283     rv = mCallbacks->GetInterface(uuid, result);
   284   }
   285   return rv;
   286 }
   288 // This is a new magic value. However, it re-uses the first 4 bytes
   289 // of the previous value. This is so when older versions attempt to
   290 // read a newer serialized TransportSecurityInfo, they will actually
   291 // fail and return NS_ERROR_FAILURE instead of silently failing.
   292 #define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x28ea, 0x45d2, \
   293   { 0xa2, 0x5a, 0x35, 0x7c, 0xae, 0xfa, 0x7f, 0x82 } }
   294 static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
   296 NS_IMETHODIMP
   297 TransportSecurityInfo::Write(nsIObjectOutputStream* stream)
   298 {
   299   nsresult rv = stream->WriteID(kTransportSecurityInfoMagic);
   300   if (NS_FAILED(rv)) {
   301     return rv;
   302   }
   304   MutexAutoLock lock(mMutex);
   306   rv = stream->Write32(mSecurityState);
   307   if (NS_FAILED(rv)) {
   308     return rv;
   309   }
   310   rv = stream->Write32(mSubRequestsBrokenSecurity);
   311   if (NS_FAILED(rv)) {
   312     return rv;
   313   }
   314   rv = stream->Write32(mSubRequestsNoSecurity);
   315   if (NS_FAILED(rv)) {
   316     return rv;
   317   }
   318   // XXX: uses nsNSSComponent string bundles off the main thread
   319   rv = formatErrorMessage(lock, mErrorCode, mErrorMessageType, true, true,
   320                           mErrorMessageCached);
   321   if (NS_FAILED(rv)) {
   322     return rv;
   323   }
   324   rv = stream->WriteWStringZ(mErrorMessageCached.get());
   325   if (NS_FAILED(rv)) {
   326     return rv;
   327   }
   328   nsCOMPtr<nsISerializable> serializable(mSSLStatus);
   329   rv = stream->WriteCompoundObject(serializable, NS_GET_IID(nsISSLStatus),
   330                                    true);
   331   if (NS_FAILED(rv)) {
   332     return rv;
   333   }
   334   return NS_OK;
   335 }
   337 NS_IMETHODIMP
   338 TransportSecurityInfo::Read(nsIObjectInputStream* stream)
   339 {
   340   nsID id;
   341   nsresult rv = stream->ReadID(&id);
   342   if (NS_FAILED(rv)) {
   343     return rv;
   344   }
   345   if (!id.Equals(kTransportSecurityInfoMagic)) {
   346     return NS_ERROR_UNEXPECTED;
   347   }
   349   MutexAutoLock lock(mMutex);
   351   rv = stream->Read32(&mSecurityState);
   352   if (NS_FAILED(rv)) {
   353     return rv;
   354   }
   355   uint32_t subRequestsBrokenSecurity;
   356   rv = stream->Read32(&subRequestsBrokenSecurity);
   357   if (NS_FAILED(rv)) {
   358     return rv;
   359   }
   360   if (subRequestsBrokenSecurity >
   361       static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
   362     return NS_ERROR_UNEXPECTED;
   363   }
   364   mSubRequestsBrokenSecurity = subRequestsBrokenSecurity;
   365   uint32_t subRequestsNoSecurity;
   366   rv = stream->Read32(&subRequestsNoSecurity);
   367   if (NS_FAILED(rv)) {
   368     return rv;
   369   }
   370   if (subRequestsNoSecurity >
   371       static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
   372     return NS_ERROR_UNEXPECTED;
   373   }
   374   mSubRequestsNoSecurity = subRequestsNoSecurity;
   375   rv = stream->ReadString(mErrorMessageCached);
   376   if (NS_FAILED(rv)) {
   377     return rv;
   378   }
   379   mErrorCode = 0;
   380   nsCOMPtr<nsISupports> supports;
   381   rv = stream->ReadObject(true, getter_AddRefs(supports));
   382   if (NS_FAILED(rv)) {
   383     return rv;
   384   }
   385   mSSLStatus = reinterpret_cast<nsSSLStatus*>(supports.get());
   386   if (!mSSLStatus) {
   387     return NS_ERROR_FAILURE;
   388   }
   389   return NS_OK;
   390 }
   392 NS_IMETHODIMP
   393 TransportSecurityInfo::GetInterfaces(uint32_t *count, nsIID * **array)
   394 {
   395   *count = 0;
   396   *array = nullptr;
   397   return NS_OK;
   398 }
   400 NS_IMETHODIMP
   401 TransportSecurityInfo::GetHelperForLanguage(uint32_t language,
   402                                             nsISupports **_retval)
   403 {
   404   *_retval = nullptr;
   405   return NS_OK;
   406 }
   408 NS_IMETHODIMP
   409 TransportSecurityInfo::GetContractID(char * *aContractID)
   410 {
   411   *aContractID = nullptr;
   412   return NS_OK;
   413 }
   415 NS_IMETHODIMP
   416 TransportSecurityInfo::GetClassDescription(char * *aClassDescription)
   417 {
   418   *aClassDescription = nullptr;
   419   return NS_OK;
   420 }
   422 NS_IMETHODIMP
   423 TransportSecurityInfo::GetClassID(nsCID * *aClassID)
   424 {
   425   *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
   426   if (!*aClassID)
   427     return NS_ERROR_OUT_OF_MEMORY;
   428   return GetClassIDNoAlloc(*aClassID);
   429 }
   431 NS_IMETHODIMP
   432 TransportSecurityInfo::GetImplementationLanguage(
   433   uint32_t *aImplementationLanguage)
   434 {
   435   *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
   436   return NS_OK;
   437 }
   439 NS_IMETHODIMP
   440 TransportSecurityInfo::GetFlags(uint32_t *aFlags)
   441 {
   442   *aFlags = 0;
   443   return NS_OK;
   444 }
   446 static NS_DEFINE_CID(kNSSSocketInfoCID, TRANSPORTSECURITYINFO_CID);
   448 NS_IMETHODIMP
   449 TransportSecurityInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
   450 {
   451   *aClassIDNoAlloc = kNSSSocketInfoCID;
   452   return NS_OK;
   453 }
   455 nsresult
   456 TransportSecurityInfo::GetSSLStatus(nsISSLStatus** _result)
   457 {
   458   NS_ENSURE_ARG_POINTER(_result);
   460   *_result = mSSLStatus;
   461   NS_IF_ADDREF(*_result);
   463   return NS_OK;
   464 }
   466 nsresult
   467 TransportSecurityInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
   468 {
   469   mSSLStatus = aSSLStatus;
   471   return NS_OK;
   472 }
   474 /* Formats an error message for non-certificate-related SSL errors
   475  * and non-overridable certificate errors (both are of type
   476  * PlainErrormMessage). Use formatOverridableCertErrorMessage
   477  * for overridable cert errors.
   478  */
   479 static nsresult
   480 formatPlainErrorMessage(const nsXPIDLCString &host, int32_t port,
   481                         PRErrorCode err, 
   482                         bool suppressPort443,
   483                         nsString &returnedMessage)
   484 {
   485   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   487   const char16_t *params[1];
   488   nsresult rv;
   490   nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
   491   NS_ENSURE_SUCCESS(rv, rv);
   493   if (host.Length())
   494   {
   495     nsString hostWithPort;
   497     // For now, hide port when it's 443 and we're reporting the error.
   498     // In the future a better mechanism should be used
   499     // to make a decision about showing the port number, possibly by requiring
   500     // the context object to implement a specific interface.
   501     // The motivation is that Mozilla browser would like to hide the port number
   502     // in error pages in the common case.
   504     hostWithPort.AssignASCII(host);
   505     if (!suppressPort443 || port != 443) {
   506       hostWithPort.AppendLiteral(":");
   507       hostWithPort.AppendInt(port);
   508     }
   509     params[0] = hostWithPort.get();
   511     nsString formattedString;
   512     rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix", 
   513                                                   params, 1, 
   514                                                   formattedString);
   515     if (NS_SUCCEEDED(rv))
   516     {
   517       returnedMessage.Append(formattedString);
   518       returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
   519     }
   520   }
   522   nsString explanation;
   523   rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
   524   if (NS_SUCCEEDED(rv))
   525     returnedMessage.Append(explanation);
   527   return NS_OK;
   528 }
   530 static void
   531 AppendErrorTextUntrusted(PRErrorCode errTrust,
   532                          const nsString &host,
   533                          nsIX509Cert* ix509,
   534                          nsINSSComponent *component,
   535                          nsString &returnedMessage)
   536 {
   537   const char *errorID = nullptr;
   538   nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
   539   if (cert3) {
   540     bool isSelfSigned;
   541     if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
   542         && isSelfSigned) {
   543       errorID = "certErrorTrust_SelfSigned";
   544     }
   545   }
   547   if (!errorID) {
   548     switch (errTrust) {
   549       case SEC_ERROR_UNKNOWN_ISSUER:
   550       {
   551         nsCOMPtr<nsIArray> chain;
   552         ix509->GetChain(getter_AddRefs(chain));
   553         uint32_t length = 0;
   554         if (chain && NS_FAILED(chain->GetLength(&length)))
   555           length = 0;
   556         if (length == 1)
   557           errorID = "certErrorTrust_MissingChain";
   558         else
   559           errorID = "certErrorTrust_UnknownIssuer";
   560         break;
   561       }
   562       case SEC_ERROR_CA_CERT_INVALID:
   563         errorID = "certErrorTrust_CaInvalid";
   564         break;
   565       case SEC_ERROR_UNTRUSTED_ISSUER:
   566         errorID = "certErrorTrust_Issuer";
   567         break;
   568       case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   569         errorID = "certErrorTrust_SignatureAlgorithmDisabled";
   570         break;
   571       case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
   572         errorID = "certErrorTrust_ExpiredIssuer";
   573         break;
   574       case SEC_ERROR_UNTRUSTED_CERT:
   575       default:
   576         errorID = "certErrorTrust_Untrusted";
   577         break;
   578     }
   579   }
   581   nsString formattedString;
   582   nsresult rv = component->GetPIPNSSBundleString(errorID, 
   583                                                  formattedString);
   584   if (NS_SUCCEEDED(rv))
   585   {
   586     returnedMessage.Append(formattedString);
   587     returnedMessage.Append(NS_LITERAL_STRING("\n"));
   588   }
   589 }
   591 // returns TRUE if SAN was used to produce names
   592 // return FALSE if nothing was produced
   593 // names => a single name or a list of names
   594 // multipleNames => whether multiple names were delivered
   595 static bool
   596 GetSubjectAltNames(CERTCertificate *nssCert,
   597                    nsINSSComponent *component,
   598                    nsString &allNames,
   599                    uint32_t &nameCount)
   600 {
   601   allNames.Truncate();
   602   nameCount = 0;
   604   PLArenaPool *san_arena = nullptr;
   605   SECItem altNameExtension = {siBuffer, nullptr, 0 };
   606   CERTGeneralName *sanNameList = nullptr;
   608   SECStatus rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
   609                                         &altNameExtension);
   610   if (rv != SECSuccess)
   611     return false;
   613   san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   614   if (!san_arena)
   615     return false;
   617   sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
   618   if (!sanNameList)
   619     return false;
   621   SECITEM_FreeItem(&altNameExtension, false);
   623   CERTGeneralName *current = sanNameList;
   624   do {
   625     nsAutoString name;
   626     switch (current->type) {
   627       case certDNSName:
   628         {
   629           nsDependentCSubstring nameFromCert(reinterpret_cast<char*>
   630                                               (current->name.other.data),
   631                                               current->name.other.len);
   632           // dNSName fields are defined as type IA5String and thus should
   633           // be limited to ASCII characters.
   634           if (IsASCII(nameFromCert)) {
   635             name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
   636             if (!allNames.IsEmpty()) {
   637               allNames.Append(NS_LITERAL_STRING(", "));
   638             }
   639             ++nameCount;
   640             allNames.Append(name);
   641           }
   642         }
   643         break;
   645       case certIPAddress:
   646         {
   647           char buf[INET6_ADDRSTRLEN];
   648           PRNetAddr addr;
   649           if (current->name.other.len == 4) {
   650             addr.inet.family = PR_AF_INET;
   651             memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
   652             PR_NetAddrToString(&addr, buf, sizeof(buf));
   653             name.AssignASCII(buf);
   654           } else if (current->name.other.len == 16) {
   655             addr.ipv6.family = PR_AF_INET6;
   656             memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
   657             PR_NetAddrToString(&addr, buf, sizeof(buf));
   658             name.AssignASCII(buf);
   659           } else {
   660             /* invalid IP address */
   661           }
   662           if (!name.IsEmpty()) {
   663             if (!allNames.IsEmpty()) {
   664               allNames.Append(NS_LITERAL_STRING(", "));
   665             }
   666             ++nameCount;
   667             allNames.Append(name);
   668           }
   669           break;
   670         }
   672       default: // all other types of names are ignored
   673         break;
   674     }
   675     current = CERT_GetNextGeneralName(current);
   676   } while (current != sanNameList); // double linked
   678   PORT_FreeArena(san_arena, false);
   679   return true;
   680 }
   682 static void
   683 AppendErrorTextMismatch(const nsString &host,
   684                         nsIX509Cert* ix509,
   685                         nsINSSComponent *component,
   686                         bool wantsHtml,
   687                         nsString &returnedMessage)
   688 {
   689   const char16_t *params[1];
   690   nsresult rv;
   692   mozilla::pkix::ScopedCERTCertificate nssCert;
   694   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
   695   if (cert2)
   696     nssCert = cert2->GetCert();
   698   if (!nssCert) {
   699     // We are unable to extract the valid names, say "not valid for name".
   700     params[0] = host.get();
   701     nsString formattedString;
   702     rv = component->PIPBundleFormatStringFromName("certErrorMismatch", 
   703                                                   params, 1, 
   704                                                   formattedString);
   705     if (NS_SUCCEEDED(rv)) {
   706       returnedMessage.Append(formattedString);
   707       returnedMessage.Append(NS_LITERAL_STRING("\n"));
   708     }
   709     return;
   710   }
   712   nsString allNames;
   713   uint32_t nameCount = 0;
   714   bool useSAN = false;
   716   if (nssCert)
   717     useSAN = GetSubjectAltNames(nssCert.get(), component, allNames, nameCount);
   719   if (!useSAN) {
   720     char *certName = nullptr;
   721     // currently CERT_FindNSStringExtension is not being exported by NSS.
   722     // If it gets exported, enable the following line.
   723     //   certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
   724     // However, it has been discussed to treat the extension as obsolete and ignore it.
   725     if (!certName)
   726       certName = CERT_GetCommonName(&nssCert->subject);
   727     if (certName) {
   728       nsDependentCSubstring commonName(certName, strlen(certName));
   729       if (IsUTF8(commonName)) {
   730         // Bug 1024781
   731         // We should actually check that the common name is a valid dns name or
   732         // ip address and not any string value before adding it to the display
   733         // list.
   734         ++nameCount;
   735         allNames.Assign(NS_ConvertUTF8toUTF16(commonName));
   736       }
   737       PORT_Free(certName);
   738     }
   739   }
   741   if (nameCount > 1) {
   742     nsString message;
   743     rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple", 
   744                                           message);
   745     if (NS_SUCCEEDED(rv)) {
   746       returnedMessage.Append(message);
   747       returnedMessage.Append(NS_LITERAL_STRING("\n  "));
   748       returnedMessage.Append(allNames);
   749       returnedMessage.Append(NS_LITERAL_STRING("  \n"));
   750     }
   751   }
   752   else if (nameCount == 1) {
   753     const char16_t *params[1];
   754     params[0] = allNames.get();
   756     const char *stringID;
   757     if (wantsHtml)
   758       stringID = "certErrorMismatchSingle2";
   759     else
   760       stringID = "certErrorMismatchSinglePlain";
   762     nsString formattedString;
   763     rv = component->PIPBundleFormatStringFromName(stringID, 
   764                                                   params, 1, 
   765                                                   formattedString);
   766     if (NS_SUCCEEDED(rv)) {
   767       returnedMessage.Append(formattedString);
   768       returnedMessage.Append(NS_LITERAL_STRING("\n"));
   769     }
   770   }
   771   else { // nameCount == 0
   772     nsString message;
   773     nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames",
   774                                                    message);
   775     if (NS_SUCCEEDED(rv)) {
   776       returnedMessage.Append(message);
   777       returnedMessage.Append(NS_LITERAL_STRING("\n"));
   778     }
   779   }
   780 }
   782 static void
   783 GetDateBoundary(nsIX509Cert* ix509,
   784                 nsString &formattedDate,
   785                 nsString &nowDate,
   786                 bool &trueExpired_falseNotYetValid)
   787 {
   788   trueExpired_falseNotYetValid = true;
   789   formattedDate.Truncate();
   791   PRTime notAfter, notBefore, timeToUse;
   792   nsCOMPtr<nsIX509CertValidity> validity;
   793   nsresult rv;
   795   rv = ix509->GetValidity(getter_AddRefs(validity));
   796   if (NS_FAILED(rv))
   797     return;
   799   rv = validity->GetNotAfter(&notAfter);
   800   if (NS_FAILED(rv))
   801     return;
   803   rv = validity->GetNotBefore(&notBefore);
   804   if (NS_FAILED(rv))
   805     return;
   807   PRTime now = PR_Now();
   808   if (now > notAfter) {
   809     timeToUse = notAfter;
   810   } else {
   811     timeToUse = notBefore;
   812     trueExpired_falseNotYetValid = false;
   813   }
   815   nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv));
   816   if (NS_FAILED(rv))
   817     return;
   819   dateTimeFormat->FormatPRTime(nullptr, kDateFormatShort, 
   820                                kTimeFormatNoSeconds, timeToUse, 
   821                                formattedDate);
   822   dateTimeFormat->FormatPRTime(nullptr, kDateFormatShort,
   823                                kTimeFormatNoSeconds, now,
   824                                nowDate);
   825 }
   827 static void
   828 AppendErrorTextTime(nsIX509Cert* ix509,
   829                     nsINSSComponent *component,
   830                     nsString &returnedMessage)
   831 {
   832   nsAutoString formattedDate, nowDate;
   833   bool trueExpired_falseNotYetValid;
   834   GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
   836   const char16_t *params[2];
   837   params[0] = formattedDate.get(); // might be empty, if helper function had a problem 
   838   params[1] = nowDate.get();
   840   const char *key = trueExpired_falseNotYetValid ? 
   841                     "certErrorExpiredNow" : "certErrorNotYetValidNow";
   842   nsresult rv;
   843   nsString formattedString;
   844   rv = component->PIPBundleFormatStringFromName(
   845            key,
   846            params, 
   847            ArrayLength(params),
   848            formattedString);
   849   if (NS_SUCCEEDED(rv))
   850   {
   851     returnedMessage.Append(formattedString);
   852     returnedMessage.Append(NS_LITERAL_STRING("\n"));
   853   }
   854 }
   856 static void
   857 AppendErrorTextCode(PRErrorCode errorCodeToReport,
   858                     nsINSSComponent *component,
   859                     nsString &returnedMessage)
   860 {
   861   const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
   862   if (codeName)
   863   {
   864     nsCString error_id(codeName);
   865     ToLowerCase(error_id);
   866     NS_ConvertASCIItoUTF16 idU(error_id);
   868     const char16_t *params[1];
   869     params[0] = idU.get();
   871     nsString formattedString;
   872     nsresult rv;
   873     rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix", 
   874                                                   params, 1, 
   875                                                   formattedString);
   876     if (NS_SUCCEEDED(rv)) {
   877       returnedMessage.Append(NS_LITERAL_STRING("\n"));
   878       returnedMessage.Append(formattedString);
   879       returnedMessage.Append(NS_LITERAL_STRING("\n"));
   880     }
   881     else {
   882       returnedMessage.Append(NS_LITERAL_STRING(" ("));
   883       returnedMessage.Append(idU);
   884       returnedMessage.Append(NS_LITERAL_STRING(")"));
   885     }
   886   }
   887 }
   889 /* Formats an error message for overridable certificate errors (of type
   890  * OverridableCertErrorMessage). Use formatPlainErrorMessage to format
   891  * non-overridable cert errors and non-cert-related errors.
   892  */
   893 static nsresult
   894 formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
   895                                   PRErrorCode errorCodeToReport, 
   896                                   const nsXPIDLCString & host, int32_t port,
   897                                   bool suppressPort443,
   898                                   bool wantsHtml,
   899                                   nsString & returnedMessage)
   900 {
   901   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   903   const char16_t *params[1];
   904   nsresult rv;
   905   nsAutoString hostWithPort;
   906   nsAutoString hostWithoutPort;
   908   // For now, hide port when it's 443 and we're reporting the error.
   909   // In the future a better mechanism should be used
   910   // to make a decision about showing the port number, possibly by requiring
   911   // the context object to implement a specific interface.
   912   // The motivation is that Mozilla browser would like to hide the port number
   913   // in error pages in the common case.
   915   hostWithoutPort.AppendASCII(host);
   916   if (suppressPort443 && port == 443) {
   917     params[0] = hostWithoutPort.get();
   918   } else {
   919     hostWithPort.AppendASCII(host);
   920     hostWithPort.Append(':');
   921     hostWithPort.AppendInt(port);
   922     params[0] = hostWithPort.get();
   923   }
   925   nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
   926   NS_ENSURE_SUCCESS(rv, rv);
   928   returnedMessage.Truncate();
   929   rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
   930                                                 returnedMessage);
   931   NS_ENSURE_SUCCESS(rv, rv);
   933   returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
   935   RefPtr<nsIX509Cert> ix509;
   936   rv = sslStatus.GetServerCert(byRef(ix509));
   937   NS_ENSURE_SUCCESS(rv, rv);
   939   bool isUntrusted;
   940   rv = sslStatus.GetIsUntrusted(&isUntrusted);
   941   NS_ENSURE_SUCCESS(rv, rv);
   942   if (isUntrusted) {
   943     AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509, 
   944                              component, returnedMessage);
   945   }
   947   bool isDomainMismatch;
   948   rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
   949   NS_ENSURE_SUCCESS(rv, rv);
   950   if (isDomainMismatch) {
   951     AppendErrorTextMismatch(hostWithoutPort, ix509, component, wantsHtml, returnedMessage);
   952   }
   954   bool isNotValidAtThisTime;
   955   rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
   956   NS_ENSURE_SUCCESS(rv, rv);
   957   if (isNotValidAtThisTime) {
   958     AppendErrorTextTime(ix509, component, returnedMessage);
   959   }
   961   AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
   963   return NS_OK;
   964 }
   966 // RememberCertErrorsTable
   968 /*static*/ RememberCertErrorsTable*
   969 RememberCertErrorsTable::sInstance = nullptr;
   971 RememberCertErrorsTable::RememberCertErrorsTable()
   972   : mErrorHosts(16)
   973   , mMutex("RememberCertErrorsTable::mMutex")
   974 {
   975 }
   977 static nsresult
   978 GetHostPortKey(TransportSecurityInfo* infoObject, nsAutoCString &result)
   979 {
   980   nsresult rv;
   982   result.Truncate();
   984   nsXPIDLCString hostName;
   985   rv = infoObject->GetHostName(getter_Copies(hostName));
   986   NS_ENSURE_SUCCESS(rv, rv);
   988   int32_t port;
   989   rv = infoObject->GetPort(&port);
   990   NS_ENSURE_SUCCESS(rv, rv);
   992   result.Assign(hostName);
   993   result.Append(':');
   994   result.AppendInt(port);
   996   return NS_OK;
   997 }
   999 void
  1000 RememberCertErrorsTable::RememberCertHasError(TransportSecurityInfo* infoObject,
  1001                                               nsSSLStatus* status,
  1002                                               SECStatus certVerificationResult)
  1004   nsresult rv;
  1006   nsAutoCString hostPortKey;
  1007   rv = GetHostPortKey(infoObject, hostPortKey);
  1008   if (NS_FAILED(rv))
  1009     return;
  1011   if (certVerificationResult != SECSuccess) {
  1012     NS_ASSERTION(status,
  1013         "Must have nsSSLStatus object when remembering flags");
  1015     if (!status)
  1016       return;
  1018     CertStateBits bits;
  1019     bits.mIsDomainMismatch = status->mIsDomainMismatch;
  1020     bits.mIsNotValidAtThisTime = status->mIsNotValidAtThisTime;
  1021     bits.mIsUntrusted = status->mIsUntrusted;
  1023     MutexAutoLock lock(mMutex);
  1024     mErrorHosts.Put(hostPortKey, bits);
  1026   else {
  1027     MutexAutoLock lock(mMutex);
  1028     mErrorHosts.Remove(hostPortKey);
  1032 void
  1033 RememberCertErrorsTable::LookupCertErrorBits(TransportSecurityInfo* infoObject,
  1034                                              nsSSLStatus* status)
  1036   // Get remembered error bits from our cache, because of SSL session caching
  1037   // the NSS library potentially hasn't notified us for this socket.
  1038   if (status->mHaveCertErrorBits)
  1039     // Rather do not modify bits if already set earlier
  1040     return;
  1042   nsresult rv;
  1044   nsAutoCString hostPortKey;
  1045   rv = GetHostPortKey(infoObject, hostPortKey);
  1046   if (NS_FAILED(rv))
  1047     return;
  1049   CertStateBits bits;
  1051     MutexAutoLock lock(mMutex);
  1052     if (!mErrorHosts.Get(hostPortKey, &bits))
  1053       // No record was found, this host had no cert errors
  1054       return;
  1057   // This host had cert errors, update the bits correctly
  1058   status->mHaveCertErrorBits = true;
  1059   status->mIsDomainMismatch = bits.mIsDomainMismatch;
  1060   status->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
  1061   status->mIsUntrusted = bits.mIsUntrusted;
  1064 void
  1065 TransportSecurityInfo::SetStatusErrorBits(nsIX509Cert & cert,
  1066                                           uint32_t collected_errors)
  1068   MutexAutoLock lock(mMutex);
  1070   if (!mSSLStatus)
  1071     mSSLStatus = new nsSSLStatus();
  1073   mSSLStatus->mServerCert = &cert;
  1075   mSSLStatus->mHaveCertErrorBits = true;
  1076   mSSLStatus->mIsDomainMismatch = 
  1077     collected_errors & nsICertOverrideService::ERROR_MISMATCH;
  1078   mSSLStatus->mIsNotValidAtThisTime = 
  1079     collected_errors & nsICertOverrideService::ERROR_TIME;
  1080   mSSLStatus->mIsUntrusted = 
  1081     collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
  1083   RememberCertErrorsTable::GetInstance().RememberCertHasError(this,
  1084                                                               mSSLStatus,
  1085                                                               SECFailure);
  1088 } } // namespace mozilla::psm

mercurial