LCOV - code coverage report
Current view: top level - security/manager/ssl - nsNSSIOLayer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 77 1133 6.8 %
Date: 2017-07-14 16:53:18 Functions: 10 116 8.6 %
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 "nsNSSIOLayer.h"
       8             : 
       9             : #include <algorithm>
      10             : 
      11             : #include "NSSCertDBTrustDomain.h"
      12             : #include "NSSErrorsService.h"
      13             : #include "PSMRunnable.h"
      14             : #include "SSLServerCertVerification.h"
      15             : #include "ScopedNSSTypes.h"
      16             : #include "SharedSSLState.h"
      17             : #include "keyhi.h"
      18             : #include "mozilla/Casting.h"
      19             : #include "mozilla/DebugOnly.h"
      20             : #include "mozilla/Logging.h"
      21             : #include "mozilla/Move.h"
      22             : #include "mozilla/Preferences.h"
      23             : #include "mozilla/Telemetry.h"
      24             : #include "nsArray.h"
      25             : #include "nsArrayUtils.h"
      26             : #include "nsCRT.h"
      27             : #include "nsCharSeparatedTokenizer.h"
      28             : #include "nsClientAuthRemember.h"
      29             : #include "nsContentUtils.h"
      30             : #include "nsIClientAuthDialogs.h"
      31             : #include "nsIConsoleService.h"
      32             : #include "nsIPrefService.h"
      33             : #include "nsISocketProvider.h"
      34             : #include "nsIWebProgressListener.h"
      35             : #include "nsNSSCertHelper.h"
      36             : #include "nsNSSComponent.h"
      37             : #include "nsPrintfCString.h"
      38             : #include "nsServiceManagerUtils.h"
      39             : #include "pkix/pkixtypes.h"
      40             : #include "prmem.h"
      41             : #include "prnetdb.h"
      42             : #include "secder.h"
      43             : #include "secerr.h"
      44             : #include "ssl.h"
      45             : #include "sslerr.h"
      46             : #include "sslproto.h"
      47             : 
      48             : using namespace mozilla;
      49             : using namespace mozilla::psm;
      50             : 
      51             : //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
      52             :                             //reports when doing SSL read/write
      53             : 
      54             : //#define DUMP_BUFFER  //Enable this define along with
      55             :                        //DEBUG_SSL_VERBOSE to dump SSL
      56             :                        //read/write buffer to a log.
      57             :                        //Uses PR_LOG except on Mac where
      58             :                        //we always write out to our own
      59             :                        //file.
      60             : 
      61             : namespace {
      62             : 
      63             : #define MAX_ALPN_LENGTH 255
      64             : 
      65             : void
      66           0 : getSiteKey(const nsACString& hostName, uint16_t port,
      67             :            /*out*/ nsACString& key)
      68             : {
      69           0 :   key = hostName;
      70           0 :   key.AppendASCII(":");
      71           0 :   key.AppendInt(port);
      72           0 : }
      73             : 
      74             : } // unnamed namespace
      75             : 
      76             : extern LazyLogModule gPIPNSSLog;
      77             : 
      78           0 : nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
      79             :   : mFd(nullptr),
      80             :     mCertVerificationState(before_cert_verification),
      81             :     mSharedState(aState),
      82             :     mForSTARTTLS(false),
      83             :     mHandshakePending(true),
      84             :     mRememberClientAuthCertificate(false),
      85             :     mPreliminaryHandshakeDone(false),
      86             :     mNPNCompleted(false),
      87             :     mEarlyDataAccepted(false),
      88             :     mFalseStartCallbackCalled(false),
      89             :     mFalseStarted(false),
      90             :     mIsFullHandshake(false),
      91             :     mHandshakeCompleted(false),
      92             :     mJoined(false),
      93             :     mSentClientCert(false),
      94             :     mNotedTimeUntilReady(false),
      95             :     mFailedVerification(false),
      96             :     mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
      97             :     mKEAKeyBits(0),
      98             :     mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN),
      99             :     mMACAlgorithmUsed(nsISSLSocketControl::SSL_MAC_UNKNOWN),
     100             :     mBypassAuthentication(false),
     101             :     mProviderFlags(providerFlags),
     102             :     mSocketCreationTimestamp(TimeStamp::Now()),
     103             :     mPlaintextBytesRead(0),
     104           0 :     mClientCert(nullptr)
     105             : {
     106           0 :   mTLSVersionRange.min = 0;
     107           0 :   mTLSVersionRange.max = 0;
     108           0 : }
     109             : 
     110           0 : nsNSSSocketInfo::~nsNSSSocketInfo()
     111             : {
     112           0 : }
     113             : 
     114           0 : NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketInfo, TransportSecurityInfo,
     115             :                             nsISSLSocketControl,
     116             :                             nsIClientAuthUserDecision)
     117             : 
     118             : NS_IMETHODIMP
     119           0 : nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
     120             : {
     121           0 :   *aProviderFlags = mProviderFlags;
     122           0 :   return NS_OK;
     123             : }
     124             : 
     125             : NS_IMETHODIMP
     126           0 : nsNSSSocketInfo::GetKEAUsed(int16_t* aKea)
     127             : {
     128           0 :   *aKea = mKEAUsed;
     129           0 :   return NS_OK;
     130             : }
     131             : 
     132             : NS_IMETHODIMP
     133           0 : nsNSSSocketInfo::GetKEAKeyBits(uint32_t* aKeyBits)
     134             : {
     135           0 :   *aKeyBits = mKEAKeyBits;
     136           0 :   return NS_OK;
     137             : }
     138             : 
     139             : NS_IMETHODIMP
     140           0 : nsNSSSocketInfo::GetSSLVersionUsed(int16_t* aSSLVersionUsed)
     141             : {
     142           0 :   *aSSLVersionUsed = mSSLVersionUsed;
     143           0 :   return NS_OK;
     144             : }
     145             : 
     146             : NS_IMETHODIMP
     147           0 : nsNSSSocketInfo::GetSSLVersionOffered(int16_t* aSSLVersionOffered)
     148             : {
     149           0 :   *aSSLVersionOffered = mTLSVersionRange.max;
     150           0 :   return NS_OK;
     151             : }
     152             : 
     153             : NS_IMETHODIMP
     154           0 : nsNSSSocketInfo::GetMACAlgorithmUsed(int16_t* aMac)
     155             : {
     156           0 :   *aMac = mMACAlgorithmUsed;
     157           0 :   return NS_OK;
     158             : }
     159             : 
     160             : NS_IMETHODIMP
     161           0 : nsNSSSocketInfo::GetClientCert(nsIX509Cert** aClientCert)
     162             : {
     163           0 :   NS_ENSURE_ARG_POINTER(aClientCert);
     164           0 :   *aClientCert = mClientCert;
     165           0 :   NS_IF_ADDREF(*aClientCert);
     166           0 :   return NS_OK;
     167             : }
     168             : 
     169             : NS_IMETHODIMP
     170           0 : nsNSSSocketInfo::SetClientCert(nsIX509Cert* aClientCert)
     171             : {
     172           0 :   mClientCert = aClientCert;
     173           0 :   return NS_OK;
     174             : }
     175             : 
     176             : NS_IMETHODIMP
     177           0 : nsNSSSocketInfo::GetBypassAuthentication(bool* arg)
     178             : {
     179           0 :   *arg = mBypassAuthentication;
     180           0 :   return NS_OK;
     181             : }
     182             : 
     183             : NS_IMETHODIMP
     184           0 : nsNSSSocketInfo::GetFailedVerification(bool* arg)
     185             : {
     186           0 :   *arg = mFailedVerification;
     187           0 :   return NS_OK;
     188             : }
     189             : 
     190             : NS_IMETHODIMP
     191           0 : nsNSSSocketInfo::GetRememberClientAuthCertificate(bool* aRemember)
     192             : {
     193           0 :   NS_ENSURE_ARG_POINTER(aRemember);
     194           0 :   *aRemember = mRememberClientAuthCertificate;
     195           0 :   return NS_OK;
     196             : }
     197             : 
     198             : NS_IMETHODIMP
     199           0 : nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRemember)
     200             : {
     201           0 :   mRememberClientAuthCertificate = aRemember;
     202           0 :   return NS_OK;
     203             : }
     204             : 
     205             : NS_IMETHODIMP
     206           0 : nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
     207             : {
     208           0 :   *aCallbacks = mCallbacks;
     209           0 :   NS_IF_ADDREF(*aCallbacks);
     210           0 :   return NS_OK;
     211             : }
     212             : 
     213             : NS_IMETHODIMP
     214           0 : nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
     215             : {
     216           0 :   if (!aCallbacks) {
     217           0 :     mCallbacks = nullptr;
     218           0 :     return NS_OK;
     219             :   }
     220             : 
     221           0 :   mCallbacks = aCallbacks;
     222             : 
     223           0 :   return NS_OK;
     224             : }
     225             : 
     226             : void
     227           0 : nsNSSSocketInfo::NoteTimeUntilReady()
     228             : {
     229           0 :   if (mNotedTimeUntilReady)
     230           0 :     return;
     231             : 
     232           0 :   mNotedTimeUntilReady = true;
     233             : 
     234             :   // This will include TCP and proxy tunnel wait time
     235           0 :   Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
     236           0 :                                  mSocketCreationTimestamp, TimeStamp::Now());
     237           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     238             :          ("[%p] nsNSSSocketInfo::NoteTimeUntilReady\n", mFd));
     239             : }
     240             : 
     241             : void
     242           0 : nsNSSSocketInfo::SetHandshakeCompleted()
     243             : {
     244           0 :   if (!mHandshakeCompleted) {
     245             :     enum HandshakeType {
     246             :       Resumption = 1,
     247             :       FalseStarted = 2,
     248             :       ChoseNotToFalseStart = 3,
     249             :       NotAllowedToFalseStart = 4,
     250             :     };
     251             : 
     252           0 :     HandshakeType handshakeType = !IsFullHandshake() ? Resumption
     253           0 :                                 : mFalseStarted ? FalseStarted
     254           0 :                                 : mFalseStartCallbackCalled ? ChoseNotToFalseStart
     255           0 :                                 : NotAllowedToFalseStart;
     256             : 
     257             :     // This will include TCP and proxy tunnel wait time
     258           0 :     Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_HANDSHAKE_FINISHED,
     259           0 :                                    mSocketCreationTimestamp, TimeStamp::Now());
     260             : 
     261             :     // If the handshake is completed for the first time from just 1 callback
     262             :     // that means that TLS session resumption must have been used.
     263           0 :     Telemetry::Accumulate(Telemetry::SSL_RESUMED_SESSION,
     264           0 :                           handshakeType == Resumption);
     265           0 :     Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_TYPE, handshakeType);
     266             :   }
     267             : 
     268             : 
     269             :     // Remove the plain text layer as it is not needed anymore.
     270             :     // The plain text layer is not always present - so its not a fatal error
     271             :     // if it cannot be removed
     272             :     PRFileDesc* poppedPlaintext =
     273           0 :       PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
     274           0 :     if (poppedPlaintext) {
     275           0 :       PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
     276           0 :       poppedPlaintext->dtor(poppedPlaintext);
     277             :     }
     278             : 
     279           0 :     mHandshakeCompleted = true;
     280             : 
     281           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
     282             :            ("[%p] nsNSSSocketInfo::SetHandshakeCompleted\n", (void*) mFd));
     283             : 
     284           0 :     mIsFullHandshake = false; // reset for next handshake on this connection
     285           0 : }
     286             : 
     287             : void
     288           0 : nsNSSSocketInfo::SetNegotiatedNPN(const char* value, uint32_t length)
     289             : {
     290           0 :   if (!value) {
     291           0 :     mNegotiatedNPN.Truncate();
     292             :   } else {
     293           0 :     mNegotiatedNPN.Assign(value, length);
     294             :   }
     295           0 :   mNPNCompleted = true;
     296           0 : }
     297             : 
     298             : NS_IMETHODIMP
     299           0 : nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN)
     300             : {
     301           0 :   if (!mNPNCompleted)
     302           0 :     return NS_ERROR_NOT_CONNECTED;
     303             : 
     304           0 :   aNegotiatedNPN = mNegotiatedNPN;
     305           0 :   return NS_OK;
     306             : }
     307             : 
     308             : NS_IMETHODIMP
     309           0 : nsNSSSocketInfo::GetAlpnEarlySelection(nsACString& aAlpnSelected)
     310             : {
     311           0 :   aAlpnSelected.Truncate();
     312             : 
     313           0 :   nsNSSShutDownPreventionLock locker;
     314           0 :   if (isAlreadyShutDown() || isPK11LoggedOut()) {
     315           0 :     return NS_ERROR_NOT_AVAILABLE;
     316             :   }
     317             : 
     318             :   SSLPreliminaryChannelInfo info;
     319           0 :   SECStatus rv = SSL_GetPreliminaryChannelInfo(mFd, &info, sizeof(info));
     320           0 :   if (rv != SECSuccess || !info.canSendEarlyData) {
     321           0 :     return NS_ERROR_NOT_AVAILABLE;
     322             :   }
     323             : 
     324             :   SSLNextProtoState alpnState;
     325             :   unsigned char chosenAlpn[MAX_ALPN_LENGTH];
     326             :   unsigned int chosenAlpnLen;
     327           0 :   rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen,
     328           0 :                         AssertedCast<unsigned int>(ArrayLength(chosenAlpn)));
     329             : 
     330           0 :   if (rv != SECSuccess) {
     331           0 :     return NS_ERROR_NOT_AVAILABLE;
     332             :   }
     333             : 
     334           0 :   if (alpnState == SSL_NEXT_PROTO_EARLY_VALUE) {
     335           0 :     aAlpnSelected.Assign(BitwiseCast<char*, unsigned char*>(chosenAlpn),
     336           0 :                          chosenAlpnLen);
     337             :   }
     338             : 
     339           0 :   return NS_OK;
     340             : }
     341             : 
     342             : NS_IMETHODIMP
     343           0 : nsNSSSocketInfo::GetEarlyDataAccepted(bool* aAccepted)
     344             : {
     345           0 :   *aAccepted = mEarlyDataAccepted;
     346           0 :   return NS_OK;
     347             : }
     348             : 
     349             : void
     350           0 : nsNSSSocketInfo::SetEarlyDataAccepted(bool aAccepted)
     351             : {
     352           0 :   mEarlyDataAccepted = aAccepted;
     353           0 : }
     354             : 
     355             : NS_IMETHODIMP
     356           0 : nsNSSSocketInfo::DriveHandshake()
     357             : {
     358           0 :   nsNSSShutDownPreventionLock locker;
     359           0 :   if (isAlreadyShutDown() || isPK11LoggedOut()) {
     360           0 :     return NS_ERROR_NOT_AVAILABLE;
     361             :   }
     362           0 :   if (!mFd) {
     363           0 :     return NS_ERROR_FAILURE;
     364             :   }
     365           0 :   PRErrorCode errorCode = GetErrorCode();
     366           0 :   if (errorCode) {
     367           0 :     return GetXPCOMFromNSSError(errorCode);
     368             :   }
     369             : 
     370           0 :   SECStatus rv = SSL_ForceHandshake(mFd);
     371             : 
     372           0 :   if (rv != SECSuccess) {
     373           0 :     errorCode = PR_GetError();
     374           0 :     if (errorCode == PR_WOULD_BLOCK_ERROR) {
     375           0 :       return NS_BASE_STREAM_WOULD_BLOCK;
     376             :     }
     377             : 
     378           0 :     SetCanceled(errorCode, SSLErrorMessageType::Plain);
     379           0 :     return GetXPCOMFromNSSError(errorCode);
     380             :   }
     381           0 :   return NS_OK;
     382             : }
     383             : 
     384             : NS_IMETHODIMP
     385           0 : nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
     386             : {
     387           0 :   NS_ENSURE_ARG(_retval);
     388             : 
     389           0 :   *_retval = false;
     390             : 
     391             :   // If this is the same hostname then the certicate status does not
     392             :   // need to be considered. They are joinable.
     393           0 :   if (hostname.Equals(GetHostName())) {
     394           0 :     *_retval = true;
     395           0 :     return NS_OK;
     396             :   }
     397             : 
     398             :   // Before checking the server certificate we need to make sure the
     399             :   // handshake has completed.
     400           0 :   if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->HasServerCert()) {
     401           0 :     return NS_OK;
     402             :   }
     403             : 
     404             :   // If the cert has error bits (e.g. it is untrusted) then do not join.
     405             :   // The value of mHaveCertErrorBits is only reliable because we know that
     406             :   // the handshake completed.
     407           0 :   if (SSLStatus()->mHaveCertErrorBits)
     408           0 :     return NS_OK;
     409             : 
     410             :   // If the connection is using client certificates then do not join
     411             :   // because the user decides on whether to send client certs to hosts on a
     412             :   // per-domain basis.
     413           0 :   if (mSentClientCert)
     414           0 :     return NS_OK;
     415             : 
     416             :   // Ensure that the server certificate covers the hostname that would
     417             :   // like to join this connection
     418             : 
     419           0 :   UniqueCERTCertificate nssCert;
     420             : 
     421           0 :   nsCOMPtr<nsIX509Cert> cert;
     422           0 :   if (NS_FAILED(SSLStatus()->GetServerCert(getter_AddRefs(cert)))) {
     423           0 :     return NS_OK;
     424             :   }
     425           0 :   if (cert) {
     426           0 :     nssCert.reset(cert->GetCert());
     427             :   }
     428             : 
     429           0 :   if (!nssCert) {
     430           0 :     return NS_OK;
     431             :   }
     432             : 
     433             :   // Attempt to verify the joinee's certificate using the joining hostname.
     434             :   // This ensures that any hostname-specific verification logic (e.g. key
     435             :   // pinning) is satisfied by the joinee's certificate chain.
     436             :   // This verification only uses local information; since we're on the network
     437             :   // thread, we would be blocking on ourselves if we attempted any network i/o.
     438             :   // TODO(bug 1056935): The certificate chain built by this verification may be
     439             :   // different than the certificate chain originally built during the joined
     440             :   // connection's TLS handshake. Consequently, we may report a wrong and/or
     441             :   // misleading certificate chain for HTTP transactions coalesced onto this
     442             :   // connection. This may become problematic in the future. For example,
     443             :   // if/when we begin relying on intermediate certificates being stored in the
     444             :   // securityInfo of a cached HTTPS response, that cached certificate chain may
     445             :   // actually be the wrong chain. We should consider having JoinConnection
     446             :   // return the certificate chain built here, so that the calling Necko code
     447             :   // can associate the correct certificate chain with the HTTP transactions it
     448             :   // is trying to join onto this connection.
     449           0 :   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
     450           0 :   if (!certVerifier) {
     451           0 :     return NS_OK;
     452             :   }
     453           0 :   CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY;
     454           0 :   UniqueCERTCertList unusedBuiltChain;
     455             :   mozilla::pkix::Result result =
     456           0 :     certVerifier->VerifySSLServerCert(nssCert,
     457             :                                       nullptr, // stapledOCSPResponse
     458             :                                       nullptr, // sctsFromTLSExtension
     459             :                                       mozilla::pkix::Now(),
     460             :                                       nullptr, // pinarg
     461             :                                       hostname,
     462             :                                       unusedBuiltChain,
     463             :                                       nullptr, // no peerCertChain
     464             :                                       false, // save intermediates
     465           0 :                                       flags);
     466           0 :   if (result != mozilla::pkix::Success) {
     467           0 :     return NS_OK;
     468             :   }
     469             : 
     470             :   // All tests pass
     471           0 :   *_retval = true;
     472           0 :   return NS_OK;
     473             : }
     474             : 
     475             : NS_IMETHODIMP
     476           0 : nsNSSSocketInfo::TestJoinConnection(const nsACString& npnProtocol,
     477             :                                     const nsACString& hostname,
     478             :                                     int32_t port,
     479             :                                     bool* _retval)
     480             : {
     481           0 :   *_retval = false;
     482             : 
     483             :   // Different ports may not be joined together
     484           0 :   if (port != GetPort())
     485           0 :     return NS_OK;
     486             : 
     487             :   // Make sure NPN has been completed and matches requested npnProtocol
     488           0 :   if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
     489           0 :     return NS_OK;
     490             : 
     491           0 :   if (mBypassAuthentication) {
     492             :     // An unauthenticated connection does not know whether or not it
     493             :     // is acceptable for a particular hostname
     494           0 :     return NS_OK;
     495             :   }
     496             : 
     497           0 :   IsAcceptableForHost(hostname, _retval); // sets _retval
     498           0 :   return NS_OK;
     499             : }
     500             : 
     501             : NS_IMETHODIMP
     502           0 : nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
     503             :                                 const nsACString& hostname,
     504             :                                 int32_t port,
     505             :                                 bool* _retval)
     506             : {
     507           0 :   nsresult rv = TestJoinConnection(npnProtocol, hostname, port, _retval);
     508           0 :   if (NS_SUCCEEDED(rv) && *_retval) {
     509             :     // All tests pass - this is joinable
     510           0 :     mJoined = true;
     511             :   }
     512           0 :   return rv;
     513             : }
     514             : 
     515             : bool
     516           0 : nsNSSSocketInfo::GetForSTARTTLS()
     517             : {
     518           0 :   return mForSTARTTLS;
     519             : }
     520             : 
     521             : void
     522           0 : nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
     523             : {
     524           0 :   mForSTARTTLS = aForSTARTTLS;
     525           0 : }
     526             : 
     527             : NS_IMETHODIMP
     528           0 : nsNSSSocketInfo::ProxyStartSSL()
     529             : {
     530           0 :   return ActivateSSL();
     531             : }
     532             : 
     533             : NS_IMETHODIMP
     534           0 : nsNSSSocketInfo::StartTLS()
     535             : {
     536           0 :   return ActivateSSL();
     537             : }
     538             : 
     539             : NS_IMETHODIMP
     540           0 : nsNSSSocketInfo::SetNPNList(nsTArray<nsCString>& protocolArray)
     541             : {
     542           0 :   nsNSSShutDownPreventionLock locker;
     543           0 :   if (isAlreadyShutDown())
     544           0 :     return NS_ERROR_NOT_AVAILABLE;
     545           0 :   if (!mFd)
     546           0 :     return NS_ERROR_FAILURE;
     547             : 
     548             :   // the npn list is a concatenated list of 8 bit byte strings.
     549           0 :   nsCString npnList;
     550             : 
     551           0 :   for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
     552           0 :     if (protocolArray[index].IsEmpty() ||
     553           0 :         protocolArray[index].Length() > 255)
     554           0 :       return NS_ERROR_ILLEGAL_VALUE;
     555             : 
     556           0 :     npnList.Append(protocolArray[index].Length());
     557           0 :     npnList.Append(protocolArray[index]);
     558             :   }
     559             : 
     560           0 :   if (SSL_SetNextProtoNego(
     561             :         mFd,
     562             :         BitwiseCast<const unsigned char*, const char*>(npnList.get()),
     563             :         npnList.Length()) != SECSuccess)
     564           0 :     return NS_ERROR_FAILURE;
     565             : 
     566           0 :   return NS_OK;
     567             : }
     568             : 
     569             : nsresult
     570           0 : nsNSSSocketInfo::ActivateSSL()
     571             : {
     572           0 :   nsNSSShutDownPreventionLock locker;
     573           0 :   if (isAlreadyShutDown())
     574           0 :     return NS_ERROR_NOT_AVAILABLE;
     575             : 
     576           0 :   if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
     577           0 :     return NS_ERROR_FAILURE;
     578           0 :   if (SECSuccess != SSL_ResetHandshake(mFd, false))
     579           0 :     return NS_ERROR_FAILURE;
     580             : 
     581           0 :   mHandshakePending = true;
     582             : 
     583           0 :   return NS_OK;
     584             : }
     585             : 
     586             : nsresult
     587           0 : nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
     588             : {
     589           0 :   *aFilePtr = mFd;
     590           0 :   return NS_OK;
     591             : }
     592             : 
     593             : nsresult
     594           0 : nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
     595             : {
     596           0 :   mFd = aFilePtr;
     597           0 :   return NS_OK;
     598             : }
     599             : 
     600             : void
     601           0 : nsNSSSocketInfo::SetCertVerificationWaiting()
     602             : {
     603             :   // mCertVerificationState may be before_cert_verification for the first
     604             :   // handshake on the connection, or after_cert_verification for subsequent
     605             :   // renegotiation handshakes.
     606           0 :   MOZ_ASSERT(mCertVerificationState != waiting_for_cert_verification,
     607             :              "Invalid state transition to waiting_for_cert_verification");
     608           0 :   mCertVerificationState = waiting_for_cert_verification;
     609           0 : }
     610             : 
     611             : // Be careful that SetCertVerificationResult does NOT get called while we are
     612             : // processing a SSL callback function, because SSL_AuthCertificateComplete will
     613             : // attempt to acquire locks that are already held by libssl when it calls
     614             : // callbacks.
     615             : void
     616           0 : nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
     617             :                                            SSLErrorMessageType errorMessageType)
     618             : {
     619           0 :   MOZ_ASSERT(mCertVerificationState == waiting_for_cert_verification,
     620             :              "Invalid state transition to cert_verification_finished");
     621             : 
     622           0 :   if (mFd) {
     623           0 :     SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
     624             :     // Only replace errorCode if there was originally no error
     625           0 :     if (rv != SECSuccess && errorCode == 0) {
     626           0 :       errorCode = PR_GetError();
     627           0 :       errorMessageType = SSLErrorMessageType::Plain;
     628           0 :       if (errorCode == 0) {
     629           0 :         NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
     630           0 :         errorCode = PR_INVALID_STATE_ERROR;
     631             :       }
     632             :     }
     633             :   }
     634             : 
     635           0 :   if (errorCode) {
     636           0 :     mFailedVerification = true;
     637           0 :     SetCanceled(errorCode, errorMessageType);
     638             :   }
     639             : 
     640           0 :   if (mPlaintextBytesRead && !errorCode) {
     641           0 :     Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK,
     642           0 :                           AssertedCast<uint32_t>(mPlaintextBytesRead));
     643             :   }
     644             : 
     645           0 :   mCertVerificationState = after_cert_verification;
     646           0 : }
     647             : 
     648             : SharedSSLState&
     649           0 : nsNSSSocketInfo::SharedState()
     650             : {
     651           0 :   return mSharedState;
     652             : }
     653             : 
     654           0 : void nsSSLIOLayerHelpers::Cleanup()
     655             : {
     656           0 :   MutexAutoLock lock(mutex);
     657           0 :   mTLSIntoleranceInfo.Clear();
     658           0 :   mInsecureFallbackSites.Clear();
     659           0 : }
     660             : 
     661             : static void
     662           0 : nsHandleSSLError(nsNSSSocketInfo* socketInfo,
     663             :                  ::mozilla::psm::SSLErrorMessageType errtype,
     664             :                  PRErrorCode err)
     665             : {
     666           0 :   if (!NS_IsMainThread()) {
     667           0 :     NS_ERROR("nsHandleSSLError called off the main thread");
     668           0 :     return;
     669             :   }
     670             : 
     671             :   // SetCanceled is only called by the main thread or the socket transport
     672             :   // thread. Whenever this function is called on the main thread, the SSL
     673             :   // thread is blocked on it. So, no mutex is necessary for
     674             :   // SetCanceled()/GetError*().
     675           0 :   if (socketInfo->GetErrorCode()) {
     676             :     // If the socket has been flagged as canceled,
     677             :     // the code who did was responsible for setting the error code.
     678           0 :     return;
     679             :   }
     680             : 
     681             :   // We must cancel first, which sets the error code.
     682           0 :   socketInfo->SetCanceled(err, SSLErrorMessageType::Plain);
     683           0 :   nsXPIDLString errorString;
     684           0 :   socketInfo->GetErrorLogMessage(err, errtype, errorString);
     685             : 
     686           0 :   if (!errorString.IsEmpty()) {
     687           0 :     nsContentUtils::LogSimpleConsoleError(errorString, "SSL");
     688             :   }
     689             : }
     690             : 
     691             : namespace {
     692             : 
     693             : enum Operation { reading, writing, not_reading_or_writing };
     694             : 
     695             : int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
     696             :                        PRFileDesc* ssl_layer_fd,
     697             :                        nsNSSSocketInfo* socketInfo);
     698             : 
     699             : nsNSSSocketInfo*
     700           0 : getSocketInfoIfRunning(PRFileDesc* fd, Operation op,
     701             :                        const nsNSSShutDownPreventionLock& /*proofOfLock*/)
     702             : {
     703           0 :   if (!fd || !fd->lower || !fd->secret ||
     704           0 :       fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
     705           0 :     NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
     706           0 :     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
     707           0 :     return nullptr;
     708             :   }
     709             : 
     710           0 :   nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*) fd->secret;
     711             : 
     712           0 :   if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
     713           0 :     PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
     714           0 :     return nullptr;
     715             :   }
     716             : 
     717           0 :   if (socketInfo->GetErrorCode()) {
     718           0 :     PRErrorCode err = socketInfo->GetErrorCode();
     719           0 :     PR_SetError(err, 0);
     720           0 :     if (op == reading || op == writing) {
     721             :       // We must do TLS intolerance checks for reads and writes, for timeouts
     722             :       // in particular.
     723           0 :       (void) checkHandshake(-1, op == reading, fd, socketInfo);
     724             :     }
     725             : 
     726             :     // If we get here, it is probably because cert verification failed and this
     727             :     // is the first I/O attempt since that failure.
     728           0 :     return nullptr;
     729             :   }
     730             : 
     731           0 :   return socketInfo;
     732             : }
     733             : 
     734             : } // namespace
     735             : 
     736             : static PRStatus
     737           0 : nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
     738             :                     PRIntervalTime timeout)
     739             : {
     740           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] connecting SSL socket\n",
     741             :          (void*) fd));
     742           0 :   nsNSSShutDownPreventionLock locker;
     743           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
     744           0 :     return PR_FAILURE;
     745             : 
     746           0 :   PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
     747           0 :   if (status != PR_SUCCESS) {
     748           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("[%p] Lower layer connect error: %d\n",
     749             :                                       (void*) fd, PR_GetError()));
     750           0 :     return status;
     751             :   }
     752             : 
     753           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Connect\n", (void*) fd));
     754           0 :   return status;
     755             : }
     756             : 
     757             : void
     758           0 : nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
     759             :                                                int16_t port, uint16_t tolerant)
     760             : {
     761           0 :   nsCString key;
     762           0 :   getSiteKey(hostName, port, key);
     763             : 
     764           0 :   MutexAutoLock lock(mutex);
     765             : 
     766             :   IntoleranceEntry entry;
     767           0 :   if (mTLSIntoleranceInfo.Get(key, &entry)) {
     768           0 :     entry.AssertInvariant();
     769           0 :     entry.tolerant = std::max(entry.tolerant, tolerant);
     770           0 :     if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
     771           0 :       entry.intolerant = entry.tolerant + 1;
     772           0 :       entry.intoleranceReason = 0; // lose the reason
     773             :     }
     774             :   } else {
     775           0 :     entry.tolerant = tolerant;
     776           0 :     entry.intolerant = 0;
     777           0 :     entry.intoleranceReason = 0;
     778             :   }
     779             : 
     780           0 :   entry.AssertInvariant();
     781             : 
     782           0 :   mTLSIntoleranceInfo.Put(key, entry);
     783           0 : }
     784             : 
     785             : void
     786           0 : nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
     787             :                                        int16_t port)
     788             : {
     789           0 :   nsCString key;
     790           0 :   getSiteKey(hostName, port, key);
     791             : 
     792           0 :   MutexAutoLock lock(mutex);
     793             : 
     794             :   IntoleranceEntry entry;
     795           0 :   if (mTLSIntoleranceInfo.Get(key, &entry)) {
     796           0 :     entry.AssertInvariant();
     797             : 
     798           0 :     entry.intolerant = 0;
     799           0 :     entry.intoleranceReason = 0;
     800             : 
     801           0 :     entry.AssertInvariant();
     802           0 :     mTLSIntoleranceInfo.Put(key, entry);
     803             :   }
     804           0 : }
     805             : 
     806             : bool
     807           0 : nsSSLIOLayerHelpers::fallbackLimitReached(const nsACString& hostName,
     808             :                                           uint16_t intolerant)
     809             : {
     810           0 :   if (isInsecureFallbackSite(hostName)) {
     811           0 :     return intolerant <= SSL_LIBRARY_VERSION_TLS_1_0;
     812             :   }
     813           0 :   return intolerant <= mVersionFallbackLimit;
     814             : }
     815             : 
     816             : // returns true if we should retry the handshake
     817             : bool
     818           0 : nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName,
     819             :                                                  int16_t port,
     820             :                                                  uint16_t minVersion,
     821             :                                                  uint16_t intolerant,
     822             :                                                  PRErrorCode intoleranceReason)
     823             : {
     824           0 :   if (intolerant <= minVersion || fallbackLimitReached(hostName, intolerant)) {
     825             :     // We can't fall back any further. Assume that intolerance isn't the issue.
     826           0 :     forgetIntolerance(hostName, port);
     827           0 :     return false;
     828             :   }
     829             : 
     830           0 :   nsCString key;
     831           0 :   getSiteKey(hostName, port, key);
     832             : 
     833           0 :   MutexAutoLock lock(mutex);
     834             : 
     835             :   IntoleranceEntry entry;
     836           0 :   if (mTLSIntoleranceInfo.Get(key, &entry)) {
     837           0 :     entry.AssertInvariant();
     838           0 :     if (intolerant <= entry.tolerant) {
     839             :       // We already know the server is tolerant at an equal or higher version.
     840           0 :       return false;
     841             :     }
     842           0 :     if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
     843             :       // We already know that the server is intolerant at a lower version.
     844           0 :       return true;
     845             :     }
     846             :   } else {
     847           0 :     entry.tolerant = 0;
     848             :   }
     849             : 
     850           0 :   entry.intolerant = intolerant;
     851           0 :   entry.intoleranceReason = intoleranceReason;
     852           0 :   entry.AssertInvariant();
     853           0 :   mTLSIntoleranceInfo.Put(key, entry);
     854             : 
     855           0 :   return true;
     856             : }
     857             : 
     858             : void
     859           0 : nsSSLIOLayerHelpers::adjustForTLSIntolerance(const nsACString& hostName,
     860             :                                              int16_t port,
     861             :                                              /*in/out*/ SSLVersionRange& range)
     862             : {
     863             :   IntoleranceEntry entry;
     864             : 
     865             :   {
     866           0 :     nsCString key;
     867           0 :     getSiteKey(hostName, port, key);
     868             : 
     869           0 :     MutexAutoLock lock(mutex);
     870           0 :     if (!mTLSIntoleranceInfo.Get(key, &entry)) {
     871           0 :       return;
     872             :     }
     873             :   }
     874             : 
     875           0 :   entry.AssertInvariant();
     876             : 
     877           0 :   if (entry.intolerant != 0) {
     878             :     // We've tried connecting at a higher range but failed, so try at the
     879             :     // version we haven't tried yet, unless we have reached the minimum.
     880           0 :     if (range.min < entry.intolerant) {
     881           0 :       range.max = entry.intolerant - 1;
     882             :     }
     883             :   }
     884             : }
     885             : 
     886             : PRErrorCode
     887           0 : nsSSLIOLayerHelpers::getIntoleranceReason(const nsACString& hostName,
     888             :                                           int16_t port)
     889             : {
     890             :   IntoleranceEntry entry;
     891             : 
     892             :   {
     893           0 :     nsCString key;
     894           0 :     getSiteKey(hostName, port, key);
     895             : 
     896           0 :     MutexAutoLock lock(mutex);
     897           0 :     if (!mTLSIntoleranceInfo.Get(key, &entry)) {
     898           0 :       return 0;
     899             :     }
     900             :   }
     901             : 
     902           0 :   entry.AssertInvariant();
     903           0 :   return entry.intoleranceReason;
     904             : }
     905             : 
     906             : bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
     907             : PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
     908             : PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
     909             : PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
     910             : PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
     911             : 
     912             : static PRStatus
     913           0 : nsSSLIOLayerClose(PRFileDesc* fd)
     914             : {
     915           0 :   nsNSSShutDownPreventionLock locker;
     916           0 :   if (!fd)
     917           0 :     return PR_FAILURE;
     918             : 
     919           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Shutting down socket\n",
     920             :          (void*) fd));
     921             : 
     922           0 :   nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*) fd->secret;
     923           0 :   MOZ_ASSERT(socketInfo, "nsNSSSocketInfo was null for an fd");
     924             : 
     925           0 :   return socketInfo->CloseSocketAndDestroy(locker);
     926             : }
     927             : 
     928             : PRStatus
     929           0 : nsNSSSocketInfo::CloseSocketAndDestroy(
     930             :     const nsNSSShutDownPreventionLock& /*proofOfLock*/)
     931             : {
     932           0 :   PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
     933           0 :   MOZ_ASSERT(popped &&
     934             :                popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
     935             :              "SSL Layer not on top of stack");
     936             : 
     937             :   // The plain text layer is not always present - so its not a fatal error
     938             :   // if it cannot be removed
     939             :   PRFileDesc* poppedPlaintext =
     940           0 :     PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
     941           0 :   if (poppedPlaintext) {
     942           0 :     PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
     943           0 :     poppedPlaintext->dtor(poppedPlaintext);
     944             :   }
     945             : 
     946           0 :   PRStatus status = mFd->methods->close(mFd);
     947             : 
     948             :   // the nsNSSSocketInfo instance can out-live the connection, so we need some
     949             :   // indication that the connection has been closed. mFd == nullptr is that
     950             :   // indication. This is needed, for example, when the connection is closed
     951             :   // before we have finished validating the server's certificate.
     952           0 :   mFd = nullptr;
     953             : 
     954           0 :   if (status != PR_SUCCESS) return status;
     955             : 
     956           0 :   popped->identity = PR_INVALID_IO_LAYER;
     957           0 :   NS_RELEASE_THIS();
     958           0 :   popped->dtor(popped);
     959             : 
     960           0 :   return PR_SUCCESS;
     961             : }
     962             : 
     963             : #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
     964             : // Dumps a (potentially binary) buffer using SSM_DEBUG.  (We could have used
     965             : // the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
     966             : #define DUMPBUF_LINESIZE 24
     967             : static void
     968             : nsDumpBuffer(unsigned char* buf, int len)
     969             : {
     970             :   char hexbuf[DUMPBUF_LINESIZE*3+1];
     971             :   char chrbuf[DUMPBUF_LINESIZE+1];
     972             :   static const char* hex = "0123456789abcdef";
     973             :   int i = 0;
     974             :   int l = 0;
     975             :   char ch;
     976             :   char* c;
     977             :   char* h;
     978             :   if (len == 0)
     979             :     return;
     980             :   hexbuf[DUMPBUF_LINESIZE*3] = '\0';
     981             :   chrbuf[DUMPBUF_LINESIZE] = '\0';
     982             :   (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
     983             :   (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
     984             :   h = hexbuf;
     985             :   c = chrbuf;
     986             : 
     987             :   while (i < len) {
     988             :     ch = buf[i];
     989             : 
     990             :     if (l == DUMPBUF_LINESIZE) {
     991             :       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
     992             :       (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
     993             :       (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
     994             :       h = hexbuf;
     995             :       c = chrbuf;
     996             :       l = 0;
     997             :     }
     998             : 
     999             :     // Convert a character to hex.
    1000             :     *h++ = hex[(ch >> 4) & 0xf];
    1001             :     *h++ = hex[ch & 0xf];
    1002             :     h++;
    1003             : 
    1004             :     // Put the character (if it's printable) into the character buffer.
    1005             :     if ((ch >= 0x20) && (ch <= 0x7e)) {
    1006             :       *c++ = ch;
    1007             :     } else {
    1008             :       *c++ = '.';
    1009             :     }
    1010             :     i++; l++;
    1011             :   }
    1012             :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
    1013             : }
    1014             : 
    1015             : #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
    1016             : #else
    1017             : #define DEBUG_DUMP_BUFFER(buf,len)
    1018             : #endif
    1019             : 
    1020           0 : class SSLErrorRunnable : public SyncRunnableBase
    1021             : {
    1022             :  public:
    1023           0 :   SSLErrorRunnable(nsNSSSocketInfo* infoObject,
    1024             :                    ::mozilla::psm::SSLErrorMessageType errtype,
    1025             :                    PRErrorCode errorCode)
    1026           0 :     : mInfoObject(infoObject)
    1027             :     , mErrType(errtype)
    1028           0 :     , mErrorCode(errorCode)
    1029             :   {
    1030           0 :   }
    1031             : 
    1032           0 :   virtual void RunOnTargetThread()
    1033             :   {
    1034           0 :     nsHandleSSLError(mInfoObject, mErrType, mErrorCode);
    1035           0 :   }
    1036             : 
    1037             :   RefPtr<nsNSSSocketInfo> mInfoObject;
    1038             :   ::mozilla::psm::SSLErrorMessageType mErrType;
    1039             :   const PRErrorCode mErrorCode;
    1040             : };
    1041             : 
    1042             : namespace {
    1043             : 
    1044           0 : uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err)
    1045             : {
    1046             :   // returns a numeric code for where we track various errors in telemetry
    1047             :   // only errors that cause version fallback are tracked,
    1048             :   // so this is also used to determine which errors can cause version fallback
    1049           0 :   switch (err) {
    1050           0 :     case SSL_ERROR_BAD_MAC_ALERT: return 1;
    1051           0 :     case SSL_ERROR_BAD_MAC_READ: return 2;
    1052           0 :     case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: return 3;
    1053           0 :     case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: return 4;
    1054           0 :     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: return 6;
    1055           0 :     case SSL_ERROR_NO_CYPHER_OVERLAP: return 7;
    1056           0 :     case SSL_ERROR_UNSUPPORTED_VERSION: return 10;
    1057           0 :     case SSL_ERROR_PROTOCOL_VERSION_ALERT: return 11;
    1058           0 :     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: return 13;
    1059           0 :     case SSL_ERROR_DECODE_ERROR_ALERT: return 14;
    1060           0 :     case PR_CONNECT_RESET_ERROR: return 16;
    1061           0 :     case PR_END_OF_FILE_ERROR: return 17;
    1062           0 :     case SSL_ERROR_INTERNAL_ERROR_ALERT: return 18;
    1063           0 :     default: return 0;
    1064             :   }
    1065             : }
    1066             : 
    1067             : bool
    1068           0 : retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
    1069             : {
    1070             :   // This function is supposed to decide which error codes should
    1071             :   // be used to conclude server is TLS intolerant.
    1072             :   // Note this only happens during the initial SSL handshake.
    1073             : 
    1074           0 :   SSLVersionRange range = socketInfo->GetTLSVersionRange();
    1075           0 :   nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
    1076             : 
    1077           0 :   if (err == SSL_ERROR_UNSUPPORTED_VERSION &&
    1078           0 :       range.min == SSL_LIBRARY_VERSION_TLS_1_0) {
    1079           0 :     socketInfo->SetSecurityState(nsIWebProgressListener::STATE_IS_INSECURE |
    1080           0 :                                  nsIWebProgressListener::STATE_USES_SSL_3);
    1081             :   }
    1082             : 
    1083             :   // NSS will return SSL_ERROR_RX_MALFORMED_SERVER_HELLO if anti-downgrade
    1084             :   // detected the downgrade.
    1085           0 :   if (err == SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT ||
    1086             :       err == SSL_ERROR_RX_MALFORMED_SERVER_HELLO) {
    1087             :     // This is a clear signal that we've fallen back too many versions.  Treat
    1088             :     // this as a hard failure, but forget any intolerance so that later attempts
    1089             :     // don't use this version (i.e., range.max) and trigger the error again.
    1090             : 
    1091             :     // First, track the original cause of the version fallback.  This uses the
    1092             :     // same buckets as the telemetry below, except that bucket 0 will include
    1093             :     // all cases where there wasn't an original reason.
    1094             :     PRErrorCode originalReason =
    1095           0 :       helpers.getIntoleranceReason(socketInfo->GetHostName(),
    1096           0 :                                    socketInfo->GetPort());
    1097           0 :     Telemetry::Accumulate(Telemetry::SSL_VERSION_FALLBACK_INAPPROPRIATE,
    1098           0 :                           tlsIntoleranceTelemetryBucket(originalReason));
    1099             : 
    1100           0 :     helpers.forgetIntolerance(socketInfo->GetHostName(),
    1101           0 :                               socketInfo->GetPort());
    1102             : 
    1103           0 :     return false;
    1104             :   }
    1105             : 
    1106             :   // When not using a proxy we'll see a connection reset error.
    1107             :   // When using a proxy, we'll see an end of file error.
    1108             : 
    1109             :   // Don't allow STARTTLS connections to fall back on connection resets or
    1110             :   // EOF.
    1111           0 :   if ((err == PR_CONNECT_RESET_ERROR || err == PR_END_OF_FILE_ERROR)
    1112           0 :       && socketInfo->GetForSTARTTLS()) {
    1113           0 :     return false;
    1114             :   }
    1115             : 
    1116           0 :   uint32_t reason = tlsIntoleranceTelemetryBucket(err);
    1117           0 :   if (reason == 0) {
    1118           0 :     return false;
    1119             :   }
    1120             : 
    1121             :   Telemetry::HistogramID pre;
    1122             :   Telemetry::HistogramID post;
    1123           0 :   switch (range.max) {
    1124             :     case SSL_LIBRARY_VERSION_TLS_1_3:
    1125           0 :       pre = Telemetry::SSL_TLS13_INTOLERANCE_REASON_PRE;
    1126           0 :       post = Telemetry::SSL_TLS13_INTOLERANCE_REASON_POST;
    1127           0 :       break;
    1128             :     case SSL_LIBRARY_VERSION_TLS_1_2:
    1129           0 :       pre = Telemetry::SSL_TLS12_INTOLERANCE_REASON_PRE;
    1130           0 :       post = Telemetry::SSL_TLS12_INTOLERANCE_REASON_POST;
    1131           0 :       break;
    1132             :     case SSL_LIBRARY_VERSION_TLS_1_1:
    1133           0 :       pre = Telemetry::SSL_TLS11_INTOLERANCE_REASON_PRE;
    1134           0 :       post = Telemetry::SSL_TLS11_INTOLERANCE_REASON_POST;
    1135           0 :       break;
    1136             :     case SSL_LIBRARY_VERSION_TLS_1_0:
    1137           0 :       pre = Telemetry::SSL_TLS10_INTOLERANCE_REASON_PRE;
    1138           0 :       post = Telemetry::SSL_TLS10_INTOLERANCE_REASON_POST;
    1139           0 :       break;
    1140             :     default:
    1141           0 :       MOZ_CRASH("impossible TLS version");
    1142             :       return false;
    1143             :   }
    1144             : 
    1145             :   // The difference between _PRE and _POST represents how often we avoided
    1146             :   // TLS intolerance fallback due to remembered tolerance.
    1147           0 :   Telemetry::Accumulate(pre, reason);
    1148             : 
    1149           0 :   if (!helpers.rememberIntolerantAtVersion(socketInfo->GetHostName(),
    1150           0 :                                            socketInfo->GetPort(),
    1151           0 :                                            range.min, range.max, err)) {
    1152           0 :     return false;
    1153             :   }
    1154             : 
    1155           0 :   Telemetry::Accumulate(post, reason);
    1156             : 
    1157           0 :   return true;
    1158             : }
    1159             : 
    1160             : // Ensure that we haven't added too many errors to fit.
    1161             : static_assert((SSL_ERROR_END_OF_LIST - SSL_ERROR_BASE) <= 256,
    1162             :               "too many SSL errors");
    1163             : static_assert((SEC_ERROR_END_OF_LIST - SEC_ERROR_BASE) <= 256,
    1164             :               "too many SEC errors");
    1165             : static_assert((PR_MAX_ERROR - PR_NSPR_ERROR_BASE) <= 128,
    1166             :               "too many NSPR errors");
    1167             : static_assert((mozilla::pkix::ERROR_BASE - mozilla::pkix::END_OF_LIST) < 31,
    1168             :               "too many moz::pkix errors");
    1169             : 
    1170             : static void
    1171           0 : reportHandshakeResult(int32_t bytesTransferred, bool wasReading, PRErrorCode err)
    1172             : {
    1173             :   uint32_t bucket;
    1174             : 
    1175             :   // A negative bytesTransferred or a 0 read are errors.
    1176           0 :   if (bytesTransferred > 0) {
    1177           0 :     bucket = 0;
    1178           0 :   } else if ((bytesTransferred == 0) && !wasReading) {
    1179             :     // PR_Write() is defined to never return 0, but let's make sure.
    1180             :     // https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/PR_Write.
    1181           0 :     MOZ_ASSERT(false);
    1182             :     bucket = 671;
    1183           0 :   } else if (IS_SSL_ERROR(err)) {
    1184           0 :     bucket = err - SSL_ERROR_BASE;
    1185           0 :     MOZ_ASSERT(bucket > 0);   // SSL_ERROR_EXPORT_ONLY_SERVER isn't used.
    1186           0 :   } else if (IS_SEC_ERROR(err)) {
    1187           0 :     bucket = (err - SEC_ERROR_BASE) + 256;
    1188           0 :   } else if ((err >= PR_NSPR_ERROR_BASE) && (err < PR_MAX_ERROR)) {
    1189           0 :     bucket = (err - PR_NSPR_ERROR_BASE) + 512;
    1190           0 :   } else if ((err >= mozilla::pkix::ERROR_BASE) &&
    1191             :              (err < mozilla::pkix::ERROR_LIMIT)) {
    1192           0 :     bucket = (err - mozilla::pkix::ERROR_BASE) + 640;
    1193             :   } else {
    1194           0 :     bucket = 671;
    1195             :   }
    1196             : 
    1197           0 :   Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT, bucket);
    1198           0 : }
    1199             : 
    1200             : int32_t
    1201           0 : checkHandshake(int32_t bytesTransfered, bool wasReading,
    1202             :                PRFileDesc* ssl_layer_fd, nsNSSSocketInfo* socketInfo)
    1203             : {
    1204           0 :   const PRErrorCode originalError = PR_GetError();
    1205           0 :   PRErrorCode err = originalError;
    1206             : 
    1207             :   // This is where we work around all of those SSL servers that don't
    1208             :   // conform to the SSL spec and shutdown a connection when we request
    1209             :   // SSL v3.1 (aka TLS).  The spec says the client says what version
    1210             :   // of the protocol we're willing to perform, in our case SSL v3.1
    1211             :   // In its response, the server says which version it wants to perform.
    1212             :   // Many servers out there only know how to do v3.0.  Next, we're supposed
    1213             :   // to send back the version of the protocol we requested (ie v3.1).  At
    1214             :   // this point many servers's implementations are broken and they shut
    1215             :   // down the connection when they don't see the version they sent back.
    1216             :   // This is supposed to prevent a man in the middle from forcing one
    1217             :   // side to dumb down to a lower level of the protocol.  Unfortunately,
    1218             :   // there are enough broken servers out there that such a gross work-around
    1219             :   // is necessary.  :(
    1220             : 
    1221             :   // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
    1222             :   // Simply retry.
    1223             :   // This depends on the fact that Cert UI will not be shown again,
    1224             :   // should the user override the bad cert.
    1225             : 
    1226           0 :   bool handleHandshakeResultNow = socketInfo->IsHandshakePending();
    1227             : 
    1228           0 :   bool wantRetry = false;
    1229             : 
    1230           0 :   if (0 > bytesTransfered) {
    1231           0 :     if (handleHandshakeResultNow) {
    1232           0 :       if (PR_WOULD_BLOCK_ERROR == err) {
    1233           0 :         PR_SetError(err, 0);
    1234           0 :         return bytesTransfered;
    1235             :       }
    1236             : 
    1237           0 :       wantRetry = retryDueToTLSIntolerance(err, socketInfo);
    1238             :     }
    1239             : 
    1240             :     // This is the common place where we trigger non-cert-errors on a SSL
    1241             :     // socket. This might be reached at any time of the connection.
    1242             :     //
    1243             :     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
    1244             :     // do the synchronous dispatch to the main thread unnecessarily after we've
    1245             :     // already handled a certificate error. (SSLErrorRunnable calls
    1246             :     // nsHandleSSLError, which has logic to avoid replacing the error message,
    1247             :     // so without the !socketInfo->GetErrorCode(), it would just be an
    1248             :     // expensive no-op.)
    1249           0 :     if (!wantRetry && mozilla::psm::IsNSSErrorCode(err) &&
    1250           0 :         !socketInfo->GetErrorCode()) {
    1251             :       RefPtr<SyncRunnableBase> runnable(
    1252           0 :         new SSLErrorRunnable(socketInfo, SSLErrorMessageType::Plain, err));
    1253           0 :       (void) runnable->DispatchToMainThreadAndWait();
    1254             :     }
    1255           0 :   } else if (wasReading && 0 == bytesTransfered) {
    1256             :     // zero bytes on reading, socket closed
    1257           0 :     if (handleHandshakeResultNow) {
    1258           0 :       wantRetry = retryDueToTLSIntolerance(PR_END_OF_FILE_ERROR, socketInfo);
    1259             :     }
    1260             :   }
    1261             : 
    1262           0 :   if (wantRetry) {
    1263           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1264             :            ("[%p] checkHandshake: will retry with lower max TLS version\n",
    1265             :             ssl_layer_fd));
    1266             :     // We want to cause the network layer to retry the connection.
    1267           0 :     err = PR_CONNECT_RESET_ERROR;
    1268           0 :     if (wasReading)
    1269           0 :       bytesTransfered = -1;
    1270             :   }
    1271             : 
    1272             :   // TLS intolerant servers only cause the first transfer to fail, so let's
    1273             :   // set the HandshakePending attribute to false so that we don't try the logic
    1274             :   // above again in a subsequent transfer.
    1275           0 :   if (handleHandshakeResultNow) {
    1276             :     // Report the result once for each handshake. Note that this does not
    1277             :     // get handshakes which are cancelled before any reads or writes
    1278             :     // happen.
    1279           0 :     reportHandshakeResult(bytesTransfered, wasReading, originalError);
    1280           0 :     socketInfo->SetHandshakeNotPending();
    1281             :   }
    1282             : 
    1283           0 :   if (bytesTransfered < 0) {
    1284             :     // Remember that we encountered an error so that getSocketInfoIfRunning
    1285             :     // will correctly cause us to fail if another part of Gecko
    1286             :     // (erroneously) calls an I/O function (PR_Send/PR_Recv/etc.) again on
    1287             :     // this socket. Note that we use the original error because if we use
    1288             :     // PR_CONNECT_RESET_ERROR, we'll repeated try to reconnect.
    1289           0 :     if (originalError != PR_WOULD_BLOCK_ERROR && !socketInfo->GetErrorCode()) {
    1290           0 :       socketInfo->SetCanceled(originalError, SSLErrorMessageType::Plain);
    1291             :     }
    1292           0 :     PR_SetError(err, 0);
    1293             :   }
    1294             : 
    1295           0 :   return bytesTransfered;
    1296             : }
    1297             : 
    1298             : } // namespace
    1299             : 
    1300             : static int16_t
    1301           0 : nsSSLIOLayerPoll(PRFileDesc* fd, int16_t in_flags, int16_t* out_flags)
    1302             : {
    1303           0 :   nsNSSShutDownPreventionLock locker;
    1304             : 
    1305           0 :   if (!out_flags) {
    1306           0 :     NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
    1307           0 :     return 0;
    1308             :   }
    1309             : 
    1310           0 :   *out_flags = 0;
    1311             : 
    1312             :   nsNSSSocketInfo* socketInfo =
    1313           0 :     getSocketInfoIfRunning(fd, not_reading_or_writing, locker);
    1314             : 
    1315           0 :   if (!socketInfo) {
    1316             :     // If we get here, it is probably because certificate validation failed
    1317             :     // and this is the first I/O operation after the failure.
    1318           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    1319             :             ("[%p] polling SSL socket right after certificate verification failed "
    1320             :                   "or NSS shutdown or SDR logout %d\n",
    1321             :              fd, (int) in_flags));
    1322             : 
    1323           0 :     MOZ_ASSERT(in_flags & PR_POLL_EXCEPT,
    1324             :                "Caller did not poll for EXCEPT (canceled)");
    1325             :     // Since this poll method cannot return errors, we want the caller to call
    1326             :     // PR_Send/PR_Recv right away to get the error, so we tell that we are
    1327             :     // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
    1328           0 :     *out_flags = in_flags | PR_POLL_EXCEPT; // see also bug 480619
    1329           0 :     return in_flags;
    1330             :   }
    1331             : 
    1332           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    1333             :           (socketInfo->IsWaitingForCertVerification()
    1334             :              ?  "[%p] polling SSL socket during certificate verification using lower %d\n"
    1335             :              :  "[%p] poll SSL socket using lower %d\n",
    1336             :            fd, (int) in_flags));
    1337             : 
    1338             :   // We want the handshake to continue during certificate validation, so we
    1339             :   // don't need to do anything special here. libssl automatically blocks when
    1340             :   // it reaches any point that would be unsafe to send/receive something before
    1341             :   // cert validation is complete.
    1342           0 :   int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
    1343           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    1344             :           ("[%p] poll SSL socket returned %d\n", (void*) fd, (int) result));
    1345           0 :   return result;
    1346             : }
    1347             : 
    1348           2 : nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
    1349             :   : mTreatUnsafeNegotiationAsBroken(false)
    1350             :   , mTLSIntoleranceInfo()
    1351             :   , mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0)
    1352           2 :   , mutex("nsSSLIOLayerHelpers.mutex")
    1353             : {
    1354           2 : }
    1355             : 
    1356             : static int
    1357           0 : _PSM_InvalidInt(void)
    1358             : {
    1359           0 :   MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
    1360             :   PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    1361             :   return -1;
    1362             : }
    1363             : 
    1364             : static int64_t
    1365           0 : _PSM_InvalidInt64(void)
    1366             : {
    1367           0 :   MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
    1368             :   PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    1369             :   return -1;
    1370             : }
    1371             : 
    1372             : static PRStatus
    1373           0 : _PSM_InvalidStatus(void)
    1374             : {
    1375           0 :   MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
    1376             :   PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    1377             :   return PR_FAILURE;
    1378             : }
    1379             : 
    1380             : static PRFileDesc*
    1381           0 : _PSM_InvalidDesc(void)
    1382             : {
    1383           0 :   MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
    1384             :   PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    1385             :   return nullptr;
    1386             : }
    1387             : 
    1388             : static PRStatus
    1389           0 : PSMGetsockname(PRFileDesc* fd, PRNetAddr* addr)
    1390             : {
    1391           0 :   nsNSSShutDownPreventionLock locker;
    1392           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    1393           0 :     return PR_FAILURE;
    1394             : 
    1395           0 :   return fd->lower->methods->getsockname(fd->lower, addr);
    1396             : }
    1397             : 
    1398             : static PRStatus
    1399           0 : PSMGetpeername(PRFileDesc* fd, PRNetAddr* addr)
    1400             : {
    1401           0 :   nsNSSShutDownPreventionLock locker;
    1402           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    1403           0 :     return PR_FAILURE;
    1404             : 
    1405           0 :   return fd->lower->methods->getpeername(fd->lower, addr);
    1406             : }
    1407             : 
    1408             : static PRStatus
    1409           0 : PSMGetsocketoption(PRFileDesc* fd, PRSocketOptionData* data)
    1410             : {
    1411           0 :   nsNSSShutDownPreventionLock locker;
    1412           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    1413           0 :     return PR_FAILURE;
    1414             : 
    1415           0 :   return fd->lower->methods->getsocketoption(fd, data);
    1416             : }
    1417             : 
    1418             : static PRStatus
    1419           0 : PSMSetsocketoption(PRFileDesc* fd, const PRSocketOptionData* data)
    1420             : {
    1421           0 :   nsNSSShutDownPreventionLock locker;
    1422           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    1423           0 :     return PR_FAILURE;
    1424             : 
    1425           0 :   return fd->lower->methods->setsocketoption(fd, data);
    1426             : }
    1427             : 
    1428             : static int32_t
    1429           0 : PSMRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
    1430             :         PRIntervalTime timeout)
    1431             : {
    1432           0 :   nsNSSShutDownPreventionLock locker;
    1433           0 :   nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, reading, locker);
    1434           0 :   if (!socketInfo)
    1435           0 :     return -1;
    1436             : 
    1437           0 :   if (flags != PR_MSG_PEEK && flags != 0) {
    1438           0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1439           0 :     return -1;
    1440             :   }
    1441             : 
    1442           0 :   int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
    1443           0 :                                                timeout);
    1444             : 
    1445           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    1446             :           ("[%p] read %d bytes\n", (void*) fd, bytesRead));
    1447             : 
    1448             : #ifdef DEBUG_SSL_VERBOSE
    1449             :   DEBUG_DUMP_BUFFER((unsigned char*) buf, bytesRead);
    1450             : #endif
    1451             : 
    1452           0 :   return checkHandshake(bytesRead, true, fd, socketInfo);
    1453             : }
    1454             : 
    1455             : static int32_t
    1456           0 : PSMSend(PRFileDesc* fd, const void* buf, int32_t amount, int flags,
    1457             :         PRIntervalTime timeout)
    1458             : {
    1459           0 :   nsNSSShutDownPreventionLock locker;
    1460           0 :   nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, writing, locker);
    1461           0 :   if (!socketInfo)
    1462           0 :     return -1;
    1463             : 
    1464           0 :   if (flags != 0) {
    1465           0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1466           0 :     return -1;
    1467             :   }
    1468             : 
    1469             : #ifdef DEBUG_SSL_VERBOSE
    1470             :   DEBUG_DUMP_BUFFER((unsigned char*) buf, amount);
    1471             : #endif
    1472             : 
    1473           0 :   int32_t bytesWritten = fd->lower->methods->send(fd->lower, buf, amount,
    1474           0 :                                                   flags, timeout);
    1475             : 
    1476           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
    1477             :           ("[%p] wrote %d bytes\n", fd, bytesWritten));
    1478             : 
    1479           0 :   return checkHandshake(bytesWritten, false, fd, socketInfo);
    1480             : }
    1481             : 
    1482             : static PRStatus
    1483           0 : PSMBind(PRFileDesc* fd, const PRNetAddr *addr)
    1484             : {
    1485           0 :   nsNSSShutDownPreventionLock locker;
    1486           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    1487           0 :     return PR_FAILURE;
    1488             : 
    1489           0 :   return fd->lower->methods->bind(fd->lower, addr);
    1490             : }
    1491             : 
    1492             : static int32_t
    1493           0 : nsSSLIOLayerRead(PRFileDesc* fd, void* buf, int32_t amount)
    1494             : {
    1495           0 :   return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    1496             : }
    1497             : 
    1498             : static int32_t
    1499           0 : nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, int32_t amount)
    1500             : {
    1501           0 :   return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    1502             : }
    1503             : 
    1504             : static PRStatus
    1505           0 : PSMConnectcontinue(PRFileDesc* fd, int16_t out_flags)
    1506             : {
    1507           0 :   nsNSSShutDownPreventionLock locker;
    1508           0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker)) {
    1509           0 :     return PR_FAILURE;
    1510             :   }
    1511             : 
    1512           0 :   return fd->lower->methods->connectcontinue(fd, out_flags);
    1513             : }
    1514             : 
    1515             : static int
    1516           0 : PSMAvailable(void)
    1517             : {
    1518             :   // This is called through PR_Available(), but is not implemented in PSM
    1519           0 :   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    1520           0 :   return -1;
    1521             : }
    1522             : 
    1523             : static int64_t
    1524           0 : PSMAvailable64(void)
    1525             : {
    1526             :   // This is called through PR_Available(), but is not implemented in PSM
    1527           0 :   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    1528           0 :   return -1;
    1529             : }
    1530             : 
    1531             : namespace {
    1532             : 
    1533             : class PrefObserver : public nsIObserver {
    1534             : public:
    1535             :   NS_DECL_THREADSAFE_ISUPPORTS
    1536             :   NS_DECL_NSIOBSERVER
    1537           2 :   explicit PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
    1538             : 
    1539             : protected:
    1540           0 :   virtual ~PrefObserver() {}
    1541             : private:
    1542             :   nsSSLIOLayerHelpers* mOwner;
    1543             : };
    1544             : 
    1545             : } // unnamed namespace
    1546             : 
    1547          56 : NS_IMPL_ISUPPORTS(PrefObserver, nsIObserver)
    1548             : 
    1549             : NS_IMETHODIMP
    1550           0 : PrefObserver::Observe(nsISupports* aSubject, const char* aTopic,
    1551             :                       const char16_t* someData)
    1552             : {
    1553           0 :   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
    1554           0 :     NS_ConvertUTF16toUTF8 prefName(someData);
    1555             : 
    1556           0 :     if (prefName.EqualsLiteral("security.ssl.treat_unsafe_negotiation_as_broken")) {
    1557             :       bool enabled;
    1558           0 :       Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
    1559           0 :       mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
    1560           0 :     } else if (prefName.EqualsLiteral("security.tls.version.fallback-limit")) {
    1561           0 :       mOwner->loadVersionFallbackLimit();
    1562           0 :     } else if (prefName.EqualsLiteral("security.tls.insecure_fallback_hosts")) {
    1563             :       // Changes to the whitelist on the public side will update the pref.
    1564             :       // Don't propagate the changes to the private side.
    1565           0 :       if (mOwner->isPublic()) {
    1566           0 :         mOwner->initInsecureFallbackSites();
    1567             :       }
    1568             :     }
    1569             :   }
    1570           0 :   return NS_OK;
    1571             : }
    1572             : 
    1573             : static int32_t
    1574           0 : PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
    1575             :               PRIntervalTime timeout)
    1576             : {
    1577             :   // The shutdownlocker is not needed here because it will already be
    1578             :   // held higher in the stack
    1579           0 :   nsNSSSocketInfo* socketInfo = nullptr;
    1580             : 
    1581           0 :   int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
    1582           0 :                                                timeout);
    1583           0 :   if (fd->identity == nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)
    1584           0 :     socketInfo = (nsNSSSocketInfo*) fd->secret;
    1585             : 
    1586           0 :   if ((bytesRead > 0) && socketInfo)
    1587           0 :     socketInfo->AddPlaintextBytesRead(bytesRead);
    1588           0 :   return bytesRead;
    1589             : }
    1590             : 
    1591           0 : nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
    1592             : {
    1593             :   // mPrefObserver will only be set if this->Init was called. The GTest tests
    1594             :   // do not call Init.
    1595           0 :   if (mPrefObserver) {
    1596           0 :     Preferences::RemoveObserver(mPrefObserver,
    1597           0 :         "security.ssl.treat_unsafe_negotiation_as_broken");
    1598           0 :     Preferences::RemoveObserver(mPrefObserver,
    1599           0 :         "security.tls.version.fallback-limit");
    1600           0 :     Preferences::RemoveObserver(mPrefObserver,
    1601           0 :         "security.tls.insecure_fallback_hosts");
    1602             :   }
    1603           0 : }
    1604             : 
    1605             : nsresult
    1606           2 : nsSSLIOLayerHelpers::Init()
    1607             : {
    1608           2 :   if (!nsSSLIOLayerInitialized) {
    1609           1 :     nsSSLIOLayerInitialized = true;
    1610           1 :     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
    1611           1 :     nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
    1612             : 
    1613           1 :     nsSSLIOLayerMethods.available = (PRAvailableFN) PSMAvailable;
    1614           1 :     nsSSLIOLayerMethods.available64 = (PRAvailable64FN) PSMAvailable64;
    1615           1 :     nsSSLIOLayerMethods.fsync = (PRFsyncFN) _PSM_InvalidStatus;
    1616           1 :     nsSSLIOLayerMethods.seek = (PRSeekFN) _PSM_InvalidInt;
    1617           1 :     nsSSLIOLayerMethods.seek64 = (PRSeek64FN) _PSM_InvalidInt64;
    1618           1 :     nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN) _PSM_InvalidStatus;
    1619           1 :     nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN) _PSM_InvalidStatus;
    1620           1 :     nsSSLIOLayerMethods.writev = (PRWritevFN) _PSM_InvalidInt;
    1621           1 :     nsSSLIOLayerMethods.accept = (PRAcceptFN) _PSM_InvalidDesc;
    1622           1 :     nsSSLIOLayerMethods.listen = (PRListenFN) _PSM_InvalidStatus;
    1623           1 :     nsSSLIOLayerMethods.shutdown = (PRShutdownFN) _PSM_InvalidStatus;
    1624           1 :     nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN) _PSM_InvalidInt;
    1625           1 :     nsSSLIOLayerMethods.sendto = (PRSendtoFN) _PSM_InvalidInt;
    1626           1 :     nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN) _PSM_InvalidInt;
    1627           1 :     nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN) _PSM_InvalidInt;
    1628           1 :     nsSSLIOLayerMethods.sendfile = (PRSendfileFN) _PSM_InvalidInt;
    1629             : 
    1630           1 :     nsSSLIOLayerMethods.getsockname = PSMGetsockname;
    1631           1 :     nsSSLIOLayerMethods.getpeername = PSMGetpeername;
    1632           1 :     nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
    1633           1 :     nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
    1634           1 :     nsSSLIOLayerMethods.recv = PSMRecv;
    1635           1 :     nsSSLIOLayerMethods.send = PSMSend;
    1636           1 :     nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
    1637           1 :     nsSSLIOLayerMethods.bind = PSMBind;
    1638             : 
    1639           1 :     nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
    1640           1 :     nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
    1641           1 :     nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
    1642           1 :     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
    1643           1 :     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
    1644             : 
    1645           1 :     nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
    1646           1 :     nsSSLPlaintextLayerMethods  = *PR_GetDefaultIOMethods();
    1647           1 :     nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
    1648             :   }
    1649             : 
    1650           2 :   bool enabled = false;
    1651           2 :   Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
    1652           2 :   setTreatUnsafeNegotiationAsBroken(enabled);
    1653             : 
    1654           2 :   loadVersionFallbackLimit();
    1655           2 :   initInsecureFallbackSites();
    1656             : 
    1657           2 :   mPrefObserver = new PrefObserver(this);
    1658           2 :   Preferences::AddStrongObserver(mPrefObserver,
    1659           2 :                                  "security.ssl.treat_unsafe_negotiation_as_broken");
    1660           2 :   Preferences::AddStrongObserver(mPrefObserver,
    1661           2 :                                  "security.tls.version.fallback-limit");
    1662           2 :   Preferences::AddStrongObserver(mPrefObserver,
    1663           2 :                                  "security.tls.insecure_fallback_hosts");
    1664           2 :   return NS_OK;
    1665             : }
    1666             : 
    1667             : void
    1668           2 : nsSSLIOLayerHelpers::loadVersionFallbackLimit()
    1669             : {
    1670             :   // see nsNSSComponent::setEnabledTLSVersions for pref handling rules
    1671             :   uint32_t limit = Preferences::GetUint("security.tls.version.fallback-limit",
    1672           2 :                                         3); // 3 = TLS 1.2
    1673             :   SSLVersionRange defaults = { SSL_LIBRARY_VERSION_TLS_1_2,
    1674           2 :                                SSL_LIBRARY_VERSION_TLS_1_2 };
    1675             :   SSLVersionRange filledInRange;
    1676           2 :   nsNSSComponent::FillTLSVersionRange(filledInRange, limit, limit, defaults);
    1677           2 :   if (filledInRange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
    1678           0 :     filledInRange.max = SSL_LIBRARY_VERSION_TLS_1_2;
    1679             :   }
    1680             : 
    1681           2 :   mVersionFallbackLimit = filledInRange.max;
    1682           2 : }
    1683             : 
    1684             : void
    1685           0 : nsSSLIOLayerHelpers::clearStoredData()
    1686             : {
    1687           0 :   MutexAutoLock lock(mutex);
    1688           0 :   mInsecureFallbackSites.Clear();
    1689           0 :   mTLSIntoleranceInfo.Clear();
    1690           0 : }
    1691             : 
    1692             : void
    1693           2 : nsSSLIOLayerHelpers::setInsecureFallbackSites(const nsCString& str)
    1694             : {
    1695           2 :   MutexAutoLock lock(mutex);
    1696             : 
    1697           2 :   mInsecureFallbackSites.Clear();
    1698             : 
    1699           2 :   if (str.IsEmpty()) {
    1700           2 :     return;
    1701             :   }
    1702             : 
    1703           0 :   nsCCharSeparatedTokenizer toker(str, ',');
    1704             : 
    1705           0 :   while (toker.hasMoreTokens()) {
    1706           0 :     const nsACString& host = toker.nextToken();
    1707           0 :     if (!host.IsEmpty()) {
    1708           0 :       mInsecureFallbackSites.PutEntry(host);
    1709             :     }
    1710             :   }
    1711             : }
    1712             : 
    1713             : void
    1714           2 : nsSSLIOLayerHelpers::initInsecureFallbackSites()
    1715             : {
    1716           2 :   MOZ_ASSERT(NS_IsMainThread());
    1717           4 :   nsCString insecureFallbackHosts;
    1718             :   Preferences::GetCString("security.tls.insecure_fallback_hosts",
    1719           2 :                           &insecureFallbackHosts);
    1720           2 :   setInsecureFallbackSites(insecureFallbackHosts);
    1721           2 : }
    1722             : 
    1723             : bool
    1724           0 : nsSSLIOLayerHelpers::isPublic() const
    1725             : {
    1726           0 :   return this == &PublicSSLState()->IOLayerHelpers();
    1727             : }
    1728             : 
    1729           0 : class FallbackPrefRemover final : public Runnable
    1730             : {
    1731             : public:
    1732           0 :   explicit FallbackPrefRemover(const nsACString& aHost)
    1733           0 :     : mozilla::Runnable("FallbackPrefRemover")
    1734           0 :     , mHost(aHost)
    1735           0 :   {}
    1736             :   NS_IMETHOD Run() override;
    1737             : private:
    1738             :   nsCString mHost;
    1739             : };
    1740             : 
    1741             : NS_IMETHODIMP
    1742           0 : FallbackPrefRemover::Run()
    1743             : {
    1744           0 :   MOZ_ASSERT(NS_IsMainThread());
    1745           0 :   nsCString oldValue;
    1746           0 :   Preferences::GetCString("security.tls.insecure_fallback_hosts", &oldValue);
    1747           0 :   nsCCharSeparatedTokenizer toker(oldValue, ',');
    1748           0 :   nsCString newValue;
    1749           0 :   while (toker.hasMoreTokens()) {
    1750           0 :     const nsACString& host = toker.nextToken();
    1751           0 :     if (host.Equals(mHost)) {
    1752           0 :       continue;
    1753             :     }
    1754           0 :     if (!newValue.IsEmpty()) {
    1755           0 :       newValue.Append(',');
    1756             :     }
    1757           0 :     newValue.Append(host);
    1758             :   }
    1759           0 :   Preferences::SetCString("security.tls.insecure_fallback_hosts", newValue);
    1760           0 :   return NS_OK;
    1761             : }
    1762             : 
    1763             : void
    1764           0 : nsSSLIOLayerHelpers::removeInsecureFallbackSite(const nsACString& hostname,
    1765             :                                                 uint16_t port)
    1766             : {
    1767           0 :   forgetIntolerance(hostname, port);
    1768             :   {
    1769           0 :     MutexAutoLock lock(mutex);
    1770           0 :     if (!mInsecureFallbackSites.Contains(hostname)) {
    1771           0 :       return;
    1772             :     }
    1773           0 :     mInsecureFallbackSites.RemoveEntry(hostname);
    1774             :   }
    1775           0 :   if (!isPublic()) {
    1776           0 :     return;
    1777             :   }
    1778           0 :   RefPtr<Runnable> runnable = new FallbackPrefRemover(hostname);
    1779           0 :   if (NS_IsMainThread()) {
    1780           0 :     runnable->Run();
    1781             :   } else {
    1782           0 :     NS_DispatchToMainThread(runnable);
    1783             :   }
    1784             : }
    1785             : 
    1786             : bool
    1787           0 : nsSSLIOLayerHelpers::isInsecureFallbackSite(const nsACString& hostname)
    1788             : {
    1789           0 :   MutexAutoLock lock(mutex);
    1790           0 :   return mInsecureFallbackSites.Contains(hostname);
    1791             : }
    1792             : 
    1793             : void
    1794           2 : nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
    1795             : {
    1796           4 :   MutexAutoLock lock(mutex);
    1797           2 :   mTreatUnsafeNegotiationAsBroken = broken;
    1798           2 : }
    1799             : 
    1800             : bool
    1801           0 : nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
    1802             : {
    1803           0 :   MutexAutoLock lock(mutex);
    1804           0 :   return mTreatUnsafeNegotiationAsBroken;
    1805             : }
    1806             : 
    1807             : nsresult
    1808           0 : nsSSLIOLayerNewSocket(int32_t family,
    1809             :                       const char* host,
    1810             :                       int32_t port,
    1811             :                       nsIProxyInfo *proxy,
    1812             :                       const OriginAttributes& originAttributes,
    1813             :                       PRFileDesc** fd,
    1814             :                       nsISupports** info,
    1815             :                       bool forSTARTTLS,
    1816             :                       uint32_t flags)
    1817             : {
    1818             : 
    1819           0 :   PRFileDesc* sock = PR_OpenTCPSocket(family);
    1820           0 :   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
    1821             : 
    1822           0 :   nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxy,
    1823             :                                         originAttributes, sock, info,
    1824           0 :                                         forSTARTTLS, flags);
    1825           0 :   if (NS_FAILED(rv)) {
    1826           0 :     PR_Close(sock);
    1827           0 :     return rv;
    1828             :   }
    1829             : 
    1830           0 :   *fd = sock;
    1831           0 :   return NS_OK;
    1832             : }
    1833             : 
    1834             : // Creates CA names strings from (CERTDistNames* caNames)
    1835             : //
    1836             : // - arena: arena to allocate strings on
    1837             : // - caNameStrings: filled with CA names strings on return
    1838             : // - caNames: CERTDistNames to extract strings from
    1839             : // - return: SECSuccess if successful; error code otherwise
    1840             : //
    1841             : // Note: copied in its entirety from Nova code
    1842             : static SECStatus
    1843           0 : nsConvertCANamesToStrings(const UniquePLArenaPool& arena, char** caNameStrings,
    1844             :                           CERTDistNames* caNames)
    1845             : {
    1846           0 :     MOZ_ASSERT(arena.get());
    1847           0 :     MOZ_ASSERT(caNameStrings);
    1848           0 :     MOZ_ASSERT(caNames);
    1849           0 :     if (!arena.get() || !caNameStrings || !caNames) {
    1850           0 :         PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    1851           0 :         return SECFailure;
    1852             :     }
    1853             : 
    1854             :     SECItem* dername;
    1855             :     SECStatus rv;
    1856             :     int headerlen;
    1857             :     uint32_t contentlen;
    1858             :     SECItem newitem;
    1859             :     int n;
    1860             :     char* namestring;
    1861             : 
    1862           0 :     for (n = 0; n < caNames->nnames; n++) {
    1863           0 :         newitem.data = nullptr;
    1864           0 :         dername = &caNames->names[n];
    1865             : 
    1866           0 :         rv = DER_Lengths(dername, &headerlen, &contentlen);
    1867             : 
    1868           0 :         if (rv != SECSuccess) {
    1869           0 :             goto loser;
    1870             :         }
    1871             : 
    1872           0 :         if (headerlen + contentlen != dername->len) {
    1873             :             // This must be from an enterprise 2.x server, which sent
    1874             :             // incorrectly formatted der without the outer wrapper of type and
    1875             :             // length. Fix it up by adding the top level header.
    1876           0 :             if (dername->len <= 127) {
    1877           0 :                 newitem.data = (unsigned char*) malloc(dername->len + 2);
    1878           0 :                 if (!newitem.data) {
    1879           0 :                     goto loser;
    1880             :                 }
    1881           0 :                 newitem.data[0] = (unsigned char) 0x30;
    1882           0 :                 newitem.data[1] = (unsigned char) dername->len;
    1883           0 :                 (void) memcpy(&newitem.data[2], dername->data, dername->len);
    1884           0 :             } else if (dername->len <= 255) {
    1885           0 :                 newitem.data = (unsigned char*) malloc(dername->len + 3);
    1886           0 :                 if (!newitem.data) {
    1887           0 :                     goto loser;
    1888             :                 }
    1889           0 :                 newitem.data[0] = (unsigned char) 0x30;
    1890           0 :                 newitem.data[1] = (unsigned char) 0x81;
    1891           0 :                 newitem.data[2] = (unsigned char) dername->len;
    1892           0 :                 (void) memcpy(&newitem.data[3], dername->data, dername->len);
    1893             :             } else {
    1894             :                 // greater than 256, better be less than 64k
    1895           0 :                 newitem.data = (unsigned char*) malloc(dername->len + 4);
    1896           0 :                 if (!newitem.data) {
    1897           0 :                     goto loser;
    1898             :                 }
    1899           0 :                 newitem.data[0] = (unsigned char) 0x30;
    1900           0 :                 newitem.data[1] = (unsigned char) 0x82;
    1901           0 :                 newitem.data[2] = (unsigned char) ((dername->len >> 8) & 0xff);
    1902           0 :                 newitem.data[3] = (unsigned char) (dername->len & 0xff);
    1903           0 :                 memcpy(&newitem.data[4], dername->data, dername->len);
    1904             :             }
    1905           0 :             dername = &newitem;
    1906             :         }
    1907             : 
    1908           0 :         namestring = CERT_DerNameToAscii(dername);
    1909           0 :         if (!namestring) {
    1910             :             // XXX - keep going until we fail to convert the name
    1911           0 :             caNameStrings[n] = const_cast<char*>("");
    1912             :         } else {
    1913           0 :             caNameStrings[n] = PORT_ArenaStrdup(arena.get(), namestring);
    1914           0 :             PR_Free(namestring); // CERT_DerNameToAscii() uses PR_Malloc().
    1915           0 :             if (!caNameStrings[n]) {
    1916           0 :                 goto loser;
    1917             :             }
    1918             :         }
    1919             : 
    1920           0 :         if (newitem.data) {
    1921           0 :             free(newitem.data);
    1922             :         }
    1923             :     }
    1924             : 
    1925           0 :     return SECSuccess;
    1926             : loser:
    1927           0 :     if (newitem.data) {
    1928           0 :         free(newitem.data);
    1929             :     }
    1930           0 :     return SECFailure;
    1931             : }
    1932             : 
    1933             : // Possible behaviors for choosing a cert for client auth.
    1934             : enum class UserCertChoice {
    1935             :   // Ask the user to choose a cert.
    1936             :   Ask = 0,
    1937             :   // Automatically choose a cert.
    1938             :   Auto = 1,
    1939             : };
    1940             : 
    1941             : // Returns the most appropriate user cert choice based on the value of the
    1942             : // security.default_personal_cert preference.
    1943             : UserCertChoice
    1944           0 : nsGetUserCertChoice()
    1945             : {
    1946           0 :   nsAutoCString value;
    1947           0 :   nsresult rv = Preferences::GetCString("security.default_personal_cert", &value);
    1948           0 :   if (NS_FAILED(rv)) {
    1949           0 :     return UserCertChoice::Ask;
    1950             :   }
    1951             : 
    1952             :   // There are three cases for what the preference could be set to:
    1953             :   //   1. "Select Automatically" -> Auto.
    1954             :   //   2. "Ask Every Time" -> Ask.
    1955             :   //   3. Something else -> Ask. This might be a nickname from a migrated cert,
    1956             :   //      but we no longer support this case.
    1957           0 :   return value.EqualsLiteral("Select Automatically") ? UserCertChoice::Auto
    1958           0 :                                                      : UserCertChoice::Ask;
    1959             : }
    1960             : 
    1961             : static bool
    1962           0 : hasExplicitKeyUsageNonRepudiation(CERTCertificate* cert)
    1963             : {
    1964             :   // There is no extension, v1 or v2 certificate
    1965           0 :   if (!cert->extensions)
    1966           0 :     return false;
    1967             : 
    1968             :   SECStatus srv;
    1969             :   SECItem keyUsageItem;
    1970           0 :   keyUsageItem.data = nullptr;
    1971             : 
    1972           0 :   srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
    1973           0 :   if (srv == SECFailure)
    1974           0 :     return false;
    1975             : 
    1976           0 :   unsigned char keyUsage = keyUsageItem.data[0];
    1977           0 :   PORT_Free (keyUsageItem.data);
    1978             : 
    1979           0 :   return !!(keyUsage & KU_NON_REPUDIATION);
    1980             : }
    1981             : 
    1982           0 : class ClientAuthDataRunnable : public SyncRunnableBase
    1983             : {
    1984             : public:
    1985           0 :   ClientAuthDataRunnable(CERTDistNames* caNames,
    1986             :                          CERTCertificate** pRetCert,
    1987             :                          SECKEYPrivateKey** pRetKey,
    1988             :                          nsNSSSocketInfo* info,
    1989             :                          const UniqueCERTCertificate& serverCert)
    1990           0 :     : mRV(SECFailure)
    1991             :     , mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
    1992             :     , mPRetCert(pRetCert)
    1993             :     , mPRetKey(pRetKey)
    1994             :     , mCANames(caNames)
    1995             :     , mSocketInfo(info)
    1996           0 :     , mServerCert(serverCert.get())
    1997             :   {
    1998           0 :   }
    1999             : 
    2000             :   SECStatus mRV;                        // out
    2001             :   PRErrorCode mErrorCodeToReport;       // out
    2002             :   CERTCertificate** const mPRetCert;    // in/out
    2003             :   SECKEYPrivateKey** const mPRetKey;    // in/out
    2004             : protected:
    2005             :   virtual void RunOnTargetThread();
    2006             : private:
    2007             :   CERTDistNames* const mCANames;        // in
    2008             :   nsNSSSocketInfo* const mSocketInfo;   // in
    2009             :   CERTCertificate* const mServerCert;   // in
    2010             : };
    2011             : 
    2012             : // This callback function is used to pull client certificate
    2013             : // information upon server request
    2014             : //
    2015             : // - arg: SSL data connection
    2016             : // - socket: SSL socket we're dealing with
    2017             : // - caNames: list of CA names
    2018             : // - pRetCert: returns a pointer to a pointer to a valid certificate if
    2019             : //             successful; otherwise nullptr
    2020             : // - pRetKey: returns a pointer to a pointer to the corresponding key if
    2021             : //            successful; otherwise nullptr
    2022             : SECStatus
    2023           0 : nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
    2024             :                            CERTDistNames* caNames, CERTCertificate** pRetCert,
    2025             :                            SECKEYPrivateKey** pRetKey)
    2026             : {
    2027           0 :   nsNSSShutDownPreventionLock locker;
    2028             : 
    2029           0 :   if (!socket || !caNames || !pRetCert || !pRetKey) {
    2030           0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    2031           0 :     return SECFailure;
    2032             :   }
    2033             : 
    2034             :   RefPtr<nsNSSSocketInfo> info(
    2035           0 :     BitwiseCast<nsNSSSocketInfo*, PRFilePrivate*>(socket->higher->secret));
    2036             : 
    2037           0 :   UniqueCERTCertificate serverCert(SSL_PeerCertificate(socket));
    2038           0 :   if (!serverCert) {
    2039           0 :     MOZ_ASSERT_UNREACHABLE(
    2040             :       "Missing server cert should have been detected during server cert auth.");
    2041             :     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
    2042             :     return SECFailure;
    2043             :   }
    2044             : 
    2045           0 :   if (info->GetJoined()) {
    2046             :     // We refuse to send a client certificate when there are multiple hostnames
    2047             :     // joined on this connection, because we only show the user one hostname
    2048             :     // (mHostName) in the client certificate UI.
    2049             : 
    2050           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2051             :            ("[%p] Not returning client cert due to previous join\n", socket));
    2052           0 :     *pRetCert = nullptr;
    2053           0 :     *pRetKey = nullptr;
    2054           0 :     return SECSuccess;
    2055             :   }
    2056             : 
    2057             :   // XXX: This should be done asynchronously; see bug 696976
    2058             :   RefPtr<ClientAuthDataRunnable> runnable(
    2059           0 :     new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert));
    2060           0 :   nsresult rv = runnable->DispatchToMainThreadAndWait();
    2061           0 :   if (NS_FAILED(rv)) {
    2062           0 :     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
    2063           0 :     return SECFailure;
    2064             :   }
    2065             : 
    2066           0 :   if (runnable->mRV != SECSuccess) {
    2067           0 :     PR_SetError(runnable->mErrorCodeToReport, 0);
    2068           0 :   } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
    2069             :     // Make joinConnection prohibit joining after we've sent a client cert
    2070           0 :     info->SetSentClientCert();
    2071             :   }
    2072             : 
    2073           0 :   return runnable->mRV;
    2074             : }
    2075             : 
    2076             : void
    2077           0 : ClientAuthDataRunnable::RunOnTargetThread()
    2078             : {
    2079             :   // We check the value of a pref in this runnable, so this runnable should only
    2080             :   // be run on the main thread.
    2081           0 :   MOZ_ASSERT(NS_IsMainThread());
    2082             : 
    2083           0 :   UniquePLArenaPool arena;
    2084             :   char** caNameStrings;
    2085           0 :   UniqueCERTCertificate cert;
    2086           0 :   UniqueSECKEYPrivateKey privKey;
    2087           0 :   void* wincx = mSocketInfo;
    2088             :   nsresult rv;
    2089             : 
    2090           0 :   nsCOMPtr<nsIX509Cert> socketClientCert;
    2091           0 :   mSocketInfo->GetClientCert(getter_AddRefs(socketClientCert));
    2092             : 
    2093             :   // If a client cert preference was set on the socket info, use that and skip
    2094             :   // the client cert UI and/or search of the user's past cert decisions.
    2095           0 :   if (socketClientCert) {
    2096           0 :     cert.reset(socketClientCert->GetCert());
    2097           0 :     if (!cert) {
    2098           0 :       goto loser;
    2099             :     }
    2100             : 
    2101             :     // Get the private key
    2102           0 :     privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
    2103           0 :     if (!privKey) {
    2104           0 :       goto loser;
    2105             :     }
    2106             : 
    2107           0 :     *mPRetCert = cert.release();
    2108           0 :     *mPRetKey = privKey.release();
    2109           0 :     mRV = SECSuccess;
    2110           0 :     return;
    2111             :   }
    2112             : 
    2113             :   // create caNameStrings
    2114           0 :   arena.reset(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    2115           0 :   if (!arena) {
    2116           0 :     goto loser;
    2117             :   }
    2118             : 
    2119             :   caNameStrings = static_cast<char**>(
    2120           0 :     PORT_ArenaAlloc(arena.get(), sizeof(char*) * mCANames->nnames));
    2121           0 :   if (!caNameStrings) {
    2122           0 :     goto loser;
    2123             :   }
    2124             : 
    2125           0 :   mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
    2126           0 :   if (mRV != SECSuccess) {
    2127           0 :     goto loser;
    2128             :   }
    2129             : 
    2130             :   // find valid user cert and key pair
    2131           0 :   if (nsGetUserCertChoice() == UserCertChoice::Auto) {
    2132             :     // automatically find the right cert
    2133             : 
    2134             :     // find all user certs that are valid and for SSL
    2135             :     UniqueCERTCertList certList(
    2136             :       CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
    2137           0 :                                 false, true, wincx));
    2138           0 :     if (!certList) {
    2139           0 :       goto loser;
    2140             :     }
    2141             : 
    2142             :     // filter the list to those issued by CAs supported by the server
    2143           0 :     mRV = CERT_FilterCertListByCANames(certList.get(), mCANames->nnames,
    2144             :                                        caNameStrings, certUsageSSLClient);
    2145           0 :     if (mRV != SECSuccess) {
    2146           0 :       goto loser;
    2147             :     }
    2148             : 
    2149             :     // make sure the list is not empty
    2150           0 :     if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
    2151           0 :       goto loser;
    2152             :     }
    2153             : 
    2154           0 :     UniqueCERTCertificate lowPrioNonrepCert;
    2155             : 
    2156             :     // loop through the list until we find a cert with a key
    2157           0 :     for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
    2158           0 :          !CERT_LIST_END(node, certList);
    2159           0 :          node = CERT_LIST_NEXT(node)) {
    2160             :       // if the certificate has restriction and we do not satisfy it we do not
    2161             :       // use it
    2162           0 :       privKey.reset(PK11_FindKeyByAnyCert(node->cert, wincx));
    2163           0 :       if (privKey) {
    2164           0 :         if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
    2165           0 :           privKey = nullptr;
    2166             :           // Not a preferred cert
    2167           0 :           if (!lowPrioNonrepCert) { // did not yet find a low prio cert
    2168           0 :             lowPrioNonrepCert.reset(CERT_DupCertificate(node->cert));
    2169             :           }
    2170             :         } else {
    2171             :           // this is a good cert to present
    2172           0 :           cert.reset(CERT_DupCertificate(node->cert));
    2173           0 :           break;
    2174             :         }
    2175             :       }
    2176           0 :       if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) {
    2177             :         // problem with password: bail
    2178           0 :         goto loser;
    2179             :       }
    2180             :     }
    2181             : 
    2182           0 :     if (!cert && lowPrioNonrepCert) {
    2183           0 :       cert = Move(lowPrioNonrepCert);
    2184           0 :       privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
    2185             :     }
    2186             : 
    2187           0 :     if (!cert) {
    2188           0 :       goto loser;
    2189             :     }
    2190             :   } else { // Not Auto => ask
    2191             :     // Get the SSL Certificate
    2192             : 
    2193           0 :     const nsACString& hostname = mSocketInfo->GetHostName();
    2194             : 
    2195             :     RefPtr<nsClientAuthRememberService> cars =
    2196           0 :       mSocketInfo->SharedState().GetClientAuthRememberService();
    2197             : 
    2198           0 :     bool hasRemembered = false;
    2199           0 :     nsCString rememberedDBKey;
    2200           0 :     if (cars) {
    2201             :       bool found;
    2202           0 :       rv = cars->HasRememberedDecision(hostname,
    2203           0 :                                        mSocketInfo->GetOriginAttributes(),
    2204           0 :                                        mServerCert, rememberedDBKey, &found);
    2205           0 :       if (NS_SUCCEEDED(rv) && found) {
    2206           0 :         hasRemembered = true;
    2207             :       }
    2208             :     }
    2209             : 
    2210           0 :     if (hasRemembered && !rememberedDBKey.IsEmpty()) {
    2211           0 :       nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
    2212           0 :       if (certdb) {
    2213           0 :         nsCOMPtr<nsIX509Cert> foundCert;
    2214           0 :         rv = certdb->FindCertByDBKey(rememberedDBKey, getter_AddRefs(foundCert));
    2215           0 :         if (NS_SUCCEEDED(rv) && foundCert) {
    2216             :           nsNSSCertificate* objCert =
    2217           0 :             BitwiseCast<nsNSSCertificate*, nsIX509Cert*>(foundCert.get());
    2218           0 :           if (objCert) {
    2219           0 :             cert.reset(objCert->GetCert());
    2220             :           }
    2221             :         }
    2222             : 
    2223           0 :         if (!cert) {
    2224           0 :           hasRemembered = false;
    2225             :         }
    2226             :       }
    2227             :     }
    2228             : 
    2229           0 :     if (!hasRemembered) {
    2230             :       // user selects a cert to present
    2231           0 :       nsCOMPtr<nsIClientAuthDialogs> dialogs;
    2232             : 
    2233             :       // find all user certs that are for SSL
    2234             :       // note that we are allowing expired certs in this list
    2235             :       UniqueCERTCertList certList(
    2236             :         CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageSSLClient,
    2237           0 :                                   false, false, wincx));
    2238           0 :       if (!certList) {
    2239           0 :         goto loser;
    2240             :       }
    2241             : 
    2242           0 :       if (mCANames->nnames != 0) {
    2243             :         // filter the list to those issued by CAs supported by the server
    2244           0 :         mRV = CERT_FilterCertListByCANames(certList.get(),
    2245           0 :                                            mCANames->nnames,
    2246             :                                            caNameStrings,
    2247             :                                            certUsageSSLClient);
    2248           0 :         if (mRV != SECSuccess) {
    2249           0 :           goto loser;
    2250             :         }
    2251             :       }
    2252             : 
    2253           0 :       if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
    2254             :         // list is empty - no matching certs
    2255           0 :         goto loser;
    2256             :       }
    2257             : 
    2258           0 :       UniquePORTString corg(CERT_GetOrgName(&mServerCert->subject));
    2259           0 :       nsAutoCString org(corg.get());
    2260             : 
    2261           0 :       UniquePORTString cissuer(CERT_GetOrgName(&mServerCert->issuer));
    2262           0 :       nsAutoCString issuer(cissuer.get());
    2263             : 
    2264           0 :       nsCOMPtr<nsIMutableArray> certArray = nsArrayBase::Create();
    2265           0 :       if (!certArray) {
    2266           0 :         goto loser;
    2267             :       }
    2268             : 
    2269           0 :       for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
    2270           0 :            !CERT_LIST_END(node, certList);
    2271           0 :            node = CERT_LIST_NEXT(node)) {
    2272           0 :         nsCOMPtr<nsIX509Cert> tempCert = nsNSSCertificate::Create(node->cert);
    2273           0 :         if (!tempCert) {
    2274           0 :           goto loser;
    2275             :         }
    2276             : 
    2277           0 :         rv = certArray->AppendElement(tempCert, false);
    2278           0 :         if (NS_FAILED(rv)) {
    2279           0 :           goto loser;
    2280             :         }
    2281             :       }
    2282             : 
    2283             :       // Throw up the client auth dialog and get back the index of the selected cert
    2284           0 :       rv = getNSSDialogs(getter_AddRefs(dialogs),
    2285             :                          NS_GET_IID(nsIClientAuthDialogs),
    2286           0 :                          NS_CLIENTAUTHDIALOGS_CONTRACTID);
    2287             : 
    2288           0 :       if (NS_FAILED(rv)) {
    2289           0 :         goto loser;
    2290             :       }
    2291             : 
    2292           0 :       uint32_t selectedIndex = 0;
    2293           0 :       bool certChosen = false;
    2294           0 :       rv = dialogs->ChooseCertificate(mSocketInfo, hostname,
    2295           0 :                                       mSocketInfo->GetPort(), org, issuer,
    2296           0 :                                       certArray, &selectedIndex, &certChosen);
    2297           0 :       if (NS_FAILED(rv)) {
    2298           0 :         goto loser;
    2299             :       }
    2300             : 
    2301             :       // even if the user has canceled, we want to remember that, to avoid repeating prompts
    2302           0 :       bool wantRemember = false;
    2303           0 :       mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
    2304             : 
    2305           0 :       if (certChosen) {
    2306           0 :         nsCOMPtr<nsIX509Cert> selectedCert = do_QueryElementAt(certArray,
    2307           0 :                                                                selectedIndex);
    2308           0 :         if (!selectedCert) {
    2309           0 :           goto loser;
    2310             :         }
    2311           0 :         cert.reset(selectedCert->GetCert());
    2312             :       }
    2313             : 
    2314           0 :       if (cars && wantRemember) {
    2315           0 :         cars->RememberDecision(hostname, mSocketInfo->GetOriginAttributes(),
    2316           0 :                                mServerCert, certChosen ? cert.get() : nullptr);
    2317             :       }
    2318             :     }
    2319             : 
    2320           0 :     if (!cert) {
    2321           0 :       goto loser;
    2322             :     }
    2323             : 
    2324             :     // go get the private key
    2325           0 :     privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
    2326           0 :     if (!privKey) {
    2327           0 :       goto loser;
    2328             :     }
    2329             :   }
    2330           0 :   goto done;
    2331             : 
    2332             : loser:
    2333           0 :   if (mRV == SECSuccess) {
    2334           0 :     mRV = SECFailure;
    2335             :   }
    2336             : done:
    2337           0 :   int error = PR_GetError();
    2338             : 
    2339           0 :   *mPRetCert = cert.release();
    2340           0 :   *mPRetKey = privKey.release();
    2341             : 
    2342           0 :   if (mRV == SECFailure) {
    2343           0 :     mErrorCodeToReport = error;
    2344             :   }
    2345             : }
    2346             : 
    2347             : static PRFileDesc*
    2348           0 : nsSSLIOLayerImportFD(PRFileDesc* fd,
    2349             :                      nsNSSSocketInfo* infoObject,
    2350             :                      const char* host)
    2351             : {
    2352           0 :   nsNSSShutDownPreventionLock locker;
    2353           0 :   PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd);
    2354           0 :   if (!sslSock) {
    2355           0 :     MOZ_ASSERT_UNREACHABLE("NSS: Error importing socket");
    2356             :     return nullptr;
    2357             :   }
    2358           0 :   SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*) infoObject);
    2359           0 :   SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
    2360           0 :   SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback, infoObject);
    2361             : 
    2362             :   // Disable this hook if we connect anonymously. See bug 466080.
    2363           0 :   uint32_t flags = 0;
    2364           0 :   infoObject->GetProviderFlags(&flags);
    2365           0 :   if (flags & nsISocketProvider::ANONYMOUS_CONNECT) {
    2366           0 :       SSL_GetClientAuthDataHook(sslSock, nullptr, infoObject);
    2367             :   } else {
    2368             :       SSL_GetClientAuthDataHook(sslSock,
    2369             :                             (SSLGetClientAuthData) nsNSS_SSLGetClientAuthData,
    2370           0 :                             infoObject);
    2371             :   }
    2372           0 :   if (flags & nsISocketProvider::MITM_OK) {
    2373           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2374             :            ("[%p] nsSSLIOLayerImportFD: bypass authentication flag\n", fd));
    2375           0 :     infoObject->SetBypassAuthentication(true);
    2376             :   }
    2377           0 :   if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook,
    2378             :                                             infoObject)) {
    2379           0 :     MOZ_ASSERT_UNREACHABLE("Failed to configure AuthCertificateHook");
    2380             :     goto loser;
    2381             :   }
    2382             : 
    2383           0 :   if (SECSuccess != SSL_SetURL(sslSock, host)) {
    2384           0 :     MOZ_ASSERT_UNREACHABLE("SSL_SetURL failed");
    2385             :     goto loser;
    2386             :   }
    2387             : 
    2388           0 :   return sslSock;
    2389             : loser:
    2390             :   if (sslSock) {
    2391             :     PR_Close(sslSock);
    2392             :   }
    2393             :   return nullptr;
    2394             : }
    2395             : 
    2396             : static const SSLSignatureScheme sEnabledSignatureSchemes[] = {
    2397             :   ssl_sig_ecdsa_secp256r1_sha256,
    2398             :   ssl_sig_ecdsa_secp384r1_sha384,
    2399             :   ssl_sig_ecdsa_secp521r1_sha512,
    2400             :   ssl_sig_rsa_pss_sha256,
    2401             :   ssl_sig_rsa_pss_sha384,
    2402             :   ssl_sig_rsa_pss_sha512,
    2403             :   ssl_sig_rsa_pkcs1_sha256,
    2404             :   ssl_sig_rsa_pkcs1_sha384,
    2405             :   ssl_sig_rsa_pkcs1_sha512,
    2406             :   ssl_sig_ecdsa_sha1,
    2407             :   ssl_sig_rsa_pkcs1_sha1,
    2408             : };
    2409             : 
    2410             : static nsresult
    2411           0 : nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
    2412             :                        bool haveProxy, const char* host, int32_t port,
    2413             :                        nsNSSSocketInfo* infoObject)
    2414             : {
    2415           0 :   nsNSSShutDownPreventionLock locker;
    2416           0 :   if (forSTARTTLS || haveProxy) {
    2417           0 :     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
    2418           0 :       return NS_ERROR_FAILURE;
    2419             :     }
    2420             :   }
    2421             : 
    2422             :   SSLVersionRange range;
    2423           0 :   if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
    2424           0 :     return NS_ERROR_FAILURE;
    2425             :   }
    2426             : 
    2427           0 :   if ((infoObject->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE) &&
    2428           0 :       (range.max > SSL_LIBRARY_VERSION_TLS_1_2)) {
    2429           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2430             :             ("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to BE_CONSERVATIVE flag\n",
    2431             :              fd));
    2432           0 :     range.max = SSL_LIBRARY_VERSION_TLS_1_2;
    2433             :   }
    2434             : 
    2435           0 :   uint16_t maxEnabledVersion = range.max;
    2436           0 :   infoObject->SharedState().IOLayerHelpers()
    2437           0 :     .adjustForTLSIntolerance(infoObject->GetHostName(), infoObject->GetPort(),
    2438           0 :                              range);
    2439           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2440             :          ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
    2441             :           fd, static_cast<unsigned int>(range.min),
    2442             :               static_cast<unsigned int>(range.max)));
    2443             : 
    2444           0 :   if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
    2445           0 :     return NS_ERROR_FAILURE;
    2446             :   }
    2447           0 :   infoObject->SetTLSVersionRange(range);
    2448             : 
    2449             :   // when adjustForTLSIntolerance tweaks the maximum version downward,
    2450             :   // we tell the server using this SCSV so they can detect a downgrade attack
    2451           0 :   if (range.max < maxEnabledVersion) {
    2452           0 :     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
    2453             :            ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
    2454             :     // Some servers will choke if we send the fallback SCSV with TLS 1.2.
    2455           0 :     if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) {
    2456           0 :       if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
    2457           0 :         return NS_ERROR_FAILURE;
    2458             :       }
    2459             :     }
    2460             :     // tell NSS the max enabled version to make anti-downgrade effective
    2461           0 :     if (SECSuccess != SSL_SetDowngradeCheckVersion(fd, maxEnabledVersion)) {
    2462           0 :       return NS_ERROR_FAILURE;
    2463             :     }
    2464             :   }
    2465             : 
    2466           0 :   if (range.max > SSL_LIBRARY_VERSION_TLS_1_2) {
    2467           0 :     SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, false);
    2468           0 :     SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, false);
    2469           0 :     SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false);
    2470           0 :     SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false);
    2471             :   }
    2472             : 
    2473             :   // Include a modest set of named groups.
    2474             :   const SSLNamedGroup namedGroups[] = {
    2475             :     ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
    2476             :     ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072
    2477           0 :   };
    2478           0 :   if (SECSuccess != SSL_NamedGroupConfig(fd, namedGroups,
    2479           0 :                                          mozilla::ArrayLength(namedGroups))) {
    2480           0 :     return NS_ERROR_FAILURE;
    2481             :   }
    2482             :   // This ensures that we send key shares for X25519 and P-256 in TLS 1.3, so
    2483             :   // that servers are less likely to use HelloRetryRequest.
    2484           0 :   if (SECSuccess != SSL_SendAdditionalKeyShares(fd, 1)) {
    2485           0 :     return NS_ERROR_FAILURE;
    2486             :   }
    2487             : 
    2488           0 :   if (SECSuccess != SSL_SignatureSchemePrefSet(fd, sEnabledSignatureSchemes,
    2489           0 :                       mozilla::ArrayLength(sEnabledSignatureSchemes))) {
    2490           0 :     return NS_ERROR_FAILURE;
    2491             :   }
    2492             : 
    2493           0 :   bool enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
    2494           0 :   if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
    2495           0 :     return NS_ERROR_FAILURE;
    2496             :   }
    2497             : 
    2498           0 :   bool sctsEnabled = infoObject->SharedState().IsSignedCertTimestampsEnabled();
    2499           0 :   if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
    2500             :       sctsEnabled)) {
    2501           0 :     return NS_ERROR_FAILURE;
    2502             :   }
    2503             : 
    2504           0 :   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
    2505           0 :     return NS_ERROR_FAILURE;
    2506             :   }
    2507             : 
    2508             :   // Set the Peer ID so that SSL proxy connections work properly and to
    2509             :   // separate anonymous and/or private browsing connections.
    2510           0 :   uint32_t flags = infoObject->GetProviderFlags();
    2511           0 :   nsAutoCString peerId;
    2512           0 :   if (flags & nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
    2513           0 :     peerId.AppendLiteral("anon:");
    2514             :   }
    2515           0 :   if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
    2516           0 :     peerId.AppendLiteral("private:");
    2517             :   }
    2518           0 :   if (flags & nsISocketProvider::MITM_OK) {
    2519           0 :     peerId.AppendLiteral("bypassAuth:");
    2520             :   }
    2521           0 :   if (flags & nsISocketProvider::BE_CONSERVATIVE) {
    2522           0 :     peerId.AppendLiteral("beConservative:");
    2523             :   }
    2524           0 :   peerId.Append(host);
    2525           0 :   peerId.Append(':');
    2526           0 :   peerId.AppendInt(port);
    2527           0 :   nsAutoCString suffix;
    2528           0 :   infoObject->GetOriginAttributes().CreateSuffix(suffix);
    2529           0 :   peerId.Append(suffix);
    2530           0 :   if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
    2531           0 :     return NS_ERROR_FAILURE;
    2532             :   }
    2533             : 
    2534           0 :   return NS_OK;
    2535             : }
    2536             : 
    2537             : nsresult
    2538           0 : nsSSLIOLayerAddToSocket(int32_t family,
    2539             :                         const char* host,
    2540             :                         int32_t port,
    2541             :                         nsIProxyInfo* proxy,
    2542             :                         const OriginAttributes& originAttributes,
    2543             :                         PRFileDesc* fd,
    2544             :                         nsISupports** info,
    2545             :                         bool forSTARTTLS,
    2546             :                         uint32_t providerFlags)
    2547             : {
    2548           0 :   nsNSSShutDownPreventionLock locker;
    2549           0 :   PRFileDesc* layer = nullptr;
    2550           0 :   PRFileDesc* plaintextLayer = nullptr;
    2551             :   nsresult rv;
    2552             :   PRStatus stat;
    2553             : 
    2554             :   SharedSSLState* sharedState =
    2555           0 :     providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
    2556           0 :   nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
    2557           0 :   if (!infoObject) return NS_ERROR_FAILURE;
    2558             : 
    2559           0 :   NS_ADDREF(infoObject);
    2560           0 :   infoObject->SetForSTARTTLS(forSTARTTLS);
    2561           0 :   infoObject->SetHostName(host);
    2562           0 :   infoObject->SetPort(port);
    2563           0 :   infoObject->SetOriginAttributes(originAttributes);
    2564             : 
    2565           0 :   bool haveProxy = false;
    2566           0 :   if (proxy) {
    2567           0 :     nsCString proxyHost;
    2568           0 :     proxy->GetHost(proxyHost);
    2569           0 :     haveProxy = !proxyHost.IsEmpty();
    2570             :   }
    2571             : 
    2572             :   // A plaintext observer shim is inserted so we can observe some protocol
    2573             :   // details without modifying nss
    2574           0 :   plaintextLayer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
    2575           0 :                                         &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
    2576           0 :   if (plaintextLayer) {
    2577           0 :     plaintextLayer->secret = (PRFilePrivate*) infoObject;
    2578           0 :     stat = PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer);
    2579           0 :     if (stat == PR_FAILURE) {
    2580           0 :       plaintextLayer->dtor(plaintextLayer);
    2581           0 :       plaintextLayer = nullptr;
    2582             :     }
    2583             :   }
    2584             : 
    2585           0 :   PRFileDesc* sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
    2586           0 :   if (!sslSock) {
    2587           0 :     MOZ_ASSERT_UNREACHABLE("NSS: Error importing socket");
    2588             :     goto loser;
    2589             :   }
    2590             : 
    2591           0 :   infoObject->SetFileDescPtr(sslSock);
    2592             : 
    2593           0 :   rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host, port,
    2594           0 :                               infoObject);
    2595             : 
    2596           0 :   if (NS_FAILED(rv))
    2597           0 :     goto loser;
    2598             : 
    2599             :   // Now, layer ourselves on top of the SSL socket...
    2600           0 :   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
    2601           0 :                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
    2602           0 :   if (!layer)
    2603           0 :     goto loser;
    2604             : 
    2605           0 :   layer->secret = (PRFilePrivate*) infoObject;
    2606           0 :   stat = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
    2607             : 
    2608           0 :   if (stat == PR_FAILURE) {
    2609           0 :     goto loser;
    2610             :   }
    2611             : 
    2612           0 :   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Socket set up\n", (void*) sslSock));
    2613           0 :   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
    2614             : 
    2615             :   // We are going use a clear connection first //
    2616           0 :   if (forSTARTTLS || haveProxy) {
    2617           0 :     infoObject->SetHandshakeNotPending();
    2618             :   }
    2619             : 
    2620           0 :   infoObject->SharedState().NoteSocketCreated();
    2621             : 
    2622           0 :   return NS_OK;
    2623             :  loser:
    2624           0 :   NS_IF_RELEASE(infoObject);
    2625           0 :   if (layer) {
    2626           0 :     layer->dtor(layer);
    2627             :   }
    2628           0 :   if (plaintextLayer) {
    2629           0 :     PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
    2630           0 :     plaintextLayer->dtor(plaintextLayer);
    2631             :   }
    2632           0 :   return NS_ERROR_FAILURE;
    2633             : }

Generated by: LCOV version 1.13