security/manager/ssl/src/nsNSSIOLayer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsNSSIOLayer.h"
     9 #include "pkix/pkixtypes.h"
    10 #include "nsNSSComponent.h"
    11 #include "mozilla/Casting.h"
    12 #include "mozilla/DebugOnly.h"
    13 #include "mozilla/Telemetry.h"
    15 #include "prlog.h"
    16 #include "prnetdb.h"
    17 #include "nsIPrefService.h"
    18 #include "nsIClientAuthDialogs.h"
    19 #include "nsClientAuthRemember.h"
    20 #include "nsISSLErrorListener.h"
    22 #include "nsNetUtil.h"
    23 #include "nsPrintfCString.h"
    24 #include "SSLServerCertVerification.h"
    25 #include "nsNSSCertHelper.h"
    26 #include "nsNSSCleaner.h"
    28 #ifndef MOZ_NO_EV_CERTS
    29 #include "nsIDocShell.h"
    30 #include "nsIDocShellTreeItem.h"
    31 #include "nsISecureBrowserUI.h"
    32 #include "nsIInterfaceRequestorUtils.h"
    33 #endif
    35 #include "nsCharSeparatedTokenizer.h"
    36 #include "nsIConsoleService.h"
    37 #include "PSMRunnable.h"
    38 #include "ScopedNSSTypes.h"
    39 #include "SharedSSLState.h"
    40 #include "mozilla/Preferences.h"
    41 #include "nsContentUtils.h"
    43 #include "ssl.h"
    44 #include "sslproto.h"
    45 #include "secerr.h"
    46 #include "sslerr.h"
    47 #include "secder.h"
    48 #include "keyhi.h"
    50 #include <algorithm>
    52 using namespace mozilla;
    53 using namespace mozilla::psm;
    55 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
    56                             //reports when doing SSL read/write
    58 //#define DUMP_BUFFER  //Enable this define along with
    59                        //DEBUG_SSL_VERBOSE to dump SSL
    60                        //read/write buffer to a log.
    61                        //Uses PR_LOG except on Mac where
    62                        //we always write out to our own
    63                        //file.
    65 namespace {
    67 NSSCleanupAutoPtrClass(void, PR_FREEIF)
    69 void
    70 getSiteKey(const nsACString& hostName, uint16_t port,
    71            /*out*/ nsCSubstring& key)
    72 {
    73   key = hostName;
    74   key.AppendASCII(":");
    75   key.AppendInt(port);
    76 }
    78 // SSM_UserCertChoice: enum for cert choice info
    79 typedef enum {ASK, AUTO} SSM_UserCertChoice;
    81 // Forward secrecy provides us with a proof of posession of the private key
    82 // from the server. Without of proof of posession of the private key of the
    83 // server, any MitM can force us to false start in a connection that the real
    84 // server never participates in, since with RSA key exchange a MitM can
    85 // complete the server's first round of the handshake without knowing the
    86 // server's public key This would be used, for example, to greatly accelerate
    87 // the attacks on RC4 or other attacks that allow a MitM to decrypt encrypted
    88 // data without having the server's private key. Without false start, such
    89 // attacks are naturally rate limited by network latency and may also be rate
    90 // limited explicitly by the server's DoS or other security mechanisms.
    91 // Further, because the server that has the private key must participate in the
    92 // handshake, the server could detect these kinds of attacks if they they are
    93 // repeated rapidly and/or frequently, by noticing lots of invalid or
    94 // incomplete handshakes.
    95 //
    96 // With this in mind, when we choose not to require forward secrecy (when the
    97 // pref's value is false), then we will still only false start for RSA key
    98 // exchange only if the most recent handshake we've previously done used RSA
    99 // key exchange. This way, we prevent any (EC)DHE-to-RSA downgrade attacks for
   100 // servers that consistently choose (EC)DHE key exchange. In order to prevent
   101 // downgrade from ECDHE_*_GCM cipher suites, we need to also consider downgrade
   102 // from TLS 1.2 to earlier versions (bug 861310).
   103 static const bool FALSE_START_REQUIRE_FORWARD_SECRECY_DEFAULT = true;
   105 // XXX(perf bug 940787): We currently require NPN because there is a very
   106 // high (perfect so far) correlation between servers that are false-start-
   107 // tolerant and servers that support NPN, according to Google. Without this, we
   108 // will run into interop issues with a small percentage of servers that stop
   109 // responding when we attempt to false start.
   110 static const bool FALSE_START_REQUIRE_NPN_DEFAULT = true;
   112 } // unnamed namespace
   114 #ifdef PR_LOGGING
   115 extern PRLogModuleInfo* gPIPNSSLog;
   116 #endif
   118 nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
   119   : mFd(nullptr),
   120     mCertVerificationState(before_cert_verification),
   121     mSharedState(aState),
   122     mForSTARTTLS(false),
   123     mHandshakePending(true),
   124     mRememberClientAuthCertificate(false),
   125     mPreliminaryHandshakeDone(false),
   126     mNPNCompleted(false),
   127     mFalseStartCallbackCalled(false),
   128     mFalseStarted(false),
   129     mIsFullHandshake(false),
   130     mHandshakeCompleted(false),
   131     mJoined(false),
   132     mSentClientCert(false),
   133     mNotedTimeUntilReady(false),
   134     mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
   135     mKEAExpected(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
   136     mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN),
   137     mProviderFlags(providerFlags),
   138     mSocketCreationTimestamp(TimeStamp::Now()),
   139     mPlaintextBytesRead(0)
   140 {
   141   mTLSVersionRange.min = 0;
   142   mTLSVersionRange.max = 0;
   143 }
   145 NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketInfo, TransportSecurityInfo,
   146                             nsISSLSocketControl,
   147                             nsIClientAuthUserDecision)
   149 NS_IMETHODIMP
   150 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
   151 {
   152   *aProviderFlags = mProviderFlags;
   153   return NS_OK;
   154 }
   156 NS_IMETHODIMP
   157 nsNSSSocketInfo::GetKEAUsed(int16_t* aKea)
   158 {
   159   *aKea = mKEAUsed;
   160   return NS_OK;
   161 }
   163 NS_IMETHODIMP
   164 nsNSSSocketInfo::GetKEAExpected(int16_t* aKea)
   165 {
   166   *aKea = mKEAExpected;
   167   return NS_OK;
   168 }
   170 NS_IMETHODIMP
   171 nsNSSSocketInfo::SetKEAExpected(int16_t aKea)
   172 {
   173   mKEAExpected = aKea;
   174   return NS_OK;
   175 }
   177 NS_IMETHODIMP
   178 nsNSSSocketInfo::GetSSLVersionUsed(int16_t* aSSLVersionUsed)
   179 {
   180   *aSSLVersionUsed = mSSLVersionUsed;
   181   return NS_OK;
   182 }
   184 NS_IMETHODIMP
   185 nsNSSSocketInfo::GetRememberClientAuthCertificate(bool* aRemember)
   186 {
   187   NS_ENSURE_ARG_POINTER(aRemember);
   188   *aRemember = mRememberClientAuthCertificate;
   189   return NS_OK;
   190 }
   192 NS_IMETHODIMP
   193 nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRemember)
   194 {
   195   mRememberClientAuthCertificate = aRemember;
   196   return NS_OK;
   197 }
   199 NS_IMETHODIMP
   200 nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
   201 {
   202   *aCallbacks = mCallbacks;
   203   NS_IF_ADDREF(*aCallbacks);
   204   return NS_OK;
   205 }
   207 NS_IMETHODIMP
   208 nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
   209 {
   210   if (!aCallbacks) {
   211     mCallbacks = nullptr;
   212     return NS_OK;
   213   }
   215   mCallbacks = aCallbacks;
   217   return NS_OK;
   218 }
   220 #ifndef MOZ_NO_EV_CERTS
   221 static void
   222 getSecureBrowserUI(nsIInterfaceRequestor* callbacks,
   223                    nsISecureBrowserUI** result)
   224 {
   225   NS_ASSERTION(result, "result parameter to getSecureBrowserUI is null");
   226   *result = nullptr;
   228   NS_ASSERTION(NS_IsMainThread(),
   229                "getSecureBrowserUI called off the main thread");
   231   if (!callbacks)
   232     return;
   234   nsCOMPtr<nsISecureBrowserUI> secureUI = do_GetInterface(callbacks);
   235   if (secureUI) {
   236     secureUI.forget(result);
   237     return;
   238   }
   240   nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(callbacks);
   241   if (item) {
   242     nsCOMPtr<nsIDocShellTreeItem> rootItem;
   243     (void) item->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
   245     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(rootItem);
   246     if (docShell) {
   247       (void) docShell->GetSecurityUI(result);
   248     }
   249   }
   250 }
   251 #endif
   253 void
   254 nsNSSSocketInfo::NoteTimeUntilReady()
   255 {
   256   if (mNotedTimeUntilReady)
   257     return;
   259   mNotedTimeUntilReady = true;
   261   // This will include TCP and proxy tunnel wait time
   262   Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
   263                                  mSocketCreationTimestamp, TimeStamp::Now());
   264   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   265          ("[%p] nsNSSSocketInfo::NoteTimeUntilReady\n", mFd));
   266 }
   268 void
   269 nsNSSSocketInfo::SetHandshakeCompleted()
   270 {
   271   if (!mHandshakeCompleted) {
   272     enum HandshakeType {
   273       Resumption = 1,
   274       FalseStarted = 2,
   275       ChoseNotToFalseStart = 3,
   276       NotAllowedToFalseStart = 4,
   277     };
   279     HandshakeType handshakeType = !IsFullHandshake() ? Resumption
   280                                 : mFalseStarted ? FalseStarted
   281                                 : mFalseStartCallbackCalled ? ChoseNotToFalseStart
   282                                 : NotAllowedToFalseStart;
   284     // This will include TCP and proxy tunnel wait time
   285     Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_HANDSHAKE_FINISHED,
   286                                    mSocketCreationTimestamp, TimeStamp::Now());
   288     // If the handshake is completed for the first time from just 1 callback
   289     // that means that TLS session resumption must have been used.
   290     Telemetry::Accumulate(Telemetry::SSL_RESUMED_SESSION,
   291                           handshakeType == Resumption);
   292     Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_TYPE, handshakeType);
   293   }
   296     // Remove the plain text layer as it is not needed anymore.
   297     // The plain text layer is not always present - so its not a fatal error
   298     // if it cannot be removed
   299     PRFileDesc* poppedPlaintext =
   300       PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
   301     if (poppedPlaintext) {
   302       PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
   303       poppedPlaintext->dtor(poppedPlaintext);
   304     }
   306     mHandshakeCompleted = true;
   308     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   309            ("[%p] nsNSSSocketInfo::SetHandshakeCompleted\n", (void*) mFd));
   311     mIsFullHandshake = false; // reset for next handshake on this connection
   312 }
   314 void
   315 nsNSSSocketInfo::SetNegotiatedNPN(const char* value, uint32_t length)
   316 {
   317   if (!value) {
   318     mNegotiatedNPN.Truncate();
   319   } else {
   320     mNegotiatedNPN.Assign(value, length);
   321   }
   322   mNPNCompleted = true;
   323 }
   325 NS_IMETHODIMP
   326 nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN)
   327 {
   328   if (!mNPNCompleted)
   329     return NS_ERROR_NOT_CONNECTED;
   331   aNegotiatedNPN = mNegotiatedNPN;
   332   return NS_OK;
   333 }
   335 NS_IMETHODIMP
   336 nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
   337                                 const nsACString& hostname,
   338                                 int32_t port,
   339                                 bool* _retval)
   340 {
   341   *_retval = false;
   343   // Different ports may not be joined together
   344   if (port != GetPort())
   345     return NS_OK;
   347   // Make sure NPN has been completed and matches requested npnProtocol
   348   if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
   349     return NS_OK;
   351   // If this is the same hostname then the certicate status does not
   352   // need to be considered. They are joinable.
   353   if (hostname.Equals(GetHostName())) {
   354     *_retval = true;
   355     return NS_OK;
   356   }
   358   // Before checking the server certificate we need to make sure the
   359   // handshake has completed.
   360   if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
   361     return NS_OK;
   363   // If the cert has error bits (e.g. it is untrusted) then do not join.
   364   // The value of mHaveCertErrorBits is only reliable because we know that
   365   // the handshake completed.
   366   if (SSLStatus()->mHaveCertErrorBits)
   367     return NS_OK;
   369   // If the connection is using client certificates then do not join
   370   // because the user decides on whether to send client certs to hosts on a
   371   // per-domain basis.
   372   if (mSentClientCert)
   373     return NS_OK;
   375   // Ensure that the server certificate covers the hostname that would
   376   // like to join this connection
   378   ScopedCERTCertificate nssCert;
   380   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
   381   if (cert2)
   382     nssCert = cert2->GetCert();
   384   if (!nssCert)
   385     return NS_OK;
   387   if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
   388       SECSuccess)
   389     return NS_OK;
   391   // All tests pass - this is joinable
   392   mJoined = true;
   393   *_retval = true;
   394   return NS_OK;
   395 }
   397 bool
   398 nsNSSSocketInfo::GetForSTARTTLS()
   399 {
   400   return mForSTARTTLS;
   401 }
   403 void
   404 nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
   405 {
   406   mForSTARTTLS = aForSTARTTLS;
   407 }
   409 NS_IMETHODIMP
   410 nsNSSSocketInfo::ProxyStartSSL()
   411 {
   412   return ActivateSSL();
   413 }
   415 NS_IMETHODIMP
   416 nsNSSSocketInfo::StartTLS()
   417 {
   418   return ActivateSSL();
   419 }
   421 NS_IMETHODIMP
   422 nsNSSSocketInfo::SetNPNList(nsTArray<nsCString>& protocolArray)
   423 {
   424   nsNSSShutDownPreventionLock locker;
   425   if (isAlreadyShutDown())
   426     return NS_ERROR_NOT_AVAILABLE;
   427   if (!mFd)
   428     return NS_ERROR_FAILURE;
   430   // the npn list is a concatenated list of 8 bit byte strings.
   431   nsCString npnList;
   433   for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
   434     if (protocolArray[index].IsEmpty() ||
   435         protocolArray[index].Length() > 255)
   436       return NS_ERROR_ILLEGAL_VALUE;
   438     npnList.Append(protocolArray[index].Length());
   439     npnList.Append(protocolArray[index]);
   440   }
   442   if (SSL_SetNextProtoNego(
   443         mFd,
   444         reinterpret_cast<const unsigned char*>(npnList.get()),
   445         npnList.Length()) != SECSuccess)
   446     return NS_ERROR_FAILURE;
   448   return NS_OK;
   449 }
   451 nsresult
   452 nsNSSSocketInfo::ActivateSSL()
   453 {
   454   nsNSSShutDownPreventionLock locker;
   455   if (isAlreadyShutDown())
   456     return NS_ERROR_NOT_AVAILABLE;
   458   if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
   459     return NS_ERROR_FAILURE;
   460   if (SECSuccess != SSL_ResetHandshake(mFd, false))
   461     return NS_ERROR_FAILURE;
   463   mHandshakePending = true;
   465   return NS_OK;
   466 }
   468 nsresult
   469 nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
   470 {
   471   *aFilePtr = mFd;
   472   return NS_OK;
   473 }
   475 nsresult
   476 nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
   477 {
   478   mFd = aFilePtr;
   479   return NS_OK;
   480 }
   482 #ifndef MOZ_NO_EV_CERTS
   483 class PreviousCertRunnable : public SyncRunnableBase
   484 {
   485 public:
   486   PreviousCertRunnable(nsIInterfaceRequestor* callbacks)
   487     : mCallbacks(callbacks)
   488   {
   489   }
   491   virtual void RunOnTargetThread()
   492   {
   493     nsCOMPtr<nsISecureBrowserUI> secureUI;
   494     getSecureBrowserUI(mCallbacks, getter_AddRefs(secureUI));
   495     nsCOMPtr<nsISSLStatusProvider> statusProvider = do_QueryInterface(secureUI);
   496     if (statusProvider) {
   497       nsCOMPtr<nsISSLStatus> status;
   498       (void) statusProvider->GetSSLStatus(getter_AddRefs(status));
   499       if (status) {
   500         (void) status->GetServerCert(getter_AddRefs(mPreviousCert));
   501       }
   502     }
   503   }
   505   nsCOMPtr<nsIX509Cert> mPreviousCert; // out
   506 private:
   507   nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
   508 };
   509 #endif
   511 void
   512 nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
   513 {
   514   NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
   515   *_result = nullptr;
   517 #ifndef MOZ_NO_EV_CERTS
   518   RefPtr<PreviousCertRunnable> runnable(new PreviousCertRunnable(mCallbacks));
   519   DebugOnly<nsresult> rv = runnable->DispatchToMainThreadAndWait();
   520   NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
   521   runnable->mPreviousCert.forget(_result);
   522 #endif
   523 }
   525 void
   526 nsNSSSocketInfo::SetCertVerificationWaiting()
   527 {
   528   // mCertVerificationState may be before_cert_verification for the first
   529   // handshake on the connection, or after_cert_verification for subsequent
   530   // renegotiation handshakes.
   531   NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
   532                "Invalid state transition to waiting_for_cert_verification");
   533   mCertVerificationState = waiting_for_cert_verification;
   534 }
   536 // Be careful that SetCertVerificationResult does NOT get called while we are
   537 // processing a SSL callback function, because SSL_AuthCertificateComplete will
   538 // attempt to acquire locks that are already held by libssl when it calls
   539 // callbacks.
   540 void
   541 nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
   542                                            SSLErrorMessageType errorMessageType)
   543 {
   544   NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
   545                "Invalid state transition to cert_verification_finished");
   547   if (mFd) {
   548     SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
   549     // Only replace errorCode if there was originally no error
   550     if (rv != SECSuccess && errorCode == 0) {
   551       errorCode = PR_GetError();
   552       errorMessageType = PlainErrorMessage;
   553       if (errorCode == 0) {
   554         NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
   555         errorCode = PR_INVALID_STATE_ERROR;
   556       }
   557     }
   558   }
   560   if (errorCode) {
   561     SetCanceled(errorCode, errorMessageType);
   562   }
   564   if (mPlaintextBytesRead && !errorCode) {
   565     Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK,
   566                           SafeCast<uint32_t>(mPlaintextBytesRead));
   567   }
   569   mCertVerificationState = after_cert_verification;
   570 }
   572 SharedSSLState&
   573 nsNSSSocketInfo::SharedState()
   574 {
   575   return mSharedState;
   576 }
   578 void nsSSLIOLayerHelpers::Cleanup()
   579 {
   580   mTLSIntoleranceInfo.Clear();
   582   if (mRenegoUnrestrictedSites) {
   583     delete mRenegoUnrestrictedSites;
   584     mRenegoUnrestrictedSites = nullptr;
   585   }
   586 }
   588 static void
   589 nsHandleSSLError(nsNSSSocketInfo* socketInfo,
   590                  ::mozilla::psm::SSLErrorMessageType errtype,
   591                  PRErrorCode err)
   592 {
   593   if (!NS_IsMainThread()) {
   594     NS_ERROR("nsHandleSSLError called off the main thread");
   595     return;
   596   }
   598   // SetCanceled is only called by the main thread or the socket transport
   599   // thread. Whenever this function is called on the main thread, the SSL
   600   // thread is blocked on it. So, no mutex is necessary for
   601   // SetCanceled()/GetError*().
   602   if (socketInfo->GetErrorCode()) {
   603     // If the socket has been flagged as canceled,
   604     // the code who did was responsible for setting the error code.
   605     return;
   606   }
   608   nsresult rv;
   609   NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
   610   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
   611   if (NS_FAILED(rv))
   612     return;
   614   // Try to get a nsISSLErrorListener implementation from the socket consumer.
   615   nsCOMPtr<nsIInterfaceRequestor> cb;
   616   socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
   617   if (cb) {
   618     nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
   619     if (sel) {
   620       nsIInterfaceRequestor* csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
   622       nsCString hostWithPortString;
   623       getSiteKey(socketInfo->GetHostName(), socketInfo->GetPort(),
   624                  hostWithPortString);
   626       bool suppressMessage = false; // obsolete, ignored
   627       rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
   628     }
   629   }
   631   // We must cancel first, which sets the error code.
   632   socketInfo->SetCanceled(err, PlainErrorMessage);
   633   nsXPIDLString errorString;
   634   socketInfo->GetErrorLogMessage(err, errtype, errorString);
   636   if (!errorString.IsEmpty()) {
   637     nsContentUtils::LogSimpleConsoleError(errorString, "SSL");
   638   }
   639 }
   641 namespace {
   643 enum Operation { reading, writing, not_reading_or_writing };
   645 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
   646                        PRFileDesc* ssl_layer_fd,
   647                        nsNSSSocketInfo* socketInfo);
   649 nsNSSSocketInfo*
   650 getSocketInfoIfRunning(PRFileDesc* fd, Operation op,
   651                        const nsNSSShutDownPreventionLock& /*proofOfLock*/)
   652 {
   653   if (!fd || !fd->lower || !fd->secret ||
   654       fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
   655     NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
   656     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   657     return nullptr;
   658   }
   660   nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*) fd->secret;
   662   if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
   663     PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
   664     return nullptr;
   665   }
   667   if (socketInfo->GetErrorCode()) {
   668     PRErrorCode err = socketInfo->GetErrorCode();
   669     PR_SetError(err, 0);
   670     if (op == reading || op == writing) {
   671       // We must do TLS intolerance checks for reads and writes, for timeouts
   672       // in particular.
   673       (void) checkHandshake(-1, op == reading, fd, socketInfo);
   674     }
   676     // If we get here, it is probably because cert verification failed and this
   677     // is the first I/O attempt since that failure.
   678     return nullptr;
   679   }
   681   return socketInfo;
   682 }
   684 } // unnnamed namespace
   686 static PRStatus
   687 nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
   688                     PRIntervalTime timeout)
   689 {
   690   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n",
   691          (void*) fd));
   692   nsNSSShutDownPreventionLock locker;
   693   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
   694     return PR_FAILURE;
   696   PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
   697   if (status != PR_SUCCESS) {
   698     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
   699                                       (void*) fd, PR_GetError()));
   700     return status;
   701   }
   703   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*) fd));
   704   return status;
   705 }
   707 void
   708 nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
   709                                                int16_t port, uint16_t tolerant)
   710 {
   711   nsCString key;
   712   getSiteKey(hostName, port, key);
   714   MutexAutoLock lock(mutex);
   716   IntoleranceEntry entry;
   717   if (mTLSIntoleranceInfo.Get(key, &entry)) {
   718     entry.AssertInvariant();
   719     entry.tolerant = std::max(entry.tolerant, tolerant);
   720     if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
   721       entry.intolerant = entry.tolerant + 1;
   722     }
   723   } else {
   724     entry.tolerant = tolerant;
   725     entry.intolerant = 0;
   726   }
   728   entry.AssertInvariant();
   730   mTLSIntoleranceInfo.Put(key, entry);
   731 }
   733 // returns true if we should retry the handshake
   734 bool
   735 nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName,
   736                                                  int16_t port,
   737                                                  uint16_t minVersion,
   738                                                  uint16_t intolerant)
   739 {
   740   nsCString key;
   741   getSiteKey(hostName, port, key);
   743   MutexAutoLock lock(mutex);
   745   if (intolerant <= minVersion) {
   746     // We can't fall back any further. Assume that intolerance isn't the issue.
   747     IntoleranceEntry entry;
   748     if (mTLSIntoleranceInfo.Get(key, &entry)) {
   749       entry.AssertInvariant();
   750       entry.intolerant = 0;
   751       entry.AssertInvariant();
   752       mTLSIntoleranceInfo.Put(key, entry);
   753     }
   755     return false;
   756   }
   758   IntoleranceEntry entry;
   759   if (mTLSIntoleranceInfo.Get(key, &entry)) {
   760     entry.AssertInvariant();
   761     if (intolerant <= entry.tolerant) {
   762       // We already know the server is tolerant at an equal or higher version.
   763       return false;
   764     }
   765     if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
   766       // We already know that the server is intolerant at a lower version.
   767       return true;
   768     }
   769   } else {
   770     entry.tolerant = 0;
   771   }
   773   entry.intolerant = intolerant;
   774   entry.AssertInvariant();
   775   mTLSIntoleranceInfo.Put(key, entry);
   777   return true;
   778 }
   780 void
   781 nsSSLIOLayerHelpers::adjustForTLSIntolerance(const nsACString& hostName,
   782                                              int16_t port,
   783                                              /*in/out*/ SSLVersionRange& range)
   784 {
   785   IntoleranceEntry entry;
   787   {
   788     nsCString key;
   789     getSiteKey(hostName, port, key);
   791     MutexAutoLock lock(mutex);
   792     if (!mTLSIntoleranceInfo.Get(key, &entry)) {
   793       return;
   794     }
   795   }
   797   entry.AssertInvariant();
   799   if (entry.intolerant != 0) {
   800     // We've tried connecting at a higher range but failed, so try at the
   801     // version we haven't tried yet, unless we have reached the minimum.
   802     if (range.min < entry.intolerant) {
   803       range.max = entry.intolerant - 1;
   804     }
   805   }
   806 }
   808 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
   809 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
   810 PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
   811 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
   812 PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
   814 static PRStatus
   815 nsSSLIOLayerClose(PRFileDesc* fd)
   816 {
   817   nsNSSShutDownPreventionLock locker;
   818   if (!fd)
   819     return PR_FAILURE;
   821   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n",
   822          (void*) fd));
   824   nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*) fd->secret;
   825   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
   827   return socketInfo->CloseSocketAndDestroy(locker);
   828 }
   830 PRStatus
   831 nsNSSSocketInfo::CloseSocketAndDestroy(
   832     const nsNSSShutDownPreventionLock& /*proofOfLock*/)
   833 {
   834   nsNSSShutDownList::trackSSLSocketClose();
   836   PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
   837   NS_ASSERTION(popped &&
   838                popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
   839                "SSL Layer not on top of stack");
   841   // The plain text layer is not always present - so its not a fatal error
   842   // if it cannot be removed
   843   PRFileDesc* poppedPlaintext =
   844     PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
   845   if (poppedPlaintext) {
   846     PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
   847     poppedPlaintext->dtor(poppedPlaintext);
   848   }
   850   PRStatus status = mFd->methods->close(mFd);
   852   // the nsNSSSocketInfo instance can out-live the connection, so we need some
   853   // indication that the connection has been closed. mFd == nullptr is that
   854   // indication. This is needed, for example, when the connection is closed
   855   // before we have finished validating the server's certificate.
   856   mFd = nullptr;
   858   if (status != PR_SUCCESS) return status;
   860   popped->identity = PR_INVALID_IO_LAYER;
   861   NS_RELEASE_THIS();
   862   popped->dtor(popped);
   864   return PR_SUCCESS;
   865 }
   867 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
   868 // Dumps a (potentially binary) buffer using SSM_DEBUG.  (We could have used
   869 // the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
   870 #define DUMPBUF_LINESIZE 24
   871 static void
   872 nsDumpBuffer(unsigned char* buf, int len)
   873 {
   874   char hexbuf[DUMPBUF_LINESIZE*3+1];
   875   char chrbuf[DUMPBUF_LINESIZE+1];
   876   static const char* hex = "0123456789abcdef";
   877   int i = 0;
   878   int l = 0;
   879   char ch;
   880   char* c;
   881   char* h;
   882   if (len == 0)
   883     return;
   884   hexbuf[DUMPBUF_LINESIZE*3] = '\0';
   885   chrbuf[DUMPBUF_LINESIZE] = '\0';
   886   (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
   887   (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
   888   h = hexbuf;
   889   c = chrbuf;
   891   while (i < len) {
   892     ch = buf[i];
   894     if (l == DUMPBUF_LINESIZE) {
   895       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
   896       (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
   897       (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
   898       h = hexbuf;
   899       c = chrbuf;
   900       l = 0;
   901     }
   903     // Convert a character to hex.
   904     *h++ = hex[(ch >> 4) & 0xf];
   905     *h++ = hex[ch & 0xf];
   906     h++;
   908     // Put the character (if it's printable) into the character buffer.
   909     if ((ch >= 0x20) && (ch <= 0x7e)) {
   910       *c++ = ch;
   911     } else {
   912       *c++ = '.';
   913     }
   914     i++; l++;
   915   }
   916   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
   917 }
   919 #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
   920 #else
   921 #define DEBUG_DUMP_BUFFER(buf,len)
   922 #endif
   924 class SSLErrorRunnable : public SyncRunnableBase
   925 {
   926  public:
   927   SSLErrorRunnable(nsNSSSocketInfo* infoObject,
   928                    ::mozilla::psm::SSLErrorMessageType errtype,
   929                    PRErrorCode errorCode)
   930     : mInfoObject(infoObject)
   931     , mErrType(errtype)
   932     , mErrorCode(errorCode)
   933   {
   934   }
   936   virtual void RunOnTargetThread()
   937   {
   938     nsHandleSSLError(mInfoObject, mErrType, mErrorCode);
   939   }
   941   RefPtr<nsNSSSocketInfo> mInfoObject;
   942   ::mozilla::psm::SSLErrorMessageType mErrType;
   943   const PRErrorCode mErrorCode;
   944 };
   946 namespace {
   948 bool
   949 retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
   950 {
   951   // This function is supposed to decide which error codes should
   952   // be used to conclude server is TLS intolerant.
   953   // Note this only happens during the initial SSL handshake.
   955   SSLVersionRange range = socketInfo->GetTLSVersionRange();
   957   uint32_t reason;
   958   switch (err) {
   959     case SSL_ERROR_BAD_MAC_ALERT: reason = 1; break;
   960     case SSL_ERROR_BAD_MAC_READ: reason = 2; break;
   961     case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: reason = 3; break;
   962     case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: reason = 4; break;
   963     case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE: reason = 5; break;
   964     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: reason = 6; break;
   965     case SSL_ERROR_NO_CYPHER_OVERLAP: reason = 7; break;
   966     case SSL_ERROR_BAD_SERVER: reason = 8; break;
   967     case SSL_ERROR_BAD_BLOCK_PADDING: reason = 9; break;
   968     case SSL_ERROR_UNSUPPORTED_VERSION: reason = 10; break;
   969     case SSL_ERROR_PROTOCOL_VERSION_ALERT: reason = 11; break;
   970     case SSL_ERROR_RX_MALFORMED_FINISHED: reason = 12; break;
   971     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: reason = 13; break;
   972     case SSL_ERROR_DECODE_ERROR_ALERT: reason = 14; break;
   973     case SSL_ERROR_RX_UNKNOWN_ALERT: reason = 15; break;
   975     case PR_CONNECT_RESET_ERROR: reason = 16; goto conditional;
   976     case PR_END_OF_FILE_ERROR: reason = 17; goto conditional;
   978       // When not using a proxy we'll see a connection reset error.
   979       // When using a proxy, we'll see an end of file error.
   980       // In addition check for some error codes where it is reasonable
   981       // to retry without TLS.
   983       // Don't allow STARTTLS connections to fall back on connection resets or
   984       // EOF. Also, don't fall back from TLS 1.0 to SSL 3.0 for connection
   985       // resets, because connection resets have too many false positives,
   986       // and we want to maximize how often we send TLS 1.0+ with extensions
   987       // if at all reasonable. Unfortunately, it appears we have to allow
   988       // fallback from TLS 1.2 and TLS 1.1 for connection resets due to bad
   989       // servers and possibly bad intermediaries.
   990     conditional:
   991       if ((err == PR_CONNECT_RESET_ERROR &&
   992            range.max <= SSL_LIBRARY_VERSION_TLS_1_0) ||
   993           socketInfo->GetForSTARTTLS()) {
   994         return false;
   995       }
   996       break;
   998     default:
   999       return false;
  1002   Telemetry::ID pre;
  1003   Telemetry::ID post;
  1004   switch (range.max) {
  1005     case SSL_LIBRARY_VERSION_TLS_1_2:
  1006       pre = Telemetry::SSL_TLS12_INTOLERANCE_REASON_PRE;
  1007       post = Telemetry::SSL_TLS12_INTOLERANCE_REASON_POST;
  1008       break;
  1009     case SSL_LIBRARY_VERSION_TLS_1_1:
  1010       pre = Telemetry::SSL_TLS11_INTOLERANCE_REASON_PRE;
  1011       post = Telemetry::SSL_TLS11_INTOLERANCE_REASON_POST;
  1012       break;
  1013     case SSL_LIBRARY_VERSION_TLS_1_0:
  1014       pre = Telemetry::SSL_TLS10_INTOLERANCE_REASON_PRE;
  1015       post = Telemetry::SSL_TLS10_INTOLERANCE_REASON_POST;
  1016       break;
  1017     case SSL_LIBRARY_VERSION_3_0:
  1018       pre = Telemetry::SSL_SSL30_INTOLERANCE_REASON_PRE;
  1019       post = Telemetry::SSL_SSL30_INTOLERANCE_REASON_POST;
  1020       break;
  1021     default:
  1022       MOZ_CRASH("impossible TLS version");
  1023       return false;
  1026   // The difference between _PRE and _POST represents how often we avoided
  1027   // TLS intolerance fallback due to remembered tolerance.
  1028   Telemetry::Accumulate(pre, reason);
  1030   if (!socketInfo->SharedState().IOLayerHelpers()
  1031                  .rememberIntolerantAtVersion(socketInfo->GetHostName(),
  1032                                               socketInfo->GetPort(),
  1033                                               range.min, range.max)) {
  1034     return false;
  1037   Telemetry::Accumulate(post, reason);
  1039   return true;
  1042 int32_t
  1043 checkHandshake(int32_t bytesTransfered, bool wasReading,
  1044                PRFileDesc* ssl_layer_fd, nsNSSSocketInfo* socketInfo)
  1046   const PRErrorCode originalError = PR_GetError();
  1047   PRErrorCode err = originalError;
  1049   // This is where we work around all of those SSL servers that don't
  1050   // conform to the SSL spec and shutdown a connection when we request
  1051   // SSL v3.1 (aka TLS).  The spec says the client says what version
  1052   // of the protocol we're willing to perform, in our case SSL v3.1
  1053   // In its response, the server says which version it wants to perform.
  1054   // Many servers out there only know how to do v3.0.  Next, we're supposed
  1055   // to send back the version of the protocol we requested (ie v3.1).  At
  1056   // this point many servers's implementations are broken and they shut
  1057   // down the connection when they don't see the version they sent back.
  1058   // This is supposed to prevent a man in the middle from forcing one
  1059   // side to dumb down to a lower level of the protocol.  Unfortunately,
  1060   // there are enough broken servers out there that such a gross work-around
  1061   // is necessary.  :(
  1063   // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
  1064   // Simply retry.
  1065   // This depends on the fact that Cert UI will not be shown again,
  1066   // should the user override the bad cert.
  1068   bool handleHandshakeResultNow = socketInfo->IsHandshakePending();
  1070   bool wantRetry = false;
  1072   if (0 > bytesTransfered) {
  1073     if (handleHandshakeResultNow) {
  1074       if (PR_WOULD_BLOCK_ERROR == err) {
  1075         PR_SetError(err, 0);
  1076         return bytesTransfered;
  1079       wantRetry = retryDueToTLSIntolerance(err, socketInfo);
  1082     // This is the common place where we trigger non-cert-errors on a SSL
  1083     // socket. This might be reached at any time of the connection.
  1084     //
  1085     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
  1086     // do the synchronous dispatch to the main thread unnecessarily after we've
  1087     // already handled a certificate error. (SSLErrorRunnable calls
  1088     // nsHandleSSLError, which has logic to avoid replacing the error message,
  1089     // so without the !socketInfo->GetErrorCode(), it would just be an
  1090     // expensive no-op.)
  1091     if (!wantRetry && (IS_SSL_ERROR(err) || IS_SEC_ERROR(err)) &&
  1092         !socketInfo->GetErrorCode()) {
  1093       RefPtr<SyncRunnableBase> runnable(new SSLErrorRunnable(socketInfo,
  1094                                                              PlainErrorMessage,
  1095                                                              err));
  1096       (void) runnable->DispatchToMainThreadAndWait();
  1098   } else if (wasReading && 0 == bytesTransfered) {
  1099     // zero bytes on reading, socket closed
  1100     if (handleHandshakeResultNow) {
  1101       wantRetry = retryDueToTLSIntolerance(PR_END_OF_FILE_ERROR, socketInfo);
  1105   if (wantRetry) {
  1106     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1107            ("[%p] checkHandshake: will retry with lower max TLS version\n",
  1108             ssl_layer_fd));
  1109     // We want to cause the network layer to retry the connection.
  1110     err = PR_CONNECT_RESET_ERROR;
  1111     if (wasReading)
  1112       bytesTransfered = -1;
  1115   // TLS intolerant servers only cause the first transfer to fail, so let's
  1116   // set the HandshakePending attribute to false so that we don't try the logic
  1117   // above again in a subsequent transfer.
  1118   if (handleHandshakeResultNow) {
  1119     socketInfo->SetHandshakeNotPending();
  1122   if (bytesTransfered < 0) {
  1123     // Remember that we encountered an error so that getSocketInfoIfRunning
  1124     // will correctly cause us to fail if another part of Gecko
  1125     // (erroneously) calls an I/O function (PR_Send/PR_Recv/etc.) again on
  1126     // this socket. Note that we use the original error because if we use
  1127     // PR_CONNECT_RESET_ERROR, we'll repeated try to reconnect.
  1128     if (originalError != PR_WOULD_BLOCK_ERROR && !socketInfo->GetErrorCode()) {
  1129       socketInfo->SetCanceled(originalError, PlainErrorMessage);
  1131     PR_SetError(err, 0);
  1134   return bytesTransfered;
  1139 static int16_t
  1140 nsSSLIOLayerPoll(PRFileDesc* fd, int16_t in_flags, int16_t* out_flags)
  1142   nsNSSShutDownPreventionLock locker;
  1144   if (!out_flags) {
  1145     NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
  1146     return 0;
  1149   *out_flags = 0;
  1151   nsNSSSocketInfo* socketInfo =
  1152     getSocketInfoIfRunning(fd, not_reading_or_writing, locker);
  1154   if (!socketInfo) {
  1155     // If we get here, it is probably because certificate validation failed
  1156     // and this is the first I/O operation after the failure.
  1157     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1158             ("[%p] polling SSL socket right after certificate verification failed "
  1159                   "or NSS shutdown or SDR logout %d\n",
  1160              fd, (int) in_flags));
  1162     NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
  1163                  "caller did not poll for EXCEPT (canceled)");
  1164     // Since this poll method cannot return errors, we want the caller to call
  1165     // PR_Send/PR_Recv right away to get the error, so we tell that we are
  1166     // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
  1167     *out_flags = in_flags | PR_POLL_EXCEPT; // see also bug 480619
  1168     return in_flags;
  1171   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1172          (socketInfo->IsWaitingForCertVerification()
  1173             ?  "[%p] polling SSL socket during certificate verification using lower %d\n"
  1174             :  "[%p] poll SSL socket using lower %d\n",
  1175          fd, (int) in_flags));
  1177   // We want the handshake to continue during certificate validation, so we
  1178   // don't need to do anything special here. libssl automatically blocks when
  1179   // it reaches any point that would be unsafe to send/receive something before
  1180   // cert validation is complete.
  1181   int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
  1182   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
  1183                                     (void*) fd, (int) result));
  1184   return result;
  1187 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
  1188   : mRenegoUnrestrictedSites(nullptr)
  1189   , mTreatUnsafeNegotiationAsBroken(false)
  1190   , mWarnLevelMissingRFC5746(1)
  1191   , mTLSIntoleranceInfo(16)
  1192   , mFalseStartRequireNPN(true)
  1193   , mFalseStartRequireForwardSecrecy(false)
  1194   , mutex("nsSSLIOLayerHelpers.mutex")
  1198 static int
  1199 _PSM_InvalidInt(void)
  1201     PR_ASSERT(!"I/O method is invalid");
  1202     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  1203     return -1;
  1206 static int64_t
  1207 _PSM_InvalidInt64(void)
  1209     PR_ASSERT(!"I/O method is invalid");
  1210     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  1211     return -1;
  1214 static PRStatus
  1215 _PSM_InvalidStatus(void)
  1217     PR_ASSERT(!"I/O method is invalid");
  1218     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  1219     return PR_FAILURE;
  1222 static PRFileDesc*
  1223 _PSM_InvalidDesc(void)
  1225     PR_ASSERT(!"I/O method is invalid");
  1226     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  1227     return nullptr;
  1230 static PRStatus
  1231 PSMGetsockname(PRFileDesc* fd, PRNetAddr* addr)
  1233   nsNSSShutDownPreventionLock locker;
  1234   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
  1235     return PR_FAILURE;
  1237   return fd->lower->methods->getsockname(fd->lower, addr);
  1240 static PRStatus
  1241 PSMGetpeername(PRFileDesc* fd, PRNetAddr* addr)
  1243   nsNSSShutDownPreventionLock locker;
  1244   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
  1245     return PR_FAILURE;
  1247   return fd->lower->methods->getpeername(fd->lower, addr);
  1250 static PRStatus
  1251 PSMGetsocketoption(PRFileDesc* fd, PRSocketOptionData* data)
  1253   nsNSSShutDownPreventionLock locker;
  1254   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
  1255     return PR_FAILURE;
  1257   return fd->lower->methods->getsocketoption(fd, data);
  1260 static PRStatus
  1261 PSMSetsocketoption(PRFileDesc* fd, const PRSocketOptionData* data)
  1263   nsNSSShutDownPreventionLock locker;
  1264   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
  1265     return PR_FAILURE;
  1267   return fd->lower->methods->setsocketoption(fd, data);
  1270 static int32_t
  1271 PSMRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
  1272         PRIntervalTime timeout)
  1274   nsNSSShutDownPreventionLock locker;
  1275   nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, reading, locker);
  1276   if (!socketInfo)
  1277     return -1;
  1279   if (flags != PR_MSG_PEEK && flags != 0) {
  1280     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1281     return -1;
  1284   int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
  1285                                                timeout);
  1287   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*) fd,
  1288          bytesRead));
  1290 #ifdef DEBUG_SSL_VERBOSE
  1291   DEBUG_DUMP_BUFFER((unsigned char*) buf, bytesRead);
  1292 #endif
  1294   return checkHandshake(bytesRead, true, fd, socketInfo);
  1297 static int32_t
  1298 PSMSend(PRFileDesc* fd, const void* buf, int32_t amount, int flags,
  1299         PRIntervalTime timeout)
  1301   nsNSSShutDownPreventionLock locker;
  1302   nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, writing, locker);
  1303   if (!socketInfo)
  1304     return -1;
  1306   if (flags != 0) {
  1307     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1308     return -1;
  1311 #ifdef DEBUG_SSL_VERBOSE
  1312   DEBUG_DUMP_BUFFER((unsigned char*) buf, amount);
  1313 #endif
  1315   int32_t bytesWritten = fd->lower->methods->send(fd->lower, buf, amount,
  1316                                                   flags, timeout);
  1318   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n",
  1319          fd, bytesWritten));
  1321   return checkHandshake(bytesWritten, false, fd, socketInfo);
  1324 static int32_t
  1325 nsSSLIOLayerRead(PRFileDesc* fd, void* buf, int32_t amount)
  1327   return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  1330 static int32_t
  1331 nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, int32_t amount)
  1333   return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  1336 static PRStatus
  1337 PSMConnectcontinue(PRFileDesc* fd, int16_t out_flags)
  1339   nsNSSShutDownPreventionLock locker;
  1340   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker)) {
  1341     return PR_FAILURE;
  1344   return fd->lower->methods->connectcontinue(fd, out_flags);
  1347 static int
  1348 PSMAvailable(void)
  1350   // This is called through PR_Available(), but is not implemented in PSM
  1351   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1352   return -1;
  1355 static int64_t
  1356 PSMAvailable64(void)
  1358   // This is called through PR_Available(), but is not implemented in PSM
  1359   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1360   return -1;
  1363 namespace {
  1365 class PrefObserver : public nsIObserver {
  1366 public:
  1367   NS_DECL_THREADSAFE_ISUPPORTS
  1368   NS_DECL_NSIOBSERVER
  1369   PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
  1370   virtual ~PrefObserver() {}
  1371 private:
  1372   nsSSLIOLayerHelpers* mOwner;
  1373 };
  1375 } // unnamed namespace
  1377 NS_IMPL_ISUPPORTS(PrefObserver, nsIObserver)
  1379 NS_IMETHODIMP
  1380 PrefObserver::Observe(nsISupports* aSubject, const char* aTopic,
  1381                       const char16_t* someData)
  1383   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
  1384     NS_ConvertUTF16toUTF8 prefName(someData);
  1386     if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
  1387       nsCString unrestricted_hosts;
  1388       Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
  1389       if (!unrestricted_hosts.IsEmpty()) {
  1390         mOwner->setRenegoUnrestrictedSites(unrestricted_hosts);
  1392     } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
  1393       bool enabled;
  1394       Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
  1395       mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
  1396     } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
  1397       int32_t warnLevel = 1;
  1398       Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
  1399       mOwner->setWarnLevelMissingRFC5746(warnLevel);
  1400     } else if (prefName.Equals("security.ssl.false_start.require-npn")) {
  1401       mOwner->mFalseStartRequireNPN =
  1402         Preferences::GetBool("security.ssl.false_start.require-npn",
  1403                              FALSE_START_REQUIRE_NPN_DEFAULT);
  1404     } else if (prefName.Equals("security.ssl.false_start.require-forward-secrecy")) {
  1405       mOwner->mFalseStartRequireForwardSecrecy =
  1406         Preferences::GetBool("security.ssl.false_start.require-forward-secrecy",
  1407                              FALSE_START_REQUIRE_FORWARD_SECRECY_DEFAULT);
  1410   return NS_OK;
  1413 static int32_t
  1414 PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
  1415               PRIntervalTime timeout)
  1417   // The shutdownlocker is not needed here because it will already be
  1418   // held higher in the stack
  1419   nsNSSSocketInfo* socketInfo = nullptr;
  1421   int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
  1422                                                timeout);
  1423   if (fd->identity == nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)
  1424     socketInfo = (nsNSSSocketInfo*) fd->secret;
  1426   if ((bytesRead > 0) && socketInfo)
  1427     socketInfo->AddPlaintextBytesRead(bytesRead);
  1428   return bytesRead;
  1431 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
  1433   // mPrefObserver will only be set if this->Init was called. The GTest tests
  1434   // do not call Init.
  1435   if (mPrefObserver) {
  1436     Preferences::RemoveObserver(mPrefObserver,
  1437       "security.ssl.renego_unrestricted_hosts");
  1438     Preferences::RemoveObserver(mPrefObserver,
  1439         "security.ssl.treat_unsafe_negotiation_as_broken");
  1440     Preferences::RemoveObserver(mPrefObserver,
  1441         "security.ssl.warn_missing_rfc5746");
  1442     Preferences::RemoveObserver(mPrefObserver,
  1443         "security.ssl.false_start.require-npn");
  1444     Preferences::RemoveObserver(mPrefObserver,
  1445         "security.ssl.false_start.require-forward-secrecy");
  1449 nsresult
  1450 nsSSLIOLayerHelpers::Init()
  1452   if (!nsSSLIOLayerInitialized) {
  1453     nsSSLIOLayerInitialized = true;
  1454     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
  1455     nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
  1457     nsSSLIOLayerMethods.available = (PRAvailableFN) PSMAvailable;
  1458     nsSSLIOLayerMethods.available64 = (PRAvailable64FN) PSMAvailable64;
  1459     nsSSLIOLayerMethods.fsync = (PRFsyncFN) _PSM_InvalidStatus;
  1460     nsSSLIOLayerMethods.seek = (PRSeekFN) _PSM_InvalidInt;
  1461     nsSSLIOLayerMethods.seek64 = (PRSeek64FN) _PSM_InvalidInt64;
  1462     nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN) _PSM_InvalidStatus;
  1463     nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN) _PSM_InvalidStatus;
  1464     nsSSLIOLayerMethods.writev = (PRWritevFN) _PSM_InvalidInt;
  1465     nsSSLIOLayerMethods.accept = (PRAcceptFN) _PSM_InvalidDesc;
  1466     nsSSLIOLayerMethods.bind = (PRBindFN) _PSM_InvalidStatus;
  1467     nsSSLIOLayerMethods.listen = (PRListenFN) _PSM_InvalidStatus;
  1468     nsSSLIOLayerMethods.shutdown = (PRShutdownFN) _PSM_InvalidStatus;
  1469     nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN) _PSM_InvalidInt;
  1470     nsSSLIOLayerMethods.sendto = (PRSendtoFN) _PSM_InvalidInt;
  1471     nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN) _PSM_InvalidInt;
  1472     nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN) _PSM_InvalidInt;
  1473     nsSSLIOLayerMethods.sendfile = (PRSendfileFN) _PSM_InvalidInt;
  1475     nsSSLIOLayerMethods.getsockname = PSMGetsockname;
  1476     nsSSLIOLayerMethods.getpeername = PSMGetpeername;
  1477     nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
  1478     nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
  1479     nsSSLIOLayerMethods.recv = PSMRecv;
  1480     nsSSLIOLayerMethods.send = PSMSend;
  1481     nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
  1483     nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
  1484     nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
  1485     nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
  1486     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
  1487     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
  1489     nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
  1490     nsSSLPlaintextLayerMethods  = *PR_GetDefaultIOMethods();
  1491     nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
  1494   mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>(16);
  1496   nsCString unrestricted_hosts;
  1497   Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
  1498   if (!unrestricted_hosts.IsEmpty()) {
  1499     setRenegoUnrestrictedSites(unrestricted_hosts);
  1502   bool enabled = false;
  1503   Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
  1504   setTreatUnsafeNegotiationAsBroken(enabled);
  1506   int32_t warnLevel = 1;
  1507   Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
  1508   setWarnLevelMissingRFC5746(warnLevel);
  1510   mFalseStartRequireNPN =
  1511     Preferences::GetBool("security.ssl.false_start.require-npn",
  1512                          FALSE_START_REQUIRE_NPN_DEFAULT);
  1513   mFalseStartRequireForwardSecrecy =
  1514     Preferences::GetBool("security.ssl.false_start.require-forward-secrecy",
  1515                          FALSE_START_REQUIRE_FORWARD_SECRECY_DEFAULT);
  1517   mPrefObserver = new PrefObserver(this);
  1518   Preferences::AddStrongObserver(mPrefObserver,
  1519                                  "security.ssl.renego_unrestricted_hosts");
  1520   Preferences::AddStrongObserver(mPrefObserver,
  1521                                  "security.ssl.treat_unsafe_negotiation_as_broken");
  1522   Preferences::AddStrongObserver(mPrefObserver,
  1523                                  "security.ssl.warn_missing_rfc5746");
  1524   Preferences::AddStrongObserver(mPrefObserver,
  1525                                  "security.ssl.false_start.require-npn");
  1526   Preferences::AddStrongObserver(mPrefObserver,
  1527                                  "security.ssl.false_start.require-forward-secrecy");
  1528   return NS_OK;
  1531 void
  1532 nsSSLIOLayerHelpers::clearStoredData()
  1534   mRenegoUnrestrictedSites->Clear();
  1535   mTLSIntoleranceInfo.Clear();
  1538 void
  1539 nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString& str)
  1541   MutexAutoLock lock(mutex);
  1543   if (mRenegoUnrestrictedSites) {
  1544     delete mRenegoUnrestrictedSites;
  1545     mRenegoUnrestrictedSites = nullptr;
  1548   mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
  1549   if (!mRenegoUnrestrictedSites)
  1550     return;
  1552   nsCCharSeparatedTokenizer toker(str, ',');
  1554   while (toker.hasMoreTokens()) {
  1555     const nsCSubstring& host = toker.nextToken();
  1556     if (!host.IsEmpty()) {
  1557       mRenegoUnrestrictedSites->PutEntry(host);
  1562 bool
  1563 nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString& str)
  1565   MutexAutoLock lock(mutex);
  1566   return mRenegoUnrestrictedSites->Contains(str);
  1569 void
  1570 nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
  1572   MutexAutoLock lock(mutex);
  1573   mTreatUnsafeNegotiationAsBroken = broken;
  1576 bool
  1577 nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
  1579   MutexAutoLock lock(mutex);
  1580   return mTreatUnsafeNegotiationAsBroken;
  1583 void
  1584 nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(int32_t level)
  1586   MutexAutoLock lock(mutex);
  1587   mWarnLevelMissingRFC5746 = level;
  1590 int32_t
  1591 nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746()
  1593   MutexAutoLock lock(mutex);
  1594   return mWarnLevelMissingRFC5746;
  1597 nsresult
  1598 nsSSLIOLayerNewSocket(int32_t family,
  1599                       const char* host,
  1600                       int32_t port,
  1601                       nsIProxyInfo *proxy,
  1602                       PRFileDesc** fd,
  1603                       nsISupports** info,
  1604                       bool forSTARTTLS,
  1605                       uint32_t flags)
  1608   PRFileDesc* sock = PR_OpenTCPSocket(family);
  1609   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
  1611   nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxy,
  1612                                         sock, info, forSTARTTLS, flags);
  1613   if (NS_FAILED(rv)) {
  1614     PR_Close(sock);
  1615     return rv;
  1618   *fd = sock;
  1619   return NS_OK;
  1622 // Creates CA names strings from (CERTDistNames* caNames)
  1623 //
  1624 // - arena: arena to allocate strings on
  1625 // - caNameStrings: filled with CA names strings on return
  1626 // - caNames: CERTDistNames to extract strings from
  1627 // - return: SECSuccess if successful; error code otherwise
  1628 //
  1629 // Note: copied in its entirety from Nova code
  1630 static SECStatus
  1631 nsConvertCANamesToStrings(PLArenaPool* arena, char** caNameStrings,
  1632                           CERTDistNames* caNames)
  1634     SECItem* dername;
  1635     SECStatus rv;
  1636     int headerlen;
  1637     uint32_t contentlen;
  1638     SECItem newitem;
  1639     int n;
  1640     char* namestring;
  1642     for (n = 0; n < caNames->nnames; n++) {
  1643         newitem.data = nullptr;
  1644         dername = &caNames->names[n];
  1646         rv = DER_Lengths(dername, &headerlen, &contentlen);
  1648         if (rv != SECSuccess) {
  1649             goto loser;
  1652         if (headerlen + contentlen != dername->len) {
  1653             // This must be from an enterprise 2.x server, which sent
  1654             // incorrectly formatted der without the outer wrapper of type and
  1655             // length. Fix it up by adding the top level header.
  1656             if (dername->len <= 127) {
  1657                 newitem.data = (unsigned char*) PR_Malloc(dername->len + 2);
  1658                 if (!newitem.data) {
  1659                     goto loser;
  1661                 newitem.data[0] = (unsigned char) 0x30;
  1662                 newitem.data[1] = (unsigned char) dername->len;
  1663                 (void) memcpy(&newitem.data[2], dername->data, dername->len);
  1664             } else if (dername->len <= 255) {
  1665                 newitem.data = (unsigned char*) PR_Malloc(dername->len + 3);
  1666                 if (!newitem.data) {
  1667                     goto loser;
  1669                 newitem.data[0] = (unsigned char) 0x30;
  1670                 newitem.data[1] = (unsigned char) 0x81;
  1671                 newitem.data[2] = (unsigned char) dername->len;
  1672                 (void) memcpy(&newitem.data[3], dername->data, dername->len);
  1673             } else {
  1674                 // greater than 256, better be less than 64k
  1675                 newitem.data = (unsigned char*) PR_Malloc(dername->len + 4);
  1676                 if (!newitem.data) {
  1677                     goto loser;
  1679                 newitem.data[0] = (unsigned char) 0x30;
  1680                 newitem.data[1] = (unsigned char) 0x82;
  1681                 newitem.data[2] = (unsigned char) ((dername->len >> 8) & 0xff);
  1682                 newitem.data[3] = (unsigned char) (dername->len & 0xff);
  1683                 memcpy(&newitem.data[4], dername->data, dername->len);
  1685             dername = &newitem;
  1688         namestring = CERT_DerNameToAscii(dername);
  1689         if (!namestring) {
  1690             // XXX - keep going until we fail to convert the name
  1691             caNameStrings[n] = const_cast<char*>("");
  1692         } else {
  1693             caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
  1694             PR_Free(namestring);
  1695             if (!caNameStrings[n]) {
  1696                 goto loser;
  1700         if (newitem.data) {
  1701             PR_Free(newitem.data);
  1705     return SECSuccess;
  1706 loser:
  1707     if (newitem.data) {
  1708         PR_Free(newitem.data);
  1710     return SECFailure;
  1713 // Sets certChoice by reading the preference
  1714 //
  1715 // If done properly, this function will read the identifier strings for ASK and
  1716 // AUTO modes read the selected strings from the preference, compare the
  1717 // strings, and determine in which mode it is in. We currently use ASK mode for
  1718 // UI apps and AUTO mode for UI-less apps without really asking for
  1719 // preferences.
  1720 nsresult
  1721 nsGetUserCertChoice(SSM_UserCertChoice* certChoice)
  1723   char* mode = nullptr;
  1724   nsresult ret;
  1726   NS_ENSURE_ARG_POINTER(certChoice);
  1728   nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
  1730   ret = pref->GetCharPref("security.default_personal_cert", &mode);
  1731   if (NS_FAILED(ret)) {
  1732     goto loser;
  1735   if (PL_strcmp(mode, "Select Automatically") == 0) {
  1736     *certChoice = AUTO;
  1737   } else if (PL_strcmp(mode, "Ask Every Time") == 0) {
  1738     *certChoice = ASK;
  1739   } else {
  1740     // Most likely we see a nickname from a migrated cert.
  1741     // We do not currently support that, ask the user which cert to use.
  1742     *certChoice = ASK;
  1745 loser:
  1746   if (mode) {
  1747     nsMemory::Free(mode);
  1749   return ret;
  1752 static bool
  1753 hasExplicitKeyUsageNonRepudiation(CERTCertificate* cert)
  1755   // There is no extension, v1 or v2 certificate
  1756   if (!cert->extensions)
  1757     return false;
  1759   SECStatus srv;
  1760   SECItem keyUsageItem;
  1761   keyUsageItem.data = nullptr;
  1763   srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
  1764   if (srv == SECFailure)
  1765     return false;
  1767   unsigned char keyUsage = keyUsageItem.data[0];
  1768   PORT_Free (keyUsageItem.data);
  1770   return !!(keyUsage & KU_NON_REPUDIATION);
  1773 class ClientAuthDataRunnable : public SyncRunnableBase
  1775 public:
  1776   ClientAuthDataRunnable(CERTDistNames* caNames,
  1777                          CERTCertificate** pRetCert,
  1778                          SECKEYPrivateKey** pRetKey,
  1779                          nsNSSSocketInfo* info,
  1780                          CERTCertificate* serverCert)
  1781     : mRV(SECFailure)
  1782     , mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
  1783     , mPRetCert(pRetCert)
  1784     , mPRetKey(pRetKey)
  1785     , mCANames(caNames)
  1786     , mSocketInfo(info)
  1787     , mServerCert(serverCert)
  1791   SECStatus mRV;                        // out
  1792   PRErrorCode mErrorCodeToReport;       // out
  1793   CERTCertificate** const mPRetCert;    // in/out
  1794   SECKEYPrivateKey** const mPRetKey;    // in/out
  1795 protected:
  1796   virtual void RunOnTargetThread();
  1797 private:
  1798   CERTDistNames* const mCANames;        // in
  1799   nsNSSSocketInfo* const mSocketInfo;   // in
  1800   CERTCertificate* const mServerCert;   // in
  1801 };
  1803 // This callback function is used to pull client certificate
  1804 // information upon server request
  1805 //
  1806 // - arg: SSL data connection
  1807 // - socket: SSL socket we're dealing with
  1808 // - caNames: list of CA names
  1809 // - pRetCert: returns a pointer to a pointer to a valid certificate if
  1810 //             successful; otherwise nullptr
  1811 // - pRetKey: returns a pointer to a pointer to the corresponding key if
  1812 //            successful; otherwise nullptr
  1813 SECStatus
  1814 nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
  1815                            CERTDistNames* caNames, CERTCertificate** pRetCert,
  1816                            SECKEYPrivateKey** pRetKey)
  1818   nsNSSShutDownPreventionLock locker;
  1820   if (!socket || !caNames || !pRetCert || !pRetKey) {
  1821     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1822     return SECFailure;
  1825   RefPtr<nsNSSSocketInfo> info(
  1826     reinterpret_cast<nsNSSSocketInfo*>(socket->higher->secret));
  1828   CERTCertificate* serverCert = SSL_PeerCertificate(socket);
  1829   if (!serverCert) {
  1830     NS_NOTREACHED("Missing server certificate should have been detected during "
  1831                   "server cert authentication.");
  1832     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
  1833     return SECFailure;
  1836   if (info->GetJoined()) {
  1837     // We refuse to send a client certificate when there are multiple hostnames
  1838     // joined on this connection, because we only show the user one hostname
  1839     // (mHostName) in the client certificate UI.
  1841     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  1842            ("[%p] Not returning client cert due to previous join\n", socket));
  1843     *pRetCert = nullptr;
  1844     *pRetKey = nullptr;
  1845     return SECSuccess;
  1848   // XXX: This should be done asynchronously; see bug 696976
  1849   RefPtr<ClientAuthDataRunnable> runnable(
  1850     new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert));
  1851   nsresult rv = runnable->DispatchToMainThreadAndWait();
  1852   if (NS_FAILED(rv)) {
  1853     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
  1854     return SECFailure;
  1857   if (runnable->mRV != SECSuccess) {
  1858     PR_SetError(runnable->mErrorCodeToReport, 0);
  1859   } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
  1860     // Make joinConnection prohibit joining after we've sent a client cert
  1861     info->SetSentClientCert();
  1864   return runnable->mRV;
  1867 void
  1868 ClientAuthDataRunnable::RunOnTargetThread()
  1870   PLArenaPool* arena = nullptr;
  1871   char** caNameStrings;
  1872   mozilla::pkix::ScopedCERTCertificate cert;
  1873   ScopedSECKEYPrivateKey privKey;
  1874   mozilla::pkix::ScopedCERTCertList certList;
  1875   CERTCertListNode* node;
  1876   ScopedCERTCertNicknames nicknames;
  1877   int keyError = 0; // used for private key retrieval error
  1878   SSM_UserCertChoice certChoice;
  1879   int32_t NumberOfCerts = 0;
  1880   void* wincx = mSocketInfo;
  1881   nsresult rv;
  1883   // create caNameStrings
  1884   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1885   if (!arena) {
  1886     goto loser;
  1889   caNameStrings = (char**) PORT_ArenaAlloc(arena,
  1890                                            sizeof(char*) * (mCANames->nnames));
  1891   if (!caNameStrings) {
  1892     goto loser;
  1895   mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
  1896   if (mRV != SECSuccess) {
  1897     goto loser;
  1900   // get the preference
  1901   if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
  1902     goto loser;
  1905   // find valid user cert and key pair
  1906   if (certChoice == AUTO) {
  1907     // automatically find the right cert
  1909     // find all user certs that are valid and for SSL
  1910     certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
  1911                                          certUsageSSLClient, false,
  1912                                          true, wincx);
  1913     if (!certList) {
  1914       goto noCert;
  1917     // filter the list to those issued by CAs supported by the server
  1918     mRV = CERT_FilterCertListByCANames(certList.get(), mCANames->nnames,
  1919                                        caNameStrings, certUsageSSLClient);
  1920     if (mRV != SECSuccess) {
  1921       goto noCert;
  1924     // make sure the list is not empty
  1925     node = CERT_LIST_HEAD(certList);
  1926     if (CERT_LIST_END(node, certList)) {
  1927       goto noCert;
  1930     ScopedCERTCertificate low_prio_nonrep_cert;
  1932     // loop through the list until we find a cert with a key
  1933     while (!CERT_LIST_END(node, certList)) {
  1934       // if the certificate has restriction and we do not satisfy it we do not
  1935       // use it
  1936       privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
  1937       if (privKey) {
  1938         if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
  1939           privKey = nullptr;
  1940           // Not a prefered cert
  1941           if (!low_prio_nonrep_cert) { // did not yet find a low prio cert
  1942             low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
  1944         } else {
  1945           // this is a good cert to present
  1946           cert = CERT_DupCertificate(node->cert);
  1947           break;
  1950       keyError = PR_GetError();
  1951       if (keyError == SEC_ERROR_BAD_PASSWORD) {
  1952         // problem with password: bail
  1953         goto loser;
  1956       node = CERT_LIST_NEXT(node);
  1959     if (!cert && low_prio_nonrep_cert) {
  1960       cert = low_prio_nonrep_cert.forget();
  1961       privKey = PK11_FindKeyByAnyCert(cert.get(), wincx);
  1964     if (!cert) {
  1965       goto noCert;
  1967   } else { // Not Auto => ask
  1968     // Get the SSL Certificate
  1970     nsXPIDLCString hostname;
  1971     mSocketInfo->GetHostName(getter_Copies(hostname));
  1973     RefPtr<nsClientAuthRememberService> cars =
  1974       mSocketInfo->SharedState().GetClientAuthRememberService();
  1976     bool hasRemembered = false;
  1977     nsCString rememberedDBKey;
  1978     if (cars) {
  1979       bool found;
  1980       rv = cars->HasRememberedDecision(hostname, mServerCert,
  1981         rememberedDBKey, &found);
  1982       if (NS_SUCCEEDED(rv) && found) {
  1983         hasRemembered = true;
  1987     bool canceled = false;
  1989     if (hasRemembered) {
  1990       if (rememberedDBKey.IsEmpty()) {
  1991         canceled = true;
  1992       } else {
  1993         nsCOMPtr<nsIX509CertDB> certdb;
  1994         certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
  1995         if (certdb) {
  1996           nsCOMPtr<nsIX509Cert> found_cert;
  1997           nsresult find_rv =
  1998             certdb->FindCertByDBKey(rememberedDBKey.get(), nullptr,
  1999             getter_AddRefs(found_cert));
  2000           if (NS_SUCCEEDED(find_rv) && found_cert) {
  2001             nsNSSCertificate* obj_cert =
  2002               reinterpret_cast<nsNSSCertificate*>(found_cert.get());
  2003             if (obj_cert) {
  2004               cert = obj_cert->GetCert();
  2008           if (!cert) {
  2009             hasRemembered = false;
  2015     if (!hasRemembered) {
  2016       // user selects a cert to present
  2017       nsIClientAuthDialogs* dialogs = nullptr;
  2018       int32_t selectedIndex = -1;
  2019       char16_t** certNicknameList = nullptr;
  2020       char16_t** certDetailsList = nullptr;
  2022       // find all user certs that are for SSL
  2023       // note that we are allowing expired certs in this list
  2024       certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
  2025         certUsageSSLClient, false,
  2026         false, wincx);
  2027       if (!certList) {
  2028         goto noCert;
  2031       if (mCANames->nnames != 0) {
  2032         // filter the list to those issued by CAs supported by the server
  2033         mRV = CERT_FilterCertListByCANames(certList.get(),
  2034                                            mCANames->nnames,
  2035                                            caNameStrings,
  2036                                            certUsageSSLClient);
  2037         if (mRV != SECSuccess) {
  2038           goto loser;
  2042       if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
  2043         // list is empty - no matching certs
  2044         goto noCert;
  2047       // filter it further for hostname restriction
  2048       node = CERT_LIST_HEAD(certList.get());
  2049       while (!CERT_LIST_END(node, certList.get())) {
  2050         ++NumberOfCerts;
  2051         node = CERT_LIST_NEXT(node);
  2053       if (CERT_LIST_END(CERT_LIST_HEAD(certList.get()), certList.get())) {
  2054         goto noCert;
  2057       nicknames = getNSSCertNicknamesFromCertList(certList.get());
  2059       if (!nicknames) {
  2060         goto loser;
  2063       NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
  2065       // Get CN and O of the subject and O of the issuer
  2066       char* ccn = CERT_GetCommonName(&mServerCert->subject);
  2067       void* v = ccn;
  2068       voidCleaner ccnCleaner(v);
  2069       NS_ConvertUTF8toUTF16 cn(ccn);
  2071       int32_t port;
  2072       mSocketInfo->GetPort(&port);
  2074       nsString cn_host_port;
  2075       if (ccn && strcmp(ccn, hostname) == 0) {
  2076         cn_host_port.Append(cn);
  2077         cn_host_port.AppendLiteral(":");
  2078         cn_host_port.AppendInt(port);
  2079       } else {
  2080         cn_host_port.Append(cn);
  2081         cn_host_port.AppendLiteral(" (");
  2082         cn_host_port.AppendLiteral(":");
  2083         cn_host_port.AppendInt(port);
  2084         cn_host_port.AppendLiteral(")");
  2087       char* corg = CERT_GetOrgName(&mServerCert->subject);
  2088       NS_ConvertUTF8toUTF16 org(corg);
  2089       if (corg) PORT_Free(corg);
  2091       char* cissuer = CERT_GetOrgName(&mServerCert->issuer);
  2092       NS_ConvertUTF8toUTF16 issuer(cissuer);
  2093       if (cissuer) PORT_Free(cissuer);
  2095       certNicknameList =
  2096         (char16_t**)nsMemory::Alloc(sizeof(char16_t*)* nicknames->numnicknames);
  2097       if (!certNicknameList)
  2098         goto loser;
  2099       certDetailsList =
  2100         (char16_t**)nsMemory::Alloc(sizeof(char16_t*)* nicknames->numnicknames);
  2101       if (!certDetailsList) {
  2102         nsMemory::Free(certNicknameList);
  2103         goto loser;
  2106       int32_t CertsToUse;
  2107       for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
  2108         !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
  2109         node = CERT_LIST_NEXT(node)
  2110         ) {
  2111         RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
  2113         if (!tempCert)
  2114           continue;
  2116         NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
  2117         nsAutoString nickWithSerial, details;
  2119         if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
  2120           continue;
  2122         certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
  2123         if (!certNicknameList[CertsToUse])
  2124           continue;
  2125         certDetailsList[CertsToUse] = ToNewUnicode(details);
  2126         if (!certDetailsList[CertsToUse]) {
  2127           nsMemory::Free(certNicknameList[CertsToUse]);
  2128           continue;
  2131         ++CertsToUse;
  2134       // Throw up the client auth dialog and get back the index of the selected cert
  2135       nsresult rv = getNSSDialogs((void**)&dialogs,
  2136         NS_GET_IID(nsIClientAuthDialogs),
  2137         NS_CLIENTAUTHDIALOGS_CONTRACTID);
  2139       if (NS_FAILED(rv)) {
  2140         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
  2141         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
  2142         goto loser;
  2146         nsPSMUITracker tracker;
  2147         if (tracker.isUIForbidden()) {
  2148           rv = NS_ERROR_NOT_AVAILABLE;
  2149         } else {
  2150           rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port.get(),
  2151             org.get(), issuer.get(),
  2152             (const char16_t**)certNicknameList,
  2153             (const char16_t**)certDetailsList,
  2154             CertsToUse, &selectedIndex, &canceled);
  2158       NS_RELEASE(dialogs);
  2159       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
  2160       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
  2162       if (NS_FAILED(rv)) goto loser;
  2164       // even if the user has canceled, we want to remember that, to avoid repeating prompts
  2165       bool wantRemember = false;
  2166       mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
  2168       int i;
  2169       if (!canceled)
  2170       for (i = 0, node = CERT_LIST_HEAD(certList);
  2171         !CERT_LIST_END(node, certList);
  2172         ++i, node = CERT_LIST_NEXT(node)) {
  2174         if (i == selectedIndex) {
  2175           cert = CERT_DupCertificate(node->cert);
  2176           break;
  2180       if (cars && wantRemember) {
  2181         cars->RememberDecision(hostname, mServerCert,
  2182           canceled ? nullptr : cert.get());
  2186     if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
  2188     if (!cert) {
  2189       goto loser;
  2192     // go get the private key
  2193     privKey = PK11_FindKeyByAnyCert(cert.get(), wincx);
  2194     if (!privKey) {
  2195       keyError = PR_GetError();
  2196       if (keyError == SEC_ERROR_BAD_PASSWORD) {
  2197         // problem with password: bail
  2198         goto loser;
  2199       } else {
  2200         goto noCert;
  2204   goto done;
  2206 noCert:
  2207 loser:
  2208   if (mRV == SECSuccess) {
  2209     mRV = SECFailure;
  2211 done:
  2212   int error = PR_GetError();
  2214   if (arena) {
  2215     PORT_FreeArena(arena, false);
  2218   *mPRetCert = cert.release();
  2219   *mPRetKey = privKey.forget();
  2221   if (mRV == SECFailure) {
  2222     mErrorCodeToReport = error;
  2226 static PRFileDesc*
  2227 nsSSLIOLayerImportFD(PRFileDesc* fd,
  2228                      nsNSSSocketInfo* infoObject,
  2229                      const char* host)
  2231   nsNSSShutDownPreventionLock locker;
  2232   PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd);
  2233   if (!sslSock) {
  2234     NS_ASSERTION(false, "NSS: Error importing socket");
  2235     return nullptr;
  2237   SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*) infoObject);
  2238   SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
  2239   SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback, infoObject);
  2241   // Disable this hook if we connect anonymously. See bug 466080.
  2242   uint32_t flags = 0;
  2243   infoObject->GetProviderFlags(&flags);
  2244   if (flags & nsISocketProvider::ANONYMOUS_CONNECT) {
  2245       SSL_GetClientAuthDataHook(sslSock, nullptr, infoObject);
  2246   } else {
  2247       SSL_GetClientAuthDataHook(sslSock,
  2248                             (SSLGetClientAuthData) nsNSS_SSLGetClientAuthData,
  2249                             infoObject);
  2251   if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook,
  2252                                             infoObject)) {
  2253     NS_NOTREACHED("failed to configure AuthCertificateHook");
  2254     goto loser;
  2257   if (SECSuccess != SSL_SetURL(sslSock, host)) {
  2258     NS_NOTREACHED("SSL_SetURL failed");
  2259     goto loser;
  2262   // This is an optimization to make sure the identity info dataset is parsed
  2263   // and loaded on a separate thread and can be overlapped with network latency.
  2264   EnsureServerVerificationInitialized();
  2266   return sslSock;
  2267 loser:
  2268   if (sslSock) {
  2269     PR_Close(sslSock);
  2271   return nullptr;
  2274 static nsresult
  2275 nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
  2276                        bool haveProxy, const char* host, int32_t port,
  2277                        nsNSSSocketInfo* infoObject)
  2279   nsNSSShutDownPreventionLock locker;
  2280   if (forSTARTTLS || haveProxy) {
  2281     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
  2282       return NS_ERROR_FAILURE;
  2286   // Let's see if we're trying to connect to a site we know is
  2287   // TLS intolerant.
  2288   nsAutoCString key;
  2289   key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
  2291   SSLVersionRange range;
  2292   if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
  2293     return NS_ERROR_FAILURE;
  2296  uint16_t maxEnabledVersion = range.max;
  2298   infoObject->SharedState().IOLayerHelpers()
  2299     .adjustForTLSIntolerance(infoObject->GetHostName(), infoObject->GetPort(),
  2300                              range);
  2301   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  2302          ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
  2303           fd, static_cast<unsigned int>(range.min),
  2304               static_cast<unsigned int>(range.max)));
  2306   if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
  2307     return NS_ERROR_FAILURE;
  2309   infoObject->SetTLSVersionRange(range);
  2311   // when adjustForTLSIntolerance tweaks the maximum version downward,
  2312   // we tell the server using this SCSV so they can detect a downgrade attack
  2313   if (range.max < maxEnabledVersion) {
  2314     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
  2315            ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
  2316     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
  2317       return NS_ERROR_FAILURE;
  2321   bool enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
  2322   if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
  2323     return NS_ERROR_FAILURE;
  2326   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
  2327     return NS_ERROR_FAILURE;
  2330   nsSSLIOLayerHelpers& ioHelpers = infoObject->SharedState().IOLayerHelpers();
  2331   if (ioHelpers.isRenegoUnrestrictedSite(nsDependentCString(host))) {
  2332     if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
  2333       return NS_ERROR_FAILURE;
  2335     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
  2336       return NS_ERROR_FAILURE;
  2340   // Set the Peer ID so that SSL proxy connections work properly and to
  2341   // separate anonymous and/or private browsing connections.
  2342   uint32_t flags = infoObject->GetProviderFlags();
  2343   nsAutoCString peerId;
  2344   if (flags & nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
  2345     peerId.Append("anon:");
  2347   if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
  2348     peerId.Append("private:");
  2350   peerId.Append(host);
  2351   peerId.Append(':');
  2352   peerId.AppendInt(port);
  2353   if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
  2354     return NS_ERROR_FAILURE;
  2357   return NS_OK;
  2360 nsresult
  2361 nsSSLIOLayerAddToSocket(int32_t family,
  2362                         const char* host,
  2363                         int32_t port,
  2364                         nsIProxyInfo* proxy,
  2365                         PRFileDesc* fd,
  2366                         nsISupports** info,
  2367                         bool forSTARTTLS,
  2368                         uint32_t providerFlags)
  2370   nsNSSShutDownPreventionLock locker;
  2371   PRFileDesc* layer = nullptr;
  2372   PRFileDesc* plaintextLayer = nullptr;
  2373   nsresult rv;
  2374   PRStatus stat;
  2376   SharedSSLState* sharedState =
  2377     providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
  2378   nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
  2379   if (!infoObject) return NS_ERROR_FAILURE;
  2381   NS_ADDREF(infoObject);
  2382   infoObject->SetForSTARTTLS(forSTARTTLS);
  2383   infoObject->SetHostName(host);
  2384   infoObject->SetPort(port);
  2386   bool haveProxy = false;
  2387   if (proxy) {
  2388     nsCString proxyHost;
  2389     proxy->GetHost(proxyHost);
  2390     haveProxy = !proxyHost.IsEmpty();
  2393   // A plaintext observer shim is inserted so we can observe some protocol
  2394   // details without modifying nss
  2395   plaintextLayer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
  2396                                         &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
  2397   if (plaintextLayer) {
  2398     plaintextLayer->secret = (PRFilePrivate*) infoObject;
  2399     stat = PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer);
  2400     if (stat == PR_FAILURE) {
  2401       plaintextLayer->dtor(plaintextLayer);
  2402       plaintextLayer = nullptr;
  2406   PRFileDesc* sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
  2407   if (!sslSock) {
  2408     NS_ASSERTION(false, "NSS: Error importing socket");
  2409     goto loser;
  2412   infoObject->SetFileDescPtr(sslSock);
  2414   rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host, port,
  2415                               infoObject);
  2417   if (NS_FAILED(rv))
  2418     goto loser;
  2420   // Now, layer ourselves on top of the SSL socket...
  2421   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
  2422                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
  2423   if (!layer)
  2424     goto loser;
  2426   layer->secret = (PRFilePrivate*) infoObject;
  2427   stat = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
  2429   if (stat == PR_FAILURE) {
  2430     goto loser;
  2433   nsNSSShutDownList::trackSSLSocketCreate();
  2435   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*) sslSock));
  2436   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
  2438   // We are going use a clear connection first //
  2439   if (forSTARTTLS || haveProxy) {
  2440     infoObject->SetHandshakeNotPending();
  2443   infoObject->SharedState().NoteSocketCreated();
  2445   return NS_OK;
  2446  loser:
  2447   NS_IF_RELEASE(infoObject);
  2448   if (layer) {
  2449     layer->dtor(layer);
  2451   if (plaintextLayer) {
  2452     PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
  2453     plaintextLayer->dtor(plaintextLayer);
  2455   return NS_ERROR_FAILURE;

mercurial