LCOV - code coverage report
Current view: top level - security/manager/ssl - SSLServerCertVerification.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 7 732 1.0 %
Date: 2017-07-14 16:53:18 Functions: 1 39 2.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : // 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 immediately returns 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.
      94             : 
      95             : #include "SSLServerCertVerification.h"
      96             : 
      97             : #include <cstring>
      98             : 
      99             : #include "BRNameMatchingPolicy.h"
     100             : #include "CertVerifier.h"
     101             : #include "CryptoTask.h"
     102             : #include "ExtendedValidation.h"
     103             : #include "NSSCertDBTrustDomain.h"
     104             : #include "PSMRunnable.h"
     105             : #include "RootCertificateTelemetryUtils.h"
     106             : #include "ScopedNSSTypes.h"
     107             : #include "SharedCertVerifier.h"
     108             : #include "SharedSSLState.h"
     109             : #include "TransportSecurityInfo.h" // For RememberCertErrorsTable
     110             : #include "cert.h"
     111             : #include "mozilla/Assertions.h"
     112             : #include "mozilla/Casting.h"
     113             : #include "mozilla/RefPtr.h"
     114             : #include "mozilla/Telemetry.h"
     115             : #include "mozilla/UniquePtr.h"
     116             : #include "mozilla/Unused.h"
     117             : #include "mozilla/net/DNS.h"
     118             : #include "nsComponentManagerUtils.h"
     119             : #include "nsContentUtils.h"
     120             : #include "nsIBadCertListener2.h"
     121             : #include "nsICertOverrideService.h"
     122             : #include "nsISiteSecurityService.h"
     123             : #include "nsISocketProvider.h"
     124             : #include "nsIThreadPool.h"
     125             : #include "nsNSSCertificate.h"
     126             : #include "nsNSSComponent.h"
     127             : #include "nsNSSIOLayer.h"
     128             : #include "nsNSSShutDown.h"
     129             : #include "nsSSLStatus.h"
     130             : #include "nsServiceManagerUtils.h"
     131             : #include "nsString.h"
     132             : #include "nsURLHelper.h"
     133             : #include "nsXPCOMCIDInternal.h"
     134             : #include "pkix/pkix.h"
     135             : #include "pkix/pkixnss.h"
     136             : #include "secerr.h"
     137             : #include "secoidt.h"
     138             : #include "secport.h"
     139             : #include "ssl.h"
     140             : #include "sslerr.h"
     141             : 
     142             : extern mozilla::LazyLogModule gPIPNSSLog;
     143             : 
     144             : using namespace mozilla::pkix;
     145             : 
     146             : namespace mozilla { namespace psm {
     147             : 
     148             : namespace {
     149             : 
     150             : // do not use a nsCOMPtr to avoid static initializer/destructor
     151             : nsIThreadPool* gCertVerificationThreadPool = nullptr;
     152             : 
     153             : } // unnamed namespace
     154             : 
     155             : // Called when the socket transport thread starts, to initialize the SSL cert
     156             : // verification thread pool. By tying the thread pool startup/shutdown directly
     157             : // to the STS thread's lifetime, we ensure that they are *always* available for
     158             : // SSL connections and that there are no races during startup and especially
     159             : // shutdown. (Previously, we have had multiple problems with races in PSM
     160             : // background threads, and the race-prevention/shutdown logic used there is
     161             : // brittle. Since this service is critical to things like downloading updates,
     162             : // we take no chances.) Also, by doing things this way, we avoid the need for
     163             : // locks, since gCertVerificationThreadPool is only ever accessed on the socket
     164             : // transport thread.
     165             : void
     166           3 : InitializeSSLServerCertVerificationThreads()
     167             : {
     168             :   // TODO: tuning, make parameters preferences
     169             :   // XXX: instantiate nsThreadPool directly, to make this more bulletproof.
     170             :   // Currently, the nsThreadPool.h header isn't exported for us to do so.
     171             :   nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID,
     172           3 :                                    &gCertVerificationThreadPool);
     173           3 :   if (NS_FAILED(rv)) {
     174           0 :     NS_WARNING("Failed to create SSL cert verification threads.");
     175           0 :     return;
     176             :   }
     177             : 
     178           3 :   (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
     179           3 :   (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
     180           3 :   (void) gCertVerificationThreadPool->SetThreadLimit(5);
     181           3 :   (void) gCertVerificationThreadPool->SetName(NS_LITERAL_CSTRING("SSL Cert"));
     182             : }
     183             : 
     184             : // Called when the socket transport thread finishes, to destroy the thread
     185             : // pool. Since the socket transport service has stopped processing events, it
     186             : // will not attempt any more SSL I/O operations, so it is clearly safe to shut
     187             : // down the SSL cert verification infrastructure. Also, the STS will not
     188             : // dispatch many SSL verification result events at this point, so any pending
     189             : // cert verifications will (correctly) fail at the point they are dispatched.
     190             : //
     191             : // The other shutdown race condition that is possible is a race condition with
     192             : // shutdown of the nsNSSComponent service. We use the
     193             : // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
     194           0 : void StopSSLServerCertVerificationThreads()
     195             : {
     196           0 :   if (gCertVerificationThreadPool) {
     197           0 :     gCertVerificationThreadPool->Shutdown();
     198           0 :     NS_RELEASE(gCertVerificationThreadPool);
     199             :   }
     200           0 : }
     201             : 
     202             : namespace {
     203             : 
     204             : void
     205           0 : LogInvalidCertError(nsNSSSocketInfo* socketInfo,
     206             :                     PRErrorCode errorCode,
     207             :                     ::mozilla::psm::SSLErrorMessageType errorMessageType)
     208             : {
     209           0 :   nsString message;
     210           0 :   socketInfo->GetErrorLogMessage(errorCode, errorMessageType, message);
     211           0 :   if (!message.IsEmpty()) {
     212           0 :     nsContentUtils::LogSimpleConsoleError(message, "SSL");
     213             :   }
     214           0 : }
     215             : 
     216             : // Dispatched to the STS thread to notify the infoObject of the verification
     217             : // result.
     218             : //
     219             : // This will cause the PR_Poll in the STS thread to return, so things work
     220             : // correctly even if the STS thread is blocked polling (only) on the file
     221             : // descriptor that is waiting for this result.
     222           0 : class SSLServerCertVerificationResult : public Runnable
     223             : {
     224             : public:
     225             :   NS_DECL_NSIRUNNABLE
     226             : 
     227             :   SSLServerCertVerificationResult(nsNSSSocketInfo* infoObject,
     228             :                                   PRErrorCode errorCode,
     229             :                                   Telemetry::HistogramID telemetryID = Telemetry::HistogramCount,
     230             :                                   uint32_t telemetryValue = -1,
     231             :                                   SSLErrorMessageType errorMessageType =
     232             :                                     SSLErrorMessageType::Plain);
     233             : 
     234             :   void Dispatch();
     235             : private:
     236             :   const RefPtr<nsNSSSocketInfo> mInfoObject;
     237             : public:
     238             :   const PRErrorCode mErrorCode;
     239             :   const SSLErrorMessageType mErrorMessageType;
     240             :   const Telemetry::HistogramID mTelemetryID;
     241             :   const uint32_t mTelemetryValue;
     242             : };
     243             : 
     244           0 : class CertErrorRunnable : public SyncRunnableBase
     245             : {
     246             :  public:
     247           0 :   CertErrorRunnable(const void* fdForLogging,
     248             :                     nsIX509Cert* cert,
     249             :                     nsNSSSocketInfo* infoObject,
     250             :                     PRErrorCode defaultErrorCodeToReport,
     251             :                     uint32_t collectedErrors,
     252             :                     PRErrorCode errorCodeTrust,
     253             :                     PRErrorCode errorCodeMismatch,
     254             :                     PRErrorCode errorCodeTime,
     255             :                     uint32_t providerFlags)
     256           0 :     : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
     257             :       mDefaultErrorCodeToReport(defaultErrorCodeToReport),
     258             :       mCollectedErrors(collectedErrors),
     259             :       mErrorCodeTrust(errorCodeTrust),
     260             :       mErrorCodeMismatch(errorCodeMismatch),
     261             :       mErrorCodeTime(errorCodeTime),
     262           0 :       mProviderFlags(providerFlags)
     263             :   {
     264           0 :   }
     265             : 
     266             :   virtual void RunOnTargetThread();
     267             :   RefPtr<SSLServerCertVerificationResult> mResult; // out
     268             : private:
     269             :   SSLServerCertVerificationResult* CheckCertOverrides();
     270             :   nsresult OverrideAllowedForHost(/*out*/ bool& overrideAllowed);
     271             : 
     272             :   const void* const mFdForLogging; // may become an invalid pointer; do not dereference
     273             :   const nsCOMPtr<nsIX509Cert> mCert;
     274             :   const RefPtr<nsNSSSocketInfo> mInfoObject;
     275             :   const PRErrorCode mDefaultErrorCodeToReport;
     276             :   const uint32_t mCollectedErrors;
     277             :   const PRErrorCode mErrorCodeTrust;
     278             :   const PRErrorCode mErrorCodeMismatch;
     279             :   const PRErrorCode mErrorCodeTime;
     280             :   const uint32_t mProviderFlags;
     281             : };
     282             : 
     283             : // A probe value of 1 means "no error".
     284             : uint32_t
     285           0 : MapOverridableErrorToProbeValue(PRErrorCode errorCode)
     286             : {
     287           0 :   switch (errorCode)
     288             :   {
     289           0 :     case SEC_ERROR_UNKNOWN_ISSUER:                     return  2;
     290           0 :     case SEC_ERROR_CA_CERT_INVALID:                    return  3;
     291           0 :     case SEC_ERROR_UNTRUSTED_ISSUER:                   return  4;
     292           0 :     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:         return  5;
     293           0 :     case SEC_ERROR_UNTRUSTED_CERT:                     return  6;
     294           0 :     case SEC_ERROR_INADEQUATE_KEY_USAGE:               return  7;
     295           0 :     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:  return  8;
     296           0 :     case SSL_ERROR_BAD_CERT_DOMAIN:                    return  9;
     297           0 :     case SEC_ERROR_EXPIRED_CERTIFICATE:                return 10;
     298           0 :     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: return 11;
     299           0 :     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: return 12;
     300           0 :     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE: return 13;
     301           0 :     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE: return 14;
     302             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
     303           0 :       return 15;
     304           0 :     case SEC_ERROR_INVALID_TIME: return 16;
     305           0 :     case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME: return 17;
     306             :   }
     307             :   NS_WARNING("Unknown certificate error code. Does MapOverridableErrorToProbeValue "
     308           0 :              "handle everything in DetermineCertOverrideErrors?");
     309           0 :   return 0;
     310             : }
     311             : 
     312             : static uint32_t
     313           0 : MapCertErrorToProbeValue(PRErrorCode errorCode)
     314             : {
     315             :   uint32_t probeValue;
     316           0 :   switch (errorCode)
     317             :   {
     318             :     // see security/pkix/include/pkix/Result.h
     319             : #define MOZILLA_PKIX_MAP(name, value, nss_name) case nss_name: probeValue = value; break;
     320           0 :     MOZILLA_PKIX_MAP_LIST
     321             : #undef MOZILLA_PKIX_MAP
     322           0 :     default: return 0;
     323             :   }
     324             : 
     325             :   // Since FATAL_ERROR_FLAG is 0x800, fatal error values are much larger than
     326             :   // non-fatal error values. To conserve space, we remap these so they start at
     327             :   // (decimal) 90 instead of 0x800. Currently there are ~50 non-fatal errors
     328             :   // mozilla::pkix might return, so saving space for 90 should be sufficient
     329             :   // (similarly, there are 4 fatal errors, so saving space for 10 should also
     330             :   // be sufficient).
     331             :   static_assert(FATAL_ERROR_FLAG == 0x800,
     332             :                 "mozilla::pkix::FATAL_ERROR_FLAG is not what we were expecting");
     333           0 :   if (probeValue & FATAL_ERROR_FLAG) {
     334           0 :     probeValue ^= FATAL_ERROR_FLAG;
     335           0 :     probeValue += 90;
     336             :   }
     337           0 :   return probeValue;
     338             : }
     339             : 
     340             : SECStatus
     341           0 : DetermineCertOverrideErrors(const UniqueCERTCertificate& cert,
     342             :                             const nsACString& hostName,
     343             :                             PRTime now, PRErrorCode defaultErrorCodeToReport,
     344             :                             /*out*/ uint32_t& collectedErrors,
     345             :                             /*out*/ PRErrorCode& errorCodeTrust,
     346             :                             /*out*/ PRErrorCode& errorCodeMismatch,
     347             :                             /*out*/ PRErrorCode& errorCodeTime)
     348             : {
     349           0 :   MOZ_ASSERT(cert);
     350           0 :   MOZ_ASSERT(collectedErrors == 0);
     351           0 :   MOZ_ASSERT(errorCodeTrust == 0);
     352           0 :   MOZ_ASSERT(errorCodeMismatch == 0);
     353           0 :   MOZ_ASSERT(errorCodeTime == 0);
     354             : 
     355             :   // Assumes the error prioritization described in mozilla::pkix's
     356             :   // BuildForward function. Also assumes that CheckCertHostname was only
     357             :   // called if CertVerifier::VerifyCert succeeded.
     358           0 :   switch (defaultErrorCodeToReport) {
     359             :     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
     360             :     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
     361             :     case SEC_ERROR_UNKNOWN_ISSUER:
     362             :     case SEC_ERROR_CA_CERT_INVALID:
     363             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
     364             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
     365             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
     366             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
     367             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
     368             :     {
     369           0 :       collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
     370           0 :       errorCodeTrust = defaultErrorCodeToReport;
     371             : 
     372           0 :       SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert.get(), now,
     373           0 :                                                               false);
     374           0 :       if (validity == secCertTimeUndetermined) {
     375             :         // This only happens if cert is null. CERT_CheckCertValidTimes will
     376             :         // have set the error code to SEC_ERROR_INVALID_ARGS. We should really
     377             :         // be using mozilla::pkix here anyway.
     378           0 :         MOZ_ASSERT(PR_GetError() == SEC_ERROR_INVALID_ARGS);
     379           0 :         return SECFailure;
     380             :       }
     381           0 :       if (validity == secCertTimeExpired) {
     382           0 :         collectedErrors |= nsICertOverrideService::ERROR_TIME;
     383           0 :         errorCodeTime = SEC_ERROR_EXPIRED_CERTIFICATE;
     384           0 :       } else if (validity == secCertTimeNotValidYet) {
     385           0 :         collectedErrors |= nsICertOverrideService::ERROR_TIME;
     386           0 :         errorCodeTime =
     387             :           mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE;
     388             :       }
     389           0 :       break;
     390             :     }
     391             : 
     392             :     case SEC_ERROR_INVALID_TIME:
     393             :     case SEC_ERROR_EXPIRED_CERTIFICATE:
     394             :     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
     395           0 :       collectedErrors = nsICertOverrideService::ERROR_TIME;
     396           0 :       errorCodeTime = defaultErrorCodeToReport;
     397           0 :       break;
     398             : 
     399             :     case SSL_ERROR_BAD_CERT_DOMAIN:
     400           0 :       collectedErrors = nsICertOverrideService::ERROR_MISMATCH;
     401           0 :       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
     402           0 :       break;
     403             : 
     404             :     case 0:
     405           0 :       NS_ERROR("No error code set during certificate validation failure.");
     406           0 :       PR_SetError(PR_INVALID_STATE_ERROR, 0);
     407           0 :       return SECFailure;
     408             : 
     409             :     default:
     410           0 :       PR_SetError(defaultErrorCodeToReport, 0);
     411           0 :       return SECFailure;
     412             :   }
     413             : 
     414           0 :   if (defaultErrorCodeToReport != SSL_ERROR_BAD_CERT_DOMAIN) {
     415           0 :     Input certInput;
     416           0 :     if (certInput.Init(cert->derCert.data, cert->derCert.len) != Success) {
     417           0 :       PR_SetError(SEC_ERROR_BAD_DER, 0);
     418           0 :       return SECFailure;
     419             :     }
     420           0 :     Input hostnameInput;
     421           0 :     Result result = hostnameInput.Init(
     422             :       BitwiseCast<const uint8_t*, const char*>(hostName.BeginReading()),
     423           0 :       hostName.Length());
     424           0 :     if (result != Success) {
     425           0 :       PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
     426           0 :       return SECFailure;
     427             :     }
     428             :     // Use a lax policy so as to not generate potentially spurious name
     429             :     // mismatch "hints".
     430             :     BRNameMatchingPolicy nameMatchingPolicy(
     431           0 :       BRNameMatchingPolicy::Mode::DoNotEnforce);
     432             :     // CheckCertHostname expects that its input represents a certificate that
     433             :     // has already been successfully validated by BuildCertChain. This is
     434             :     // obviously not the case, however, because we're in the error path of
     435             :     // certificate verification. Thus, this is problematic. In the future, it
     436             :     // would be nice to remove this optimistic additional error checking and
     437             :     // simply punt to the front-end, which can more easily (and safely) perform
     438             :     // extra checks to give the user hints as to why verification failed.
     439           0 :     result = CheckCertHostname(certInput, hostnameInput, nameMatchingPolicy);
     440             :     // Treat malformed name information as a domain mismatch.
     441           0 :     if (result == Result::ERROR_BAD_DER ||
     442             :         result == Result::ERROR_BAD_CERT_DOMAIN) {
     443           0 :       collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
     444           0 :       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
     445           0 :     } else if (IsFatalError(result)) {
     446             :       // Because its input has not been validated by BuildCertChain,
     447             :       // CheckCertHostname can return an error that is less important than the
     448             :       // original certificate verification error. Only return an error result
     449             :       // from this function if we've encountered a fatal error.
     450           0 :       PR_SetError(MapResultToPRErrorCode(result), 0);
     451           0 :       return SECFailure;
     452             :     }
     453             :   }
     454             : 
     455           0 :   return SECSuccess;
     456             : }
     457             : 
     458             : // Helper function to determine if overrides are allowed for this host.
     459             : // Overrides are not allowed for known HSTS or HPKP hosts. However, an IP
     460             : // address is never considered an HSTS or HPKP host.
     461             : nsresult
     462           0 : CertErrorRunnable::OverrideAllowedForHost(/*out*/ bool& overrideAllowed)
     463             : {
     464           0 :   overrideAllowed = false;
     465             : 
     466             :   // If this is an IP address, overrides are allowed, because an IP address is
     467             :   // never an HSTS or HPKP host. nsISiteSecurityService takes this into account
     468             :   // already, but the real problem here is that calling NS_NewURI with an IPv6
     469             :   // address fails. We do this to avoid that. A more comprehensive fix would be
     470             :   // to have Necko provide an nsIURI to PSM and to use that here (and
     471             :   // everywhere). However, that would be a wide-spanning change.
     472           0 :   const nsACString& hostname = mInfoObject->GetHostName();
     473           0 :   if (net_IsValidIPv6Addr(hostname.BeginReading(), hostname.Length())) {
     474           0 :     overrideAllowed = true;
     475           0 :     return NS_OK;
     476             :   }
     477             : 
     478             :   // If this is an HTTP Strict Transport Security host or a pinned host and the
     479             :   // certificate is bad, don't allow overrides (RFC 6797 section 12.1,
     480             :   // HPKP draft spec section 2.6).
     481           0 :   bool strictTransportSecurityEnabled = false;
     482           0 :   bool hasPinningInformation = false;
     483           0 :   nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
     484           0 :   if (!sss) {
     485           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     486             :             ("[%p][%p] couldn't get nsISiteSecurityService to check HSTS/HPKP",
     487             :             mFdForLogging, this));
     488           0 :     return NS_ERROR_FAILURE;
     489             :   }
     490           0 :   nsCOMPtr<nsIURI> uri;
     491           0 :   nsresult rv = NS_NewURI(getter_AddRefs(uri),
     492           0 :                           NS_LITERAL_CSTRING("https://") + hostname);
     493           0 :   if (NS_FAILED(rv)) {
     494           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     495             :             ("[%p][%p] Creating new URI failed", mFdForLogging, this));
     496           0 :     return rv;
     497             :   }
     498           0 :   rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
     499             :                         uri,
     500           0 :                         mProviderFlags,
     501           0 :                         mInfoObject->GetOriginAttributes(),
     502             :                         nullptr,
     503             :                         nullptr,
     504           0 :                         &strictTransportSecurityEnabled);
     505           0 :   if (NS_FAILED(rv)) {
     506           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     507             :             ("[%p][%p] checking for HSTS failed", mFdForLogging, this));
     508           0 :     return rv;
     509             :   }
     510           0 :   rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP,
     511             :                         uri,
     512           0 :                         mProviderFlags,
     513           0 :                         mInfoObject->GetOriginAttributes(),
     514             :                         nullptr,
     515             :                         nullptr,
     516           0 :                         &hasPinningInformation);
     517           0 :   if (NS_FAILED(rv)) {
     518           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     519             :             ("[%p][%p] checking for HPKP failed", mFdForLogging, this));
     520           0 :     return rv;
     521             :   }
     522             : 
     523           0 :   overrideAllowed = !strictTransportSecurityEnabled && !hasPinningInformation;
     524           0 :   return NS_OK;
     525             : }
     526             : 
     527             : SSLServerCertVerificationResult*
     528           0 : CertErrorRunnable::CheckCertOverrides()
     529             : {
     530           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p][%p] top of CheckCertOverrides\n",
     531             :                                     mFdForLogging, this));
     532             :   // "Use" mFdForLogging in non-PR_LOGGING builds, too, to suppress
     533             :   // clang's -Wunused-private-field build warning for this variable:
     534           0 :   Unused << mFdForLogging;
     535             : 
     536           0 :   if (!NS_IsMainThread()) {
     537           0 :     NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
     538             :     return new SSLServerCertVerificationResult(mInfoObject,
     539           0 :                                                mDefaultErrorCodeToReport);
     540             :   }
     541             : 
     542           0 :   int32_t port = mInfoObject->GetPort();
     543             : 
     544           0 :   nsAutoCString hostWithPortString(mInfoObject->GetHostName());
     545           0 :   hostWithPortString.Append(':');
     546           0 :   hostWithPortString.AppendInt(port);
     547             : 
     548           0 :   uint32_t remaining_display_errors = mCollectedErrors;
     549             : 
     550             :   bool overrideAllowed;
     551           0 :   if (NS_FAILED(OverrideAllowedForHost(overrideAllowed))) {
     552             :     return new SSLServerCertVerificationResult(mInfoObject,
     553           0 :                                                mDefaultErrorCodeToReport);
     554             :   }
     555             : 
     556           0 :   if (overrideAllowed) {
     557           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     558             :            ("[%p][%p] no HSTS or HPKP - overrides allowed\n",
     559             :             mFdForLogging, this));
     560             :     nsCOMPtr<nsICertOverrideService> overrideService =
     561           0 :       do_GetService(NS_CERTOVERRIDE_CONTRACTID);
     562             :     // it is fine to continue without the nsICertOverrideService
     563             : 
     564           0 :     uint32_t overrideBits = 0;
     565             : 
     566           0 :     if (overrideService) {
     567             :       bool haveOverride;
     568             :       bool isTemporaryOverride; // we don't care
     569           0 :       const nsACString& hostString(mInfoObject->GetHostName());
     570           0 :       nsresult rv = overrideService->HasMatchingOverride(hostString, port,
     571             :                                                          mCert,
     572             :                                                          &overrideBits,
     573             :                                                          &isTemporaryOverride,
     574           0 :                                                          &haveOverride);
     575           0 :       if (NS_SUCCEEDED(rv) && haveOverride) {
     576             :        // remove the errors that are already overriden
     577           0 :         remaining_display_errors &= ~overrideBits;
     578             :       }
     579             :     }
     580             : 
     581           0 :     if (!remaining_display_errors) {
     582             :       // This can double- or triple-count one certificate with multiple
     583             :       // different types of errors. Since this is telemetry and we just
     584             :       // want a ballpark answer, we don't care.
     585           0 :       if (mErrorCodeTrust != 0) {
     586           0 :         uint32_t probeValue = MapOverridableErrorToProbeValue(mErrorCodeTrust);
     587           0 :         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
     588             :       }
     589           0 :       if (mErrorCodeMismatch != 0) {
     590           0 :         uint32_t probeValue = MapOverridableErrorToProbeValue(mErrorCodeMismatch);
     591           0 :         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
     592             :       }
     593           0 :       if (mErrorCodeTime != 0) {
     594           0 :         uint32_t probeValue = MapOverridableErrorToProbeValue(mErrorCodeTime);
     595           0 :         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
     596             :       }
     597             : 
     598             :       // all errors are covered by override rules, so let's accept the cert
     599           0 :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     600             :              ("[%p][%p] All errors covered by override rules\n",
     601             :              mFdForLogging, this));
     602           0 :       return new SSLServerCertVerificationResult(mInfoObject, 0);
     603             :     }
     604             :   } else {
     605           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     606             :            ("[%p][%p] HSTS or HPKP - no overrides allowed\n",
     607             :             mFdForLogging, this));
     608             :   }
     609             : 
     610           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     611             :          ("[%p][%p] Certificate error was not overridden\n",
     612             :          mFdForLogging, this));
     613             : 
     614             :   // Ok, this is a full stop.
     615             :   // First, deliver the technical details of the broken SSL status.
     616             : 
     617             :   // Try to get a nsIBadCertListener2 implementation from the socket consumer.
     618             :   nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
     619           0 :     NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
     620           0 :   if (sslSocketControl) {
     621           0 :     nsCOMPtr<nsIInterfaceRequestor> cb;
     622           0 :     sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
     623           0 :     if (cb) {
     624           0 :       nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
     625           0 :       if (bcl) {
     626             :         nsIInterfaceRequestor* csi
     627           0 :           = static_cast<nsIInterfaceRequestor*>(mInfoObject);
     628           0 :         bool suppressMessage = false; // obsolete, ignored
     629           0 :         Unused << bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
     630           0 :                                          hostWithPortString, &suppressMessage);
     631             :       }
     632             :     }
     633             :   }
     634             : 
     635             :   // pick the error code to report by priority
     636           0 :   PRErrorCode errorCodeToReport = mErrorCodeTrust    ? mErrorCodeTrust
     637           0 :                                 : mErrorCodeMismatch ? mErrorCodeMismatch
     638           0 :                                 : mErrorCodeTime     ? mErrorCodeTime
     639           0 :                                 : mDefaultErrorCodeToReport;
     640             : 
     641             :   SSLServerCertVerificationResult* result =
     642             :     new SSLServerCertVerificationResult(mInfoObject,
     643             :                                         errorCodeToReport,
     644             :                                         Telemetry::HistogramCount,
     645             :                                         -1,
     646           0 :                                         SSLErrorMessageType::OverridableCert);
     647             : 
     648           0 :   LogInvalidCertError(mInfoObject,
     649           0 :                       result->mErrorCode,
     650           0 :                       result->mErrorMessageType);
     651             : 
     652           0 :   return result;
     653             : }
     654             : 
     655             : void
     656           0 : CertErrorRunnable::RunOnTargetThread()
     657             : {
     658           0 :   MOZ_ASSERT(NS_IsMainThread());
     659             : 
     660           0 :   mResult = CheckCertOverrides();
     661             : 
     662           0 :   MOZ_ASSERT(mResult);
     663           0 : }
     664             : 
     665             : // Returns null with the error code (PR_GetError()) set if it does not create
     666             : // the CertErrorRunnable.
     667             : CertErrorRunnable*
     668           0 : CreateCertErrorRunnable(CertVerifier& certVerifier,
     669             :                         PRErrorCode defaultErrorCodeToReport,
     670             :                         nsNSSSocketInfo* infoObject,
     671             :                         const UniqueCERTCertificate& cert,
     672             :                         const void* fdForLogging,
     673             :                         uint32_t providerFlags,
     674             :                         PRTime now)
     675             : {
     676           0 :   MOZ_ASSERT(infoObject);
     677           0 :   MOZ_ASSERT(cert);
     678             : 
     679           0 :   uint32_t probeValue = MapCertErrorToProbeValue(defaultErrorCodeToReport);
     680           0 :   Telemetry::Accumulate(Telemetry::SSL_CERT_VERIFICATION_ERRORS, probeValue);
     681             : 
     682           0 :   uint32_t collected_errors = 0;
     683           0 :   PRErrorCode errorCodeTrust = 0;
     684           0 :   PRErrorCode errorCodeMismatch = 0;
     685           0 :   PRErrorCode errorCodeTime = 0;
     686           0 :   if (DetermineCertOverrideErrors(cert, infoObject->GetHostName(), now,
     687             :                                   defaultErrorCodeToReport, collected_errors,
     688             :                                   errorCodeTrust, errorCodeMismatch,
     689             :                                   errorCodeTime) != SECSuccess) {
     690             :     // Attempt to enforce that if DetermineCertOverrideErrors failed,
     691             :     // PR_SetError was set with a non-overridable error. This is because if we
     692             :     // return from CreateCertErrorRunnable without calling
     693             :     // infoObject->SetStatusErrorBits, we won't have the required information
     694             :     // to actually add a certificate error override. This results in a broken
     695             :     // UI which is annoying but not a security disaster.
     696           0 :     MOZ_ASSERT(!ErrorIsOverridable(PR_GetError()));
     697           0 :     return nullptr;
     698             :   }
     699             : 
     700           0 :   RefPtr<nsNSSCertificate> nssCert(nsNSSCertificate::Create(cert.get()));
     701           0 :   if (!nssCert) {
     702           0 :     NS_ERROR("nsNSSCertificate::Create failed");
     703           0 :     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
     704           0 :     return nullptr;
     705             :   }
     706             : 
     707           0 :   if (!collected_errors) {
     708             :     // This will happen when CERT_*Verify* only returned error(s) that are
     709             :     // not on our whitelist of overridable certificate errors.
     710           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] !collected_errors: %d\n",
     711             :            fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
     712           0 :     PR_SetError(defaultErrorCodeToReport, 0);
     713           0 :     return nullptr;
     714             :   }
     715             : 
     716           0 :   infoObject->SetStatusErrorBits(nssCert, collected_errors);
     717             : 
     718             :   return new CertErrorRunnable(fdForLogging,
     719           0 :                                static_cast<nsIX509Cert*>(nssCert.get()),
     720             :                                infoObject, defaultErrorCodeToReport,
     721             :                                collected_errors, errorCodeTrust,
     722             :                                errorCodeMismatch, errorCodeTime,
     723           0 :                                providerFlags);
     724             : }
     725             : 
     726             : // When doing async cert processing, we dispatch one of these runnables to the
     727             : // socket transport service thread, which blocks the socket transport
     728             : // service thread while it waits for the inner CertErrorRunnable to execute
     729             : // CheckCertOverrides on the main thread. CheckCertOverrides must block events
     730             : // on both of these threads because it calls TransportSecurityInfo::GetInterface(),
     731             : // which may call nsHttpConnection::GetInterface() through
     732             : // TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always
     733             : // execute on the main thread, with the socket transport service thread
     734             : // blocked.
     735           0 : class CertErrorRunnableRunnable : public Runnable
     736             : {
     737             : public:
     738           0 :   explicit CertErrorRunnableRunnable(CertErrorRunnable* certErrorRunnable)
     739           0 :     : Runnable("psm::CertErrorRunnableRunnable")
     740           0 :     , mCertErrorRunnable(certErrorRunnable)
     741             :   {
     742           0 :   }
     743             : private:
     744           0 :   NS_IMETHOD Run() override
     745             :   {
     746           0 :     nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
     747             :     // The result must run on the socket transport thread, which we are already
     748             :     // on, so we can just run it directly, instead of dispatching it.
     749           0 :     if (NS_SUCCEEDED(rv)) {
     750           0 :       rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
     751           0 :                                        : NS_ERROR_UNEXPECTED;
     752             :     }
     753           0 :     return rv;
     754             :   }
     755             :   RefPtr<CertErrorRunnable> mCertErrorRunnable;
     756             : };
     757             : 
     758           0 : class SSLServerCertVerificationJob : public Runnable
     759             : {
     760             : public:
     761             :   // Must be called only on the socket transport thread
     762             :   static SECStatus Dispatch(const RefPtr<SharedCertVerifier>& certVerifier,
     763             :                             const void* fdForLogging,
     764             :                             nsNSSSocketInfo* infoObject,
     765             :                             const UniqueCERTCertificate& serverCert,
     766             :                             const UniqueCERTCertList& peerCertChain,
     767             :                             const SECItem* stapledOCSPResponse,
     768             :                             const SECItem* sctsFromTLSExtension,
     769             :                             uint32_t providerFlags,
     770             :                             Time time,
     771             :                             PRTime prtime);
     772             : private:
     773             :   NS_DECL_NSIRUNNABLE
     774             : 
     775             :   // Must be called only on the socket transport thread
     776             :   SSLServerCertVerificationJob(const RefPtr<SharedCertVerifier>& certVerifier,
     777             :                                const void* fdForLogging,
     778             :                                nsNSSSocketInfo* infoObject,
     779             :                                const UniqueCERTCertificate& cert,
     780             :                                UniqueCERTCertList peerCertChain,
     781             :                                const SECItem* stapledOCSPResponse,
     782             :                                const SECItem* sctsFromTLSExtension,
     783             :                                uint32_t providerFlags,
     784             :                                Time time,
     785             :                                PRTime prtime);
     786             :   const RefPtr<SharedCertVerifier> mCertVerifier;
     787             :   const void* const mFdForLogging;
     788             :   const RefPtr<nsNSSSocketInfo> mInfoObject;
     789             :   const UniqueCERTCertificate mCert;
     790             :   UniqueCERTCertList mPeerCertChain;
     791             :   const uint32_t mProviderFlags;
     792             :   const Time mTime;
     793             :   const PRTime mPRTime;
     794             :   const TimeStamp mJobStartTime;
     795             :   const UniqueSECItem mStapledOCSPResponse;
     796             :   const UniqueSECItem mSCTsFromTLSExtension;
     797             : };
     798             : 
     799           0 : SSLServerCertVerificationJob::SSLServerCertVerificationJob(
     800             :   const RefPtr<SharedCertVerifier>& certVerifier,
     801             :   const void* fdForLogging,
     802             :   nsNSSSocketInfo* infoObject,
     803             :   const UniqueCERTCertificate& cert,
     804             :   UniqueCERTCertList peerCertChain,
     805             :   const SECItem* stapledOCSPResponse,
     806             :   const SECItem* sctsFromTLSExtension,
     807             :   uint32_t providerFlags,
     808             :   Time time,
     809           0 :   PRTime prtime)
     810             :   : Runnable("psm::SSLServerCertVerificationJob")
     811             :   , mCertVerifier(certVerifier)
     812             :   , mFdForLogging(fdForLogging)
     813             :   , mInfoObject(infoObject)
     814             :   , mCert(CERT_DupCertificate(cert.get()))
     815           0 :   , mPeerCertChain(Move(peerCertChain))
     816             :   , mProviderFlags(providerFlags)
     817             :   , mTime(time)
     818             :   , mPRTime(prtime)
     819             :   , mJobStartTime(TimeStamp::Now())
     820             :   , mStapledOCSPResponse(SECITEM_DupItem(stapledOCSPResponse))
     821           0 :   , mSCTsFromTLSExtension(SECITEM_DupItem(sctsFromTLSExtension))
     822             : {
     823           0 : }
     824             : 
     825             : // This function assumes that we will only use the SPDY connection coalescing
     826             : // feature on connections where we have negotiated SPDY using NPN. If we ever
     827             : // talk SPDY without having negotiated it with SPDY, this code will give wrong
     828             : // and perhaps unsafe results.
     829             : //
     830             : // Returns SECSuccess on the initial handshake of all connections, on
     831             : // renegotiations for any connections where we did not negotiate SPDY, or on any
     832             : // SPDY connection where the server's certificate did not change.
     833             : //
     834             : // Prohibit changing the server cert only if we negotiated SPDY,
     835             : // in order to support SPDY's cross-origin connection pooling.
     836             : static SECStatus
     837           0 : BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
     838             :                              const UniqueCERTCertificate& serverCert)
     839             : {
     840             :   // Get the existing cert. If there isn't one, then there is
     841             :   // no cert change to worry about.
     842           0 :   nsCOMPtr<nsIX509Cert> cert;
     843             : 
     844           0 :   RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
     845           0 :   if (!status) {
     846             :     // If we didn't have a status, then this is the
     847             :     // first handshake on this connection, not a
     848             :     // renegotiation.
     849           0 :     return SECSuccess;
     850             :   }
     851             : 
     852           0 :   status->GetServerCert(getter_AddRefs(cert));
     853           0 :   if (!cert) {
     854           0 :     MOZ_ASSERT_UNREACHABLE("nsSSLStatus must have a cert implementing nsIX509Cert");
     855             :     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
     856             :     return SECFailure;
     857             :   }
     858             : 
     859             :   // Filter out sockets that did not neogtiate SPDY via NPN
     860           0 :   nsAutoCString negotiatedNPN;
     861           0 :   nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
     862           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv), "GetNegotiatedNPN() failed during renegotiation");
     863             : 
     864           0 :   if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
     865           0 :                                             NS_LITERAL_CSTRING("spdy/"))) {
     866           0 :     return SECSuccess;
     867             :   }
     868             :   // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
     869           0 :   if (NS_FAILED(rv)) {
     870           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     871             :            ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
     872             :             " Assuming spdy.\n"));
     873             :   }
     874             : 
     875             :   // Check to see if the cert has actually changed
     876           0 :   UniqueCERTCertificate c(cert->GetCert());
     877           0 :   MOZ_ASSERT(c, "Somehow couldn't get underlying cert from nsIX509Cert");
     878           0 :   bool sameCert = CERT_CompareCerts(c.get(), serverCert.get());
     879           0 :   if (sameCert) {
     880           0 :     return SECSuccess;
     881             :   }
     882             : 
     883             :   // Report an error - changed cert is confirmed
     884           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     885             :          ("SPDY Refused to allow new cert during renegotiation\n"));
     886           0 :   PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
     887           0 :   return SECFailure;
     888             : }
     889             : 
     890             : void
     891           0 : AccumulateSubjectCommonNameTelemetry(const char* commonName,
     892             :                                      bool commonNameInSubjectAltNames)
     893             : {
     894           0 :   if (!commonName) {
     895             :     // 1 means no common name present
     896           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_2_SUBJECT_COMMON_NAME, 1);
     897           0 :   } else if (!commonNameInSubjectAltNames) {
     898           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     899             :            ("BR telemetry: common name '%s' not in subject alt. names "
     900             :             "(or the subject alt. names extension is not present)\n",
     901             :             commonName));
     902             :     // 2 means the common name is not present in subject alt names
     903           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_2_SUBJECT_COMMON_NAME, 2);
     904             :   } else {
     905             :     // 0 means the common name is present in subject alt names
     906           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_2_SUBJECT_COMMON_NAME, 0);
     907             :   }
     908           0 : }
     909             : 
     910             : // Returns true if and only if commonName ends with altName (minus its leading
     911             : // "*"). altName has already been checked to be of the form "*.<something>".
     912             : // commonName may be NULL.
     913             : static bool
     914           0 : TryMatchingWildcardSubjectAltName(const char* commonName,
     915             :                                   const nsACString& altName)
     916             : {
     917           0 :   return commonName &&
     918           0 :          StringEndsWith(nsDependentCString(commonName), Substring(altName, 1));
     919             : }
     920             : 
     921             : // Gathers telemetry on Baseline Requirements 9.2.1 (Subject Alternative
     922             : // Names Extension) and 9.2.2 (Subject Common Name Field).
     923             : // Specifically:
     924             : //  - whether or not the subject common name field is present
     925             : //  - whether or not the subject alternative names extension is present
     926             : //  - if there is a malformed entry in the subject alt. names extension
     927             : //  - if there is an entry in the subject alt. names extension corresponding
     928             : //    to the subject common name
     929             : // Telemetry is only gathered for certificates that chain to a trusted root
     930             : // in Mozilla's Root CA program.
     931             : // certList consists of a validated certificate chain. The end-entity
     932             : // certificate is first and the root (trust anchor) is last.
     933             : void
     934           0 : GatherBaselineRequirementsTelemetry(const UniqueCERTCertList& certList)
     935             : {
     936           0 :   CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certList);
     937           0 :   CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
     938           0 :   MOZ_ASSERT(!(CERT_LIST_END(endEntityNode, certList) ||
     939             :                CERT_LIST_END(rootNode, certList)));
     940           0 :   if (CERT_LIST_END(endEntityNode, certList) ||
     941           0 :       CERT_LIST_END(rootNode, certList)) {
     942           0 :     return;
     943             :   }
     944           0 :   CERTCertificate* cert = endEntityNode->cert;
     945           0 :   MOZ_ASSERT(cert);
     946           0 :   if (!cert) {
     947           0 :     return;
     948             :   }
     949           0 :   UniquePORTString commonName(CERT_GetCommonName(&cert->subject));
     950             :   // This only applies to certificates issued by authorities in our root
     951             :   // program.
     952           0 :   CERTCertificate* rootCert = rootNode->cert;
     953           0 :   MOZ_ASSERT(rootCert);
     954           0 :   if (!rootCert) {
     955           0 :     return;
     956             :   }
     957           0 :   bool isBuiltIn = false;
     958           0 :   Result result = IsCertBuiltInRoot(rootCert, isBuiltIn);
     959           0 :   if (result != Success || !isBuiltIn) {
     960           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     961             :            ("BR telemetry: root certificate for '%s' is not a built-in root "
     962             :             "(or IsCertBuiltInRoot failed)\n", commonName.get()));
     963           0 :     return;
     964             :   }
     965           0 :   ScopedAutoSECItem altNameExtension;
     966             :   SECStatus rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
     967           0 :                                         &altNameExtension);
     968           0 :   if (rv != SECSuccess) {
     969           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     970             :            ("BR telemetry: no subject alt names extension for '%s'\n",
     971             :             commonName.get()));
     972             :     // 1 means there is no subject alt names extension
     973           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_1_SUBJECT_ALT_NAMES, 1);
     974           0 :     AccumulateSubjectCommonNameTelemetry(commonName.get(), false);
     975           0 :     return;
     976             :   }
     977             : 
     978           0 :   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     979             :   CERTGeneralName* subjectAltNames =
     980           0 :     CERT_DecodeAltNameExtension(arena.get(), &altNameExtension);
     981           0 :   if (!subjectAltNames) {
     982           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     983             :            ("BR telemetry: could not decode subject alt names for '%s'\n",
     984             :             commonName.get()));
     985             :     // 2 means the subject alt names extension could not be decoded
     986           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_1_SUBJECT_ALT_NAMES, 2);
     987           0 :     AccumulateSubjectCommonNameTelemetry(commonName.get(), false);
     988           0 :     return;
     989             :   }
     990             : 
     991           0 :   CERTGeneralName* currentName = subjectAltNames;
     992           0 :   bool commonNameInSubjectAltNames = false;
     993           0 :   bool nonDNSNameOrIPAddressPresent = false;
     994           0 :   bool malformedDNSNameOrIPAddressPresent = false;
     995           0 :   bool nonFQDNPresent = false;
     996           0 :   do {
     997           0 :     nsAutoCString altName;
     998           0 :     if (currentName->type == certDNSName) {
     999           0 :       altName.Assign(BitwiseCast<char*, unsigned char*>(
    1000             :                        currentName->name.other.data),
    1001           0 :                      currentName->name.other.len);
    1002           0 :       nsDependentCString altNameWithoutWildcard(altName, 0);
    1003           0 :       if (StringBeginsWith(altNameWithoutWildcard, NS_LITERAL_CSTRING("*."))) {
    1004           0 :         altNameWithoutWildcard.Rebind(altName, 2);
    1005           0 :         commonNameInSubjectAltNames |=
    1006           0 :           TryMatchingWildcardSubjectAltName(commonName.get(), altName);
    1007             :       }
    1008             :       // net_IsValidHostName appears to return true for valid IP addresses,
    1009             :       // which would be invalid for a DNS name.
    1010             :       // Note that the net_IsValidHostName check will catch things like
    1011             :       // "a.*.example.com".
    1012           0 :       if (!net_IsValidHostName(altNameWithoutWildcard) ||
    1013           0 :           net_IsValidIPv4Addr(altName.get(), altName.Length()) ||
    1014           0 :           net_IsValidIPv6Addr(altName.get(), altName.Length())) {
    1015           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1016             :                ("BR telemetry: DNSName '%s' not valid (for '%s')\n",
    1017             :                 altName.get(), commonName.get()));
    1018           0 :         malformedDNSNameOrIPAddressPresent = true;
    1019             :       }
    1020           0 :       if (!altName.Contains('.')) {
    1021           0 :         nonFQDNPresent = true;
    1022             :       }
    1023           0 :     } else if (currentName->type == certIPAddress) {
    1024             :       // According to DNS.h, this includes space for the null-terminator
    1025           0 :       char buf[net::kNetAddrMaxCStrBufSize] = { 0 };
    1026             :       PRNetAddr addr;
    1027           0 :       if (currentName->name.other.len == 4) {
    1028           0 :         addr.inet.family = PR_AF_INET;
    1029           0 :         memcpy(&addr.inet.ip, currentName->name.other.data,
    1030           0 :                currentName->name.other.len);
    1031           0 :         if (PR_NetAddrToString(&addr, buf, sizeof(buf) - 1) != PR_SUCCESS) {
    1032           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1033             :                ("BR telemetry: IPAddress (v4) not valid (for '%s')\n",
    1034             :                 commonName.get()));
    1035           0 :           malformedDNSNameOrIPAddressPresent = true;
    1036             :         } else {
    1037           0 :           altName.Assign(buf);
    1038             :         }
    1039           0 :       } else if (currentName->name.other.len == 16) {
    1040           0 :         addr.inet.family = PR_AF_INET6;
    1041           0 :         memcpy(&addr.ipv6.ip, currentName->name.other.data,
    1042           0 :                currentName->name.other.len);
    1043           0 :         if (PR_NetAddrToString(&addr, buf, sizeof(buf) - 1) != PR_SUCCESS) {
    1044           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1045             :                ("BR telemetry: IPAddress (v6) not valid (for '%s')\n",
    1046             :                 commonName.get()));
    1047           0 :           malformedDNSNameOrIPAddressPresent = true;
    1048             :         } else {
    1049           0 :           altName.Assign(buf);
    1050             :         }
    1051             :       } else {
    1052           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1053             :                ("BR telemetry: IPAddress not valid (for '%s')\n",
    1054             :                 commonName.get()));
    1055           0 :         malformedDNSNameOrIPAddressPresent = true;
    1056             :       }
    1057             :     } else {
    1058           0 :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1059             :              ("BR telemetry: non-DNSName, non-IPAddress present for '%s'\n",
    1060             :               commonName.get()));
    1061           0 :       nonDNSNameOrIPAddressPresent = true;
    1062             :     }
    1063           0 :     if (commonName && altName.Equals(commonName.get())) {
    1064           0 :       commonNameInSubjectAltNames = true;
    1065             :     }
    1066           0 :     currentName = CERT_GetNextGeneralName(currentName);
    1067           0 :   } while (currentName && currentName != subjectAltNames);
    1068             : 
    1069           0 :   if (nonDNSNameOrIPAddressPresent) {
    1070             :     // 3 means there's an entry that isn't an ip address or dns name
    1071           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_1_SUBJECT_ALT_NAMES, 3);
    1072             :   }
    1073           0 :   if (malformedDNSNameOrIPAddressPresent) {
    1074             :     // 4 means there's a malformed ip address or dns name entry
    1075           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_1_SUBJECT_ALT_NAMES, 4);
    1076             :   }
    1077           0 :   if (nonFQDNPresent) {
    1078             :     // 5 means there's a DNS name entry with a non-fully-qualified domain name
    1079           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_1_SUBJECT_ALT_NAMES, 5);
    1080             :   }
    1081           0 :   if (!nonDNSNameOrIPAddressPresent && !malformedDNSNameOrIPAddressPresent &&
    1082           0 :       !nonFQDNPresent) {
    1083             :     // 0 means the extension is acceptable
    1084           0 :     Telemetry::Accumulate(Telemetry::BR_9_2_1_SUBJECT_ALT_NAMES, 0);
    1085             :   }
    1086             : 
    1087           0 :   AccumulateSubjectCommonNameTelemetry(commonName.get(),
    1088           0 :                                        commonNameInSubjectAltNames);
    1089             : }
    1090             : 
    1091             : // Gather telemetry on whether the end-entity cert for a server has the
    1092             : // required TLS Server Authentication EKU, or any others
    1093             : void
    1094           0 : GatherEKUTelemetry(const UniqueCERTCertList& certList)
    1095             : {
    1096           0 :   CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certList);
    1097           0 :   CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
    1098           0 :   MOZ_ASSERT(!(CERT_LIST_END(endEntityNode, certList) ||
    1099             :                CERT_LIST_END(rootNode, certList)));
    1100           0 :   if (CERT_LIST_END(endEntityNode, certList) ||
    1101           0 :       CERT_LIST_END(rootNode, certList)) {
    1102           0 :     return;
    1103             :   }
    1104           0 :   CERTCertificate* endEntityCert = endEntityNode->cert;
    1105           0 :   MOZ_ASSERT(endEntityCert);
    1106           0 :   if (!endEntityCert) {
    1107           0 :     return;
    1108             :   }
    1109             : 
    1110             :   // Only log telemetry if the root CA is built-in
    1111           0 :   CERTCertificate* rootCert = rootNode->cert;
    1112           0 :   MOZ_ASSERT(rootCert);
    1113           0 :   if (!rootCert) {
    1114           0 :     return;
    1115             :   }
    1116           0 :   bool isBuiltIn = false;
    1117           0 :   Result rv = IsCertBuiltInRoot(rootCert, isBuiltIn);
    1118           0 :   if (rv != Success || !isBuiltIn) {
    1119           0 :     return;
    1120             :   }
    1121             : 
    1122             :   // Find the EKU extension, if present
    1123           0 :   bool foundEKU = false;
    1124             :   SECOidTag oidTag;
    1125           0 :   CERTCertExtension* ekuExtension = nullptr;
    1126           0 :   for (size_t i = 0; endEntityCert->extensions && endEntityCert->extensions[i];
    1127             :        i++) {
    1128           0 :     oidTag = SECOID_FindOIDTag(&endEntityCert->extensions[i]->id);
    1129           0 :     if (oidTag == SEC_OID_X509_EXT_KEY_USAGE) {
    1130           0 :       foundEKU = true;
    1131           0 :       ekuExtension = endEntityCert->extensions[i];
    1132             :     }
    1133             :   }
    1134             : 
    1135           0 :   if (!foundEKU) {
    1136           0 :     Telemetry::Accumulate(Telemetry::SSL_SERVER_AUTH_EKU, 0);
    1137           0 :     return;
    1138             :   }
    1139             : 
    1140             :   // Parse the EKU extension
    1141             :   UniqueCERTOidSequence ekuSequence(
    1142           0 :     CERT_DecodeOidSequence(&ekuExtension->value));
    1143           0 :   if (!ekuSequence) {
    1144           0 :     return;
    1145             :   }
    1146             : 
    1147             :   // Search through the available EKUs
    1148           0 :   bool foundServerAuth = false;
    1149           0 :   bool foundOther = false;
    1150           0 :   for (SECItem** oids = ekuSequence->oids; oids && *oids; oids++) {
    1151           0 :     oidTag = SECOID_FindOIDTag(*oids);
    1152           0 :     if (oidTag == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) {
    1153           0 :       foundServerAuth = true;
    1154             :     } else {
    1155           0 :       foundOther = true;
    1156             :     }
    1157             :   }
    1158             : 
    1159             :   // Cases 3 is included only for completeness.  It should never
    1160             :   // appear in these statistics, because CheckExtendedKeyUsage()
    1161             :   // should require the EKU extension, if present, to contain the
    1162             :   // value id_kp_serverAuth.
    1163           0 :   if (foundServerAuth && !foundOther) {
    1164           0 :     Telemetry::Accumulate(Telemetry::SSL_SERVER_AUTH_EKU, 1);
    1165           0 :   } else if (foundServerAuth && foundOther) {
    1166           0 :     Telemetry::Accumulate(Telemetry::SSL_SERVER_AUTH_EKU, 2);
    1167           0 :   } else if (!foundServerAuth) {
    1168           0 :     Telemetry::Accumulate(Telemetry::SSL_SERVER_AUTH_EKU, 3);
    1169             :   }
    1170             : }
    1171             : 
    1172             : // Gathers telemetry on which CA is the root of a given cert chain.
    1173             : // If the root is a built-in root, then the telemetry makes a count
    1174             : // by root.  Roots that are not built-in are counted in one bin.
    1175             : void
    1176           0 : GatherRootCATelemetry(const UniqueCERTCertList& certList)
    1177             : {
    1178           0 :   CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
    1179           0 :   MOZ_ASSERT(rootNode);
    1180           0 :   if (!rootNode) {
    1181           0 :     return;
    1182             :   }
    1183           0 :   MOZ_ASSERT(!CERT_LIST_END(rootNode, certList));
    1184           0 :   if (CERT_LIST_END(rootNode, certList)) {
    1185           0 :     return;
    1186             :   }
    1187           0 :   CERTCertificate* rootCert = rootNode->cert;
    1188           0 :   MOZ_ASSERT(rootCert);
    1189           0 :   if (!rootCert) {
    1190           0 :     return;
    1191             :   }
    1192             :   AccumulateTelemetryForRootCA(Telemetry::CERT_VALIDATION_SUCCESS_BY_CA,
    1193           0 :                                rootCert);
    1194             : }
    1195             : 
    1196             : // These time are appoximate, i.e., doesn't account for leap seconds, etc
    1197             : const uint64_t ONE_WEEK_IN_SECONDS = (7 * (24 * 60 *60));
    1198             : const uint64_t ONE_YEAR_IN_WEEKS   = 52;
    1199             : 
    1200             : // Gathers telemetry on the certificate lifetimes we observe in the wild
    1201             : void
    1202           0 : GatherEndEntityTelemetry(const UniqueCERTCertList& certList)
    1203             : {
    1204           0 :   CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certList);
    1205           0 :   MOZ_ASSERT(endEntityNode && !CERT_LIST_END(endEntityNode, certList));
    1206           0 :   if (!endEntityNode || CERT_LIST_END(endEntityNode, certList)) {
    1207           0 :     return;
    1208             :   }
    1209             : 
    1210           0 :   CERTCertificate* endEntityCert = endEntityNode->cert;
    1211           0 :   MOZ_ASSERT(endEntityCert);
    1212           0 :   if (!endEntityCert) {
    1213           0 :     return;
    1214             :   }
    1215             : 
    1216             :   PRTime notBefore;
    1217             :   PRTime notAfter;
    1218             : 
    1219           0 :   if (CERT_GetCertTimes(endEntityCert, &notBefore, &notAfter) != SECSuccess) {
    1220           0 :     return;
    1221             :   }
    1222             : 
    1223           0 :   MOZ_ASSERT(notAfter > notBefore);
    1224           0 :   if (notAfter <= notBefore) {
    1225           0 :     return;
    1226             :   }
    1227             : 
    1228           0 :   uint64_t durationInWeeks = (notAfter - notBefore)
    1229           0 :     / PR_USEC_PER_SEC
    1230           0 :     / ONE_WEEK_IN_SECONDS;
    1231             : 
    1232           0 :   if (durationInWeeks > (2 * ONE_YEAR_IN_WEEKS)) {
    1233           0 :     durationInWeeks = (2 * ONE_YEAR_IN_WEEKS) + 1;
    1234             :   }
    1235             : 
    1236           0 :   Telemetry::Accumulate(Telemetry::SSL_OBSERVED_END_ENTITY_CERTIFICATE_LIFETIME,
    1237           0 :       durationInWeeks);
    1238             : }
    1239             : 
    1240             : // There are various things that we want to measure about certificate
    1241             : // chains that we accept.  This is a single entry point for all of them.
    1242             : void
    1243           0 : GatherSuccessfulValidationTelemetry(const UniqueCERTCertList& certList)
    1244             : {
    1245           0 :   GatherBaselineRequirementsTelemetry(certList);
    1246           0 :   GatherEKUTelemetry(certList);
    1247           0 :   GatherRootCATelemetry(certList);
    1248           0 :   GatherEndEntityTelemetry(certList);
    1249           0 : }
    1250             : 
    1251             : void
    1252           0 : GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct)
    1253             : {
    1254             :   // See SSL_SCTS_ORIGIN in Histograms.json.
    1255           0 :   uint32_t origin = 0;
    1256           0 :   switch (verifiedSct.origin) {
    1257             :     case ct::VerifiedSCT::Origin::Embedded:
    1258           0 :       origin = 1;
    1259           0 :       break;
    1260             :     case ct::VerifiedSCT::Origin::TLSExtension:
    1261           0 :       origin = 2;
    1262           0 :       break;
    1263             :     case ct::VerifiedSCT::Origin::OCSPResponse:
    1264           0 :       origin = 3;
    1265           0 :       break;
    1266             :     default:
    1267           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Origin type");
    1268             :   }
    1269           0 :   Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, origin);
    1270             : 
    1271             :   // See SSL_SCTS_VERIFICATION_STATUS in Histograms.json.
    1272           0 :   uint32_t verificationStatus = 0;
    1273           0 :   switch (verifiedSct.status) {
    1274             :     case ct::VerifiedSCT::Status::Valid:
    1275           0 :       verificationStatus = 1;
    1276           0 :       break;
    1277             :     case ct::VerifiedSCT::Status::UnknownLog:
    1278           0 :       verificationStatus = 2;
    1279           0 :       break;
    1280             :     case ct::VerifiedSCT::Status::InvalidSignature:
    1281           0 :       verificationStatus = 3;
    1282           0 :       break;
    1283             :     case ct::VerifiedSCT::Status::InvalidTimestamp:
    1284           0 :       verificationStatus = 4;
    1285           0 :       break;
    1286             :     case ct::VerifiedSCT::Status::ValidFromDisqualifiedLog:
    1287           0 :       verificationStatus = 5;
    1288           0 :       break;
    1289             :     default:
    1290           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
    1291             :   }
    1292             :   Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS,
    1293           0 :                         verificationStatus);
    1294           0 : }
    1295             : 
    1296             : void
    1297           0 : GatherCertificateTransparencyTelemetry(const UniqueCERTCertList& certList,
    1298             :                                        bool isEV,
    1299             :                                        const CertificateTransparencyInfo& info)
    1300             : {
    1301           0 :   if (!info.enabled) {
    1302             :     // No telemetry is gathered when CT is disabled.
    1303           0 :     return;
    1304             :   }
    1305             : 
    1306           0 :   for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) {
    1307           0 :     GatherTelemetryForSingleSCT(sct);
    1308             :   }
    1309             : 
    1310             :   // Decoding errors are reported to the 0th bucket
    1311             :   // of the SSL_SCTS_VERIFICATION_STATUS enumerated probe.
    1312           0 :   for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) {
    1313           0 :     Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 0);
    1314             :   }
    1315             : 
    1316             :   // Handle the histogram of SCTs counts.
    1317             :   uint32_t sctsCount =
    1318           0 :     static_cast<uint32_t>(info.verifyResult.verifiedScts.length());
    1319             :   // Note that sctsCount can also be 0 in case we've received SCT binary data,
    1320             :   // but it failed to parse (e.g. due to unsupported CT protocol version).
    1321           0 :   Telemetry::Accumulate(Telemetry::SSL_SCTS_PER_CONNECTION, sctsCount);
    1322             : 
    1323             :   // Report CT Policy compliance of EV certificates.
    1324           0 :   if (isEV) {
    1325           0 :     uint32_t evCompliance = 0;
    1326           0 :     switch (info.policyCompliance) {
    1327             :       case ct::CTPolicyCompliance::Compliant:
    1328           0 :         evCompliance = 1;
    1329           0 :         break;
    1330             :       case ct::CTPolicyCompliance::NotEnoughScts:
    1331           0 :         evCompliance = 2;
    1332           0 :         break;
    1333             :       case ct::CTPolicyCompliance::NotDiverseScts:
    1334           0 :         evCompliance = 3;
    1335           0 :         break;
    1336             :       case ct::CTPolicyCompliance::Unknown:
    1337             :       default:
    1338           0 :         MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type");
    1339             :     }
    1340             :     Telemetry::Accumulate(Telemetry::SSL_CT_POLICY_COMPLIANCE_OF_EV_CERTS,
    1341           0 :                           evCompliance);
    1342             :   }
    1343             : 
    1344             :   // Get the root cert.
    1345           0 :   CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
    1346           0 :   MOZ_ASSERT(rootNode);
    1347           0 :   if (!rootNode) {
    1348           0 :     return;
    1349             :   }
    1350           0 :   MOZ_ASSERT(!CERT_LIST_END(rootNode, certList));
    1351           0 :   if (CERT_LIST_END(rootNode, certList)) {
    1352           0 :     return;
    1353             :   }
    1354           0 :   CERTCertificate* rootCert = rootNode->cert;
    1355           0 :   MOZ_ASSERT(rootCert);
    1356           0 :   if (!rootCert) {
    1357           0 :     return;
    1358             :   }
    1359             : 
    1360             :   // Report CT Policy compliance by CA.
    1361           0 :   switch (info.policyCompliance) {
    1362             :     case ct::CTPolicyCompliance::Compliant:
    1363             :       AccumulateTelemetryForRootCA(
    1364           0 :         Telemetry::SSL_CT_POLICY_COMPLIANT_CONNECTIONS_BY_CA, rootCert);
    1365           0 :       break;
    1366             :     case ct::CTPolicyCompliance::NotEnoughScts:
    1367             :     case ct::CTPolicyCompliance::NotDiverseScts:
    1368             :       AccumulateTelemetryForRootCA(
    1369           0 :         Telemetry::SSL_CT_POLICY_NON_COMPLIANT_CONNECTIONS_BY_CA, rootCert);
    1370           0 :       break;
    1371             :     case ct::CTPolicyCompliance::Unknown:
    1372             :     default:
    1373           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type");
    1374             :   }
    1375             : }
    1376             : 
    1377             : // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned.
    1378             : SECStatus
    1379           0 : AuthCertificate(CertVerifier& certVerifier,
    1380             :                 nsNSSSocketInfo* infoObject,
    1381             :                 const UniqueCERTCertificate& cert,
    1382             :                 UniqueCERTCertList& peerCertChain,
    1383             :                 const SECItem* stapledOCSPResponse,
    1384             :                 const SECItem* sctsFromTLSExtension,
    1385             :                 uint32_t providerFlags,
    1386             :                 Time time)
    1387             : {
    1388           0 :   MOZ_ASSERT(infoObject);
    1389           0 :   MOZ_ASSERT(cert);
    1390             : 
    1391             :   // We want to avoid storing any intermediate cert information when browsing
    1392             :   // in private, transient contexts.
    1393             :   bool saveIntermediates =
    1394           0 :     !(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE);
    1395             : 
    1396             :   SECOidTag evOidPolicy;
    1397           0 :   UniqueCERTCertList certList;
    1398             :   CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
    1399           0 :     CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
    1400           0 :   KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
    1401           0 :   SHA1ModeResult sha1ModeResult = SHA1ModeResult::NeverChecked;
    1402           0 :   PinningTelemetryInfo pinningTelemetryInfo;
    1403           0 :   CertificateTransparencyInfo certificateTransparencyInfo;
    1404             : 
    1405           0 :   int flags = 0;
    1406           0 :   if (!infoObject->SharedState().IsOCSPStaplingEnabled() ||
    1407           0 :       !infoObject->SharedState().IsOCSPMustStapleEnabled()) {
    1408           0 :     flags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
    1409             :   }
    1410             : 
    1411           0 :   Result rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
    1412             :                                                sctsFromTLSExtension, time,
    1413             :                                                infoObject,
    1414             :                                                infoObject->GetHostName(),
    1415             :                                                certList, &peerCertChain,
    1416             :                                                saveIntermediates, flags,
    1417             :                                                infoObject->
    1418             :                                                       GetOriginAttributes(),
    1419             :                                                &evOidPolicy,
    1420             :                                                &ocspStaplingStatus,
    1421             :                                                &keySizeStatus, &sha1ModeResult,
    1422             :                                                &pinningTelemetryInfo,
    1423           0 :                                                &certificateTransparencyInfo);
    1424             : 
    1425           0 :   uint32_t evStatus = (rv != Success) ? 0                   // 0 = Failure
    1426           0 :                     : (evOidPolicy == SEC_OID_UNKNOWN) ? 1  // 1 = DV
    1427           0 :                     : 2;                                    // 2 = EV
    1428           0 :   Telemetry::Accumulate(Telemetry::CERT_EV_STATUS, evStatus);
    1429             : 
    1430           0 :   if (ocspStaplingStatus != CertVerifier::OCSP_STAPLING_NEVER_CHECKED) {
    1431           0 :     Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, ocspStaplingStatus);
    1432             :   }
    1433           0 :   if (keySizeStatus != KeySizeStatus::NeverChecked) {
    1434           0 :     Telemetry::Accumulate(Telemetry::CERT_CHAIN_KEY_SIZE_STATUS,
    1435           0 :                           static_cast<uint32_t>(keySizeStatus));
    1436             :   }
    1437           0 :   if (sha1ModeResult != SHA1ModeResult::NeverChecked) {
    1438           0 :     Telemetry::Accumulate(Telemetry::CERT_CHAIN_SHA1_POLICY_STATUS,
    1439           0 :                           static_cast<uint32_t>(sha1ModeResult));
    1440             :   }
    1441             : 
    1442           0 :   if (pinningTelemetryInfo.accumulateForRoot) {
    1443           0 :     Telemetry::Accumulate(Telemetry::CERT_PINNING_FAILURES_BY_CA,
    1444           0 :                           pinningTelemetryInfo.rootBucket);
    1445             :   }
    1446             : 
    1447           0 :   if (pinningTelemetryInfo.accumulateResult) {
    1448           0 :     Telemetry::Accumulate(pinningTelemetryInfo.certPinningResultHistogram,
    1449           0 :                           pinningTelemetryInfo.certPinningResultBucket);
    1450             :   }
    1451             : 
    1452           0 :   if (rv == Success) {
    1453             :     // Certificate verification succeeded. Delete any potential record of
    1454             :     // certificate error bits.
    1455           0 :     RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject,
    1456             :                                                                 nullptr,
    1457           0 :                                                                 SECSuccess);
    1458           0 :     GatherSuccessfulValidationTelemetry(certList);
    1459           0 :     GatherCertificateTransparencyTelemetry(certList,
    1460             :                                   /*isEV*/ evOidPolicy != SEC_OID_UNKNOWN,
    1461           0 :                                            certificateTransparencyInfo);
    1462             : 
    1463             :     // The connection may get terminated, for example, if the server requires
    1464             :     // a client cert. Let's provide a minimal SSLStatus
    1465             :     // to the caller that contains at least the cert and its status.
    1466           0 :     RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
    1467           0 :     if (!status) {
    1468           0 :       status = new nsSSLStatus();
    1469           0 :       infoObject->SetSSLStatus(status);
    1470             :     }
    1471             : 
    1472           0 :     if (!status->HasServerCert()) {
    1473             :       EVStatus evStatus;
    1474           0 :       if (evOidPolicy == SEC_OID_UNKNOWN) {
    1475           0 :         evStatus = EVStatus::NotEV;
    1476             :       } else {
    1477           0 :         evStatus = EVStatus::EV;
    1478             :       }
    1479             : 
    1480           0 :       RefPtr<nsNSSCertificate> nsc = nsNSSCertificate::Create(cert.get());
    1481           0 :       status->SetServerCert(nsc, evStatus);
    1482           0 :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1483             :               ("AuthCertificate setting NEW cert %p", nsc.get()));
    1484             :     }
    1485             : 
    1486           0 :     status->SetCertificateTransparencyInfo(certificateTransparencyInfo);
    1487             :   }
    1488             : 
    1489           0 :   if (rv != Success) {
    1490             :     // Certificate validation failed; store the peer certificate chain on
    1491             :     // infoObject so it can be used for error reporting.
    1492           0 :     infoObject->SetFailedCertChain(Move(peerCertChain));
    1493           0 :     PR_SetError(MapResultToPRErrorCode(rv), 0);
    1494             :   }
    1495             : 
    1496           0 :   return rv == Success ? SECSuccess : SECFailure;
    1497             : }
    1498             : 
    1499             : /*static*/ SECStatus
    1500           0 : SSLServerCertVerificationJob::Dispatch(
    1501             :   const RefPtr<SharedCertVerifier>& certVerifier,
    1502             :   const void* fdForLogging,
    1503             :   nsNSSSocketInfo* infoObject,
    1504             :   const UniqueCERTCertificate& serverCert,
    1505             :   const UniqueCERTCertList& peerCertChain,
    1506             :   const SECItem* stapledOCSPResponse,
    1507             :   const SECItem* sctsFromTLSExtension,
    1508             :   uint32_t providerFlags,
    1509             :   Time time,
    1510             :   PRTime prtime)
    1511             : {
    1512             :   // Runs on the socket transport thread
    1513           0 :   if (!certVerifier || !infoObject || !serverCert) {
    1514           0 :     NS_ERROR("Invalid parameters for SSL server cert validation");
    1515           0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1516           0 :     return SECFailure;
    1517             :   }
    1518             : 
    1519           0 :   if (!gCertVerificationThreadPool) {
    1520           0 :     PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1521           0 :     return SECFailure;
    1522             :   }
    1523             : 
    1524             :   // Copy the certificate list so the runnable can take ownership of it in the
    1525             :   // constructor.
    1526             :   // We can safely skip checking if NSS has already shut down here since we're
    1527             :   // in the middle of verifying a certificate.
    1528           0 :   nsNSSShutDownPreventionLock lock;
    1529             :   UniqueCERTCertList peerCertChainCopy =
    1530           0 :     nsNSSCertList::DupCertList(peerCertChain, lock);
    1531           0 :   if (!peerCertChainCopy) {
    1532           0 :     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
    1533           0 :     return SECFailure;
    1534             :   }
    1535             : 
    1536             :   RefPtr<SSLServerCertVerificationJob> job(
    1537             :     new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject,
    1538           0 :                                      serverCert, Move(peerCertChainCopy),
    1539             :                                      stapledOCSPResponse, sctsFromTLSExtension,
    1540           0 :                                      providerFlags, time, prtime));
    1541             : 
    1542           0 :   nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
    1543           0 :   if (NS_FAILED(nrv)) {
    1544             :     // We can't call SetCertVerificationResult here to change
    1545             :     // mCertVerificationState because SetCertVerificationResult will call
    1546             :     // libssl functions that acquire SSL locks that are already being held at
    1547             :     // this point. However, we can set an error with PR_SetError and return
    1548             :     // SECFailure, and the correct thing will happen (the error will be
    1549             :     // propagated and this connection will be terminated).
    1550             :     PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
    1551             :                       ? PR_OUT_OF_MEMORY_ERROR
    1552           0 :                       : PR_INVALID_STATE_ERROR;
    1553           0 :     PR_SetError(error, 0);
    1554           0 :     return SECFailure;
    1555             :   }
    1556             : 
    1557           0 :   PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
    1558           0 :   return SECWouldBlock;
    1559             : }
    1560             : 
    1561             : NS_IMETHODIMP
    1562           0 : SSLServerCertVerificationJob::Run()
    1563             : {
    1564             :   // Runs on a cert verification thread
    1565             : 
    1566           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1567             :           ("[%p] SSLServerCertVerificationJob::Run\n", mInfoObject.get()));
    1568             : 
    1569             :   PRErrorCode error;
    1570             : 
    1571           0 :   nsNSSShutDownPreventionLock nssShutdownPrevention;
    1572           0 :   if (mInfoObject->isAlreadyShutDown()) {
    1573           0 :     error = SEC_ERROR_USER_CANCELLED;
    1574             :   } else {
    1575             :     Telemetry::HistogramID successTelemetry
    1576           0 :       = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX;
    1577             :     Telemetry::HistogramID failureTelemetry
    1578           0 :       = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX;
    1579             : 
    1580             :     // Reset the error code here so we can detect if AuthCertificate fails to
    1581             :     // set the error code if/when it fails.
    1582           0 :     PR_SetError(0, 0);
    1583           0 :     SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert,
    1584           0 :                                    mPeerCertChain, mStapledOCSPResponse.get(),
    1585           0 :                                    mSCTsFromTLSExtension.get(),
    1586           0 :                                    mProviderFlags, mTime);
    1587           0 :     MOZ_ASSERT(mPeerCertChain || rv != SECSuccess,
    1588             :                "AuthCertificate() should take ownership of chain on failure");
    1589           0 :     if (rv == SECSuccess) {
    1590           0 :       uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds());
    1591             :       RefPtr<SSLServerCertVerificationResult> restart(
    1592             :         new SSLServerCertVerificationResult(mInfoObject, 0,
    1593           0 :                                             successTelemetry, interval));
    1594           0 :       restart->Dispatch();
    1595           0 :       Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
    1596           0 :       return NS_OK;
    1597             :     }
    1598             : 
    1599             :     // Note: the interval is not calculated once as PR_GetError MUST be called
    1600             :     // before any other  function call
    1601           0 :     error = PR_GetError();
    1602             : 
    1603           0 :     TimeStamp now = TimeStamp::Now();
    1604           0 :     Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now);
    1605             : 
    1606           0 :     if (error != 0) {
    1607             :       RefPtr<CertErrorRunnable> runnable(
    1608           0 :           CreateCertErrorRunnable(*mCertVerifier, error, mInfoObject, mCert,
    1609           0 :                                   mFdForLogging, mProviderFlags, mPRTime));
    1610           0 :       if (!runnable) {
    1611             :         // CreateCertErrorRunnable set a new error code
    1612           0 :         error = PR_GetError();
    1613             :       } else {
    1614             :         // We must block the the socket transport service thread while the
    1615             :         // main thread executes the CertErrorRunnable. The CertErrorRunnable
    1616             :         // will dispatch the result asynchronously, so we don't have to block
    1617             :         // this thread waiting for it.
    1618             : 
    1619           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1620             :                 ("[%p][%p] Before dispatching CertErrorRunnable\n",
    1621             :                 mFdForLogging, runnable.get()));
    1622             : 
    1623             :         nsresult nrv;
    1624             :         nsCOMPtr<nsIEventTarget> stsTarget
    1625           0 :           = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
    1626           0 :         if (NS_SUCCEEDED(nrv)) {
    1627           0 :           nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
    1628             :                                     NS_DISPATCH_NORMAL);
    1629             :         }
    1630           0 :         if (NS_SUCCEEDED(nrv)) {
    1631           0 :           return NS_OK;
    1632             :         }
    1633             : 
    1634           0 :         NS_ERROR("Failed to dispatch CertErrorRunnable");
    1635           0 :         error = PR_INVALID_STATE_ERROR;
    1636             :       }
    1637             :     }
    1638             :   }
    1639             : 
    1640           0 :   if (error == 0) {
    1641           0 :     MOZ_ASSERT_UNREACHABLE("No error set during certificate validation failure");
    1642             :     error = PR_INVALID_STATE_ERROR;
    1643             :   }
    1644             : 
    1645             :   RefPtr<SSLServerCertVerificationResult> failure(
    1646           0 :     new SSLServerCertVerificationResult(mInfoObject, error));
    1647           0 :   failure->Dispatch();
    1648           0 :   return NS_OK;
    1649             : }
    1650             : 
    1651             : } // unnamed namespace
    1652             : 
    1653             : // Extracts whatever information we need out of fd (using SSL_*) and passes it
    1654             : // to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
    1655             : // never do anything with fd except logging.
    1656             : SECStatus
    1657           0 : AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
    1658             : {
    1659           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
    1660           0 :   if (!certVerifier) {
    1661           0 :     PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
    1662           0 :     return SECFailure;
    1663             :   }
    1664             : 
    1665             :   // Runs on the socket transport thread
    1666             : 
    1667           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1668             :          ("[%p] starting AuthCertificateHook\n", fd));
    1669             : 
    1670             :   // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
    1671             :   // doing verification without checking signatures.
    1672           0 :   MOZ_ASSERT(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
    1673             : 
    1674             :   // PSM never causes libssl to call this function with PR_TRUE for isServer,
    1675             :   // and many things in PSM assume that we are a client.
    1676           0 :   MOZ_ASSERT(!isServer, "AuthCertificateHook: isServer unexpectedly true");
    1677             : 
    1678           0 :   nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg);
    1679             : 
    1680           0 :   UniqueCERTCertificate serverCert(SSL_PeerCertificate(fd));
    1681             : 
    1682           0 :   if (!checkSig || isServer || !socketInfo || !serverCert) {
    1683           0 :       PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1684           0 :       return SECFailure;
    1685             :   }
    1686             : 
    1687             :   // Get the peer certificate chain for error reporting
    1688           0 :   UniqueCERTCertList peerCertChain(SSL_PeerCertificateChain(fd));
    1689           0 :   if (!peerCertChain) {
    1690           0 :     PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1691           0 :     return SECFailure;
    1692             :   }
    1693             : 
    1694           0 :   socketInfo->SetFullHandshake();
    1695             : 
    1696           0 :   Time now(Now());
    1697           0 :   PRTime prnow(PR_Now());
    1698             : 
    1699           0 :   if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
    1700           0 :     return SECFailure;
    1701             : 
    1702             :   nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
    1703           0 :     NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, socketInfo));
    1704           0 :   if (sslSocketControl && sslSocketControl->GetBypassAuthentication()) {
    1705           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1706             :             ("[%p] Bypass Auth in AuthCertificateHook\n", fd));
    1707           0 :     return SECSuccess;
    1708             :   }
    1709             : 
    1710             :   bool onSTSThread;
    1711             :   nsresult nrv;
    1712             :   nsCOMPtr<nsIEventTarget> sts
    1713           0 :     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
    1714           0 :   if (NS_SUCCEEDED(nrv)) {
    1715           0 :     nrv = sts->IsOnCurrentThread(&onSTSThread);
    1716             :   }
    1717             : 
    1718           0 :   if (NS_FAILED(nrv)) {
    1719           0 :     NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
    1720           0 :     PR_SetError(PR_UNKNOWN_ERROR, 0);
    1721           0 :     return SECFailure;
    1722             :   }
    1723             : 
    1724             :   // SSL_PeerStapledOCSPResponses will never return a non-empty response if
    1725             :   // OCSP stapling wasn't enabled because libssl wouldn't have let the server
    1726             :   // return a stapled OCSP response.
    1727             :   // We don't own these pointers.
    1728           0 :   const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
    1729           0 :   SECItem* stapledOCSPResponse = nullptr;
    1730             :   // we currently only support single stapled responses
    1731           0 :   if (csa && csa->len == 1) {
    1732           0 :     stapledOCSPResponse = &csa->items[0];
    1733             :   }
    1734             : 
    1735           0 :   const SECItem* sctsFromTLSExtension = SSL_PeerSignedCertTimestamps(fd);
    1736           0 :   if (sctsFromTLSExtension && sctsFromTLSExtension->len == 0) {
    1737             :     // SSL_PeerSignedCertTimestamps returns null on error and empty item
    1738             :     // when no extension was returned by the server. We always use null when
    1739             :     // no extension was received (for whatever reason), ignoring errors.
    1740           0 :     sctsFromTLSExtension = nullptr;
    1741             :   }
    1742             : 
    1743           0 :   uint32_t providerFlags = 0;
    1744           0 :   socketInfo->GetProviderFlags(&providerFlags);
    1745             : 
    1746           0 :   if (onSTSThread) {
    1747             : 
    1748             :     // We *must* do certificate verification on a background thread because
    1749             :     // we need the socket transport thread to be free for our OCSP requests,
    1750             :     // and we *want* to do certificate verification on a background thread
    1751             :     // because of the performance benefits of doing so.
    1752           0 :     socketInfo->SetCertVerificationWaiting();
    1753           0 :     SECStatus rv = SSLServerCertVerificationJob::Dispatch(
    1754             :                      certVerifier, static_cast<const void*>(fd), socketInfo,
    1755             :                      serverCert, peerCertChain, stapledOCSPResponse,
    1756           0 :                      sctsFromTLSExtension, providerFlags, now, prnow);
    1757           0 :     return rv;
    1758             :   }
    1759             : 
    1760             :   // We can't do certificate verification on a background thread, because the
    1761             :   // thread doing the network I/O may not interrupt its network I/O on receipt
    1762             :   // of our SSLServerCertVerificationResult event, and/or it might not even be
    1763             :   // a non-blocking socket.
    1764             : 
    1765           0 :   SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert,
    1766             :                                  peerCertChain, stapledOCSPResponse,
    1767           0 :                                  sctsFromTLSExtension, providerFlags, now);
    1768           0 :   MOZ_ASSERT(peerCertChain || rv != SECSuccess,
    1769             :              "AuthCertificate() should take ownership of chain on failure");
    1770           0 :   if (rv == SECSuccess) {
    1771           0 :     Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
    1772           0 :     return SECSuccess;
    1773             :   }
    1774             : 
    1775           0 :   PRErrorCode error = PR_GetError();
    1776           0 :   if (error != 0) {
    1777             :     RefPtr<CertErrorRunnable> runnable(
    1778           0 :         CreateCertErrorRunnable(*certVerifier, error, socketInfo, serverCert,
    1779             :                                 static_cast<const void*>(fd), providerFlags,
    1780           0 :                                 prnow));
    1781           0 :     if (!runnable) {
    1782             :       // CreateCertErrorRunnable sets a new error code when it fails
    1783           0 :       error = PR_GetError();
    1784             :     } else {
    1785             :       // We have to return SECSuccess or SECFailure based on the result of the
    1786             :       // override processing, so we must block this thread waiting for it. The
    1787             :       // CertErrorRunnable will NOT dispatch the result at all, since we passed
    1788             :       // false for CreateCertErrorRunnable's async parameter
    1789           0 :       nrv = runnable->DispatchToMainThreadAndWait();
    1790           0 :       if (NS_FAILED(nrv)) {
    1791           0 :         NS_ERROR("Failed to dispatch CertErrorRunnable");
    1792           0 :         PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1793           0 :         return SECFailure;
    1794             :       }
    1795             : 
    1796           0 :       if (!runnable->mResult) {
    1797           0 :         NS_ERROR("CertErrorRunnable did not set result");
    1798           0 :         PR_SetError(PR_INVALID_STATE_ERROR, 0);
    1799           0 :         return SECFailure;
    1800             :       }
    1801             : 
    1802           0 :       if (runnable->mResult->mErrorCode == 0) {
    1803           0 :         return SECSuccess; // cert error override occurred.
    1804             :       }
    1805             : 
    1806             :       // We must call SetCanceled here to set the error message type
    1807             :       // in case it isn't SSLErrorMessageType::Plain, which is what we would
    1808             :       // default to if we just called
    1809             :       // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
    1810             :       // SECFailure without doing this.
    1811           0 :       socketInfo->SetCanceled(runnable->mResult->mErrorCode,
    1812           0 :                               runnable->mResult->mErrorMessageType);
    1813           0 :       error = runnable->mResult->mErrorCode;
    1814             :     }
    1815             :   }
    1816             : 
    1817           0 :   if (error == 0) {
    1818           0 :     NS_ERROR("error code not set");
    1819           0 :     error = PR_UNKNOWN_ERROR;
    1820             :   }
    1821             : 
    1822           0 :   PR_SetError(error, 0);
    1823           0 :   return SECFailure;
    1824             : }
    1825             : 
    1826           0 : SSLServerCertVerificationResult::SSLServerCertVerificationResult(
    1827             :   nsNSSSocketInfo* infoObject,
    1828             :   PRErrorCode errorCode,
    1829             :   Telemetry::HistogramID telemetryID,
    1830             :   uint32_t telemetryValue,
    1831           0 :   SSLErrorMessageType errorMessageType)
    1832             :   : Runnable("psm::SSLServerCertVerificationResult")
    1833             :   , mInfoObject(infoObject)
    1834             :   , mErrorCode(errorCode)
    1835             :   , mErrorMessageType(errorMessageType)
    1836             :   , mTelemetryID(telemetryID)
    1837           0 :   , mTelemetryValue(telemetryValue)
    1838             : {
    1839             : // We accumulate telemetry for (only) successful validations on the main thread
    1840             : // to avoid adversely affecting performance by acquiring the mutex that we use
    1841             : // when accumulating the telemetry for unsuccessful validations. Unsuccessful
    1842             : // validations times are accumulated elsewhere.
    1843           0 : MOZ_ASSERT(telemetryID == Telemetry::HistogramCount || errorCode == 0);
    1844           0 : }
    1845             : 
    1846             : void
    1847           0 : SSLServerCertVerificationResult::Dispatch()
    1848             : {
    1849             :   nsresult rv;
    1850             :   nsCOMPtr<nsIEventTarget> stsTarget
    1851           0 :     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    1852           0 :   MOZ_ASSERT(stsTarget,
    1853             :              "Failed to get socket transport service event target");
    1854           0 :   rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
    1855           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    1856             :              "Failed to dispatch SSLServerCertVerificationResult");
    1857           0 : }
    1858             : 
    1859             : NS_IMETHODIMP
    1860           0 : SSLServerCertVerificationResult::Run()
    1861             : {
    1862             :   // TODO: Assert that we're on the socket transport thread
    1863           0 :   if (mTelemetryID != Telemetry::HistogramCount) {
    1864           0 :      Telemetry::Accumulate(mTelemetryID, mTelemetryValue);
    1865             :   }
    1866           0 :   mInfoObject->SetCertVerificationResult(mErrorCode, mErrorMessageType);
    1867           0 :   return NS_OK;
    1868             : }
    1869             : 
    1870             : } } // namespace mozilla::psm

Generated by: LCOV version 1.13