security/manager/ssl/src/nsNSSCallbacks.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     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/. */
     7 #include "nsNSSCallbacks.h"
     8 #include "pkix/pkixtypes.h"
     9 #include "mozilla/Telemetry.h"
    10 #include "mozilla/TimeStamp.h"
    11 #include "nsNSSComponent.h"
    12 #include "nsNSSIOLayer.h"
    13 #include "nsIWebProgressListener.h"
    14 #include "nsProtectedAuthThread.h"
    15 #include "nsITokenDialogs.h"
    16 #include "nsIUploadChannel.h"
    17 #include "nsIPrompt.h"
    18 #include "nsProxyRelease.h"
    19 #include "PSMRunnable.h"
    20 #include "nsContentUtils.h"
    21 #include "nsIHttpChannelInternal.h"
    22 #include "nsISupportsPriority.h"
    23 #include "nsNetUtil.h"
    24 #include "SharedSSLState.h"
    25 #include "ssl.h"
    26 #include "sslproto.h"
    28 using namespace mozilla;
    29 using namespace mozilla::psm;
    31 #ifdef PR_LOGGING
    32 extern PRLogModuleInfo* gPIPNSSLog;
    33 #endif
    35 static void AccumulateCipherSuite(Telemetry::ID probe,
    36                                   const SSLChannelInfo& channelInfo);
    38 namespace {
    40 // Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe
    41 // These bits are numbered so that the least subtle issues have higher values.
    42 // This should make it easier for us to interpret the results.
    43 const uint32_t NPN_NOT_NEGOTIATED = 64;
    44 const uint32_t KEA_NOT_FORWARD_SECRET = 32;
    45 const uint32_t KEA_NOT_SAME_AS_EXPECTED = 16;
    46 const uint32_t KEA_NOT_ALLOWED = 8;
    47 const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4;
    48 const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2;
    49 const uint32_t KEA_NOT_SUPPORTED = 1;
    51 }
    53 class nsHTTPDownloadEvent : public nsRunnable {
    54 public:
    55   nsHTTPDownloadEvent();
    56   ~nsHTTPDownloadEvent();
    58   NS_IMETHOD Run();
    60   nsNSSHttpRequestSession *mRequestSession;
    62   nsRefPtr<nsHTTPListener> mListener;
    63   bool mResponsibleForDoneSignal;
    64   TimeStamp mStartTime;
    65 };
    67 nsHTTPDownloadEvent::nsHTTPDownloadEvent()
    68 :mResponsibleForDoneSignal(true)
    69 {
    70 }
    72 nsHTTPDownloadEvent::~nsHTTPDownloadEvent()
    73 {
    74   if (mResponsibleForDoneSignal && mListener)
    75     mListener->send_done_signal();
    77   mRequestSession->Release();
    78 }
    80 NS_IMETHODIMP
    81 nsHTTPDownloadEvent::Run()
    82 {
    83   if (!mListener)
    84     return NS_OK;
    86   nsresult rv;
    88   nsCOMPtr<nsIIOService> ios = do_GetIOService();
    89   NS_ENSURE_STATE(ios);
    91   nsCOMPtr<nsIChannel> chan;
    92   ios->NewChannel(mRequestSession->mURL, nullptr, nullptr, getter_AddRefs(chan));
    93   NS_ENSURE_STATE(chan);
    95   // Security operations scheduled through normal HTTP channels are given
    96   // high priority to accommodate real time OCSP transactions. Background CRL
    97   // fetches happen through a different path (CRLDownloadEvent).
    98   nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(chan);
    99   if (priorityChannel)
   100     priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
   102   chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS);
   104   // Create a loadgroup for this new channel.  This way if the channel
   105   // is redirected, we'll have a way to cancel the resulting channel.
   106   nsCOMPtr<nsILoadGroup> lg = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   107   chan->SetLoadGroup(lg);
   109   if (mRequestSession->mHasPostData)
   110   {
   111     nsCOMPtr<nsIInputStream> uploadStream;
   112     rv = NS_NewPostDataStream(getter_AddRefs(uploadStream),
   113                               false,
   114                               mRequestSession->mPostData);
   115     NS_ENSURE_SUCCESS(rv, rv);
   117     nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(chan));
   118     NS_ENSURE_STATE(uploadChannel);
   120     rv = uploadChannel->SetUploadStream(uploadStream, 
   121                                         mRequestSession->mPostContentType,
   122                                         -1);
   123     NS_ENSURE_SUCCESS(rv, rv);
   124   }
   126   // Do not use SPDY for internal security operations. It could result
   127   // in the silent upgrade to ssl, which in turn could require an SSL
   128   // operation to fufill something like a CRL fetch, which is an
   129   // endless loop.
   130   nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(chan);
   131   if (internalChannel) {
   132     rv = internalChannel->SetAllowSpdy(false);
   133     NS_ENSURE_SUCCESS(rv, rv);
   134   }
   136   nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan);
   137   NS_ENSURE_STATE(hchan);
   139   rv = hchan->SetRequestMethod(mRequestSession->mRequestMethod);
   140   NS_ENSURE_SUCCESS(rv, rv);
   142   mResponsibleForDoneSignal = false;
   143   mListener->mResponsibleForDoneSignal = true;
   145   mListener->mLoadGroup = lg.get();
   146   NS_ADDREF(mListener->mLoadGroup);
   147   mListener->mLoadGroupOwnerThread = PR_GetCurrentThread();
   149   rv = NS_NewStreamLoader(getter_AddRefs(mListener->mLoader), 
   150                           mListener);
   152   if (NS_SUCCEEDED(rv)) {
   153     mStartTime = TimeStamp::Now();
   154     rv = hchan->AsyncOpen(mListener->mLoader, nullptr);
   155   }
   157   if (NS_FAILED(rv)) {
   158     mListener->mResponsibleForDoneSignal = false;
   159     mResponsibleForDoneSignal = true;
   161     NS_RELEASE(mListener->mLoadGroup);
   162     mListener->mLoadGroup = nullptr;
   163     mListener->mLoadGroupOwnerThread = nullptr;
   164   }
   166   return NS_OK;
   167 }
   169 struct nsCancelHTTPDownloadEvent : nsRunnable {
   170   nsRefPtr<nsHTTPListener> mListener;
   172   NS_IMETHOD Run() {
   173     mListener->FreeLoadGroup(true);
   174     mListener = nullptr;
   175     return NS_OK;
   176   }
   177 };
   179 SECStatus nsNSSHttpServerSession::createSessionFcn(const char *host,
   180                                                    uint16_t portnum,
   181                                                    SEC_HTTP_SERVER_SESSION *pSession)
   182 {
   183   if (!host || !pSession)
   184     return SECFailure;
   186   nsNSSHttpServerSession *hss = new nsNSSHttpServerSession;
   187   if (!hss)
   188     return SECFailure;
   190   hss->mHost = host;
   191   hss->mPort = portnum;
   193   *pSession = hss;
   194   return SECSuccess;
   195 }
   197 SECStatus nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session,
   198                                              const char *http_protocol_variant,
   199                                              const char *path_and_query_string,
   200                                              const char *http_request_method, 
   201                                              const PRIntervalTime timeout, 
   202                                              SEC_HTTP_REQUEST_SESSION *pRequest)
   203 {
   204   if (!session || !http_protocol_variant || !path_and_query_string || 
   205       !http_request_method || !pRequest)
   206     return SECFailure;
   208   nsNSSHttpServerSession* hss = static_cast<nsNSSHttpServerSession*>(session);
   209   if (!hss)
   210     return SECFailure;
   212   nsNSSHttpRequestSession *rs = new nsNSSHttpRequestSession;
   213   if (!rs)
   214     return SECFailure;
   216   rs->mTimeoutInterval = timeout;
   218   // Use a maximum timeout value of 10 seconds because of bug 404059.
   219   // FIXME: Use a better approach once 406120 is ready.
   220   uint32_t maxBug404059Timeout = PR_TicksPerSecond() * 10;
   221   if (timeout > maxBug404059Timeout) {
   222     rs->mTimeoutInterval = maxBug404059Timeout;
   223   }
   225   rs->mURL.Assign(http_protocol_variant);
   226   rs->mURL.AppendLiteral("://");
   227   rs->mURL.Append(hss->mHost);
   228   rs->mURL.AppendLiteral(":");
   229   rs->mURL.AppendInt(hss->mPort);
   230   rs->mURL.Append(path_and_query_string);
   232   rs->mRequestMethod = http_request_method;
   234   *pRequest = (void*)rs;
   235   return SECSuccess;
   236 }
   238 SECStatus nsNSSHttpRequestSession::setPostDataFcn(const char *http_data, 
   239                                                   const uint32_t http_data_len,
   240                                                   const char *http_content_type)
   241 {
   242   mHasPostData = true;
   243   mPostData.Assign(http_data, http_data_len);
   244   mPostContentType.Assign(http_content_type);
   246   return SECSuccess;
   247 }
   249 SECStatus nsNSSHttpRequestSession::addHeaderFcn(const char *http_header_name, 
   250                                                 const char *http_header_value)
   251 {
   252   return SECFailure; // not yet implemented
   254   // All http code needs to be postponed to the UI thread.
   255   // Once this gets implemented, we need to add a string list member to
   256   // nsNSSHttpRequestSession and queue up the headers,
   257   // so they can be added in HandleHTTPDownloadPLEvent.
   258   //
   259   // The header will need to be set using 
   260   //   mHttpChannel->SetRequestHeader(nsDependentCString(http_header_name), 
   261   //                                  nsDependentCString(http_header_value), 
   262   //                                  false)));
   263 }
   265 SECStatus nsNSSHttpRequestSession::trySendAndReceiveFcn(PRPollDesc **pPollDesc,
   266                                                         uint16_t *http_response_code, 
   267                                                         const char **http_response_content_type, 
   268                                                         const char **http_response_headers, 
   269                                                         const char **http_response_data, 
   270                                                         uint32_t *http_response_data_len)
   271 {
   272   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   273          ("nsNSSHttpRequestSession::trySendAndReceiveFcn to %s\n", mURL.get()));
   275   bool onSTSThread;
   276   nsresult nrv;
   277   nsCOMPtr<nsIEventTarget> sts
   278     = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
   279   if (NS_FAILED(nrv)) {
   280     NS_ERROR("Could not get STS service");
   281     PR_SetError(PR_INVALID_STATE_ERROR, 0);
   282     return SECFailure;
   283   }
   285   nrv = sts->IsOnCurrentThread(&onSTSThread);
   286   if (NS_FAILED(nrv)) {
   287     NS_ERROR("IsOnCurrentThread failed");
   288     PR_SetError(PR_INVALID_STATE_ERROR, 0);
   289     return SECFailure;
   290   }
   292   if (onSTSThread) {
   293     NS_ERROR("nsNSSHttpRequestSession::trySendAndReceiveFcn called on socket "
   294              "thread; this will not work.");
   295     PR_SetError(PR_INVALID_STATE_ERROR, 0);
   296     return SECFailure;
   297   }
   299   const int max_retries = 2;
   300   int retry_count = 0;
   301   bool retryable_error = false;
   302   SECStatus result_sec_status = SECFailure;
   304   do
   305   {
   306     if (retry_count > 0)
   307     {
   308       if (retryable_error)
   309       {
   310         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   311                ("nsNSSHttpRequestSession::trySendAndReceiveFcn - sleeping and retrying: %d of %d\n",
   312                 retry_count, max_retries));
   313       }
   315       PR_Sleep( PR_MillisecondsToInterval(300) * retry_count );
   316     }
   318     ++retry_count;
   319     retryable_error = false;
   321     result_sec_status =
   322       internal_send_receive_attempt(retryable_error, pPollDesc, http_response_code,
   323                                     http_response_content_type, http_response_headers,
   324                                     http_response_data, http_response_data_len);
   325   }
   326   while (retryable_error &&
   327          retry_count < max_retries);
   329 #ifdef PR_LOGGING
   330   if (retry_count > 1)
   331   {
   332     if (retryable_error)
   333       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   334              ("nsNSSHttpRequestSession::trySendAndReceiveFcn - still failing, giving up...\n"));
   335     else
   336       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   337              ("nsNSSHttpRequestSession::trySendAndReceiveFcn - success at attempt %d\n",
   338               retry_count));
   339   }
   340 #endif
   342   return result_sec_status;
   343 }
   345 void
   346 nsNSSHttpRequestSession::AddRef()
   347 {
   348   ++mRefCount;
   349 }
   351 void
   352 nsNSSHttpRequestSession::Release()
   353 {
   354   int32_t newRefCount = --mRefCount;
   355   if (!newRefCount) {
   356     delete this;
   357   }
   358 }
   360 SECStatus
   361 nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
   362                                                        PRPollDesc **pPollDesc,
   363                                                        uint16_t *http_response_code,
   364                                                        const char **http_response_content_type,
   365                                                        const char **http_response_headers,
   366                                                        const char **http_response_data,
   367                                                        uint32_t *http_response_data_len)
   368 {
   369   if (pPollDesc) *pPollDesc = nullptr;
   370   if (http_response_code) *http_response_code = 0;
   371   if (http_response_content_type) *http_response_content_type = 0;
   372   if (http_response_headers) *http_response_headers = 0;
   373   if (http_response_data) *http_response_data = 0;
   375   uint32_t acceptableResultSize = 0;
   377   if (http_response_data_len)
   378   {
   379     acceptableResultSize = *http_response_data_len;
   380     *http_response_data_len = 0;
   381   }
   383   if (!mListener)
   384     return SECFailure;
   386   Mutex& waitLock = mListener->mLock;
   387   CondVar& waitCondition = mListener->mCondition;
   388   volatile bool &waitFlag = mListener->mWaitFlag;
   389   waitFlag = true;
   391   RefPtr<nsHTTPDownloadEvent> event(new nsHTTPDownloadEvent);
   392   if (!event)
   393     return SECFailure;
   395   event->mListener = mListener;
   396   this->AddRef();
   397   event->mRequestSession = this;
   399   nsresult rv = NS_DispatchToMainThread(event);
   400   if (NS_FAILED(rv))
   401   {
   402     event->mResponsibleForDoneSignal = false;
   403     return SECFailure;
   404   }
   406   bool request_canceled = false;
   408   {
   409     MutexAutoLock locker(waitLock);
   411     const PRIntervalTime start_time = PR_IntervalNow();
   412     PRIntervalTime wait_interval;
   414     bool running_on_main_thread = NS_IsMainThread();
   415     if (running_on_main_thread)
   416     {
   417       // The result of running this on the main thread
   418       // is a series of small timeouts mixed with spinning the
   419       // event loop - this is always dangerous as there is so much main
   420       // thread code that does not expect to be called re-entrantly. Your
   421       // app really shouldn't do that.
   422       NS_WARNING("Security network blocking I/O on Main Thread");
   424       // let's process events quickly
   425       wait_interval = PR_MicrosecondsToInterval(50);
   426     }
   427     else
   428     { 
   429       // On a secondary thread, it's fine to wait some more for
   430       // for the condition variable.
   431       wait_interval = PR_MillisecondsToInterval(250);
   432     }
   434     while (waitFlag)
   435     {
   436       if (running_on_main_thread)
   437       {
   438         // Networking runs on the main thread, which we happen to block here.
   439         // Processing events will allow the OCSP networking to run while we 
   440         // are waiting. Thanks a lot to Darin Fisher for rewriting the 
   441         // thread manager. Thanks a lot to Christian Biesinger who
   442         // made me aware of this possibility. (kaie)
   444         MutexAutoUnlock unlock(waitLock);
   445         NS_ProcessNextEvent(nullptr);
   446       }
   448       waitCondition.Wait(wait_interval);
   450       if (!waitFlag)
   451         break;
   453       if (!request_canceled)
   454       {
   455         bool timeout = 
   456           (PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval;
   458         if (timeout)
   459         {
   460           request_canceled = true;
   462           RefPtr<nsCancelHTTPDownloadEvent> cancelevent(
   463             new nsCancelHTTPDownloadEvent);
   464           cancelevent->mListener = mListener;
   465           rv = NS_DispatchToMainThread(cancelevent);
   466           if (NS_FAILED(rv)) {
   467             NS_WARNING("cannot post cancel event");
   468           }
   469           break;
   470         }
   471       }
   472     }
   473   }
   475   if (!event->mStartTime.IsNull()) {
   476     if (request_canceled) {
   477       Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 0);
   478       Telemetry::AccumulateTimeDelta(
   479         Telemetry::CERT_VALIDATION_HTTP_REQUEST_CANCELED_TIME,
   480         event->mStartTime, TimeStamp::Now());
   481     }
   482     else if (NS_SUCCEEDED(mListener->mResultCode) &&
   483              mListener->mHttpResponseCode == 200) {
   484       Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 1);
   485       Telemetry::AccumulateTimeDelta(
   486         Telemetry::CERT_VALIDATION_HTTP_REQUEST_SUCCEEDED_TIME,
   487         event->mStartTime, TimeStamp::Now());
   488     }
   489     else {
   490       Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 2);
   491       Telemetry::AccumulateTimeDelta(
   492         Telemetry::CERT_VALIDATION_HTTP_REQUEST_FAILED_TIME,
   493         event->mStartTime, TimeStamp::Now());
   494     }
   495   }
   496   else {
   497     Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 3);
   498   }
   500   if (request_canceled)
   501     return SECFailure;
   503   if (NS_FAILED(mListener->mResultCode))
   504   {
   505     if (mListener->mResultCode == NS_ERROR_CONNECTION_REFUSED
   506         ||
   507         mListener->mResultCode == NS_ERROR_NET_RESET)
   508     {
   509       retryable_error = true;
   510     }
   511     return SECFailure;
   512   }
   514   if (http_response_code)
   515     *http_response_code = mListener->mHttpResponseCode;
   517   if (mListener->mHttpRequestSucceeded && http_response_data && http_response_data_len) {
   519     *http_response_data_len = mListener->mResultLen;
   521     // acceptableResultSize == 0 means: any size is acceptable
   522     if (acceptableResultSize != 0
   523         &&
   524         acceptableResultSize < mListener->mResultLen)
   525     {
   526       return SECFailure;
   527     }
   529     // return data by reference, result data will be valid 
   530     // until "this" gets destroyed by NSS
   531     *http_response_data = (const char*)mListener->mResultData;
   532   }
   534   if (mListener->mHttpRequestSucceeded && http_response_content_type) {
   535     if (mListener->mHttpResponseContentType.Length()) {
   536       *http_response_content_type = mListener->mHttpResponseContentType.get();
   537     }
   538   }
   540   return SECSuccess;
   541 }
   543 SECStatus nsNSSHttpRequestSession::cancelFcn()
   544 {
   545   // As of today, only the blocking variant of the http interface
   546   // has been implemented. Implementing cancelFcn will be necessary
   547   // as soon as we implement the nonblocking variant.
   548   return SECSuccess;
   549 }
   551 SECStatus nsNSSHttpRequestSession::freeFcn()
   552 {
   553   Release();
   554   return SECSuccess;
   555 }
   557 nsNSSHttpRequestSession::nsNSSHttpRequestSession()
   558 : mRefCount(1),
   559   mHasPostData(false),
   560   mTimeoutInterval(0),
   561   mListener(new nsHTTPListener)
   562 {
   563 }
   565 nsNSSHttpRequestSession::~nsNSSHttpRequestSession()
   566 {
   567 }
   569 SEC_HttpClientFcn nsNSSHttpInterface::sNSSInterfaceTable;
   571 void nsNSSHttpInterface::initTable()
   572 {
   573   sNSSInterfaceTable.version = 1;
   574   SEC_HttpClientFcnV1 &v1 = sNSSInterfaceTable.fcnTable.ftable1;
   575   v1.createSessionFcn = createSessionFcn;
   576   v1.keepAliveSessionFcn = keepAliveFcn;
   577   v1.freeSessionFcn = freeSessionFcn;
   578   v1.createFcn = createFcn;
   579   v1.setPostDataFcn = setPostDataFcn;
   580   v1.addHeaderFcn = addHeaderFcn;
   581   v1.trySendAndReceiveFcn = trySendAndReceiveFcn;
   582   v1.cancelFcn = cancelFcn;
   583   v1.freeFcn = freeFcn;
   584 }
   586 void nsNSSHttpInterface::registerHttpClient()
   587 {
   588   SEC_RegisterDefaultHttpClient(&sNSSInterfaceTable);
   589 }
   591 void nsNSSHttpInterface::unregisterHttpClient()
   592 {
   593   SEC_RegisterDefaultHttpClient(nullptr);
   594 }
   596 nsHTTPListener::nsHTTPListener()
   597 : mResultData(nullptr),
   598   mResultLen(0),
   599   mLock("nsHTTPListener.mLock"),
   600   mCondition(mLock, "nsHTTPListener.mCondition"),
   601   mWaitFlag(true),
   602   mResponsibleForDoneSignal(false),
   603   mLoadGroup(nullptr),
   604   mLoadGroupOwnerThread(nullptr)
   605 {
   606 }
   608 nsHTTPListener::~nsHTTPListener()
   609 {
   610   if (mResponsibleForDoneSignal)
   611     send_done_signal();
   613   if (mResultData) {
   614     NS_Free(const_cast<uint8_t *>(mResultData));
   615   }
   617   if (mLoader) {
   618     nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
   619     NS_ProxyRelease(mainThread, mLoader);
   620   }
   621 }
   623 NS_IMPL_ISUPPORTS(nsHTTPListener, nsIStreamLoaderObserver)
   625 void
   626 nsHTTPListener::FreeLoadGroup(bool aCancelLoad)
   627 {
   628   nsILoadGroup *lg = nullptr;
   630   MutexAutoLock locker(mLock);
   632   if (mLoadGroup) {
   633     if (mLoadGroupOwnerThread != PR_GetCurrentThread()) {
   634       NS_ASSERTION(false,
   635                    "attempt to access nsHTTPDownloadEvent::mLoadGroup on multiple threads, leaking it!");
   636     }
   637     else {
   638       lg = mLoadGroup;
   639       mLoadGroup = nullptr;
   640     }
   641   }
   643   if (lg) {
   644     if (aCancelLoad) {
   645       lg->Cancel(NS_ERROR_ABORT);
   646     }
   647     NS_RELEASE(lg);
   648   }
   649 }
   651 NS_IMETHODIMP
   652 nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
   653                                  nsISupports* aContext,
   654                                  nsresult aStatus,
   655                                  uint32_t stringLen,
   656                                  const uint8_t* string)
   657 {
   658   mResultCode = aStatus;
   660   FreeLoadGroup(false);
   662   nsCOMPtr<nsIRequest> req;
   663   nsCOMPtr<nsIHttpChannel> hchan;
   665   nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
   667 #ifdef PR_LOGGING
   668   if (NS_FAILED(aStatus))
   669   {
   670     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   671            ("nsHTTPListener::OnStreamComplete status failed %d", aStatus));
   672   }
   673 #endif
   675   if (NS_SUCCEEDED(rv))
   676     hchan = do_QueryInterface(req, &rv);
   678   if (NS_SUCCEEDED(rv))
   679   {
   680     rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
   681     if (NS_FAILED(rv))
   682       mHttpRequestSucceeded = false;
   684     mResultLen = stringLen;
   685     mResultData = string; // take ownership of allocation
   686     aStatus = NS_SUCCESS_ADOPTED_DATA;
   688     unsigned int rcode;
   689     rv = hchan->GetResponseStatus(&rcode);
   690     if (NS_FAILED(rv))
   691       mHttpResponseCode = 500;
   692     else
   693       mHttpResponseCode = rcode;
   695     hchan->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"), 
   696                                     mHttpResponseContentType);
   697   }
   699   if (mResponsibleForDoneSignal)
   700     send_done_signal();
   702   return aStatus;
   703 }
   705 void nsHTTPListener::send_done_signal()
   706 {
   707   mResponsibleForDoneSignal = false;
   709   {
   710     MutexAutoLock locker(mLock);
   711     mWaitFlag = false;
   712     mCondition.NotifyAll();
   713   }
   714 }
   716 static char*
   717 ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIInterfaceRequestor *ir)
   718 {
   719   if (!NS_IsMainThread()) {
   720     NS_ERROR("ShowProtectedAuthPrompt called off the main thread");
   721     return nullptr;
   722   }
   724   char* protAuthRetVal = nullptr;
   726   // Get protected auth dialogs
   727   nsITokenDialogs* dialogs = 0;
   728   nsresult nsrv = getNSSDialogs((void**)&dialogs, 
   729                                 NS_GET_IID(nsITokenDialogs), 
   730                                 NS_TOKENDIALOGS_CONTRACTID);
   731   if (NS_SUCCEEDED(nsrv))
   732   {
   733     nsProtectedAuthThread* protectedAuthRunnable = new nsProtectedAuthThread();
   734     if (protectedAuthRunnable)
   735     {
   736       NS_ADDREF(protectedAuthRunnable);
   738       protectedAuthRunnable->SetParams(slot);
   740       nsCOMPtr<nsIProtectedAuthThread> runnable = do_QueryInterface(protectedAuthRunnable);
   741       if (runnable)
   742       {
   743         nsrv = dialogs->DisplayProtectedAuth(ir, runnable);
   745         // We call join on the thread,
   746         // so we can be sure that no simultaneous access will happen.
   747         protectedAuthRunnable->Join();
   749         if (NS_SUCCEEDED(nsrv))
   750         {
   751           SECStatus rv = protectedAuthRunnable->GetResult();
   752           switch (rv)
   753           {
   754               case SECSuccess:
   755                   protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
   756                   break;
   757               case SECWouldBlock:
   758                   protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_RETRY));
   759                   break;
   760               default:
   761                   protAuthRetVal = nullptr;
   762                   break;
   764           }
   765         }
   766       }
   768       NS_RELEASE(protectedAuthRunnable);
   769     }
   771     NS_RELEASE(dialogs);
   772   }
   774   return protAuthRetVal;
   775 }
   777 class PK11PasswordPromptRunnable : public SyncRunnableBase
   778 {
   779 public:
   780   PK11PasswordPromptRunnable(PK11SlotInfo* slot, 
   781                              nsIInterfaceRequestor* ir)
   782     : mResult(nullptr),
   783       mSlot(slot),
   784       mIR(ir)
   785   {
   786   }
   787   char * mResult; // out
   788   virtual void RunOnTargetThread();
   789 private:
   790   PK11SlotInfo* const mSlot; // in
   791   nsIInterfaceRequestor* const mIR; // in
   792 };
   794 void PK11PasswordPromptRunnable::RunOnTargetThread()
   795 {
   796   static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
   798   nsNSSShutDownPreventionLock locker;
   799   nsresult rv = NS_OK;
   800   char16_t *password = nullptr;
   801   bool value = false;
   802   nsCOMPtr<nsIPrompt> prompt;
   804   /* TODO: Retry should generate a different dialog message */
   805 /*
   806   if (retry)
   807     return nullptr;
   808 */
   810   if (!mIR)
   811   {
   812     nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
   813   }
   814   else
   815   {
   816     prompt = do_GetInterface(mIR);
   817     NS_ASSERTION(prompt, "callbacks does not implement nsIPrompt");
   818   }
   820   if (!prompt)
   821     return;
   823   if (PK11_ProtectedAuthenticationPath(mSlot)) {
   824     mResult = ShowProtectedAuthPrompt(mSlot, mIR);
   825     return;
   826   }
   828   nsAutoString promptString;
   829   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   831   if (NS_FAILED(rv))
   832     return; 
   834   const char16_t* formatStrings[1] = { 
   835     ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot)))
   836   };
   837   rv = nssComponent->PIPBundleFormatStringFromName("CertPassPrompt",
   838                                       formatStrings, 1,
   839                                       promptString);
   840   nsMemory::Free(const_cast<char16_t*>(formatStrings[0]));
   842   if (NS_FAILED(rv))
   843     return;
   845   {
   846     nsPSMUITracker tracker;
   847     if (tracker.isUIForbidden()) {
   848       rv = NS_ERROR_NOT_AVAILABLE;
   849     }
   850     else {
   851       // Although the exact value is ignored, we must not pass invalid
   852       // bool values through XPConnect.
   853       bool checkState = false;
   854       rv = prompt->PromptPassword(nullptr, promptString.get(),
   855                                   &password, nullptr, &checkState, &value);
   856     }
   857   }
   859   if (NS_SUCCEEDED(rv) && value) {
   860     mResult = ToNewUTF8String(nsDependentString(password));
   861     NS_Free(password);
   862   }
   863 }
   865 char*
   866 PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
   867 {
   868   RefPtr<PK11PasswordPromptRunnable> runnable(
   869     new PK11PasswordPromptRunnable(slot,
   870                                    static_cast<nsIInterfaceRequestor*>(arg)));
   871   runnable->DispatchToMainThreadAndWait();
   872   return runnable->mResult;
   873 }
   875 // call with shutdown prevention lock held
   876 static void
   877 PreliminaryHandshakeDone(PRFileDesc* fd)
   878 {
   879   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
   880   if (!infoObject)
   881     return;
   883   if (infoObject->IsPreliminaryHandshakeDone())
   884     return;
   886   infoObject->SetPreliminaryHandshakeDone();
   888   SSLChannelInfo channelInfo;
   889   if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) {
   890     infoObject->SetSSLVersionUsed(channelInfo.protocolVersion);
   891   }
   893   // Get the NPN value.
   894   SSLNextProtoState state;
   895   unsigned char npnbuf[256];
   896   unsigned int npnlen;
   898   if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess) {
   899     if (state == SSL_NEXT_PROTO_NEGOTIATED ||
   900         state == SSL_NEXT_PROTO_SELECTED) {
   901       infoObject->SetNegotiatedNPN(reinterpret_cast<char *>(npnbuf), npnlen);
   902     }
   903     else {
   904       infoObject->SetNegotiatedNPN(nullptr, 0);
   905     }
   906     mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
   907   }
   908   else {
   909     infoObject->SetNegotiatedNPN(nullptr, 0);
   910   }
   911 }
   913 SECStatus
   914 CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
   915 {
   916   *canFalseStart = false;
   918   nsNSSShutDownPreventionLock locker;
   920   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
   921   if (!infoObject) {
   922     PR_SetError(PR_INVALID_STATE_ERROR, 0);
   923     return SECFailure;
   924   }
   926   infoObject->SetFalseStartCallbackCalled();
   928   if (infoObject->isAlreadyShutDown()) {
   929     MOZ_CRASH("SSL socket used after NSS shut down");
   930     PR_SetError(PR_INVALID_STATE_ERROR, 0);
   931     return SECFailure;
   932   }
   934   PreliminaryHandshakeDone(fd);
   936   uint32_t reasonsForNotFalseStarting = 0;
   938   SSLChannelInfo channelInfo;
   939   if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
   940     return SECSuccess;
   941   }
   943   SSLCipherSuiteInfo cipherInfo;
   944   if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
   945                              sizeof (cipherInfo)) != SECSuccess) {
   946     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
   947                                       " KEA %d\n", fd,
   948                                       static_cast<int32_t>(cipherInfo.keaType)));
   949     return SECSuccess;
   950   }
   952   nsSSLIOLayerHelpers& helpers = infoObject->SharedState().IOLayerHelpers();
   954   // Prevent version downgrade attacks from TLS 1.x to SSL 3.0.
   955   // TODO(bug 861310): If we negotiate less than our highest-supported version,
   956   // then check that a previously-completed handshake negotiated that version;
   957   // eventually, require that the highest-supported version of TLS is used.
   958   if (channelInfo.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_0) {
   959     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
   960                                       "SSL Version must be >= TLS1 %x\n", fd,
   961                                       static_cast<int32_t>(channelInfo.protocolVersion)));
   962     reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
   963   }
   965   // never do false start without one of these key exchange algorithms
   966   if (cipherInfo.keaType != ssl_kea_rsa &&
   967       cipherInfo.keaType != ssl_kea_dh &&
   968       cipherInfo.keaType != ssl_kea_ecdh) {
   969     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
   970                                       "unsupported KEA %d\n", fd,
   971                                       static_cast<int32_t>(cipherInfo.keaType)));
   972     reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
   973   }
   975   // XXX: This assumes that all TLS_DH_* and TLS_ECDH_* cipher suites
   976   // are disabled.
   977   if (cipherInfo.keaType != ssl_kea_ecdh &&
   978       cipherInfo.keaType != ssl_kea_dh) {
   979     if (helpers.mFalseStartRequireForwardSecrecy) {
   980       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   981              ("CanFalseStartCallback [%p] failed - KEA used is %d, but "
   982               "require-forward-secrecy configured.\n", fd,
   983               static_cast<int32_t>(cipherInfo.keaType)));
   984       reasonsForNotFalseStarting |= KEA_NOT_FORWARD_SECRET;
   985     } else if (cipherInfo.keaType == ssl_kea_rsa) {
   986       // Make sure we've seen the same kea from this host in the past, to limit
   987       // the potential for downgrade attacks.
   988       int16_t expected = infoObject->GetKEAExpected();
   989       if (cipherInfo.keaType != expected) {
   990         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   991                ("CanFalseStartCallback [%p] failed - "
   992                 "KEA used is %d, expected %d\n", fd,
   993                 static_cast<int32_t>(cipherInfo.keaType),
   994                 static_cast<int32_t>(expected)));
   995         reasonsForNotFalseStarting |= KEA_NOT_SAME_AS_EXPECTED;
   996       }
   997     } else {
   998       reasonsForNotFalseStarting |= KEA_NOT_ALLOWED;
   999     }
  1002   // Prevent downgrade attacks on the symmetric cipher. We accept downgrades
  1003   // from 256-bit keys to 128-bit keys and we treat AES and Camellia as being
  1004   // equally secure. We consider every message authentication mechanism that we
  1005   // support *for these ciphers* to be equally-secure. We assume that for CBC
  1006   // mode, that the server has implemented all the same mitigations for
  1007   // published attacks that we have, or that those attacks are not relevant in
  1008   // the decision to false start.
  1009   if (cipherInfo.symCipher != ssl_calg_aes_gcm && 
  1010       cipherInfo.symCipher != ssl_calg_aes &&
  1011       cipherInfo.symCipher != ssl_calg_camellia) {
  1012     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1013            ("CanFalseStartCallback [%p] failed - Symmetric cipher used, %d, "
  1014             "is not supported with False Start.\n", fd,
  1015             static_cast<int32_t>(cipherInfo.symCipher)));
  1016     reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
  1019   // XXX: An attacker can choose which protocols are advertised in the
  1020   // NPN extension. TODO(Bug 861311): We should restrict the ability
  1021   // of an attacker leverage this capability by restricting false start
  1022   // to the same protocol we previously saw for the server, after the
  1023   // first successful connection to the server.
  1025   // Enforce NPN to do false start if policy requires it. Do this as an
  1026   // indicator if server compatibility.
  1027   if (helpers.mFalseStartRequireNPN) {
  1028     nsAutoCString negotiatedNPN;
  1029     if (NS_FAILED(infoObject->GetNegotiatedNPN(negotiatedNPN)) ||
  1030         !negotiatedNPN.Length()) {
  1031       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
  1032                                         "NPN cannot be verified\n", fd));
  1033       reasonsForNotFalseStarting |= NPN_NOT_NEGOTIATED;
  1037   Telemetry::Accumulate(Telemetry::SSL_REASONS_FOR_NOT_FALSE_STARTING,
  1038                         reasonsForNotFalseStarting);
  1040   if (reasonsForNotFalseStarting == 0) {
  1041     *canFalseStart = PR_TRUE;
  1042     infoObject->SetFalseStarted();
  1043     infoObject->NoteTimeUntilReady();
  1044     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] ok\n", fd));
  1047   return SECSuccess;
  1050 static void
  1051 AccumulateNonECCKeySize(Telemetry::ID probe, uint32_t bits)
  1053   unsigned int value = bits <   512 ?  1 : bits ==   512 ?  2
  1054                      : bits <   768 ?  3 : bits ==   768 ?  4
  1055                      : bits <  1024 ?  5 : bits ==  1024 ?  6
  1056                      : bits <  1280 ?  7 : bits ==  1280 ?  8
  1057                      : bits <  1536 ?  9 : bits ==  1536 ? 10
  1058                      : bits <  2048 ? 11 : bits ==  2048 ? 12
  1059                      : bits <  3072 ? 13 : bits ==  3072 ? 14
  1060                      : bits <  4096 ? 15 : bits ==  4096 ? 16
  1061                      : bits <  8192 ? 17 : bits ==  8192 ? 18
  1062                      : bits < 16384 ? 19 : bits == 16384 ? 20
  1063                      : 0;
  1064   Telemetry::Accumulate(probe, value);
  1067 // XXX: This attempts to map a bit count to an ECC named curve identifier. In
  1068 // the vast majority of situations, we only have the Suite B curves available.
  1069 // In that case, this mapping works fine. If we were to have more curves
  1070 // available, the mapping would be ambiguous since there could be multiple
  1071 // named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on
  1072 // that for now. See also NSS bug 323674.
  1073 static void
  1074 AccumulateECCCurve(Telemetry::ID probe, uint32_t bits)
  1076   unsigned int value = bits == 256 ? 23 // P-256
  1077                      : bits == 384 ? 24 // P-384
  1078                      : bits == 521 ? 25 // P-521
  1079                      : 0; // Unknown
  1080   Telemetry::Accumulate(probe, value);
  1083 static void
  1084 AccumulateCipherSuite(Telemetry::ID probe, const SSLChannelInfo& channelInfo)
  1086   uint32_t value;
  1087   switch (channelInfo.cipherSuite) {
  1088     // ECDHE key exchange
  1089     case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: value = 1; break;
  1090     case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: value = 2; break;
  1091     case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: value = 3; break;
  1092     case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: value = 4; break;
  1093     case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: value = 5; break;
  1094     case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: value = 6; break;
  1095     case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 7; break;
  1096     case TLS_ECDHE_RSA_WITH_RC4_128_SHA: value = 8; break;
  1097     case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: value = 9; break;
  1098     case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break;
  1099     // DHE key exchange
  1100     case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break;
  1101     case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break;
  1102     case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: value = 23; break;
  1103     case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 24; break;
  1104     case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 25; break;
  1105     case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: value = 26; break;
  1106     case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: value = 27; break;
  1107     case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: value = 28; break;
  1108     case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: value = 29; break;
  1109     case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: value = 30; break;
  1110     // ECDH key exchange
  1111     case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: value = 41; break;
  1112     case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: value = 42; break;
  1113     case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: value = 43; break;
  1114     case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: value = 44; break;
  1115     case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 45; break;
  1116     case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: value = 46; break;
  1117     case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: value = 47; break;
  1118     case TLS_ECDH_RSA_WITH_RC4_128_SHA: value = 48; break;
  1119     // RSA key exchange
  1120     case TLS_RSA_WITH_AES_128_CBC_SHA: value = 61; break;
  1121     case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 62; break;
  1122     case TLS_RSA_WITH_AES_256_CBC_SHA: value = 63; break;
  1123     case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 64; break;
  1124     case SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA: value = 65; break;
  1125     case TLS_RSA_WITH_3DES_EDE_CBC_SHA: value = 66; break;
  1126     case TLS_RSA_WITH_SEED_CBC_SHA: value = 67; break;
  1127     case TLS_RSA_WITH_RC4_128_SHA: value = 68; break;
  1128     case TLS_RSA_WITH_RC4_128_MD5: value = 69; break;
  1129     // unknown
  1130     default:
  1131       value = 0;
  1132       break;
  1134   MOZ_ASSERT(value != 0);
  1135   Telemetry::Accumulate(probe, value);
  1138 void HandshakeCallback(PRFileDesc* fd, void* client_data) {
  1139   nsNSSShutDownPreventionLock locker;
  1140   SECStatus rv;
  1142   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
  1144   // Do the bookkeeping that needs to be done after the
  1145   // server's ServerHello...ServerHelloDone have been processed, but that doesn't
  1146   // need the handshake to be completed.
  1147   PreliminaryHandshakeDone(fd);
  1149   nsSSLIOLayerHelpers& ioLayerHelpers
  1150     = infoObject->SharedState().IOLayerHelpers();
  1152   SSLVersionRange versions(infoObject->GetTLSVersionRange());
  1154   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1155          ("[%p] HandshakeCallback: succeeded using TLS version range (0x%04x,0x%04x)\n",
  1156           fd, static_cast<unsigned int>(versions.min),
  1157               static_cast<unsigned int>(versions.max)));
  1159   // If the handshake completed, then we know the site is TLS tolerant
  1160   ioLayerHelpers.rememberTolerantAtVersion(infoObject->GetHostName(),
  1161                                            infoObject->GetPort(),
  1162                                            versions.max);
  1164   PRBool siteSupportsSafeRenego;
  1165   rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
  1166                                         &siteSupportsSafeRenego);
  1167   MOZ_ASSERT(rv == SECSuccess);
  1168   if (rv != SECSuccess) {
  1169     siteSupportsSafeRenego = false;
  1172   if (siteSupportsSafeRenego ||
  1173       !ioLayerHelpers.treatUnsafeNegotiationAsBroken()) {
  1174     infoObject->SetSecurityState(nsIWebProgressListener::STATE_IS_SECURE |
  1175                                  nsIWebProgressListener::STATE_SECURE_HIGH);
  1176   } else {
  1177     infoObject->SetSecurityState(nsIWebProgressListener::STATE_IS_BROKEN);
  1180   // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
  1181   // we should set a flag on the channel that higher (UI) level code can check
  1182   // to log the warning. In particular, these warnings should go to the web
  1183   // console instead of to the error console. Also, the warning is not
  1184   // localized.
  1185   if (!siteSupportsSafeRenego &&
  1186       ioLayerHelpers.getWarnLevelMissingRFC5746() > 0) {
  1187     nsXPIDLCString hostName;
  1188     infoObject->GetHostName(getter_Copies(hostName));
  1190     nsAutoString msg;
  1191     msg.Append(NS_ConvertASCIItoUTF16(hostName));
  1192     msg.Append(NS_LITERAL_STRING(" : server does not support RFC 5746, see CVE-2009-3555"));
  1194     nsContentUtils::LogSimpleConsoleError(msg, "SSL");
  1197   mozilla::pkix::ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
  1199   /* Set the SSL Status information */
  1200   RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
  1201   if (!status) {
  1202     status = new nsSSLStatus();
  1203     infoObject->SetSSLStatus(status);
  1206   RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
  1207                                                              status);
  1209   RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(serverCert.get()));
  1210   nsCOMPtr<nsIX509Cert> prevcert;
  1211   infoObject->GetPreviousCert(getter_AddRefs(prevcert));
  1213   bool equals_previous = false;
  1214   if (prevcert && nssc) {
  1215     nsresult rv = nssc->Equals(prevcert, &equals_previous);
  1216     if (NS_FAILED(rv)) {
  1217       equals_previous = false;
  1221   if (equals_previous) {
  1222     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1223             ("HandshakeCallback using PREV cert %p\n", prevcert.get()));
  1224     status->mServerCert = prevcert;
  1226   else {
  1227     if (status->mServerCert) {
  1228       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1229               ("HandshakeCallback KEEPING cert %p\n", status->mServerCert.get()));
  1231     else {
  1232       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1233               ("HandshakeCallback using NEW cert %p\n", nssc.get()));
  1234       status->mServerCert = nssc;
  1238   SSLChannelInfo channelInfo;
  1239   rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
  1240   MOZ_ASSERT(rv == SECSuccess);
  1241   if (rv == SECSuccess) {
  1242     // Get the protocol version for telemetry
  1243     // 0=ssl3, 1=tls1, 2=tls1.1, 3=tls1.2
  1244     unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
  1245     Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
  1246     AccumulateCipherSuite(
  1247       infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
  1248                                     : Telemetry::SSL_CIPHER_SUITE_RESUMED,
  1249       channelInfo);
  1251     SSLCipherSuiteInfo cipherInfo;
  1252     rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
  1253                                 sizeof cipherInfo);
  1254     MOZ_ASSERT(rv == SECSuccess);
  1255     if (rv == SECSuccess) {
  1256       status->mHaveKeyLengthAndCipher = true;
  1257       status->mKeyLength = cipherInfo.symKeyBits;
  1258       status->mSecretKeyLength = cipherInfo.effectiveKeyBits;
  1259       status->mCipherName.Assign(cipherInfo.cipherSuiteName);
  1261       // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
  1262       Telemetry::Accumulate(
  1263         infoObject->IsFullHandshake()
  1264           ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
  1265           : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
  1266         cipherInfo.keaType);
  1267       infoObject->SetKEAUsed(cipherInfo.keaType);
  1269       if (infoObject->IsFullHandshake()) {
  1270         switch (cipherInfo.keaType) {
  1271           case ssl_kea_rsa:
  1272             AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
  1273                                     channelInfo.keaKeyBits);
  1274             break;
  1275           case ssl_kea_dh:
  1276             AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
  1277                                     channelInfo.keaKeyBits);
  1278             break;
  1279           case ssl_kea_ecdh:
  1280             AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
  1281                                channelInfo.keaKeyBits);
  1282             break;
  1283           default:
  1284             MOZ_CRASH("impossible KEA");
  1285             break;
  1288         Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
  1289                               cipherInfo.authAlgorithm);
  1291         // RSA key exchange doesn't use a signature for auth.
  1292         if (cipherInfo.keaType != ssl_kea_rsa) {
  1293           switch (cipherInfo.authAlgorithm) {
  1294             case ssl_auth_rsa:
  1295               AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
  1296                                       channelInfo.authKeyBits);
  1297               break;
  1298             case ssl_auth_dsa:
  1299               AccumulateNonECCKeySize(Telemetry::SSL_AUTH_DSA_KEY_SIZE_FULL,
  1300                                       channelInfo.authKeyBits);
  1301               break;
  1302             case ssl_auth_ecdsa:
  1303               AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
  1304                                  channelInfo.authKeyBits);
  1305               break;
  1306             default:
  1307               MOZ_CRASH("impossible auth algorithm");
  1308               break;
  1313       Telemetry::Accumulate(
  1314           infoObject->IsFullHandshake()
  1315             ? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
  1316             : Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
  1317           cipherInfo.symCipher);
  1321   infoObject->NoteTimeUntilReady();
  1322   infoObject->SetHandshakeCompleted();

mercurial