security/manager/ssl/src/TransportSecurityInfo.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/manager/ssl/src/TransportSecurityInfo.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1088 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "TransportSecurityInfo.h"
    1.11 +
    1.12 +#include "pkix/pkixtypes.h"
    1.13 +#include "nsNSSComponent.h"
    1.14 +#include "nsIWebProgressListener.h"
    1.15 +#include "nsNSSCertificate.h"
    1.16 +#include "nsIX509CertValidity.h"
    1.17 +#include "nsIDateTimeFormat.h"
    1.18 +#include "nsDateTimeFormatCID.h"
    1.19 +#include "nsICertOverrideService.h"
    1.20 +#include "nsIObjectInputStream.h"
    1.21 +#include "nsIObjectOutputStream.h"
    1.22 +#include "nsNSSCertHelper.h"
    1.23 +#include "nsIProgrammingLanguage.h"
    1.24 +#include "nsIArray.h"
    1.25 +#include "nsComponentManagerUtils.h"
    1.26 +#include "nsReadableUtils.h"
    1.27 +#include "nsServiceManagerUtils.h"
    1.28 +#include "PSMRunnable.h"
    1.29 +
    1.30 +#include "secerr.h"
    1.31 +
    1.32 +//#define DEBUG_SSL_VERBOSE //Enable this define to get minimal 
    1.33 +                            //reports when doing SSL read/write
    1.34 +                            
    1.35 +//#define DUMP_BUFFER  //Enable this define along with
    1.36 +                       //DEBUG_SSL_VERBOSE to dump SSL
    1.37 +                       //read/write buffer to a log.
    1.38 +                       //Uses PR_LOG except on Mac where
    1.39 +                       //we always write out to our own
    1.40 +                       //file.
    1.41 +
    1.42 +namespace mozilla { namespace psm {
    1.43 +
    1.44 +TransportSecurityInfo::TransportSecurityInfo()
    1.45 +  : mMutex("TransportSecurityInfo::mMutex"),
    1.46 +    mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
    1.47 +    mSubRequestsBrokenSecurity(0),
    1.48 +    mSubRequestsNoSecurity(0),
    1.49 +    mErrorCode(0),
    1.50 +    mErrorMessageType(PlainErrorMessage),
    1.51 +    mPort(0)
    1.52 +{
    1.53 +}
    1.54 +
    1.55 +TransportSecurityInfo::~TransportSecurityInfo()
    1.56 +{
    1.57 +  nsNSSShutDownPreventionLock locker;
    1.58 +  if (isAlreadyShutDown())
    1.59 +    return;
    1.60 +
    1.61 +  shutdown(calledFromObject);
    1.62 +}
    1.63 +
    1.64 +void
    1.65 +TransportSecurityInfo::virtualDestroyNSSReference()
    1.66 +{
    1.67 +}
    1.68 +
    1.69 +NS_IMPL_ISUPPORTS(TransportSecurityInfo,
    1.70 +                  nsITransportSecurityInfo,
    1.71 +                  nsIInterfaceRequestor,
    1.72 +                  nsISSLStatusProvider,
    1.73 +                  nsIAssociatedContentSecurity,
    1.74 +                  nsISerializable,
    1.75 +                  nsIClassInfo)
    1.76 +
    1.77 +nsresult
    1.78 +TransportSecurityInfo::SetHostName(const char* host)
    1.79 +{
    1.80 +  mHostName.Adopt(host ? NS_strdup(host) : 0);
    1.81 +  return NS_OK;
    1.82 +}
    1.83 +
    1.84 +nsresult
    1.85 +TransportSecurityInfo::GetHostName(char **host)
    1.86 +{
    1.87 +  *host = (mHostName) ? NS_strdup(mHostName) : nullptr;
    1.88 +  return NS_OK;
    1.89 +}
    1.90 +
    1.91 +nsresult
    1.92 +TransportSecurityInfo::SetPort(int32_t aPort)
    1.93 +{
    1.94 +  mPort = aPort;
    1.95 +  return NS_OK;
    1.96 +}
    1.97 +
    1.98 +nsresult
    1.99 +TransportSecurityInfo::GetPort(int32_t *aPort)
   1.100 +{
   1.101 +  *aPort = mPort;
   1.102 +  return NS_OK;
   1.103 +}
   1.104 +
   1.105 +PRErrorCode
   1.106 +TransportSecurityInfo::GetErrorCode() const
   1.107 +{
   1.108 +  MutexAutoLock lock(mMutex);
   1.109 +
   1.110 +  return mErrorCode;
   1.111 +}
   1.112 +
   1.113 +void
   1.114 +TransportSecurityInfo::SetCanceled(PRErrorCode errorCode,
   1.115 +                                   SSLErrorMessageType errorMessageType)
   1.116 +{
   1.117 +  MutexAutoLock lock(mMutex);
   1.118 +
   1.119 +  mErrorCode = errorCode;
   1.120 +  mErrorMessageType = errorMessageType;
   1.121 +  mErrorMessageCached.Truncate();
   1.122 +}
   1.123 +
   1.124 +NS_IMETHODIMP
   1.125 +TransportSecurityInfo::GetSecurityState(uint32_t* state)
   1.126 +{
   1.127 +  *state = mSecurityState;
   1.128 +  return NS_OK;
   1.129 +}
   1.130 +
   1.131 +nsresult
   1.132 +TransportSecurityInfo::SetSecurityState(uint32_t aState)
   1.133 +{
   1.134 +  mSecurityState = aState;
   1.135 +  return NS_OK;
   1.136 +}
   1.137 +
   1.138 +/* attribute unsigned long countSubRequestsBrokenSecurity; */
   1.139 +NS_IMETHODIMP
   1.140 +TransportSecurityInfo::GetCountSubRequestsBrokenSecurity(
   1.141 +  int32_t *aSubRequestsBrokenSecurity)
   1.142 +{
   1.143 +  *aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
   1.144 +  return NS_OK;
   1.145 +}
   1.146 +
   1.147 +NS_IMETHODIMP
   1.148 +TransportSecurityInfo::SetCountSubRequestsBrokenSecurity(
   1.149 +  int32_t aSubRequestsBrokenSecurity)
   1.150 +{
   1.151 +  mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
   1.152 +  return NS_OK;
   1.153 +}
   1.154 +
   1.155 +/* attribute unsigned long countSubRequestsNoSecurity; */
   1.156 +NS_IMETHODIMP
   1.157 +TransportSecurityInfo::GetCountSubRequestsNoSecurity(
   1.158 +  int32_t *aSubRequestsNoSecurity)
   1.159 +{
   1.160 +  *aSubRequestsNoSecurity = mSubRequestsNoSecurity;
   1.161 +  return NS_OK;
   1.162 +}
   1.163 +
   1.164 +NS_IMETHODIMP
   1.165 +TransportSecurityInfo::SetCountSubRequestsNoSecurity(
   1.166 +  int32_t aSubRequestsNoSecurity)
   1.167 +{
   1.168 +  mSubRequestsNoSecurity = aSubRequestsNoSecurity;
   1.169 +  return NS_OK;
   1.170 +}
   1.171 +
   1.172 +NS_IMETHODIMP
   1.173 +TransportSecurityInfo::Flush()
   1.174 +{
   1.175 +  return NS_OK;
   1.176 +}
   1.177 +
   1.178 +NS_IMETHODIMP
   1.179 +TransportSecurityInfo::GetErrorMessage(char16_t** aText)
   1.180 +{
   1.181 +  NS_ENSURE_ARG_POINTER(aText);
   1.182 +  *aText = nullptr;
   1.183 +
   1.184 +  if (!NS_IsMainThread()) {
   1.185 +    NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
   1.186 +    return NS_ERROR_NOT_SAME_THREAD;
   1.187 +  }
   1.188 +
   1.189 +  MutexAutoLock lock(mMutex);
   1.190 +
   1.191 +  if (mErrorMessageCached.IsEmpty()) {
   1.192 +    nsresult rv = formatErrorMessage(lock, 
   1.193 +                                     mErrorCode, mErrorMessageType,
   1.194 +                                     true, true, mErrorMessageCached);
   1.195 +    NS_ENSURE_SUCCESS(rv, rv);
   1.196 +  }
   1.197 +
   1.198 +  *aText = ToNewUnicode(mErrorMessageCached);
   1.199 +  return *aText ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   1.200 +}
   1.201 +
   1.202 +void
   1.203 +TransportSecurityInfo::GetErrorLogMessage(PRErrorCode errorCode,
   1.204 +                                          SSLErrorMessageType errorMessageType,
   1.205 +                                          nsString &result)
   1.206 +{
   1.207 +  if (!NS_IsMainThread()) {
   1.208 +    NS_ERROR("nsNSSSocketInfo::GetErrorLogMessage called off the main thread");
   1.209 +    return;
   1.210 +  }
   1.211 +
   1.212 +  MutexAutoLock lock(mMutex);
   1.213 +  (void) formatErrorMessage(lock, errorCode, errorMessageType,
   1.214 +                            false, false, result);
   1.215 +}
   1.216 +
   1.217 +static nsresult
   1.218 +formatPlainErrorMessage(nsXPIDLCString const & host, int32_t port,
   1.219 +                        PRErrorCode err, 
   1.220 +                        bool suppressPort443,
   1.221 +                        nsString &returnedMessage);
   1.222 +
   1.223 +static nsresult
   1.224 +formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
   1.225 +                                  PRErrorCode errorCodeToReport, 
   1.226 +                                  const nsXPIDLCString & host, int32_t port,
   1.227 +                                  bool suppressPort443,
   1.228 +                                  bool wantsHtml,
   1.229 +                                  nsString & returnedMessage);
   1.230 +
   1.231 +// XXX: uses nsNSSComponent string bundles off the main thread when called by
   1.232 +//      nsNSSSocketInfo::Write().
   1.233 +nsresult
   1.234 +TransportSecurityInfo::formatErrorMessage(MutexAutoLock const & proofOfLock, 
   1.235 +                                          PRErrorCode errorCode,
   1.236 +                                          SSLErrorMessageType errorMessageType,
   1.237 +                                          bool wantsHtml, bool suppressPort443, 
   1.238 +                                          nsString &result)
   1.239 +{
   1.240 +  if (errorCode == 0) {
   1.241 +    result.Truncate();
   1.242 +    return NS_OK;
   1.243 +  }
   1.244 +
   1.245 +  nsresult rv;
   1.246 +  NS_ConvertASCIItoUTF16 hostNameU(mHostName);
   1.247 +  NS_ASSERTION(errorMessageType != OverridableCertErrorMessage || 
   1.248 +                (mSSLStatus && mSSLStatus->mServerCert &&
   1.249 +                 mSSLStatus->mHaveCertErrorBits),
   1.250 +                "GetErrorLogMessage called for cert error without cert");
   1.251 +  if (errorMessageType == OverridableCertErrorMessage && 
   1.252 +      mSSLStatus && mSSLStatus->mServerCert) {
   1.253 +    rv = formatOverridableCertErrorMessage(*mSSLStatus, errorCode,
   1.254 +                                           mHostName, mPort,
   1.255 +                                           suppressPort443,
   1.256 +                                           wantsHtml,
   1.257 +                                           result);
   1.258 +  } else {
   1.259 +    rv = formatPlainErrorMessage(mHostName, mPort, 
   1.260 +                                 errorCode,
   1.261 +                                 suppressPort443,
   1.262 +                                 result);
   1.263 +  }
   1.264 +
   1.265 +  if (NS_FAILED(rv)) {
   1.266 +    result.Truncate();
   1.267 +  }
   1.268 +
   1.269 +  return rv;
   1.270 +}
   1.271 +
   1.272 +/* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
   1.273 +NS_IMETHODIMP
   1.274 +TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result)
   1.275 +{
   1.276 +  if (!NS_IsMainThread()) {
   1.277 +    NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
   1.278 +    return NS_ERROR_NOT_SAME_THREAD;
   1.279 +  }
   1.280 +
   1.281 +  nsresult rv;
   1.282 +  if (!mCallbacks) {
   1.283 +    nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
   1.284 +    rv = ir->GetInterface(uuid, result);
   1.285 +  } else {
   1.286 +    rv = mCallbacks->GetInterface(uuid, result);
   1.287 +  }
   1.288 +  return rv;
   1.289 +}
   1.290 +
   1.291 +// This is a new magic value. However, it re-uses the first 4 bytes
   1.292 +// of the previous value. This is so when older versions attempt to
   1.293 +// read a newer serialized TransportSecurityInfo, they will actually
   1.294 +// fail and return NS_ERROR_FAILURE instead of silently failing.
   1.295 +#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x28ea, 0x45d2, \
   1.296 +  { 0xa2, 0x5a, 0x35, 0x7c, 0xae, 0xfa, 0x7f, 0x82 } }
   1.297 +static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
   1.298 +
   1.299 +NS_IMETHODIMP
   1.300 +TransportSecurityInfo::Write(nsIObjectOutputStream* stream)
   1.301 +{
   1.302 +  nsresult rv = stream->WriteID(kTransportSecurityInfoMagic);
   1.303 +  if (NS_FAILED(rv)) {
   1.304 +    return rv;
   1.305 +  }
   1.306 +
   1.307 +  MutexAutoLock lock(mMutex);
   1.308 +
   1.309 +  rv = stream->Write32(mSecurityState);
   1.310 +  if (NS_FAILED(rv)) {
   1.311 +    return rv;
   1.312 +  }
   1.313 +  rv = stream->Write32(mSubRequestsBrokenSecurity);
   1.314 +  if (NS_FAILED(rv)) {
   1.315 +    return rv;
   1.316 +  }
   1.317 +  rv = stream->Write32(mSubRequestsNoSecurity);
   1.318 +  if (NS_FAILED(rv)) {
   1.319 +    return rv;
   1.320 +  }
   1.321 +  // XXX: uses nsNSSComponent string bundles off the main thread
   1.322 +  rv = formatErrorMessage(lock, mErrorCode, mErrorMessageType, true, true,
   1.323 +                          mErrorMessageCached);
   1.324 +  if (NS_FAILED(rv)) {
   1.325 +    return rv;
   1.326 +  }
   1.327 +  rv = stream->WriteWStringZ(mErrorMessageCached.get());
   1.328 +  if (NS_FAILED(rv)) {
   1.329 +    return rv;
   1.330 +  }
   1.331 +  nsCOMPtr<nsISerializable> serializable(mSSLStatus);
   1.332 +  rv = stream->WriteCompoundObject(serializable, NS_GET_IID(nsISSLStatus),
   1.333 +                                   true);
   1.334 +  if (NS_FAILED(rv)) {
   1.335 +    return rv;
   1.336 +  }
   1.337 +  return NS_OK;
   1.338 +}
   1.339 +
   1.340 +NS_IMETHODIMP
   1.341 +TransportSecurityInfo::Read(nsIObjectInputStream* stream)
   1.342 +{
   1.343 +  nsID id;
   1.344 +  nsresult rv = stream->ReadID(&id);
   1.345 +  if (NS_FAILED(rv)) {
   1.346 +    return rv;
   1.347 +  }
   1.348 +  if (!id.Equals(kTransportSecurityInfoMagic)) {
   1.349 +    return NS_ERROR_UNEXPECTED;
   1.350 +  }
   1.351 +
   1.352 +  MutexAutoLock lock(mMutex);
   1.353 +
   1.354 +  rv = stream->Read32(&mSecurityState);
   1.355 +  if (NS_FAILED(rv)) {
   1.356 +    return rv;
   1.357 +  }
   1.358 +  uint32_t subRequestsBrokenSecurity;
   1.359 +  rv = stream->Read32(&subRequestsBrokenSecurity);
   1.360 +  if (NS_FAILED(rv)) {
   1.361 +    return rv;
   1.362 +  }
   1.363 +  if (subRequestsBrokenSecurity >
   1.364 +      static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
   1.365 +    return NS_ERROR_UNEXPECTED;
   1.366 +  }
   1.367 +  mSubRequestsBrokenSecurity = subRequestsBrokenSecurity;
   1.368 +  uint32_t subRequestsNoSecurity;
   1.369 +  rv = stream->Read32(&subRequestsNoSecurity);
   1.370 +  if (NS_FAILED(rv)) {
   1.371 +    return rv;
   1.372 +  }
   1.373 +  if (subRequestsNoSecurity >
   1.374 +      static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
   1.375 +    return NS_ERROR_UNEXPECTED;
   1.376 +  }
   1.377 +  mSubRequestsNoSecurity = subRequestsNoSecurity;
   1.378 +  rv = stream->ReadString(mErrorMessageCached);
   1.379 +  if (NS_FAILED(rv)) {
   1.380 +    return rv;
   1.381 +  }
   1.382 +  mErrorCode = 0;
   1.383 +  nsCOMPtr<nsISupports> supports;
   1.384 +  rv = stream->ReadObject(true, getter_AddRefs(supports));
   1.385 +  if (NS_FAILED(rv)) {
   1.386 +    return rv;
   1.387 +  }
   1.388 +  mSSLStatus = reinterpret_cast<nsSSLStatus*>(supports.get());
   1.389 +  if (!mSSLStatus) {
   1.390 +    return NS_ERROR_FAILURE;
   1.391 +  }
   1.392 +  return NS_OK;
   1.393 +}
   1.394 +
   1.395 +NS_IMETHODIMP
   1.396 +TransportSecurityInfo::GetInterfaces(uint32_t *count, nsIID * **array)
   1.397 +{
   1.398 +  *count = 0;
   1.399 +  *array = nullptr;
   1.400 +  return NS_OK;
   1.401 +}
   1.402 +
   1.403 +NS_IMETHODIMP
   1.404 +TransportSecurityInfo::GetHelperForLanguage(uint32_t language,
   1.405 +                                            nsISupports **_retval)
   1.406 +{
   1.407 +  *_retval = nullptr;
   1.408 +  return NS_OK;
   1.409 +}
   1.410 +
   1.411 +NS_IMETHODIMP
   1.412 +TransportSecurityInfo::GetContractID(char * *aContractID)
   1.413 +{
   1.414 +  *aContractID = nullptr;
   1.415 +  return NS_OK;
   1.416 +}
   1.417 +
   1.418 +NS_IMETHODIMP
   1.419 +TransportSecurityInfo::GetClassDescription(char * *aClassDescription)
   1.420 +{
   1.421 +  *aClassDescription = nullptr;
   1.422 +  return NS_OK;
   1.423 +}
   1.424 +
   1.425 +NS_IMETHODIMP
   1.426 +TransportSecurityInfo::GetClassID(nsCID * *aClassID)
   1.427 +{
   1.428 +  *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
   1.429 +  if (!*aClassID)
   1.430 +    return NS_ERROR_OUT_OF_MEMORY;
   1.431 +  return GetClassIDNoAlloc(*aClassID);
   1.432 +}
   1.433 +
   1.434 +NS_IMETHODIMP
   1.435 +TransportSecurityInfo::GetImplementationLanguage(
   1.436 +  uint32_t *aImplementationLanguage)
   1.437 +{
   1.438 +  *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
   1.439 +  return NS_OK;
   1.440 +}
   1.441 +
   1.442 +NS_IMETHODIMP
   1.443 +TransportSecurityInfo::GetFlags(uint32_t *aFlags)
   1.444 +{
   1.445 +  *aFlags = 0;
   1.446 +  return NS_OK;
   1.447 +}
   1.448 +
   1.449 +static NS_DEFINE_CID(kNSSSocketInfoCID, TRANSPORTSECURITYINFO_CID);
   1.450 +
   1.451 +NS_IMETHODIMP
   1.452 +TransportSecurityInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
   1.453 +{
   1.454 +  *aClassIDNoAlloc = kNSSSocketInfoCID;
   1.455 +  return NS_OK;
   1.456 +}
   1.457 +
   1.458 +nsresult
   1.459 +TransportSecurityInfo::GetSSLStatus(nsISSLStatus** _result)
   1.460 +{
   1.461 +  NS_ENSURE_ARG_POINTER(_result);
   1.462 +
   1.463 +  *_result = mSSLStatus;
   1.464 +  NS_IF_ADDREF(*_result);
   1.465 +
   1.466 +  return NS_OK;
   1.467 +}
   1.468 +
   1.469 +nsresult
   1.470 +TransportSecurityInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
   1.471 +{
   1.472 +  mSSLStatus = aSSLStatus;
   1.473 +
   1.474 +  return NS_OK;
   1.475 +}
   1.476 +
   1.477 +/* Formats an error message for non-certificate-related SSL errors
   1.478 + * and non-overridable certificate errors (both are of type
   1.479 + * PlainErrormMessage). Use formatOverridableCertErrorMessage
   1.480 + * for overridable cert errors.
   1.481 + */
   1.482 +static nsresult
   1.483 +formatPlainErrorMessage(const nsXPIDLCString &host, int32_t port,
   1.484 +                        PRErrorCode err, 
   1.485 +                        bool suppressPort443,
   1.486 +                        nsString &returnedMessage)
   1.487 +{
   1.488 +  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.489 +
   1.490 +  const char16_t *params[1];
   1.491 +  nsresult rv;
   1.492 +
   1.493 +  nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
   1.494 +  NS_ENSURE_SUCCESS(rv, rv);
   1.495 +
   1.496 +  if (host.Length())
   1.497 +  {
   1.498 +    nsString hostWithPort;
   1.499 +
   1.500 +    // For now, hide port when it's 443 and we're reporting the error.
   1.501 +    // In the future a better mechanism should be used
   1.502 +    // to make a decision about showing the port number, possibly by requiring
   1.503 +    // the context object to implement a specific interface.
   1.504 +    // The motivation is that Mozilla browser would like to hide the port number
   1.505 +    // in error pages in the common case.
   1.506 +
   1.507 +    hostWithPort.AssignASCII(host);
   1.508 +    if (!suppressPort443 || port != 443) {
   1.509 +      hostWithPort.AppendLiteral(":");
   1.510 +      hostWithPort.AppendInt(port);
   1.511 +    }
   1.512 +    params[0] = hostWithPort.get();
   1.513 +
   1.514 +    nsString formattedString;
   1.515 +    rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix", 
   1.516 +                                                  params, 1, 
   1.517 +                                                  formattedString);
   1.518 +    if (NS_SUCCEEDED(rv))
   1.519 +    {
   1.520 +      returnedMessage.Append(formattedString);
   1.521 +      returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
   1.522 +    }
   1.523 +  }
   1.524 +
   1.525 +  nsString explanation;
   1.526 +  rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
   1.527 +  if (NS_SUCCEEDED(rv))
   1.528 +    returnedMessage.Append(explanation);
   1.529 +
   1.530 +  return NS_OK;
   1.531 +}
   1.532 +
   1.533 +static void
   1.534 +AppendErrorTextUntrusted(PRErrorCode errTrust,
   1.535 +                         const nsString &host,
   1.536 +                         nsIX509Cert* ix509,
   1.537 +                         nsINSSComponent *component,
   1.538 +                         nsString &returnedMessage)
   1.539 +{
   1.540 +  const char *errorID = nullptr;
   1.541 +  nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
   1.542 +  if (cert3) {
   1.543 +    bool isSelfSigned;
   1.544 +    if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
   1.545 +        && isSelfSigned) {
   1.546 +      errorID = "certErrorTrust_SelfSigned";
   1.547 +    }
   1.548 +  }
   1.549 +
   1.550 +  if (!errorID) {
   1.551 +    switch (errTrust) {
   1.552 +      case SEC_ERROR_UNKNOWN_ISSUER:
   1.553 +      {
   1.554 +        nsCOMPtr<nsIArray> chain;
   1.555 +        ix509->GetChain(getter_AddRefs(chain));
   1.556 +        uint32_t length = 0;
   1.557 +        if (chain && NS_FAILED(chain->GetLength(&length)))
   1.558 +          length = 0;
   1.559 +        if (length == 1)
   1.560 +          errorID = "certErrorTrust_MissingChain";
   1.561 +        else
   1.562 +          errorID = "certErrorTrust_UnknownIssuer";
   1.563 +        break;
   1.564 +      }
   1.565 +      case SEC_ERROR_CA_CERT_INVALID:
   1.566 +        errorID = "certErrorTrust_CaInvalid";
   1.567 +        break;
   1.568 +      case SEC_ERROR_UNTRUSTED_ISSUER:
   1.569 +        errorID = "certErrorTrust_Issuer";
   1.570 +        break;
   1.571 +      case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   1.572 +        errorID = "certErrorTrust_SignatureAlgorithmDisabled";
   1.573 +        break;
   1.574 +      case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
   1.575 +        errorID = "certErrorTrust_ExpiredIssuer";
   1.576 +        break;
   1.577 +      case SEC_ERROR_UNTRUSTED_CERT:
   1.578 +      default:
   1.579 +        errorID = "certErrorTrust_Untrusted";
   1.580 +        break;
   1.581 +    }
   1.582 +  }
   1.583 +
   1.584 +  nsString formattedString;
   1.585 +  nsresult rv = component->GetPIPNSSBundleString(errorID, 
   1.586 +                                                 formattedString);
   1.587 +  if (NS_SUCCEEDED(rv))
   1.588 +  {
   1.589 +    returnedMessage.Append(formattedString);
   1.590 +    returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.591 +  }
   1.592 +}
   1.593 +
   1.594 +// returns TRUE if SAN was used to produce names
   1.595 +// return FALSE if nothing was produced
   1.596 +// names => a single name or a list of names
   1.597 +// multipleNames => whether multiple names were delivered
   1.598 +static bool
   1.599 +GetSubjectAltNames(CERTCertificate *nssCert,
   1.600 +                   nsINSSComponent *component,
   1.601 +                   nsString &allNames,
   1.602 +                   uint32_t &nameCount)
   1.603 +{
   1.604 +  allNames.Truncate();
   1.605 +  nameCount = 0;
   1.606 +
   1.607 +  PLArenaPool *san_arena = nullptr;
   1.608 +  SECItem altNameExtension = {siBuffer, nullptr, 0 };
   1.609 +  CERTGeneralName *sanNameList = nullptr;
   1.610 +
   1.611 +  SECStatus rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
   1.612 +                                        &altNameExtension);
   1.613 +  if (rv != SECSuccess)
   1.614 +    return false;
   1.615 +
   1.616 +  san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.617 +  if (!san_arena)
   1.618 +    return false;
   1.619 +
   1.620 +  sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
   1.621 +  if (!sanNameList)
   1.622 +    return false;
   1.623 +
   1.624 +  SECITEM_FreeItem(&altNameExtension, false);
   1.625 +
   1.626 +  CERTGeneralName *current = sanNameList;
   1.627 +  do {
   1.628 +    nsAutoString name;
   1.629 +    switch (current->type) {
   1.630 +      case certDNSName:
   1.631 +        {
   1.632 +          nsDependentCSubstring nameFromCert(reinterpret_cast<char*>
   1.633 +                                              (current->name.other.data),
   1.634 +                                              current->name.other.len);
   1.635 +          // dNSName fields are defined as type IA5String and thus should
   1.636 +          // be limited to ASCII characters.
   1.637 +          if (IsASCII(nameFromCert)) {
   1.638 +            name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
   1.639 +            if (!allNames.IsEmpty()) {
   1.640 +              allNames.Append(NS_LITERAL_STRING(", "));
   1.641 +            }
   1.642 +            ++nameCount;
   1.643 +            allNames.Append(name);
   1.644 +          }
   1.645 +        }
   1.646 +        break;
   1.647 +
   1.648 +      case certIPAddress:
   1.649 +        {
   1.650 +          char buf[INET6_ADDRSTRLEN];
   1.651 +          PRNetAddr addr;
   1.652 +          if (current->name.other.len == 4) {
   1.653 +            addr.inet.family = PR_AF_INET;
   1.654 +            memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
   1.655 +            PR_NetAddrToString(&addr, buf, sizeof(buf));
   1.656 +            name.AssignASCII(buf);
   1.657 +          } else if (current->name.other.len == 16) {
   1.658 +            addr.ipv6.family = PR_AF_INET6;
   1.659 +            memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
   1.660 +            PR_NetAddrToString(&addr, buf, sizeof(buf));
   1.661 +            name.AssignASCII(buf);
   1.662 +          } else {
   1.663 +            /* invalid IP address */
   1.664 +          }
   1.665 +          if (!name.IsEmpty()) {
   1.666 +            if (!allNames.IsEmpty()) {
   1.667 +              allNames.Append(NS_LITERAL_STRING(", "));
   1.668 +            }
   1.669 +            ++nameCount;
   1.670 +            allNames.Append(name);
   1.671 +          }
   1.672 +          break;
   1.673 +        }
   1.674 +
   1.675 +      default: // all other types of names are ignored
   1.676 +        break;
   1.677 +    }
   1.678 +    current = CERT_GetNextGeneralName(current);
   1.679 +  } while (current != sanNameList); // double linked
   1.680 +
   1.681 +  PORT_FreeArena(san_arena, false);
   1.682 +  return true;
   1.683 +}
   1.684 +
   1.685 +static void
   1.686 +AppendErrorTextMismatch(const nsString &host,
   1.687 +                        nsIX509Cert* ix509,
   1.688 +                        nsINSSComponent *component,
   1.689 +                        bool wantsHtml,
   1.690 +                        nsString &returnedMessage)
   1.691 +{
   1.692 +  const char16_t *params[1];
   1.693 +  nsresult rv;
   1.694 +
   1.695 +  mozilla::pkix::ScopedCERTCertificate nssCert;
   1.696 +
   1.697 +  nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
   1.698 +  if (cert2)
   1.699 +    nssCert = cert2->GetCert();
   1.700 +
   1.701 +  if (!nssCert) {
   1.702 +    // We are unable to extract the valid names, say "not valid for name".
   1.703 +    params[0] = host.get();
   1.704 +    nsString formattedString;
   1.705 +    rv = component->PIPBundleFormatStringFromName("certErrorMismatch", 
   1.706 +                                                  params, 1, 
   1.707 +                                                  formattedString);
   1.708 +    if (NS_SUCCEEDED(rv)) {
   1.709 +      returnedMessage.Append(formattedString);
   1.710 +      returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.711 +    }
   1.712 +    return;
   1.713 +  }
   1.714 +
   1.715 +  nsString allNames;
   1.716 +  uint32_t nameCount = 0;
   1.717 +  bool useSAN = false;
   1.718 +
   1.719 +  if (nssCert)
   1.720 +    useSAN = GetSubjectAltNames(nssCert.get(), component, allNames, nameCount);
   1.721 +
   1.722 +  if (!useSAN) {
   1.723 +    char *certName = nullptr;
   1.724 +    // currently CERT_FindNSStringExtension is not being exported by NSS.
   1.725 +    // If it gets exported, enable the following line.
   1.726 +    //   certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
   1.727 +    // However, it has been discussed to treat the extension as obsolete and ignore it.
   1.728 +    if (!certName)
   1.729 +      certName = CERT_GetCommonName(&nssCert->subject);
   1.730 +    if (certName) {
   1.731 +      nsDependentCSubstring commonName(certName, strlen(certName));
   1.732 +      if (IsUTF8(commonName)) {
   1.733 +        // Bug 1024781
   1.734 +        // We should actually check that the common name is a valid dns name or
   1.735 +        // ip address and not any string value before adding it to the display
   1.736 +        // list.
   1.737 +        ++nameCount;
   1.738 +        allNames.Assign(NS_ConvertUTF8toUTF16(commonName));
   1.739 +      }
   1.740 +      PORT_Free(certName);
   1.741 +    }
   1.742 +  }
   1.743 +
   1.744 +  if (nameCount > 1) {
   1.745 +    nsString message;
   1.746 +    rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple", 
   1.747 +                                          message);
   1.748 +    if (NS_SUCCEEDED(rv)) {
   1.749 +      returnedMessage.Append(message);
   1.750 +      returnedMessage.Append(NS_LITERAL_STRING("\n  "));
   1.751 +      returnedMessage.Append(allNames);
   1.752 +      returnedMessage.Append(NS_LITERAL_STRING("  \n"));
   1.753 +    }
   1.754 +  }
   1.755 +  else if (nameCount == 1) {
   1.756 +    const char16_t *params[1];
   1.757 +    params[0] = allNames.get();
   1.758 +    
   1.759 +    const char *stringID;
   1.760 +    if (wantsHtml)
   1.761 +      stringID = "certErrorMismatchSingle2";
   1.762 +    else
   1.763 +      stringID = "certErrorMismatchSinglePlain";
   1.764 +
   1.765 +    nsString formattedString;
   1.766 +    rv = component->PIPBundleFormatStringFromName(stringID, 
   1.767 +                                                  params, 1, 
   1.768 +                                                  formattedString);
   1.769 +    if (NS_SUCCEEDED(rv)) {
   1.770 +      returnedMessage.Append(formattedString);
   1.771 +      returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.772 +    }
   1.773 +  }
   1.774 +  else { // nameCount == 0
   1.775 +    nsString message;
   1.776 +    nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames",
   1.777 +                                                   message);
   1.778 +    if (NS_SUCCEEDED(rv)) {
   1.779 +      returnedMessage.Append(message);
   1.780 +      returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.781 +    }
   1.782 +  }
   1.783 +}
   1.784 +
   1.785 +static void
   1.786 +GetDateBoundary(nsIX509Cert* ix509,
   1.787 +                nsString &formattedDate,
   1.788 +                nsString &nowDate,
   1.789 +                bool &trueExpired_falseNotYetValid)
   1.790 +{
   1.791 +  trueExpired_falseNotYetValid = true;
   1.792 +  formattedDate.Truncate();
   1.793 +
   1.794 +  PRTime notAfter, notBefore, timeToUse;
   1.795 +  nsCOMPtr<nsIX509CertValidity> validity;
   1.796 +  nsresult rv;
   1.797 +
   1.798 +  rv = ix509->GetValidity(getter_AddRefs(validity));
   1.799 +  if (NS_FAILED(rv))
   1.800 +    return;
   1.801 +
   1.802 +  rv = validity->GetNotAfter(&notAfter);
   1.803 +  if (NS_FAILED(rv))
   1.804 +    return;
   1.805 +
   1.806 +  rv = validity->GetNotBefore(&notBefore);
   1.807 +  if (NS_FAILED(rv))
   1.808 +    return;
   1.809 +
   1.810 +  PRTime now = PR_Now();
   1.811 +  if (now > notAfter) {
   1.812 +    timeToUse = notAfter;
   1.813 +  } else {
   1.814 +    timeToUse = notBefore;
   1.815 +    trueExpired_falseNotYetValid = false;
   1.816 +  }
   1.817 +
   1.818 +  nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv));
   1.819 +  if (NS_FAILED(rv))
   1.820 +    return;
   1.821 +
   1.822 +  dateTimeFormat->FormatPRTime(nullptr, kDateFormatShort, 
   1.823 +                               kTimeFormatNoSeconds, timeToUse, 
   1.824 +                               formattedDate);
   1.825 +  dateTimeFormat->FormatPRTime(nullptr, kDateFormatShort,
   1.826 +                               kTimeFormatNoSeconds, now,
   1.827 +                               nowDate);
   1.828 +}
   1.829 +
   1.830 +static void
   1.831 +AppendErrorTextTime(nsIX509Cert* ix509,
   1.832 +                    nsINSSComponent *component,
   1.833 +                    nsString &returnedMessage)
   1.834 +{
   1.835 +  nsAutoString formattedDate, nowDate;
   1.836 +  bool trueExpired_falseNotYetValid;
   1.837 +  GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
   1.838 +
   1.839 +  const char16_t *params[2];
   1.840 +  params[0] = formattedDate.get(); // might be empty, if helper function had a problem 
   1.841 +  params[1] = nowDate.get();
   1.842 +
   1.843 +  const char *key = trueExpired_falseNotYetValid ? 
   1.844 +                    "certErrorExpiredNow" : "certErrorNotYetValidNow";
   1.845 +  nsresult rv;
   1.846 +  nsString formattedString;
   1.847 +  rv = component->PIPBundleFormatStringFromName(
   1.848 +           key,
   1.849 +           params, 
   1.850 +           ArrayLength(params),
   1.851 +           formattedString);
   1.852 +  if (NS_SUCCEEDED(rv))
   1.853 +  {
   1.854 +    returnedMessage.Append(formattedString);
   1.855 +    returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.856 +  }
   1.857 +}
   1.858 +
   1.859 +static void
   1.860 +AppendErrorTextCode(PRErrorCode errorCodeToReport,
   1.861 +                    nsINSSComponent *component,
   1.862 +                    nsString &returnedMessage)
   1.863 +{
   1.864 +  const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
   1.865 +  if (codeName)
   1.866 +  {
   1.867 +    nsCString error_id(codeName);
   1.868 +    ToLowerCase(error_id);
   1.869 +    NS_ConvertASCIItoUTF16 idU(error_id);
   1.870 +
   1.871 +    const char16_t *params[1];
   1.872 +    params[0] = idU.get();
   1.873 +
   1.874 +    nsString formattedString;
   1.875 +    nsresult rv;
   1.876 +    rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix", 
   1.877 +                                                  params, 1, 
   1.878 +                                                  formattedString);
   1.879 +    if (NS_SUCCEEDED(rv)) {
   1.880 +      returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.881 +      returnedMessage.Append(formattedString);
   1.882 +      returnedMessage.Append(NS_LITERAL_STRING("\n"));
   1.883 +    }
   1.884 +    else {
   1.885 +      returnedMessage.Append(NS_LITERAL_STRING(" ("));
   1.886 +      returnedMessage.Append(idU);
   1.887 +      returnedMessage.Append(NS_LITERAL_STRING(")"));
   1.888 +    }
   1.889 +  }
   1.890 +}
   1.891 +
   1.892 +/* Formats an error message for overridable certificate errors (of type
   1.893 + * OverridableCertErrorMessage). Use formatPlainErrorMessage to format
   1.894 + * non-overridable cert errors and non-cert-related errors.
   1.895 + */
   1.896 +static nsresult
   1.897 +formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
   1.898 +                                  PRErrorCode errorCodeToReport, 
   1.899 +                                  const nsXPIDLCString & host, int32_t port,
   1.900 +                                  bool suppressPort443,
   1.901 +                                  bool wantsHtml,
   1.902 +                                  nsString & returnedMessage)
   1.903 +{
   1.904 +  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.905 +
   1.906 +  const char16_t *params[1];
   1.907 +  nsresult rv;
   1.908 +  nsAutoString hostWithPort;
   1.909 +  nsAutoString hostWithoutPort;
   1.910 +
   1.911 +  // For now, hide port when it's 443 and we're reporting the error.
   1.912 +  // In the future a better mechanism should be used
   1.913 +  // to make a decision about showing the port number, possibly by requiring
   1.914 +  // the context object to implement a specific interface.
   1.915 +  // The motivation is that Mozilla browser would like to hide the port number
   1.916 +  // in error pages in the common case.
   1.917 +  
   1.918 +  hostWithoutPort.AppendASCII(host);
   1.919 +  if (suppressPort443 && port == 443) {
   1.920 +    params[0] = hostWithoutPort.get();
   1.921 +  } else {
   1.922 +    hostWithPort.AppendASCII(host);
   1.923 +    hostWithPort.Append(':');
   1.924 +    hostWithPort.AppendInt(port);
   1.925 +    params[0] = hostWithPort.get();
   1.926 +  }
   1.927 +
   1.928 +  nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
   1.929 +  NS_ENSURE_SUCCESS(rv, rv);
   1.930 +
   1.931 +  returnedMessage.Truncate();
   1.932 +  rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
   1.933 +                                                returnedMessage);
   1.934 +  NS_ENSURE_SUCCESS(rv, rv);
   1.935 +
   1.936 +  returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
   1.937 +
   1.938 +  RefPtr<nsIX509Cert> ix509;
   1.939 +  rv = sslStatus.GetServerCert(byRef(ix509));
   1.940 +  NS_ENSURE_SUCCESS(rv, rv);
   1.941 +
   1.942 +  bool isUntrusted;
   1.943 +  rv = sslStatus.GetIsUntrusted(&isUntrusted);
   1.944 +  NS_ENSURE_SUCCESS(rv, rv);
   1.945 +  if (isUntrusted) {
   1.946 +    AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509, 
   1.947 +                             component, returnedMessage);
   1.948 +  }
   1.949 +
   1.950 +  bool isDomainMismatch;
   1.951 +  rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
   1.952 +  NS_ENSURE_SUCCESS(rv, rv);
   1.953 +  if (isDomainMismatch) {
   1.954 +    AppendErrorTextMismatch(hostWithoutPort, ix509, component, wantsHtml, returnedMessage);
   1.955 +  }
   1.956 +
   1.957 +  bool isNotValidAtThisTime;
   1.958 +  rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
   1.959 +  NS_ENSURE_SUCCESS(rv, rv);
   1.960 +  if (isNotValidAtThisTime) {
   1.961 +    AppendErrorTextTime(ix509, component, returnedMessage);
   1.962 +  }
   1.963 +
   1.964 +  AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
   1.965 +
   1.966 +  return NS_OK;
   1.967 +}
   1.968 +
   1.969 +// RememberCertErrorsTable
   1.970 +
   1.971 +/*static*/ RememberCertErrorsTable*
   1.972 +RememberCertErrorsTable::sInstance = nullptr;
   1.973 +
   1.974 +RememberCertErrorsTable::RememberCertErrorsTable()
   1.975 +  : mErrorHosts(16)
   1.976 +  , mMutex("RememberCertErrorsTable::mMutex")
   1.977 +{
   1.978 +}
   1.979 +
   1.980 +static nsresult
   1.981 +GetHostPortKey(TransportSecurityInfo* infoObject, nsAutoCString &result)
   1.982 +{
   1.983 +  nsresult rv;
   1.984 +
   1.985 +  result.Truncate();
   1.986 +
   1.987 +  nsXPIDLCString hostName;
   1.988 +  rv = infoObject->GetHostName(getter_Copies(hostName));
   1.989 +  NS_ENSURE_SUCCESS(rv, rv);
   1.990 +
   1.991 +  int32_t port;
   1.992 +  rv = infoObject->GetPort(&port);
   1.993 +  NS_ENSURE_SUCCESS(rv, rv);
   1.994 +
   1.995 +  result.Assign(hostName);
   1.996 +  result.Append(':');
   1.997 +  result.AppendInt(port);
   1.998 +
   1.999 +  return NS_OK;
  1.1000 +}
  1.1001 +
  1.1002 +void
  1.1003 +RememberCertErrorsTable::RememberCertHasError(TransportSecurityInfo* infoObject,
  1.1004 +                                              nsSSLStatus* status,
  1.1005 +                                              SECStatus certVerificationResult)
  1.1006 +{
  1.1007 +  nsresult rv;
  1.1008 +
  1.1009 +  nsAutoCString hostPortKey;
  1.1010 +  rv = GetHostPortKey(infoObject, hostPortKey);
  1.1011 +  if (NS_FAILED(rv))
  1.1012 +    return;
  1.1013 +
  1.1014 +  if (certVerificationResult != SECSuccess) {
  1.1015 +    NS_ASSERTION(status,
  1.1016 +        "Must have nsSSLStatus object when remembering flags");
  1.1017 +
  1.1018 +    if (!status)
  1.1019 +      return;
  1.1020 +
  1.1021 +    CertStateBits bits;
  1.1022 +    bits.mIsDomainMismatch = status->mIsDomainMismatch;
  1.1023 +    bits.mIsNotValidAtThisTime = status->mIsNotValidAtThisTime;
  1.1024 +    bits.mIsUntrusted = status->mIsUntrusted;
  1.1025 +
  1.1026 +    MutexAutoLock lock(mMutex);
  1.1027 +    mErrorHosts.Put(hostPortKey, bits);
  1.1028 +  }
  1.1029 +  else {
  1.1030 +    MutexAutoLock lock(mMutex);
  1.1031 +    mErrorHosts.Remove(hostPortKey);
  1.1032 +  }
  1.1033 +}
  1.1034 +
  1.1035 +void
  1.1036 +RememberCertErrorsTable::LookupCertErrorBits(TransportSecurityInfo* infoObject,
  1.1037 +                                             nsSSLStatus* status)
  1.1038 +{
  1.1039 +  // Get remembered error bits from our cache, because of SSL session caching
  1.1040 +  // the NSS library potentially hasn't notified us for this socket.
  1.1041 +  if (status->mHaveCertErrorBits)
  1.1042 +    // Rather do not modify bits if already set earlier
  1.1043 +    return;
  1.1044 +
  1.1045 +  nsresult rv;
  1.1046 +
  1.1047 +  nsAutoCString hostPortKey;
  1.1048 +  rv = GetHostPortKey(infoObject, hostPortKey);
  1.1049 +  if (NS_FAILED(rv))
  1.1050 +    return;
  1.1051 +
  1.1052 +  CertStateBits bits;
  1.1053 +  {
  1.1054 +    MutexAutoLock lock(mMutex);
  1.1055 +    if (!mErrorHosts.Get(hostPortKey, &bits))
  1.1056 +      // No record was found, this host had no cert errors
  1.1057 +      return;
  1.1058 +  }
  1.1059 +
  1.1060 +  // This host had cert errors, update the bits correctly
  1.1061 +  status->mHaveCertErrorBits = true;
  1.1062 +  status->mIsDomainMismatch = bits.mIsDomainMismatch;
  1.1063 +  status->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
  1.1064 +  status->mIsUntrusted = bits.mIsUntrusted;
  1.1065 +}
  1.1066 +
  1.1067 +void
  1.1068 +TransportSecurityInfo::SetStatusErrorBits(nsIX509Cert & cert,
  1.1069 +                                          uint32_t collected_errors)
  1.1070 +{
  1.1071 +  MutexAutoLock lock(mMutex);
  1.1072 +
  1.1073 +  if (!mSSLStatus)
  1.1074 +    mSSLStatus = new nsSSLStatus();
  1.1075 +
  1.1076 +  mSSLStatus->mServerCert = &cert;
  1.1077 +
  1.1078 +  mSSLStatus->mHaveCertErrorBits = true;
  1.1079 +  mSSLStatus->mIsDomainMismatch = 
  1.1080 +    collected_errors & nsICertOverrideService::ERROR_MISMATCH;
  1.1081 +  mSSLStatus->mIsNotValidAtThisTime = 
  1.1082 +    collected_errors & nsICertOverrideService::ERROR_TIME;
  1.1083 +  mSSLStatus->mIsUntrusted = 
  1.1084 +    collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
  1.1085 +
  1.1086 +  RememberCertErrorsTable::GetInstance().RememberCertHasError(this,
  1.1087 +                                                              mSSLStatus,
  1.1088 +                                                              SECFailure);
  1.1089 +}
  1.1090 +
  1.1091 +} } // namespace mozilla::psm

mercurial