tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SSLServerCertVerification.cpp (51866B)


      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 // During certificate authentication, we call CertVerifier::VerifySSLServerCert.
      8 // This function may make zero or more HTTP requests (e.g. to gather revocation
      9 // information). Our fetching logic for these requests processes them on the
     10 // socket transport service thread.
     11 //
     12 // Because the connection for which we are verifying the certificate is
     13 // happening on the socket transport thread, if our cert auth hook were to call
     14 // VerifySSLServerCert directly, there would be a deadlock: VerifySSLServerCert
     15 // would cause an event to be asynchronously posted to the socket transport
     16 // thread, and then it would block the socket transport thread waiting to be
     17 // notified of the HTTP response. However, the HTTP request would never actually
     18 // be processed because the socket transport thread would be blocked and so it
     19 // wouldn't be able process HTTP requests.
     20 //
     21 // Consequently, when we are asked to verify a certificate, we must always call
     22 // VerifySSLServerCert on another thread. To accomplish this, our auth cert hook
     23 // dispatches a SSLServerCertVerificationJob to a pool of background threads,
     24 // and then immediately returns SECWouldBlock to libssl. These jobs are where
     25 // VerifySSLServerCert is actually called.
     26 //
     27 // When our auth cert hook returns SECWouldBlock, libssl will carry on the
     28 // handshake while we validate the certificate. This will free up the socket
     29 // transport thread so that HTTP requests--including the OCSP requests needed
     30 // for cert verification as mentioned above--can be processed.
     31 //
     32 // Once VerifySSLServerCert returns, the cert verification job dispatches a
     33 // SSLServerCertVerificationResult to the socket transport thread; the
     34 // SSLServerCertVerificationResult will notify libssl that the certificate
     35 // authentication is complete. Once libssl is notified that the authentication
     36 // is complete, it will continue the TLS handshake (if it hasn't already
     37 // finished) and it will begin allowing us to send/receive data on the
     38 // connection.
     39 //
     40 // Timeline of events (for connections managed by the socket transport service):
     41 //
     42 //    * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
     43 //      transport thread.
     44 //    * SSLServerCertVerificationJob::Dispatch queues a job
     45 //      (instance of SSLServerCertVerificationJob) to its background thread
     46 //      pool and returns.
     47 //    * One of the background threads calls CertVerifier::VerifySSLServerCert,
     48 //      which may enqueue some HTTP request(s) onto the socket transport thread,
     49 //      and then blocks that background thread waiting for the responses and/or
     50 //      timeouts or errors for those requests.
     51 //    * Once those HTTP responses have all come back or failed, the
     52 //      CertVerifier::VerifySSLServerCert function returns a result indicating
     53 //      that the validation succeeded or failed.
     54 //    * If the validation succeeded, then a SSLServerCertVerificationResult
     55 //      event is posted to the socket transport thread, and the cert
     56 //      verification thread becomes free to verify other certificates.
     57 //    * Otherwise, we do cert override processing to see if the validation
     58 //      error can be convered by override rules. The result of this processing
     59 //      is similarly dispatched in a SSLServerCertVerificationResult.
     60 //    * The SSLServerCertVerificationResult event will either wake up the
     61 //      socket (using SSL_AuthCertificateComplete) if validation succeeded or
     62 //      there was an error override, or it will set an error flag so that the
     63 //      next I/O operation on the socket will fail, causing the socket transport
     64 //      thread to close the connection.
     65 //
     66 // SSLServerCertVerificationResult must be dispatched to the socket transport
     67 // thread because we must only call SSL_* functions on the socket transport
     68 // thread since they may do I/O, because many parts of NSSSocketControl and the
     69 // PSM NSS I/O layer are not thread-safe, and because we need the event to
     70 // interrupt the PR_Poll that may waiting for I/O on the socket for which we
     71 // are validating the cert.
     72 //
     73 // When socket process is enabled, libssl is running on socket process. To
     74 // perform certificate authentication with CertVerifier, we have to send all
     75 // needed information to parent process and send the result back to socket
     76 // process via IPC. The workflow is described below.
     77 // 1. In AuthCertificateHookInternal(), we call RemoteProcessCertVerification()
     78 //    instead of SSLServerCertVerificationJob::Dispatch when we are on socket
     79 //    process.
     80 // 2. In RemoteProcessCertVerification(), PVerifySSLServerCert actors will be
     81 //    created on IPDL background thread for carrying needed information via IPC.
     82 // 3. On parent process, VerifySSLServerCertParent is created and it calls
     83 //    SSLServerCertVerificationJob::Dispatch for doing certificate verification
     84 //    on one of CertVerificationThreads.
     85 // 4. When validation is done, OnVerifiedSSLServerCertSuccess IPC message is
     86 //    sent through the IPDL background thread when
     87 //    CertVerifier::VerifySSLServerCert returns Success. Otherwise,
     88 //    OnVerifiedSSLServerCertFailure is sent.
     89 // 5. After setp 4, PVerifySSLServerCert actors will be released. The
     90 //    verification result will be dispatched via
     91 //    SSLServerCertVerificationResult.
     92 
     93 #include "SSLServerCertVerification.h"
     94 
     95 #include <cstring>
     96 
     97 #include "CertVerifier.h"
     98 #include "CryptoTask.h"
     99 #include "ExtendedValidation.h"
    100 #include "NSSCertDBTrustDomain.h"
    101 #include "NSSSocketControl.h"
    102 #include "PSMRunnable.h"
    103 #include "RootCertificateTelemetryUtils.h"
    104 #include "ScopedNSSTypes.h"
    105 #include "SharedCertVerifier.h"
    106 #include "VerifySSLServerCertChild.h"
    107 #include "cert.h"
    108 #include "mozilla/Assertions.h"
    109 #include "mozilla/RefPtr.h"
    110 #include "mozilla/StaticPrefs_security.h"
    111 #include "mozilla/UniquePtr.h"
    112 #include "mozilla/glean/SecurityManagerSslMetrics.h"
    113 #include "nsComponentManagerUtils.h"
    114 #include "nsContentUtils.h"
    115 #include "nsICertOverrideService.h"
    116 #include "nsIPublicKeyPinningService.h"
    117 #include "nsISiteSecurityService.h"
    118 #include "nsISocketProvider.h"
    119 #include "nsThreadPool.h"
    120 #include "nsNetUtil.h"
    121 #include "nsNSSCertificate.h"
    122 #include "nsNSSComponent.h"
    123 #include "nsNSSIOLayer.h"
    124 #include "nsServiceManagerUtils.h"
    125 #include "nsString.h"
    126 #include "nsURLHelper.h"
    127 #include "nsXPCOMCIDInternal.h"
    128 #include "mozpkix/pkix.h"
    129 #include "mozpkix/pkixcheck.h"
    130 #include "mozpkix/pkixnss.h"
    131 #include "mozpkix/pkixutil.h"
    132 #include "secerr.h"
    133 #include "secport.h"
    134 #include "ssl.h"
    135 #include "sslerr.h"
    136 #include "sslexp.h"
    137 
    138 #include "IOnionAliasService.h"
    139 
    140 extern mozilla::LazyLogModule gPIPNSSLog;
    141 
    142 using namespace mozilla::pkix;
    143 
    144 namespace mozilla {
    145 namespace psm {
    146 
    147 // do not use a nsCOMPtr to avoid static initializer/destructor
    148 nsIThreadPool* gCertVerificationThreadPool = nullptr;
    149 
    150 // Called when the socket transport thread starts, to initialize the SSL cert
    151 // verification thread pool. By tying the thread pool startup/shutdown directly
    152 // to the STS thread's lifetime, we ensure that they are *always* available for
    153 // SSL connections and that there are no races during startup and especially
    154 // shutdown. (Previously, we have had multiple problems with races in PSM
    155 // background threads, and the race-prevention/shutdown logic used there is
    156 // brittle. Since this service is critical to things like downloading updates,
    157 // we take no chances.) Also, by doing things this way, we avoid the need for
    158 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
    159 // transport thread.
    160 void InitializeSSLServerCertVerificationThreads() {
    161  // TODO: tuning, make parameters preferences
    162  gCertVerificationThreadPool = new nsThreadPool();
    163  NS_ADDREF(gCertVerificationThreadPool);
    164 
    165  (void)gCertVerificationThreadPool->SetThreadLimit(5);
    166  (void)gCertVerificationThreadPool->SetIdleThreadLimit(1);
    167  (void)gCertVerificationThreadPool->SetIdleThreadMaximumTimeout(30 * 1000);
    168  (void)gCertVerificationThreadPool->SetIdleThreadGraceTimeout(500);
    169  (void)gCertVerificationThreadPool->SetName("SSL Cert"_ns);
    170 }
    171 
    172 // Called when the socket transport thread finishes, to destroy the thread
    173 // pool. Since the socket transport service has stopped processing events, it
    174 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
    175 // down the SSL cert verification infrastructure. Also, the STS will not
    176 // dispatch many SSL verification result events at this point, so any pending
    177 // cert verifications will (correctly) fail at the point they are dispatched.
    178 //
    179 // The other shutdown race condition that is possible is a race condition with
    180 // shutdown of the nsNSSComponent service. We use the
    181 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
    182 void StopSSLServerCertVerificationThreads() {
    183  if (gCertVerificationThreadPool) {
    184    gCertVerificationThreadPool->Shutdown();
    185    NS_RELEASE(gCertVerificationThreadPool);
    186  }
    187 }
    188 
    189 // A probe value of 1 means "no error".
    190 uint32_t MapOverridableErrorToProbeValue(PRErrorCode errorCode) {
    191  switch (errorCode) {
    192    case SEC_ERROR_UNKNOWN_ISSUER:
    193      return 2;
    194    case SEC_ERROR_CA_CERT_INVALID:
    195      return 3;
    196    case SEC_ERROR_UNTRUSTED_ISSUER:
    197      return 4;
    198    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
    199      return 5;
    200    case SEC_ERROR_UNTRUSTED_CERT:
    201      return 6;
    202    case SEC_ERROR_INADEQUATE_KEY_USAGE:
    203      return 7;
    204    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
    205      return 8;
    206    case SSL_ERROR_BAD_CERT_DOMAIN:
    207      return 9;
    208    case SEC_ERROR_EXPIRED_CERTIFICATE:
    209      return 10;
    210    case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
    211      return 11;
    212    case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
    213      return 12;
    214    case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
    215      return 13;
    216    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
    217      return 14;
    218    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
    219      return 15;
    220    case SEC_ERROR_INVALID_TIME:
    221      return 16;
    222    case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
    223      return 17;
    224    // mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED was
    225    // 18
    226    case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
    227      return 19;
    228    case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
    229      return 20;
    230    case mozilla::pkix::
    231        MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY:
    232      return 21;
    233  }
    234  NS_WARNING(
    235      "Unknown certificate error code. Does MapOverridableErrorToProbeValue "
    236      "handle everything in CategorizeCertificateError?");
    237  return 0;
    238 }
    239 
    240 static uint32_t MapCertErrorToProbeValue(PRErrorCode errorCode) {
    241  uint32_t probeValue;
    242  switch (errorCode) {
    243    // see security/pkix/include/pkix/Result.h
    244 #define MOZILLA_PKIX_MAP(name, value, nss_name) \
    245  case nss_name:                                \
    246    probeValue = value;                         \
    247    break;
    248    MOZILLA_PKIX_MAP_LIST
    249 #undef MOZILLA_PKIX_MAP
    250    default:
    251      return 0;
    252  }
    253 
    254  // Since FATAL_ERROR_FLAG is 0x800, fatal error values are much larger than
    255  // non-fatal error values. To conserve space, we remap these so they start at
    256  // (decimal) 90 instead of 0x800. Currently there are ~50 non-fatal errors
    257  // mozilla::pkix might return, so saving space for 90 should be sufficient
    258  // (similarly, there are 4 fatal errors, so saving space for 10 should also
    259  // be sufficient).
    260  static_assert(
    261      FATAL_ERROR_FLAG == 0x800,
    262      "mozilla::pkix::FATAL_ERROR_FLAG is not what we were expecting");
    263  if (probeValue & FATAL_ERROR_FLAG) {
    264    probeValue ^= FATAL_ERROR_FLAG;
    265    probeValue += 90;
    266  }
    267  return probeValue;
    268 }
    269 
    270 // If the given PRErrorCode is an overridable certificate error, return which
    271 // category (trust, time, domain mismatch) it falls in. If it is not
    272 // overridable, return Nothing.
    273 Maybe<nsITransportSecurityInfo::OverridableErrorCategory>
    274 CategorizeCertificateError(PRErrorCode certificateError) {
    275  switch (certificateError) {
    276    case SEC_ERROR_CA_CERT_INVALID:
    277    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
    278    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
    279    case SEC_ERROR_UNKNOWN_ISSUER:
    280    case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
    281    case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
    282    case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
    283    case mozilla::pkix::
    284        MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY:
    285    case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
    286    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
    287    case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
    288    case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
    289    case mozilla::pkix::MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT:
    290      return Some(
    291          nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST);
    292 
    293    case SSL_ERROR_BAD_CERT_DOMAIN:
    294      return Some(
    295          nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN);
    296 
    297    case SEC_ERROR_EXPIRED_CERTIFICATE:
    298    case SEC_ERROR_INVALID_TIME:
    299    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
    300      return Some(
    301          nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME);
    302 
    303    default:
    304      break;
    305  }
    306  return Nothing();
    307 }
    308 
    309 // Helper function to determine if overrides are allowed for this host.
    310 // Overrides are not allowed for known HSTS hosts or hosts with pinning
    311 // information. However, IP addresses can never be HSTS hosts and don't have
    312 // pinning information.
    313 static nsresult OverrideAllowedForHost(
    314    uint64_t aPtrForLog, const nsACString& aHostname,
    315    const OriginAttributes& aOriginAttributes, /*out*/ bool& aOverrideAllowed) {
    316  aOverrideAllowed = false;
    317 
    318  // If this is an IP address, overrides are allowed, because an IP address is
    319  // never an HSTS host. nsISiteSecurityService takes this into account
    320  // already, but the real problem here is that calling NS_NewURI with an IPv6
    321  // address fails. We do this to avoid that. A more comprehensive fix would be
    322  // to have Necko provide an nsIURI to PSM and to use that here (and
    323  // everywhere). However, that would be a wide-spanning change.
    324  if (net_IsValidIPv6Addr(aHostname)) {
    325    aOverrideAllowed = true;
    326    return NS_OK;
    327  }
    328 
    329  // If this is an HTTP Strict Transport Security host or a pinned host and the
    330  // certificate is bad, don't allow overrides (RFC 6797 section 12.1).
    331  bool strictTransportSecurityEnabled = false;
    332  bool isStaticallyPinned = false;
    333  nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
    334  if (!sss) {
    335    MOZ_LOG(
    336        gPIPNSSLog, LogLevel::Debug,
    337        ("[0x%" PRIx64 "] Couldn't get nsISiteSecurityService to check HSTS",
    338         aPtrForLog));
    339    return NS_ERROR_FAILURE;
    340  }
    341 
    342  nsCOMPtr<nsIURI> uri;
    343  nsresult rv = NS_NewURI(getter_AddRefs(uri), "https://"_ns + aHostname);
    344  if (NS_FAILED(rv)) {
    345    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    346            ("[0x%" PRIx64 "] Creating new URI failed", aPtrForLog));
    347    return rv;
    348  }
    349 
    350  rv =
    351      sss->IsSecureURI(uri, aOriginAttributes, &strictTransportSecurityEnabled);
    352  if (NS_FAILED(rv)) {
    353    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    354            ("[0x%" PRIx64 "] checking for HSTS failed", aPtrForLog));
    355    return rv;
    356  }
    357 
    358  nsCOMPtr<nsIPublicKeyPinningService> pkps =
    359      do_GetService(NS_PKPSERVICE_CONTRACTID, &rv);
    360  if (!pkps) {
    361    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    362            ("[0x%" PRIx64
    363             "] Couldn't get nsIPublicKeyPinningService to check pinning",
    364             aPtrForLog));
    365    return NS_ERROR_FAILURE;
    366  }
    367  rv = pkps->HostHasPins(uri, &isStaticallyPinned);
    368  if (NS_FAILED(rv)) {
    369    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    370            ("[0x%" PRIx64 "] checking for static pin failed", aPtrForLog));
    371    return rv;
    372  }
    373 
    374  aOverrideAllowed = !strictTransportSecurityEnabled && !isStaticallyPinned;
    375  return NS_OK;
    376 }
    377 
    378 // This function assumes that we will only use the SPDY connection coalescing
    379 // feature on connections where we have negotiated SPDY using NPN. If we ever
    380 // talk SPDY without having negotiated it with SPDY, this code will give wrong
    381 // and perhaps unsafe results.
    382 //
    383 // Returns SECSuccess on the initial handshake of all connections, on
    384 // renegotiations for any connections where we did not negotiate SPDY, or on any
    385 // SPDY connection where the server's certificate did not change.
    386 //
    387 // Prohibit changing the server cert only if we negotiated SPDY,
    388 // in order to support SPDY's cross-origin connection pooling.
    389 static SECStatus BlockServerCertChangeForSpdy(
    390    NSSSocketControl* socketControl, const UniqueCERTCertificate& serverCert) {
    391  if (!socketControl->IsHandshakeCompleted()) {
    392    // first handshake on this connection, not a
    393    // renegotiation.
    394    return SECSuccess;
    395  }
    396 
    397  // Filter out sockets that did not neogtiate SPDY via NPN
    398  nsCOMPtr<nsITransportSecurityInfo> securityInfo;
    399  nsresult rv = socketControl->GetSecurityInfo(getter_AddRefs(securityInfo));
    400  MOZ_ASSERT(NS_SUCCEEDED(rv), "GetSecurityInfo() failed during renegotiation");
    401  if (NS_FAILED(rv) || !securityInfo) {
    402    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
    403    return SECFailure;
    404  }
    405  nsAutoCString negotiatedNPN;
    406  rv = securityInfo->GetNegotiatedNPN(negotiatedNPN);
    407  MOZ_ASSERT(NS_SUCCEEDED(rv),
    408             "GetNegotiatedNPN() failed during renegotiation");
    409 
    410  if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, "spdy/"_ns)) {
    411    return SECSuccess;
    412  }
    413  // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
    414  if (NS_FAILED(rv)) {
    415    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    416            ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
    417             " Assuming spdy."));
    418  }
    419 
    420  // Check to see if the cert has actually changed
    421  nsCOMPtr<nsIX509Cert> cert(socketControl->GetServerCert());
    422  if (!cert) {
    423    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
    424    return SECFailure;
    425  }
    426  nsTArray<uint8_t> certDER;
    427  if (NS_FAILED(cert->GetRawDER(certDER))) {
    428    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
    429    return SECFailure;
    430  }
    431  if (certDER.Length() == serverCert->derCert.len &&
    432      memcmp(certDER.Elements(), serverCert->derCert.data, certDER.Length()) ==
    433          0) {
    434    return SECSuccess;
    435  }
    436 
    437  // Report an error - changed cert is confirmed
    438  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    439          ("SPDY refused to allow new cert during renegotiation"));
    440  PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
    441  return SECFailure;
    442 }
    443 
    444 void GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct) {
    445  // See scts_verification_status in metrics.yaml.
    446  uint32_t verificationStatus = 0;
    447  switch (verifiedSct.logState) {
    448    case ct::CTLogState::Admissible:
    449      verificationStatus = 1;
    450      break;
    451    case ct::CTLogState::Retired:
    452      verificationStatus = 5;
    453      break;
    454  }
    455  glean::ssl::scts_verification_status.AccumulateSingleSample(
    456      verificationStatus);
    457 }
    458 
    459 void GatherCertificateTransparencyTelemetry(
    460    const nsTArray<uint8_t>& rootCert,
    461    const CertificateTransparencyInfo& info) {
    462  if (!info.enabled) {
    463    // No telemetry is gathered when CT is disabled.
    464    return;
    465  }
    466 
    467  for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) {
    468    GatherTelemetryForSingleSCT(sct);
    469  }
    470 
    471  // See scts_verification_status in metrics.yaml.
    472  for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) {
    473    glean::ssl::scts_verification_status.AccumulateSingleSample(0);
    474  }
    475  for (size_t i = 0; i < info.verifyResult.sctsFromUnknownLogs; ++i) {
    476    glean::ssl::scts_verification_status.AccumulateSingleSample(2);
    477  }
    478  for (size_t i = 0; i < info.verifyResult.sctsWithInvalidSignatures; ++i) {
    479    glean::ssl::scts_verification_status.AccumulateSingleSample(3);
    480  }
    481  for (size_t i = 0; i < info.verifyResult.sctsWithInvalidTimestamps; ++i) {
    482    glean::ssl::scts_verification_status.AccumulateSingleSample(4);
    483  }
    484  for (size_t i = 0; i < info.verifyResult.sctsWithDistrustedTimestamps; ++i) {
    485    glean::ssl::scts_verification_status.AccumulateSingleSample(6);
    486  }
    487 
    488  // See scts_origin in metrics.yaml.
    489  for (size_t i = 0; i < info.verifyResult.embeddedSCTs; ++i) {
    490    glean::ssl::scts_origin.AccumulateSingleSample(1);
    491  }
    492  for (size_t i = 0; i < info.verifyResult.sctsFromTLSHandshake; ++i) {
    493    glean::ssl::scts_origin.AccumulateSingleSample(2);
    494  }
    495  for (size_t i = 0; i < info.verifyResult.sctsFromOCSP; ++i) {
    496    glean::ssl::scts_origin.AccumulateSingleSample(3);
    497  }
    498 
    499  // Handle the histogram of SCTs counts.
    500  uint32_t sctsCount =
    501      static_cast<uint32_t>(info.verifyResult.verifiedScts.size());
    502  // Note that sctsCount can also be 0 in case we've received SCT binary data,
    503  // but it failed to parse (e.g. due to unsupported CT protocol version).
    504  glean::ssl::scts_per_connection.AccumulateSingleSample(sctsCount);
    505 
    506  uint32_t sctsFromTiledLogs = 0;
    507  for (auto verifiedSCT : info.verifyResult.verifiedScts) {
    508    if (verifiedSCT.logFormat == ct::CTLogFormat::Tiled) {
    509      sctsFromTiledLogs++;
    510    }
    511  }
    512  glean::ssl::scts_from_tiled_logs_per_connection.AccumulateSingleSample(
    513      sctsFromTiledLogs);
    514 
    515  // Report CT Policy compliance by CA.
    516  if (info.policyCompliance.isSome() &&
    517      *info.policyCompliance != ct::CTPolicyCompliance::Compliant) {
    518    int32_t binId = RootCABinNumber(rootCert);
    519    if (binId != ROOT_CERTIFICATE_HASH_FAILURE) {
    520      glean::ssl::ct_policy_non_compliant_connections_by_ca_2
    521          .AccumulateSingleSample(binId);
    522    }
    523  }
    524 }
    525 
    526 // This function collects telemetry about certs. It will be called on one of
    527 // CertVerificationThread. When the socket process is used this will be called
    528 // on the parent process.
    529 static void CollectCertTelemetry(
    530    mozilla::pkix::Result aCertVerificationResult, EVStatus aEVStatus,
    531    CertVerifier::OCSPStaplingStatus aOcspStaplingStatus,
    532    KeySizeStatus aKeySizeStatus,
    533    const PinningTelemetryInfo& aPinningTelemetryInfo,
    534    const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
    535    const CertificateTransparencyInfo& aCertificateTransparencyInfo,
    536    const IssuerSources& issuerSources) {
    537  uint32_t evStatus = (aCertVerificationResult != Success) ? 0  // 0 = Failure
    538                      : (aEVStatus != EVStatus::EV)        ? 1  // 1 = DV
    539                                                           : 2;        // 2 = EV
    540  glean::cert::ev_status.AccumulateSingleSample(evStatus);
    541 
    542  if (aOcspStaplingStatus != CertVerifier::OCSP_STAPLING_NEVER_CHECKED) {
    543    glean::ssl::ocsp_stapling.AccumulateSingleSample(aOcspStaplingStatus);
    544  }
    545 
    546  if (aKeySizeStatus != KeySizeStatus::NeverChecked) {
    547    glean::cert::chain_key_size_status.AccumulateSingleSample(
    548        static_cast<uint32_t>(aKeySizeStatus));
    549  }
    550 
    551  if (aPinningTelemetryInfo.accumulateForRoot) {
    552    glean::cert_pinning::failures_by_ca_2.AccumulateSingleSample(
    553        aPinningTelemetryInfo.rootBucket);
    554  }
    555 
    556  if (aPinningTelemetryInfo.accumulateResult) {
    557    if (aPinningTelemetryInfo.isMoz) {
    558      if (aPinningTelemetryInfo.testMode) {
    559        glean::cert_pinning::moz_test_results_by_host.AccumulateSingleSample(
    560            aPinningTelemetryInfo.certPinningResultBucket);
    561      } else {
    562        glean::cert_pinning::moz_results_by_host.AccumulateSingleSample(
    563            aPinningTelemetryInfo.certPinningResultBucket);
    564      }
    565    } else {
    566      if (aPinningTelemetryInfo.testMode) {
    567        glean::cert_pinning::test_results
    568            .EnumGet(static_cast<glean::cert_pinning::TestResultsLabel>(
    569                aPinningTelemetryInfo.certPinningResultBucket))
    570            .Add();
    571      } else {
    572        glean::cert_pinning::results
    573            .EnumGet(static_cast<glean::cert_pinning::ResultsLabel>(
    574                aPinningTelemetryInfo.certPinningResultBucket))
    575            .Add();
    576      }
    577    }
    578  }
    579 
    580  if (aCertVerificationResult == Success && aBuiltCertChain.Length() > 0) {
    581    const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement();
    582    int32_t binId = RootCABinNumber(rootCert);
    583    if (binId != ROOT_CERTIFICATE_HASH_FAILURE) {
    584      glean::cert::validation_success_by_ca_2.AccumulateSingleSample(binId);
    585    }
    586 
    587    mozilla::glean::tls::certificate_verifications.Add(1);
    588    if (issuerSources.contains(IssuerSource::TLSHandshake)) {
    589      mozilla::glean::verification_used_cert_from::tls_handshake.AddToNumerator(
    590          1);
    591    }
    592    if (issuerSources.contains(IssuerSource::PreloadedIntermediates)) {
    593      mozilla::glean::verification_used_cert_from::preloaded_intermediates
    594          .AddToNumerator(1);
    595    }
    596    if (issuerSources.contains(IssuerSource::ThirdPartyCertificates)) {
    597      mozilla::glean::verification_used_cert_from::third_party_certificates
    598          .AddToNumerator(1);
    599    }
    600    if (issuerSources.contains(IssuerSource::NSSCertDB)) {
    601      mozilla::glean::verification_used_cert_from::nss_cert_db.AddToNumerator(
    602          1);
    603    }
    604    if (issuerSources.contains(IssuerSource::BuiltInRootsModule)) {
    605      mozilla::glean::verification_used_cert_from::built_in_roots_module
    606          .AddToNumerator(1);
    607    }
    608  }
    609 
    610  if ((aCertVerificationResult == Success ||
    611       aCertVerificationResult ==
    612           Result::ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY) &&
    613      aBuiltCertChain.Length() > 0) {
    614    const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement();
    615    GatherCertificateTransparencyTelemetry(rootCert,
    616                                           aCertificateTransparencyInfo);
    617  }
    618 }
    619 
    620 // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned.
    621 Result AuthCertificate(
    622    CertVerifier& certVerifier, void* aPinArg,
    623    const nsTArray<uint8_t>& certBytes,
    624    const nsTArray<nsTArray<uint8_t>>& peerCertChain,
    625    const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
    626    const Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
    627    const Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
    628    const Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
    629    Time time, uint32_t certVerifierFlags,
    630    /*out*/ nsTArray<nsTArray<uint8_t>>& builtCertChain,
    631    /*out*/ EVStatus& evStatus,
    632    /*out*/ CertificateTransparencyInfo& certificateTransparencyInfo,
    633    /*out*/ bool& aIsBuiltCertChainRootBuiltInRoot,
    634    /*out*/ bool& aMadeOCSPRequests) {
    635  CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
    636      CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
    637  KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
    638  PinningTelemetryInfo pinningTelemetryInfo;
    639 
    640  nsTArray<nsTArray<uint8_t>> peerCertsBytes;
    641  // Don't include the end-entity certificate.
    642  if (!peerCertChain.IsEmpty()) {
    643    std::transform(
    644        peerCertChain.cbegin() + 1, peerCertChain.cend(),
    645        MakeBackInserter(peerCertsBytes),
    646        [](const auto& elementArray) { return elementArray.Clone(); });
    647  }
    648 
    649  IssuerSources issuerSources;
    650  Result rv = certVerifier.VerifySSLServerCert(
    651      certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
    652      Some(std::move(peerCertsBytes)), stapledOCSPResponse,
    653      sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
    654      &ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo,
    655      &certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot,
    656      &aMadeOCSPRequests, &issuerSources);
    657 
    658  CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
    659                       pinningTelemetryInfo, builtCertChain,
    660                       certificateTransparencyInfo, issuerSources);
    661 
    662  return rv;
    663 }
    664 
    665 /**
    666 * Check if the self-signed onion certificate error can be overridden by another
    667 * error.
    668 *
    669 * Basically, this function restore part of the old functionalities of
    670 * DetermineCertOverrideErrors, before it was changed in Bug 1781104.
    671 */
    672 static PRErrorCode OverrideOnionSelfSignedError(
    673    const nsCOMPtr<nsIX509Cert>& aCert, const nsACString& aHostName,
    674    mozilla::pkix::Time aNow, PRErrorCode aCertVerificationError) {
    675  nsTArray<uint8_t> certDER;
    676  if (NS_FAILED(aCert->GetRawDER(certDER))) {
    677    return SEC_ERROR_LIBRARY_FAILURE;
    678  }
    679  mozilla::pkix::Input certInput;
    680  if (certInput.Init(certDER.Elements(), certDER.Length()) != Success) {
    681    return SEC_ERROR_BAD_DER;
    682  }
    683 
    684  // First, check the hostname.
    685  {
    686    Input hostnameInput;
    687    Result result = hostnameInput.Init(
    688        BitwiseCast<const uint8_t*, const char*>(aHostName.BeginReading()),
    689        aHostName.Length());
    690    if (result != Success) {
    691      return SEC_ERROR_INVALID_ARGS;
    692    }
    693    result = CheckCertHostname(certInput, hostnameInput);
    694    if (result == Result::ERROR_BAD_DER ||
    695        result == Result::ERROR_BAD_CERT_DOMAIN) {
    696      aCertVerificationError = SSL_ERROR_BAD_CERT_DOMAIN;
    697    } else if (IsFatalError(result)) {
    698      // This should be then mapped to a fatal error by
    699      // CategorizeCertificateError.
    700      return MapResultToPRErrorCode(result);
    701    }
    702  }
    703 
    704  // Then, check if the certificate has expired.
    705  {
    706    mozilla::pkix::BackCert backCert(
    707        certInput, mozilla::pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
    708    Result rv = backCert.Init();
    709    if (rv != Success) {
    710      PR_SetError(MapResultToPRErrorCode(rv), 0);
    711      return SECFailure;
    712    }
    713    mozilla::pkix::Time notBefore(mozilla::pkix::Time::uninitialized);
    714    mozilla::pkix::Time notAfter(mozilla::pkix::Time::uninitialized);
    715    // If the validity can't be parsed, ParseValidity will return
    716    // Result::ERROR_INVALID_DER_TIME.
    717    rv = mozilla::pkix::ParseValidity(backCert.GetValidity(), &notBefore,
    718                                      &notAfter);
    719    if (rv != Success) {
    720      return MapResultToPRErrorCode(rv);
    721    }
    722    // If `now` is outside of the certificate's validity period,
    723    // CheckValidity will return Result::ERROR_NOT_YET_VALID_CERTIFICATE or
    724    // Result::ERROR_EXPIRED_CERTIFICATE, as appropriate, and Success
    725    // otherwise.
    726    rv = mozilla::pkix::CheckValidity(aNow, notBefore, notAfter);
    727    if (rv != Success) {
    728      return MapResultToPRErrorCode(rv);
    729    }
    730  }
    731 
    732  // If we arrive here, the cert is okay, just self-signed, so return the
    733  // original error.
    734  return aCertVerificationError;
    735 }
    736 
    737 PRErrorCode AuthCertificateParseResults(
    738    uint64_t aPtrForLog, const nsACString& aHostName, int32_t aPort,
    739    const OriginAttributes& aOriginAttributes,
    740    const nsCOMPtr<nsIX509Cert>& aCert, mozilla::pkix::Time aTime,
    741    PRErrorCode aCertVerificationError,
    742    /* out */
    743    nsITransportSecurityInfo::OverridableErrorCategory&
    744        aOverridableErrorCategory) {
    745  uint32_t probeValue = MapCertErrorToProbeValue(aCertVerificationError);
    746  glean::ssl::cert_verification_errors.AccumulateSingleSample(probeValue);
    747 
    748  if (aCertVerificationError ==
    749      mozilla::pkix::MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT) {
    750    aCertVerificationError = OverrideOnionSelfSignedError(
    751        aCert, aHostName, aTime, aCertVerificationError);
    752  }
    753 
    754  Maybe<nsITransportSecurityInfo::OverridableErrorCategory>
    755      maybeOverridableErrorCategory =
    756          CategorizeCertificateError(aCertVerificationError);
    757  // If this isn't an overridable error, return it now. This will stop the
    758  // connection and report the given error.
    759  if (!maybeOverridableErrorCategory.isSome()) {
    760    return aCertVerificationError;
    761  }
    762  aOverridableErrorCategory = *maybeOverridableErrorCategory;
    763 
    764  bool overrideAllowed = false;
    765  nsresult rv = OverrideAllowedForHost(aPtrForLog, aHostName, aOriginAttributes,
    766                                       overrideAllowed);
    767  if (NS_FAILED(rv)) {
    768    return aCertVerificationError;
    769  }
    770 
    771  if (!overrideAllowed) {
    772    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    773            ("[0x%" PRIx64 "] HSTS or pinned host - no overrides allowed",
    774             aPtrForLog));
    775    return aCertVerificationError;
    776  }
    777 
    778  nsCOMPtr<nsICertOverrideService> overrideService =
    779      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
    780  if (!overrideService) {
    781    return aCertVerificationError;
    782  }
    783  bool haveOverride;
    784  bool isTemporaryOverride;
    785  rv = overrideService->HasMatchingOverride(aHostName, aPort, aOriginAttributes,
    786                                            aCert, &isTemporaryOverride,
    787                                            &haveOverride);
    788  if (NS_FAILED(rv)) {
    789    return aCertVerificationError;
    790  }
    791  (void)isTemporaryOverride;
    792  if (haveOverride) {
    793    uint32_t probeValue =
    794        MapOverridableErrorToProbeValue(aCertVerificationError);
    795    glean::ssl::cert_error_overrides.AccumulateSingleSample(probeValue);
    796    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    797            ("[0x%" PRIx64 "] certificate error overridden", aPtrForLog));
    798    return 0;
    799  }
    800 
    801  return aCertVerificationError;
    802 }
    803 
    804 static nsTArray<nsTArray<uint8_t>> CreateCertBytesArray(
    805    const UniqueSECItemArray& aCertChain) {
    806  nsTArray<nsTArray<uint8_t>> certsBytes;
    807  for (size_t i = 0; i < aCertChain->len; i++) {
    808    nsTArray<uint8_t> certBytes;
    809    certBytes.AppendElements(aCertChain->items[i].data,
    810                             aCertChain->items[i].len);
    811    certsBytes.AppendElement(std::move(certBytes));
    812  }
    813  return certsBytes;
    814 }
    815 
    816 /*static*/
    817 SECStatus SSLServerCertVerificationJob::Dispatch(
    818    uint64_t addrForLogging, void* aPinArg,
    819    nsTArray<nsTArray<uint8_t>>&& peerCertChain, const nsACString& aHostName,
    820    int32_t aPort, const OriginAttributes& aOriginAttributes,
    821    Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
    822    Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
    823    Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, Time time,
    824    uint32_t certVerifierFlags,
    825    BaseSSLServerCertVerificationResult* aResultTask) {
    826  // Runs on the socket transport thread
    827  if (!aResultTask || peerCertChain.IsEmpty()) {
    828    MOZ_ASSERT_UNREACHABLE(
    829        "must have result task and non-empty peer cert chain");
    830    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
    831    return SECFailure;
    832  }
    833 
    834  if (!gCertVerificationThreadPool) {
    835    PR_SetError(PR_INVALID_STATE_ERROR, 0);
    836    return SECFailure;
    837  }
    838 
    839  RefPtr<SSLServerCertVerificationJob> job(new SSLServerCertVerificationJob(
    840      addrForLogging, aPinArg, std::move(peerCertChain), aHostName, aPort,
    841      aOriginAttributes, stapledOCSPResponse, sctsFromTLSExtension, dcInfo,
    842      providerFlags, time, certVerifierFlags, aResultTask));
    843 
    844  nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
    845  if (NS_FAILED(nrv)) {
    846    // We can't call SetCertVerificationResult here to change
    847    // mCertVerificationState because SetCertVerificationResult will call
    848    // libssl functions that acquire SSL locks that are already being held at
    849    // this point. However, we can set an error with PR_SetError and return
    850    // SECFailure, and the correct thing will happen (the error will be
    851    // propagated and this connection will be terminated).
    852    PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY ? PR_OUT_OF_MEMORY_ERROR
    853                                                      : PR_INVALID_STATE_ERROR;
    854    PR_SetError(error, 0);
    855    return SECFailure;
    856  }
    857 
    858  PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
    859  return SECWouldBlock;
    860 }
    861 
    862 void SSLServerCertVerificationJob::FixOnionAlias() {
    863  if (StringEndsWith(mHostName, ".tor.onion"_ns)) {
    864    nsCOMPtr<IOnionAliasService> oas = do_GetService(ONIONALIAS_CID);
    865    oas->GetOnionAlias(mHostName, mHostName);
    866  }
    867 }
    868 
    869 NS_IMETHODIMP
    870 SSLServerCertVerificationJob::Run() {
    871  // Runs on a cert verification thread and only on parent process.
    872  MOZ_ASSERT(XRE_IsParentProcess());
    873 
    874  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    875          ("[%" PRIx64 "] SSLServerCertVerificationJob::Run", mAddrForLogging));
    876 
    877  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
    878  if (!certVerifier) {
    879    // We can't release this off the STS thread because some parts of it
    880    // are not threadsafe. Just leak mResultTask.
    881    mResultTask.forget().leak();
    882    return NS_ERROR_FAILURE;
    883  }
    884 
    885  TimeStamp jobStartTime = TimeStamp::Now();
    886  EVStatus evStatus;
    887  CertificateTransparencyInfo certificateTransparencyInfo;
    888  bool isCertChainRootBuiltInRoot = false;
    889  bool madeOCSPRequests = false;
    890  nsTArray<nsTArray<uint8_t>> builtChainBytesArray;
    891  nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
    892  Result result = AuthCertificate(
    893      *certVerifier, mPinArg, certBytes, mPeerCertChain, mHostName,
    894      mOriginAttributes, mStapledOCSPResponse, mSCTsFromTLSExtension, mDCInfo,
    895      mProviderFlags, mTime, mCertVerifierFlags, builtChainBytesArray, evStatus,
    896      certificateTransparencyInfo, isCertChainRootBuiltInRoot,
    897      madeOCSPRequests);
    898 
    899  TimeDuration elapsed = TimeStamp::Now() - jobStartTime;
    900  if (result == Success) {
    901    mozilla::glean::cert_verification_time::success.AccumulateRawDuration(
    902        elapsed);
    903    glean::ssl::cert_error_overrides.AccumulateSingleSample(1);
    904 
    905    nsresult rv = mResultTask->Dispatch(
    906        std::move(builtChainBytesArray), std::move(mPeerCertChain),
    907        TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
    908            certificateTransparencyInfo),
    909        evStatus, true, 0,
    910        nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET,
    911        isCertChainRootBuiltInRoot, mProviderFlags, madeOCSPRequests);
    912    if (NS_FAILED(rv)) {
    913      // We can't release this off the STS thread because some parts of it
    914      // are not threadsafe. Just leak mResultTask.
    915      mResultTask.forget().leak();
    916    }
    917    return rv;
    918  }
    919 
    920  mozilla::glean::cert_verification_time::failure.AccumulateRawDuration(
    921      elapsed);
    922 
    923  PRErrorCode error = MapResultToPRErrorCode(result);
    924  nsITransportSecurityInfo::OverridableErrorCategory overridableErrorCategory =
    925      nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET;
    926  nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
    927  PRErrorCode finalError = AuthCertificateParseResults(
    928      mAddrForLogging, mHostName, mPort, mOriginAttributes, cert, mTime, error,
    929      overridableErrorCategory);
    930 
    931  // NB: finalError may be 0 here, in which the connection will continue.
    932  nsresult rv = mResultTask->Dispatch(
    933      std::move(builtChainBytesArray), std::move(mPeerCertChain),
    934      TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
    935          certificateTransparencyInfo),
    936      EVStatus::NotEV, false, finalError, overridableErrorCategory,
    937      // If the certificate verifier returned Result::ERROR_BAD_CERT_DOMAIN,
    938      // a chain was built, so isCertChainRootBuiltInRoot is valid and
    939      // potentially useful. Otherwise, assume no chain was built.
    940      result == Result::ERROR_BAD_CERT_DOMAIN ? isCertChainRootBuiltInRoot
    941                                              : false,
    942      mProviderFlags, madeOCSPRequests);
    943  if (NS_FAILED(rv)) {
    944    // We can't release this off the STS thread because some parts of it
    945    // are not threadsafe. Just leak mResultTask.
    946    mResultTask.forget().leak();
    947  }
    948  return rv;
    949 }
    950 
    951 // Takes information needed for cert verification, does some consistency
    952 //  checks and calls SSLServerCertVerificationJob::Dispatch.
    953 SECStatus AuthCertificateHookInternal(
    954    CommonSocketControl* socketControl, const void* aPtrForLogging,
    955    const nsACString& hostName, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
    956    Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
    957    Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
    958    Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
    959    uint32_t certVerifierFlags) {
    960  // Runs on the socket transport thread
    961 
    962  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    963          ("[%p] starting AuthCertificateHookInternal\n", aPtrForLogging));
    964 
    965  if (!socketControl || peerCertChain.IsEmpty()) {
    966    PR_SetError(PR_INVALID_STATE_ERROR, 0);
    967    return SECFailure;
    968  }
    969 
    970  bool onSTSThread;
    971  nsresult nrv;
    972  nsCOMPtr<nsIEventTarget> sts =
    973      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
    974  if (NS_SUCCEEDED(nrv)) {
    975    nrv = sts->IsOnCurrentThread(&onSTSThread);
    976  }
    977 
    978  if (NS_FAILED(nrv)) {
    979    NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
    980    PR_SetError(PR_UNKNOWN_ERROR, 0);
    981    return SECFailure;
    982  }
    983 
    984  MOZ_ASSERT(onSTSThread);
    985 
    986  if (!onSTSThread) {
    987    PR_SetError(PR_INVALID_STATE_ERROR, 0);
    988    return SECFailure;
    989  }
    990 
    991  uint64_t addr = reinterpret_cast<uintptr_t>(aPtrForLogging);
    992  RefPtr<SSLServerCertVerificationResult> resultTask =
    993      new SSLServerCertVerificationResult(socketControl);
    994 
    995  if (XRE_IsSocketProcess()) {
    996    return RemoteProcessCertVerification(
    997        std::move(peerCertChain), hostName, socketControl->GetPort(),
    998        socketControl->GetOriginAttributes(), stapledOCSPResponse,
    999        sctsFromTLSExtension, dcInfo, providerFlags, certVerifierFlags,
   1000        resultTask);
   1001  }
   1002 
   1003  // We *must* do certificate verification on a background thread because
   1004  // we need the socket transport thread to be free for our OCSP requests,
   1005  // and we *want* to do certificate verification on a background thread
   1006  // because of the performance benefits of doing so.
   1007  return SSLServerCertVerificationJob::Dispatch(
   1008      addr, socketControl, std::move(peerCertChain), hostName,
   1009      socketControl->GetPort(), socketControl->GetOriginAttributes(),
   1010      stapledOCSPResponse, sctsFromTLSExtension, dcInfo, providerFlags, Now(),
   1011      certVerifierFlags, resultTask);
   1012 }
   1013 
   1014 // Extracts whatever information we need out of fd (using SSL_*) and passes it
   1015 // to AuthCertificateHookInternal. AuthCertificateHookInternal will call
   1016 // SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob
   1017 // should never do anything with fd except logging.
   1018 SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig,
   1019                              PRBool isServer) {
   1020  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1021          ("[%p] starting AuthCertificateHook\n", fd));
   1022 
   1023  // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
   1024  // doing verification without checking signatures.
   1025  MOZ_ASSERT(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
   1026 
   1027  // PSM never causes libssl to call this function with PR_TRUE for isServer,
   1028  // and many things in PSM assume that we are a client.
   1029  MOZ_ASSERT(!isServer, "AuthCertificateHook: isServer unexpectedly true");
   1030 
   1031  NSSSocketControl* socketInfo = static_cast<NSSSocketControl*>(arg);
   1032 
   1033  UniqueCERTCertificate serverCert(SSL_PeerCertificate(fd));
   1034 
   1035  if (!checkSig || isServer || !socketInfo || !serverCert) {
   1036    PR_SetError(PR_INVALID_STATE_ERROR, 0);
   1037    return SECFailure;
   1038  }
   1039  socketInfo->SetFullHandshake();
   1040 
   1041  if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) {
   1042    return SECFailure;
   1043  }
   1044 
   1045  UniqueSECItemArray peerCertChain;
   1046  SECStatus rv =
   1047      SSL_PeerCertificateChainDER(fd, TempPtrToSetter(&peerCertChain));
   1048  if (rv != SECSuccess) {
   1049    PR_SetError(PR_INVALID_STATE_ERROR, 0);
   1050    return SECFailure;
   1051  }
   1052  MOZ_ASSERT(peerCertChain,
   1053             "AuthCertificateHook: peerCertChain unexpectedly null");
   1054 
   1055  nsTArray<nsTArray<uint8_t>> peerCertsBytes =
   1056      CreateCertBytesArray(peerCertChain);
   1057 
   1058  // SSL_PeerStapledOCSPResponses will never return a non-empty response if
   1059  // OCSP stapling wasn't enabled because libssl wouldn't have let the server
   1060  // return a stapled OCSP response.
   1061  // We don't own these pointers.
   1062  const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
   1063  Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
   1064  // we currently only support single stapled responses
   1065  if (csa && csa->len == 1) {
   1066    stapledOCSPResponse.emplace();
   1067    stapledOCSPResponse->SetCapacity(csa->items[0].len);
   1068    stapledOCSPResponse->AppendElements(csa->items[0].data, csa->items[0].len);
   1069  }
   1070 
   1071  Maybe<nsTArray<uint8_t>> sctsFromTLSExtension;
   1072  const SECItem* sctsFromTLSExtensionSECItem = SSL_PeerSignedCertTimestamps(fd);
   1073  if (sctsFromTLSExtensionSECItem) {
   1074    sctsFromTLSExtension.emplace();
   1075    sctsFromTLSExtension->SetCapacity(sctsFromTLSExtensionSECItem->len);
   1076    sctsFromTLSExtension->AppendElements(sctsFromTLSExtensionSECItem->data,
   1077                                         sctsFromTLSExtensionSECItem->len);
   1078  }
   1079 
   1080  uint32_t providerFlags = 0;
   1081  socketInfo->GetProviderFlags(&providerFlags);
   1082 
   1083  uint32_t certVerifierFlags = 0;
   1084  if (!StaticPrefs::security_ssl_enable_ocsp_stapling() ||
   1085      !StaticPrefs::security_ssl_enable_ocsp_must_staple()) {
   1086    certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
   1087  }
   1088 
   1089  // Get DC information
   1090  Maybe<DelegatedCredentialInfo> dcInfo;
   1091  SSLPreliminaryChannelInfo channelPreInfo;
   1092  rv = SSL_GetPreliminaryChannelInfo(fd, &channelPreInfo,
   1093                                     sizeof(channelPreInfo));
   1094  if (rv != SECSuccess) {
   1095    PR_SetError(PR_INVALID_STATE_ERROR, 0);
   1096    return SECFailure;
   1097  }
   1098  if (channelPreInfo.peerDelegCred) {
   1099    dcInfo.emplace(DelegatedCredentialInfo(channelPreInfo.signatureScheme,
   1100                                           channelPreInfo.authKeyBits));
   1101  }
   1102 
   1103  // If we configured an ECHConfig and NSS returned the public name
   1104  // for verification, ECH was rejected. Proceed, verifying to the
   1105  // public name. The result determines how NSS will fail (i.e. with
   1106  // any provided retry_configs if successful). See draft-ietf-tls-esni-08.
   1107  nsCString echConfig;
   1108  nsresult nsrv = socketInfo->GetEchConfig(echConfig);
   1109  bool verifyToEchPublicName =
   1110      NS_SUCCEEDED(nsrv) && echConfig.Length() && channelPreInfo.echPublicName;
   1111 
   1112  const nsCString echPublicName(channelPreInfo.echPublicName);
   1113  const nsACString& hostname =
   1114      verifyToEchPublicName ? echPublicName : socketInfo->GetHostName();
   1115  socketInfo->SetCertVerificationWaiting();
   1116  rv = AuthCertificateHookInternal(socketInfo, static_cast<const void*>(fd),
   1117                                   hostname, std::move(peerCertsBytes),
   1118                                   stapledOCSPResponse, sctsFromTLSExtension,
   1119                                   dcInfo, providerFlags, certVerifierFlags);
   1120  return rv;
   1121 }
   1122 
   1123 // Takes information needed for cert verification, does some consistency
   1124 // checks and calls SSLServerCertVerificationJob::Dispatch.
   1125 // This function is used for Quic.
   1126 SECStatus AuthCertificateHookWithInfo(
   1127    CommonSocketControl* socketControl, const nsACString& aHostName,
   1128    const void* aPtrForLogging, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
   1129    Maybe<nsTArray<nsTArray<uint8_t>>>& stapledOCSPResponses,
   1130    Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, uint32_t providerFlags) {
   1131  if (peerCertChain.IsEmpty()) {
   1132    PR_SetError(PR_INVALID_STATE_ERROR, 0);
   1133    return SECFailure;
   1134  }
   1135 
   1136  // we currently only support single stapled responses
   1137  Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
   1138  if (stapledOCSPResponses && (stapledOCSPResponses->Length() == 1)) {
   1139    stapledOCSPResponse.emplace(stapledOCSPResponses->ElementAt(0).Clone());
   1140  }
   1141 
   1142  uint32_t certVerifierFlags = 0;
   1143  if (!StaticPrefs::security_ssl_enable_ocsp_stapling() ||
   1144      !StaticPrefs::security_ssl_enable_ocsp_must_staple()) {
   1145    certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
   1146  }
   1147 
   1148  // Need to update Quic stack to reflect the PreliminaryInfo fields
   1149  // for Delegated Credentials.
   1150  Maybe<DelegatedCredentialInfo> dcInfo;
   1151 
   1152  return AuthCertificateHookInternal(socketControl, aPtrForLogging, aHostName,
   1153                                     std::move(peerCertChain),
   1154                                     stapledOCSPResponse, sctsFromTLSExtension,
   1155                                     dcInfo, providerFlags, certVerifierFlags);
   1156 }
   1157 
   1158 NS_IMPL_ISUPPORTS_INHERITED0(SSLServerCertVerificationResult, Runnable)
   1159 
   1160 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
   1161    CommonSocketControl* socketControl)
   1162    : Runnable("psm::SSLServerCertVerificationResult"),
   1163      mSocketControl(socketControl),
   1164      mCertificateTransparencyStatus(0),
   1165      mEVStatus(EVStatus::NotEV),
   1166      mSucceeded(false),
   1167      mFinalError(0),
   1168      mOverridableErrorCategory(
   1169          nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET),
   1170      mProviderFlags(0) {}
   1171 
   1172 nsresult SSLServerCertVerificationResult::Dispatch(
   1173    nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
   1174    nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
   1175    uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
   1176    bool aSucceeded, PRErrorCode aFinalError,
   1177    nsITransportSecurityInfo::OverridableErrorCategory
   1178        aOverridableErrorCategory,
   1179    bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
   1180    bool aMadeOCSPRequests) {
   1181  mBuiltChain = std::move(aBuiltChain);
   1182  mPeerCertChain = std::move(aPeerCertChain);
   1183  mCertificateTransparencyStatus = aCertificateTransparencyStatus;
   1184  mEVStatus = aEVStatus;
   1185  mSucceeded = aSucceeded;
   1186  mFinalError = aFinalError;
   1187  mOverridableErrorCategory = aOverridableErrorCategory;
   1188  mIsBuiltCertChainRootBuiltInRoot = aIsBuiltCertChainRootBuiltInRoot;
   1189  mProviderFlags = aProviderFlags;
   1190  mMadeOCSPRequests = aMadeOCSPRequests;
   1191 
   1192  if (mSucceeded &&
   1193      (mBuiltChain.IsEmpty() || mFinalError != 0 ||
   1194       mOverridableErrorCategory !=
   1195           nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET)) {
   1196    MOZ_ASSERT_UNREACHABLE(
   1197        "if certificate verification succeeded without overridden errors, the "
   1198        "built chain shouldn't be empty and any error bits should be unset");
   1199    mSucceeded = false;
   1200    mFinalError = SEC_ERROR_LIBRARY_FAILURE;
   1201  }
   1202  // Note that mSucceeded can be false while mFinalError is 0, in which case
   1203  // the connection will proceed.
   1204  if (!mSucceeded && mPeerCertChain.IsEmpty()) {
   1205    MOZ_ASSERT_UNREACHABLE(
   1206        "if certificate verification failed, the peer chain shouldn't be "
   1207        "empty");
   1208    mFinalError = SEC_ERROR_LIBRARY_FAILURE;
   1209  }
   1210 
   1211  nsresult rv;
   1212  nsCOMPtr<nsIEventTarget> stsTarget =
   1213      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
   1214  MOZ_ASSERT(stsTarget, "Failed to get socket transport service event target");
   1215  if (!stsTarget) {
   1216    // This has to be released on STS; just leak it
   1217    mSocketControl.forget().leak();
   1218    return NS_ERROR_FAILURE;
   1219  }
   1220  rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
   1221  MOZ_ASSERT(NS_SUCCEEDED(rv),
   1222             "Failed to dispatch SSLServerCertVerificationResult");
   1223  return rv;
   1224 }
   1225 
   1226 NS_IMETHODIMP
   1227 SSLServerCertVerificationResult::Run() {
   1228 #ifdef DEBUG
   1229  bool onSTSThread = false;
   1230  nsresult nrv;
   1231  nsCOMPtr<nsIEventTarget> sts =
   1232      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
   1233  if (NS_SUCCEEDED(nrv)) {
   1234    nrv = sts->IsOnCurrentThread(&onSTSThread);
   1235  }
   1236 
   1237  MOZ_ASSERT(onSTSThread);
   1238 #endif
   1239 
   1240  mSocketControl->SetMadeOCSPRequests(mMadeOCSPRequests);
   1241  mSocketControl->SetIsBuiltCertChainRootBuiltInRoot(
   1242      mIsBuiltCertChainRootBuiltInRoot);
   1243  mSocketControl->SetCertificateTransparencyStatus(
   1244      mCertificateTransparencyStatus);
   1245 
   1246  if (mSucceeded) {
   1247    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1248            ("SSLServerCertVerificationResult::Run setting NEW cert"));
   1249    nsTArray<uint8_t> certBytes(mBuiltChain.ElementAt(0).Clone());
   1250    nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
   1251    mSocketControl->SetServerCert(cert, mEVStatus);
   1252    mSocketControl->SetSucceededCertChain(std::move(mBuiltChain));
   1253  } else {
   1254    nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
   1255    nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
   1256    mSocketControl->SetServerCert(cert, EVStatus::NotEV);
   1257    if (mOverridableErrorCategory !=
   1258        nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET) {
   1259      mSocketControl->SetStatusErrorBits(mOverridableErrorCategory);
   1260    }
   1261  }
   1262 
   1263  mSocketControl->SetHandshakeCertificates(std::move(mPeerCertChain));
   1264  mSocketControl->SetCertVerificationResult(mFinalError);
   1265  // Release this reference to the socket control so that it will be freed on
   1266  // the socket thread.
   1267  mSocketControl = nullptr;
   1268  return NS_OK;
   1269 }
   1270 
   1271 }  // namespace psm
   1272 }  // namespace mozilla