tor-browser

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

nsNSSIOLayer.cpp (72211B)


      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 #include "nsNSSIOLayer.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 #include <vector>
     12 
     13 #include "NSSCertDBTrustDomain.h"
     14 #include "NSSErrorsService.h"
     15 #include "NSSSocketControl.h"
     16 #include "PSMRunnable.h"
     17 #include "SSLServerCertVerification.h"
     18 #include "ScopedNSSTypes.h"
     19 #include "TLSClientAuthCertSelection.h"
     20 #include "keyhi.h"
     21 #include "mozilla/Base64.h"
     22 #include "mozilla/Logging.h"
     23 #include "mozilla/Preferences.h"
     24 #include "mozilla/RandomNum.h"
     25 #include "mozilla/ScopeExit.h"
     26 #include "mozilla/StaticPrefs_security.h"
     27 #include "mozilla/glean/SecurityManagerSslMetrics.h"
     28 #include "mozilla/net/SSLTokensCache.h"
     29 #include "mozilla/net/SocketProcessChild.h"
     30 #include "mozilla/psm/IPCClientCertsChild.h"
     31 #include "mozilla/psm/mozilla_abridged_certs_generated.h"
     32 #include "mozilla/psm/PIPCClientCertsChild.h"
     33 #include "mozpkix/pkixnss.h"
     34 #include "mozpkix/pkixtypes.h"
     35 #include "mozpkix/pkixutil.h"
     36 #include "nsArray.h"
     37 #include "nsArrayUtils.h"
     38 #include "nsCRT.h"
     39 #include "nsCharSeparatedTokenizer.h"
     40 #include "nsClientAuthRemember.h"
     41 #include "nsContentUtils.h"
     42 #include "nsISocketProvider.h"
     43 #include "nsIWebProgressListener.h"
     44 #include "nsNSSComponent.h"
     45 #include "nsNSSHelper.h"
     46 #include "nsPrintfCString.h"
     47 #include "nsServiceManagerUtils.h"
     48 #include "prmem.h"
     49 #include "prnetdb.h"
     50 #include "secder.h"
     51 #include "secerr.h"
     52 #include "ssl.h"
     53 #include "sslerr.h"
     54 #include "sslexp.h"
     55 #include "sslproto.h"
     56 #include "zlib.h"
     57 #include "brotli/decode.h"
     58 #include "zstd/zstd.h"
     59 
     60 #if defined(__arm__)
     61 #  include "mozilla/arm.h"
     62 #endif
     63 
     64 #ifdef MOZ_WIDGET_ANDROID
     65 #  include "mozilla/java/ClientAuthCertificateManagerWrappers.h"
     66 #endif  // MOZ_WIDGET_ANDROID
     67 
     68 using namespace mozilla;
     69 using namespace mozilla::psm;
     70 using namespace mozilla::ipc;
     71 
     72 // #define DEBUG_SSL_VERBOSE //Enable this define to get minimal
     73 //  reports when doing SSL read/write
     74 
     75 // #define DUMP_BUFFER  //Enable this define along with
     76 //  DEBUG_SSL_VERBOSE to dump SSL
     77 //  read/write buffer to a log.
     78 //  Uses PR_LOG except on Mac where
     79 //  we always write out to our own
     80 //  file.
     81 
     82 namespace {
     83 
     84 // The NSSSocketInfo tls flags are meant to be opaque to most calling
     85 // applications but provide a mechanism for direct TLS manipulation when
     86 // experimenting with new features in the scope of a single socket. They do not
     87 // create a persistent ABI.
     88 //
     89 // Use of these flags creates a new 'sharedSSLState' so existing states for
     90 // intolerance are not carried to sockets that use these flags (and intolerance
     91 // they discover does not impact other normal sockets not using the flags.)
     92 //
     93 // Their current definitions are:
     94 //
     95 // bits 0-2 (mask 0x07) specify the max tls version
     96 //          0 means no override 1->4 are 1.0, 1.1, 1.2, 1.3, 4->7 unused
     97 // bits 3-5 (mask 0x38) specify the tls fallback limit
     98 //          0 means no override, values 1->4 match prefs
     99 // bit    6 (mask 0x40) was used to specify compat mode. Temporarily reserved.
    100 
    101 enum {
    102  kTLSProviderFlagMaxVersion10 = 0x01,
    103  kTLSProviderFlagMaxVersion11 = 0x02,
    104  kTLSProviderFlagMaxVersion12 = 0x03,
    105  kTLSProviderFlagMaxVersion13 = 0x04,
    106 };
    107 
    108 static uint32_t getTLSProviderFlagMaxVersion(uint32_t flags) {
    109  return (flags & 0x07);
    110 }
    111 
    112 static uint32_t getTLSProviderFlagFallbackLimit(uint32_t flags) {
    113  return (flags & 0x38) >> 3;
    114 }
    115 
    116 void getSiteKey(const nsACString& hostName, uint16_t port,
    117                /*out*/ nsACString& key) {
    118  key = hostName;
    119  key.AppendLiteral(":");
    120  key.AppendInt(port);
    121 }
    122 
    123 }  // unnamed namespace
    124 
    125 extern LazyLogModule gPIPNSSLog;
    126 
    127 namespace {
    128 
    129 enum Operation { reading, writing, not_reading_or_writing };
    130 
    131 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
    132                       PRFileDesc* ssl_layer_fd, NSSSocketControl* socketInfo);
    133 
    134 NSSSocketControl* getSocketInfoIfRunning(PRFileDesc* fd, Operation op) {
    135  if (!fd || !fd->lower || !fd->secret ||
    136      fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
    137    NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
    138    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    139    return nullptr;
    140  }
    141 
    142  NSSSocketControl* socketInfo = (NSSSocketControl*)fd->secret;
    143 
    144  if (socketInfo->IsCanceled()) {
    145    PRErrorCode err = socketInfo->GetErrorCode();
    146    PR_SetError(err, 0);
    147    if (op == reading || op == writing) {
    148      // We must do TLS intolerance checks for reads and writes, for timeouts
    149      // in particular.
    150      (void)checkHandshake(-1, op == reading, fd, socketInfo);
    151    }
    152 
    153    // If we get here, it is probably because cert verification failed and this
    154    // is the first I/O attempt since that failure.
    155    return nullptr;
    156  }
    157 
    158  return socketInfo;
    159 }
    160 
    161 }  // namespace
    162 
    163 static PRStatus nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
    164                                    PRIntervalTime timeout) {
    165  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    166          ("[%p] connecting SSL socket\n", (void*)fd));
    167  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
    168 
    169  PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
    170  if (status != PR_SUCCESS) {
    171    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    172            ("[%p] Lower layer connect error: %d\n", (void*)fd, PR_GetError()));
    173    return status;
    174  }
    175 
    176  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Connect\n", (void*)fd));
    177  return status;
    178 }
    179 
    180 void nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
    181                                                    uint16_t port,
    182                                                    uint16_t tolerant) {
    183  nsCString key;
    184  getSiteKey(hostName, port, key);
    185 
    186  MutexAutoLock lock(mutex);
    187 
    188  IntoleranceEntry entry;
    189  if (mTLSIntoleranceInfo.Get(key, &entry)) {
    190    entry.AssertInvariant();
    191    entry.tolerant = std::max(entry.tolerant, tolerant);
    192    if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
    193      entry.intolerant = entry.tolerant + 1;
    194      entry.intoleranceReason = 0;  // lose the reason
    195    }
    196  } else {
    197    entry.tolerant = tolerant;
    198    entry.intolerant = 0;
    199    entry.intoleranceReason = 0;
    200  }
    201 
    202  entry.AssertInvariant();
    203 
    204  mTLSIntoleranceInfo.InsertOrUpdate(key, entry);
    205 }
    206 
    207 void nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
    208                                            uint16_t port) {
    209  nsCString key;
    210  getSiteKey(hostName, port, key);
    211 
    212  MutexAutoLock lock(mutex);
    213 
    214  IntoleranceEntry entry;
    215  if (mTLSIntoleranceInfo.Get(key, &entry)) {
    216    entry.AssertInvariant();
    217 
    218    entry.intolerant = 0;
    219    entry.intoleranceReason = 0;
    220 
    221    entry.AssertInvariant();
    222    mTLSIntoleranceInfo.InsertOrUpdate(key, entry);
    223  }
    224 }
    225 
    226 bool nsSSLIOLayerHelpers::fallbackLimitReached(const nsACString& hostName,
    227                                               uint16_t intolerant) {
    228  if (isInsecureFallbackSite(hostName)) {
    229    return intolerant <= SSL_LIBRARY_VERSION_TLS_1_0;
    230  }
    231  return intolerant <= mVersionFallbackLimit;
    232 }
    233 
    234 // returns true if we should retry the handshake
    235 bool nsSSLIOLayerHelpers::rememberIntolerantAtVersion(
    236    const nsACString& hostName, uint16_t port, uint16_t minVersion,
    237    uint16_t intolerant, PRErrorCode intoleranceReason) {
    238  if (intolerant <= minVersion || fallbackLimitReached(hostName, intolerant)) {
    239    // We can't fall back any further. Assume that intolerance isn't the issue.
    240    forgetIntolerance(hostName, port);
    241    return false;
    242  }
    243 
    244  nsCString key;
    245  getSiteKey(hostName, port, key);
    246 
    247  MutexAutoLock lock(mutex);
    248 
    249  IntoleranceEntry entry;
    250  if (mTLSIntoleranceInfo.Get(key, &entry)) {
    251    entry.AssertInvariant();
    252    if (intolerant <= entry.tolerant) {
    253      // We already know the server is tolerant at an equal or higher version.
    254      return false;
    255    }
    256    if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
    257      // We already know that the server is intolerant at a lower version.
    258      return true;
    259    }
    260  } else {
    261    entry.tolerant = 0;
    262  }
    263 
    264  entry.intolerant = intolerant;
    265  entry.intoleranceReason = intoleranceReason;
    266  entry.AssertInvariant();
    267  mTLSIntoleranceInfo.InsertOrUpdate(key, entry);
    268 
    269  return true;
    270 }
    271 
    272 void nsSSLIOLayerHelpers::adjustForTLSIntolerance(
    273    const nsACString& hostName, uint16_t port,
    274    /*in/out*/ SSLVersionRange& range) {
    275  IntoleranceEntry entry;
    276 
    277  {
    278    nsCString key;
    279    getSiteKey(hostName, port, key);
    280 
    281    MutexAutoLock lock(mutex);
    282    if (!mTLSIntoleranceInfo.Get(key, &entry)) {
    283      return;
    284    }
    285  }
    286 
    287  entry.AssertInvariant();
    288 
    289  if (entry.intolerant != 0) {
    290    // We've tried connecting at a higher range but failed, so try at the
    291    // version we haven't tried yet, unless we have reached the minimum.
    292    if (range.min < entry.intolerant) {
    293      range.max = entry.intolerant - 1;
    294    }
    295  }
    296 }
    297 
    298 PRErrorCode nsSSLIOLayerHelpers::getIntoleranceReason(
    299    const nsACString& hostName, uint16_t port) {
    300  IntoleranceEntry entry;
    301 
    302  {
    303    nsCString key;
    304    getSiteKey(hostName, port, key);
    305 
    306    MutexAutoLock lock(mutex);
    307    if (!mTLSIntoleranceInfo.Get(key, &entry)) {
    308      return 0;
    309    }
    310  }
    311 
    312  entry.AssertInvariant();
    313  return entry.intoleranceReason;
    314 }
    315 
    316 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
    317 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
    318 PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
    319 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
    320 PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
    321 
    322 static PRStatus nsSSLIOLayerClose(PRFileDesc* fd) {
    323  if (!fd) {
    324    return PR_FAILURE;
    325  }
    326 
    327  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Shutting down socket", fd));
    328 
    329  // Take the owning reference from the layer. See the corresponding comment in
    330  // nsSSLIOLayerAddToSocket where this gets set.
    331  RefPtr<NSSSocketControl> socketInfo(
    332      already_AddRefed((NSSSocketControl*)fd->secret));
    333  fd->secret = nullptr;
    334  if (!socketInfo) {
    335    return PR_FAILURE;
    336  }
    337 
    338  return socketInfo->CloseSocketAndDestroy();
    339 }
    340 
    341 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
    342 // Dumps a (potentially binary) buffer using SSM_DEBUG.  (We could have used
    343 // the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
    344 #  define DUMPBUF_LINESIZE 24
    345 static void nsDumpBuffer(unsigned char* buf, int len) {
    346  char hexbuf[DUMPBUF_LINESIZE * 3 + 1];
    347  char chrbuf[DUMPBUF_LINESIZE + 1];
    348  static const char* hex = "0123456789abcdef";
    349  int i = 0;
    350  int l = 0;
    351  char ch;
    352  char* c;
    353  char* h;
    354  if (len == 0) return;
    355  hexbuf[DUMPBUF_LINESIZE * 3] = '\0';
    356  chrbuf[DUMPBUF_LINESIZE] = '\0';
    357  (void)memset(hexbuf, 0x20, DUMPBUF_LINESIZE * 3);
    358  (void)memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
    359  h = hexbuf;
    360  c = chrbuf;
    361 
    362  while (i < len) {
    363    ch = buf[i];
    364 
    365    if (l == DUMPBUF_LINESIZE) {
    366      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
    367      (void)memset(hexbuf, 0x20, DUMPBUF_LINESIZE * 3);
    368      (void)memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
    369      h = hexbuf;
    370      c = chrbuf;
    371      l = 0;
    372    }
    373 
    374    // Convert a character to hex.
    375    *h++ = hex[(ch >> 4) & 0xf];
    376    *h++ = hex[ch & 0xf];
    377    h++;
    378 
    379    // Put the character (if it's printable) into the character buffer.
    380    if ((ch >= 0x20) && (ch <= 0x7e)) {
    381      *c++ = ch;
    382    } else {
    383      *c++ = '.';
    384    }
    385    i++;
    386    l++;
    387  }
    388  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
    389 }
    390 
    391 #  define DEBUG_DUMP_BUFFER(buf, len) nsDumpBuffer(buf, len)
    392 #else
    393 #  define DEBUG_DUMP_BUFFER(buf, len)
    394 #endif
    395 
    396 namespace {
    397 
    398 uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err) {
    399  // returns a numeric code for where we track various errors in telemetry
    400  // only errors that cause version fallback are tracked,
    401  // so this is also used to determine which errors can cause version fallback
    402  switch (err) {
    403    case SSL_ERROR_BAD_MAC_ALERT:
    404      return 1;
    405    case SSL_ERROR_BAD_MAC_READ:
    406      return 2;
    407    case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
    408      return 3;
    409    case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
    410      return 4;
    411    case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
    412      return 6;
    413    case SSL_ERROR_NO_CYPHER_OVERLAP:
    414      return 7;
    415    case SSL_ERROR_UNSUPPORTED_VERSION:
    416      return 10;
    417    case SSL_ERROR_PROTOCOL_VERSION_ALERT:
    418      return 11;
    419    case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
    420      return 13;
    421    case SSL_ERROR_DECODE_ERROR_ALERT:
    422      return 14;
    423    case PR_CONNECT_RESET_ERROR:
    424      return 16;
    425    case PR_END_OF_FILE_ERROR:
    426      return 17;
    427    case SSL_ERROR_INTERNAL_ERROR_ALERT:
    428      return 18;
    429    default:
    430      return 0;
    431  }
    432 }
    433 
    434 bool retryDueToTLSIntolerance(PRErrorCode err, NSSSocketControl* socketInfo) {
    435  // This function is supposed to decide which error codes should
    436  // be used to conclude server is TLS intolerant.
    437  // Note this only happens during the initial SSL handshake.
    438 
    439  if (StaticPrefs::security_tls_ech_disable_grease_on_fallback() &&
    440      socketInfo->GetEchExtensionStatus() == EchExtensionStatus::kGREASE) {
    441    // Don't record any intolerances if we used ECH GREASE but force a retry.
    442    return true;
    443  }
    444 
    445  if (!socketInfo->IsPreliminaryHandshakeDone() &&
    446      !socketInfo->HasTls13HandshakeSecrets() && socketInfo->SentMlkemShare()) {
    447    nsAutoCString errorName;
    448    const char* prErrorName = PR_ErrorToName(err);
    449    if (prErrorName) {
    450      errorName.AppendASCII(prErrorName);
    451    }
    452    mozilla::glean::tls::xyber_intolerance_reason.Get(errorName).Add(1);
    453    // Don't record version intolerance if we sent mlkem768x25519, just force a
    454    // retry.
    455    return true;
    456  }
    457 
    458  SSLVersionRange range = socketInfo->GetTLSVersionRange();
    459 
    460  if (err == SSL_ERROR_UNSUPPORTED_VERSION &&
    461      range.min == SSL_LIBRARY_VERSION_TLS_1_0) {
    462    socketInfo->SetSecurityState(nsIWebProgressListener::STATE_IS_INSECURE |
    463                                 nsIWebProgressListener::STATE_USES_SSL_3);
    464  }
    465 
    466  // NSS will return SSL_ERROR_RX_MALFORMED_SERVER_HELLO if anti-downgrade
    467  // detected the downgrade.
    468  if (err == SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT ||
    469      err == SSL_ERROR_RX_MALFORMED_SERVER_HELLO) {
    470    // This is a clear signal that we've fallen back too many versions.  Treat
    471    // this as a hard failure, but forget any intolerance so that later attempts
    472    // don't use this version (i.e., range.max) and trigger the error again.
    473 
    474    // First, track the original cause of the version fallback.  This uses the
    475    // same buckets as the telemetry below, except that bucket 0 will include
    476    // all cases where there wasn't an original reason.
    477    PRErrorCode originalReason = socketInfo->GetTLSIntoleranceReason();
    478    glean::ssl::version_fallback_inappropriate.AccumulateSingleSample(
    479        tlsIntoleranceTelemetryBucket(originalReason));
    480 
    481    socketInfo->ForgetTLSIntolerance();
    482 
    483    return false;
    484  }
    485 
    486  // When not using a proxy we'll see a connection reset error.
    487  // When using a proxy, we'll see an end of file error.
    488 
    489  // Don't allow STARTTLS connections to fall back on connection resets or
    490  // EOF.
    491  if ((err == PR_CONNECT_RESET_ERROR || err == PR_END_OF_FILE_ERROR) &&
    492      socketInfo->GetForSTARTTLS()) {
    493    return false;
    494  }
    495 
    496  uint32_t reason = tlsIntoleranceTelemetryBucket(err);
    497  if (reason == 0) {
    498    return false;
    499  }
    500 
    501  // The difference between _PRE and _POST represents how often we avoided
    502  // TLS intolerance fallback due to remembered tolerance.
    503 
    504  switch (range.max) {
    505    case SSL_LIBRARY_VERSION_TLS_1_3:
    506      glean::ssl::tls13_intolerance_reason_pre.AccumulateSingleSample(reason);
    507      break;
    508    case SSL_LIBRARY_VERSION_TLS_1_2:
    509      glean::ssl::tls12_intolerance_reason_pre.AccumulateSingleSample(reason);
    510      break;
    511    case SSL_LIBRARY_VERSION_TLS_1_1:
    512      glean::ssl::tls11_intolerance_reason_pre.AccumulateSingleSample(reason);
    513      break;
    514    case SSL_LIBRARY_VERSION_TLS_1_0:
    515      glean::ssl::tls10_intolerance_reason_pre.AccumulateSingleSample(reason);
    516      break;
    517    default:
    518      MOZ_CRASH("impossible TLS version");
    519      return false;
    520  }
    521 
    522  if (!socketInfo->RememberTLSIntolerant(err)) {
    523    return false;
    524  }
    525 
    526  switch (range.max) {
    527    case SSL_LIBRARY_VERSION_TLS_1_3:
    528      glean::ssl::tls13_intolerance_reason_post.AccumulateSingleSample(reason);
    529      break;
    530    case SSL_LIBRARY_VERSION_TLS_1_2:
    531      glean::ssl::tls12_intolerance_reason_post.AccumulateSingleSample(reason);
    532      break;
    533    case SSL_LIBRARY_VERSION_TLS_1_1:
    534      glean::ssl::tls11_intolerance_reason_post.AccumulateSingleSample(reason);
    535      break;
    536    case SSL_LIBRARY_VERSION_TLS_1_0:
    537      glean::ssl::tls10_intolerance_reason_post.AccumulateSingleSample(reason);
    538      break;
    539    default:
    540      MOZ_CRASH("impossible TLS version");
    541      return false;
    542  }
    543 
    544  return true;
    545 }
    546 
    547 // Ensure that we haven't added too many errors to fit.
    548 static_assert((SSL_ERROR_END_OF_LIST - SSL_ERROR_BASE) <= 256,
    549              "too many SSL errors");
    550 static_assert((SEC_ERROR_END_OF_LIST - SEC_ERROR_BASE) <= 256,
    551              "too many SEC errors");
    552 static_assert((PR_MAX_ERROR - PR_NSPR_ERROR_BASE) <= 128,
    553              "too many NSPR errors");
    554 static_assert((mozilla::pkix::ERROR_BASE - mozilla::pkix::END_OF_LIST) < 31,
    555              "too many moz::pkix errors");
    556 
    557 static void reportHandshakeResult(int32_t bytesTransferred, bool wasReading,
    558                                  PRErrorCode err,
    559                                  NSSSocketControl* socketInfo) {
    560  uint32_t bucket;
    561 
    562  // A negative bytesTransferred or a 0 read are errors.
    563  if (bytesTransferred > 0) {
    564    bucket = 0;
    565  } else if ((bytesTransferred == 0) && !wasReading) {
    566    // PR_Write() is defined to never return 0, but let's make sure.
    567    // https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/PR_Write.
    568    MOZ_ASSERT(false);
    569    bucket = 671;
    570  } else if (IS_SSL_ERROR(err)) {
    571    bucket = err - SSL_ERROR_BASE;
    572    MOZ_ASSERT(bucket > 0);  // SSL_ERROR_EXPORT_ONLY_SERVER isn't used.
    573  } else if (IS_SEC_ERROR(err)) {
    574    bucket = (err - SEC_ERROR_BASE) + 256;
    575  } else if ((err >= PR_NSPR_ERROR_BASE) && (err < PR_MAX_ERROR)) {
    576    bucket = (err - PR_NSPR_ERROR_BASE) + 512;
    577  } else if ((err >= mozilla::pkix::ERROR_BASE) &&
    578             (err < mozilla::pkix::ERROR_LIMIT)) {
    579    bucket = (err - mozilla::pkix::ERROR_BASE) + 640;
    580  } else {
    581    bucket = 671;
    582  }
    583 
    584  uint32_t flags = socketInfo->GetProviderFlags();
    585  if (!(flags & nsISocketProvider::IS_RETRY)) {
    586    glean::ssl_handshake::result_first_try.AccumulateSingleSample(bucket);
    587  }
    588 
    589  if (flags & nsISocketProvider::BE_CONSERVATIVE) {
    590    glean::ssl_handshake::result_conservative.AccumulateSingleSample(bucket);
    591  }
    592 
    593  switch (socketInfo->GetEchExtensionStatus()) {
    594    case EchExtensionStatus::kGREASE:
    595      glean::ssl_handshake::result_ech_grease.AccumulateSingleSample(bucket);
    596      break;
    597    case EchExtensionStatus::kReal:
    598      glean::ssl_handshake::result_ech.AccumulateSingleSample(bucket);
    599      break;
    600    default:
    601      break;
    602  }
    603  glean::ssl_handshake::result.AccumulateSingleSample(bucket);
    604 
    605  if (bucket == 0) {
    606    nsCOMPtr<nsITransportSecurityInfo> securityInfo;
    607    if (NS_FAILED(socketInfo->GetSecurityInfo(getter_AddRefs(securityInfo))) ||
    608        !securityInfo) {
    609      return;
    610    }
    611    // Web Privacy Telemetry for successful connections.
    612    bool success = true;
    613 
    614    bool usedPrivateDNS = false;
    615    success &= securityInfo->GetUsedPrivateDNS(&usedPrivateDNS) == NS_OK;
    616 
    617    bool madeOCSPRequest = false;
    618    success &= securityInfo->GetMadeOCSPRequests(&madeOCSPRequest) == NS_OK;
    619 
    620    uint16_t protocolVersion = 0;
    621    success &= securityInfo->GetProtocolVersion(&protocolVersion) == NS_OK;
    622    bool usedTLS13 = protocolVersion == 4;
    623 
    624    bool usedECH = false;
    625    success &= securityInfo->GetIsAcceptedEch(&usedECH) == NS_OK;
    626 
    627    // As bucket is 0 we are reporting the results of a sucessful connection
    628    // and so TransportSecurityInfo should be populated. However, this isn't
    629    // happening in all cases, see Bug 1789458.
    630    if (success) {
    631      uint8_t TLSPrivacyResult = 0;
    632      TLSPrivacyResult |= usedTLS13 << 0;
    633      TLSPrivacyResult |= !madeOCSPRequest << 1;
    634      TLSPrivacyResult |= usedPrivateDNS << 2;
    635      TLSPrivacyResult |= usedECH << 3;
    636 
    637      glean::ssl_handshake::privacy.AccumulateSingleSample(TLSPrivacyResult);
    638    }
    639  }
    640 }
    641 
    642 // Check the status of the handshake. This is where PSM checks for TLS
    643 // intolerance and potentially sets up TLS intolerance fallback by noting the
    644 // intolerance, setting the NSPR error to PR_CONNECT_RESET_ERROR, and returning
    645 // -1 as the bytes transferred so that necko retries the connection.
    646 // Otherwise, PSM returns the bytes transferred unchanged.
    647 int32_t checkHandshake(int32_t bytesTransferred, bool wasReading,
    648                       PRFileDesc* ssl_layer_fd, NSSSocketControl* socketInfo) {
    649  const PRErrorCode originalError = PR_GetError();
    650 
    651  // If the connection would block, return early.
    652  if (bytesTransferred < 0 && originalError == PR_WOULD_BLOCK_ERROR) {
    653    PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
    654    return bytesTransferred;
    655  }
    656 
    657  // We only need to do TLS intolerance checking for the first transfer.
    658  bool handleHandshakeResultNow = socketInfo->IsHandshakePending();
    659  if (!handleHandshakeResultNow) {
    660    // If we've encountered an error since the handshake, ensure the socket
    661    // control is cancelled, so that getSocketInfoIfRunning will correctly
    662    // cause us to fail if another part of Gecko (erroneously) calls an I/O
    663    // function (PR_Send/PR_Recv/etc.) again on this socket.
    664    if (bytesTransferred < 0) {
    665      if (!socketInfo->IsCanceled()) {
    666        socketInfo->SetCanceled(originalError);
    667      }
    668      PR_SetError(originalError, 0);
    669    }
    670    return bytesTransferred;
    671  }
    672 
    673  // TLS intolerant servers only cause the first transfer to fail, so let's
    674  // set the HandshakePending attribute to false so that we don't try this logic
    675  // again in a subsequent transfer.
    676  socketInfo->SetHandshakeNotPending();
    677  // Report the result once for each handshake. Note that this does not
    678  // get handshakes which are cancelled before any reads or writes
    679  // happen.
    680  reportHandshakeResult(bytesTransferred, wasReading, originalError,
    681                        socketInfo);
    682 
    683  // If there was no error, return early. The case where we read 0 bytes is not
    684  // considered an error by NSS, but PSM interprets this as TLS intolerance, so
    685  // we turn it into an error. Writes of 0 bytes are an error, because PR_Write
    686  // is never supposed to return 0.
    687  if (bytesTransferred > 0) {
    688    return bytesTransferred;
    689  }
    690 
    691  // There was some sort of error. Determine what it was and if we want to
    692  // retry the connection due to TLS intolerance.
    693  PRErrorCode errorToUse = originalError;
    694  // Turn zero-length reads into errors and handle zero-length write errors.
    695  if (bytesTransferred == 0) {
    696    if (wasReading) {
    697      errorToUse = PR_END_OF_FILE_ERROR;
    698    } else {
    699      errorToUse = SEC_ERROR_LIBRARY_FAILURE;
    700    }
    701    bytesTransferred = -1;
    702  }
    703  bool wantRetry = retryDueToTLSIntolerance(errorToUse, socketInfo);
    704  // Set the error on the socket control and cancel it.
    705  if (!socketInfo->IsCanceled()) {
    706    socketInfo->SetCanceled(errorToUse);
    707  }
    708 
    709  if (wantRetry) {
    710    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    711            ("[%p] checkHandshake: will retry with lower max TLS version",
    712             ssl_layer_fd));
    713    // Setting the error PR_CONNECT_RESET_ERROR causes necko to retry the
    714    // connection.
    715    PR_SetError(PR_CONNECT_RESET_ERROR, 0);
    716  } else {
    717    PR_SetError(originalError, 0);
    718  }
    719 
    720  return bytesTransferred;
    721 }
    722 
    723 }  // namespace
    724 
    725 static int16_t nsSSLIOLayerPoll(PRFileDesc* fd, int16_t in_flags,
    726                                int16_t* out_flags) {
    727  if (!out_flags) {
    728    NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
    729    return 0;
    730  }
    731 
    732  *out_flags = 0;
    733 
    734  NSSSocketControl* socketInfo =
    735      getSocketInfoIfRunning(fd, not_reading_or_writing);
    736 
    737  if (!socketInfo) {
    738    // If we get here, it is probably because certificate validation failed
    739    // and this is the first I/O operation after the failure.
    740    MOZ_LOG(
    741        gPIPNSSLog, LogLevel::Debug,
    742        ("[%p] polling SSL socket right after certificate verification failed "
    743         "or NSS shutdown or SDR logout %d\n",
    744         fd, (int)in_flags));
    745 
    746    MOZ_ASSERT(in_flags & PR_POLL_EXCEPT,
    747               "Caller did not poll for EXCEPT (canceled)");
    748    // Since this poll method cannot return errors, we want the caller to call
    749    // PR_Send/PR_Recv right away to get the error, so we tell that we are
    750    // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
    751    *out_flags = in_flags | PR_POLL_EXCEPT;  // see also bug 480619
    752    return in_flags;
    753  }
    754 
    755  MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    756          (socketInfo->IsWaitingForCertVerification()
    757               ? "[%p] polling SSL socket during certificate verification "
    758                 "using lower %d\n"
    759               : "[%p] poll SSL socket using lower %d\n",
    760           fd, (int)in_flags));
    761 
    762  socketInfo->MaybeSelectClientAuthCertificate();
    763 
    764  // We want the handshake to continue during certificate validation, so we
    765  // don't need to do anything special here. libssl automatically blocks when
    766  // it reaches any point that would be unsafe to send/receive something before
    767  // cert validation is complete.
    768  int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
    769  MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    770          ("[%p] poll SSL socket returned %d\n", (void*)fd, (int)result));
    771  return result;
    772 }
    773 
    774 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers(PublicOrPrivate aPublicOrPrivate,
    775                                         uint32_t aTlsFlags)
    776    : mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0),
    777      mPublicOrPrivate(aPublicOrPrivate),
    778      mutex("nsSSLIOLayerHelpers.mutex"),
    779      mTlsFlags(aTlsFlags) {}
    780 
    781 // PSMAvailable and PSMAvailable64 are reachable, but they're unimplemented in
    782 // PSM, so we set an error and return -1.
    783 static int32_t PSMAvailable(PRFileDesc*) {
    784  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    785  return -1;
    786 }
    787 
    788 static int64_t PSMAvailable64(PRFileDesc*) {
    789  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    790  return -1;
    791 }
    792 
    793 static PRStatus PSMGetsockname(PRFileDesc* fd, PRNetAddr* addr) {
    794  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
    795 
    796  return fd->lower->methods->getsockname(fd->lower, addr);
    797 }
    798 
    799 static PRStatus PSMGetpeername(PRFileDesc* fd, PRNetAddr* addr) {
    800  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
    801 
    802  return fd->lower->methods->getpeername(fd->lower, addr);
    803 }
    804 
    805 static PRStatus PSMGetsocketoption(PRFileDesc* fd, PRSocketOptionData* data) {
    806  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
    807 
    808  return fd->lower->methods->getsocketoption(fd, data);
    809 }
    810 
    811 static PRStatus PSMSetsocketoption(PRFileDesc* fd,
    812                                   const PRSocketOptionData* data) {
    813  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
    814 
    815  return fd->lower->methods->setsocketoption(fd, data);
    816 }
    817 
    818 static int32_t PSMRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
    819                       PRIntervalTime timeout) {
    820  NSSSocketControl* socketInfo = getSocketInfoIfRunning(fd, reading);
    821  if (!socketInfo) return -1;
    822 
    823  if (flags != PR_MSG_PEEK && flags != 0) {
    824    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    825    return -1;
    826  }
    827 
    828  int32_t bytesRead =
    829      fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
    830 
    831  MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    832          ("[%p] read %d bytes\n", (void*)fd, bytesRead));
    833 
    834 #ifdef DEBUG_SSL_VERBOSE
    835  DEBUG_DUMP_BUFFER((unsigned char*)buf, bytesRead);
    836 #endif
    837 
    838  return checkHandshake(bytesRead, true, fd, socketInfo);
    839 }
    840 
    841 static int32_t PSMSend(PRFileDesc* fd, const void* buf, int32_t amount,
    842                       int flags, PRIntervalTime timeout) {
    843  NSSSocketControl* socketInfo = getSocketInfoIfRunning(fd, writing);
    844  if (!socketInfo) return -1;
    845 
    846  if (flags != 0) {
    847    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    848    return -1;
    849  }
    850 
    851 #ifdef DEBUG_SSL_VERBOSE
    852  DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
    853 #endif
    854 
    855  if (socketInfo->IsShortWritePending() && amount > 0) {
    856    // We got "SSL short write" last time, try to flush the pending byte.
    857 #ifdef DEBUG
    858    socketInfo->CheckShortWrittenBuffer(static_cast<const unsigned char*>(buf),
    859                                        amount);
    860 #endif
    861 
    862    buf = socketInfo->GetShortWritePendingByteRef();
    863    amount = 1;
    864 
    865    MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    866            ("[%p] pushing 1 byte after SSL short write", fd));
    867  }
    868 
    869  int32_t bytesWritten =
    870      fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
    871 
    872  // NSS indicates that it can't write all requested data (due to network
    873  // congestion, for example) by returning either one less than the amount
    874  // of data requested or 16383, if the requested amount is greater than
    875  // 16384. We refer to this as a "short write". If we simply returned
    876  // the amount that NSS did write, the layer above us would then call
    877  // PSMSend with a very small amount of data (often 1). This is inefficient
    878  // and can lead to alternating between sending large packets and very small
    879  // packets. To prevent this, we alert the layer calling us that the operation
    880  // would block and that it should be retried later, with the same data.
    881  // When it does, we tell NSS to write the remaining byte it didn't write
    882  // in the previous call. We then return the total number of bytes written,
    883  // which is the number that caused the short write plus the additional byte
    884  // we just wrote out.
    885 
    886  // The 16384 value is based on libssl's maximum buffer size:
    887  //    MAX_FRAGMENT_LENGTH - 1
    888  //
    889  // It's in a private header, though, filed bug 1394822 to expose it.
    890  static const int32_t kShortWrite16k = 16383;
    891 
    892  if ((amount > 1 && bytesWritten == (amount - 1)) ||
    893      (amount > kShortWrite16k && bytesWritten == kShortWrite16k)) {
    894    // This is indication of an "SSL short write", block to force retry.
    895    socketInfo->SetShortWritePending(
    896        bytesWritten + 1,  // The amount to return after the flush
    897        *(static_cast<const unsigned char*>(buf) + bytesWritten));
    898 
    899    MOZ_LOG(
    900        gPIPNSSLog, LogLevel::Verbose,
    901        ("[%p] indicated SSL short write for %d bytes (written just %d bytes)",
    902         fd, amount, bytesWritten));
    903 
    904    bytesWritten = -1;
    905    PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
    906 
    907 #ifdef DEBUG
    908    socketInfo->RememberShortWrittenBuffer(
    909        static_cast<const unsigned char*>(buf));
    910 #endif
    911 
    912  } else if (socketInfo->IsShortWritePending() && bytesWritten == 1) {
    913    // We have now flushed all pending data in the SSL socket
    914    // after the indicated short write.  Tell the upper layer
    915    // it has sent all its data now.
    916    MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    917            ("[%p] finished SSL short write", fd));
    918 
    919    bytesWritten = socketInfo->ResetShortWritePending();
    920  }
    921 
    922  MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    923          ("[%p] wrote %d bytes\n", fd, bytesWritten));
    924 
    925  return checkHandshake(bytesWritten, false, fd, socketInfo);
    926 }
    927 
    928 static PRStatus PSMBind(PRFileDesc* fd, const PRNetAddr* addr) {
    929  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
    930 
    931  return fd->lower->methods->bind(fd->lower, addr);
    932 }
    933 
    934 static int32_t nsSSLIOLayerRead(PRFileDesc* fd, void* buf, int32_t amount) {
    935  return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    936 }
    937 
    938 static int32_t nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf,
    939                                 int32_t amount) {
    940  return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    941 }
    942 
    943 static PRStatus PSMConnectcontinue(PRFileDesc* fd, int16_t out_flags) {
    944  if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) {
    945    return PR_FAILURE;
    946  }
    947 
    948  return fd->lower->methods->connectcontinue(fd, out_flags);
    949 }
    950 
    951 NS_IMPL_ISUPPORTS(nsSSLIOLayerHelpers, nsIObserver)
    952 
    953 NS_IMETHODIMP
    954 nsSSLIOLayerHelpers::Observe(nsISupports* aSubject, const char* aTopic,
    955                             const char16_t* someData) {
    956  if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
    957    NS_ConvertUTF16toUTF8 prefName(someData);
    958 
    959    if (prefName.EqualsLiteral("security.tls.version.fallback-limit")) {
    960      loadVersionFallbackLimit();
    961    } else if (prefName.EqualsLiteral("security.tls.insecure_fallback_hosts")) {
    962      initInsecureFallbackSites();
    963    }
    964  } else if (nsCRT::strcmp(aTopic, "last-pb-context-exited") == 0) {
    965    clearStoredData();
    966  }
    967  return NS_OK;
    968 }
    969 
    970 void nsSSLIOLayerHelpers::GlobalInit() {
    971  MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
    972  gPublicSSLIOLayerHelpers = new nsSSLIOLayerHelpers(PublicOrPrivate::Public);
    973  gPublicSSLIOLayerHelpers->Init();
    974  gPrivateSSLIOLayerHelpers = new nsSSLIOLayerHelpers(PublicOrPrivate::Private);
    975  gPrivateSSLIOLayerHelpers->Init();
    976 }
    977 
    978 /*static*/
    979 void nsSSLIOLayerHelpers::GlobalCleanup() {
    980  MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
    981 
    982  if (gPrivateSSLIOLayerHelpers) {
    983    gPrivateSSLIOLayerHelpers = nullptr;
    984  }
    985 
    986  if (gPublicSSLIOLayerHelpers) {
    987    gPublicSSLIOLayerHelpers = nullptr;
    988  }
    989 }
    990 
    991 already_AddRefed<nsSSLIOLayerHelpers> PublicSSLIOLayerHelpers() {
    992  return do_AddRef(gPublicSSLIOLayerHelpers);
    993 }
    994 
    995 already_AddRefed<nsSSLIOLayerHelpers> PrivateSSLIOLayerHelpers() {
    996  return do_AddRef(gPrivateSSLIOLayerHelpers);
    997 }
    998 
    999 static int32_t PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount,
   1000                             int flags, PRIntervalTime timeout) {
   1001  NSSSocketControl* socketInfo = nullptr;
   1002 
   1003  int32_t bytesRead =
   1004      fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
   1005  if (fd->identity == nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity) {
   1006    socketInfo = (NSSSocketControl*)fd->secret;
   1007  }
   1008 
   1009  if ((bytesRead > 0) && socketInfo) {
   1010    socketInfo->AddPlaintextBytesRead(bytesRead);
   1011  }
   1012  return bytesRead;
   1013 }
   1014 
   1015 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers() {
   1016  Preferences::RemoveObserver(this, "security.tls.version.fallback-limit");
   1017  Preferences::RemoveObserver(this, "security.tls.insecure_fallback_hosts");
   1018 }
   1019 
   1020 template <typename R, R return_value, typename... Args>
   1021 static R InvalidPRIOMethod(Args...) {
   1022  MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
   1023  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   1024  return return_value;
   1025 }
   1026 
   1027 nsresult nsSSLIOLayerHelpers::Init() {
   1028  if (!nsSSLIOLayerInitialized) {
   1029    MOZ_ASSERT(NS_IsMainThread());
   1030    nsSSLIOLayerInitialized = true;
   1031    nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
   1032    nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
   1033 
   1034    nsSSLIOLayerMethods.fsync =
   1035        InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*>;
   1036    nsSSLIOLayerMethods.seek =
   1037        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, int32_t, PRSeekWhence>;
   1038    nsSSLIOLayerMethods.seek64 =
   1039        InvalidPRIOMethod<int64_t, -1, PRFileDesc*, int64_t, PRSeekWhence>;
   1040    nsSSLIOLayerMethods.fileInfo =
   1041        InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, PRFileInfo*>;
   1042    nsSSLIOLayerMethods.fileInfo64 =
   1043        InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, PRFileInfo64*>;
   1044    nsSSLIOLayerMethods.writev =
   1045        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, const PRIOVec*, int32_t,
   1046                          PRIntervalTime>;
   1047    nsSSLIOLayerMethods.accept =
   1048        InvalidPRIOMethod<PRFileDesc*, nullptr, PRFileDesc*, PRNetAddr*,
   1049                          PRIntervalTime>;
   1050    nsSSLIOLayerMethods.listen =
   1051        InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, int>;
   1052    nsSSLIOLayerMethods.shutdown =
   1053        InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, int>;
   1054    nsSSLIOLayerMethods.recvfrom =
   1055        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, void*, int32_t, int,
   1056                          PRNetAddr*, PRIntervalTime>;
   1057    nsSSLIOLayerMethods.sendto =
   1058        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, const void*, int32_t, int,
   1059                          const PRNetAddr*, PRIntervalTime>;
   1060    nsSSLIOLayerMethods.acceptread =
   1061        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRFileDesc**, PRNetAddr**,
   1062                          void*, int32_t, PRIntervalTime>;
   1063    nsSSLIOLayerMethods.transmitfile =
   1064        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRFileDesc*, const void*,
   1065                          int32_t, PRTransmitFileFlags, PRIntervalTime>;
   1066    nsSSLIOLayerMethods.sendfile =
   1067        InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRSendFileData*,
   1068                          PRTransmitFileFlags, PRIntervalTime>;
   1069 
   1070    nsSSLIOLayerMethods.available = PSMAvailable;
   1071    nsSSLIOLayerMethods.available64 = PSMAvailable64;
   1072    nsSSLIOLayerMethods.getsockname = PSMGetsockname;
   1073    nsSSLIOLayerMethods.getpeername = PSMGetpeername;
   1074    nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
   1075    nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
   1076    nsSSLIOLayerMethods.recv = PSMRecv;
   1077    nsSSLIOLayerMethods.send = PSMSend;
   1078    nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
   1079    nsSSLIOLayerMethods.bind = PSMBind;
   1080 
   1081    nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
   1082    nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
   1083    nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
   1084    nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
   1085    nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
   1086 
   1087    nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
   1088    nsSSLPlaintextLayerMethods = *PR_GetDefaultIOMethods();
   1089    nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
   1090  }
   1091 
   1092  loadVersionFallbackLimit();
   1093 
   1094  // non main thread helpers will need to use defaults
   1095  if (NS_IsMainThread()) {
   1096    initInsecureFallbackSites();
   1097 
   1098    Preferences::AddStrongObserver(this, "security.tls.version.fallback-limit");
   1099    if (isPublic()) {
   1100      // Changes to the allowlist on the public side will update the pref.
   1101      // Don't propagate the changes to the private side.
   1102      Preferences::AddStrongObserver(this,
   1103                                     "security.tls.insecure_fallback_hosts");
   1104    } else {
   1105      nsCOMPtr<nsIObserverService> obsSvc =
   1106          mozilla::services::GetObserverService();
   1107      if (obsSvc) {
   1108        obsSvc->AddObserver(this, "last-pb-context-exited", false);
   1109      }
   1110    }
   1111  } else {
   1112    MOZ_ASSERT(mTlsFlags, "Only per socket version can ignore prefs");
   1113  }
   1114 
   1115  return NS_OK;
   1116 }
   1117 
   1118 void nsSSLIOLayerHelpers::loadVersionFallbackLimit() {
   1119  // see nsNSSComponent::SetEnabledTLSVersions for pref handling rules
   1120  uint32_t limit = StaticPrefs::security_tls_version_fallback_limit();
   1121 
   1122  // set fallback limit if it is set in the tls flags
   1123  uint32_t tlsFlagsFallbackLimit = getTLSProviderFlagFallbackLimit(mTlsFlags);
   1124 
   1125  if (tlsFlagsFallbackLimit) {
   1126    limit = tlsFlagsFallbackLimit;
   1127    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1128            ("loadVersionFallbackLimit overriden by tlsFlags %d\n", limit));
   1129  }
   1130 
   1131  SSLVersionRange defaults = {SSL_LIBRARY_VERSION_TLS_1_2,
   1132                              SSL_LIBRARY_VERSION_TLS_1_2};
   1133  SSLVersionRange filledInRange;
   1134  nsNSSComponent::FillTLSVersionRange(filledInRange, limit, limit, defaults);
   1135  if (filledInRange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
   1136    filledInRange.max = SSL_LIBRARY_VERSION_TLS_1_2;
   1137  }
   1138 
   1139  mVersionFallbackLimit = filledInRange.max;
   1140 }
   1141 
   1142 void nsSSLIOLayerHelpers::clearStoredData() {
   1143  MOZ_ASSERT(NS_IsMainThread());
   1144  initInsecureFallbackSites();
   1145 
   1146  MutexAutoLock lock(mutex);
   1147  mTLSIntoleranceInfo.Clear();
   1148 }
   1149 
   1150 void nsSSLIOLayerHelpers::setInsecureFallbackSites(const nsCString& str) {
   1151  MutexAutoLock lock(mutex);
   1152 
   1153  mInsecureFallbackSites.Clear();
   1154 
   1155  for (const nsACString& host : nsCCharSeparatedTokenizer(str, ',').ToRange()) {
   1156    if (!host.IsEmpty()) {
   1157      mInsecureFallbackSites.PutEntry(host);
   1158    }
   1159  }
   1160 }
   1161 
   1162 void nsSSLIOLayerHelpers::initInsecureFallbackSites() {
   1163  MOZ_ASSERT(NS_IsMainThread());
   1164  nsAutoCString insecureFallbackHosts;
   1165  Preferences::GetCString("security.tls.insecure_fallback_hosts",
   1166                          insecureFallbackHosts);
   1167  setInsecureFallbackSites(insecureFallbackHosts);
   1168 }
   1169 
   1170 bool nsSSLIOLayerHelpers::isPublic() const {
   1171  return mPublicOrPrivate == PublicOrPrivate::Public;
   1172 }
   1173 
   1174 class FallbackPrefRemover final : public Runnable {
   1175 public:
   1176  explicit FallbackPrefRemover(const nsACString& aHost)
   1177      : mozilla::Runnable("FallbackPrefRemover"), mHost(aHost) {}
   1178  NS_IMETHOD Run() override;
   1179 
   1180 private:
   1181  nsCString mHost;
   1182 };
   1183 
   1184 NS_IMETHODIMP
   1185 FallbackPrefRemover::Run() {
   1186  MOZ_ASSERT(NS_IsMainThread());
   1187  nsAutoCString oldValue;
   1188  Preferences::GetCString("security.tls.insecure_fallback_hosts", oldValue);
   1189  nsCString newValue;
   1190  for (const nsACString& host :
   1191       nsCCharSeparatedTokenizer(oldValue, ',').ToRange()) {
   1192    if (host.Equals(mHost)) {
   1193      continue;
   1194    }
   1195    if (!newValue.IsEmpty()) {
   1196      newValue.Append(',');
   1197    }
   1198    newValue.Append(host);
   1199  }
   1200  Preferences::SetCString("security.tls.insecure_fallback_hosts", newValue);
   1201  return NS_OK;
   1202 }
   1203 
   1204 void nsSSLIOLayerHelpers::removeInsecureFallbackSite(const nsACString& hostname,
   1205                                                     uint16_t port) {
   1206  forgetIntolerance(hostname, port);
   1207  {
   1208    MutexAutoLock lock(mutex);
   1209    if (!mInsecureFallbackSites.Contains(hostname)) {
   1210      return;
   1211    }
   1212    mInsecureFallbackSites.RemoveEntry(hostname);
   1213  }
   1214  if (!isPublic()) {
   1215    return;
   1216  }
   1217  RefPtr<Runnable> runnable = new FallbackPrefRemover(hostname);
   1218  if (NS_IsMainThread()) {
   1219    runnable->Run();
   1220  } else {
   1221    NS_DispatchToMainThread(runnable);
   1222  }
   1223 }
   1224 
   1225 bool nsSSLIOLayerHelpers::isInsecureFallbackSite(const nsACString& hostname) {
   1226  MutexAutoLock lock(mutex);
   1227  return mInsecureFallbackSites.Contains(hostname);
   1228 }
   1229 
   1230 nsresult nsSSLIOLayerNewSocket(int32_t family, const char* host, int32_t port,
   1231                               nsIProxyInfo* proxy,
   1232                               const OriginAttributes& originAttributes,
   1233                               PRFileDesc** fd,
   1234                               nsITLSSocketControl** tlsSocketControl,
   1235                               bool forSTARTTLS, uint32_t flags,
   1236                               uint32_t tlsFlags) {
   1237  PRFileDesc* sock = PR_OpenTCPSocket(family);
   1238  if (!sock) return NS_ERROR_OUT_OF_MEMORY;
   1239 
   1240  nsresult rv =
   1241      nsSSLIOLayerAddToSocket(family, host, port, proxy, originAttributes, sock,
   1242                              tlsSocketControl, forSTARTTLS, flags, tlsFlags);
   1243  if (NS_FAILED(rv)) {
   1244    PR_Close(sock);
   1245    return rv;
   1246  }
   1247 
   1248  *fd = sock;
   1249  return NS_OK;
   1250 }
   1251 
   1252 static PRFileDesc* nsSSLIOLayerImportFD(PRFileDesc* fd,
   1253                                        NSSSocketControl* infoObject,
   1254                                        const char* host, bool haveHTTPSProxy) {
   1255  // Memory allocated here is released when fd is closed, regardless of the
   1256  // success of this function.
   1257  PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd);
   1258  if (!sslSock) {
   1259    return nullptr;
   1260  }
   1261  if (SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject) !=
   1262      SECSuccess) {
   1263    return nullptr;
   1264  }
   1265  if (SSL_SecretCallback(sslSock, SecretCallback, infoObject) != SECSuccess) {
   1266    return nullptr;
   1267  }
   1268  if (SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback,
   1269                                   infoObject) != SECSuccess) {
   1270    return nullptr;
   1271  }
   1272 
   1273  // Disable this hook if we connect anonymously. See bug 466080.
   1274  uint32_t flags = infoObject->GetProviderFlags();
   1275  SSLGetClientAuthData clientAuthDataHook = SSLGetClientAuthDataHook;
   1276  // Provide the client cert to HTTPS proxy no matter if it is anonymous.
   1277  if (flags & nsISocketProvider::ANONYMOUS_CONNECT && !haveHTTPSProxy &&
   1278      !(flags & nsISocketProvider::ANONYMOUS_CONNECT_ALLOW_CLIENT_CERT)) {
   1279    clientAuthDataHook = nullptr;
   1280  }
   1281  if (SSL_GetClientAuthDataHook(sslSock, clientAuthDataHook, infoObject) !=
   1282      SECSuccess) {
   1283    return nullptr;
   1284  }
   1285 
   1286  if (SSL_AuthCertificateHook(sslSock, AuthCertificateHook, infoObject) !=
   1287      SECSuccess) {
   1288    return nullptr;
   1289  }
   1290  if (SSL_SetURL(sslSock, host) != SECSuccess) {
   1291    return nullptr;
   1292  }
   1293 
   1294  return sslSock;
   1295 }
   1296 
   1297 // Please change getSignatureName in nsNSSCallbacks.cpp when changing the list
   1298 // here. See NOTE at SSL_SignatureSchemePrefSet call site.
   1299 static const SSLSignatureScheme sEnabledSignatureSchemes[] = {
   1300    ssl_sig_ecdsa_secp256r1_sha256,
   1301    ssl_sig_ecdsa_secp384r1_sha384,
   1302    ssl_sig_ecdsa_secp521r1_sha512,
   1303    ssl_sig_rsa_pss_sha256,
   1304    ssl_sig_rsa_pss_sha384,
   1305    ssl_sig_rsa_pss_sha512,
   1306    ssl_sig_rsa_pkcs1_sha256,
   1307    ssl_sig_rsa_pkcs1_sha384,
   1308    ssl_sig_rsa_pkcs1_sha512,
   1309 #if !defined(EARLY_BETA_OR_EARLIER)
   1310    ssl_sig_ecdsa_sha1,
   1311 #endif
   1312    ssl_sig_rsa_pkcs1_sha1,
   1313 };
   1314 
   1315 enum CertificateCompressionAlgorithms {
   1316  zlib = 0x01,
   1317  brotli = 0x02,
   1318  zstd = 0x03
   1319 };
   1320 
   1321 void GatherCertificateCompressionTelemetry(SECStatus rv,
   1322                                           CertificateCompressionAlgorithms alg,
   1323                                           PRUint64 actualCertLen,
   1324                                           PRUint64 encodedCertLen) {
   1325  nsAutoCString decoder;
   1326 
   1327  switch (alg) {
   1328    case zlib:
   1329      decoder.AssignLiteral("zlib");
   1330      break;
   1331    case brotli:
   1332      decoder.AssignLiteral("brotli");
   1333      break;
   1334    case zstd:
   1335      decoder.AssignLiteral("zstd");
   1336      break;
   1337  }
   1338 
   1339  if (rv != SECSuccess) {
   1340    mozilla::glean::cert_compression::failures.Get(decoder).Add(1);
   1341    return;
   1342  }
   1343  // Glam requires us to send 0 in case of success.
   1344  mozilla::glean::cert_compression::failures.Get(decoder).Add(0);
   1345 }
   1346 
   1347 SECStatus abridgedCertificatePass1Decode(const SECItem* input,
   1348                                         unsigned char* output,
   1349                                         size_t outputLen, size_t* usedLen) {
   1350  if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
   1351    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
   1352    return SECFailure;
   1353  }
   1354  if (NS_FAILED(mozilla::psm::abridged_certs::decompress(
   1355          input->data, input->len, output, outputLen, usedLen))) {
   1356    PR_SetError(SEC_ERROR_BAD_DATA, 0);
   1357    return SECFailure;
   1358  }
   1359  return SECSuccess;
   1360 }
   1361 
   1362 SECStatus abridgedCertificateDecode(const SECItem* input, unsigned char* output,
   1363                                    size_t outputLen, size_t* usedLen) {
   1364  if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
   1365    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
   1366            ("AbridgedCerts: Invalid arguments passed to "
   1367             "abridgedCertificateDecode"));
   1368    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
   1369    return SECFailure;
   1370  }
   1371  // Pass 2 - Brotli with no dictionary
   1372  UniqueSECItem tempBuffer(::SECITEM_AllocItem(nullptr, nullptr, outputLen));
   1373  if (!tempBuffer) {
   1374    PR_SetError(SEC_ERROR_NO_MEMORY, 0);
   1375    return SECFailure;
   1376  }
   1377  size_t tempUsed;
   1378  SECStatus rv = brotliCertificateDecode(input, tempBuffer->data,
   1379                                         (size_t)tempBuffer->len, &tempUsed);
   1380  if (rv != SECSuccess) {
   1381    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
   1382            ("AbridgedCerts: Brotli Decoder failed"));
   1383    // Error code set by brotliCertificateDecode
   1384    return rv;
   1385  }
   1386  tempBuffer->len = tempUsed;
   1387  // Error code (if any) set by abridgedCertificatePass1Decode
   1388  return abridgedCertificatePass1Decode(tempBuffer.get(), output, outputLen,
   1389                                        usedLen);
   1390 }
   1391 
   1392 SECStatus zlibCertificateDecode(const SECItem* input, unsigned char* output,
   1393                                size_t outputLen, size_t* usedLen) {
   1394  SECStatus rv = SECFailure;
   1395  if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
   1396    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
   1397    return rv;
   1398  }
   1399 
   1400  z_stream strm = {};
   1401 
   1402  if (inflateInit(&strm) != Z_OK) {
   1403    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
   1404    return rv;
   1405  }
   1406 
   1407  auto cleanup = MakeScopeExit([&] {
   1408    GatherCertificateCompressionTelemetry(rv, zlib, *usedLen, input->len);
   1409    (void)inflateEnd(&strm);
   1410  });
   1411 
   1412  strm.avail_in = input->len;
   1413  strm.next_in = input->data;
   1414 
   1415  strm.avail_out = outputLen;
   1416  strm.next_out = output;
   1417 
   1418  int ret = inflate(&strm, Z_FINISH);
   1419  bool ok = ret == Z_STREAM_END && strm.avail_in == 0 && strm.avail_out == 0;
   1420  if (!ok) {
   1421    PR_SetError(SEC_ERROR_BAD_DATA, 0);
   1422    return rv;
   1423  }
   1424 
   1425  *usedLen = strm.total_out;
   1426  rv = SECSuccess;
   1427  return rv;
   1428 }
   1429 
   1430 SECStatus brotliCertificateDecode(const SECItem* input, unsigned char* output,
   1431                                  size_t outputLen, size_t* usedLen) {
   1432  SECStatus rv = SECFailure;
   1433 
   1434  if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
   1435    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
   1436    return rv;
   1437  }
   1438 
   1439  auto cleanup = MakeScopeExit([&] {
   1440    GatherCertificateCompressionTelemetry(rv, brotli, *usedLen, input->len);
   1441  });
   1442 
   1443  size_t uncompressedSize = outputLen;
   1444  BrotliDecoderResult result = BrotliDecoderDecompress(
   1445      input->len, input->data, &uncompressedSize, output);
   1446 
   1447  if (result != BROTLI_DECODER_RESULT_SUCCESS) {
   1448    PR_SetError(SEC_ERROR_BAD_DATA, 0);
   1449    return rv;
   1450  }
   1451 
   1452  *usedLen = uncompressedSize;
   1453  rv = SECSuccess;
   1454  return rv;
   1455 }
   1456 
   1457 SECStatus zstdCertificateDecode(const SECItem* input, unsigned char* output,
   1458                                size_t outputLen, size_t* usedLen) {
   1459  SECStatus rv = SECFailure;
   1460 
   1461  if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
   1462    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
   1463    return rv;
   1464  }
   1465 
   1466  auto cleanup = MakeScopeExit([&] {
   1467    GatherCertificateCompressionTelemetry(rv, zstd, *usedLen, input->len);
   1468  });
   1469 
   1470  size_t result = ZSTD_decompress(output, outputLen, input->data, input->len);
   1471 
   1472  if (ZSTD_isError(result)) {
   1473    PR_SetError(SEC_ERROR_BAD_DATA, 0);
   1474    return rv;
   1475  }
   1476 
   1477  *usedLen = result;
   1478  rv = SECSuccess;
   1479  return rv;
   1480 }
   1481 
   1482 static nsresult nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
   1483                                       bool haveProxy, const char* host,
   1484                                       int32_t port,
   1485                                       NSSSocketControl* infoObject) {
   1486  if (forSTARTTLS || haveProxy) {
   1487    if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
   1488      return NS_ERROR_FAILURE;
   1489    }
   1490  }
   1491 
   1492  SSLVersionRange range;
   1493  if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
   1494    return NS_ERROR_FAILURE;
   1495  }
   1496 
   1497  // Set TLS 1.3 compat mode.
   1498  if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE)) {
   1499    MOZ_LOG(gPIPNSSLog, LogLevel::Error,
   1500            ("[%p] nsSSLIOLayerSetOptions: Setting compat mode failed\n", fd));
   1501  }
   1502 
   1503  // setting TLS max version
   1504  uint32_t versionFlags =
   1505      getTLSProviderFlagMaxVersion(infoObject->GetProviderTlsFlags());
   1506  if (versionFlags) {
   1507    MOZ_LOG(
   1508        gPIPNSSLog, LogLevel::Debug,
   1509        ("[%p] nsSSLIOLayerSetOptions: version flags %d\n", fd, versionFlags));
   1510    if (versionFlags == kTLSProviderFlagMaxVersion10) {
   1511      range.max = SSL_LIBRARY_VERSION_TLS_1_0;
   1512    } else if (versionFlags == kTLSProviderFlagMaxVersion11) {
   1513      range.max = SSL_LIBRARY_VERSION_TLS_1_1;
   1514    } else if (versionFlags == kTLSProviderFlagMaxVersion12) {
   1515      range.max = SSL_LIBRARY_VERSION_TLS_1_2;
   1516    } else if (versionFlags == kTLSProviderFlagMaxVersion13) {
   1517      range.max = SSL_LIBRARY_VERSION_TLS_1_3;
   1518    } else {
   1519      MOZ_LOG(gPIPNSSLog, LogLevel::Error,
   1520              ("[%p] nsSSLIOLayerSetOptions: unknown version flags %d\n", fd,
   1521               versionFlags));
   1522    }
   1523  }
   1524 
   1525  if ((infoObject->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE) &&
   1526      (range.max > SSL_LIBRARY_VERSION_TLS_1_2)) {
   1527    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1528            ("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to "
   1529             "BE_CONSERVATIVE flag\n",
   1530             fd));
   1531    range.max = SSL_LIBRARY_VERSION_TLS_1_2;
   1532  }
   1533 
   1534  uint16_t maxEnabledVersion = range.max;
   1535  infoObject->AdjustForTLSIntolerance(range);
   1536  MOZ_LOG(
   1537      gPIPNSSLog, LogLevel::Debug,
   1538      ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
   1539       fd, static_cast<unsigned int>(range.min),
   1540       static_cast<unsigned int>(range.max)));
   1541 
   1542  // If the user has set their minimum version to something higher than what
   1543  // we've now set the maximum to, this will result in an inconsistent version
   1544  // range unless we fix it up. This will override their preference, but we only
   1545  // do this for sites critical to the operation of the browser (e.g. update
   1546  // servers) and telemetry experiments.
   1547  if (range.min > range.max) {
   1548    range.min = range.max;
   1549  }
   1550 
   1551  if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
   1552    return NS_ERROR_FAILURE;
   1553  }
   1554  infoObject->SetTLSVersionRange(range);
   1555 
   1556  // when adjustForTLSIntolerance tweaks the maximum version downward,
   1557  // we tell the server using this SCSV so they can detect a downgrade attack
   1558  if (range.max < maxEnabledVersion) {
   1559    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1560            ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
   1561    // Some servers will choke if we send the fallback SCSV with TLS 1.2.
   1562    if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) {
   1563      if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
   1564        return NS_ERROR_FAILURE;
   1565      }
   1566    }
   1567    // tell NSS the max enabled version to make anti-downgrade effective
   1568    if (SECSuccess != SSL_SetDowngradeCheckVersion(fd, maxEnabledVersion)) {
   1569      return NS_ERROR_FAILURE;
   1570    }
   1571  }
   1572 
   1573  // Enable ECH GREASE if suitable. Has no impact if 'real' ECH is being used.
   1574  if (range.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
   1575      !(infoObject->GetProviderFlags() & (nsISocketProvider::BE_CONSERVATIVE |
   1576                                          nsISocketProvider::DONT_TRY_ECH)) &&
   1577      StaticPrefs::security_tls_ech_grease_probability()) {
   1578    if ((RandomUint64().valueOr(0) % 100) >=
   1579        100 - StaticPrefs::security_tls_ech_grease_probability()) {
   1580      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1581              ("[%p] nsSSLIOLayerSetOptions: enabling TLS ECH Grease\n", fd));
   1582      if (SECSuccess != SSL_EnableTls13GreaseEch(fd, PR_TRUE)) {
   1583        return NS_ERROR_FAILURE;
   1584      }
   1585      // ECH Padding can be between 1 and 255
   1586      if (SECSuccess !=
   1587          SSL_SetTls13GreaseEchSize(
   1588              fd, std::clamp(StaticPrefs::security_tls_ech_grease_size(), 1U,
   1589                             255U))) {
   1590        return NS_ERROR_FAILURE;
   1591      }
   1592      infoObject->UpdateEchExtensionStatus(EchExtensionStatus::kGREASE);
   1593    }
   1594  }
   1595 
   1596  // Include a modest set of named groups in supported_groups and determine how
   1597  // many key shares to send. Please change getKeaGroupName in
   1598  // nsNSSCallbacks.cpp when changing the lists here.
   1599  unsigned int additional_shares =
   1600      StaticPrefs::security_tls_client_hello_send_p256_keyshare();
   1601  if (StaticPrefs::security_tls_enable_kyber() &&
   1602      range.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
   1603      !(infoObject->GetProviderFlags() &
   1604        (nsISocketProvider::BE_CONSERVATIVE | nsISocketProvider::IS_RETRY))) {
   1605    const SSLNamedGroup namedGroups[] = {
   1606        ssl_grp_kem_mlkem768x25519, ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1,
   1607        ssl_grp_ec_secp384r1,       ssl_grp_ec_secp521r1,  ssl_grp_ffdhe_2048,
   1608        ssl_grp_ffdhe_3072};
   1609    if (SECSuccess !=
   1610        SSL_NamedGroupConfig(fd, namedGroups, std::size(namedGroups))) {
   1611      return NS_ERROR_FAILURE;
   1612    }
   1613    additional_shares += 1;
   1614    infoObject->WillSendMlkemShare();
   1615  } else {
   1616    const SSLNamedGroup namedGroups[] = {
   1617        ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
   1618        ssl_grp_ec_secp521r1,  ssl_grp_ffdhe_2048,   ssl_grp_ffdhe_3072};
   1619    // Skip the |ssl_grp_kem_mlkem768x25519| entry.
   1620    if (SECSuccess !=
   1621        SSL_NamedGroupConfig(fd, namedGroups, std::size(namedGroups))) {
   1622      return NS_ERROR_FAILURE;
   1623    }
   1624  }
   1625 
   1626  // If additional_shares == 2, send mlkem768x25519, x25519, and p256.
   1627  // If additional_shares == 1, send {mlkem768x25519, x25519} or {x25519, p256}.
   1628  // If additional_shares == 0, send x25519.
   1629  if (SECSuccess != SSL_SendAdditionalKeyShares(fd, additional_shares)) {
   1630    return NS_ERROR_FAILURE;
   1631  }
   1632 
   1633  // Enabling Certificate Compression Decoding mechanisms.
   1634  if (range.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
   1635      !(infoObject->GetProviderFlags() &
   1636        (nsISocketProvider::BE_CONSERVATIVE | nsISocketProvider::IS_RETRY))) {
   1637    SSLCertificateCompressionAlgorithm zlibAlg = {1, "zlib", nullptr,
   1638                                                  zlibCertificateDecode};
   1639 
   1640    SSLCertificateCompressionAlgorithm brotliAlg = {2, "brotli", nullptr,
   1641                                                    brotliCertificateDecode};
   1642 
   1643    SSLCertificateCompressionAlgorithm zstdAlg = {3, "zstd", nullptr,
   1644                                                  zstdCertificateDecode};
   1645 
   1646    SSLCertificateCompressionAlgorithm abridgedAlg = {
   1647        0xab00, "abridged-00", nullptr, abridgedCertificateDecode};
   1648 
   1649    if (StaticPrefs::security_tls_enable_certificate_compression_zlib() &&
   1650        SSL_SetCertificateCompressionAlgorithm(fd, zlibAlg) != SECSuccess) {
   1651      return NS_ERROR_FAILURE;
   1652    }
   1653 
   1654    if (StaticPrefs::security_tls_enable_certificate_compression_brotli() &&
   1655        SSL_SetCertificateCompressionAlgorithm(fd, brotliAlg) != SECSuccess) {
   1656      return NS_ERROR_FAILURE;
   1657    }
   1658 
   1659    if (StaticPrefs::security_tls_enable_certificate_compression_zstd() &&
   1660        SSL_SetCertificateCompressionAlgorithm(fd, zstdAlg) != SECSuccess) {
   1661      return NS_ERROR_FAILURE;
   1662    }
   1663 
   1664    if (StaticPrefs::security_tls_enable_certificate_compression_abridged() &&
   1665        mozilla::psm::abridged_certs::certs_are_available() &&
   1666        SSL_SetCertificateCompressionAlgorithm(fd, abridgedAlg) != SECSuccess) {
   1667      return NS_ERROR_FAILURE;
   1668    }
   1669  }
   1670 
   1671  // NOTE: Should this list ever include ssl_sig_rsa_pss_pss_sha* (or should
   1672  // it become possible to enable this scheme via a pref), it is required
   1673  // to test that a Delegated Credential containing a small-modulus RSA-PSS SPKI
   1674  // is properly rejected. NSS will not advertise PKCS1 or RSAE schemes (which
   1675  // the |ssl_sig_rsa_pss_*| defines alias, meaning we will not currently accept
   1676  // any RSA DC.
   1677  if (SECSuccess !=
   1678      SSL_SignatureSchemePrefSet(fd, sEnabledSignatureSchemes,
   1679                                 std::size(sEnabledSignatureSchemes))) {
   1680    return NS_ERROR_FAILURE;
   1681  }
   1682 
   1683  bool enabled = StaticPrefs::security_ssl_enable_ocsp_stapling();
   1684  if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
   1685    return NS_ERROR_FAILURE;
   1686  }
   1687 
   1688  bool sctsEnabled = GetCertificateTransparencyMode() !=
   1689                     CertVerifier::CertificateTransparencyMode::Disabled;
   1690  if (SECSuccess !=
   1691      SSL_OptionSet(fd, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, sctsEnabled)) {
   1692    return NS_ERROR_FAILURE;
   1693  }
   1694 
   1695  if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
   1696    return NS_ERROR_FAILURE;
   1697  }
   1698 
   1699 #if defined(__arm__)
   1700  if (!mozilla::supports_arm_aes()) {
   1701    unsigned int enabledCiphers = 0;
   1702    std::vector<uint16_t> ciphers(SSL_GetNumImplementedCiphers());
   1703 
   1704    // Returns only the enabled (reflecting prefs) ciphers, ordered
   1705    // by their occurence in
   1706    // https://hg.mozilla.org/projects/nss/file/a75ea4cdacd95282c6c245ebb849c25e84ccd908/lib/ssl/ssl3con.c#l87
   1707    if (SSL_CipherSuiteOrderGet(fd, ciphers.data(), &enabledCiphers) !=
   1708        SECSuccess) {
   1709      return NS_ERROR_FAILURE;
   1710    }
   1711 
   1712    // On ARM, prefer (TLS_CHACHA20_POLY1305_SHA256) over AES when hardware
   1713    // support for AES isn't available. However, it may be disabled. If enabled,
   1714    // it will either be element [0] or [1]*. If [0], we're done. If [1], swap
   1715    // it with [0] (TLS_AES_128_GCM_SHA256).
   1716    // *(assuming the compile-time order remains unchanged)
   1717    if (enabledCiphers > 1) {
   1718      if (ciphers[0] != TLS_CHACHA20_POLY1305_SHA256 &&
   1719          ciphers[1] == TLS_CHACHA20_POLY1305_SHA256) {
   1720        std::swap(ciphers[0], ciphers[1]);
   1721 
   1722        if (SSL_CipherSuiteOrderSet(fd, ciphers.data(), enabledCiphers) !=
   1723            SECSuccess) {
   1724          return NS_ERROR_FAILURE;
   1725        }
   1726      }
   1727    }
   1728  }
   1729 #endif
   1730 
   1731  // Set the Peer ID so that SSL proxy connections work properly and to
   1732  // separate anonymous and/or private browsing connections.
   1733  nsAutoCString peerId;
   1734  infoObject->GetPeerId(peerId);
   1735  if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
   1736    return NS_ERROR_FAILURE;
   1737  }
   1738 
   1739  uint32_t flags = infoObject->GetProviderFlags();
   1740  if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
   1741    if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_SESSION_TICKETS, false) ||
   1742        SECSuccess != SSL_OptionSet(fd, SSL_NO_CACHE, true)) {
   1743      return NS_ERROR_FAILURE;
   1744    }
   1745  }
   1746 
   1747  return NS_OK;
   1748 }
   1749 
   1750 SECStatus StoreResumptionToken(PRFileDesc* fd, const PRUint8* resumptionToken,
   1751                               unsigned int len, void* ctx) {
   1752  PRIntn val;
   1753  if (SSL_OptionGet(fd, SSL_ENABLE_SESSION_TICKETS, &val) != SECSuccess ||
   1754      val == 0) {
   1755    return SECFailure;
   1756  }
   1757 
   1758  NSSSocketControl* infoObject = (NSSSocketControl*)ctx;
   1759  if (!infoObject) {
   1760    return SECFailure;
   1761  }
   1762 
   1763  nsAutoCString peerId;
   1764  infoObject->GetPeerId(peerId);
   1765  if (NS_FAILED(
   1766          net::SSLTokensCache::Put(peerId, resumptionToken, len, infoObject))) {
   1767    return SECFailure;
   1768  }
   1769 
   1770  return SECSuccess;
   1771 }
   1772 
   1773 nsresult nsSSLIOLayerAddToSocket(int32_t family, const char* host, int32_t port,
   1774                                 nsIProxyInfo* proxy,
   1775                                 const OriginAttributes& originAttributes,
   1776                                 PRFileDesc* fd,
   1777                                 nsITLSSocketControl** tlsSocketControl,
   1778                                 bool forSTARTTLS, uint32_t providerFlags,
   1779                                 uint32_t providerTlsFlags) {
   1780  RefPtr<nsSSLIOLayerHelpers> sslIOLayerHelpers;
   1781  if (providerTlsFlags) {
   1782    sslIOLayerHelpers =
   1783        new nsSSLIOLayerHelpers(PublicOrPrivate::Public, providerTlsFlags);
   1784    sslIOLayerHelpers->Init();
   1785  } else {
   1786    bool isPrivate = providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ||
   1787                     originAttributes.IsPrivateBrowsing();
   1788    sslIOLayerHelpers =
   1789        isPrivate ? PrivateSSLIOLayerHelpers() : PublicSSLIOLayerHelpers();
   1790  }
   1791 
   1792  RefPtr<NSSSocketControl> infoObject(new NSSSocketControl(
   1793      nsDependentCString(host), port, sslIOLayerHelpers.forget(), providerFlags,
   1794      providerTlsFlags));
   1795  if (!infoObject) {
   1796    return NS_ERROR_FAILURE;
   1797  }
   1798 
   1799  infoObject->SetForSTARTTLS(forSTARTTLS);
   1800  infoObject->SetOriginAttributes(originAttributes);
   1801 
   1802  bool haveProxy = false;
   1803  bool haveHTTPSProxy = false;
   1804  if (proxy) {
   1805    nsAutoCString proxyHost;
   1806    nsresult rv = proxy->GetHost(proxyHost);
   1807    if (NS_FAILED(rv)) {
   1808      return rv;
   1809    }
   1810    haveProxy = !proxyHost.IsEmpty();
   1811    nsAutoCString type;
   1812    haveHTTPSProxy = haveProxy && NS_SUCCEEDED(proxy->GetType(type)) &&
   1813                     type.EqualsLiteral("https");
   1814  }
   1815 
   1816  // A plaintext observer shim is inserted so we can observe some protocol
   1817  // details without modifying nss
   1818  PRFileDesc* plaintextLayer =
   1819      PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
   1820                           &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
   1821  if (!plaintextLayer) {
   1822    return NS_ERROR_FAILURE;
   1823  }
   1824  plaintextLayer->secret = (PRFilePrivate*)infoObject.get();
   1825  if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer) != PR_SUCCESS) {
   1826    plaintextLayer->dtor(plaintextLayer);
   1827    return NS_ERROR_FAILURE;
   1828  }
   1829  auto plaintextLayerCleanup = MakeScopeExit([&fd] {
   1830    // Note that PR_*IOLayer operations may modify the stack of fds, so a
   1831    // previously-valid pointer may no longer point to what we think it points
   1832    // to after calling PR_PopIOLayer. We must operate on the pointer returned
   1833    // by PR_PopIOLayer.
   1834    PRFileDesc* plaintextLayer =
   1835        PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
   1836    if (plaintextLayer) {
   1837      plaintextLayer->dtor(plaintextLayer);
   1838    }
   1839  });
   1840 
   1841  PRFileDesc* sslSock =
   1842      nsSSLIOLayerImportFD(fd, infoObject, host, haveHTTPSProxy);
   1843  if (!sslSock) {
   1844    return NS_ERROR_FAILURE;
   1845  }
   1846 
   1847  nsresult rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host,
   1848                                       port, infoObject);
   1849  if (NS_FAILED(rv)) {
   1850    return rv;
   1851  }
   1852 
   1853  // Now, layer ourselves on top of the SSL socket...
   1854  PRFileDesc* layer =
   1855      PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
   1856                           &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
   1857  if (!layer) {
   1858    return NS_ERROR_FAILURE;
   1859  }
   1860  // Give the layer an owning reference to the NSSSocketControl.
   1861  // This is the simplest way to prevent the layer from outliving the
   1862  // NSSSocketControl (otherwise, the layer could potentially use it in
   1863  // nsSSLIOLayerClose after it has been released).
   1864  // nsSSLIOLayerClose takes the owning reference when the underlying fd gets
   1865  // closed. If the fd never gets closed (as in, leaks), the NSSSocketControl
   1866  // will also leak.
   1867  layer->secret = (PRFilePrivate*)do_AddRef(infoObject).take();
   1868 
   1869  if (PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer) !=
   1870      PR_SUCCESS) {
   1871    layer->dtor(layer);
   1872    return NS_ERROR_FAILURE;
   1873  }
   1874  auto layerCleanup = MakeScopeExit([&fd] {
   1875    PRFileDesc* layer =
   1876        PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLIOLayerIdentity);
   1877    if (layer) {
   1878      layer->dtor(layer);
   1879    }
   1880  });
   1881 
   1882  // We are going use a clear connection first //
   1883  if (forSTARTTLS || haveProxy) {
   1884    infoObject->SetHandshakeNotPending();
   1885  }
   1886 
   1887  rv = infoObject->SetResumptionTokenFromExternalCache(sslSock);
   1888  if (NS_FAILED(rv)) {
   1889    return rv;
   1890  }
   1891  if (SSL_SetResumptionTokenCallback(sslSock, &StoreResumptionToken,
   1892                                     infoObject) != SECSuccess) {
   1893    return NS_ERROR_FAILURE;
   1894  }
   1895 
   1896  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Socket set up", (void*)sslSock));
   1897 
   1898  (void)infoObject->SetFileDescPtr(sslSock);
   1899  layerCleanup.release();
   1900  plaintextLayerCleanup.release();
   1901  *tlsSocketControl = infoObject.forget().take();
   1902  return NS_OK;
   1903 }
   1904 
   1905 extern "C" {
   1906 
   1907 const uint8_t kIPCClientCertsObjectTypeCert = 1;
   1908 const uint8_t kIPCClientCertsObjectTypeRSAKey = 2;
   1909 const uint8_t kIPCClientCertsObjectTypeECKey = 3;
   1910 
   1911 // This function is provided to the IPC client certs module so it can cause the
   1912 // parent process to find certificates and keys and send identifying
   1913 // information about them over IPC.
   1914 void DoFindObjects(FindObjectsCallback cb, void* ctx) {
   1915  net::SocketProcessChild* socketChild =
   1916      net::SocketProcessChild::GetSingleton();
   1917  if (!socketChild) {
   1918    return;
   1919  }
   1920 
   1921  RefPtr<IPCClientCertsChild> ipcClientCertsActor(
   1922      socketChild->GetIPCClientCertsActor());
   1923  if (!ipcClientCertsActor) {
   1924    return;
   1925  }
   1926  nsTArray<IPCClientCertObject> objects;
   1927  if (!ipcClientCertsActor->SendFindObjects(&objects)) {
   1928    return;
   1929  }
   1930  for (const auto& object : objects) {
   1931    switch (object.type()) {
   1932      case IPCClientCertObject::TECKey:
   1933        cb(kIPCClientCertsObjectTypeECKey, object.get_ECKey().params().Length(),
   1934           object.get_ECKey().params().Elements(),
   1935           object.get_ECKey().cert().Length(),
   1936           object.get_ECKey().cert().Elements(), ctx);
   1937        break;
   1938      case IPCClientCertObject::TRSAKey:
   1939        cb(kIPCClientCertsObjectTypeRSAKey,
   1940           object.get_RSAKey().modulus().Length(),
   1941           object.get_RSAKey().modulus().Elements(),
   1942           object.get_RSAKey().cert().Length(),
   1943           object.get_RSAKey().cert().Elements(), ctx);
   1944        break;
   1945      case IPCClientCertObject::TCertificate:
   1946        cb(kIPCClientCertsObjectTypeCert,
   1947           object.get_Certificate().der().Length(),
   1948           object.get_Certificate().der().Elements(), 0, nullptr, ctx);
   1949        break;
   1950      default:
   1951        MOZ_ASSERT_UNREACHABLE("unhandled IPCClientCertObject type");
   1952        break;
   1953    }
   1954  }
   1955 }
   1956 
   1957 // This function is provided to the IPC client certs module so it can cause the
   1958 // parent process to sign the given data using the key corresponding to the
   1959 // given certificate, using the given parameters.
   1960 void DoSign(size_t cert_len, const uint8_t* cert, size_t data_len,
   1961            const uint8_t* data, size_t params_len, const uint8_t* params,
   1962            SignCallback cb, void* ctx) {
   1963  net::SocketProcessChild* socketChild =
   1964      net::SocketProcessChild::GetSingleton();
   1965  if (!socketChild) {
   1966    return;
   1967  }
   1968 
   1969  RefPtr<IPCClientCertsChild> ipcClientCertsActor(
   1970      socketChild->GetIPCClientCertsActor());
   1971  if (!ipcClientCertsActor) {
   1972    return;
   1973  }
   1974  ByteArray certBytes(nsTArray<uint8_t>(cert, cert_len));
   1975  ByteArray dataBytes(nsTArray<uint8_t>(data, data_len));
   1976  ByteArray paramsBytes(nsTArray<uint8_t>(params, params_len));
   1977  ByteArray signature;
   1978  if (!ipcClientCertsActor->SendSign(certBytes, dataBytes, paramsBytes,
   1979                                     &signature)) {
   1980    return;
   1981  }
   1982  cb(signature.data().Length(), signature.data().Elements(), ctx);
   1983 }
   1984 
   1985 #ifdef MOZ_WIDGET_ANDROID
   1986 // Similar to `DoFindObjects`, this function implements searching for client
   1987 // authentication certificates on Android. When a TLS server requests a client
   1988 // auth certificate, the backend will forward that request to the frontend,
   1989 // which calls KeyChain.choosePrivateKeyAlias. The user can choose a
   1990 // certificate, which causes it to become available for use. The
   1991 // `ClientAuthCertificateManager` singleton keeps track of these certificates.
   1992 // This function is called by osclientcerts when the backend looks for new
   1993 // certificates and keys. It gets a list of all known client auth certificates
   1994 // from `ClientAuthCertificateManager` and returns them via the callback.
   1995 void AndroidDoFindObjects(FindObjectsCallback cb, void* ctx) {
   1996  if (!jni::IsAvailable()) {
   1997    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1998            ("AndroidDoFindObjects: JNI not available"));
   1999    return;
   2000  }
   2001  jni::ObjectArray::LocalRef clientAuthCertificates =
   2002      java::ClientAuthCertificateManager::GetClientAuthCertificates();
   2003  for (size_t i = 0; i < clientAuthCertificates->Length(); i++) {
   2004    java::ClientAuthCertificateManager::ClientAuthCertificate::LocalRef
   2005        clientAuthCertificate = clientAuthCertificates->GetElement(i);
   2006    jni::ByteArray::LocalRef der = clientAuthCertificate->GetCertificateBytes();
   2007    jni::ByteArray::LocalRef keyParameters =
   2008        clientAuthCertificate->GetKeyParameters();
   2009    cb(kIPCClientCertsObjectTypeCert, der->Length(),
   2010       reinterpret_cast<uint8_t*>(der->GetElements().Elements()), 0, nullptr,
   2011       ctx);
   2012    cb(clientAuthCertificate->GetType(), keyParameters->Length(),
   2013       reinterpret_cast<uint8_t*>(keyParameters->GetElements().Elements()),
   2014       der->Length(), reinterpret_cast<uint8_t*>(der->GetElements().Elements()),
   2015       ctx);
   2016    jni::ObjectArray::LocalRef issuersBytes =
   2017        clientAuthCertificate->GetIssuersBytes();
   2018    if (issuersBytes) {
   2019      for (size_t i = 0; i < issuersBytes->Length(); i++) {
   2020        jni::ByteArray::LocalRef issuer = issuersBytes->GetElement(i);
   2021        cb(kIPCClientCertsObjectTypeCert, issuer->Length(),
   2022           reinterpret_cast<uint8_t*>(issuer->GetElements().Elements()), 0,
   2023           nullptr, ctx);
   2024      }
   2025    }
   2026  }
   2027 }
   2028 
   2029 // Similar to `DoSign`, this function implements signing for client
   2030 // authentication certificates on Android. `ClientAuthCertificateManager` keeps
   2031 // track of any available client auth certificates and does the actual work of
   2032 // signing - this function just passes in the appropriate parameters.
   2033 void AndroidDoSign(size_t certLen, const uint8_t* cert, size_t dataLen,
   2034                   const uint8_t* data, const char* algorithm, SignCallback cb,
   2035                   void* ctx) {
   2036  if (!jni::IsAvailable()) {
   2037    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("AndroidDoSign: JNI not available"));
   2038    return;
   2039  }
   2040  jni::ByteArray::LocalRef certBytes =
   2041      jni::ByteArray::New(reinterpret_cast<const int8_t*>(cert), certLen);
   2042  jni::ByteArray::LocalRef dataBytes =
   2043      jni::ByteArray::New(reinterpret_cast<const int8_t*>(data), dataLen);
   2044  jni::String::LocalRef algorithmStr = jni::StringParam(algorithm);
   2045  jni::ByteArray::LocalRef signature = java::ClientAuthCertificateManager::Sign(
   2046      certBytes, dataBytes, algorithmStr);
   2047  if (signature) {
   2048    cb(signature->Length(),
   2049       reinterpret_cast<const uint8_t*>(signature->GetElements().Elements()),
   2050       ctx);
   2051  }
   2052 }
   2053 #endif  // MOZ_WIDGET_ANDROID
   2054 }  // extern "C"