security/manager/ssl/src/SSLServerCertVerification.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 // For connections that are not processed on the socket transport thread, we do
     8 // NOT use the async logic described below. Instead, we authenticate the
     9 // certificate on the thread that the connection's I/O happens on,
    10 // synchronously. This allows us to do certificate verification for blocking
    11 // (not non-blocking) sockets and sockets that have their I/O processed on a
    12 // thread other than the socket transport service thread. Also, we DO NOT
    13 // support blocking sockets on the socket transport service thread at all.
    14 //
    15 // During certificate authentication, we call CERT_PKIXVerifyCert or
    16 // CERT_VerifyCert. These functions may make zero or more HTTP requests
    17 // for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
    18 // for these requests processes them on the socket transport service thread.
    19 //
    20 // If the connection for which we are verifying the certificate is happening
    21 // on the socket transport thread (the usually case, at least for HTTP), then
    22 // if our cert auth hook were to call the CERT_*Verify* functions directly,
    23 // there would be a deadlock: The CERT_*Verify* function would cause an event
    24 // to be asynchronously posted to the socket transport thread, and then it
    25 // would block the socket transport thread waiting to be notified of the HTTP
    26 // response. However, the HTTP request would never actually be processed
    27 // because the socket transport thread would be blocked and so it wouldn't be
    28 // able process HTTP requests. (i.e. Deadlock.)
    29 //
    30 // Consequently, when we are asked to verify a certificate on the socket
    31 // transport service thread, we must always call the CERT_*Verify* cert
    32 // functions on another thread. To accomplish this, our auth cert hook
    33 // dispatches a SSLServerCertVerificationJob to a pool of background threads,
    34 // and then immediatley return SECWouldBlock to libssl. These jobs are where
    35 // the CERT_*Verify* functions are actually called.
    36 //
    37 // When our auth cert hook returns SECWouldBlock, libssl will carry on the
    38 // handshake while we validate the certificate. This will free up the socket
    39 // transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
    40 // requests needed for cert verification as mentioned above--can be processed.
    41 //
    42 // Once the CERT_*Verify* function returns, the cert verification job
    43 // dispatches a SSLServerCertVerificationResult to the socket transport thread;
    44 // the SSLServerCertVerificationResult will notify libssl that the certificate
    45 // authentication is complete. Once libssl is notified that the authentication
    46 // is complete, it will continue the SSL handshake (if it hasn't already
    47 // finished) and it will begin allowing us to send/receive data on the
    48 // connection.
    49 //
    50 // Timeline of events (for connections managed by the socket transport service):
    51 //
    52 //    * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
    53 //      transport thread.
    54 //    * SSLServerCertVerificationJob::Dispatch queues a job
    55 //      (instance of SSLServerCertVerificationJob) to its background thread
    56 //      pool and returns.
    57 //    * One of the background threads calls CERT_*Verify*, which may enqueue
    58 //      some HTTP request(s) onto the socket transport thread, and then
    59 //      blocks that background thread waiting for the responses and/or timeouts
    60 //      or errors for those requests.
    61 //    * Once those HTTP responses have all come back or failed, the
    62 //      CERT_*Verify* function returns a result indicating that the validation
    63 //      succeeded or failed.
    64 //    * If the validation succeeded, then a SSLServerCertVerificationResult
    65 //      event is posted to the socket transport thread, and the cert
    66 //      verification thread becomes free to verify other certificates.
    67 //    * Otherwise, a CertErrorRunnable is posted to the socket transport thread
    68 //      and then to the main thread (blocking both, see CertErrorRunnable) to
    69 //      do cert override processing and bad cert listener notification. Then
    70 //      the cert verification thread becomes free to verify other certificates.
    71 //    * After processing cert overrides, the CertErrorRunnable will dispatch a
    72 //      SSLServerCertVerificationResult event to the socket transport thread to
    73 //      notify it of the result of the override processing; then it returns,
    74 //      freeing up the main thread.
    75 //    * The SSLServerCertVerificationResult event will either wake up the
    76 //      socket (using SSL_RestartHandshakeAfterServerCert) if validation
    77 //      succeeded or there was an error override, or it will set an error flag
    78 //      so that the next I/O operation on the socket will fail, causing the
    79 //      socket transport thread to close the connection.
    80 //
    81 // Cert override processing must happen on the main thread because it accesses
    82 // the nsICertOverrideService, and that service must be accessed on the main
    83 // thread because some extensions (Selenium, in particular) replace it with a
    84 // Javascript implementation, and chrome JS must always be run on the main
    85 // thread.
    86 //
    87 // SSLServerCertVerificationResult must be dispatched to the socket transport
    88 // thread because we must only call SSL_* functions on the socket transport
    89 // thread since they may do I/O, because many parts of nsNSSSocketInfo (the
    90 // subclass of TransportSecurityInfo used when validating certificates during
    91 // an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because
    92 // we need the event to interrupt the PR_Poll that may waiting for I/O on the
    93 // socket for which we are validating the cert.
    95 #include "SSLServerCertVerification.h"
    97 #include <cstring>
    99 #include "pkix/pkixtypes.h"
   100 #include "CertVerifier.h"
   101 #include "CryptoTask.h"
   102 #include "ExtendedValidation.h"
   103 #include "NSSCertDBTrustDomain.h"
   104 #include "nsIBadCertListener2.h"
   105 #include "nsICertOverrideService.h"
   106 #include "nsISiteSecurityService.h"
   107 #include "nsNSSComponent.h"
   108 #include "nsNSSCleaner.h"
   109 #include "nsRecentBadCerts.h"
   110 #include "nsNSSIOLayer.h"
   111 #include "nsNSSShutDown.h"
   113 #include "mozilla/Assertions.h"
   114 #include "mozilla/Mutex.h"
   115 #include "mozilla/Telemetry.h"
   116 #include "mozilla/unused.h"
   117 #include "nsIThreadPool.h"
   118 #include "nsNetUtil.h"
   119 #include "nsXPCOMCIDInternal.h"
   120 #include "nsComponentManagerUtils.h"
   121 #include "nsServiceManagerUtils.h"
   122 #include "PSMRunnable.h"
   123 #include "SharedSSLState.h"
   124 #include "nsContentUtils.h"
   126 #include "ssl.h"
   127 #include "secerr.h"
   128 #include "secport.h"
   129 #include "sslerr.h"
   130 #include "ocsp.h"
   132 #ifdef PR_LOGGING
   133 extern PRLogModuleInfo* gPIPNSSLog;
   134 #endif
   136 namespace mozilla { namespace psm {
   138 namespace {
   140 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   142 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
   143 NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
   145 // do not use a nsCOMPtr to avoid static initializer/destructor
   146 nsIThreadPool* gCertVerificationThreadPool = nullptr;
   148 // We avoid using a mutex for the success case to avoid lock-related
   149 // performance issues. However, we do use a lock in the error case to simplify
   150 // the code, since performance in the error case is not important.
   151 Mutex* gSSLVerificationTelemetryMutex = nullptr;
   153 // We add a mutex to serialize PKCS11 database operations
   154 Mutex* gSSLVerificationPK11Mutex = nullptr;
   156 } // unnamed namespace
   158 // Called when the socket transport thread starts, to initialize the SSL cert
   159 // verification thread pool. By tying the thread pool startup/shutdown directly
   160 // to the STS thread's lifetime, we ensure that they are *always* available for
   161 // SSL connections and that there are no races during startup and especially
   162 // shutdown. (Previously, we have had multiple problems with races in PSM
   163 // background threads, and the race-prevention/shutdown logic used there is
   164 // brittle. Since this service is critical to things like downloading updates,
   165 // we take no chances.) Also, by doing things this way, we avoid the need for
   166 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
   167 // transport thread.
   168 void
   169 InitializeSSLServerCertVerificationThreads()
   170 {
   171   gSSLVerificationTelemetryMutex = new Mutex("SSLVerificationTelemetryMutex");
   172   gSSLVerificationPK11Mutex = new Mutex("SSLVerificationPK11Mutex");
   173   // TODO: tuning, make parameters preferences
   174   // XXX: instantiate nsThreadPool directly, to make this more bulletproof.
   175   // Currently, the nsThreadPool.h header isn't exported for us to do so.
   176   nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID,
   177                                    &gCertVerificationThreadPool);
   178   if (NS_FAILED(rv)) {
   179     NS_WARNING("Failed to create SSL cert verification threads.");
   180     return;
   181   }
   183   (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
   184   (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
   185   (void) gCertVerificationThreadPool->SetThreadLimit(5);
   186   (void) gCertVerificationThreadPool->SetName(NS_LITERAL_CSTRING("SSL Cert"));
   187 }
   189 // Called when the socket transport thread finishes, to destroy the thread
   190 // pool. Since the socket transport service has stopped processing events, it
   191 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
   192 // down the SSL cert verification infrastructure. Also, the STS will not
   193 // dispatch many SSL verification result events at this point, so any pending
   194 // cert verifications will (correctly) fail at the point they are dispatched.
   195 //
   196 // The other shutdown race condition that is possible is a race condition with
   197 // shutdown of the nsNSSComponent service. We use the
   198 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
   199 void StopSSLServerCertVerificationThreads()
   200 {
   201   if (gCertVerificationThreadPool) {
   202     gCertVerificationThreadPool->Shutdown();
   203     NS_RELEASE(gCertVerificationThreadPool);
   204   }
   205   if (gSSLVerificationTelemetryMutex) {
   206     delete gSSLVerificationTelemetryMutex;
   207     gSSLVerificationTelemetryMutex = nullptr;
   208   }
   209   if (gSSLVerificationPK11Mutex) {
   210     delete gSSLVerificationPK11Mutex;
   211     gSSLVerificationPK11Mutex = nullptr;
   212   }
   213 }
   215 namespace {
   217 void
   218 LogInvalidCertError(TransportSecurityInfo* socketInfo,
   219                     PRErrorCode errorCode,
   220                     ::mozilla::psm::SSLErrorMessageType errorMessageType)
   221 {
   222   nsString message;
   223   socketInfo->GetErrorLogMessage(errorCode, errorMessageType, message);
   224   if (!message.IsEmpty()) {
   225     nsContentUtils::LogSimpleConsoleError(message, "SSL");
   226   }
   227 }
   229 // Dispatched to the STS thread to notify the infoObject of the verification
   230 // result.
   231 //
   232 // This will cause the PR_Poll in the STS thread to return, so things work
   233 // correctly even if the STS thread is blocked polling (only) on the file
   234 // descriptor that is waiting for this result.
   235 class SSLServerCertVerificationResult : public nsRunnable
   236 {
   237 public:
   238   NS_DECL_NSIRUNNABLE
   240   SSLServerCertVerificationResult(TransportSecurityInfo* infoObject,
   241                                   PRErrorCode errorCode,
   242                                   Telemetry::ID telemetryID = Telemetry::HistogramCount,
   243                                   uint32_t telemetryValue = -1,
   244                                   SSLErrorMessageType errorMessageType =
   245                                       PlainErrorMessage);
   247   void Dispatch();
   248 private:
   249   const RefPtr<TransportSecurityInfo> mInfoObject;
   250 public:
   251   const PRErrorCode mErrorCode;
   252   const SSLErrorMessageType mErrorMessageType;
   253   const Telemetry::ID mTelemetryID;
   254   const uint32_t mTelemetryValue;
   255 };
   257 class CertErrorRunnable : public SyncRunnableBase
   258 {
   259  public:
   260   CertErrorRunnable(const void* fdForLogging,
   261                     nsIX509Cert* cert,
   262                     TransportSecurityInfo* infoObject,
   263                     PRErrorCode defaultErrorCodeToReport,
   264                     uint32_t collectedErrors,
   265                     PRErrorCode errorCodeTrust,
   266                     PRErrorCode errorCodeMismatch,
   267                     PRErrorCode errorCodeExpired,
   268                     uint32_t providerFlags)
   269     : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
   270       mDefaultErrorCodeToReport(defaultErrorCodeToReport),
   271       mCollectedErrors(collectedErrors),
   272       mErrorCodeTrust(errorCodeTrust),
   273       mErrorCodeMismatch(errorCodeMismatch),
   274       mErrorCodeExpired(errorCodeExpired),
   275       mProviderFlags(providerFlags)
   276   {
   277   }
   279   virtual void RunOnTargetThread();
   280   RefPtr<SSLServerCertVerificationResult> mResult; // out
   281 private:
   282   SSLServerCertVerificationResult* CheckCertOverrides();
   284   const void* const mFdForLogging; // may become an invalid pointer; do not dereference
   285   const nsCOMPtr<nsIX509Cert> mCert;
   286   const RefPtr<TransportSecurityInfo> mInfoObject;
   287   const PRErrorCode mDefaultErrorCodeToReport;
   288   const uint32_t mCollectedErrors;
   289   const PRErrorCode mErrorCodeTrust;
   290   const PRErrorCode mErrorCodeMismatch;
   291   const PRErrorCode mErrorCodeExpired;
   292   const uint32_t mProviderFlags;
   293 };
   295 // A probe value of 1 means "no error".
   296 uint32_t
   297 MapCertErrorToProbeValue(PRErrorCode errorCode)
   298 {
   299   switch (errorCode)
   300   {
   301     case SEC_ERROR_UNKNOWN_ISSUER:                     return  2;
   302     case SEC_ERROR_CA_CERT_INVALID:                    return  3;
   303     case SEC_ERROR_UNTRUSTED_ISSUER:                   return  4;
   304     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:         return  5;
   305     case SEC_ERROR_UNTRUSTED_CERT:                     return  6;
   306     case SEC_ERROR_INADEQUATE_KEY_USAGE:               return  7;
   307     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:  return  8;
   308     case SSL_ERROR_BAD_CERT_DOMAIN:                    return  9;
   309     case SEC_ERROR_EXPIRED_CERTIFICATE:                return 10;
   310   }
   311   NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue "
   312              "handle everything in PRErrorCodeToOverrideType?");
   313   return 0;
   314 }
   316 SECStatus
   317 MozillaPKIXDetermineCertOverrideErrors(CERTCertificate* cert,
   318                                        const char* hostName, PRTime now,
   319                                        PRErrorCode defaultErrorCodeToReport,
   320                                        /*out*/ uint32_t& collectedErrors,
   321                                        /*out*/ PRErrorCode& errorCodeTrust,
   322                                        /*out*/ PRErrorCode& errorCodeMismatch,
   323                                        /*out*/ PRErrorCode& errorCodeExpired)
   324 {
   325   MOZ_ASSERT(cert);
   326   MOZ_ASSERT(hostName);
   327   MOZ_ASSERT(collectedErrors == 0);
   328   MOZ_ASSERT(errorCodeTrust == 0);
   329   MOZ_ASSERT(errorCodeMismatch == 0);
   330   MOZ_ASSERT(errorCodeExpired == 0);
   332   // Assumes the error prioritization described in mozilla::pkix's
   333   // BuildForward function. Also assumes that CERT_VerifyCertName was only
   334   // called if CertVerifier::VerifyCert succeeded.
   335   switch (defaultErrorCodeToReport) {
   336     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   337     case SEC_ERROR_CA_CERT_INVALID:
   338     case SEC_ERROR_UNKNOWN_ISSUER:
   339     {
   340       collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
   341       errorCodeTrust = defaultErrorCodeToReport;
   343       SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, now, false);
   344       if (validity == secCertTimeUndetermined) {
   345         PR_SetError(defaultErrorCodeToReport, 0);
   346         return SECFailure;
   347       }
   348       if (validity != secCertTimeValid) {
   349         collectedErrors |= nsICertOverrideService::ERROR_TIME;
   350         errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
   351       }
   352       break;
   353     }
   355     case SEC_ERROR_EXPIRED_CERTIFICATE:
   356       collectedErrors = nsICertOverrideService::ERROR_TIME;
   357       errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
   358       break;
   360     case SSL_ERROR_BAD_CERT_DOMAIN:
   361       collectedErrors = nsICertOverrideService::ERROR_MISMATCH;
   362       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   363       break;
   365     case 0:
   366       NS_ERROR("No error code set during certificate validation failure.");
   367       PR_SetError(PR_INVALID_STATE_ERROR, 0);
   368       return SECFailure;
   370     default:
   371       PR_SetError(defaultErrorCodeToReport, 0);
   372       return SECFailure;
   373   }
   375   if (defaultErrorCodeToReport != SSL_ERROR_BAD_CERT_DOMAIN) {
   376     if (CERT_VerifyCertName(cert, hostName) != SECSuccess) {
   377       if (PR_GetError() != SSL_ERROR_BAD_CERT_DOMAIN) {
   378         PR_SetError(defaultErrorCodeToReport, 0);
   379         return SECFailure;
   380       }
   382       collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
   383       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   384     }
   385   }
   387   return SECSuccess;
   388 }
   390 SSLServerCertVerificationResult*
   391 CertErrorRunnable::CheckCertOverrides()
   392 {
   393   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
   394                                     mFdForLogging, this));
   395   // "Use" mFdForLogging in non-PR_LOGGING builds, too, to suppress
   396   // clang's -Wunused-private-field build warning for this variable:
   397   unused << mFdForLogging;
   399   if (!NS_IsMainThread()) {
   400     NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
   401     return new SSLServerCertVerificationResult(mInfoObject,
   402                                                mDefaultErrorCodeToReport);
   403   }
   405   int32_t port;
   406   mInfoObject->GetPort(&port);
   408   nsCString hostWithPortString;
   409   hostWithPortString.AppendASCII(mInfoObject->GetHostNameRaw());
   410   hostWithPortString.AppendLiteral(":");
   411   hostWithPortString.AppendInt(port);
   413   uint32_t remaining_display_errors = mCollectedErrors;
   415   nsresult nsrv;
   417   // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
   418   // connections must be dropped when there are any certificate errors
   419   // (STS Spec section 7.3).
   420   bool strictTransportSecurityEnabled = false;
   421   nsCOMPtr<nsISiteSecurityService> sss
   422     = do_GetService(NS_SSSERVICE_CONTRACTID, &nsrv);
   423   if (NS_SUCCEEDED(nsrv)) {
   424     nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS,
   425                              mInfoObject->GetHostNameRaw(),
   426                              mProviderFlags,
   427                              &strictTransportSecurityEnabled);
   428   }
   429   if (NS_FAILED(nsrv)) {
   430     return new SSLServerCertVerificationResult(mInfoObject,
   431                                                mDefaultErrorCodeToReport);
   432   }
   434   if (!strictTransportSecurityEnabled) {
   435     nsCOMPtr<nsICertOverrideService> overrideService =
   436       do_GetService(NS_CERTOVERRIDE_CONTRACTID);
   437     // it is fine to continue without the nsICertOverrideService
   439     uint32_t overrideBits = 0;
   441     if (overrideService)
   442     {
   443       bool haveOverride;
   444       bool isTemporaryOverride; // we don't care
   445       nsCString hostString(mInfoObject->GetHostName());
   446       nsrv = overrideService->HasMatchingOverride(hostString, port,
   447                                                   mCert,
   448                                                   &overrideBits,
   449                                                   &isTemporaryOverride,
   450                                                   &haveOverride);
   451       if (NS_SUCCEEDED(nsrv) && haveOverride)
   452       {
   453        // remove the errors that are already overriden
   454         remaining_display_errors &= ~overrideBits;
   455       }
   456     }
   458     if (!remaining_display_errors) {
   459       // This can double- or triple-count one certificate with multiple
   460       // different types of errors. Since this is telemetry and we just
   461       // want a ballpark answer, we don't care.
   462       if (mErrorCodeTrust != 0) {
   463         uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeTrust);
   464         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
   465       }
   466       if (mErrorCodeMismatch != 0) {
   467         uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeMismatch);
   468         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
   469       }
   470       if (mErrorCodeExpired != 0) {
   471         uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeExpired);
   472         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
   473       }
   475       // all errors are covered by override rules, so let's accept the cert
   476       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   477              ("[%p][%p] All errors covered by override rules\n",
   478              mFdForLogging, this));
   479       return new SSLServerCertVerificationResult(mInfoObject, 0);
   480     }
   481   } else {
   482     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   483            ("[%p][%p] Strict-Transport-Security is violated: untrusted "
   484             "transport layer\n", mFdForLogging, this));
   485   }
   487   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   488          ("[%p][%p] Certificate error was not overridden\n",
   489          mFdForLogging, this));
   491   // Ok, this is a full stop.
   492   // First, deliver the technical details of the broken SSL status.
   494   // Try to get a nsIBadCertListener2 implementation from the socket consumer.
   495   nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
   496     NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
   497   if (sslSocketControl) {
   498     nsCOMPtr<nsIInterfaceRequestor> cb;
   499     sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
   500     if (cb) {
   501       nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
   502       if (bcl) {
   503         nsIInterfaceRequestor* csi
   504           = static_cast<nsIInterfaceRequestor*>(mInfoObject);
   505         bool suppressMessage = false; // obsolete, ignored
   506         nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
   507                                       hostWithPortString, &suppressMessage);
   508       }
   509     }
   510   }
   512   nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
   513   nsCOMPtr<nsIRecentBadCerts> recentBadCertsService;
   514   if (certdb) {
   515     bool isPrivate = mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
   516     certdb->GetRecentBadCerts(isPrivate, getter_AddRefs(recentBadCertsService));
   517   }
   519   if (recentBadCertsService) {
   520     NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
   521     recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
   522                                       mInfoObject->SSLStatus());
   523   }
   525   // pick the error code to report by priority
   526   PRErrorCode errorCodeToReport = mErrorCodeTrust    ? mErrorCodeTrust
   527                                 : mErrorCodeMismatch ? mErrorCodeMismatch
   528                                 : mErrorCodeExpired  ? mErrorCodeExpired
   529                                 : mDefaultErrorCodeToReport;
   531   SSLServerCertVerificationResult* result =
   532     new SSLServerCertVerificationResult(mInfoObject,
   533                                         errorCodeToReport,
   534                                         Telemetry::HistogramCount,
   535                                         -1,
   536                                         OverridableCertErrorMessage);
   538   LogInvalidCertError(mInfoObject,
   539                       result->mErrorCode,
   540                       result->mErrorMessageType);
   542   return result;
   543 }
   545 void
   546 CertErrorRunnable::RunOnTargetThread()
   547 {
   548   MOZ_ASSERT(NS_IsMainThread());
   550   mResult = CheckCertOverrides();
   552   MOZ_ASSERT(mResult);
   553 }
   555 // Converts a PRErrorCode into one of
   556 //   nsICertOverrideService::ERROR_UNTRUSTED,
   557 //   nsICertOverrideService::ERROR_MISMATCH,
   558 //   nsICertOverrideService::ERROR_TIME
   559 // if the given error code is an overridable error.
   560 // If it is not, then 0 is returned.
   561 uint32_t
   562 PRErrorCodeToOverrideType(PRErrorCode errorCode)
   563 {
   564   switch (errorCode)
   565   {
   566     case SEC_ERROR_UNKNOWN_ISSUER:
   567     case SEC_ERROR_UNTRUSTED_ISSUER:
   568     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
   569     case SEC_ERROR_UNTRUSTED_CERT:
   570     case SEC_ERROR_INADEQUATE_KEY_USAGE:
   571     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   572     case SEC_ERROR_CA_CERT_INVALID:
   573       // We group all these errors as "cert not trusted"
   574       return nsICertOverrideService::ERROR_UNTRUSTED;
   575     case SSL_ERROR_BAD_CERT_DOMAIN:
   576       return nsICertOverrideService::ERROR_MISMATCH;
   577     case SEC_ERROR_EXPIRED_CERTIFICATE:
   578       return nsICertOverrideService::ERROR_TIME;
   579     default:
   580       return 0;
   581   }
   582 }
   584 SECStatus
   585 NSSDetermineCertOverrideErrors(CertVerifier& certVerifier,
   586                                CERTCertificate* cert,
   587                                const SECItem* stapledOCSPResponse,
   588                                TransportSecurityInfo* infoObject,
   589                                PRTime now,
   590                                PRErrorCode defaultErrorCodeToReport,
   591                                /*out*/ uint32_t& collectedErrors,
   592                                /*out*/ PRErrorCode& errorCodeTrust,
   593                                /*out*/ PRErrorCode& errorCodeMismatch,
   594                                /*out*/ PRErrorCode& errorCodeExpired)
   595 {
   596   MOZ_ASSERT(cert);
   597   MOZ_ASSERT(infoObject);
   598   MOZ_ASSERT(defaultErrorCodeToReport != 0);
   599   MOZ_ASSERT(collectedErrors == 0);
   600   MOZ_ASSERT(errorCodeTrust == 0);
   601   MOZ_ASSERT(errorCodeMismatch == 0);
   602   MOZ_ASSERT(errorCodeExpired == 0);
   604   if (defaultErrorCodeToReport == 0) {
   605     NS_ERROR("No error code set during certificate validation failure.");
   606     PR_SetError(PR_INVALID_STATE_ERROR, 0);
   607     return SECFailure;
   608   }
   610   // We only allow overrides for certain errors. Return early if the error
   611   // is not one of them. This is to avoid doing revocation fetching in the
   612   // case of OCSP stapling and probably for other reasons.
   613   if (PRErrorCodeToOverrideType(defaultErrorCodeToReport) == 0) {
   614     PR_SetError(defaultErrorCodeToReport, 0);
   615     return SECFailure;
   616   }
   618   PLArenaPool* log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   619   PLArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
   620   if (!log_arena) {
   621     NS_ERROR("PORT_NewArena failed");
   622     return SECFailure; // PORT_NewArena set error code
   623   }
   625   CERTVerifyLog* verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
   626   if (!verify_log) {
   627     NS_ERROR("PORT_ArenaZNew failed");
   628     return SECFailure; // PORT_ArenaZNew set error code
   629   }
   630   CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
   631   verify_log->arena = log_arena;
   633   // We ignore the result code of the cert verification (i.e. VerifyCert's rv)
   634   // Either it is a failure, which is expected, and we'll process the
   635   //                         verify log below.
   636   // Or it is a success, then a domain mismatch is the only
   637   //                     possible failure.
   638   // XXX TODO: convert to VerifySSLServerCert
   639   // XXX TODO: get rid of error log
   640   certVerifier.VerifyCert(cert, certificateUsageSSLServer,
   641                           now, infoObject, infoObject->GetHostNameRaw(),
   642                           0, stapledOCSPResponse, nullptr, nullptr, verify_log);
   644   // Check the name field against the desired hostname.
   645   if (CERT_VerifyCertName(cert, infoObject->GetHostNameRaw()) != SECSuccess) {
   646     collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
   647     errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   648   }
   650   CERTVerifyLogNode* i_node;
   651   for (i_node = verify_log->head; i_node; i_node = i_node->next) {
   652     uint32_t overrideType = PRErrorCodeToOverrideType(i_node->error);
   653     // If this isn't an overridable error, set the error and return.
   654     if (overrideType == 0) {
   655       PR_SetError(i_node->error, 0);
   656       return SECFailure;
   657     }
   658     collectedErrors |= overrideType;
   659     if (overrideType == nsICertOverrideService::ERROR_UNTRUSTED) {
   660       if (errorCodeTrust == 0) {
   661         errorCodeTrust = i_node->error;
   662       }
   663     } else if (overrideType == nsICertOverrideService::ERROR_MISMATCH) {
   664       if (errorCodeMismatch == 0) {
   665         errorCodeMismatch = i_node->error;
   666       }
   667     } else if (overrideType == nsICertOverrideService::ERROR_TIME) {
   668       if (errorCodeExpired == 0) {
   669         errorCodeExpired = i_node->error;
   670       }
   671     } else {
   672       MOZ_CRASH("unexpected return value from PRErrorCodeToOverrideType");
   673     }
   674   }
   676   return SECSuccess;
   677 }
   679 // Returns null with the error code (PR_GetError()) set if it does not create
   680 // the CertErrorRunnable.
   681 CertErrorRunnable*
   682 CreateCertErrorRunnable(CertVerifier& certVerifier,
   683                         PRErrorCode defaultErrorCodeToReport,
   684                         TransportSecurityInfo* infoObject,
   685                         CERTCertificate* cert,
   686                         const SECItem* stapledOCSPResponse,
   687                         const void* fdForLogging,
   688                         uint32_t providerFlags,
   689                         PRTime now)
   690 {
   691   MOZ_ASSERT(infoObject);
   692   MOZ_ASSERT(cert);
   694   uint32_t collected_errors = 0;
   695   PRErrorCode errorCodeTrust = 0;
   696   PRErrorCode errorCodeMismatch = 0;
   697   PRErrorCode errorCodeExpired = 0;
   699   SECStatus rv;
   700   switch (certVerifier.mImplementation) {
   701     case CertVerifier::classic:
   702 #ifndef NSS_NO_LIBPKIX
   703     case CertVerifier::libpkix:
   704 #endif
   705       rv = NSSDetermineCertOverrideErrors(certVerifier, cert, stapledOCSPResponse,
   706                                           infoObject, now,
   707                                           defaultErrorCodeToReport,
   708                                           collected_errors, errorCodeTrust,
   709                                           errorCodeMismatch, errorCodeExpired);
   710       break;
   712     case CertVerifier::mozillapkix:
   713       rv = MozillaPKIXDetermineCertOverrideErrors(cert,
   714                                                   infoObject->GetHostNameRaw(),
   715                                                   now, defaultErrorCodeToReport,
   716                                                   collected_errors,
   717                                                   errorCodeTrust,
   718                                                   errorCodeMismatch,
   719                                                   errorCodeExpired);
   720       break;
   722     default:
   723       MOZ_CRASH("unexpected CertVerifier implementation");
   724       PR_SetError(defaultErrorCodeToReport, 0);
   725       return nullptr;
   727   }
   728   if (rv != SECSuccess) {
   729     return nullptr;
   730   }
   732   RefPtr<nsNSSCertificate> nssCert(nsNSSCertificate::Create(cert));
   733   if (!nssCert) {
   734     NS_ERROR("nsNSSCertificate::Create failed");
   735     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
   736     return nullptr;
   737   }
   739   if (!collected_errors) {
   740     // This will happen when CERT_*Verify* only returned error(s) that are
   741     // not on our whitelist of overridable certificate errors.
   742     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
   743            fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
   744     PR_SetError(defaultErrorCodeToReport, 0);
   745     return nullptr;
   746   }
   748   infoObject->SetStatusErrorBits(*nssCert, collected_errors);
   750   return new CertErrorRunnable(fdForLogging,
   751                                static_cast<nsIX509Cert*>(nssCert.get()),
   752                                infoObject, defaultErrorCodeToReport,
   753                                collected_errors, errorCodeTrust,
   754                                errorCodeMismatch, errorCodeExpired,
   755                                providerFlags);
   756 }
   758 // When doing async cert processing, we dispatch one of these runnables to the
   759 // socket transport service thread, which blocks the socket transport
   760 // service thread while it waits for the inner CertErrorRunnable to execute
   761 // CheckCertOverrides on the main thread. CheckCertOverrides must block events
   762 // on both of these threads because it calls TransportSecurityInfo::GetInterface(),
   763 // which may call nsHttpConnection::GetInterface() through
   764 // TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always
   765 // execute on the main thread, with the socket transport service thread
   766 // blocked.
   767 class CertErrorRunnableRunnable : public nsRunnable
   768 {
   769 public:
   770   CertErrorRunnableRunnable(CertErrorRunnable* certErrorRunnable)
   771     : mCertErrorRunnable(certErrorRunnable)
   772   {
   773   }
   774 private:
   775   NS_IMETHOD Run()
   776   {
   777     nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
   778     // The result must run on the socket transport thread, which we are already
   779     // on, so we can just run it directly, instead of dispatching it.
   780     if (NS_SUCCEEDED(rv)) {
   781       rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
   782                                        : NS_ERROR_UNEXPECTED;
   783     }
   784     return rv;
   785   }
   786   RefPtr<CertErrorRunnable> mCertErrorRunnable;
   787 };
   789 class SSLServerCertVerificationJob : public nsRunnable
   790 {
   791 public:
   792   // Must be called only on the socket transport thread
   793   static SECStatus Dispatch(const RefPtr<SharedCertVerifier>& certVerifier,
   794                             const void* fdForLogging,
   795                             TransportSecurityInfo* infoObject,
   796                             CERTCertificate* serverCert,
   797                             SECItem* stapledOCSPResponse,
   798                             uint32_t providerFlags,
   799                             PRTime time);
   800 private:
   801   NS_DECL_NSIRUNNABLE
   803   // Must be called only on the socket transport thread
   804   SSLServerCertVerificationJob(const RefPtr<SharedCertVerifier>& certVerifier,
   805                                const void* fdForLogging,
   806                                TransportSecurityInfo* infoObject,
   807                                CERTCertificate* cert,
   808                                SECItem* stapledOCSPResponse,
   809                                uint32_t providerFlags,
   810                                PRTime time);
   811   const RefPtr<SharedCertVerifier> mCertVerifier;
   812   const void* const mFdForLogging;
   813   const RefPtr<TransportSecurityInfo> mInfoObject;
   814   const mozilla::pkix::ScopedCERTCertificate mCert;
   815   const uint32_t mProviderFlags;
   816   const PRTime mTime;
   817   const TimeStamp mJobStartTime;
   818   const ScopedSECItem mStapledOCSPResponse;
   819 };
   821 SSLServerCertVerificationJob::SSLServerCertVerificationJob(
   822     const RefPtr<SharedCertVerifier>& certVerifier, const void* fdForLogging,
   823     TransportSecurityInfo* infoObject, CERTCertificate* cert,
   824     SECItem* stapledOCSPResponse, uint32_t providerFlags, PRTime time)
   825   : mCertVerifier(certVerifier)
   826   , mFdForLogging(fdForLogging)
   827   , mInfoObject(infoObject)
   828   , mCert(CERT_DupCertificate(cert))
   829   , mProviderFlags(providerFlags)
   830   , mTime(time)
   831   , mJobStartTime(TimeStamp::Now())
   832   , mStapledOCSPResponse(SECITEM_DupItem(stapledOCSPResponse))
   833 {
   834 }
   836 // This function assumes that we will only use the SPDY connection coalescing
   837 // feature on connections where we have negotiated SPDY using NPN. If we ever
   838 // talk SPDY without having negotiated it with SPDY, this code will give wrong
   839 // and perhaps unsafe results.
   840 //
   841 // Returns SECSuccess on the initial handshake of all connections, on
   842 // renegotiations for any connections where we did not negotiate SPDY, or on any
   843 // SPDY connection where the server's certificate did not change.
   844 //
   845 // Prohibit changing the server cert only if we negotiated SPDY,
   846 // in order to support SPDY's cross-origin connection pooling.
   847 static SECStatus
   848 BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
   849                              CERTCertificate* serverCert)
   850 {
   851   // Get the existing cert. If there isn't one, then there is
   852   // no cert change to worry about.
   853   nsCOMPtr<nsIX509Cert> cert;
   854   nsCOMPtr<nsIX509Cert2> cert2;
   856   RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
   857   if (!status) {
   858     // If we didn't have a status, then this is the
   859     // first handshake on this connection, not a
   860     // renegotiation.
   861     return SECSuccess;
   862   }
   864   status->GetServerCert(getter_AddRefs(cert));
   865   cert2 = do_QueryInterface(cert);
   866   if (!cert2) {
   867     NS_NOTREACHED("every nsSSLStatus must have a cert"
   868                   "that implements nsIX509Cert2");
   869     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
   870     return SECFailure;
   871   }
   873   // Filter out sockets that did not neogtiate SPDY via NPN
   874   nsAutoCString negotiatedNPN;
   875   nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
   876   NS_ASSERTION(NS_SUCCEEDED(rv),
   877                "GetNegotiatedNPN() failed during renegotiation");
   879   if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
   880                                             NS_LITERAL_CSTRING("spdy/")))
   881     return SECSuccess;
   883   // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
   884   if (NS_FAILED(rv)) {
   885     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   886            ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
   887             " Assuming spdy.\n"));
   888   }
   890   // Check to see if the cert has actually changed
   891   ScopedCERTCertificate c(cert2->GetCert());
   892   NS_ASSERTION(c, "very bad and hopefully impossible state");
   893   bool sameCert = CERT_CompareCerts(c, serverCert);
   894   if (sameCert)
   895     return SECSuccess;
   897   // Report an error - changed cert is confirmed
   898   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   899          ("SPDY Refused to allow new cert during renegotiation\n"));
   900   PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
   901   return SECFailure;
   902 }
   904 SECStatus
   905 AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject,
   906                 CERTCertificate* cert, SECItem* stapledOCSPResponse,
   907                 uint32_t providerFlags, PRTime time)
   908 {
   909   MOZ_ASSERT(infoObject);
   910   MOZ_ASSERT(cert);
   912   SECStatus rv;
   914   // TODO: Remove this after we switch to mozilla::pkix as the
   915   // only option
   916   if (certVerifier.mImplementation == CertVerifier::classic) {
   917     if (stapledOCSPResponse) {
   918       CERTCertDBHandle* handle = CERT_GetDefaultCertDB();
   919       rv = CERT_CacheOCSPResponseFromSideChannel(handle, cert, PR_Now(),
   920                                                  stapledOCSPResponse,
   921                                                  infoObject);
   922       if (rv != SECSuccess) {
   923         // Due to buggy servers that will staple expired OCSP responses
   924         // (see for example http://trac.nginx.org/nginx/ticket/425),
   925         // don't terminate the connection if the stapled response is expired.
   926         // We will fall back to fetching revocation information.
   927         PRErrorCode ocspErrorCode = PR_GetError();
   928         if (ocspErrorCode != SEC_ERROR_OCSP_OLD_RESPONSE) {
   929           // stapled OCSP response present but invalid for some reason
   930           Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 4);
   931           return rv;
   932         } else {
   933           // stapled OCSP response present but expired
   934           Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 3);
   935         }
   936       } else {
   937         // stapled OCSP response present and good
   938         Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 1);
   939       }
   940     } else {
   941       // no stapled OCSP response
   942       Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 2);
   944       uint32_t reasonsForNotFetching = 0;
   946       char* ocspURI = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
   947       if (!ocspURI) {
   948         reasonsForNotFetching |= 1; // invalid/missing OCSP URI
   949       } else {
   950         if (std::strncmp(ocspURI, "http://", 7)) { // approximation
   951           reasonsForNotFetching |= 1; // invalid/missing OCSP URI
   952         }
   953         PORT_Free(ocspURI);
   954       }
   956       if (!certVerifier.mOCSPDownloadEnabled) {
   957         reasonsForNotFetching |= 2;
   958       }
   960       Telemetry::Accumulate(Telemetry::SSL_OCSP_MAY_FETCH,
   961                             reasonsForNotFetching);
   962     }
   963   }
   965   // We want to avoid storing any intermediate cert information when browsing
   966   // in private, transient contexts.
   967   bool saveIntermediates =
   968     !(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE);
   970   mozilla::pkix::ScopedCERTCertList certList;
   971   SECOidTag evOidPolicy;
   972   rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
   973                                         time, infoObject,
   974                                         infoObject->GetHostNameRaw(),
   975                                         saveIntermediates, nullptr,
   976                                         &evOidPolicy);
   978   // We want to remember the CA certs in the temp db, so that the application can find the
   979   // complete chain at any time it might need it.
   980   // But we keep only those CA certs in the temp db, that we didn't already know.
   982   RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
   983   RefPtr<nsNSSCertificate> nsc;
   985   if (!status || !status->mServerCert) {
   986     if( rv == SECSuccess ){
   987       nsc = nsNSSCertificate::Create(cert, &evOidPolicy);
   988     }
   989     else {
   990       nsc = nsNSSCertificate::Create(cert);
   991     }
   992   }
   994   if (rv == SECSuccess) {
   995     // The connection may get terminated, for example, if the server requires
   996     // a client cert. Let's provide a minimal SSLStatus
   997     // to the caller that contains at least the cert and its status.
   998     if (!status) {
   999       status = new nsSSLStatus();
  1000       infoObject->SetSSLStatus(status);
  1003     if (rv == SECSuccess) {
  1004       // Certificate verification succeeded delete any potential record
  1005       // of certificate error bits.
  1006       RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject,
  1007                                                                   nullptr, rv);
  1009     else {
  1010       // Certificate verification failed, update the status' bits.
  1011       RememberCertErrorsTable::GetInstance().LookupCertErrorBits(
  1012         infoObject, status);
  1015     if (status && !status->mServerCert) {
  1016       status->mServerCert = nsc;
  1017       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1018              ("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
  1022   return rv;
  1025 /*static*/ SECStatus
  1026 SSLServerCertVerificationJob::Dispatch(
  1027   const RefPtr<SharedCertVerifier>& certVerifier,
  1028   const void* fdForLogging,
  1029   TransportSecurityInfo* infoObject,
  1030   CERTCertificate* serverCert,
  1031   SECItem* stapledOCSPResponse,
  1032   uint32_t providerFlags,
  1033   PRTime time)
  1035   // Runs on the socket transport thread
  1036   if (!certVerifier || !infoObject || !serverCert) {
  1037     NS_ERROR("Invalid parameters for SSL server cert validation");
  1038     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1039     return SECFailure;
  1042   RefPtr<SSLServerCertVerificationJob> job(
  1043     new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject,
  1044                                      serverCert, stapledOCSPResponse,
  1045                                      providerFlags, time));
  1047   nsresult nrv;
  1048   if (!gCertVerificationThreadPool) {
  1049     nrv = NS_ERROR_NOT_INITIALIZED;
  1050   } else {
  1051     nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
  1053   if (NS_FAILED(nrv)) {
  1054     // We can't call SetCertVerificationResult here to change
  1055     // mCertVerificationState because SetCertVerificationResult will call
  1056     // libssl functions that acquire SSL locks that are already being held at
  1057     // this point. infoObject->mCertVerificationState will be stuck at
  1058     // waiting_for_cert_verification here, but that is OK because we already
  1059     // have to be able to handle cases where we encounter non-cert errors while
  1060     // in that state.
  1061     PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
  1062                       ? SEC_ERROR_NO_MEMORY
  1063                       : PR_INVALID_STATE_ERROR;
  1064     PORT_SetError(error);
  1065     return SECFailure;
  1068   PORT_SetError(PR_WOULD_BLOCK_ERROR);
  1069   return SECWouldBlock;
  1072 NS_IMETHODIMP
  1073 SSLServerCertVerificationJob::Run()
  1075   // Runs on a cert verification thread
  1077   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1078           ("[%p] SSLServerCertVerificationJob::Run\n", mInfoObject.get()));
  1080   PRErrorCode error;
  1082   nsNSSShutDownPreventionLock nssShutdownPrevention;
  1083   if (mInfoObject->isAlreadyShutDown()) {
  1084     error = SEC_ERROR_USER_CANCELLED;
  1085   } else {
  1086     Telemetry::ID successTelemetry;
  1087     Telemetry::ID failureTelemetry;
  1088     switch (mCertVerifier->mImplementation) {
  1089       case CertVerifier::classic:
  1090         successTelemetry
  1091           = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_CLASSIC;
  1092         failureTelemetry
  1093           = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_CLASSIC;
  1094         break;
  1095       case CertVerifier::mozillapkix:
  1096         successTelemetry
  1097           = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX;
  1098         failureTelemetry
  1099           = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX;
  1100         break;
  1101 #ifndef NSS_NO_LIBPKIX
  1102       case CertVerifier::libpkix:
  1103         successTelemetry
  1104           = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_LIBPKIX;
  1105         failureTelemetry
  1106           = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_LIBPKIX;
  1107         break;
  1108 #endif
  1109       default:
  1110         MOZ_CRASH("Unknown CertVerifier mode");
  1113     // XXX
  1114     // Reset the error code here so we can detect if AuthCertificate fails to
  1115     // set the error code if/when it fails.
  1116     PR_SetError(0, 0);
  1117     SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert.get(),
  1118                                    mStapledOCSPResponse, mProviderFlags,
  1119                                    mTime);
  1120     if (rv == SECSuccess) {
  1121       uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds());
  1122       RefPtr<SSLServerCertVerificationResult> restart(
  1123         new SSLServerCertVerificationResult(mInfoObject, 0,
  1124                                             successTelemetry, interval));
  1125       restart->Dispatch();
  1126       Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
  1127       return NS_OK;
  1130     // Note: the interval is not calculated once as PR_GetError MUST be called
  1131     // before any other  function call
  1132     error = PR_GetError();
  1134       TimeStamp now = TimeStamp::Now();
  1135       MutexAutoLock telemetryMutex(*gSSLVerificationTelemetryMutex);
  1136       Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now);
  1138     if (error != 0) {
  1139       RefPtr<CertErrorRunnable> runnable(
  1140           CreateCertErrorRunnable(*mCertVerifier, error, mInfoObject,
  1141                                   mCert.get(), mStapledOCSPResponse,
  1142                                   mFdForLogging, mProviderFlags, mTime));
  1143       if (!runnable) {
  1144         // CreateCertErrorRunnable set a new error code
  1145         error = PR_GetError();
  1146       } else {
  1147         // We must block the the socket transport service thread while the
  1148         // main thread executes the CertErrorRunnable. The CertErrorRunnable
  1149         // will dispatch the result asynchronously, so we don't have to block
  1150         // this thread waiting for it.
  1152         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1153                 ("[%p][%p] Before dispatching CertErrorRunnable\n",
  1154                 mFdForLogging, runnable.get()));
  1156         nsresult nrv;
  1157         nsCOMPtr<nsIEventTarget> stsTarget
  1158           = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
  1159         if (NS_SUCCEEDED(nrv)) {
  1160           nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
  1161                                     NS_DISPATCH_NORMAL);
  1163         if (NS_SUCCEEDED(nrv)) {
  1164           return NS_OK;
  1167         NS_ERROR("Failed to dispatch CertErrorRunnable");
  1168         error = PR_INVALID_STATE_ERROR;
  1173   if (error == 0) {
  1174     NS_NOTREACHED("no error set during certificate validation failure");
  1175     error = PR_INVALID_STATE_ERROR;
  1178   RefPtr<SSLServerCertVerificationResult> failure(
  1179     new SSLServerCertVerificationResult(mInfoObject, error));
  1180   failure->Dispatch();
  1181   return NS_OK;
  1184 } // unnamed namespace
  1186 // Extracts whatever information we need out of fd (using SSL_*) and passes it
  1187 // to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
  1188 // never do anything with fd except logging.
  1189 SECStatus
  1190 AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
  1192   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  1193   if (!certVerifier) {
  1194     PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
  1195     return SECFailure;
  1198   // Runs on the socket transport thread
  1200   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1201          ("[%p] starting AuthCertificateHook\n", fd));
  1203   // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
  1204   // doing verification without checking signatures.
  1205   NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
  1207   // PSM never causes libssl to call this function with PR_TRUE for isServer,
  1208   // and many things in PSM assume that we are a client.
  1209   NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
  1211   nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg);
  1213   ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
  1215   if (!checkSig || isServer || !socketInfo || !serverCert) {
  1216       PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1217       return SECFailure;
  1220   socketInfo->SetFullHandshake();
  1222   // This value of "now" is used both here for OCSP stapling and later
  1223   // when calling CreateCertErrorRunnable.
  1224   PRTime now = PR_Now();
  1226   if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
  1227     return SECFailure;
  1229   bool onSTSThread;
  1230   nsresult nrv;
  1231   nsCOMPtr<nsIEventTarget> sts
  1232     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
  1233   if (NS_SUCCEEDED(nrv)) {
  1234     nrv = sts->IsOnCurrentThread(&onSTSThread);
  1237   if (NS_FAILED(nrv)) {
  1238     NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
  1239     PR_SetError(PR_UNKNOWN_ERROR, 0);
  1240     return SECFailure;
  1243   // SSL_PeerStapledOCSPResponses will never return a non-empty response if
  1244   // OCSP stapling wasn't enabled because libssl wouldn't have let the server
  1245   // return a stapled OCSP response.
  1246   // We don't own these pointers.
  1247   const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
  1248   SECItem* stapledOCSPResponse = nullptr;
  1249   // we currently only support single stapled responses
  1250   if (csa && csa->len == 1) {
  1251     stapledOCSPResponse = &csa->items[0];
  1254   uint32_t providerFlags = 0;
  1255   socketInfo->GetProviderFlags(&providerFlags);
  1257   if (onSTSThread) {
  1259     // We *must* do certificate verification on a background thread because
  1260     // we need the socket transport thread to be free for our OCSP requests,
  1261     // and we *want* to do certificate verification on a background thread
  1262     // because of the performance benefits of doing so.
  1263     socketInfo->SetCertVerificationWaiting();
  1264     SECStatus rv = SSLServerCertVerificationJob::Dispatch(
  1265                      certVerifier, static_cast<const void*>(fd), socketInfo,
  1266                      serverCert, stapledOCSPResponse, providerFlags, now);
  1267     return rv;
  1270   // We can't do certificate verification on a background thread, because the
  1271   // thread doing the network I/O may not interrupt its network I/O on receipt
  1272   // of our SSLServerCertVerificationResult event, and/or it might not even be
  1273   // a non-blocking socket.
  1275   SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert,
  1276                                  stapledOCSPResponse, providerFlags, now);
  1277   if (rv == SECSuccess) {
  1278     Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
  1279     return SECSuccess;
  1282   PRErrorCode error = PR_GetError();
  1283   if (error != 0) {
  1284     RefPtr<CertErrorRunnable> runnable(
  1285         CreateCertErrorRunnable(*certVerifier, error, socketInfo, serverCert,
  1286                                 stapledOCSPResponse,
  1287                                 static_cast<const void*>(fd), providerFlags,
  1288                                 now));
  1289     if (!runnable) {
  1290       // CreateCertErrorRunnable sets a new error code when it fails
  1291       error = PR_GetError();
  1292     } else {
  1293       // We have to return SECSuccess or SECFailure based on the result of the
  1294       // override processing, so we must block this thread waiting for it. The
  1295       // CertErrorRunnable will NOT dispatch the result at all, since we passed
  1296       // false for CreateCertErrorRunnable's async parameter
  1297       nrv = runnable->DispatchToMainThreadAndWait();
  1298       if (NS_FAILED(nrv)) {
  1299         NS_ERROR("Failed to dispatch CertErrorRunnable");
  1300         PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1301         return SECFailure;
  1304       if (!runnable->mResult) {
  1305         NS_ERROR("CertErrorRunnable did not set result");
  1306         PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1307         return SECFailure;
  1310       if (runnable->mResult->mErrorCode == 0) {
  1311         return SECSuccess; // cert error override occurred.
  1314       // We must call SetCanceled here to set the error message type
  1315       // in case it isn't PlainErrorMessage, which is what we would
  1316       // default to if we just called
  1317       // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
  1318       // SECFailure without doing this.
  1319       socketInfo->SetCanceled(runnable->mResult->mErrorCode,
  1320                               runnable->mResult->mErrorMessageType);
  1321       error = runnable->mResult->mErrorCode;
  1325   if (error == 0) {
  1326     NS_ERROR("error code not set");
  1327     error = PR_UNKNOWN_ERROR;
  1330   PR_SetError(error, 0);
  1331   return SECFailure;
  1334 #ifndef MOZ_NO_EV_CERTS
  1335 class InitializeIdentityInfo : public CryptoTask
  1337   virtual nsresult CalculateResult() MOZ_OVERRIDE
  1339     EnsureIdentityInfoLoaded();
  1340     return NS_OK;
  1343   virtual void ReleaseNSSResources() MOZ_OVERRIDE { } // no-op
  1344   virtual void CallCallback(nsresult rv) MOZ_OVERRIDE { } // no-op
  1345 };
  1346 #endif
  1348 void EnsureServerVerificationInitialized()
  1350 #ifndef MOZ_NO_EV_CERTS
  1351   // Should only be called from socket transport thread due to the static
  1352   // variable and the reference to gCertVerificationThreadPool
  1354   static bool triggeredCertVerifierInit = false;
  1355   if (triggeredCertVerifierInit)
  1356     return;
  1357   triggeredCertVerifierInit = true;
  1359   RefPtr<InitializeIdentityInfo> initJob = new InitializeIdentityInfo();
  1360   if (gCertVerificationThreadPool)
  1361     gCertVerificationThreadPool->Dispatch(initJob, NS_DISPATCH_NORMAL);
  1362 #endif
  1365 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
  1366         TransportSecurityInfo* infoObject, PRErrorCode errorCode,
  1367         Telemetry::ID telemetryID, uint32_t telemetryValue,
  1368         SSLErrorMessageType errorMessageType)
  1369   : mInfoObject(infoObject)
  1370   , mErrorCode(errorCode)
  1371   , mErrorMessageType(errorMessageType)
  1372   , mTelemetryID(telemetryID)
  1373   , mTelemetryValue(telemetryValue)
  1375 // We accumulate telemetry for (only) successful validations on the main thread
  1376 // to avoid adversely affecting performance by acquiring the mutex that we use
  1377 // when accumulating the telemetry for unsuccessful validations. Unsuccessful
  1378 // validations times are accumulated elsewhere.
  1379 MOZ_ASSERT(telemetryID == Telemetry::HistogramCount || errorCode == 0);
  1382 void
  1383 SSLServerCertVerificationResult::Dispatch()
  1385   nsresult rv;
  1386   nsCOMPtr<nsIEventTarget> stsTarget
  1387     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  1388   NS_ASSERTION(stsTarget,
  1389                "Failed to get socket transport service event target");
  1390   rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
  1391   NS_ASSERTION(NS_SUCCEEDED(rv),
  1392                "Failed to dispatch SSLServerCertVerificationResult");
  1395 NS_IMETHODIMP
  1396 SSLServerCertVerificationResult::Run()
  1398   // TODO: Assert that we're on the socket transport thread
  1399   if (mTelemetryID != Telemetry::HistogramCount) {
  1400      Telemetry::Accumulate(mTelemetryID, mTelemetryValue);
  1402   // XXX: This cast will be removed by the next patch
  1403   ((nsNSSSocketInfo*) mInfoObject.get())
  1404     ->SetCertVerificationResult(mErrorCode, mErrorMessageType);
  1405   return NS_OK;
  1408 } } // namespace mozilla::psm

mercurial