tor-browser

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

nsNSSCallbacks.cpp (37871B)


      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 "nsNSSCallbacks.h"
      8 
      9 #include "NSSSocketControl.h"
     10 #include "PSMRunnable.h"
     11 #include "ScopedNSSTypes.h"
     12 #include "SharedCertVerifier.h"
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/Casting.h"
     15 #include "mozilla/Logging.h"
     16 #include "mozilla/RefPtr.h"
     17 #include "mozilla/ScopeExit.h"
     18 #include "mozilla/Span.h"
     19 #include "mozilla/SpinEventLoopUntil.h"
     20 #include "mozilla/StaticPrefs_security.h"
     21 #include "mozilla/glean/SecurityManagerSslMetrics.h"
     22 #include "mozilla/intl/Localization.h"
     23 #include "nsContentUtils.h"
     24 #include "nsIChannel.h"
     25 #include "nsIHttpChannel.h"
     26 #include "nsIHttpChannelInternal.h"
     27 #include "nsIPrompt.h"
     28 #include "nsIProtocolProxyService.h"
     29 #include "nsISupportsPriority.h"
     30 #include "nsIStreamLoader.h"
     31 #include "nsIUploadChannel.h"
     32 #include "nsIWebProgressListener.h"
     33 #include "nsNSSCertHelper.h"
     34 #include "nsNSSCertificate.h"
     35 #include "nsNSSComponent.h"
     36 #include "nsNSSHelper.h"
     37 #include "nsNSSIOLayer.h"
     38 #include "nsNetUtil.h"
     39 #include "nsProxyRelease.h"
     40 #include "nsStringStream.h"
     41 #include "mozpkix/pkixtypes.h"
     42 #include "ssl.h"
     43 #include "sslproto.h"
     44 #include "SSLTokensCache.h"
     45 
     46 using namespace mozilla;
     47 using namespace mozilla::pkix;
     48 using namespace mozilla::psm;
     49 
     50 extern LazyLogModule gPIPNSSLog;
     51 
     52 namespace {
     53 
     54 // Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe
     55 // These bits are numbered so that the least subtle issues have higher values.
     56 // This should make it easier for us to interpret the results.
     57 const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4;
     58 const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2;
     59 const uint32_t KEA_NOT_SUPPORTED = 1;
     60 
     61 }  // namespace
     62 
     63 class OCSPRequest final : public nsIStreamLoaderObserver, public nsIRunnable {
     64 public:
     65  OCSPRequest(const nsACString& aiaLocation,
     66              const OriginAttributes& originAttributes,
     67              const uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH],
     68              size_t ocspRequestLength, TimeDuration timeout);
     69 
     70  NS_DECL_THREADSAFE_ISUPPORTS
     71  NS_DECL_NSISTREAMLOADEROBSERVER
     72  NS_DECL_NSIRUNNABLE
     73 
     74  nsresult DispatchToMainThreadAndWait();
     75  nsresult GetResponse(/*out*/ Vector<uint8_t>& response);
     76 
     77 private:
     78  ~OCSPRequest() = default;
     79 
     80  static void OnTimeout(nsITimer* timer, void* closure);
     81  nsresult NotifyDone(nsresult rv, MonitorAutoLock& proofOfLock);
     82 
     83  // mMonitor provides the memory barrier protecting these member variables.
     84  // What happens is the originating thread creates an OCSPRequest object with
     85  // the information necessary to perform an OCSP request. It sends the object
     86  // to the main thread and waits on the monitor for the operation to complete.
     87  // On the main thread, a channel is set up to perform the request. This gets
     88  // dispatched to necko. At the same time, a timeout timer is initialized. If
     89  // the necko request completes, the response data is filled out, mNotifiedDone
     90  // is set to true, and the monitor is notified. The original thread then wakes
     91  // up and continues with the results that have been filled out. If the request
     92  // times out, again the response data is filled out, mNotifiedDone is set to
     93  // true, and the monitor is notified. The first of these two events wins. That
     94  // is, if the timeout timer fires but the request completes shortly after, the
     95  // caller will see the request as having timed out.
     96  // When the request completes (i.e. OnStreamComplete runs), the timer will be
     97  // cancelled. This is how we know the closure in OnTimeout is valid. If the
     98  // timer fires before OnStreamComplete runs, it should be safe to not cancel
     99  // the request because necko has a strong reference to it.
    100  Monitor mMonitor MOZ_UNANNOTATED;
    101  bool mNotifiedDone;
    102  nsCOMPtr<nsIStreamLoader> mLoader;
    103  const nsCString mAIALocation;
    104  const OriginAttributes mOriginAttributes;
    105  const mozilla::Span<const char> mPOSTData;
    106  const TimeDuration mTimeout;
    107  nsCOMPtr<nsITimer> mTimeoutTimer;
    108  TimeStamp mStartTime;
    109  nsresult mResponseResult;
    110  Vector<uint8_t> mResponseBytes;
    111 };
    112 
    113 NS_IMPL_ISUPPORTS(OCSPRequest, nsIStreamLoaderObserver, nsIRunnable)
    114 
    115 OCSPRequest::OCSPRequest(const nsACString& aiaLocation,
    116                         const OriginAttributes& originAttributes,
    117                         const uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH],
    118                         size_t ocspRequestLength, TimeDuration timeout)
    119    : mMonitor("OCSPRequest.mMonitor"),
    120      mNotifiedDone(false),
    121      mLoader(nullptr),
    122      mAIALocation(aiaLocation),
    123      mOriginAttributes(originAttributes),
    124      mPOSTData(reinterpret_cast<const char*>(ocspRequest), ocspRequestLength),
    125      mTimeout(timeout),
    126      mTimeoutTimer(nullptr),
    127      mResponseResult(NS_ERROR_FAILURE) {
    128  MOZ_ASSERT(ocspRequestLength <= OCSP_REQUEST_MAX_LENGTH);
    129 }
    130 
    131 nsresult OCSPRequest::DispatchToMainThreadAndWait() {
    132  MOZ_ASSERT(!NS_IsMainThread());
    133  if (NS_IsMainThread()) {
    134    return NS_ERROR_FAILURE;
    135  }
    136 
    137  MonitorAutoLock lock(mMonitor);
    138  nsresult rv = NS_DispatchToMainThread(this);
    139  if (NS_FAILED(rv)) {
    140    return rv;
    141  }
    142  while (!mNotifiedDone) {
    143    lock.Wait();
    144  }
    145 
    146  // CERT_VALIDATION_HTTP_REQUEST_RESULT:
    147  // 0: request timed out
    148  // 1: request succeeded
    149  // 2: request failed
    150  // 3: internal error
    151  // If mStartTime was never set, we consider this an internal error.
    152  // Otherwise, we managed to at least send the request.
    153  if (mStartTime.IsNull()) {
    154    glean::cert::validation_http_request_result.AccumulateSingleSample(3);
    155  } else if (mResponseResult == NS_ERROR_NET_TIMEOUT) {
    156    glean::cert::validation_http_request_result.AccumulateSingleSample(0);
    157    mozilla::glean::ocsp_request_time::cancel.AccumulateRawDuration(
    158        TimeStamp::Now() - mStartTime);
    159  } else if (NS_SUCCEEDED(mResponseResult)) {
    160    glean::cert::validation_http_request_result.AccumulateSingleSample(1);
    161    mozilla::glean::ocsp_request_time::success.AccumulateRawDuration(
    162        TimeStamp::Now() - mStartTime);
    163  } else {
    164    glean::cert::validation_http_request_result.AccumulateSingleSample(2);
    165    mozilla::glean::ocsp_request_time::failure.AccumulateRawDuration(
    166        TimeStamp::Now() - mStartTime);
    167  }
    168  return rv;
    169 }
    170 
    171 nsresult OCSPRequest::GetResponse(/*out*/ Vector<uint8_t>& response) {
    172  MOZ_ASSERT(!NS_IsMainThread());
    173  if (NS_IsMainThread()) {
    174    return NS_ERROR_FAILURE;
    175  }
    176 
    177  MonitorAutoLock lock(mMonitor);
    178  if (!mNotifiedDone) {
    179    return NS_ERROR_IN_PROGRESS;
    180  }
    181  if (NS_FAILED(mResponseResult)) {
    182    return mResponseResult;
    183  }
    184  response.clear();
    185  if (!response.append(mResponseBytes.begin(), mResponseBytes.length())) {
    186    return NS_ERROR_OUT_OF_MEMORY;
    187  }
    188  return NS_OK;
    189 }
    190 
    191 static constexpr auto OCSP_REQUEST_MIME_TYPE = "application/ocsp-request"_ns;
    192 static constexpr auto OCSP_REQUEST_METHOD = "POST"_ns;
    193 
    194 NS_IMETHODIMP
    195 OCSPRequest::Run() {
    196  MOZ_ASSERT(NS_IsMainThread());
    197  if (!NS_IsMainThread()) {
    198    return NS_ERROR_FAILURE;
    199  }
    200 
    201  MonitorAutoLock lock(mMonitor);
    202 
    203  nsCOMPtr<nsIIOService> ios = do_GetIOService();
    204  if (!ios) {
    205    return NotifyDone(NS_ERROR_FAILURE, lock);
    206  }
    207 
    208  nsCOMPtr<nsIURI> uri;
    209  nsresult rv = NS_NewURI(getter_AddRefs(uri), mAIALocation);
    210  if (NS_FAILED(rv)) {
    211    return NotifyDone(NS_ERROR_MALFORMED_URI, lock);
    212  }
    213  nsAutoCString scheme;
    214  rv = uri->GetScheme(scheme);
    215  if (NS_FAILED(rv)) {
    216    return NotifyDone(rv, lock);
    217  }
    218  if (!scheme.LowerCaseEqualsLiteral("http")) {
    219    return NotifyDone(NS_ERROR_MALFORMED_URI, lock);
    220  }
    221 
    222  // See bug 1219935.
    223  // We should not send OCSP request if the PAC is still loading.
    224  nsCOMPtr<nsIProtocolProxyService> pps =
    225      do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
    226  if (NS_FAILED(rv)) {
    227    return NotifyDone(rv, lock);
    228  }
    229 
    230  if (pps->GetIsPACLoading()) {
    231    return NotifyDone(NS_ERROR_FAILURE, lock);
    232  }
    233 
    234  nsCOMPtr<nsIChannel> channel;
    235  rv = ios->NewChannel(mAIALocation, nullptr, nullptr,
    236                       nullptr,  // aLoadingNode
    237                       nsContentUtils::GetSystemPrincipal(),
    238                       nullptr,  // aTriggeringPrincipal
    239                       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    240                       nsIContentPolicy::TYPE_OTHER, getter_AddRefs(channel));
    241  if (NS_FAILED(rv)) {
    242    return NotifyDone(rv, lock);
    243  }
    244 
    245  // Security operations scheduled through normal HTTP channels are given
    246  // high priority to accommodate real time OCSP transactions.
    247  nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(channel);
    248  if (priorityChannel) {
    249    priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
    250  }
    251 
    252  channel->SetLoadFlags(
    253      nsIRequest::LOAD_ANONYMOUS | nsIRequest::LOAD_BYPASS_CACHE |
    254      nsIRequest::INHIBIT_CACHING | nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
    255      nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
    256 
    257  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    258 
    259  // Prevent HTTPS-Only Mode from upgrading the OCSP request.
    260  uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
    261  httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
    262  loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
    263 
    264  // allow deprecated HTTP request from SystemPrincipal
    265  loadInfo->SetAllowDeprecatedSystemRequests(true);
    266 
    267  // For OCSP requests, only the first party domain and private browsing id
    268  // aspects of origin attributes are used. This means that:
    269  // a) if first party isolation is enabled, OCSP requests will be isolated
    270  // according to the first party domain of the original https request
    271  // b) OCSP requests are shared across different containers as long as first
    272  // party isolation is not enabled and none of the containers are in private
    273  // browsing mode.
    274  if (mOriginAttributes != OriginAttributes()) {
    275    OriginAttributes attrs;
    276    attrs.mFirstPartyDomain = mOriginAttributes.mFirstPartyDomain;
    277    attrs.mPrivateBrowsingId = mOriginAttributes.mPrivateBrowsingId;
    278 
    279    rv = loadInfo->SetOriginAttributes(attrs);
    280    if (NS_FAILED(rv)) {
    281      return NotifyDone(rv, lock);
    282    }
    283  }
    284 
    285  nsCOMPtr<nsIInputStream> uploadStream;
    286  rv = NS_NewByteInputStream(getter_AddRefs(uploadStream), mPOSTData,
    287                             NS_ASSIGNMENT_COPY);
    288  if (NS_FAILED(rv)) {
    289    return NotifyDone(rv, lock);
    290  }
    291  nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(channel));
    292  if (!uploadChannel) {
    293    return NotifyDone(NS_ERROR_FAILURE, lock);
    294  }
    295  rv = uploadChannel->SetUploadStream(uploadStream, OCSP_REQUEST_MIME_TYPE, -1);
    296  if (NS_FAILED(rv)) {
    297    return NotifyDone(rv, lock);
    298  }
    299  // Do not use SPDY or HTTP3 for internal security operations. It could result
    300  // in the silent upgrade to ssl, which in turn could require an SSL
    301  // operation to fulfill something like an OCSP fetch, which is an
    302  // endless loop.
    303  nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(channel);
    304  if (!internalChannel) {
    305    return NotifyDone(rv, lock);
    306  }
    307  rv = internalChannel->SetAllowSpdy(false);
    308  if (NS_FAILED(rv)) {
    309    return NotifyDone(rv, lock);
    310  }
    311  rv = internalChannel->SetAllowHttp3(false);
    312  if (NS_FAILED(rv)) {
    313    return NotifyDone(rv, lock);
    314  }
    315  rv = internalChannel->SetIsOCSP(true);
    316  if (NS_FAILED(rv)) {
    317    return NotifyDone(rv, lock);
    318  }
    319  nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(channel);
    320  if (!hchan) {
    321    return NotifyDone(NS_ERROR_FAILURE, lock);
    322  }
    323  rv = hchan->SetAllowSTS(false);
    324  if (NS_FAILED(rv)) {
    325    return NotifyDone(rv, lock);
    326  }
    327  rv = hchan->SetRequestMethod(OCSP_REQUEST_METHOD);
    328  if (NS_FAILED(rv)) {
    329    return NotifyDone(rv, lock);
    330  }
    331 
    332  rv = NS_NewStreamLoader(getter_AddRefs(mLoader), this);
    333  if (NS_FAILED(rv)) {
    334    return NotifyDone(rv, lock);
    335  }
    336 
    337  rv = NS_NewTimerWithFuncCallback(
    338      getter_AddRefs(mTimeoutTimer), OCSPRequest::OnTimeout, this,
    339      mTimeout.ToMilliseconds(), nsITimer::TYPE_ONE_SHOT,
    340      "OCSPRequest::Run"_ns);
    341  if (NS_FAILED(rv)) {
    342    return NotifyDone(rv, lock);
    343  }
    344  rv = hchan->AsyncOpen(this->mLoader);
    345  if (NS_FAILED(rv)) {
    346    return NotifyDone(rv, lock);
    347  }
    348  mStartTime = TimeStamp::Now();
    349  return NS_OK;
    350 }
    351 
    352 nsresult OCSPRequest::NotifyDone(nsresult rv, MonitorAutoLock& lock) {
    353  MOZ_ASSERT(NS_IsMainThread());
    354  if (!NS_IsMainThread()) {
    355    return NS_ERROR_FAILURE;
    356  }
    357 
    358  if (mNotifiedDone) {
    359    return mResponseResult;
    360  }
    361  mLoader = nullptr;
    362  mResponseResult = rv;
    363  if (mTimeoutTimer) {
    364    (void)mTimeoutTimer->Cancel();
    365  }
    366  mNotifiedDone = true;
    367  lock.Notify();
    368  return rv;
    369 }
    370 
    371 NS_IMETHODIMP
    372 OCSPRequest::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
    373                              nsresult aStatus, uint32_t responseLen,
    374                              const uint8_t* responseBytes) {
    375  MOZ_ASSERT(NS_IsMainThread());
    376  if (!NS_IsMainThread()) {
    377    return NS_ERROR_FAILURE;
    378  }
    379 
    380  MonitorAutoLock lock(mMonitor);
    381 
    382  nsCOMPtr<nsIRequest> req;
    383  nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
    384  if (NS_FAILED(rv)) {
    385    return NotifyDone(rv, lock);
    386  }
    387 
    388  if (NS_FAILED(aStatus)) {
    389    return NotifyDone(aStatus, lock);
    390  }
    391 
    392  nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(req);
    393  if (!hchan) {
    394    return NotifyDone(NS_ERROR_FAILURE, lock);
    395  }
    396 
    397  bool requestSucceeded;
    398  rv = hchan->GetRequestSucceeded(&requestSucceeded);
    399  if (NS_FAILED(rv)) {
    400    return NotifyDone(rv, lock);
    401  }
    402  if (!requestSucceeded) {
    403    return NotifyDone(NS_ERROR_FAILURE, lock);
    404  }
    405 
    406  unsigned int rcode;
    407  rv = hchan->GetResponseStatus(&rcode);
    408  if (NS_FAILED(rv)) {
    409    return NotifyDone(rv, lock);
    410  }
    411  if (rcode != 200) {
    412    return NotifyDone(NS_ERROR_FAILURE, lock);
    413  }
    414 
    415  mResponseBytes.clear();
    416  if (!mResponseBytes.append(responseBytes, responseLen)) {
    417    return NotifyDone(NS_ERROR_OUT_OF_MEMORY, lock);
    418  }
    419  mResponseResult = aStatus;
    420 
    421  return NotifyDone(NS_OK, lock);
    422 }
    423 
    424 void OCSPRequest::OnTimeout(nsITimer* timer, void* closure) {
    425  MOZ_ASSERT(NS_IsMainThread());
    426  if (!NS_IsMainThread()) {
    427    return;
    428  }
    429 
    430  // We know the OCSPRequest is still alive because if the request had completed
    431  // (i.e. OnStreamComplete ran), the timer would have been cancelled in
    432  // NotifyDone.
    433  OCSPRequest* self = static_cast<OCSPRequest*>(closure);
    434  MonitorAutoLock lock(self->mMonitor);
    435  self->mTimeoutTimer = nullptr;
    436  self->NotifyDone(NS_ERROR_NET_TIMEOUT, lock);
    437 }
    438 
    439 mozilla::pkix::Result DoOCSPRequest(
    440    const nsCString& aiaLocation, const OriginAttributes& originAttributes,
    441    uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH], size_t ocspRequestLength,
    442    TimeDuration timeout, /*out*/ Vector<uint8_t>& result) {
    443  MOZ_ASSERT(!NS_IsMainThread());
    444  if (NS_IsMainThread()) {
    445    return mozilla::pkix::Result::ERROR_OCSP_UNKNOWN_CERT;
    446  }
    447 
    448  if (ocspRequestLength > OCSP_REQUEST_MAX_LENGTH) {
    449    return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
    450  }
    451 
    452  result.clear();
    453  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    454          ("DoOCSPRequest to '%s'", aiaLocation.get()));
    455 
    456  nsCOMPtr<nsIEventTarget> sts =
    457      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
    458  MOZ_ASSERT(sts);
    459  if (!sts) {
    460    return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE;
    461  }
    462  bool onSTSThread;
    463  nsresult rv = sts->IsOnCurrentThread(&onSTSThread);
    464  if (NS_FAILED(rv)) {
    465    return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
    466  }
    467  MOZ_ASSERT(!onSTSThread);
    468  if (onSTSThread) {
    469    return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE;
    470  }
    471 
    472  RefPtr<OCSPRequest> request(new OCSPRequest(
    473      aiaLocation, originAttributes, ocspRequest, ocspRequestLength, timeout));
    474  rv = request->DispatchToMainThreadAndWait();
    475  if (NS_FAILED(rv)) {
    476    return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
    477  }
    478  rv = request->GetResponse(result);
    479  if (NS_FAILED(rv)) {
    480    if (rv == NS_ERROR_MALFORMED_URI) {
    481      return mozilla::pkix::Result::ERROR_CERT_BAD_ACCESS_LOCATION;
    482    }
    483    return mozilla::pkix::Result::ERROR_OCSP_SERVER_ERROR;
    484  }
    485  return Success;
    486 }
    487 
    488 static char* ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIPrompt* prompt) {
    489  MOZ_ASSERT(NS_IsMainThread());
    490  MOZ_ASSERT(slot);
    491  MOZ_ASSERT(prompt);
    492  if (!NS_IsMainThread() || !slot || !prompt) {
    493    return nullptr;
    494  }
    495 
    496  // Dispatch a background task to (eventually) call C_Login. The call will
    497  // block until the protected authentication succeeds or fails.
    498  Atomic<bool> done;
    499  Atomic<SECStatus> result;
    500  nsresult rv =
    501      NS_DispatchBackgroundTask(NS_NewRunnableFunction(__func__, [&]() mutable {
    502        result = PK11_CheckUserPassword(slot, nullptr);
    503        done = true;
    504      }));
    505  if (NS_FAILED(rv)) {
    506    return nullptr;
    507  }
    508 
    509  nsTArray<nsCString> resIds = {
    510      "security/pippki/pippki.ftl"_ns,
    511  };
    512  RefPtr<mozilla::intl::Localization> l10n =
    513      mozilla::intl::Localization::Create(resIds, true);
    514  auto l10nId = "protected-auth-alert"_ns;
    515  auto l10nArgs = mozilla::dom::Optional<intl::L10nArgs>();
    516  l10nArgs.Construct();
    517  auto dirArg = l10nArgs.Value().Entries().AppendElement();
    518  dirArg->mKey = "tokenName"_ns;
    519  dirArg->mValue.SetValue().SetAsUTF8String().Assign(PK11_GetTokenName(slot));
    520  nsAutoCString promptString;
    521  ErrorResult errorResult;
    522  l10n->FormatValueSync(l10nId, l10nArgs, promptString, errorResult);
    523  if (NS_FAILED(errorResult.StealNSResult())) {
    524    return nullptr;
    525  }
    526  rv = prompt->Alert(nullptr, NS_ConvertUTF8toUTF16(promptString).get());
    527  if (NS_FAILED(rv)) {
    528    return nullptr;
    529  }
    530 
    531  MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
    532      "ShowProtectedAuthPrompt"_ns, [&]() { return static_cast<bool>(done); }));
    533 
    534  switch (result) {
    535    case SECSuccess:
    536      return ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
    537    case SECWouldBlock:
    538      return ToNewCString(nsDependentCString(PK11_PW_RETRY));
    539    default:
    540      return nullptr;
    541  }
    542 }
    543 
    544 class PK11PasswordPromptRunnable : public SyncRunnableBase {
    545 public:
    546  PK11PasswordPromptRunnable(PK11SlotInfo* slot, nsIInterfaceRequestor* ir)
    547      : mResult(nullptr), mSlot(slot), mIR(ir) {}
    548  virtual ~PK11PasswordPromptRunnable() = default;
    549 
    550  char* mResult;  // out
    551  virtual void RunOnTargetThread() override;
    552 
    553 private:
    554  static bool mRunning;
    555 
    556  PK11SlotInfo* mSlot;
    557  nsIInterfaceRequestor* mIR;
    558 };
    559 
    560 bool PK11PasswordPromptRunnable::mRunning = false;
    561 
    562 void PK11PasswordPromptRunnable::RunOnTargetThread() {
    563  MOZ_ASSERT(NS_IsMainThread());
    564  if (!NS_IsMainThread()) {
    565    return;
    566  }
    567 
    568  // If we've reentered due to the nested event loop implicit in using
    569  // nsIPrompt synchronously (or indeed the explicit nested event loop in the
    570  // protected authentication case), bail early, cancelling the password
    571  // prompt. This will probably cause the operation that resulted in the prompt
    572  // to fail, but this is better than littering the screen with a bunch of
    573  // password prompts that the user will probably just cancel anyway.
    574  if (mRunning) {
    575    return;
    576  }
    577  mRunning = true;
    578  auto setRunningToFalseOnExit = MakeScopeExit([&]() { mRunning = false; });
    579 
    580  nsresult rv;
    581  nsCOMPtr<nsIPrompt> prompt;
    582  if (!mIR) {
    583    rv = nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
    584    if (NS_FAILED(rv)) {
    585      return;
    586    }
    587  } else {
    588    prompt = do_GetInterface(mIR);
    589    MOZ_ASSERT(prompt, "Interface requestor should implement nsIPrompt");
    590  }
    591 
    592  if (!prompt) {
    593    return;
    594  }
    595 
    596  if (PK11_ProtectedAuthenticationPath(mSlot)) {
    597    mResult = ShowProtectedAuthPrompt(mSlot, prompt);
    598    return;
    599  }
    600 
    601  nsAutoString promptString;
    602  if (PK11_IsInternal(mSlot)) {
    603    rv = GetPIPNSSBundleString("CertPasswordPromptDefault", promptString);
    604  } else {
    605    AutoTArray<nsString, 1> formatStrings = {
    606        NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot))};
    607    rv = PIPBundleFormatStringFromName("CertPasswordPrompt", formatStrings,
    608                                       promptString);
    609  }
    610  if (NS_FAILED(rv)) {
    611    return;
    612  }
    613 
    614  nsString password;
    615  bool userClickedOK = false;
    616  rv = prompt->PromptPassword(nullptr, promptString.get(),
    617                              getter_Copies(password), &userClickedOK);
    618  if (NS_FAILED(rv) || !userClickedOK) {
    619    return;
    620  }
    621 
    622  mResult = ToNewUTF8String(password);
    623 }
    624 
    625 char* PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg) {
    626  if (!slot) {
    627    return nullptr;
    628  }
    629  RefPtr<PK11PasswordPromptRunnable> runnable(new PK11PasswordPromptRunnable(
    630      slot, static_cast<nsIInterfaceRequestor*>(arg)));
    631  runnable->DispatchToMainThreadAndWait();
    632  return runnable->mResult;
    633 }
    634 
    635 nsCString getKeaGroupName(uint32_t aKeaGroup) {
    636  nsCString groupName;
    637  switch (aKeaGroup) {
    638    case ssl_grp_ec_secp256r1:
    639      groupName = "P256"_ns;
    640      break;
    641    case ssl_grp_ec_secp384r1:
    642      groupName = "P384"_ns;
    643      break;
    644    case ssl_grp_ec_secp521r1:
    645      groupName = "P521"_ns;
    646      break;
    647    case ssl_grp_ec_curve25519:
    648      groupName = "x25519"_ns;
    649      break;
    650    case ssl_grp_kem_xyber768d00:
    651      groupName = "xyber768d00"_ns;
    652      break;
    653    case ssl_grp_kem_mlkem768x25519:
    654      groupName = "mlkem768x25519"_ns;
    655      break;
    656    case ssl_grp_kem_secp256r1mlkem768:
    657      groupName = "secp256r1mlkem768"_ns;
    658      break;
    659    case ssl_grp_kem_secp384r1mlkem1024:
    660      groupName = "secp384r1mlkem1024"_ns;
    661      break;
    662    case ssl_grp_ffdhe_2048:
    663      groupName = "FF 2048"_ns;
    664      break;
    665    case ssl_grp_ffdhe_3072:
    666      groupName = "FF 3072"_ns;
    667      break;
    668    case ssl_grp_none:
    669      groupName = "none"_ns;
    670      break;
    671    case ssl_grp_ffdhe_custom:
    672      groupName = "custom"_ns;
    673      break;
    674    // All other groups are not enabled in Firefox. See namedGroups in
    675    // nsNSSIOLayer.cpp.
    676    default:
    677      // This really shouldn't happen!
    678      MOZ_ASSERT_UNREACHABLE("Invalid key exchange group.");
    679      groupName = "unknown group"_ns;
    680  }
    681  return groupName;
    682 }
    683 
    684 nsCString getSignatureName(uint32_t aSignatureScheme) {
    685  nsCString signatureName;
    686  switch (aSignatureScheme) {
    687    case ssl_sig_none:
    688      signatureName = "none"_ns;
    689      break;
    690    case ssl_sig_rsa_pkcs1_sha1:
    691      signatureName = "RSA-PKCS1-SHA1"_ns;
    692      break;
    693    case ssl_sig_rsa_pkcs1_sha256:
    694      signatureName = "RSA-PKCS1-SHA256"_ns;
    695      break;
    696    case ssl_sig_rsa_pkcs1_sha384:
    697      signatureName = "RSA-PKCS1-SHA384"_ns;
    698      break;
    699    case ssl_sig_rsa_pkcs1_sha512:
    700      signatureName = "RSA-PKCS1-SHA512"_ns;
    701      break;
    702    case ssl_sig_ecdsa_secp256r1_sha256:
    703      signatureName = "ECDSA-P256-SHA256"_ns;
    704      break;
    705    case ssl_sig_ecdsa_secp384r1_sha384:
    706      signatureName = "ECDSA-P384-SHA384"_ns;
    707      break;
    708    case ssl_sig_ecdsa_secp521r1_sha512:
    709      signatureName = "ECDSA-P521-SHA512"_ns;
    710      break;
    711    case ssl_sig_rsa_pss_sha256:
    712      signatureName = "RSA-PSS-SHA256"_ns;
    713      break;
    714    case ssl_sig_rsa_pss_sha384:
    715      signatureName = "RSA-PSS-SHA384"_ns;
    716      break;
    717    case ssl_sig_rsa_pss_sha512:
    718      signatureName = "RSA-PSS-SHA512"_ns;
    719      break;
    720    case ssl_sig_ecdsa_sha1:
    721      signatureName = "ECDSA-SHA1"_ns;
    722      break;
    723    case ssl_sig_rsa_pkcs1_sha1md5:
    724      signatureName = "RSA-PKCS1-SHA1MD5"_ns;
    725      break;
    726    // All other groups are not enabled in Firefox. See sEnabledSignatureSchemes
    727    // in nsNSSIOLayer.cpp.
    728    default:
    729      // This really shouldn't happen!
    730      MOZ_ASSERT_UNREACHABLE("Invalid signature scheme.");
    731      signatureName = "unknown signature"_ns;
    732  }
    733  return signatureName;
    734 }
    735 
    736 static void PreliminaryHandshakeDone(PRFileDesc* fd) {
    737  NSSSocketControl* socketControl = (NSSSocketControl*)fd->higher->secret;
    738  if (!socketControl) {
    739    return;
    740  }
    741  if (socketControl->IsPreliminaryHandshakeDone()) {
    742    return;
    743  }
    744 
    745  SSLChannelInfo channelInfo;
    746  if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
    747    return;
    748  }
    749  SSLCipherSuiteInfo cipherInfo;
    750  if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
    751                             sizeof(cipherInfo)) != SECSuccess) {
    752    return;
    753  }
    754  socketControl->SetPreliminaryHandshakeInfo(channelInfo, cipherInfo);
    755  socketControl->SetSSLVersionUsed(channelInfo.protocolVersion);
    756  socketControl->SetEarlyDataAccepted(channelInfo.earlyDataAccepted);
    757  socketControl->SetKEAUsed(channelInfo.keaType);
    758  socketControl->SetKEAKeyBits(channelInfo.keaKeyBits);
    759  socketControl->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
    760 
    761  // Get the NPN value.
    762  SSLNextProtoState state;
    763  unsigned char npnbuf[256];
    764  unsigned int npnlen;
    765 
    766  if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen,
    767                       AssertedCast<unsigned int>(std::size(npnbuf))) ==
    768      SECSuccess) {
    769    if (state == SSL_NEXT_PROTO_NEGOTIATED ||
    770        state == SSL_NEXT_PROTO_SELECTED) {
    771      socketControl->SetNegotiatedNPN(
    772          BitwiseCast<char*, unsigned char*>(npnbuf), npnlen);
    773    } else {
    774      socketControl->SetNegotiatedNPN(nullptr, 0);
    775    }
    776    mozilla::glean::ssl::npn_type.AccumulateSingleSample(state);
    777  } else {
    778    socketControl->SetNegotiatedNPN(nullptr, 0);
    779  }
    780 
    781  socketControl->SetPreliminaryHandshakeDone();
    782 }
    783 
    784 SECStatus CanFalseStartCallback(PRFileDesc* fd, void* client_data,
    785                                PRBool* canFalseStart) {
    786  *canFalseStart = false;
    787 
    788  NSSSocketControl* infoObject = (NSSSocketControl*)fd->higher->secret;
    789  if (!infoObject) {
    790    PR_SetError(PR_INVALID_STATE_ERROR, 0);
    791    return SECFailure;
    792  }
    793 
    794  infoObject->SetFalseStartCallbackCalled();
    795 
    796  PreliminaryHandshakeDone(fd);
    797 
    798  uint32_t reasonsForNotFalseStarting = 0;
    799 
    800  SSLChannelInfo channelInfo;
    801  if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
    802    return SECSuccess;
    803  }
    804 
    805  SSLCipherSuiteInfo cipherInfo;
    806  if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
    807                             sizeof(cipherInfo)) != SECSuccess) {
    808    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    809            ("CanFalseStartCallback [%p] failed - "
    810             " KEA %d\n",
    811             fd, static_cast<int32_t>(channelInfo.keaType)));
    812    return SECSuccess;
    813  }
    814 
    815  // Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
    816  // TLS 1.3 and later. See Bug 861310 for all the details as to why.
    817  if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) {
    818    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    819            ("CanFalseStartCallback [%p] failed - "
    820             "SSL Version must be TLS 1.2, was %x\n",
    821             fd, static_cast<int32_t>(channelInfo.protocolVersion)));
    822    reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
    823  }
    824 
    825  // See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not.
    826  // Also note that ecdh_hybrid groups are not supported in TLS 1.2 and are out
    827  // of scope.
    828  if (channelInfo.keaType != ssl_kea_ecdh) {
    829    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    830            ("CanFalseStartCallback [%p] failed - "
    831             "unsupported KEA %d\n",
    832             fd, static_cast<int32_t>(channelInfo.keaType)));
    833    reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
    834  }
    835 
    836  // Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
    837  // mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
    838  // design. See bug 1109766 for more details.
    839  if (cipherInfo.macAlgorithm != ssl_mac_aead) {
    840    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    841            ("CanFalseStartCallback [%p] failed - non-AEAD cipher used, %d, "
    842             "is not supported with False Start.\n",
    843             fd, static_cast<int32_t>(cipherInfo.symCipher)));
    844    reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
    845  }
    846 
    847  // XXX: An attacker can choose which protocols are advertised in the
    848  // NPN extension. TODO(Bug 861311): We should restrict the ability
    849  // of an attacker leverage this capability by restricting false start
    850  // to the same protocol we previously saw for the server, after the
    851  // first successful connection to the server.
    852 
    853  glean::ssl::reasons_for_not_false_starting.AccumulateSingleSample(
    854      reasonsForNotFalseStarting);
    855 
    856  if (reasonsForNotFalseStarting == 0) {
    857    *canFalseStart = PR_TRUE;
    858    infoObject->SetFalseStarted();
    859    infoObject->NoteTimeUntilReady();
    860    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    861            ("CanFalseStartCallback [%p] ok\n", fd));
    862  }
    863 
    864  return SECSuccess;
    865 }
    866 
    867 static unsigned int NonECCKeySize(uint32_t bits) {
    868  return bits < 512      ? 1
    869         : bits == 512   ? 2
    870         : bits < 768    ? 3
    871         : bits == 768   ? 4
    872         : bits < 1024   ? 5
    873         : bits == 1024  ? 6
    874         : bits < 1280   ? 7
    875         : bits == 1280  ? 8
    876         : bits < 1536   ? 9
    877         : bits == 1536  ? 10
    878         : bits < 2048   ? 11
    879         : bits == 2048  ? 12
    880         : bits < 3072   ? 13
    881         : bits == 3072  ? 14
    882         : bits < 4096   ? 15
    883         : bits == 4096  ? 16
    884         : bits < 8192   ? 17
    885         : bits == 8192  ? 18
    886         : bits < 16384  ? 19
    887         : bits == 16384 ? 20
    888                         : 0;
    889 }
    890 
    891 // XXX: This attempts to map a bit count to an ECC named curve identifier. In
    892 // the vast majority of situations, we only have the Suite B curves available.
    893 // In that case, this mapping works fine. If we were to have more curves
    894 // available, the mapping would be ambiguous since there could be multiple
    895 // named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on
    896 // that for now. See also NSS bug 323674.
    897 static unsigned int ECCCurve(uint32_t bits) {
    898  return bits == 255   ? 29  // Curve25519
    899         : bits == 256 ? 23  // P-256
    900         : bits == 384 ? 24  // P-384
    901         : bits == 521 ? 25  // P-521
    902                       : 0;  // Unknown
    903 }
    904 
    905 static void AccumulateCipherSuite(const SSLChannelInfo& channelInfo) {
    906  uint32_t value;
    907  // Note: this list must include every cipher suite it is possible to enable
    908  // in nsNSSComponent.cpp (see sCipherPrefs and sDeprecatedTLS1CipherPrefs).
    909  switch (channelInfo.cipherSuite) {
    910    case TLS_RSA_WITH_3DES_EDE_CBC_SHA:  // 0x000A
    911      value = 1;
    912      break;
    913    case TLS_RSA_WITH_AES_128_CBC_SHA:  // 0x002F
    914      value = 2;
    915      break;
    916    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:  // 0x0033
    917      value = 3;
    918      break;
    919    case TLS_RSA_WITH_AES_256_CBC_SHA:  // 0x0035
    920      value = 4;
    921      break;
    922    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:  // 0x0039
    923      value = 5;
    924      break;
    925    case TLS_RSA_WITH_AES_128_GCM_SHA256:  // 0x009C
    926      value = 6;
    927      break;
    928    case TLS_RSA_WITH_AES_256_GCM_SHA384:  // 0x009D
    929      value = 7;
    930      break;
    931    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:  // 0xC009
    932      value = 8;
    933      break;
    934    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:  // 0xC00A
    935      value = 9;
    936      break;
    937    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:  // 0xC013
    938      value = 10;
    939      break;
    940    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:  // 0xC014
    941      value = 11;
    942      break;
    943    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:  // 0xC02B
    944      value = 12;
    945      break;
    946    case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:  // 0xC02C
    947      value = 13;
    948      break;
    949    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:  // 0xC02F
    950      value = 14;
    951      break;
    952    case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:  // 0xC030
    953      value = 15;
    954      break;
    955    case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:  // 0xCCA8
    956      value = 16;
    957      break;
    958    case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:  // 0xCCA9
    959      value = 17;
    960      break;
    961 
    962    // TLS 1.3 cipher suites
    963    case TLS_AES_128_GCM_SHA256:  // 0x1301
    964      value = 18;
    965      break;
    966    case TLS_AES_256_GCM_SHA384:  // 0x1302
    967      value = 19;
    968      break;
    969    case TLS_CHACHA20_POLY1305_SHA256:  // 0x1303
    970      value = 20;
    971      break;
    972 
    973    // unknown
    974    default:
    975      value = 0;
    976      break;
    977  }
    978  MOZ_ASSERT(value != 0);
    979  glean::tls::cipher_suite.AccumulateSingleSample(value);
    980 }
    981 
    982 void HandshakeCallback(PRFileDesc* fd, void* client_data) {
    983  // Do the bookkeeping that needs to be done after the
    984  // server's ServerHello...ServerHelloDone have been processed, but that
    985  // doesn't need the handshake to be completed.
    986  PreliminaryHandshakeDone(fd);
    987 
    988  NSSSocketControl* infoObject = (NSSSocketControl*)fd->higher->secret;
    989 
    990  SSLVersionRange versions(infoObject->GetTLSVersionRange());
    991  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    992          ("[%p] HandshakeCallback: succeeded using TLS version range "
    993           "(0x%04x,0x%04x)\n",
    994           fd, static_cast<unsigned int>(versions.min),
    995           static_cast<unsigned int>(versions.max)));
    996  // If the handshake completed, then we know the site is TLS tolerant
    997  infoObject->RememberTLSTolerant();
    998 
    999  SSLChannelInfo channelInfo;
   1000  SECStatus rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
   1001  MOZ_ASSERT(rv == SECSuccess);
   1002  if (rv != SECSuccess) {
   1003    return;
   1004  }
   1005  AccumulateCipherSuite(channelInfo);
   1006 
   1007  // Get the protocol version for telemetry
   1008  // 1=tls1, 2=tls1.1, 3=tls1.2, 4=tls1.3
   1009  unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
   1010  MOZ_ASSERT(versionEnum > 0);
   1011  glean::ssl_handshake::version.AccumulateSingleSample(versionEnum);
   1012 
   1013  SSLCipherSuiteInfo cipherInfo;
   1014  rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
   1015                              sizeof cipherInfo);
   1016  MOZ_ASSERT(rv == SECSuccess);
   1017  if (rv != SECSuccess) {
   1018    return;
   1019  }
   1020  // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4, ecdh_hybrid=8
   1021  if (infoObject->IsFullHandshake()) {
   1022    glean::ssl::key_exchange_algorithm_full.AccumulateSingleSample(
   1023        channelInfo.keaType);
   1024  } else {
   1025    glean::ssl::key_exchange_algorithm_resumed.AccumulateSingleSample(
   1026        channelInfo.keaType);
   1027  }
   1028 
   1029  if (infoObject->IsFullHandshake()) {
   1030    switch (channelInfo.keaType) {
   1031      case ssl_kea_rsa:
   1032        glean::ssl::kea_rsa_key_size_full.AccumulateSingleSample(
   1033            NonECCKeySize(channelInfo.keaKeyBits));
   1034        break;
   1035      case ssl_kea_dh:
   1036        glean::ssl::kea_dhe_key_size_full.AccumulateSingleSample(
   1037            NonECCKeySize(channelInfo.keaKeyBits));
   1038        break;
   1039      case ssl_kea_ecdh:
   1040        glean::ssl::kea_ecdhe_curve_full.AccumulateSingleSample(
   1041            ECCCurve(channelInfo.keaKeyBits));
   1042        break;
   1043      case ssl_kea_ecdh_hybrid:
   1044        break;
   1045      default:
   1046        MOZ_CRASH("impossible KEA");
   1047        break;
   1048    }
   1049 
   1050    glean::ssl::auth_algorithm_full.AccumulateSingleSample(
   1051        channelInfo.authType);
   1052 
   1053    // RSA key exchange doesn't use a signature for auth.
   1054    if (channelInfo.keaType != ssl_kea_rsa) {
   1055      switch (channelInfo.authType) {
   1056        case ssl_auth_rsa:
   1057        case ssl_auth_rsa_sign:
   1058          glean::ssl::auth_rsa_key_size_full.AccumulateSingleSample(
   1059              NonECCKeySize(channelInfo.authKeyBits));
   1060          break;
   1061        case ssl_auth_ecdsa:
   1062          glean::ssl::auth_ecdsa_curve_full.AccumulateSingleSample(
   1063              ECCCurve(channelInfo.authKeyBits));
   1064          break;
   1065        default:
   1066          MOZ_CRASH("impossible auth algorithm");
   1067          break;
   1068      }
   1069    }
   1070  }
   1071 
   1072  PRBool siteSupportsSafeRenego;
   1073  if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_3) {
   1074    rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
   1075                                          &siteSupportsSafeRenego);
   1076    MOZ_ASSERT(rv == SECSuccess);
   1077    if (rv != SECSuccess) {
   1078      siteSupportsSafeRenego = false;
   1079    }
   1080  } else {
   1081    // TLS 1.3 dropped support for renegotiation.
   1082    siteSupportsSafeRenego = true;
   1083  }
   1084  bool renegotiationUnsafe =
   1085      !siteSupportsSafeRenego &&
   1086      StaticPrefs::security_ssl_treat_unsafe_negotiation_as_broken();
   1087 
   1088  bool deprecatedTlsVer =
   1089      (channelInfo.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2);
   1090 
   1091  uint32_t state;
   1092  if (renegotiationUnsafe || deprecatedTlsVer) {
   1093    state = nsIWebProgressListener::STATE_IS_BROKEN;
   1094  } else {
   1095    state = nsIWebProgressListener::STATE_IS_SECURE;
   1096    SSLVersionRange defVersion;
   1097    rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
   1098    if (rv == SECSuccess && versions.max >= defVersion.max) {
   1099      // we know this site no longer requires a version fallback
   1100      infoObject->RemoveInsecureTLSFallback();
   1101    }
   1102  }
   1103 
   1104  if (infoObject->HasServerCert()) {
   1105    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
   1106            ("HandshakeCallback KEEPING existing cert\n"));
   1107  } else {
   1108    infoObject->RebuildCertificateInfoFromSSLTokenCache();
   1109  }
   1110 
   1111  // Check if the user has added an override for a certificate error.
   1112  if (infoObject->HasUserOverriddenCertificateError()) {
   1113    state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
   1114  }
   1115 
   1116  infoObject->SetSecurityState(state);
   1117 
   1118  // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
   1119  // we should set a flag on the channel that higher (UI) level code can check
   1120  // to log the warning. In particular, these warnings should go to the web
   1121  // console instead of to the error console. Also, the warning is not
   1122  // localized.
   1123  if (!siteSupportsSafeRenego) {
   1124    NS_ConvertASCIItoUTF16 msg(infoObject->GetHostName());
   1125    msg.AppendLiteral(" : server does not support RFC 5746, see CVE-2009-3555");
   1126 
   1127    nsContentUtils::LogSimpleConsoleError(
   1128        msg, "SSL"_ns, infoObject->GetOriginAttributes().IsPrivateBrowsing(),
   1129        true /* from chrome context */);
   1130  }
   1131 
   1132  infoObject->NoteTimeUntilReady();
   1133  infoObject->SetHandshakeCompleted();
   1134 }
   1135 
   1136 void SecretCallback(PRFileDesc* fd, PRUint16 epoch, SSLSecretDirection dir,
   1137                    PK11SymKey* secret, void* arg) {
   1138  // arg must be set to an NSSSocketControl* in SSL_SecretCallback
   1139  MOZ_ASSERT(arg);
   1140  NSSSocketControl* infoObject = (NSSSocketControl*)arg;
   1141  if (epoch == 2 && dir == ssl_secret_read) {
   1142    // |secret| is the server_handshake_traffic_secret. Set a flag to indicate
   1143    // that the Server Hello has been processed successfully. We use this when
   1144    // deciding whether to retry a connection in which an mlkem768x25519 share
   1145    // was sent.
   1146    infoObject->SetHasTls13HandshakeSecrets();
   1147  }
   1148 }