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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsNSSCallbacks.h"
       8             : 
       9             : #include "PSMRunnable.h"
      10             : #include "ScopedNSSTypes.h"
      11             : #include "SharedCertVerifier.h"
      12             : #include "SharedSSLState.h"
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/Assertions.h"
      15             : #include "mozilla/Casting.h"
      16             : #include "mozilla/RefPtr.h"
      17             : #include "mozilla/Telemetry.h"
      18             : #include "mozilla/Unused.h"
      19             : #include "nsContentUtils.h"
      20             : #include "nsICertOverrideService.h"
      21             : #include "nsIHttpChannelInternal.h"
      22             : #include "nsIPrompt.h"
      23             : #include "nsISupportsPriority.h"
      24             : #include "nsITokenDialogs.h"
      25             : #include "nsIUploadChannel.h"
      26             : #include "nsIWebProgressListener.h"
      27             : #include "nsNSSCertificate.h"
      28             : #include "nsNSSComponent.h"
      29             : #include "nsNSSIOLayer.h"
      30             : #include "nsNetUtil.h"
      31             : #include "nsProtectedAuthThread.h"
      32             : #include "nsProxyRelease.h"
      33             : #include "pkix/pkixtypes.h"
      34             : #include "ssl.h"
      35             : #include "sslproto.h"
      36             : 
      37             : using namespace mozilla;
      38             : using namespace mozilla::psm;
      39             : 
      40             : extern LazyLogModule gPIPNSSLog;
      41             : 
      42             : static void AccumulateCipherSuite(Telemetry::HistogramID probe,
      43             :                                   const SSLChannelInfo& channelInfo);
      44             : 
      45             : namespace {
      46             : 
      47             : // Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe
      48             : // These bits are numbered so that the least subtle issues have higher values.
      49             : // This should make it easier for us to interpret the results.
      50             : const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4;
      51             : const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2;
      52             : const uint32_t KEA_NOT_SUPPORTED = 1;
      53             : 
      54             : } // namespace
      55             : 
      56             : class nsHTTPDownloadEvent : public Runnable {
      57             : public:
      58             :   nsHTTPDownloadEvent();
      59             :   ~nsHTTPDownloadEvent();
      60             : 
      61             :   NS_IMETHOD Run();
      62             : 
      63             :   RefPtr<nsNSSHttpRequestSession> mRequestSession;
      64             : 
      65             :   RefPtr<nsHTTPListener> mListener;
      66             :   bool mResponsibleForDoneSignal;
      67             :   TimeStamp mStartTime;
      68             : };
      69             : 
      70           0 : nsHTTPDownloadEvent::nsHTTPDownloadEvent()
      71             :   : mozilla::Runnable("nsHTTPDownloadEvent")
      72           0 :   , mResponsibleForDoneSignal(true)
      73             : {
      74           0 : }
      75             : 
      76           0 : nsHTTPDownloadEvent::~nsHTTPDownloadEvent()
      77             : {
      78           0 :   if (mResponsibleForDoneSignal && mListener)
      79           0 :     mListener->send_done_signal();
      80           0 : }
      81             : 
      82             : NS_IMETHODIMP
      83           0 : nsHTTPDownloadEvent::Run()
      84             : {
      85           0 :   if (!mListener)
      86           0 :     return NS_OK;
      87             : 
      88             :   nsresult rv;
      89             : 
      90           0 :   nsCOMPtr<nsIIOService> ios = do_GetIOService();
      91           0 :   NS_ENSURE_STATE(ios);
      92             : 
      93           0 :   nsCOMPtr<nsIChannel> chan;
      94           0 :   ios->NewChannel2(mRequestSession->mURL,
      95             :                    nullptr,
      96             :                    nullptr,
      97             :                    nullptr, // aLoadingNode
      98             :                    nsContentUtils::GetSystemPrincipal(),
      99             :                    nullptr, // aTriggeringPrincipal
     100             :                    nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     101             :                    nsIContentPolicy::TYPE_OTHER,
     102           0 :                    getter_AddRefs(chan));
     103           0 :   NS_ENSURE_STATE(chan);
     104             : 
     105             :   // Security operations scheduled through normal HTTP channels are given
     106             :   // high priority to accommodate real time OCSP transactions.
     107           0 :   nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(chan);
     108           0 :   if (priorityChannel)
     109           0 :     priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
     110             : 
     111           0 :   chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS |
     112           0 :                      nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
     113             : 
     114             :   // For OCSP requests, only the first party domain aspect of origin attributes
     115             :   // is used. This means that OCSP requests are shared across different
     116             :   // containers.
     117           0 :   if (mRequestSession->mOriginAttributes != OriginAttributes()) {
     118           0 :     OriginAttributes attrs;
     119             :     attrs.mFirstPartyDomain =
     120           0 :       mRequestSession->mOriginAttributes.mFirstPartyDomain;
     121             : 
     122           0 :     nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo();
     123           0 :     if (loadInfo) {
     124           0 :       rv = loadInfo->SetOriginAttributes(attrs);
     125           0 :       NS_ENSURE_SUCCESS(rv, rv);
     126             :     }
     127             :   }
     128             : 
     129             :   // Create a loadgroup for this new channel.  This way if the channel
     130             :   // is redirected, we'll have a way to cancel the resulting channel.
     131           0 :   nsCOMPtr<nsILoadGroup> lg = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
     132           0 :   chan->SetLoadGroup(lg);
     133             : 
     134           0 :   if (mRequestSession->mHasPostData)
     135             :   {
     136           0 :     nsCOMPtr<nsIInputStream> uploadStream;
     137           0 :     rv = NS_NewPostDataStream(getter_AddRefs(uploadStream),
     138             :                               false,
     139           0 :                               mRequestSession->mPostData);
     140           0 :     NS_ENSURE_SUCCESS(rv, rv);
     141             : 
     142           0 :     nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(chan));
     143           0 :     NS_ENSURE_STATE(uploadChannel);
     144             : 
     145           0 :     rv = uploadChannel->SetUploadStream(uploadStream,
     146           0 :                                         mRequestSession->mPostContentType,
     147           0 :                                         -1);
     148           0 :     NS_ENSURE_SUCCESS(rv, rv);
     149             :   }
     150             : 
     151             :   // Do not use SPDY for internal security operations. It could result
     152             :   // in the silent upgrade to ssl, which in turn could require an SSL
     153             :   // operation to fulfill something like an OCSP fetch, which is an
     154             :   // endless loop.
     155           0 :   nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(chan);
     156           0 :   if (internalChannel) {
     157           0 :     rv = internalChannel->SetAllowSpdy(false);
     158           0 :     NS_ENSURE_SUCCESS(rv, rv);
     159             :   }
     160             : 
     161           0 :   nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan);
     162           0 :   NS_ENSURE_STATE(hchan);
     163             : 
     164           0 :   rv = hchan->SetAllowSTS(false);
     165           0 :   NS_ENSURE_SUCCESS(rv, rv);
     166             : 
     167           0 :   rv = hchan->SetRequestMethod(mRequestSession->mRequestMethod);
     168           0 :   NS_ENSURE_SUCCESS(rv, rv);
     169             : 
     170           0 :   mResponsibleForDoneSignal = false;
     171           0 :   mListener->mResponsibleForDoneSignal = true;
     172             : 
     173           0 :   mListener->mLoadGroup = lg.get();
     174           0 :   NS_ADDREF(mListener->mLoadGroup);
     175           0 :   mListener->mLoadGroupOwnerThread = PR_GetCurrentThread();
     176             : 
     177           0 :   rv = NS_NewStreamLoader(getter_AddRefs(mListener->mLoader),
     178           0 :                           mListener);
     179             : 
     180           0 :   if (NS_SUCCEEDED(rv)) {
     181           0 :     mStartTime = TimeStamp::Now();
     182           0 :     rv = hchan->AsyncOpen2(mListener->mLoader);
     183             :   }
     184             : 
     185           0 :   if (NS_FAILED(rv)) {
     186           0 :     mListener->mResponsibleForDoneSignal = false;
     187           0 :     mResponsibleForDoneSignal = true;
     188             : 
     189           0 :     NS_RELEASE(mListener->mLoadGroup);
     190           0 :     mListener->mLoadGroup = nullptr;
     191           0 :     mListener->mLoadGroupOwnerThread = nullptr;
     192             :   }
     193             : 
     194           0 :   return NS_OK;
     195             : }
     196             : 
     197           0 : struct nsCancelHTTPDownloadEvent : Runnable {
     198             :   RefPtr<nsHTTPListener> mListener;
     199             : 
     200           0 :   nsCancelHTTPDownloadEvent() : Runnable("nsCancelHTTPDownloadEvent") {}
     201           0 :   NS_IMETHOD Run() override {
     202           0 :     mListener->FreeLoadGroup(true);
     203           0 :     mListener = nullptr;
     204           0 :     return NS_OK;
     205             :   }
     206             : };
     207             : 
     208             : mozilla::pkix::Result
     209           0 : nsNSSHttpServerSession::createSessionFcn(const char* host,
     210             :                                          uint16_t portnum,
     211             :                                  /*out*/ nsNSSHttpServerSession** pSession)
     212             : {
     213           0 :   if (!host || !pSession) {
     214           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     215             :   }
     216             : 
     217           0 :   nsNSSHttpServerSession* hss = new nsNSSHttpServerSession;
     218           0 :   if (!hss) {
     219           0 :     return Result::FATAL_ERROR_NO_MEMORY;
     220             :   }
     221             : 
     222           0 :   hss->mHost = host;
     223           0 :   hss->mPort = portnum;
     224             : 
     225           0 :   *pSession = hss;
     226           0 :   return Success;
     227             : }
     228             : 
     229             : mozilla::pkix::Result
     230           0 : nsNSSHttpRequestSession::createFcn(const nsNSSHttpServerSession* session,
     231             :                                    const char* http_protocol_variant,
     232             :                                    const char* path_and_query_string,
     233             :                                    const char* http_request_method,
     234             :                                    const OriginAttributes& origin_attributes,
     235             :                                    const TimeDuration timeout,
     236             :                            /*out*/ nsNSSHttpRequestSession** pRequest)
     237             : {
     238           0 :   if (!session || !http_protocol_variant || !path_and_query_string ||
     239           0 :       !http_request_method || !pRequest) {
     240           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     241             :   }
     242             : 
     243           0 :   nsNSSHttpRequestSession* rs = new nsNSSHttpRequestSession;
     244           0 :   if (!rs) {
     245           0 :     return Result::FATAL_ERROR_NO_MEMORY;
     246             :   }
     247             : 
     248           0 :   rs->mTimeout = timeout;
     249             : 
     250           0 :   rs->mURL.Assign(http_protocol_variant);
     251           0 :   rs->mURL.AppendLiteral("://");
     252           0 :   rs->mURL.Append(session->mHost);
     253           0 :   rs->mURL.Append(':');
     254           0 :   rs->mURL.AppendInt(session->mPort);
     255           0 :   rs->mURL.Append(path_and_query_string);
     256             : 
     257           0 :   rs->mOriginAttributes = origin_attributes;
     258             : 
     259           0 :   rs->mRequestMethod = http_request_method;
     260             : 
     261           0 :   *pRequest = rs;
     262           0 :   return Success;
     263             : }
     264             : 
     265             : mozilla::pkix::Result
     266           0 : nsNSSHttpRequestSession::setPostDataFcn(const char* http_data,
     267             :                                         const uint32_t http_data_len,
     268             :                                         const char* http_content_type)
     269             : {
     270           0 :   mHasPostData = true;
     271           0 :   mPostData.Assign(http_data, http_data_len);
     272           0 :   mPostContentType.Assign(http_content_type);
     273             : 
     274           0 :   return Success;
     275             : }
     276             : 
     277             : mozilla::pkix::Result
     278           0 : nsNSSHttpRequestSession::trySendAndReceiveFcn(PRPollDesc** pPollDesc,
     279             :                                               uint16_t* http_response_code,
     280             :                                               const char** http_response_headers,
     281             :                                               const char** http_response_data,
     282             :                                               uint32_t* http_response_data_len)
     283             : {
     284           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     285             :          ("nsNSSHttpRequestSession::trySendAndReceiveFcn to %s\n", mURL.get()));
     286             : 
     287             :   bool onSTSThread;
     288             :   nsresult nrv;
     289             :   nsCOMPtr<nsIEventTarget> sts
     290           0 :     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
     291           0 :   if (NS_FAILED(nrv)) {
     292           0 :     NS_ERROR("Could not get STS service");
     293           0 :     return Result::FATAL_ERROR_INVALID_STATE;
     294             :   }
     295             : 
     296           0 :   nrv = sts->IsOnCurrentThread(&onSTSThread);
     297           0 :   if (NS_FAILED(nrv)) {
     298           0 :     NS_ERROR("IsOnCurrentThread failed");
     299           0 :     return Result::FATAL_ERROR_INVALID_STATE;
     300             :   }
     301             : 
     302           0 :   if (onSTSThread) {
     303           0 :     NS_ERROR("nsNSSHttpRequestSession::trySendAndReceiveFcn called on socket "
     304             :              "thread; this will not work.");
     305           0 :     return Result::FATAL_ERROR_INVALID_STATE;
     306             :   }
     307             : 
     308           0 :   const int max_retries = 2;
     309           0 :   int retry_count = 0;
     310           0 :   bool retryable_error = false;
     311           0 :   Result rv = Result::ERROR_UNKNOWN_ERROR;
     312             : 
     313           0 :   do
     314             :   {
     315           0 :     if (retry_count > 0)
     316             :     {
     317           0 :       if (retryable_error)
     318             :       {
     319           0 :         MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     320             :                ("nsNSSHttpRequestSession::trySendAndReceiveFcn - sleeping and retrying: %d of %d\n",
     321             :                 retry_count, max_retries));
     322             :       }
     323             : 
     324           0 :       PR_Sleep( PR_MillisecondsToInterval(300) * retry_count );
     325             :     }
     326             : 
     327           0 :     ++retry_count;
     328           0 :     retryable_error = false;
     329             : 
     330             :     rv =
     331             :       internal_send_receive_attempt(retryable_error, pPollDesc, http_response_code,
     332             :                                     http_response_headers,
     333           0 :                                     http_response_data, http_response_data_len);
     334             :   }
     335           0 :   while (retryable_error &&
     336             :          retry_count < max_retries);
     337             : 
     338           0 :   if (retry_count > 1)
     339             :   {
     340           0 :     if (retryable_error)
     341           0 :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     342             :              ("nsNSSHttpRequestSession::trySendAndReceiveFcn - still failing, giving up...\n"));
     343             :     else
     344           0 :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     345             :              ("nsNSSHttpRequestSession::trySendAndReceiveFcn - success at attempt %d\n",
     346             :               retry_count));
     347             :   }
     348             : 
     349           0 :   return rv;
     350             : }
     351             : 
     352             : void
     353           0 : nsNSSHttpRequestSession::AddRef()
     354             : {
     355           0 :   ++mRefCount;
     356           0 : }
     357             : 
     358             : void
     359           0 : nsNSSHttpRequestSession::Release()
     360             : {
     361           0 :   int32_t newRefCount = --mRefCount;
     362           0 :   if (!newRefCount) {
     363           0 :     delete this;
     364             :   }
     365           0 : }
     366             : 
     367             : mozilla::pkix::Result
     368           0 : nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
     369             :                                                        PRPollDesc **pPollDesc,
     370             :                                                        uint16_t *http_response_code,
     371             :                                                        const char **http_response_headers,
     372             :                                                        const char **http_response_data,
     373             :                                                        uint32_t *http_response_data_len)
     374             : {
     375           0 :   if (pPollDesc) *pPollDesc = nullptr;
     376           0 :   if (http_response_code) *http_response_code = 0;
     377           0 :   if (http_response_headers) *http_response_headers = 0;
     378           0 :   if (http_response_data) *http_response_data = 0;
     379             : 
     380           0 :   uint32_t acceptableResultSize = 0;
     381             : 
     382           0 :   if (http_response_data_len)
     383             :   {
     384           0 :     acceptableResultSize = *http_response_data_len;
     385           0 :     *http_response_data_len = 0;
     386             :   }
     387             : 
     388           0 :   if (!mListener) {
     389           0 :     return Result::FATAL_ERROR_INVALID_STATE;
     390             :   }
     391             : 
     392           0 :   Mutex& waitLock = mListener->mLock;
     393           0 :   CondVar& waitCondition = mListener->mCondition;
     394           0 :   volatile bool &waitFlag = mListener->mWaitFlag;
     395           0 :   waitFlag = true;
     396             : 
     397           0 :   RefPtr<nsHTTPDownloadEvent> event(new nsHTTPDownloadEvent);
     398           0 :   if (!event) {
     399           0 :     return Result::FATAL_ERROR_NO_MEMORY;
     400             :   }
     401             : 
     402           0 :   event->mListener = mListener;
     403           0 :   event->mRequestSession = this;
     404             : 
     405           0 :   nsresult rv = NS_DispatchToMainThread(event);
     406           0 :   if (NS_FAILED(rv)) {
     407           0 :     event->mResponsibleForDoneSignal = false;
     408           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     409             :   }
     410             : 
     411           0 :   bool request_canceled = false;
     412             : 
     413             :   {
     414           0 :     MutexAutoLock locker(waitLock);
     415             : 
     416           0 :     const TimeStamp startTime = TimeStamp::NowLoRes();
     417             :     PRIntervalTime wait_interval;
     418             : 
     419           0 :     bool running_on_main_thread = NS_IsMainThread();
     420           0 :     if (running_on_main_thread)
     421             :     {
     422             :       // The result of running this on the main thread
     423             :       // is a series of small timeouts mixed with spinning the
     424             :       // event loop - this is always dangerous as there is so much main
     425             :       // thread code that does not expect to be called re-entrantly. Your
     426             :       // app really shouldn't do that.
     427           0 :       NS_WARNING("Security network blocking I/O on Main Thread");
     428             : 
     429             :       // let's process events quickly
     430           0 :       wait_interval = PR_MicrosecondsToInterval(50);
     431             :     }
     432             :     else
     433             :     {
     434             :       // On a secondary thread, it's fine to wait some more for
     435             :       // for the condition variable.
     436           0 :       wait_interval = PR_MillisecondsToInterval(250);
     437             :     }
     438             : 
     439           0 :     while (waitFlag)
     440             :     {
     441           0 :       if (running_on_main_thread)
     442             :       {
     443             :         // Networking runs on the main thread, which we happen to block here.
     444             :         // Processing events will allow the OCSP networking to run while we
     445             :         // are waiting. Thanks a lot to Darin Fisher for rewriting the
     446             :         // thread manager. Thanks a lot to Christian Biesinger who
     447             :         // made me aware of this possibility. (kaie)
     448             : 
     449           0 :         MutexAutoUnlock unlock(waitLock);
     450           0 :         NS_ProcessNextEvent(nullptr);
     451             :       }
     452             : 
     453           0 :       waitCondition.Wait(wait_interval);
     454             : 
     455           0 :       if (!waitFlag)
     456           0 :         break;
     457             : 
     458           0 :       if (!request_canceled)
     459             :       {
     460           0 :         bool timeout = (TimeStamp::NowLoRes() - startTime) > mTimeout;
     461           0 :         if (timeout)
     462             :         {
     463           0 :           request_canceled = true;
     464             : 
     465             :           RefPtr<nsCancelHTTPDownloadEvent> cancelevent(
     466           0 :             new nsCancelHTTPDownloadEvent);
     467           0 :           cancelevent->mListener = mListener;
     468           0 :           rv = NS_DispatchToMainThread(cancelevent);
     469           0 :           if (NS_FAILED(rv)) {
     470           0 :             NS_WARNING("cannot post cancel event");
     471             :           }
     472           0 :           break;
     473             :         }
     474             :       }
     475             :     }
     476             :   }
     477             : 
     478           0 :   if (!event->mStartTime.IsNull()) {
     479           0 :     if (request_canceled) {
     480           0 :       Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 0);
     481           0 :       Telemetry::AccumulateTimeDelta(
     482             :         Telemetry::CERT_VALIDATION_HTTP_REQUEST_CANCELED_TIME,
     483           0 :         event->mStartTime, TimeStamp::Now());
     484             :     }
     485           0 :     else if (NS_SUCCEEDED(mListener->mResultCode) &&
     486           0 :              mListener->mHttpResponseCode == 200) {
     487           0 :       Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 1);
     488           0 :       Telemetry::AccumulateTimeDelta(
     489             :         Telemetry::CERT_VALIDATION_HTTP_REQUEST_SUCCEEDED_TIME,
     490           0 :         event->mStartTime, TimeStamp::Now());
     491             :     }
     492             :     else {
     493           0 :       Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 2);
     494           0 :       Telemetry::AccumulateTimeDelta(
     495             :         Telemetry::CERT_VALIDATION_HTTP_REQUEST_FAILED_TIME,
     496           0 :         event->mStartTime, TimeStamp::Now());
     497             :     }
     498             :   }
     499             :   else {
     500           0 :     Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 3);
     501             :   }
     502             : 
     503           0 :   if (request_canceled) {
     504           0 :     return Result::ERROR_OCSP_SERVER_ERROR;
     505             :   }
     506             : 
     507           0 :   if (NS_FAILED(mListener->mResultCode)) {
     508           0 :     if (mListener->mResultCode == NS_ERROR_CONNECTION_REFUSED ||
     509           0 :         mListener->mResultCode == NS_ERROR_NET_RESET) {
     510           0 :       retryable_error = true;
     511             :     }
     512           0 :     return Result::ERROR_OCSP_SERVER_ERROR;
     513             :   }
     514             : 
     515           0 :   if (http_response_code)
     516           0 :     *http_response_code = mListener->mHttpResponseCode;
     517             : 
     518           0 :   if (mListener->mHttpRequestSucceeded && http_response_data &&
     519             :       http_response_data_len) {
     520           0 :     *http_response_data_len = mListener->mResultLen;
     521             : 
     522             :     // acceptableResultSize == 0 means: any size is acceptable
     523           0 :     if (acceptableResultSize != 0 &&
     524           0 :         acceptableResultSize < mListener->mResultLen) {
     525           0 :       return Result::ERROR_OCSP_SERVER_ERROR;
     526             :     }
     527             : 
     528             :     // Return data by reference, result data will be valid until "this" gets
     529             :     // destroyed.
     530           0 :     *http_response_data = (const char*)mListener->mResultData;
     531             :   }
     532             : 
     533           0 :   return Success;
     534             : }
     535             : 
     536           0 : nsNSSHttpRequestSession::nsNSSHttpRequestSession()
     537             :   : mRefCount(1)
     538             :   , mHasPostData(false)
     539             :   , mTimeout(0)
     540           0 :   , mListener(new nsHTTPListener)
     541             : {
     542           0 : }
     543             : 
     544           0 : nsNSSHttpRequestSession::~nsNSSHttpRequestSession()
     545             : {
     546           0 : }
     547             : 
     548           0 : nsHTTPListener::nsHTTPListener()
     549             : : mResultData(nullptr),
     550             :   mResultLen(0),
     551             :   mLock("nsHTTPListener.mLock"),
     552             :   mCondition(mLock, "nsHTTPListener.mCondition"),
     553             :   mWaitFlag(true),
     554             :   mResponsibleForDoneSignal(false),
     555             :   mLoadGroup(nullptr),
     556           0 :   mLoadGroupOwnerThread(nullptr)
     557             : {
     558           0 : }
     559             : 
     560           0 : nsHTTPListener::~nsHTTPListener()
     561             : {
     562           0 :   if (mResponsibleForDoneSignal)
     563           0 :     send_done_signal();
     564             : 
     565           0 :   if (mResultData) {
     566           0 :     free(const_cast<uint8_t *>(mResultData));
     567             :   }
     568             : 
     569           0 :   if (mLoader) {
     570           0 :     NS_ReleaseOnMainThread("nsHTTPListener::mLoader", mLoader.forget());
     571             :   }
     572           0 : }
     573             : 
     574           0 : NS_IMPL_ISUPPORTS(nsHTTPListener, nsIStreamLoaderObserver)
     575             : 
     576             : void
     577           0 : nsHTTPListener::FreeLoadGroup(bool aCancelLoad)
     578             : {
     579           0 :   nsILoadGroup *lg = nullptr;
     580             : 
     581           0 :   MutexAutoLock locker(mLock);
     582             : 
     583           0 :   if (mLoadGroup) {
     584           0 :     if (mLoadGroupOwnerThread != PR_GetCurrentThread()) {
     585           0 :       MOZ_ASSERT_UNREACHABLE(
     586             :         "Attempt to access mLoadGroup on multiple threads, leaking it!");
     587             :     }
     588             :     else {
     589           0 :       lg = mLoadGroup;
     590           0 :       mLoadGroup = nullptr;
     591             :     }
     592             :   }
     593             : 
     594           0 :   if (lg) {
     595           0 :     if (aCancelLoad) {
     596           0 :       lg->Cancel(NS_ERROR_ABORT);
     597             :     }
     598           0 :     NS_RELEASE(lg);
     599             :   }
     600           0 : }
     601             : 
     602             : NS_IMETHODIMP
     603           0 : nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
     604             :                                  nsISupports* aContext,
     605             :                                  nsresult aStatus,
     606             :                                  uint32_t stringLen,
     607             :                                  const uint8_t* string)
     608             : {
     609           0 :   mResultCode = aStatus;
     610             : 
     611           0 :   FreeLoadGroup(false);
     612             : 
     613           0 :   nsCOMPtr<nsIRequest> req;
     614           0 :   nsCOMPtr<nsIHttpChannel> hchan;
     615             : 
     616           0 :   nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
     617             : 
     618           0 :   if (NS_FAILED(aStatus))
     619             :   {
     620           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     621             :            ("nsHTTPListener::OnStreamComplete status failed %" PRIu32,
     622             :             static_cast<uint32_t>(aStatus)));
     623             :   }
     624             : 
     625           0 :   if (NS_SUCCEEDED(rv))
     626           0 :     hchan = do_QueryInterface(req, &rv);
     627             : 
     628           0 :   if (NS_SUCCEEDED(rv))
     629             :   {
     630           0 :     rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
     631           0 :     if (NS_FAILED(rv))
     632           0 :       mHttpRequestSucceeded = false;
     633             : 
     634           0 :     mResultLen = stringLen;
     635           0 :     mResultData = string; // take ownership of allocation
     636           0 :     aStatus = NS_SUCCESS_ADOPTED_DATA;
     637             : 
     638             :     unsigned int rcode;
     639           0 :     rv = hchan->GetResponseStatus(&rcode);
     640           0 :     if (NS_FAILED(rv))
     641           0 :       mHttpResponseCode = 500;
     642             :     else
     643           0 :       mHttpResponseCode = rcode;
     644             :   }
     645             : 
     646           0 :   if (mResponsibleForDoneSignal)
     647           0 :     send_done_signal();
     648             : 
     649           0 :   return aStatus;
     650             : }
     651             : 
     652           0 : void nsHTTPListener::send_done_signal()
     653             : {
     654           0 :   mResponsibleForDoneSignal = false;
     655             : 
     656             :   {
     657           0 :     MutexAutoLock locker(mLock);
     658           0 :     mWaitFlag = false;
     659           0 :     mCondition.NotifyAll();
     660             :   }
     661           0 : }
     662             : 
     663             : static char*
     664           0 : ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIInterfaceRequestor *ir)
     665             : {
     666           0 :   if (!NS_IsMainThread()) {
     667           0 :     NS_ERROR("ShowProtectedAuthPrompt called off the main thread");
     668           0 :     return nullptr;
     669             :   }
     670             : 
     671           0 :   char* protAuthRetVal = nullptr;
     672             : 
     673             :   // Get protected auth dialogs
     674           0 :   nsCOMPtr<nsITokenDialogs> dialogs;
     675           0 :   nsresult nsrv = getNSSDialogs(getter_AddRefs(dialogs),
     676             :                                 NS_GET_IID(nsITokenDialogs),
     677           0 :                                 NS_TOKENDIALOGS_CONTRACTID);
     678           0 :   if (NS_SUCCEEDED(nsrv))
     679             :   {
     680           0 :     nsProtectedAuthThread* protectedAuthRunnable = new nsProtectedAuthThread();
     681           0 :     if (protectedAuthRunnable)
     682             :     {
     683           0 :       NS_ADDREF(protectedAuthRunnable);
     684             : 
     685           0 :       protectedAuthRunnable->SetParams(slot);
     686             : 
     687           0 :       nsCOMPtr<nsIProtectedAuthThread> runnable = do_QueryInterface(protectedAuthRunnable);
     688           0 :       if (runnable)
     689             :       {
     690           0 :         nsrv = dialogs->DisplayProtectedAuth(ir, runnable);
     691             : 
     692             :         // We call join on the thread,
     693             :         // so we can be sure that no simultaneous access will happen.
     694           0 :         protectedAuthRunnable->Join();
     695             : 
     696           0 :         if (NS_SUCCEEDED(nsrv))
     697             :         {
     698           0 :           SECStatus rv = protectedAuthRunnable->GetResult();
     699           0 :           switch (rv)
     700             :           {
     701             :               case SECSuccess:
     702           0 :                   protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
     703           0 :                   break;
     704             :               case SECWouldBlock:
     705           0 :                   protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_RETRY));
     706           0 :                   break;
     707             :               default:
     708           0 :                   protAuthRetVal = nullptr;
     709           0 :                   break;
     710             :           }
     711             :         }
     712             :       }
     713             : 
     714           0 :       NS_RELEASE(protectedAuthRunnable);
     715             :     }
     716             :   }
     717             : 
     718           0 :   return protAuthRetVal;
     719             : }
     720             : 
     721             : class PK11PasswordPromptRunnable : public SyncRunnableBase
     722             :                                  , public nsNSSShutDownObject
     723             : {
     724             : public:
     725           0 :   PK11PasswordPromptRunnable(PK11SlotInfo* slot,
     726             :                              nsIInterfaceRequestor* ir)
     727           0 :     : mResult(nullptr),
     728             :       mSlot(slot),
     729           0 :       mIR(ir)
     730             :   {
     731           0 :   }
     732             :   virtual ~PK11PasswordPromptRunnable();
     733             : 
     734             :   // This doesn't own the PK11SlotInfo or any other NSS objects, so there's
     735             :   // nothing to release.
     736           0 :   virtual void virtualDestroyNSSReference() override {}
     737             :   char * mResult; // out
     738             :   virtual void RunOnTargetThread() override;
     739             : private:
     740             :   PK11SlotInfo* const mSlot; // in
     741             :   nsIInterfaceRequestor* const mIR; // in
     742             : };
     743             : 
     744           0 : PK11PasswordPromptRunnable::~PK11PasswordPromptRunnable()
     745             : {
     746           0 :   nsNSSShutDownPreventionLock locker;
     747           0 :   if (isAlreadyShutDown()) {
     748           0 :     return;
     749             :   }
     750             : 
     751           0 :   shutdown(ShutdownCalledFrom::Object);
     752           0 : }
     753             : 
     754             : void
     755           0 : PK11PasswordPromptRunnable::RunOnTargetThread()
     756             : {
     757             :   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     758             : 
     759           0 :   nsNSSShutDownPreventionLock locker;
     760           0 :   if (isAlreadyShutDown()) {
     761           0 :     return;
     762             :   }
     763             : 
     764             :   nsresult rv;
     765           0 :   nsCOMPtr<nsIPrompt> prompt;
     766           0 :   if (!mIR) {
     767           0 :     rv = nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
     768           0 :     if (NS_FAILED(rv)) {
     769           0 :       return;
     770             :     }
     771             :   } else {
     772           0 :     prompt = do_GetInterface(mIR);
     773           0 :     MOZ_ASSERT(prompt, "Interface requestor should implement nsIPrompt");
     774             :   }
     775             : 
     776           0 :   if (!prompt) {
     777           0 :     return;
     778             :   }
     779             : 
     780           0 :   if (PK11_ProtectedAuthenticationPath(mSlot)) {
     781           0 :     mResult = ShowProtectedAuthPrompt(mSlot, mIR);
     782           0 :     return;
     783             :   }
     784             : 
     785           0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID));
     786           0 :   if (!nssComponent) {
     787           0 :     return;
     788             :   }
     789             : 
     790           0 :   NS_ConvertUTF8toUTF16 tokenName(PK11_GetTokenName(mSlot));
     791             :   const char16_t* formatStrings[] = {
     792           0 :     tokenName.get(),
     793           0 :   };
     794           0 :   nsAutoString promptString;
     795           0 :   rv = nssComponent->PIPBundleFormatStringFromName("CertPassPrompt",
     796             :                                                    formatStrings,
     797           0 :                                                    ArrayLength(formatStrings),
     798           0 :                                                    promptString);
     799           0 :   if (NS_FAILED(rv)) {
     800           0 :     return;
     801             :   }
     802             : 
     803           0 :   nsXPIDLString password;
     804             :   // |checkState| is unused because |checkMsg| (the argument just before it) is
     805             :   // null, but XPConnect requires it to point to a valid bool nonetheless.
     806           0 :   bool checkState = false;
     807           0 :   bool userClickedOK = false;
     808           0 :   rv = prompt->PromptPassword(nullptr, promptString.get(),
     809           0 :                               getter_Copies(password), nullptr, &checkState,
     810           0 :                               &userClickedOK);
     811           0 :   if (NS_FAILED(rv) || !userClickedOK) {
     812           0 :     return;
     813             :   }
     814             : 
     815           0 :   mResult = ToNewUTF8String(password);
     816             : }
     817             : 
     818             : char*
     819           0 : PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg)
     820             : {
     821             :   RefPtr<PK11PasswordPromptRunnable> runnable(
     822             :     new PK11PasswordPromptRunnable(slot,
     823           0 :                                    static_cast<nsIInterfaceRequestor*>(arg)));
     824           0 :   runnable->DispatchToMainThreadAndWait();
     825           0 :   return runnable->mResult;
     826             : }
     827             : 
     828             : // call with shutdown prevention lock held
     829             : static void
     830           0 : PreliminaryHandshakeDone(PRFileDesc* fd)
     831             : {
     832           0 :   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
     833           0 :   if (!infoObject)
     834           0 :     return;
     835             : 
     836             :   SSLChannelInfo channelInfo;
     837           0 :   if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) {
     838           0 :     infoObject->SetSSLVersionUsed(channelInfo.protocolVersion);
     839           0 :     infoObject->SetEarlyDataAccepted(channelInfo.earlyDataAccepted);
     840             : 
     841             :     SSLCipherSuiteInfo cipherInfo;
     842           0 :     if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
     843             :                                sizeof cipherInfo) == SECSuccess) {
     844             :       /* Set the SSL Status information */
     845           0 :       RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
     846           0 :       if (!status) {
     847           0 :         status = new nsSSLStatus();
     848           0 :         infoObject->SetSSLStatus(status);
     849             :       }
     850             : 
     851           0 :       status->mHaveCipherSuiteAndProtocol = true;
     852           0 :       status->mCipherSuite = channelInfo.cipherSuite;
     853           0 :       status->mProtocolVersion = channelInfo.protocolVersion & 0xFF;
     854           0 :       infoObject->SetKEAUsed(channelInfo.keaType);
     855           0 :       infoObject->SetKEAKeyBits(channelInfo.keaKeyBits);
     856           0 :       infoObject->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
     857             :     }
     858             :   }
     859             : 
     860             :   // Don't update NPN details on renegotiation.
     861           0 :   if (infoObject->IsPreliminaryHandshakeDone()) {
     862           0 :     return;
     863             :   }
     864             : 
     865             :   // Get the NPN value.
     866             :   SSLNextProtoState state;
     867             :   unsigned char npnbuf[256];
     868             :   unsigned int npnlen;
     869             : 
     870           0 :   if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen,
     871             :                        AssertedCast<unsigned int>(ArrayLength(npnbuf)))
     872             :         == SECSuccess) {
     873           0 :     if (state == SSL_NEXT_PROTO_NEGOTIATED ||
     874           0 :         state == SSL_NEXT_PROTO_SELECTED) {
     875           0 :       infoObject->SetNegotiatedNPN(BitwiseCast<char*, unsigned char*>(npnbuf),
     876           0 :                                    npnlen);
     877             :     } else {
     878           0 :       infoObject->SetNegotiatedNPN(nullptr, 0);
     879             :     }
     880           0 :     mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
     881             :   } else {
     882           0 :     infoObject->SetNegotiatedNPN(nullptr, 0);
     883             :   }
     884             : 
     885           0 :   infoObject->SetPreliminaryHandshakeDone();
     886             : }
     887             : 
     888             : SECStatus
     889           0 : CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
     890             : {
     891           0 :   *canFalseStart = false;
     892             : 
     893           0 :   nsNSSShutDownPreventionLock locker;
     894             : 
     895           0 :   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
     896           0 :   if (!infoObject) {
     897           0 :     PR_SetError(PR_INVALID_STATE_ERROR, 0);
     898           0 :     return SECFailure;
     899             :   }
     900             : 
     901           0 :   infoObject->SetFalseStartCallbackCalled();
     902             : 
     903           0 :   if (infoObject->isAlreadyShutDown()) {
     904           0 :     MOZ_CRASH("SSL socket used after NSS shut down");
     905             :     PR_SetError(PR_INVALID_STATE_ERROR, 0);
     906             :     return SECFailure;
     907             :   }
     908             : 
     909           0 :   PreliminaryHandshakeDone(fd);
     910             : 
     911           0 :   uint32_t reasonsForNotFalseStarting = 0;
     912             : 
     913             :   SSLChannelInfo channelInfo;
     914           0 :   if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
     915           0 :     return SECSuccess;
     916             :   }
     917             : 
     918             :   SSLCipherSuiteInfo cipherInfo;
     919           0 :   if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
     920             :                              sizeof (cipherInfo)) != SECSuccess) {
     921           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
     922             :                                       " KEA %d\n", fd,
     923             :                                       static_cast<int32_t>(channelInfo.keaType)));
     924           0 :     return SECSuccess;
     925             :   }
     926             : 
     927             :   // Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
     928             :   // TLS 1.3 and later. See Bug 861310 for all the details as to why.
     929           0 :   if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) {
     930           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
     931             :                                       "SSL Version must be TLS 1.2, was %x\n", fd,
     932             :                                       static_cast<int32_t>(channelInfo.protocolVersion)));
     933           0 :     reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
     934             :   }
     935             : 
     936             :   // See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not.
     937           0 :   if (channelInfo.keaType != ssl_kea_ecdh) {
     938           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
     939             :                                       "unsupported KEA %d\n", fd,
     940             :                                       static_cast<int32_t>(channelInfo.keaType)));
     941           0 :     reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
     942             :   }
     943             : 
     944             :   // Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
     945             :   // mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
     946             :   // design. See bug 1109766 for more details.
     947           0 :   if (cipherInfo.macAlgorithm != ssl_mac_aead) {
     948           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     949             :            ("CanFalseStartCallback [%p] failed - non-AEAD cipher used, %d, "
     950             :             "is not supported with False Start.\n", fd,
     951             :             static_cast<int32_t>(cipherInfo.symCipher)));
     952           0 :     reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
     953             :   }
     954             : 
     955             :   // XXX: An attacker can choose which protocols are advertised in the
     956             :   // NPN extension. TODO(Bug 861311): We should restrict the ability
     957             :   // of an attacker leverage this capability by restricting false start
     958             :   // to the same protocol we previously saw for the server, after the
     959             :   // first successful connection to the server.
     960             : 
     961             :   Telemetry::Accumulate(Telemetry::SSL_REASONS_FOR_NOT_FALSE_STARTING,
     962           0 :                         reasonsForNotFalseStarting);
     963             : 
     964           0 :   if (reasonsForNotFalseStarting == 0) {
     965           0 :     *canFalseStart = PR_TRUE;
     966           0 :     infoObject->SetFalseStarted();
     967           0 :     infoObject->NoteTimeUntilReady();
     968           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] ok\n", fd));
     969             :   }
     970             : 
     971           0 :   return SECSuccess;
     972             : }
     973             : 
     974             : static void
     975           0 : AccumulateNonECCKeySize(Telemetry::HistogramID probe, uint32_t bits)
     976             : {
     977           0 :   unsigned int value = bits <   512 ?  1 : bits ==   512 ?  2
     978             :                      : bits <   768 ?  3 : bits ==   768 ?  4
     979             :                      : bits <  1024 ?  5 : bits ==  1024 ?  6
     980             :                      : bits <  1280 ?  7 : bits ==  1280 ?  8
     981             :                      : bits <  1536 ?  9 : bits ==  1536 ? 10
     982             :                      : bits <  2048 ? 11 : bits ==  2048 ? 12
     983             :                      : bits <  3072 ? 13 : bits ==  3072 ? 14
     984             :                      : bits <  4096 ? 15 : bits ==  4096 ? 16
     985             :                      : bits <  8192 ? 17 : bits ==  8192 ? 18
     986             :                      : bits < 16384 ? 19 : bits == 16384 ? 20
     987           0 :                      : 0;
     988           0 :   Telemetry::Accumulate(probe, value);
     989           0 : }
     990             : 
     991             : // XXX: This attempts to map a bit count to an ECC named curve identifier. In
     992             : // the vast majority of situations, we only have the Suite B curves available.
     993             : // In that case, this mapping works fine. If we were to have more curves
     994             : // available, the mapping would be ambiguous since there could be multiple
     995             : // named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on
     996             : // that for now. See also NSS bug 323674.
     997             : static void
     998           0 : AccumulateECCCurve(Telemetry::HistogramID probe, uint32_t bits)
     999             : {
    1000           0 :   unsigned int value = bits == 256 ? 23 // P-256
    1001             :                      : bits == 384 ? 24 // P-384
    1002             :                      : bits == 521 ? 25 // P-521
    1003           0 :                      : 0; // Unknown
    1004           0 :   Telemetry::Accumulate(probe, value);
    1005           0 : }
    1006             : 
    1007             : static void
    1008           0 : AccumulateCipherSuite(Telemetry::HistogramID probe, const SSLChannelInfo& channelInfo)
    1009             : {
    1010             :   uint32_t value;
    1011           0 :   switch (channelInfo.cipherSuite) {
    1012             :     // ECDHE key exchange
    1013           0 :     case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: value = 1; break;
    1014           0 :     case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: value = 2; break;
    1015           0 :     case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: value = 3; break;
    1016           0 :     case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: value = 4; break;
    1017           0 :     case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: value = 5; break;
    1018           0 :     case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: value = 6; break;
    1019           0 :     case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 7; break;
    1020           0 :     case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break;
    1021           0 :     case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: value = 11; break;
    1022           0 :     case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: value = 12; break;
    1023           0 :     case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: value = 13; break;
    1024           0 :     case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: value = 14; break;
    1025             :     // DHE key exchange
    1026           0 :     case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break;
    1027           0 :     case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break;
    1028           0 :     case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: value = 23; break;
    1029           0 :     case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 24; break;
    1030           0 :     case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 25; break;
    1031           0 :     case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: value = 26; break;
    1032           0 :     case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: value = 27; break;
    1033           0 :     case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: value = 28; break;
    1034           0 :     case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: value = 29; break;
    1035           0 :     case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: value = 30; break;
    1036             :     // ECDH key exchange
    1037           0 :     case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: value = 41; break;
    1038           0 :     case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: value = 42; break;
    1039           0 :     case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: value = 43; break;
    1040           0 :     case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: value = 44; break;
    1041           0 :     case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 45; break;
    1042           0 :     case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: value = 46; break;
    1043             :     // RSA key exchange
    1044           0 :     case TLS_RSA_WITH_AES_128_CBC_SHA: value = 61; break;
    1045           0 :     case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 62; break;
    1046           0 :     case TLS_RSA_WITH_AES_256_CBC_SHA: value = 63; break;
    1047           0 :     case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 64; break;
    1048           0 :     case SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA: value = 65; break;
    1049           0 :     case TLS_RSA_WITH_3DES_EDE_CBC_SHA: value = 66; break;
    1050           0 :     case TLS_RSA_WITH_SEED_CBC_SHA: value = 67; break;
    1051             :     // TLS 1.3 PSK resumption
    1052           0 :     case TLS_AES_128_GCM_SHA256: value = 70; break;
    1053           0 :     case TLS_CHACHA20_POLY1305_SHA256: value = 71; break;
    1054           0 :     case TLS_AES_256_GCM_SHA384: value = 72; break;
    1055             :     // unknown
    1056             :     default:
    1057           0 :       value = 0;
    1058           0 :       break;
    1059             :   }
    1060           0 :   MOZ_ASSERT(value != 0);
    1061           0 :   Telemetry::Accumulate(probe, value);
    1062           0 : }
    1063             : 
    1064             : // In the case of session resumption, the AuthCertificate hook has been bypassed
    1065             : // (because we've previously successfully connected to our peer). That being the
    1066             : // case, we unfortunately don't know if the peer's server certificate verified
    1067             : // as extended validation or not. To address this, we attempt to build a
    1068             : // verified EV certificate chain here using as much of the original context as
    1069             : // possible (e.g. stapled OCSP responses, SCTs, the hostname, the first party
    1070             : // domain, etc.). Note that because we are on the socket thread, this must not
    1071             : // cause any network requests, hence the use of FLAG_LOCAL_ONLY.
    1072             : // Similarly, we need to determine the certificate's CT status.
    1073             : static void
    1074           0 : DetermineEVAndCTStatusAndSetNewCert(RefPtr<nsSSLStatus> sslStatus,
    1075             :                                     PRFileDesc* fd, nsNSSSocketInfo* infoObject)
    1076             : {
    1077           0 :   MOZ_ASSERT(sslStatus);
    1078           0 :   MOZ_ASSERT(fd);
    1079           0 :   MOZ_ASSERT(infoObject);
    1080             : 
    1081           0 :   if (!sslStatus || !fd || !infoObject) {
    1082           0 :     return;
    1083             :   }
    1084             : 
    1085           0 :   UniqueCERTCertificate cert(SSL_PeerCertificate(fd));
    1086           0 :   MOZ_ASSERT(cert, "SSL_PeerCertificate failed in TLS handshake callback?");
    1087           0 :   if (!cert) {
    1088           0 :     return;
    1089             :   }
    1090             : 
    1091           0 :   UniqueCERTCertList peerCertChain(SSL_PeerCertificateChain(fd));
    1092           0 :   MOZ_ASSERT(peerCertChain,
    1093             :              "SSL_PeerCertificateChain failed in TLS handshake callback?");
    1094           0 :   if (!peerCertChain) {
    1095           0 :     return;
    1096             :   }
    1097             : 
    1098           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
    1099           0 :   MOZ_ASSERT(certVerifier,
    1100             :              "Certificate verifier uninitialized in TLS handshake callback?");
    1101           0 :   if (!certVerifier) {
    1102           0 :     return;
    1103             :   }
    1104             : 
    1105             :   // We don't own these pointers.
    1106           0 :   const SECItemArray* stapledOCSPResponses = SSL_PeerStapledOCSPResponses(fd);
    1107           0 :   const SECItem* stapledOCSPResponse = nullptr;
    1108             :   // we currently only support single stapled responses
    1109           0 :   if (stapledOCSPResponses && stapledOCSPResponses->len == 1) {
    1110           0 :     stapledOCSPResponse = &stapledOCSPResponses->items[0];
    1111             :   }
    1112           0 :   const SECItem* sctsFromTLSExtension = SSL_PeerSignedCertTimestamps(fd);
    1113           0 :   if (sctsFromTLSExtension && sctsFromTLSExtension->len == 0) {
    1114             :     // SSL_PeerSignedCertTimestamps returns null on error and empty item
    1115             :     // when no extension was returned by the server. We always use null when
    1116             :     // no extension was received (for whatever reason), ignoring errors.
    1117           0 :     sctsFromTLSExtension = nullptr;
    1118             :   }
    1119             : 
    1120           0 :   int flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY |
    1121           0 :               mozilla::psm::CertVerifier::FLAG_MUST_BE_EV;
    1122           0 :   if (!infoObject->SharedState().IsOCSPStaplingEnabled() ||
    1123           0 :       !infoObject->SharedState().IsOCSPMustStapleEnabled()) {
    1124           0 :     flags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
    1125             :   }
    1126             : 
    1127             :   SECOidTag evOidPolicy;
    1128           0 :   CertificateTransparencyInfo certificateTransparencyInfo;
    1129           0 :   UniqueCERTCertList unusedBuiltChain;
    1130           0 :   const bool saveIntermediates = false;
    1131           0 :   mozilla::pkix::Result rv = certVerifier->VerifySSLServerCert(
    1132             :     cert,
    1133             :     stapledOCSPResponse,
    1134             :     sctsFromTLSExtension,
    1135             :     mozilla::pkix::Now(),
    1136             :     infoObject,
    1137             :     infoObject->GetHostName(),
    1138             :     unusedBuiltChain,
    1139             :     &peerCertChain,
    1140             :     saveIntermediates,
    1141             :     flags,
    1142             :     infoObject->GetOriginAttributes(),
    1143             :     &evOidPolicy,
    1144             :     nullptr, // OCSP stapling telemetry
    1145             :     nullptr, // key size telemetry
    1146             :     nullptr, // SHA-1 telemetry
    1147             :     nullptr, // pinning telemetry
    1148           0 :     &certificateTransparencyInfo);
    1149             : 
    1150           0 :   RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(cert.get()));
    1151           0 :   if (rv == Success && evOidPolicy != SEC_OID_UNKNOWN) {
    1152           0 :     sslStatus->SetCertificateTransparencyInfo(certificateTransparencyInfo);
    1153           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1154             :             ("HandshakeCallback using NEW cert %p (is EV)", nssc.get()));
    1155           0 :     sslStatus->SetServerCert(nssc, EVStatus::EV);
    1156             :   } else {
    1157           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1158             :             ("HandshakeCallback using NEW cert %p (is not EV)", nssc.get()));
    1159           0 :     sslStatus->SetServerCert(nssc, EVStatus::NotEV);
    1160             :   }
    1161             : 
    1162           0 :   if (rv == Success) {
    1163           0 :     sslStatus->SetCertificateTransparencyInfo(certificateTransparencyInfo);
    1164             :   }
    1165             : }
    1166             : 
    1167           0 : void HandshakeCallback(PRFileDesc* fd, void* client_data) {
    1168           0 :   nsNSSShutDownPreventionLock locker;
    1169             :   SECStatus rv;
    1170             : 
    1171           0 :   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
    1172             : 
    1173             :   // Do the bookkeeping that needs to be done after the
    1174             :   // server's ServerHello...ServerHelloDone have been processed, but that doesn't
    1175             :   // need the handshake to be completed.
    1176           0 :   PreliminaryHandshakeDone(fd);
    1177             : 
    1178             :   nsSSLIOLayerHelpers& ioLayerHelpers
    1179           0 :     = infoObject->SharedState().IOLayerHelpers();
    1180             : 
    1181           0 :   SSLVersionRange versions(infoObject->GetTLSVersionRange());
    1182             : 
    1183           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1184             :          ("[%p] HandshakeCallback: succeeded using TLS version range (0x%04x,0x%04x)\n",
    1185             :           fd, static_cast<unsigned int>(versions.min),
    1186             :               static_cast<unsigned int>(versions.max)));
    1187             : 
    1188             :   // If the handshake completed, then we know the site is TLS tolerant
    1189           0 :   ioLayerHelpers.rememberTolerantAtVersion(infoObject->GetHostName(),
    1190           0 :                                            infoObject->GetPort(),
    1191           0 :                                            versions.max);
    1192             : 
    1193             :   SSLChannelInfo channelInfo;
    1194           0 :   rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
    1195           0 :   MOZ_ASSERT(rv == SECSuccess);
    1196           0 :   if (rv == SECSuccess) {
    1197             :     // Get the protocol version for telemetry
    1198             :     // 1=tls1, 2=tls1.1, 3=tls1.2
    1199           0 :     unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
    1200           0 :     MOZ_ASSERT(versionEnum > 0);
    1201           0 :     Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
    1202           0 :     AccumulateCipherSuite(
    1203           0 :       infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
    1204             :                                     : Telemetry::SSL_CIPHER_SUITE_RESUMED,
    1205           0 :       channelInfo);
    1206             : 
    1207             :     SSLCipherSuiteInfo cipherInfo;
    1208           0 :     rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
    1209           0 :                                 sizeof cipherInfo);
    1210           0 :     MOZ_ASSERT(rv == SECSuccess);
    1211           0 :     if (rv == SECSuccess) {
    1212             :       // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
    1213           0 :       Telemetry::Accumulate(
    1214           0 :         infoObject->IsFullHandshake()
    1215             :           ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
    1216             :           : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
    1217           0 :         channelInfo.keaType);
    1218             : 
    1219           0 :       MOZ_ASSERT(infoObject->GetKEAUsed() == channelInfo.keaType);
    1220             : 
    1221           0 :       if (infoObject->IsFullHandshake()) {
    1222           0 :         switch (channelInfo.keaType) {
    1223             :           case ssl_kea_rsa:
    1224           0 :             AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
    1225           0 :                                     channelInfo.keaKeyBits);
    1226           0 :             break;
    1227             :           case ssl_kea_dh:
    1228           0 :             AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
    1229           0 :                                     channelInfo.keaKeyBits);
    1230           0 :             break;
    1231             :           case ssl_kea_ecdh:
    1232           0 :             AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
    1233           0 :                                channelInfo.keaKeyBits);
    1234           0 :             break;
    1235             :           default:
    1236           0 :             MOZ_CRASH("impossible KEA");
    1237             :             break;
    1238             :         }
    1239             : 
    1240             :         Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
    1241           0 :                               channelInfo.authType);
    1242             : 
    1243             :         // RSA key exchange doesn't use a signature for auth.
    1244           0 :         if (channelInfo.keaType != ssl_kea_rsa) {
    1245           0 :           switch (channelInfo.authType) {
    1246             :             case ssl_auth_rsa:
    1247             :             case ssl_auth_rsa_sign:
    1248           0 :               AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
    1249           0 :                                       channelInfo.authKeyBits);
    1250           0 :               break;
    1251             :             case ssl_auth_ecdsa:
    1252           0 :               AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
    1253           0 :                                  channelInfo.authKeyBits);
    1254           0 :               break;
    1255             :             default:
    1256           0 :               MOZ_CRASH("impossible auth algorithm");
    1257             :               break;
    1258             :           }
    1259             :         }
    1260             :       }
    1261             : 
    1262           0 :       Telemetry::Accumulate(
    1263           0 :           infoObject->IsFullHandshake()
    1264             :             ? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
    1265             :             : Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
    1266           0 :           cipherInfo.symCipher);
    1267             :     }
    1268             :   }
    1269             : 
    1270             :   PRBool siteSupportsSafeRenego;
    1271           0 :   if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_3) {
    1272             :     rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
    1273           0 :                                           &siteSupportsSafeRenego);
    1274           0 :     MOZ_ASSERT(rv == SECSuccess);
    1275           0 :     if (rv != SECSuccess) {
    1276           0 :       siteSupportsSafeRenego = false;
    1277             :     }
    1278             :   } else {
    1279             :     // TLS 1.3 dropped support for renegotiation.
    1280           0 :     siteSupportsSafeRenego = true;
    1281             :   }
    1282           0 :   bool renegotiationUnsafe = !siteSupportsSafeRenego &&
    1283           0 :                              ioLayerHelpers.treatUnsafeNegotiationAsBroken();
    1284             : 
    1285             : 
    1286             :   /* Set the SSL Status information */
    1287           0 :   RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
    1288           0 :   if (!status) {
    1289           0 :     status = new nsSSLStatus();
    1290           0 :     infoObject->SetSSLStatus(status);
    1291             :   }
    1292             : 
    1293           0 :   RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
    1294           0 :                                                              status);
    1295             : 
    1296             :   uint32_t state;
    1297           0 :   if (renegotiationUnsafe) {
    1298           0 :     state = nsIWebProgressListener::STATE_IS_BROKEN;
    1299             :   } else {
    1300           0 :     state = nsIWebProgressListener::STATE_IS_SECURE |
    1301             :             nsIWebProgressListener::STATE_SECURE_HIGH;
    1302             :     SSLVersionRange defVersion;
    1303           0 :     rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
    1304           0 :     if (rv == SECSuccess && versions.max >= defVersion.max) {
    1305             :       // we know this site no longer requires a version fallback
    1306           0 :       ioLayerHelpers.removeInsecureFallbackSite(infoObject->GetHostName(),
    1307           0 :                                                 infoObject->GetPort());
    1308             :     }
    1309             :   }
    1310             : 
    1311           0 :   if (status->HasServerCert()) {
    1312           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1313             :            ("HandshakeCallback KEEPING existing cert\n"));
    1314             :   } else {
    1315           0 :     DetermineEVAndCTStatusAndSetNewCert(status, fd, infoObject);
    1316             :   }
    1317             : 
    1318             :   bool domainMismatch;
    1319             :   bool untrusted;
    1320             :   bool notValidAtThisTime;
    1321             :   // These all return NS_OK, so don't even bother checking the return values.
    1322           0 :   Unused << status->GetIsDomainMismatch(&domainMismatch);
    1323           0 :   Unused << status->GetIsUntrusted(&untrusted);
    1324           0 :   Unused << status->GetIsNotValidAtThisTime(&notValidAtThisTime);
    1325             :   // If we're here, the TLS handshake has succeeded. Thus if any of these
    1326             :   // booleans are true, the user has added an override for a certificate error.
    1327           0 :   if (domainMismatch || untrusted || notValidAtThisTime) {
    1328           0 :     state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
    1329             :   }
    1330             : 
    1331           0 :   infoObject->SetSecurityState(state);
    1332             : 
    1333             :   // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
    1334             :   // we should set a flag on the channel that higher (UI) level code can check
    1335             :   // to log the warning. In particular, these warnings should go to the web
    1336             :   // console instead of to the error console. Also, the warning is not
    1337             :   // localized.
    1338           0 :   if (!siteSupportsSafeRenego) {
    1339           0 :     NS_ConvertASCIItoUTF16 msg(infoObject->GetHostName());
    1340           0 :     msg.AppendLiteral(" : server does not support RFC 5746, see CVE-2009-3555");
    1341             : 
    1342           0 :     nsContentUtils::LogSimpleConsoleError(msg, "SSL");
    1343             :   }
    1344             : 
    1345           0 :   infoObject->NoteTimeUntilReady();
    1346           0 :   infoObject->SetHandshakeCompleted();
    1347           0 : }

Generated by: LCOV version 1.13