security/manager/ssl/src/SSLServerCertVerification.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/manager/ssl/src/SSLServerCertVerification.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1408 @@
     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 +// For connections that are not processed on the socket transport thread, we do
    1.11 +// NOT use the async logic described below. Instead, we authenticate the
    1.12 +// certificate on the thread that the connection's I/O happens on,
    1.13 +// synchronously. This allows us to do certificate verification for blocking
    1.14 +// (not non-blocking) sockets and sockets that have their I/O processed on a
    1.15 +// thread other than the socket transport service thread. Also, we DO NOT
    1.16 +// support blocking sockets on the socket transport service thread at all.
    1.17 +//
    1.18 +// During certificate authentication, we call CERT_PKIXVerifyCert or
    1.19 +// CERT_VerifyCert. These functions may make zero or more HTTP requests
    1.20 +// for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
    1.21 +// for these requests processes them on the socket transport service thread.
    1.22 +//
    1.23 +// If the connection for which we are verifying the certificate is happening
    1.24 +// on the socket transport thread (the usually case, at least for HTTP), then
    1.25 +// if our cert auth hook were to call the CERT_*Verify* functions directly,
    1.26 +// there would be a deadlock: The CERT_*Verify* function would cause an event
    1.27 +// to be asynchronously posted to the socket transport thread, and then it
    1.28 +// would block the socket transport thread waiting to be notified of the HTTP
    1.29 +// response. However, the HTTP request would never actually be processed
    1.30 +// because the socket transport thread would be blocked and so it wouldn't be
    1.31 +// able process HTTP requests. (i.e. Deadlock.)
    1.32 +//
    1.33 +// Consequently, when we are asked to verify a certificate on the socket
    1.34 +// transport service thread, we must always call the CERT_*Verify* cert
    1.35 +// functions on another thread. To accomplish this, our auth cert hook
    1.36 +// dispatches a SSLServerCertVerificationJob to a pool of background threads,
    1.37 +// and then immediatley return SECWouldBlock to libssl. These jobs are where
    1.38 +// the CERT_*Verify* functions are actually called.
    1.39 +//
    1.40 +// When our auth cert hook returns SECWouldBlock, libssl will carry on the
    1.41 +// handshake while we validate the certificate. This will free up the socket
    1.42 +// transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
    1.43 +// requests needed for cert verification as mentioned above--can be processed.
    1.44 +//
    1.45 +// Once the CERT_*Verify* function returns, the cert verification job
    1.46 +// dispatches a SSLServerCertVerificationResult to the socket transport thread;
    1.47 +// the SSLServerCertVerificationResult will notify libssl that the certificate
    1.48 +// authentication is complete. Once libssl is notified that the authentication
    1.49 +// is complete, it will continue the SSL handshake (if it hasn't already
    1.50 +// finished) and it will begin allowing us to send/receive data on the
    1.51 +// connection.
    1.52 +//
    1.53 +// Timeline of events (for connections managed by the socket transport service):
    1.54 +//
    1.55 +//    * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
    1.56 +//      transport thread.
    1.57 +//    * SSLServerCertVerificationJob::Dispatch queues a job
    1.58 +//      (instance of SSLServerCertVerificationJob) to its background thread
    1.59 +//      pool and returns.
    1.60 +//    * One of the background threads calls CERT_*Verify*, which may enqueue
    1.61 +//      some HTTP request(s) onto the socket transport thread, and then
    1.62 +//      blocks that background thread waiting for the responses and/or timeouts
    1.63 +//      or errors for those requests.
    1.64 +//    * Once those HTTP responses have all come back or failed, the
    1.65 +//      CERT_*Verify* function returns a result indicating that the validation
    1.66 +//      succeeded or failed.
    1.67 +//    * If the validation succeeded, then a SSLServerCertVerificationResult
    1.68 +//      event is posted to the socket transport thread, and the cert
    1.69 +//      verification thread becomes free to verify other certificates.
    1.70 +//    * Otherwise, a CertErrorRunnable is posted to the socket transport thread
    1.71 +//      and then to the main thread (blocking both, see CertErrorRunnable) to
    1.72 +//      do cert override processing and bad cert listener notification. Then
    1.73 +//      the cert verification thread becomes free to verify other certificates.
    1.74 +//    * After processing cert overrides, the CertErrorRunnable will dispatch a
    1.75 +//      SSLServerCertVerificationResult event to the socket transport thread to
    1.76 +//      notify it of the result of the override processing; then it returns,
    1.77 +//      freeing up the main thread.
    1.78 +//    * The SSLServerCertVerificationResult event will either wake up the
    1.79 +//      socket (using SSL_RestartHandshakeAfterServerCert) if validation
    1.80 +//      succeeded or there was an error override, or it will set an error flag
    1.81 +//      so that the next I/O operation on the socket will fail, causing the
    1.82 +//      socket transport thread to close the connection.
    1.83 +//
    1.84 +// Cert override processing must happen on the main thread because it accesses
    1.85 +// the nsICertOverrideService, and that service must be accessed on the main
    1.86 +// thread because some extensions (Selenium, in particular) replace it with a
    1.87 +// Javascript implementation, and chrome JS must always be run on the main
    1.88 +// thread.
    1.89 +//
    1.90 +// SSLServerCertVerificationResult must be dispatched to the socket transport
    1.91 +// thread because we must only call SSL_* functions on the socket transport
    1.92 +// thread since they may do I/O, because many parts of nsNSSSocketInfo (the
    1.93 +// subclass of TransportSecurityInfo used when validating certificates during
    1.94 +// an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because
    1.95 +// we need the event to interrupt the PR_Poll that may waiting for I/O on the
    1.96 +// socket for which we are validating the cert.
    1.97 +
    1.98 +#include "SSLServerCertVerification.h"
    1.99 +
   1.100 +#include <cstring>
   1.101 +
   1.102 +#include "pkix/pkixtypes.h"
   1.103 +#include "CertVerifier.h"
   1.104 +#include "CryptoTask.h"
   1.105 +#include "ExtendedValidation.h"
   1.106 +#include "NSSCertDBTrustDomain.h"
   1.107 +#include "nsIBadCertListener2.h"
   1.108 +#include "nsICertOverrideService.h"
   1.109 +#include "nsISiteSecurityService.h"
   1.110 +#include "nsNSSComponent.h"
   1.111 +#include "nsNSSCleaner.h"
   1.112 +#include "nsRecentBadCerts.h"
   1.113 +#include "nsNSSIOLayer.h"
   1.114 +#include "nsNSSShutDown.h"
   1.115 +
   1.116 +#include "mozilla/Assertions.h"
   1.117 +#include "mozilla/Mutex.h"
   1.118 +#include "mozilla/Telemetry.h"
   1.119 +#include "mozilla/unused.h"
   1.120 +#include "nsIThreadPool.h"
   1.121 +#include "nsNetUtil.h"
   1.122 +#include "nsXPCOMCIDInternal.h"
   1.123 +#include "nsComponentManagerUtils.h"
   1.124 +#include "nsServiceManagerUtils.h"
   1.125 +#include "PSMRunnable.h"
   1.126 +#include "SharedSSLState.h"
   1.127 +#include "nsContentUtils.h"
   1.128 +
   1.129 +#include "ssl.h"
   1.130 +#include "secerr.h"
   1.131 +#include "secport.h"
   1.132 +#include "sslerr.h"
   1.133 +#include "ocsp.h"
   1.134 +
   1.135 +#ifdef PR_LOGGING
   1.136 +extern PRLogModuleInfo* gPIPNSSLog;
   1.137 +#endif
   1.138 +
   1.139 +namespace mozilla { namespace psm {
   1.140 +
   1.141 +namespace {
   1.142 +
   1.143 +NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   1.144 +
   1.145 +NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
   1.146 +NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
   1.147 +
   1.148 +// do not use a nsCOMPtr to avoid static initializer/destructor
   1.149 +nsIThreadPool* gCertVerificationThreadPool = nullptr;
   1.150 +
   1.151 +// We avoid using a mutex for the success case to avoid lock-related
   1.152 +// performance issues. However, we do use a lock in the error case to simplify
   1.153 +// the code, since performance in the error case is not important.
   1.154 +Mutex* gSSLVerificationTelemetryMutex = nullptr;
   1.155 +
   1.156 +// We add a mutex to serialize PKCS11 database operations
   1.157 +Mutex* gSSLVerificationPK11Mutex = nullptr;
   1.158 +
   1.159 +} // unnamed namespace
   1.160 +
   1.161 +// Called when the socket transport thread starts, to initialize the SSL cert
   1.162 +// verification thread pool. By tying the thread pool startup/shutdown directly
   1.163 +// to the STS thread's lifetime, we ensure that they are *always* available for
   1.164 +// SSL connections and that there are no races during startup and especially
   1.165 +// shutdown. (Previously, we have had multiple problems with races in PSM
   1.166 +// background threads, and the race-prevention/shutdown logic used there is
   1.167 +// brittle. Since this service is critical to things like downloading updates,
   1.168 +// we take no chances.) Also, by doing things this way, we avoid the need for
   1.169 +// locks, since gCertVerificationThreadPool is only ever accessed on the socket
   1.170 +// transport thread.
   1.171 +void
   1.172 +InitializeSSLServerCertVerificationThreads()
   1.173 +{
   1.174 +  gSSLVerificationTelemetryMutex = new Mutex("SSLVerificationTelemetryMutex");
   1.175 +  gSSLVerificationPK11Mutex = new Mutex("SSLVerificationPK11Mutex");
   1.176 +  // TODO: tuning, make parameters preferences
   1.177 +  // XXX: instantiate nsThreadPool directly, to make this more bulletproof.
   1.178 +  // Currently, the nsThreadPool.h header isn't exported for us to do so.
   1.179 +  nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID,
   1.180 +                                   &gCertVerificationThreadPool);
   1.181 +  if (NS_FAILED(rv)) {
   1.182 +    NS_WARNING("Failed to create SSL cert verification threads.");
   1.183 +    return;
   1.184 +  }
   1.185 +
   1.186 +  (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
   1.187 +  (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
   1.188 +  (void) gCertVerificationThreadPool->SetThreadLimit(5);
   1.189 +  (void) gCertVerificationThreadPool->SetName(NS_LITERAL_CSTRING("SSL Cert"));
   1.190 +}
   1.191 +
   1.192 +// Called when the socket transport thread finishes, to destroy the thread
   1.193 +// pool. Since the socket transport service has stopped processing events, it
   1.194 +// will not attempt any more SSL I/O operations, so it is clearly safe to shut
   1.195 +// down the SSL cert verification infrastructure. Also, the STS will not
   1.196 +// dispatch many SSL verification result events at this point, so any pending
   1.197 +// cert verifications will (correctly) fail at the point they are dispatched.
   1.198 +//
   1.199 +// The other shutdown race condition that is possible is a race condition with
   1.200 +// shutdown of the nsNSSComponent service. We use the
   1.201 +// nsNSSShutdownPreventionLock where needed (not here) to prevent that.
   1.202 +void StopSSLServerCertVerificationThreads()
   1.203 +{
   1.204 +  if (gCertVerificationThreadPool) {
   1.205 +    gCertVerificationThreadPool->Shutdown();
   1.206 +    NS_RELEASE(gCertVerificationThreadPool);
   1.207 +  }
   1.208 +  if (gSSLVerificationTelemetryMutex) {
   1.209 +    delete gSSLVerificationTelemetryMutex;
   1.210 +    gSSLVerificationTelemetryMutex = nullptr;
   1.211 +  }
   1.212 +  if (gSSLVerificationPK11Mutex) {
   1.213 +    delete gSSLVerificationPK11Mutex;
   1.214 +    gSSLVerificationPK11Mutex = nullptr;
   1.215 +  }
   1.216 +}
   1.217 +
   1.218 +namespace {
   1.219 +
   1.220 +void
   1.221 +LogInvalidCertError(TransportSecurityInfo* socketInfo,
   1.222 +                    PRErrorCode errorCode,
   1.223 +                    ::mozilla::psm::SSLErrorMessageType errorMessageType)
   1.224 +{
   1.225 +  nsString message;
   1.226 +  socketInfo->GetErrorLogMessage(errorCode, errorMessageType, message);
   1.227 +  if (!message.IsEmpty()) {
   1.228 +    nsContentUtils::LogSimpleConsoleError(message, "SSL");
   1.229 +  }
   1.230 +}
   1.231 +
   1.232 +// Dispatched to the STS thread to notify the infoObject of the verification
   1.233 +// result.
   1.234 +//
   1.235 +// This will cause the PR_Poll in the STS thread to return, so things work
   1.236 +// correctly even if the STS thread is blocked polling (only) on the file
   1.237 +// descriptor that is waiting for this result.
   1.238 +class SSLServerCertVerificationResult : public nsRunnable
   1.239 +{
   1.240 +public:
   1.241 +  NS_DECL_NSIRUNNABLE
   1.242 +
   1.243 +  SSLServerCertVerificationResult(TransportSecurityInfo* infoObject,
   1.244 +                                  PRErrorCode errorCode,
   1.245 +                                  Telemetry::ID telemetryID = Telemetry::HistogramCount,
   1.246 +                                  uint32_t telemetryValue = -1,
   1.247 +                                  SSLErrorMessageType errorMessageType =
   1.248 +                                      PlainErrorMessage);
   1.249 +
   1.250 +  void Dispatch();
   1.251 +private:
   1.252 +  const RefPtr<TransportSecurityInfo> mInfoObject;
   1.253 +public:
   1.254 +  const PRErrorCode mErrorCode;
   1.255 +  const SSLErrorMessageType mErrorMessageType;
   1.256 +  const Telemetry::ID mTelemetryID;
   1.257 +  const uint32_t mTelemetryValue;
   1.258 +};
   1.259 +
   1.260 +class CertErrorRunnable : public SyncRunnableBase
   1.261 +{
   1.262 + public:
   1.263 +  CertErrorRunnable(const void* fdForLogging,
   1.264 +                    nsIX509Cert* cert,
   1.265 +                    TransportSecurityInfo* infoObject,
   1.266 +                    PRErrorCode defaultErrorCodeToReport,
   1.267 +                    uint32_t collectedErrors,
   1.268 +                    PRErrorCode errorCodeTrust,
   1.269 +                    PRErrorCode errorCodeMismatch,
   1.270 +                    PRErrorCode errorCodeExpired,
   1.271 +                    uint32_t providerFlags)
   1.272 +    : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
   1.273 +      mDefaultErrorCodeToReport(defaultErrorCodeToReport),
   1.274 +      mCollectedErrors(collectedErrors),
   1.275 +      mErrorCodeTrust(errorCodeTrust),
   1.276 +      mErrorCodeMismatch(errorCodeMismatch),
   1.277 +      mErrorCodeExpired(errorCodeExpired),
   1.278 +      mProviderFlags(providerFlags)
   1.279 +  {
   1.280 +  }
   1.281 +
   1.282 +  virtual void RunOnTargetThread();
   1.283 +  RefPtr<SSLServerCertVerificationResult> mResult; // out
   1.284 +private:
   1.285 +  SSLServerCertVerificationResult* CheckCertOverrides();
   1.286 +
   1.287 +  const void* const mFdForLogging; // may become an invalid pointer; do not dereference
   1.288 +  const nsCOMPtr<nsIX509Cert> mCert;
   1.289 +  const RefPtr<TransportSecurityInfo> mInfoObject;
   1.290 +  const PRErrorCode mDefaultErrorCodeToReport;
   1.291 +  const uint32_t mCollectedErrors;
   1.292 +  const PRErrorCode mErrorCodeTrust;
   1.293 +  const PRErrorCode mErrorCodeMismatch;
   1.294 +  const PRErrorCode mErrorCodeExpired;
   1.295 +  const uint32_t mProviderFlags;
   1.296 +};
   1.297 +
   1.298 +// A probe value of 1 means "no error".
   1.299 +uint32_t
   1.300 +MapCertErrorToProbeValue(PRErrorCode errorCode)
   1.301 +{
   1.302 +  switch (errorCode)
   1.303 +  {
   1.304 +    case SEC_ERROR_UNKNOWN_ISSUER:                     return  2;
   1.305 +    case SEC_ERROR_CA_CERT_INVALID:                    return  3;
   1.306 +    case SEC_ERROR_UNTRUSTED_ISSUER:                   return  4;
   1.307 +    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:         return  5;
   1.308 +    case SEC_ERROR_UNTRUSTED_CERT:                     return  6;
   1.309 +    case SEC_ERROR_INADEQUATE_KEY_USAGE:               return  7;
   1.310 +    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:  return  8;
   1.311 +    case SSL_ERROR_BAD_CERT_DOMAIN:                    return  9;
   1.312 +    case SEC_ERROR_EXPIRED_CERTIFICATE:                return 10;
   1.313 +  }
   1.314 +  NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue "
   1.315 +             "handle everything in PRErrorCodeToOverrideType?");
   1.316 +  return 0;
   1.317 +}
   1.318 +
   1.319 +SECStatus
   1.320 +MozillaPKIXDetermineCertOverrideErrors(CERTCertificate* cert,
   1.321 +                                       const char* hostName, PRTime now,
   1.322 +                                       PRErrorCode defaultErrorCodeToReport,
   1.323 +                                       /*out*/ uint32_t& collectedErrors,
   1.324 +                                       /*out*/ PRErrorCode& errorCodeTrust,
   1.325 +                                       /*out*/ PRErrorCode& errorCodeMismatch,
   1.326 +                                       /*out*/ PRErrorCode& errorCodeExpired)
   1.327 +{
   1.328 +  MOZ_ASSERT(cert);
   1.329 +  MOZ_ASSERT(hostName);
   1.330 +  MOZ_ASSERT(collectedErrors == 0);
   1.331 +  MOZ_ASSERT(errorCodeTrust == 0);
   1.332 +  MOZ_ASSERT(errorCodeMismatch == 0);
   1.333 +  MOZ_ASSERT(errorCodeExpired == 0);
   1.334 +
   1.335 +  // Assumes the error prioritization described in mozilla::pkix's
   1.336 +  // BuildForward function. Also assumes that CERT_VerifyCertName was only
   1.337 +  // called if CertVerifier::VerifyCert succeeded.
   1.338 +  switch (defaultErrorCodeToReport) {
   1.339 +    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   1.340 +    case SEC_ERROR_CA_CERT_INVALID:
   1.341 +    case SEC_ERROR_UNKNOWN_ISSUER:
   1.342 +    {
   1.343 +      collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
   1.344 +      errorCodeTrust = defaultErrorCodeToReport;
   1.345 +
   1.346 +      SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, now, false);
   1.347 +      if (validity == secCertTimeUndetermined) {
   1.348 +        PR_SetError(defaultErrorCodeToReport, 0);
   1.349 +        return SECFailure;
   1.350 +      }
   1.351 +      if (validity != secCertTimeValid) {
   1.352 +        collectedErrors |= nsICertOverrideService::ERROR_TIME;
   1.353 +        errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
   1.354 +      }
   1.355 +      break;
   1.356 +    }
   1.357 +
   1.358 +    case SEC_ERROR_EXPIRED_CERTIFICATE:
   1.359 +      collectedErrors = nsICertOverrideService::ERROR_TIME;
   1.360 +      errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
   1.361 +      break;
   1.362 +
   1.363 +    case SSL_ERROR_BAD_CERT_DOMAIN:
   1.364 +      collectedErrors = nsICertOverrideService::ERROR_MISMATCH;
   1.365 +      errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   1.366 +      break;
   1.367 +
   1.368 +    case 0:
   1.369 +      NS_ERROR("No error code set during certificate validation failure.");
   1.370 +      PR_SetError(PR_INVALID_STATE_ERROR, 0);
   1.371 +      return SECFailure;
   1.372 +
   1.373 +    default:
   1.374 +      PR_SetError(defaultErrorCodeToReport, 0);
   1.375 +      return SECFailure;
   1.376 +  }
   1.377 +
   1.378 +  if (defaultErrorCodeToReport != SSL_ERROR_BAD_CERT_DOMAIN) {
   1.379 +    if (CERT_VerifyCertName(cert, hostName) != SECSuccess) {
   1.380 +      if (PR_GetError() != SSL_ERROR_BAD_CERT_DOMAIN) {
   1.381 +        PR_SetError(defaultErrorCodeToReport, 0);
   1.382 +        return SECFailure;
   1.383 +      }
   1.384 +
   1.385 +      collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
   1.386 +      errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   1.387 +    }
   1.388 +  }
   1.389 +
   1.390 +  return SECSuccess;
   1.391 +}
   1.392 +
   1.393 +SSLServerCertVerificationResult*
   1.394 +CertErrorRunnable::CheckCertOverrides()
   1.395 +{
   1.396 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
   1.397 +                                    mFdForLogging, this));
   1.398 +  // "Use" mFdForLogging in non-PR_LOGGING builds, too, to suppress
   1.399 +  // clang's -Wunused-private-field build warning for this variable:
   1.400 +  unused << mFdForLogging;
   1.401 +
   1.402 +  if (!NS_IsMainThread()) {
   1.403 +    NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
   1.404 +    return new SSLServerCertVerificationResult(mInfoObject,
   1.405 +                                               mDefaultErrorCodeToReport);
   1.406 +  }
   1.407 +
   1.408 +  int32_t port;
   1.409 +  mInfoObject->GetPort(&port);
   1.410 +
   1.411 +  nsCString hostWithPortString;
   1.412 +  hostWithPortString.AppendASCII(mInfoObject->GetHostNameRaw());
   1.413 +  hostWithPortString.AppendLiteral(":");
   1.414 +  hostWithPortString.AppendInt(port);
   1.415 +
   1.416 +  uint32_t remaining_display_errors = mCollectedErrors;
   1.417 +
   1.418 +  nsresult nsrv;
   1.419 +
   1.420 +  // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
   1.421 +  // connections must be dropped when there are any certificate errors
   1.422 +  // (STS Spec section 7.3).
   1.423 +  bool strictTransportSecurityEnabled = false;
   1.424 +  nsCOMPtr<nsISiteSecurityService> sss
   1.425 +    = do_GetService(NS_SSSERVICE_CONTRACTID, &nsrv);
   1.426 +  if (NS_SUCCEEDED(nsrv)) {
   1.427 +    nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS,
   1.428 +                             mInfoObject->GetHostNameRaw(),
   1.429 +                             mProviderFlags,
   1.430 +                             &strictTransportSecurityEnabled);
   1.431 +  }
   1.432 +  if (NS_FAILED(nsrv)) {
   1.433 +    return new SSLServerCertVerificationResult(mInfoObject,
   1.434 +                                               mDefaultErrorCodeToReport);
   1.435 +  }
   1.436 +
   1.437 +  if (!strictTransportSecurityEnabled) {
   1.438 +    nsCOMPtr<nsICertOverrideService> overrideService =
   1.439 +      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
   1.440 +    // it is fine to continue without the nsICertOverrideService
   1.441 +
   1.442 +    uint32_t overrideBits = 0;
   1.443 +
   1.444 +    if (overrideService)
   1.445 +    {
   1.446 +      bool haveOverride;
   1.447 +      bool isTemporaryOverride; // we don't care
   1.448 +      nsCString hostString(mInfoObject->GetHostName());
   1.449 +      nsrv = overrideService->HasMatchingOverride(hostString, port,
   1.450 +                                                  mCert,
   1.451 +                                                  &overrideBits,
   1.452 +                                                  &isTemporaryOverride,
   1.453 +                                                  &haveOverride);
   1.454 +      if (NS_SUCCEEDED(nsrv) && haveOverride)
   1.455 +      {
   1.456 +       // remove the errors that are already overriden
   1.457 +        remaining_display_errors &= ~overrideBits;
   1.458 +      }
   1.459 +    }
   1.460 +
   1.461 +    if (!remaining_display_errors) {
   1.462 +      // This can double- or triple-count one certificate with multiple
   1.463 +      // different types of errors. Since this is telemetry and we just
   1.464 +      // want a ballpark answer, we don't care.
   1.465 +      if (mErrorCodeTrust != 0) {
   1.466 +        uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeTrust);
   1.467 +        Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
   1.468 +      }
   1.469 +      if (mErrorCodeMismatch != 0) {
   1.470 +        uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeMismatch);
   1.471 +        Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
   1.472 +      }
   1.473 +      if (mErrorCodeExpired != 0) {
   1.474 +        uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeExpired);
   1.475 +        Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
   1.476 +      }
   1.477 +
   1.478 +      // all errors are covered by override rules, so let's accept the cert
   1.479 +      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.480 +             ("[%p][%p] All errors covered by override rules\n",
   1.481 +             mFdForLogging, this));
   1.482 +      return new SSLServerCertVerificationResult(mInfoObject, 0);
   1.483 +    }
   1.484 +  } else {
   1.485 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.486 +           ("[%p][%p] Strict-Transport-Security is violated: untrusted "
   1.487 +            "transport layer\n", mFdForLogging, this));
   1.488 +  }
   1.489 +
   1.490 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.491 +         ("[%p][%p] Certificate error was not overridden\n",
   1.492 +         mFdForLogging, this));
   1.493 +
   1.494 +  // Ok, this is a full stop.
   1.495 +  // First, deliver the technical details of the broken SSL status.
   1.496 +
   1.497 +  // Try to get a nsIBadCertListener2 implementation from the socket consumer.
   1.498 +  nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
   1.499 +    NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
   1.500 +  if (sslSocketControl) {
   1.501 +    nsCOMPtr<nsIInterfaceRequestor> cb;
   1.502 +    sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
   1.503 +    if (cb) {
   1.504 +      nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
   1.505 +      if (bcl) {
   1.506 +        nsIInterfaceRequestor* csi
   1.507 +          = static_cast<nsIInterfaceRequestor*>(mInfoObject);
   1.508 +        bool suppressMessage = false; // obsolete, ignored
   1.509 +        nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
   1.510 +                                      hostWithPortString, &suppressMessage);
   1.511 +      }
   1.512 +    }
   1.513 +  }
   1.514 +
   1.515 +  nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
   1.516 +  nsCOMPtr<nsIRecentBadCerts> recentBadCertsService;
   1.517 +  if (certdb) {
   1.518 +    bool isPrivate = mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
   1.519 +    certdb->GetRecentBadCerts(isPrivate, getter_AddRefs(recentBadCertsService));
   1.520 +  }
   1.521 +
   1.522 +  if (recentBadCertsService) {
   1.523 +    NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
   1.524 +    recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
   1.525 +                                      mInfoObject->SSLStatus());
   1.526 +  }
   1.527 +
   1.528 +  // pick the error code to report by priority
   1.529 +  PRErrorCode errorCodeToReport = mErrorCodeTrust    ? mErrorCodeTrust
   1.530 +                                : mErrorCodeMismatch ? mErrorCodeMismatch
   1.531 +                                : mErrorCodeExpired  ? mErrorCodeExpired
   1.532 +                                : mDefaultErrorCodeToReport;
   1.533 +
   1.534 +  SSLServerCertVerificationResult* result =
   1.535 +    new SSLServerCertVerificationResult(mInfoObject,
   1.536 +                                        errorCodeToReport,
   1.537 +                                        Telemetry::HistogramCount,
   1.538 +                                        -1,
   1.539 +                                        OverridableCertErrorMessage);
   1.540 +
   1.541 +  LogInvalidCertError(mInfoObject,
   1.542 +                      result->mErrorCode,
   1.543 +                      result->mErrorMessageType);
   1.544 +
   1.545 +  return result;
   1.546 +}
   1.547 +
   1.548 +void
   1.549 +CertErrorRunnable::RunOnTargetThread()
   1.550 +{
   1.551 +  MOZ_ASSERT(NS_IsMainThread());
   1.552 +
   1.553 +  mResult = CheckCertOverrides();
   1.554 +
   1.555 +  MOZ_ASSERT(mResult);
   1.556 +}
   1.557 +
   1.558 +// Converts a PRErrorCode into one of
   1.559 +//   nsICertOverrideService::ERROR_UNTRUSTED,
   1.560 +//   nsICertOverrideService::ERROR_MISMATCH,
   1.561 +//   nsICertOverrideService::ERROR_TIME
   1.562 +// if the given error code is an overridable error.
   1.563 +// If it is not, then 0 is returned.
   1.564 +uint32_t
   1.565 +PRErrorCodeToOverrideType(PRErrorCode errorCode)
   1.566 +{
   1.567 +  switch (errorCode)
   1.568 +  {
   1.569 +    case SEC_ERROR_UNKNOWN_ISSUER:
   1.570 +    case SEC_ERROR_UNTRUSTED_ISSUER:
   1.571 +    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
   1.572 +    case SEC_ERROR_UNTRUSTED_CERT:
   1.573 +    case SEC_ERROR_INADEQUATE_KEY_USAGE:
   1.574 +    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   1.575 +    case SEC_ERROR_CA_CERT_INVALID:
   1.576 +      // We group all these errors as "cert not trusted"
   1.577 +      return nsICertOverrideService::ERROR_UNTRUSTED;
   1.578 +    case SSL_ERROR_BAD_CERT_DOMAIN:
   1.579 +      return nsICertOverrideService::ERROR_MISMATCH;
   1.580 +    case SEC_ERROR_EXPIRED_CERTIFICATE:
   1.581 +      return nsICertOverrideService::ERROR_TIME;
   1.582 +    default:
   1.583 +      return 0;
   1.584 +  }
   1.585 +}
   1.586 +
   1.587 +SECStatus
   1.588 +NSSDetermineCertOverrideErrors(CertVerifier& certVerifier,
   1.589 +                               CERTCertificate* cert,
   1.590 +                               const SECItem* stapledOCSPResponse,
   1.591 +                               TransportSecurityInfo* infoObject,
   1.592 +                               PRTime now,
   1.593 +                               PRErrorCode defaultErrorCodeToReport,
   1.594 +                               /*out*/ uint32_t& collectedErrors,
   1.595 +                               /*out*/ PRErrorCode& errorCodeTrust,
   1.596 +                               /*out*/ PRErrorCode& errorCodeMismatch,
   1.597 +                               /*out*/ PRErrorCode& errorCodeExpired)
   1.598 +{
   1.599 +  MOZ_ASSERT(cert);
   1.600 +  MOZ_ASSERT(infoObject);
   1.601 +  MOZ_ASSERT(defaultErrorCodeToReport != 0);
   1.602 +  MOZ_ASSERT(collectedErrors == 0);
   1.603 +  MOZ_ASSERT(errorCodeTrust == 0);
   1.604 +  MOZ_ASSERT(errorCodeMismatch == 0);
   1.605 +  MOZ_ASSERT(errorCodeExpired == 0);
   1.606 +
   1.607 +  if (defaultErrorCodeToReport == 0) {
   1.608 +    NS_ERROR("No error code set during certificate validation failure.");
   1.609 +    PR_SetError(PR_INVALID_STATE_ERROR, 0);
   1.610 +    return SECFailure;
   1.611 +  }
   1.612 +
   1.613 +  // We only allow overrides for certain errors. Return early if the error
   1.614 +  // is not one of them. This is to avoid doing revocation fetching in the
   1.615 +  // case of OCSP stapling and probably for other reasons.
   1.616 +  if (PRErrorCodeToOverrideType(defaultErrorCodeToReport) == 0) {
   1.617 +    PR_SetError(defaultErrorCodeToReport, 0);
   1.618 +    return SECFailure;
   1.619 +  }
   1.620 +
   1.621 +  PLArenaPool* log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.622 +  PLArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
   1.623 +  if (!log_arena) {
   1.624 +    NS_ERROR("PORT_NewArena failed");
   1.625 +    return SECFailure; // PORT_NewArena set error code
   1.626 +  }
   1.627 +
   1.628 +  CERTVerifyLog* verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
   1.629 +  if (!verify_log) {
   1.630 +    NS_ERROR("PORT_ArenaZNew failed");
   1.631 +    return SECFailure; // PORT_ArenaZNew set error code
   1.632 +  }
   1.633 +  CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
   1.634 +  verify_log->arena = log_arena;
   1.635 +
   1.636 +  // We ignore the result code of the cert verification (i.e. VerifyCert's rv)
   1.637 +  // Either it is a failure, which is expected, and we'll process the
   1.638 +  //                         verify log below.
   1.639 +  // Or it is a success, then a domain mismatch is the only
   1.640 +  //                     possible failure.
   1.641 +  // XXX TODO: convert to VerifySSLServerCert
   1.642 +  // XXX TODO: get rid of error log
   1.643 +  certVerifier.VerifyCert(cert, certificateUsageSSLServer,
   1.644 +                          now, infoObject, infoObject->GetHostNameRaw(),
   1.645 +                          0, stapledOCSPResponse, nullptr, nullptr, verify_log);
   1.646 +
   1.647 +  // Check the name field against the desired hostname.
   1.648 +  if (CERT_VerifyCertName(cert, infoObject->GetHostNameRaw()) != SECSuccess) {
   1.649 +    collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
   1.650 +    errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   1.651 +  }
   1.652 +
   1.653 +  CERTVerifyLogNode* i_node;
   1.654 +  for (i_node = verify_log->head; i_node; i_node = i_node->next) {
   1.655 +    uint32_t overrideType = PRErrorCodeToOverrideType(i_node->error);
   1.656 +    // If this isn't an overridable error, set the error and return.
   1.657 +    if (overrideType == 0) {
   1.658 +      PR_SetError(i_node->error, 0);
   1.659 +      return SECFailure;
   1.660 +    }
   1.661 +    collectedErrors |= overrideType;
   1.662 +    if (overrideType == nsICertOverrideService::ERROR_UNTRUSTED) {
   1.663 +      if (errorCodeTrust == 0) {
   1.664 +        errorCodeTrust = i_node->error;
   1.665 +      }
   1.666 +    } else if (overrideType == nsICertOverrideService::ERROR_MISMATCH) {
   1.667 +      if (errorCodeMismatch == 0) {
   1.668 +        errorCodeMismatch = i_node->error;
   1.669 +      }
   1.670 +    } else if (overrideType == nsICertOverrideService::ERROR_TIME) {
   1.671 +      if (errorCodeExpired == 0) {
   1.672 +        errorCodeExpired = i_node->error;
   1.673 +      }
   1.674 +    } else {
   1.675 +      MOZ_CRASH("unexpected return value from PRErrorCodeToOverrideType");
   1.676 +    }
   1.677 +  }
   1.678 +
   1.679 +  return SECSuccess;
   1.680 +}
   1.681 +
   1.682 +// Returns null with the error code (PR_GetError()) set if it does not create
   1.683 +// the CertErrorRunnable.
   1.684 +CertErrorRunnable*
   1.685 +CreateCertErrorRunnable(CertVerifier& certVerifier,
   1.686 +                        PRErrorCode defaultErrorCodeToReport,
   1.687 +                        TransportSecurityInfo* infoObject,
   1.688 +                        CERTCertificate* cert,
   1.689 +                        const SECItem* stapledOCSPResponse,
   1.690 +                        const void* fdForLogging,
   1.691 +                        uint32_t providerFlags,
   1.692 +                        PRTime now)
   1.693 +{
   1.694 +  MOZ_ASSERT(infoObject);
   1.695 +  MOZ_ASSERT(cert);
   1.696 +
   1.697 +  uint32_t collected_errors = 0;
   1.698 +  PRErrorCode errorCodeTrust = 0;
   1.699 +  PRErrorCode errorCodeMismatch = 0;
   1.700 +  PRErrorCode errorCodeExpired = 0;
   1.701 +
   1.702 +  SECStatus rv;
   1.703 +  switch (certVerifier.mImplementation) {
   1.704 +    case CertVerifier::classic:
   1.705 +#ifndef NSS_NO_LIBPKIX
   1.706 +    case CertVerifier::libpkix:
   1.707 +#endif
   1.708 +      rv = NSSDetermineCertOverrideErrors(certVerifier, cert, stapledOCSPResponse,
   1.709 +                                          infoObject, now,
   1.710 +                                          defaultErrorCodeToReport,
   1.711 +                                          collected_errors, errorCodeTrust,
   1.712 +                                          errorCodeMismatch, errorCodeExpired);
   1.713 +      break;
   1.714 +
   1.715 +    case CertVerifier::mozillapkix:
   1.716 +      rv = MozillaPKIXDetermineCertOverrideErrors(cert,
   1.717 +                                                  infoObject->GetHostNameRaw(),
   1.718 +                                                  now, defaultErrorCodeToReport,
   1.719 +                                                  collected_errors,
   1.720 +                                                  errorCodeTrust,
   1.721 +                                                  errorCodeMismatch,
   1.722 +                                                  errorCodeExpired);
   1.723 +      break;
   1.724 +
   1.725 +    default:
   1.726 +      MOZ_CRASH("unexpected CertVerifier implementation");
   1.727 +      PR_SetError(defaultErrorCodeToReport, 0);
   1.728 +      return nullptr;
   1.729 +
   1.730 +  }
   1.731 +  if (rv != SECSuccess) {
   1.732 +    return nullptr;
   1.733 +  }
   1.734 +
   1.735 +  RefPtr<nsNSSCertificate> nssCert(nsNSSCertificate::Create(cert));
   1.736 +  if (!nssCert) {
   1.737 +    NS_ERROR("nsNSSCertificate::Create failed");
   1.738 +    PR_SetError(SEC_ERROR_NO_MEMORY, 0);
   1.739 +    return nullptr;
   1.740 +  }
   1.741 +
   1.742 +  if (!collected_errors) {
   1.743 +    // This will happen when CERT_*Verify* only returned error(s) that are
   1.744 +    // not on our whitelist of overridable certificate errors.
   1.745 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
   1.746 +           fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
   1.747 +    PR_SetError(defaultErrorCodeToReport, 0);
   1.748 +    return nullptr;
   1.749 +  }
   1.750 +
   1.751 +  infoObject->SetStatusErrorBits(*nssCert, collected_errors);
   1.752 +
   1.753 +  return new CertErrorRunnable(fdForLogging,
   1.754 +                               static_cast<nsIX509Cert*>(nssCert.get()),
   1.755 +                               infoObject, defaultErrorCodeToReport,
   1.756 +                               collected_errors, errorCodeTrust,
   1.757 +                               errorCodeMismatch, errorCodeExpired,
   1.758 +                               providerFlags);
   1.759 +}
   1.760 +
   1.761 +// When doing async cert processing, we dispatch one of these runnables to the
   1.762 +// socket transport service thread, which blocks the socket transport
   1.763 +// service thread while it waits for the inner CertErrorRunnable to execute
   1.764 +// CheckCertOverrides on the main thread. CheckCertOverrides must block events
   1.765 +// on both of these threads because it calls TransportSecurityInfo::GetInterface(),
   1.766 +// which may call nsHttpConnection::GetInterface() through
   1.767 +// TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always
   1.768 +// execute on the main thread, with the socket transport service thread
   1.769 +// blocked.
   1.770 +class CertErrorRunnableRunnable : public nsRunnable
   1.771 +{
   1.772 +public:
   1.773 +  CertErrorRunnableRunnable(CertErrorRunnable* certErrorRunnable)
   1.774 +    : mCertErrorRunnable(certErrorRunnable)
   1.775 +  {
   1.776 +  }
   1.777 +private:
   1.778 +  NS_IMETHOD Run()
   1.779 +  {
   1.780 +    nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
   1.781 +    // The result must run on the socket transport thread, which we are already
   1.782 +    // on, so we can just run it directly, instead of dispatching it.
   1.783 +    if (NS_SUCCEEDED(rv)) {
   1.784 +      rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
   1.785 +                                       : NS_ERROR_UNEXPECTED;
   1.786 +    }
   1.787 +    return rv;
   1.788 +  }
   1.789 +  RefPtr<CertErrorRunnable> mCertErrorRunnable;
   1.790 +};
   1.791 +
   1.792 +class SSLServerCertVerificationJob : public nsRunnable
   1.793 +{
   1.794 +public:
   1.795 +  // Must be called only on the socket transport thread
   1.796 +  static SECStatus Dispatch(const RefPtr<SharedCertVerifier>& certVerifier,
   1.797 +                            const void* fdForLogging,
   1.798 +                            TransportSecurityInfo* infoObject,
   1.799 +                            CERTCertificate* serverCert,
   1.800 +                            SECItem* stapledOCSPResponse,
   1.801 +                            uint32_t providerFlags,
   1.802 +                            PRTime time);
   1.803 +private:
   1.804 +  NS_DECL_NSIRUNNABLE
   1.805 +
   1.806 +  // Must be called only on the socket transport thread
   1.807 +  SSLServerCertVerificationJob(const RefPtr<SharedCertVerifier>& certVerifier,
   1.808 +                               const void* fdForLogging,
   1.809 +                               TransportSecurityInfo* infoObject,
   1.810 +                               CERTCertificate* cert,
   1.811 +                               SECItem* stapledOCSPResponse,
   1.812 +                               uint32_t providerFlags,
   1.813 +                               PRTime time);
   1.814 +  const RefPtr<SharedCertVerifier> mCertVerifier;
   1.815 +  const void* const mFdForLogging;
   1.816 +  const RefPtr<TransportSecurityInfo> mInfoObject;
   1.817 +  const mozilla::pkix::ScopedCERTCertificate mCert;
   1.818 +  const uint32_t mProviderFlags;
   1.819 +  const PRTime mTime;
   1.820 +  const TimeStamp mJobStartTime;
   1.821 +  const ScopedSECItem mStapledOCSPResponse;
   1.822 +};
   1.823 +
   1.824 +SSLServerCertVerificationJob::SSLServerCertVerificationJob(
   1.825 +    const RefPtr<SharedCertVerifier>& certVerifier, const void* fdForLogging,
   1.826 +    TransportSecurityInfo* infoObject, CERTCertificate* cert,
   1.827 +    SECItem* stapledOCSPResponse, uint32_t providerFlags, PRTime time)
   1.828 +  : mCertVerifier(certVerifier)
   1.829 +  , mFdForLogging(fdForLogging)
   1.830 +  , mInfoObject(infoObject)
   1.831 +  , mCert(CERT_DupCertificate(cert))
   1.832 +  , mProviderFlags(providerFlags)
   1.833 +  , mTime(time)
   1.834 +  , mJobStartTime(TimeStamp::Now())
   1.835 +  , mStapledOCSPResponse(SECITEM_DupItem(stapledOCSPResponse))
   1.836 +{
   1.837 +}
   1.838 +
   1.839 +// This function assumes that we will only use the SPDY connection coalescing
   1.840 +// feature on connections where we have negotiated SPDY using NPN. If we ever
   1.841 +// talk SPDY without having negotiated it with SPDY, this code will give wrong
   1.842 +// and perhaps unsafe results.
   1.843 +//
   1.844 +// Returns SECSuccess on the initial handshake of all connections, on
   1.845 +// renegotiations for any connections where we did not negotiate SPDY, or on any
   1.846 +// SPDY connection where the server's certificate did not change.
   1.847 +//
   1.848 +// Prohibit changing the server cert only if we negotiated SPDY,
   1.849 +// in order to support SPDY's cross-origin connection pooling.
   1.850 +static SECStatus
   1.851 +BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
   1.852 +                             CERTCertificate* serverCert)
   1.853 +{
   1.854 +  // Get the existing cert. If there isn't one, then there is
   1.855 +  // no cert change to worry about.
   1.856 +  nsCOMPtr<nsIX509Cert> cert;
   1.857 +  nsCOMPtr<nsIX509Cert2> cert2;
   1.858 +
   1.859 +  RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
   1.860 +  if (!status) {
   1.861 +    // If we didn't have a status, then this is the
   1.862 +    // first handshake on this connection, not a
   1.863 +    // renegotiation.
   1.864 +    return SECSuccess;
   1.865 +  }
   1.866 +
   1.867 +  status->GetServerCert(getter_AddRefs(cert));
   1.868 +  cert2 = do_QueryInterface(cert);
   1.869 +  if (!cert2) {
   1.870 +    NS_NOTREACHED("every nsSSLStatus must have a cert"
   1.871 +                  "that implements nsIX509Cert2");
   1.872 +    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
   1.873 +    return SECFailure;
   1.874 +  }
   1.875 +
   1.876 +  // Filter out sockets that did not neogtiate SPDY via NPN
   1.877 +  nsAutoCString negotiatedNPN;
   1.878 +  nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
   1.879 +  NS_ASSERTION(NS_SUCCEEDED(rv),
   1.880 +               "GetNegotiatedNPN() failed during renegotiation");
   1.881 +
   1.882 +  if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
   1.883 +                                            NS_LITERAL_CSTRING("spdy/")))
   1.884 +    return SECSuccess;
   1.885 +
   1.886 +  // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
   1.887 +  if (NS_FAILED(rv)) {
   1.888 +    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.889 +           ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
   1.890 +            " Assuming spdy.\n"));
   1.891 +  }
   1.892 +
   1.893 +  // Check to see if the cert has actually changed
   1.894 +  ScopedCERTCertificate c(cert2->GetCert());
   1.895 +  NS_ASSERTION(c, "very bad and hopefully impossible state");
   1.896 +  bool sameCert = CERT_CompareCerts(c, serverCert);
   1.897 +  if (sameCert)
   1.898 +    return SECSuccess;
   1.899 +
   1.900 +  // Report an error - changed cert is confirmed
   1.901 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.902 +         ("SPDY Refused to allow new cert during renegotiation\n"));
   1.903 +  PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
   1.904 +  return SECFailure;
   1.905 +}
   1.906 +
   1.907 +SECStatus
   1.908 +AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject,
   1.909 +                CERTCertificate* cert, SECItem* stapledOCSPResponse,
   1.910 +                uint32_t providerFlags, PRTime time)
   1.911 +{
   1.912 +  MOZ_ASSERT(infoObject);
   1.913 +  MOZ_ASSERT(cert);
   1.914 +
   1.915 +  SECStatus rv;
   1.916 +
   1.917 +  // TODO: Remove this after we switch to mozilla::pkix as the
   1.918 +  // only option
   1.919 +  if (certVerifier.mImplementation == CertVerifier::classic) {
   1.920 +    if (stapledOCSPResponse) {
   1.921 +      CERTCertDBHandle* handle = CERT_GetDefaultCertDB();
   1.922 +      rv = CERT_CacheOCSPResponseFromSideChannel(handle, cert, PR_Now(),
   1.923 +                                                 stapledOCSPResponse,
   1.924 +                                                 infoObject);
   1.925 +      if (rv != SECSuccess) {
   1.926 +        // Due to buggy servers that will staple expired OCSP responses
   1.927 +        // (see for example http://trac.nginx.org/nginx/ticket/425),
   1.928 +        // don't terminate the connection if the stapled response is expired.
   1.929 +        // We will fall back to fetching revocation information.
   1.930 +        PRErrorCode ocspErrorCode = PR_GetError();
   1.931 +        if (ocspErrorCode != SEC_ERROR_OCSP_OLD_RESPONSE) {
   1.932 +          // stapled OCSP response present but invalid for some reason
   1.933 +          Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 4);
   1.934 +          return rv;
   1.935 +        } else {
   1.936 +          // stapled OCSP response present but expired
   1.937 +          Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 3);
   1.938 +        }
   1.939 +      } else {
   1.940 +        // stapled OCSP response present and good
   1.941 +        Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 1);
   1.942 +      }
   1.943 +    } else {
   1.944 +      // no stapled OCSP response
   1.945 +      Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 2);
   1.946 +
   1.947 +      uint32_t reasonsForNotFetching = 0;
   1.948 +
   1.949 +      char* ocspURI = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
   1.950 +      if (!ocspURI) {
   1.951 +        reasonsForNotFetching |= 1; // invalid/missing OCSP URI
   1.952 +      } else {
   1.953 +        if (std::strncmp(ocspURI, "http://", 7)) { // approximation
   1.954 +          reasonsForNotFetching |= 1; // invalid/missing OCSP URI
   1.955 +        }
   1.956 +        PORT_Free(ocspURI);
   1.957 +      }
   1.958 +
   1.959 +      if (!certVerifier.mOCSPDownloadEnabled) {
   1.960 +        reasonsForNotFetching |= 2;
   1.961 +      }
   1.962 +
   1.963 +      Telemetry::Accumulate(Telemetry::SSL_OCSP_MAY_FETCH,
   1.964 +                            reasonsForNotFetching);
   1.965 +    }
   1.966 +  }
   1.967 +
   1.968 +  // We want to avoid storing any intermediate cert information when browsing
   1.969 +  // in private, transient contexts.
   1.970 +  bool saveIntermediates =
   1.971 +    !(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE);
   1.972 +
   1.973 +  mozilla::pkix::ScopedCERTCertList certList;
   1.974 +  SECOidTag evOidPolicy;
   1.975 +  rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
   1.976 +                                        time, infoObject,
   1.977 +                                        infoObject->GetHostNameRaw(),
   1.978 +                                        saveIntermediates, nullptr,
   1.979 +                                        &evOidPolicy);
   1.980 +
   1.981 +  // We want to remember the CA certs in the temp db, so that the application can find the
   1.982 +  // complete chain at any time it might need it.
   1.983 +  // But we keep only those CA certs in the temp db, that we didn't already know.
   1.984 +
   1.985 +  RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
   1.986 +  RefPtr<nsNSSCertificate> nsc;
   1.987 +
   1.988 +  if (!status || !status->mServerCert) {
   1.989 +    if( rv == SECSuccess ){
   1.990 +      nsc = nsNSSCertificate::Create(cert, &evOidPolicy);
   1.991 +    }
   1.992 +    else {
   1.993 +      nsc = nsNSSCertificate::Create(cert);
   1.994 +    }
   1.995 +  }
   1.996 +
   1.997 +  if (rv == SECSuccess) {
   1.998 +    // The connection may get terminated, for example, if the server requires
   1.999 +    // a client cert. Let's provide a minimal SSLStatus
  1.1000 +    // to the caller that contains at least the cert and its status.
  1.1001 +    if (!status) {
  1.1002 +      status = new nsSSLStatus();
  1.1003 +      infoObject->SetSSLStatus(status);
  1.1004 +    }
  1.1005 +
  1.1006 +    if (rv == SECSuccess) {
  1.1007 +      // Certificate verification succeeded delete any potential record
  1.1008 +      // of certificate error bits.
  1.1009 +      RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject,
  1.1010 +                                                                  nullptr, rv);
  1.1011 +    }
  1.1012 +    else {
  1.1013 +      // Certificate verification failed, update the status' bits.
  1.1014 +      RememberCertErrorsTable::GetInstance().LookupCertErrorBits(
  1.1015 +        infoObject, status);
  1.1016 +    }
  1.1017 +
  1.1018 +    if (status && !status->mServerCert) {
  1.1019 +      status->mServerCert = nsc;
  1.1020 +      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1021 +             ("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
  1.1022 +    }
  1.1023 +  }
  1.1024 +
  1.1025 +  return rv;
  1.1026 +}
  1.1027 +
  1.1028 +/*static*/ SECStatus
  1.1029 +SSLServerCertVerificationJob::Dispatch(
  1.1030 +  const RefPtr<SharedCertVerifier>& certVerifier,
  1.1031 +  const void* fdForLogging,
  1.1032 +  TransportSecurityInfo* infoObject,
  1.1033 +  CERTCertificate* serverCert,
  1.1034 +  SECItem* stapledOCSPResponse,
  1.1035 +  uint32_t providerFlags,
  1.1036 +  PRTime time)
  1.1037 +{
  1.1038 +  // Runs on the socket transport thread
  1.1039 +  if (!certVerifier || !infoObject || !serverCert) {
  1.1040 +    NS_ERROR("Invalid parameters for SSL server cert validation");
  1.1041 +    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1042 +    return SECFailure;
  1.1043 +  }
  1.1044 +
  1.1045 +  RefPtr<SSLServerCertVerificationJob> job(
  1.1046 +    new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject,
  1.1047 +                                     serverCert, stapledOCSPResponse,
  1.1048 +                                     providerFlags, time));
  1.1049 +
  1.1050 +  nsresult nrv;
  1.1051 +  if (!gCertVerificationThreadPool) {
  1.1052 +    nrv = NS_ERROR_NOT_INITIALIZED;
  1.1053 +  } else {
  1.1054 +    nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
  1.1055 +  }
  1.1056 +  if (NS_FAILED(nrv)) {
  1.1057 +    // We can't call SetCertVerificationResult here to change
  1.1058 +    // mCertVerificationState because SetCertVerificationResult will call
  1.1059 +    // libssl functions that acquire SSL locks that are already being held at
  1.1060 +    // this point. infoObject->mCertVerificationState will be stuck at
  1.1061 +    // waiting_for_cert_verification here, but that is OK because we already
  1.1062 +    // have to be able to handle cases where we encounter non-cert errors while
  1.1063 +    // in that state.
  1.1064 +    PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
  1.1065 +                      ? SEC_ERROR_NO_MEMORY
  1.1066 +                      : PR_INVALID_STATE_ERROR;
  1.1067 +    PORT_SetError(error);
  1.1068 +    return SECFailure;
  1.1069 +  }
  1.1070 +
  1.1071 +  PORT_SetError(PR_WOULD_BLOCK_ERROR);
  1.1072 +  return SECWouldBlock;
  1.1073 +}
  1.1074 +
  1.1075 +NS_IMETHODIMP
  1.1076 +SSLServerCertVerificationJob::Run()
  1.1077 +{
  1.1078 +  // Runs on a cert verification thread
  1.1079 +
  1.1080 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1081 +          ("[%p] SSLServerCertVerificationJob::Run\n", mInfoObject.get()));
  1.1082 +
  1.1083 +  PRErrorCode error;
  1.1084 +
  1.1085 +  nsNSSShutDownPreventionLock nssShutdownPrevention;
  1.1086 +  if (mInfoObject->isAlreadyShutDown()) {
  1.1087 +    error = SEC_ERROR_USER_CANCELLED;
  1.1088 +  } else {
  1.1089 +    Telemetry::ID successTelemetry;
  1.1090 +    Telemetry::ID failureTelemetry;
  1.1091 +    switch (mCertVerifier->mImplementation) {
  1.1092 +      case CertVerifier::classic:
  1.1093 +        successTelemetry
  1.1094 +          = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_CLASSIC;
  1.1095 +        failureTelemetry
  1.1096 +          = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_CLASSIC;
  1.1097 +        break;
  1.1098 +      case CertVerifier::mozillapkix:
  1.1099 +        successTelemetry
  1.1100 +          = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX;
  1.1101 +        failureTelemetry
  1.1102 +          = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX;
  1.1103 +        break;
  1.1104 +#ifndef NSS_NO_LIBPKIX
  1.1105 +      case CertVerifier::libpkix:
  1.1106 +        successTelemetry
  1.1107 +          = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_LIBPKIX;
  1.1108 +        failureTelemetry
  1.1109 +          = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_LIBPKIX;
  1.1110 +        break;
  1.1111 +#endif
  1.1112 +      default:
  1.1113 +        MOZ_CRASH("Unknown CertVerifier mode");
  1.1114 +    }
  1.1115 +
  1.1116 +    // XXX
  1.1117 +    // Reset the error code here so we can detect if AuthCertificate fails to
  1.1118 +    // set the error code if/when it fails.
  1.1119 +    PR_SetError(0, 0);
  1.1120 +    SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert.get(),
  1.1121 +                                   mStapledOCSPResponse, mProviderFlags,
  1.1122 +                                   mTime);
  1.1123 +    if (rv == SECSuccess) {
  1.1124 +      uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds());
  1.1125 +      RefPtr<SSLServerCertVerificationResult> restart(
  1.1126 +        new SSLServerCertVerificationResult(mInfoObject, 0,
  1.1127 +                                            successTelemetry, interval));
  1.1128 +      restart->Dispatch();
  1.1129 +      Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
  1.1130 +      return NS_OK;
  1.1131 +    }
  1.1132 +
  1.1133 +    // Note: the interval is not calculated once as PR_GetError MUST be called
  1.1134 +    // before any other  function call
  1.1135 +    error = PR_GetError();
  1.1136 +    {
  1.1137 +      TimeStamp now = TimeStamp::Now();
  1.1138 +      MutexAutoLock telemetryMutex(*gSSLVerificationTelemetryMutex);
  1.1139 +      Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now);
  1.1140 +    }
  1.1141 +    if (error != 0) {
  1.1142 +      RefPtr<CertErrorRunnable> runnable(
  1.1143 +          CreateCertErrorRunnable(*mCertVerifier, error, mInfoObject,
  1.1144 +                                  mCert.get(), mStapledOCSPResponse,
  1.1145 +                                  mFdForLogging, mProviderFlags, mTime));
  1.1146 +      if (!runnable) {
  1.1147 +        // CreateCertErrorRunnable set a new error code
  1.1148 +        error = PR_GetError();
  1.1149 +      } else {
  1.1150 +        // We must block the the socket transport service thread while the
  1.1151 +        // main thread executes the CertErrorRunnable. The CertErrorRunnable
  1.1152 +        // will dispatch the result asynchronously, so we don't have to block
  1.1153 +        // this thread waiting for it.
  1.1154 +
  1.1155 +        PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1156 +                ("[%p][%p] Before dispatching CertErrorRunnable\n",
  1.1157 +                mFdForLogging, runnable.get()));
  1.1158 +
  1.1159 +        nsresult nrv;
  1.1160 +        nsCOMPtr<nsIEventTarget> stsTarget
  1.1161 +          = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
  1.1162 +        if (NS_SUCCEEDED(nrv)) {
  1.1163 +          nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
  1.1164 +                                    NS_DISPATCH_NORMAL);
  1.1165 +        }
  1.1166 +        if (NS_SUCCEEDED(nrv)) {
  1.1167 +          return NS_OK;
  1.1168 +        }
  1.1169 +
  1.1170 +        NS_ERROR("Failed to dispatch CertErrorRunnable");
  1.1171 +        error = PR_INVALID_STATE_ERROR;
  1.1172 +      }
  1.1173 +    }
  1.1174 +  }
  1.1175 +
  1.1176 +  if (error == 0) {
  1.1177 +    NS_NOTREACHED("no error set during certificate validation failure");
  1.1178 +    error = PR_INVALID_STATE_ERROR;
  1.1179 +  }
  1.1180 +
  1.1181 +  RefPtr<SSLServerCertVerificationResult> failure(
  1.1182 +    new SSLServerCertVerificationResult(mInfoObject, error));
  1.1183 +  failure->Dispatch();
  1.1184 +  return NS_OK;
  1.1185 +}
  1.1186 +
  1.1187 +} // unnamed namespace
  1.1188 +
  1.1189 +// Extracts whatever information we need out of fd (using SSL_*) and passes it
  1.1190 +// to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
  1.1191 +// never do anything with fd except logging.
  1.1192 +SECStatus
  1.1193 +AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
  1.1194 +{
  1.1195 +  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  1.1196 +  if (!certVerifier) {
  1.1197 +    PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
  1.1198 +    return SECFailure;
  1.1199 +  }
  1.1200 +
  1.1201 +  // Runs on the socket transport thread
  1.1202 +
  1.1203 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1.1204 +         ("[%p] starting AuthCertificateHook\n", fd));
  1.1205 +
  1.1206 +  // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
  1.1207 +  // doing verification without checking signatures.
  1.1208 +  NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
  1.1209 +
  1.1210 +  // PSM never causes libssl to call this function with PR_TRUE for isServer,
  1.1211 +  // and many things in PSM assume that we are a client.
  1.1212 +  NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
  1.1213 +
  1.1214 +  nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg);
  1.1215 +
  1.1216 +  ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
  1.1217 +
  1.1218 +  if (!checkSig || isServer || !socketInfo || !serverCert) {
  1.1219 +      PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1.1220 +      return SECFailure;
  1.1221 +  }
  1.1222 +
  1.1223 +  socketInfo->SetFullHandshake();
  1.1224 +
  1.1225 +  // This value of "now" is used both here for OCSP stapling and later
  1.1226 +  // when calling CreateCertErrorRunnable.
  1.1227 +  PRTime now = PR_Now();
  1.1228 +
  1.1229 +  if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
  1.1230 +    return SECFailure;
  1.1231 +
  1.1232 +  bool onSTSThread;
  1.1233 +  nsresult nrv;
  1.1234 +  nsCOMPtr<nsIEventTarget> sts
  1.1235 +    = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
  1.1236 +  if (NS_SUCCEEDED(nrv)) {
  1.1237 +    nrv = sts->IsOnCurrentThread(&onSTSThread);
  1.1238 +  }
  1.1239 +
  1.1240 +  if (NS_FAILED(nrv)) {
  1.1241 +    NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
  1.1242 +    PR_SetError(PR_UNKNOWN_ERROR, 0);
  1.1243 +    return SECFailure;
  1.1244 +  }
  1.1245 +
  1.1246 +  // SSL_PeerStapledOCSPResponses will never return a non-empty response if
  1.1247 +  // OCSP stapling wasn't enabled because libssl wouldn't have let the server
  1.1248 +  // return a stapled OCSP response.
  1.1249 +  // We don't own these pointers.
  1.1250 +  const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
  1.1251 +  SECItem* stapledOCSPResponse = nullptr;
  1.1252 +  // we currently only support single stapled responses
  1.1253 +  if (csa && csa->len == 1) {
  1.1254 +    stapledOCSPResponse = &csa->items[0];
  1.1255 +  }
  1.1256 +
  1.1257 +  uint32_t providerFlags = 0;
  1.1258 +  socketInfo->GetProviderFlags(&providerFlags);
  1.1259 +
  1.1260 +  if (onSTSThread) {
  1.1261 +
  1.1262 +    // We *must* do certificate verification on a background thread because
  1.1263 +    // we need the socket transport thread to be free for our OCSP requests,
  1.1264 +    // and we *want* to do certificate verification on a background thread
  1.1265 +    // because of the performance benefits of doing so.
  1.1266 +    socketInfo->SetCertVerificationWaiting();
  1.1267 +    SECStatus rv = SSLServerCertVerificationJob::Dispatch(
  1.1268 +                     certVerifier, static_cast<const void*>(fd), socketInfo,
  1.1269 +                     serverCert, stapledOCSPResponse, providerFlags, now);
  1.1270 +    return rv;
  1.1271 +  }
  1.1272 +
  1.1273 +  // We can't do certificate verification on a background thread, because the
  1.1274 +  // thread doing the network I/O may not interrupt its network I/O on receipt
  1.1275 +  // of our SSLServerCertVerificationResult event, and/or it might not even be
  1.1276 +  // a non-blocking socket.
  1.1277 +
  1.1278 +  SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert,
  1.1279 +                                 stapledOCSPResponse, providerFlags, now);
  1.1280 +  if (rv == SECSuccess) {
  1.1281 +    Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
  1.1282 +    return SECSuccess;
  1.1283 +  }
  1.1284 +
  1.1285 +  PRErrorCode error = PR_GetError();
  1.1286 +  if (error != 0) {
  1.1287 +    RefPtr<CertErrorRunnable> runnable(
  1.1288 +        CreateCertErrorRunnable(*certVerifier, error, socketInfo, serverCert,
  1.1289 +                                stapledOCSPResponse,
  1.1290 +                                static_cast<const void*>(fd), providerFlags,
  1.1291 +                                now));
  1.1292 +    if (!runnable) {
  1.1293 +      // CreateCertErrorRunnable sets a new error code when it fails
  1.1294 +      error = PR_GetError();
  1.1295 +    } else {
  1.1296 +      // We have to return SECSuccess or SECFailure based on the result of the
  1.1297 +      // override processing, so we must block this thread waiting for it. The
  1.1298 +      // CertErrorRunnable will NOT dispatch the result at all, since we passed
  1.1299 +      // false for CreateCertErrorRunnable's async parameter
  1.1300 +      nrv = runnable->DispatchToMainThreadAndWait();
  1.1301 +      if (NS_FAILED(nrv)) {
  1.1302 +        NS_ERROR("Failed to dispatch CertErrorRunnable");
  1.1303 +        PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1.1304 +        return SECFailure;
  1.1305 +      }
  1.1306 +
  1.1307 +      if (!runnable->mResult) {
  1.1308 +        NS_ERROR("CertErrorRunnable did not set result");
  1.1309 +        PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1.1310 +        return SECFailure;
  1.1311 +      }
  1.1312 +
  1.1313 +      if (runnable->mResult->mErrorCode == 0) {
  1.1314 +        return SECSuccess; // cert error override occurred.
  1.1315 +      }
  1.1316 +
  1.1317 +      // We must call SetCanceled here to set the error message type
  1.1318 +      // in case it isn't PlainErrorMessage, which is what we would
  1.1319 +      // default to if we just called
  1.1320 +      // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
  1.1321 +      // SECFailure without doing this.
  1.1322 +      socketInfo->SetCanceled(runnable->mResult->mErrorCode,
  1.1323 +                              runnable->mResult->mErrorMessageType);
  1.1324 +      error = runnable->mResult->mErrorCode;
  1.1325 +    }
  1.1326 +  }
  1.1327 +
  1.1328 +  if (error == 0) {
  1.1329 +    NS_ERROR("error code not set");
  1.1330 +    error = PR_UNKNOWN_ERROR;
  1.1331 +  }
  1.1332 +
  1.1333 +  PR_SetError(error, 0);
  1.1334 +  return SECFailure;
  1.1335 +}
  1.1336 +
  1.1337 +#ifndef MOZ_NO_EV_CERTS
  1.1338 +class InitializeIdentityInfo : public CryptoTask
  1.1339 +{
  1.1340 +  virtual nsresult CalculateResult() MOZ_OVERRIDE
  1.1341 +  {
  1.1342 +    EnsureIdentityInfoLoaded();
  1.1343 +    return NS_OK;
  1.1344 +  }
  1.1345 +
  1.1346 +  virtual void ReleaseNSSResources() MOZ_OVERRIDE { } // no-op
  1.1347 +  virtual void CallCallback(nsresult rv) MOZ_OVERRIDE { } // no-op
  1.1348 +};
  1.1349 +#endif
  1.1350 +
  1.1351 +void EnsureServerVerificationInitialized()
  1.1352 +{
  1.1353 +#ifndef MOZ_NO_EV_CERTS
  1.1354 +  // Should only be called from socket transport thread due to the static
  1.1355 +  // variable and the reference to gCertVerificationThreadPool
  1.1356 +
  1.1357 +  static bool triggeredCertVerifierInit = false;
  1.1358 +  if (triggeredCertVerifierInit)
  1.1359 +    return;
  1.1360 +  triggeredCertVerifierInit = true;
  1.1361 +
  1.1362 +  RefPtr<InitializeIdentityInfo> initJob = new InitializeIdentityInfo();
  1.1363 +  if (gCertVerificationThreadPool)
  1.1364 +    gCertVerificationThreadPool->Dispatch(initJob, NS_DISPATCH_NORMAL);
  1.1365 +#endif
  1.1366 +}
  1.1367 +
  1.1368 +SSLServerCertVerificationResult::SSLServerCertVerificationResult(
  1.1369 +        TransportSecurityInfo* infoObject, PRErrorCode errorCode,
  1.1370 +        Telemetry::ID telemetryID, uint32_t telemetryValue,
  1.1371 +        SSLErrorMessageType errorMessageType)
  1.1372 +  : mInfoObject(infoObject)
  1.1373 +  , mErrorCode(errorCode)
  1.1374 +  , mErrorMessageType(errorMessageType)
  1.1375 +  , mTelemetryID(telemetryID)
  1.1376 +  , mTelemetryValue(telemetryValue)
  1.1377 +{
  1.1378 +// We accumulate telemetry for (only) successful validations on the main thread
  1.1379 +// to avoid adversely affecting performance by acquiring the mutex that we use
  1.1380 +// when accumulating the telemetry for unsuccessful validations. Unsuccessful
  1.1381 +// validations times are accumulated elsewhere.
  1.1382 +MOZ_ASSERT(telemetryID == Telemetry::HistogramCount || errorCode == 0);
  1.1383 +}
  1.1384 +
  1.1385 +void
  1.1386 +SSLServerCertVerificationResult::Dispatch()
  1.1387 +{
  1.1388 +  nsresult rv;
  1.1389 +  nsCOMPtr<nsIEventTarget> stsTarget
  1.1390 +    = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  1.1391 +  NS_ASSERTION(stsTarget,
  1.1392 +               "Failed to get socket transport service event target");
  1.1393 +  rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
  1.1394 +  NS_ASSERTION(NS_SUCCEEDED(rv),
  1.1395 +               "Failed to dispatch SSLServerCertVerificationResult");
  1.1396 +}
  1.1397 +
  1.1398 +NS_IMETHODIMP
  1.1399 +SSLServerCertVerificationResult::Run()
  1.1400 +{
  1.1401 +  // TODO: Assert that we're on the socket transport thread
  1.1402 +  if (mTelemetryID != Telemetry::HistogramCount) {
  1.1403 +     Telemetry::Accumulate(mTelemetryID, mTelemetryValue);
  1.1404 +  }
  1.1405 +  // XXX: This cast will be removed by the next patch
  1.1406 +  ((nsNSSSocketInfo*) mInfoObject.get())
  1.1407 +    ->SetCertVerificationResult(mErrorCode, mErrorMessageType);
  1.1408 +  return NS_OK;
  1.1409 +}
  1.1410 +
  1.1411 +} } // namespace mozilla::psm

mercurial