tor-browser

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

NSSSocketControl.cpp (25321B)


      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 "NSSSocketControl.h"
      8 
      9 #include "ssl.h"
     10 #include "sslexp.h"
     11 #include "nsISocketProvider.h"
     12 #include "secerr.h"
     13 #include "mozilla/Base64.h"
     14 #include "mozilla/dom/Promise.h"
     15 #include "mozilla/glean/SecurityManagerSslMetrics.h"
     16 #include "nsNSSCallbacks.h"
     17 #include "nsNSSComponent.h"
     18 #include "nsProxyRelease.h"
     19 
     20 using namespace mozilla;
     21 using namespace mozilla::psm;
     22 
     23 extern LazyLogModule gPIPNSSLog;
     24 
     25 NSSSocketControl::NSSSocketControl(
     26    const nsCString& aHostName, int32_t aPort,
     27    already_AddRefed<nsSSLIOLayerHelpers> aSSLIOLayerHelpers,
     28    uint32_t providerFlags, uint32_t providerTlsFlags)
     29    : CommonSocketControl(aHostName, aPort, providerFlags),
     30      mFd(nullptr),
     31      mCertVerificationState(BeforeCertVerification),
     32      mSSLIOLayerHelpers(aSSLIOLayerHelpers),
     33      mForSTARTTLS(false),
     34      mTLSVersionRange{0, 0},
     35      mHandshakePending(true),
     36      mPreliminaryHandshakeDone(false),
     37      mEarlyDataAccepted(false),
     38      mDenyClientCert(false),
     39      mFalseStartCallbackCalled(false),
     40      mFalseStarted(false),
     41      mIsFullHandshake(false),
     42      mNotedTimeUntilReady(false),
     43      mEchExtensionStatus(EchExtensionStatus::kNotPresent),
     44      mSentMlkemShare(false),
     45      mHasTls13HandshakeSecrets(false),
     46      mIsShortWritePending(false),
     47      mShortWritePendingByte(0),
     48      mShortWriteOriginalAmount(-1),
     49      mKEAUsed(nsITLSSocketControl::KEY_EXCHANGE_UNKNOWN),
     50      mKEAKeyBits(0),
     51      mMACAlgorithmUsed(nsITLSSocketControl::SSL_MAC_UNKNOWN),
     52      mProviderTlsFlags(providerTlsFlags),
     53      mSocketCreationTimestamp(TimeStamp::Now()),
     54      mPlaintextBytesRead(0),
     55      mClaimed(!(providerFlags & nsISocketProvider::IS_SPECULATIVE_CONNECTION)),
     56      mClientAuthCertificateRequest(Nothing()),
     57      mBrowserId(0) {}
     58 
     59 NS_IMETHODIMP
     60 NSSSocketControl::GetKEAUsed(int16_t* aKea) {
     61  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
     62  *aKea = mKEAUsed;
     63  return NS_OK;
     64 }
     65 
     66 NS_IMETHODIMP
     67 NSSSocketControl::GetKEAKeyBits(uint32_t* aKeyBits) {
     68  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
     69  *aKeyBits = mKEAKeyBits;
     70  return NS_OK;
     71 }
     72 
     73 NS_IMETHODIMP
     74 NSSSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) {
     75  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
     76  *aSSLVersionOffered = mTLSVersionRange.max;
     77  return NS_OK;
     78 }
     79 
     80 NS_IMETHODIMP
     81 NSSSocketControl::GetMACAlgorithmUsed(int16_t* aMac) {
     82  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
     83  *aMac = mMACAlgorithmUsed;
     84  return NS_OK;
     85 }
     86 
     87 void NSSSocketControl::NoteTimeUntilReady() {
     88  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
     89  if (mNotedTimeUntilReady) {
     90    return;
     91  }
     92  mNotedTimeUntilReady = true;
     93 
     94  auto duration = TimeStamp::Now() - mSocketCreationTimestamp;
     95  if (!(mProviderFlags & nsISocketProvider::IS_RETRY)) {
     96    glean::ssl::time_until_ready_first_try.AccumulateRawDuration(duration);
     97  }
     98 
     99  if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) {
    100    glean::ssl::time_until_ready_conservative.AccumulateRawDuration(duration);
    101  }
    102 
    103  switch (GetEchExtensionStatus()) {
    104    case EchExtensionStatus::kGREASE:
    105      glean::ssl::time_until_ready_ech_grease.AccumulateRawDuration(duration);
    106      break;
    107    case EchExtensionStatus::kReal:
    108      glean::ssl::time_until_ready_ech.AccumulateRawDuration(duration);
    109      break;
    110    default:
    111      break;
    112  }
    113  // This will include TCP and proxy tunnel wait time
    114  glean::ssl::time_until_ready.AccumulateRawDuration(duration);
    115 
    116  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    117          ("[%p] NSSSocketControl::NoteTimeUntilReady\n", mFd));
    118 }
    119 
    120 void NSSSocketControl::SetHandshakeCompleted() {
    121  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    122  if (!mHandshakeCompleted) {
    123    enum HandshakeType {
    124      Resumption = 1,
    125      FalseStarted = 2,
    126      ChoseNotToFalseStart = 3,
    127      NotAllowedToFalseStart = 4,
    128    };
    129 
    130    HandshakeType handshakeType = !IsFullHandshake() ? Resumption
    131                                  : mFalseStarted    ? FalseStarted
    132                                  : mFalseStartCallbackCalled
    133                                      ? ChoseNotToFalseStart
    134                                      : NotAllowedToFalseStart;
    135    // This will include TCP and proxy tunnel wait time
    136    if (mKeaGroupName.isSome()) {
    137      glean::ssl::time_until_handshake_finished_keyed_by_ka.Get(*mKeaGroupName)
    138          .AccumulateRawDuration(TimeStamp::Now() - mSocketCreationTimestamp);
    139    }
    140 
    141    // If the handshake is completed for the first time from just 1 callback
    142    // that means that TLS session resumption must have been used.
    143    glean::ssl::resumed_session
    144        .EnumGet(static_cast<glean::ssl::ResumedSessionLabel>(handshakeType ==
    145                                                              Resumption))
    146        .Add();
    147    glean::ssl_handshake::completed.AccumulateSingleSample(handshakeType);
    148  }
    149 
    150  // Remove the plaintext layer as it is not needed anymore.
    151  // The plaintext layer is not always present - so it's not a fatal error if it
    152  // cannot be removed.
    153  // Note that PR_PopIOLayer may modify its stack, so a pointer returned by
    154  // PR_GetIdentitiesLayer may not point to what we think it points to after
    155  // calling PR_PopIOLayer. We must operate on the pointer returned by
    156  // PR_PopIOLayer.
    157  if (PR_GetIdentitiesLayer(mFd,
    158                            nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) {
    159    PRFileDesc* poppedPlaintext =
    160        PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
    161    poppedPlaintext->dtor(poppedPlaintext);
    162  }
    163 
    164  mHandshakeCompleted = true;
    165 
    166  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    167          ("[%p] NSSSocketControl::SetHandshakeCompleted\n", (void*)mFd));
    168 
    169  mIsFullHandshake = false;  // reset for next handshake on this connection
    170 
    171  if (mTlsHandshakeCallback) {
    172    auto callback = std::move(mTlsHandshakeCallback);
    173    (void)callback->HandshakeDone();
    174  }
    175 }
    176 
    177 void NSSSocketControl::SetNegotiatedNPN(const char* value, uint32_t length) {
    178  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    179  if (!value) {
    180    mNegotiatedNPN.Truncate();
    181  } else {
    182    mNegotiatedNPN.Assign(value, length);
    183  }
    184  mNPNCompleted = true;
    185 }
    186 
    187 #define MAX_ALPN_LENGTH 255
    188 
    189 NS_IMETHODIMP
    190 NSSSocketControl::GetAlpnEarlySelection(nsACString& aAlpnSelected) {
    191  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    192  aAlpnSelected.Truncate();
    193 
    194  SSLPreliminaryChannelInfo info;
    195  SECStatus rv = SSL_GetPreliminaryChannelInfo(mFd, &info, sizeof(info));
    196  if (rv != SECSuccess || !info.canSendEarlyData) {
    197    return NS_ERROR_NOT_AVAILABLE;
    198  }
    199 
    200  SSLNextProtoState alpnState;
    201  unsigned char chosenAlpn[MAX_ALPN_LENGTH];
    202  unsigned int chosenAlpnLen;
    203  rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen,
    204                        AssertedCast<unsigned int>(std::size(chosenAlpn)));
    205 
    206  if (rv != SECSuccess) {
    207    return NS_ERROR_NOT_AVAILABLE;
    208  }
    209 
    210  if (alpnState == SSL_NEXT_PROTO_EARLY_VALUE) {
    211    aAlpnSelected.Assign(BitwiseCast<char*, unsigned char*>(chosenAlpn),
    212                         chosenAlpnLen);
    213  }
    214 
    215  return NS_OK;
    216 }
    217 
    218 NS_IMETHODIMP
    219 NSSSocketControl::GetEarlyDataAccepted(bool* aAccepted) {
    220  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    221  *aAccepted = mEarlyDataAccepted;
    222  return NS_OK;
    223 }
    224 
    225 void NSSSocketControl::SetEarlyDataAccepted(bool aAccepted) {
    226  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    227  mEarlyDataAccepted = aAccepted;
    228 }
    229 
    230 bool NSSSocketControl::GetDenyClientCert() {
    231  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    232  return mDenyClientCert;
    233 }
    234 
    235 void NSSSocketControl::SetDenyClientCert(bool aDenyClientCert) {
    236  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    237  mDenyClientCert = aDenyClientCert;
    238 }
    239 
    240 NS_IMETHODIMP
    241 NSSSocketControl::DriveHandshake() {
    242  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    243  if (!mFd) {
    244    return NS_ERROR_FAILURE;
    245  }
    246  if (IsCanceled()) {
    247    PRErrorCode errorCode = GetErrorCode();
    248    MOZ_DIAGNOSTIC_ASSERT(errorCode, "handshake cancelled without error code");
    249    return GetXPCOMFromNSSError(errorCode);
    250  }
    251 
    252  SECStatus rv = SSL_ForceHandshake(mFd);
    253 
    254  if (rv != SECSuccess) {
    255    PRErrorCode errorCode = PR_GetError();
    256    MOZ_ASSERT(errorCode, "handshake failed without error code");
    257    // There is a bug in NSS. Sometimes SSL_ForceHandshake will return
    258    // SECFailure without setting an error code. In these cases, cancel
    259    // the connection with SEC_ERROR_LIBRARY_FAILURE.
    260    if (!errorCode) {
    261      errorCode = SEC_ERROR_LIBRARY_FAILURE;
    262    }
    263    if (errorCode == PR_WOULD_BLOCK_ERROR) {
    264      return NS_BASE_STREAM_WOULD_BLOCK;
    265    }
    266 
    267    SetCanceled(errorCode);
    268    return GetXPCOMFromNSSError(errorCode);
    269  }
    270  return NS_OK;
    271 }
    272 
    273 bool NSSSocketControl::GetForSTARTTLS() {
    274  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    275  return mForSTARTTLS;
    276 }
    277 
    278 void NSSSocketControl::SetForSTARTTLS(bool aForSTARTTLS) {
    279  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    280  mForSTARTTLS = aForSTARTTLS;
    281 }
    282 
    283 NS_IMETHODIMP
    284 NSSSocketControl::ProxyStartSSL() {
    285  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    286  return ActivateSSL();
    287 }
    288 
    289 NS_IMETHODIMP
    290 NSSSocketControl::StartTLS() {
    291  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    292  return ActivateSSL();
    293 }
    294 
    295 NS_IMETHODIMP
    296 NSSSocketControl::AsyncStartTLS(JSContext* aCx,
    297                                mozilla::dom::Promise** aPromise) {
    298  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    299  NS_ENSURE_ARG_POINTER(aCx);
    300  NS_ENSURE_ARG_POINTER(aPromise);
    301 
    302  nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
    303  if (!globalObject) {
    304    return NS_ERROR_UNEXPECTED;
    305  }
    306 
    307  ErrorResult result;
    308  RefPtr<mozilla::dom::Promise> promise =
    309      mozilla::dom::Promise::Create(globalObject, result);
    310  if (result.Failed()) {
    311    return result.StealNSResult();
    312  }
    313 
    314  nsCOMPtr<nsIEventTarget> target(
    315      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID));
    316  if (!target) {
    317    return NS_ERROR_UNEXPECTED;
    318  }
    319 
    320  auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
    321      "AsyncStartTLS promise", promise);
    322 
    323  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
    324      "AsyncStartTLS::StartTLS",
    325      [promiseHolder = std::move(promiseHolder), self = RefPtr{this}]() {
    326        nsresult rv = self->StartTLS();
    327        NS_DispatchToMainThread(NS_NewRunnableFunction(
    328            "AsyncStartTLS::Resolve", [rv, promiseHolder]() {
    329              dom::Promise* promise = promiseHolder.get()->get();
    330              if (NS_FAILED(rv)) {
    331                promise->MaybeReject(rv);
    332              } else {
    333                promise->MaybeResolveWithUndefined();
    334              }
    335            }));
    336      }));
    337 
    338  nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
    339  if (NS_FAILED(rv)) {
    340    return rv;
    341  }
    342 
    343  promise.forget(aPromise);
    344  return NS_OK;
    345 }
    346 
    347 NS_IMETHODIMP
    348 NSSSocketControl::SetNPNList(nsTArray<nsCString>& protocolArray) {
    349  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    350  if (!mFd) return NS_ERROR_FAILURE;
    351 
    352  // the npn list is a concatenated list of 8 bit byte strings.
    353  nsCString npnList;
    354 
    355  for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
    356    if (protocolArray[index].IsEmpty() || protocolArray[index].Length() > 255)
    357      return NS_ERROR_ILLEGAL_VALUE;
    358 
    359    npnList.Append(protocolArray[index].Length());
    360    npnList.Append(protocolArray[index]);
    361  }
    362 
    363  if (SSL_SetNextProtoNego(
    364          mFd, BitwiseCast<const unsigned char*, const char*>(npnList.get()),
    365          npnList.Length()) != SECSuccess)
    366    return NS_ERROR_FAILURE;
    367 
    368  return NS_OK;
    369 }
    370 
    371 nsresult NSSSocketControl::ActivateSSL() {
    372  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    373  if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
    374    return NS_ERROR_FAILURE;
    375  if (SECSuccess != SSL_ResetHandshake(mFd, false)) return NS_ERROR_FAILURE;
    376 
    377  mHandshakePending = true;
    378 
    379  return SetResumptionTokenFromExternalCache(mFd);
    380 }
    381 
    382 nsresult NSSSocketControl::GetFileDescPtr(PRFileDesc** aFilePtr) {
    383  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    384  *aFilePtr = mFd;
    385  return NS_OK;
    386 }
    387 
    388 nsresult NSSSocketControl::SetFileDescPtr(PRFileDesc* aFilePtr) {
    389  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    390  mFd = aFilePtr;
    391  return NS_OK;
    392 }
    393 
    394 void NSSSocketControl::SetCertVerificationWaiting() {
    395  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    396  // mCertVerificationState may be BeforeCertVerification for the first
    397  // handshake on the connection, or AfterCertVerification for subsequent
    398  // renegotiation handshakes.
    399  MOZ_ASSERT(mCertVerificationState != WaitingForCertVerification,
    400             "Invalid state transition to WaitingForCertVerification");
    401  mCertVerificationState = WaitingForCertVerification;
    402 }
    403 
    404 // Be careful that SetCertVerificationResult does NOT get called while we are
    405 // processing a SSL callback function, because SSL_AuthCertificateComplete will
    406 // attempt to acquire locks that are already held by libssl when it calls
    407 // callbacks.
    408 void NSSSocketControl::SetCertVerificationResult(PRErrorCode errorCode) {
    409  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    410  MOZ_ASSERT(mCertVerificationState == WaitingForCertVerification,
    411             "Invalid state transition to AfterCertVerification");
    412 
    413  if (mFd) {
    414    PRErrorCode passCode = errorCode;
    415    if (errorCode == MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT) {
    416      passCode = 0;
    417    }
    418    SECStatus rv = SSL_AuthCertificateComplete(mFd, passCode);
    419    // Only replace errorCode if there was originally no error.
    420    // SSL_AuthCertificateComplete will return SECFailure with the error code
    421    // set to PR_WOULD_BLOCK_ERROR if there is a pending event to select a
    422    // client authentication certificate. This is not an error.
    423    if (rv != SECSuccess && PR_GetError() != PR_WOULD_BLOCK_ERROR &&
    424        errorCode == 0) {
    425      errorCode = PR_GetError();
    426      if (errorCode == 0) {
    427        NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
    428        errorCode = PR_INVALID_STATE_ERROR;
    429      }
    430    }
    431  }
    432 
    433  if (errorCode &&
    434      errorCode != MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT) {
    435    mFailedVerification = true;
    436    SetCanceled(errorCode);
    437  }
    438 
    439  if (mPlaintextBytesRead && !errorCode) {
    440    glean::ssl::bytes_before_cert_callback.Accumulate(
    441        AssertedCast<uint32_t>(mPlaintextBytesRead));
    442  }
    443 
    444  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    445          ("[%p] SetCertVerificationResult to AfterCertVerification, "
    446           "mTlsHandshakeCallback=%p",
    447           (void*)mFd, mTlsHandshakeCallback.get()));
    448 
    449  mCertVerificationState = AfterCertVerification;
    450  if (mTlsHandshakeCallback) {
    451    (void)mTlsHandshakeCallback->CertVerificationDone();
    452  }
    453 }
    454 
    455 void NSSSocketControl::ClientAuthCertificateSelected(
    456    nsTArray<uint8_t>& certBytes, nsTArray<nsTArray<uint8_t>>& certChainBytes) {
    457  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    458  // If mFd is nullptr, the connection has been closed already, so we don't
    459  // need to do anything here.
    460  if (!mFd) {
    461    return;
    462  }
    463  SECItem certItem = {
    464      siBuffer,
    465      const_cast<uint8_t*>(certBytes.Elements()),
    466      static_cast<unsigned int>(certBytes.Length()),
    467  };
    468  // Ensure that osclientcerts (or ipcclientcerts, in the socket process) will
    469  // populate its list of certificates and keys.
    470  AutoSearchingForClientAuthCertificates _;
    471  UniqueCERTCertificate cert(CERT_NewTempCertificate(
    472      CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
    473  UniqueSECKEYPrivateKey key;
    474  if (cert) {
    475    key.reset(PK11_FindKeyByAnyCert(cert.get(), nullptr));
    476    mClientCertChain.reset(CERT_NewCertList());
    477    if (key && mClientCertChain) {
    478      for (const auto& certBytes : certChainBytes) {
    479        SECItem certItem = {
    480            siBuffer,
    481            const_cast<uint8_t*>(certBytes.Elements()),
    482            static_cast<unsigned int>(certBytes.Length()),
    483        };
    484        UniqueCERTCertificate cert(CERT_NewTempCertificate(
    485            CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
    486        if (cert) {
    487          if (CERT_AddCertToListTail(mClientCertChain.get(), cert.get()) ==
    488              SECSuccess) {
    489            (void)cert.release();
    490          }
    491        }
    492      }
    493    }
    494  }
    495 
    496  bool sendingClientAuthCert = cert && key;
    497  if (sendingClientAuthCert) {
    498    mSentClientCert = true;
    499    glean::security::client_auth_cert_usage.Get("sent"_ns).Add(1);
    500  }
    501 
    502  (void)SSL_ClientCertCallbackComplete(
    503      mFd, sendingClientAuthCert ? SECSuccess : SECFailure,
    504      sendingClientAuthCert ? key.release() : nullptr,
    505      sendingClientAuthCert ? cert.release() : nullptr);
    506 
    507  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    508          ("[%p] ClientAuthCertificateSelected mTlsHandshakeCallback=%p",
    509           (void*)mFd, mTlsHandshakeCallback.get()));
    510  if (mTlsHandshakeCallback) {
    511    (void)mTlsHandshakeCallback->ClientAuthCertificateSelected();
    512  }
    513 }
    514 
    515 NS_IMETHODIMP
    516 NSSSocketControl::DisableEarlyData() {
    517  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    518  if (!mFd) {
    519    return NS_OK;
    520  }
    521  if (IsCanceled()) {
    522    return NS_OK;
    523  }
    524 
    525  if (SSL_OptionSet(mFd, SSL_ENABLE_0RTT_DATA, false) != SECSuccess) {
    526    return NS_ERROR_FAILURE;
    527  }
    528  return NS_OK;
    529 }
    530 
    531 NS_IMETHODIMP
    532 NSSSocketControl::SetHandshakeCallbackListener(
    533    nsITlsHandshakeCallbackListener* callback) {
    534  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    535  mTlsHandshakeCallback = callback;
    536  return NS_OK;
    537 }
    538 
    539 PRStatus NSSSocketControl::CloseSocketAndDestroy() {
    540  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    541 
    542  mClientAuthCertificateRequest.reset();
    543 
    544  PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
    545  MOZ_ASSERT(
    546      popped && popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
    547      "SSL Layer not on top of stack");
    548 
    549  // The plaintext layer is not always present - so it's not a fatal error if it
    550  // cannot be removed.
    551  // Note that PR_PopIOLayer may modify its stack, so a pointer returned by
    552  // PR_GetIdentitiesLayer may not point to what we think it points to after
    553  // calling PR_PopIOLayer. We must operate on the pointer returned by
    554  // PR_PopIOLayer.
    555  if (PR_GetIdentitiesLayer(mFd,
    556                            nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) {
    557    PRFileDesc* poppedPlaintext =
    558        PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
    559    poppedPlaintext->dtor(poppedPlaintext);
    560  }
    561 
    562  // We need to clear the callback to make sure the ssl layer cannot call the
    563  // callback after mFD is nulled.
    564  SSL_SetResumptionTokenCallback(mFd, nullptr, nullptr);
    565 
    566  PRStatus status = mFd->methods->close(mFd);
    567 
    568  // the NSSSocketControl instance can out-live the connection, so we need some
    569  // indication that the connection has been closed. mFd == nullptr is that
    570  // indication. This is needed, for example, when the connection is closed
    571  // before we have finished validating the server's certificate.
    572  mFd = nullptr;
    573 
    574  if (status != PR_SUCCESS) return status;
    575 
    576  popped->identity = PR_INVALID_IO_LAYER;
    577  popped->dtor(popped);
    578 
    579  return PR_SUCCESS;
    580 }
    581 
    582 NS_IMETHODIMP
    583 NSSSocketControl::GetEsniTxt(nsACString& aEsniTxt) {
    584  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    585  aEsniTxt = mEsniTxt;
    586  return NS_OK;
    587 }
    588 
    589 NS_IMETHODIMP
    590 NSSSocketControl::SetEsniTxt(const nsACString& aEsniTxt) {
    591  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    592  mEsniTxt = aEsniTxt;
    593 
    594  if (mEsniTxt.Length()) {
    595    nsAutoCString esniBin;
    596    if (NS_OK != Base64Decode(mEsniTxt, esniBin)) {
    597      MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    598              ("[%p] Invalid ESNIKeys record. Couldn't base64 decode\n",
    599               (void*)mFd));
    600      return NS_OK;
    601    }
    602 
    603    if (SECSuccess !=
    604        SSL_EnableESNI(mFd, reinterpret_cast<const PRUint8*>(esniBin.get()),
    605                       esniBin.Length(), nullptr)) {
    606      MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    607              ("[%p] Invalid ESNIKeys record %s\n", (void*)mFd,
    608               PR_ErrorToName(PR_GetError())));
    609      return NS_OK;
    610    }
    611  }
    612 
    613  return NS_OK;
    614 }
    615 
    616 NS_IMETHODIMP
    617 NSSSocketControl::GetEchConfig(nsACString& aEchConfig) {
    618  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    619  aEchConfig = mEchConfig;
    620  return NS_OK;
    621 }
    622 
    623 NS_IMETHODIMP
    624 NSSSocketControl::SetEchConfig(const nsACString& aEchConfig) {
    625  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    626  mEchConfig = aEchConfig;
    627 
    628  if (mEchConfig.Length()) {
    629    if (SECSuccess !=
    630        SSL_SetClientEchConfigs(
    631            mFd, reinterpret_cast<const PRUint8*>(aEchConfig.BeginReading()),
    632            aEchConfig.Length())) {
    633      MOZ_LOG(gPIPNSSLog, LogLevel::Error,
    634              ("[%p] Invalid EchConfig record %s\n", (void*)mFd,
    635               PR_ErrorToName(PR_GetError())));
    636      return NS_OK;
    637    }
    638    UpdateEchExtensionStatus(EchExtensionStatus::kReal);
    639  }
    640  return NS_OK;
    641 }
    642 
    643 NS_IMETHODIMP
    644 NSSSocketControl::GetRetryEchConfig(nsACString& aEchConfig) {
    645  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    646  if (!mFd) {
    647    return NS_ERROR_FAILURE;
    648  }
    649 
    650  ScopedAutoSECItem retryConfigItem;
    651  SECStatus rv = SSL_GetEchRetryConfigs(mFd, &retryConfigItem);
    652  if (rv != SECSuccess) {
    653    return NS_ERROR_FAILURE;
    654  }
    655  aEchConfig = nsCString(reinterpret_cast<const char*>(retryConfigItem.data),
    656                         retryConfigItem.len);
    657  return NS_OK;
    658 }
    659 
    660 NS_IMETHODIMP
    661 NSSSocketControl::GetPeerId(nsACString& aResult) {
    662  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    663  if (!mPeerId.IsEmpty()) {
    664    aResult.Assign(mPeerId);
    665    return NS_OK;
    666  }
    667 
    668  if (mProviderFlags &
    669      nsISocketProvider::ANONYMOUS_CONNECT) {  // See bug 466080
    670    mPeerId.AppendLiteral("anon:");
    671  }
    672  if (mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE) {
    673    mPeerId.AppendLiteral("private:");
    674  }
    675  if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) {
    676    mPeerId.AppendLiteral("beConservative:");
    677  }
    678 
    679  mPeerId.AppendPrintf("tlsflags0x%08x:", mProviderTlsFlags);
    680 
    681  mPeerId.Append(mHostName);
    682  mPeerId.Append(':');
    683  mPeerId.AppendInt(GetPort());
    684  nsAutoCString suffix;
    685  mOriginAttributes.CreateSuffix(suffix);
    686  mPeerId.Append(suffix);
    687 
    688  aResult.Assign(mPeerId);
    689  return NS_OK;
    690 }
    691 
    692 nsresult NSSSocketControl::SetResumptionTokenFromExternalCache(PRFileDesc* fd) {
    693  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    694  if (!fd) {
    695    return NS_ERROR_INVALID_ARG;
    696  }
    697 
    698  // If SSL_NO_CACHE option was set, we must not use the cache
    699  PRIntn val;
    700  if (SSL_OptionGet(fd, SSL_NO_CACHE, &val) != SECSuccess) {
    701    return NS_ERROR_FAILURE;
    702  }
    703 
    704  if (val != 0) {
    705    return NS_OK;
    706  }
    707 
    708  nsTArray<uint8_t> token;
    709  nsAutoCString peerId;
    710  nsresult rv = GetPeerId(peerId);
    711  if (NS_FAILED(rv)) {
    712    return rv;
    713  }
    714 
    715  uint64_t tokenId = 0;
    716  mozilla::net::SessionCacheInfo info;
    717  rv = mozilla::net::SSLTokensCache::Get(peerId, token, info, &tokenId);
    718  if (NS_FAILED(rv)) {
    719    if (rv == NS_ERROR_NOT_AVAILABLE) {
    720      // It's ok if we can't find the token.
    721      return NS_OK;
    722    }
    723 
    724    return rv;
    725  }
    726 
    727  SECStatus srv = SSL_SetResumptionToken(fd, token.Elements(), token.Length());
    728  if (srv == SECFailure) {
    729    PRErrorCode error = PR_GetError();
    730    mozilla::net::SSLTokensCache::Remove(peerId, tokenId);
    731    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    732            ("Setting token failed with NSS error %d [id=%s]", error,
    733             PromiseFlatCString(peerId).get()));
    734    // We don't consider SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR as a hard error,
    735    // since this error means this token is just expired or can't be decoded
    736    // correctly.
    737    if (error == SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR) {
    738      return NS_OK;
    739    }
    740 
    741    return NS_ERROR_FAILURE;
    742  }
    743 
    744  SetSessionCacheInfo(std::move(info));
    745 
    746  return NS_OK;
    747 }
    748 
    749 void NSSSocketControl::SetPreliminaryHandshakeInfo(
    750    const SSLChannelInfo& channelInfo, const SSLCipherSuiteInfo& cipherInfo) {
    751  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    752  mResumed = channelInfo.resumed;
    753  mCipherSuite.emplace(channelInfo.cipherSuite);
    754  mProtocolVersion.emplace(channelInfo.protocolVersion & 0xFF);
    755  mKeaGroupName.emplace(getKeaGroupName(channelInfo.keaGroup));
    756  mSignatureSchemeName.emplace(getSignatureName(channelInfo.signatureScheme));
    757  mIsDelegatedCredential.emplace(channelInfo.peerDelegCred);
    758  mIsAcceptedEch.emplace(channelInfo.echAccepted);
    759 }
    760 
    761 void NSSSocketControl::MaybeSelectClientAuthCertificate() {
    762  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    763  if (!IsWaitingForCertVerification() && mClaimed &&
    764      mClientAuthCertificateRequest.isSome()) {
    765    MOZ_LOG(gPIPNSSLog, mozilla::LogLevel::Debug,
    766            ("[%p] selecting client auth certificate", (void*)mFd));
    767    ClientAuthCertificateRequest request(
    768        mClientAuthCertificateRequest.extract());
    769    DoSelectClientAuthCertificate(this, std::move(request.mServerCertificate),
    770                                  std::move(request.mCANames));
    771  }
    772 }
    773 
    774 NS_IMETHODIMP NSSSocketControl::Claim() {
    775  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    776  mClaimed = true;
    777  return NS_OK;
    778 }
    779 
    780 NS_IMETHODIMP NSSSocketControl::SetBrowserId(uint64_t browserId) {
    781  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    782  mBrowserId = browserId;
    783  return NS_OK;
    784 }
    785 
    786 NS_IMETHODIMP NSSSocketControl::GetBrowserId(uint64_t* browserId) {
    787  COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
    788  if (!browserId) {
    789    return NS_ERROR_INVALID_ARG;
    790  }
    791  *browserId = mBrowserId;
    792  return NS_OK;
    793 }