LCOV - code coverage report
Current view: directory - security/manager/ssl/src - nsNSSIOLayer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1425 452 31.7 %
Date: 2012-06-02 Functions: 143 68 47.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Brian Ryner <bryner@brianryner.com>
      25                 :  *   Javier Delgadillo <javi@netscape.com>
      26                 :  *   Kai Engert <kengert@redhat.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include "nsNSSComponent.h"
      43                 : #include "nsNSSIOLayer.h"
      44                 : #include "nsNSSCallbacks.h"
      45                 : 
      46                 : #include "prlog.h"
      47                 : #include "prnetdb.h"
      48                 : #include "nsIPrefService.h"
      49                 : #include "nsIPrefBranch.h"
      50                 : #include "nsIServiceManager.h"
      51                 : #include "nsIWebProgressListener.h"
      52                 : #include "nsIChannel.h"
      53                 : #include "nsNSSCertificate.h"
      54                 : #include "nsIX509CertValidity.h"
      55                 : #include "nsIDateTimeFormat.h"
      56                 : #include "nsDateTimeFormatCID.h"
      57                 : #include "nsIClientAuthDialogs.h"
      58                 : #include "nsClientAuthRemember.h"
      59                 : #include "nsICertOverrideService.h"
      60                 : #include "nsISSLErrorListener.h"
      61                 : #include "nsIObjectInputStream.h"
      62                 : #include "nsIObjectOutputStream.h"
      63                 : 
      64                 : #include "nsXPIDLString.h"
      65                 : #include "nsReadableUtils.h"
      66                 : #include "nsCRT.h"
      67                 : #include "nsAutoPtr.h"
      68                 : #include "nsPrintfCString.h"
      69                 : #include "SSLServerCertVerification.h"
      70                 : #include "nsNSSShutDown.h"
      71                 : #include "nsSSLStatus.h"
      72                 : #include "nsNSSCertHelper.h"
      73                 : #include "nsNSSCleaner.h"
      74                 : #include "nsIDocShell.h"
      75                 : #include "nsIDocShellTreeItem.h"
      76                 : #include "nsISecureBrowserUI.h"
      77                 : #include "nsIClassInfoImpl.h"
      78                 : #include "nsIProgrammingLanguage.h"
      79                 : #include "nsIArray.h"
      80                 : #include "nsCharSeparatedTokenizer.h"
      81                 : #include "PSMRunnable.h"
      82                 : 
      83                 : #include "ssl.h"
      84                 : #include "secerr.h"
      85                 : #include "sslerr.h"
      86                 : #include "secder.h"
      87                 : #include "secasn1.h"
      88                 : #include "certdb.h"
      89                 : #include "cert.h"
      90                 : #include "keyhi.h"
      91                 : 
      92                 : #include "mozilla/Util.h"
      93                 : 
      94                 : using namespace mozilla;
      95                 : using namespace mozilla::psm;
      96                 : 
      97                 : //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal 
      98                 :                             //reports when doing SSL read/write
      99                 :                             
     100                 : //#define DUMP_BUFFER  //Enable this define along with
     101                 :                        //DEBUG_SSL_VERBOSE to dump SSL
     102                 :                        //read/write buffer to a log.
     103                 :                        //Uses PR_LOG except on Mac where
     104                 :                        //we always write out to our own
     105                 :                        //file.
     106                 : 
     107                 : 
     108               0 : NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
     109               0 : NSSCleanupAutoPtrClass(void, PR_FREEIF)
     110                 : 
     111                 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
     112                 : 
     113                 : /* SSM_UserCertChoice: enum for cert choice info */
     114                 : typedef enum {ASK, AUTO} SSM_UserCertChoice;
     115                 : 
     116                 : #ifdef PR_LOGGING
     117                 : extern PRLogModuleInfo* gPIPNSSLog;
     118                 : #endif
     119                 : 
     120                 : #if defined(DEBUG_SSL_VERBOSE) && defined (XP_MAC)
     121                 : 
     122                 : #ifdef PR_LOG
     123                 : #undef PR_LOG
     124                 : #endif
     125                 : 
     126                 : static PRFileDesc *gMyLogFile = nsnull;
     127                 : #define MAC_LOG_FILE "MAC PIPNSS Log File"
     128                 : 
     129                 : void MyLogFunction(const char *fmt, ...)
     130                 : {
     131                 :   
     132                 :   va_list ap;
     133                 :   va_start(ap,fmt);
     134                 :   if (gMyLogFile == nsnull)
     135                 :     gMyLogFile = PR_Open(MAC_LOG_FILE, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
     136                 :                          0600);
     137                 :   if (!gMyLogFile)
     138                 :       return;
     139                 :   PR_vfprintf(gMyLogFile, fmt, ap);
     140                 :   va_end(ap);
     141                 : }
     142                 : 
     143                 : #define PR_LOG(module,level,args) MyLogFunction args
     144                 : #endif
     145                 : 
     146               4 : nsNSSSocketInfo::nsNSSSocketInfo()
     147                 :   : mMutex("nsNSSSocketInfo::nsNSSSocketInfo"),
     148                 :     mFd(nsnull),
     149                 :     mCertVerificationState(before_cert_verification),
     150                 :     mCertVerificationStarted(0),
     151                 :     mCertVerificationEnded(0),
     152                 :     mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
     153                 :     mSubRequestsHighSecurity(0),
     154                 :     mSubRequestsLowSecurity(0),
     155                 :     mSubRequestsBrokenSecurity(0),
     156                 :     mSubRequestsNoSecurity(0),
     157                 :     mErrorCode(0),
     158                 :     mErrorMessageType(PlainErrorMessage),
     159                 :     mForSTARTTLS(false),
     160                 :     mSSL3Enabled(false),
     161                 :     mTLSEnabled(false),
     162                 :     mHandshakePending(true),
     163                 :     mHasCleartextPhase(false),
     164                 :     mHandshakeInProgress(false),
     165                 :     mAllowTLSIntoleranceTimeout(true),
     166                 :     mRememberClientAuthCertificate(false),
     167                 :     mHandshakeStartTime(0),
     168                 :     mPort(0),
     169                 :     mIsCertIssuerBlacklisted(false),
     170                 :     mNPNCompleted(false),
     171                 :     mHandshakeCompleted(false),
     172                 :     mJoined(false),
     173               4 :     mSentClientCert(false)
     174                 : {
     175               4 : }
     176                 : 
     177              12 : nsNSSSocketInfo::~nsNSSSocketInfo()
     178                 : {
     179               8 :   nsNSSShutDownPreventionLock locker;
     180               4 :   if (isAlreadyShutDown())
     181                 :     return;
     182                 : 
     183               4 :   shutdown(calledFromObject);
     184              16 : }
     185                 : 
     186               4 : void nsNSSSocketInfo::virtualDestroyNSSReference()
     187                 : {
     188               4 : }
     189                 : 
     190             280 : NS_IMPL_THREADSAFE_ISUPPORTS8(nsNSSSocketInfo,
     191                 :                               nsITransportSecurityInfo,
     192                 :                               nsISSLSocketControl,
     193                 :                               nsIInterfaceRequestor,
     194                 :                               nsISSLStatusProvider,
     195                 :                               nsIAssociatedContentSecurity,
     196                 :                               nsISerializable,
     197                 :                               nsIClassInfo,
     198                 :                               nsIClientAuthUserDecision)
     199                 : 
     200                 : nsresult
     201              32 : nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending)
     202                 : {
     203              32 :   *aHandshakePending = mHandshakePending;
     204              32 :   return NS_OK;
     205                 : }
     206                 : 
     207                 : nsresult
     208               4 : nsNSSSocketInfo::SetHandshakePending(bool aHandshakePending)
     209                 : {
     210               4 :   mHandshakePending = aHandshakePending;
     211               4 :   return NS_OK;
     212                 : }
     213                 : 
     214                 : nsresult
     215               4 : nsNSSSocketInfo::SetHostName(const char* host)
     216                 : {
     217               4 :   mHostName.Adopt(host ? NS_strdup(host) : 0);
     218               4 :   return NS_OK;
     219                 : }
     220                 : 
     221                 : nsresult
     222              12 : nsNSSSocketInfo::GetHostName(char **host)
     223                 : {
     224              12 :   *host = (mHostName) ? NS_strdup(mHostName) : nsnull;
     225              12 :   return NS_OK;
     226                 : }
     227                 : 
     228                 : nsresult
     229               4 : nsNSSSocketInfo::SetPort(PRInt32 aPort)
     230                 : {
     231               4 :   mPort = aPort;
     232               4 :   return NS_OK;
     233                 : }
     234                 : 
     235                 : nsresult
     236              12 : nsNSSSocketInfo::GetPort(PRInt32 *aPort)
     237                 : {
     238              12 :   *aPort = mPort;
     239              12 :   return NS_OK;
     240                 : }
     241                 : 
     242                 : PRErrorCode
     243             326 : nsNSSSocketInfo::GetErrorCode() const
     244                 : {
     245             652 :   MutexAutoLock lock(mMutex);
     246                 : 
     247             326 :   return mErrorCode;
     248                 : }
     249                 : 
     250                 : void
     251               0 : nsNSSSocketInfo::SetCanceled(PRErrorCode errorCode,
     252                 :                              SSLErrorMessageType errorMessageType)
     253                 : {
     254               0 :   MutexAutoLock lock(mMutex);
     255                 : 
     256               0 :   mErrorCode = errorCode;
     257               0 :   mErrorMessageType = errorMessageType;
     258               0 :   mErrorMessageCached.Truncate();
     259               0 : }
     260                 : 
     261               0 : NS_IMETHODIMP nsNSSSocketInfo::GetRememberClientAuthCertificate(bool *aRememberClientAuthCertificate)
     262                 : {
     263               0 :   NS_ENSURE_ARG_POINTER(aRememberClientAuthCertificate);
     264               0 :   *aRememberClientAuthCertificate = mRememberClientAuthCertificate;
     265               0 :   return NS_OK;
     266                 : }
     267                 : 
     268               0 : NS_IMETHODIMP nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRememberClientAuthCertificate)
     269                 : {
     270               0 :   mRememberClientAuthCertificate = aRememberClientAuthCertificate;
     271               0 :   return NS_OK;
     272                 : }
     273                 : 
     274               0 : void nsNSSSocketInfo::SetHasCleartextPhase(bool aHasCleartextPhase)
     275                 : {
     276               0 :   mHasCleartextPhase = aHasCleartextPhase;
     277               0 : }
     278                 : 
     279               0 : bool nsNSSSocketInfo::GetHasCleartextPhase()
     280                 : {
     281               0 :   return mHasCleartextPhase;
     282                 : }
     283                 : 
     284                 : NS_IMETHODIMP
     285               0 : nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
     286                 : {
     287               0 :   *aCallbacks = mCallbacks;
     288               0 :   NS_IF_ADDREF(*aCallbacks);
     289               0 :   return NS_OK;
     290                 : }
     291                 : 
     292                 : NS_IMETHODIMP
     293              16 : nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
     294                 : {
     295              16 :   if (!aCallbacks) {
     296               8 :     mCallbacks = nsnull;
     297               8 :     return NS_OK;
     298                 :   }
     299                 : 
     300               8 :   mCallbacks = aCallbacks;
     301                 : 
     302               8 :   return NS_OK;
     303                 : }
     304                 : 
     305                 : static void
     306               4 : getSecureBrowserUI(nsIInterfaceRequestor * callbacks,
     307                 :                    nsISecureBrowserUI ** result)
     308                 : {
     309               4 :   NS_ASSERTION(result != nsnull, "result parameter to getSecureBrowserUI is null");
     310               4 :   *result = nsnull;
     311                 : 
     312               4 :   NS_ASSERTION(NS_IsMainThread(),
     313                 :                "getSecureBrowserUI called off the main thread");
     314                 : 
     315               4 :   if (!callbacks)
     316               0 :     return;
     317                 : 
     318               8 :   nsCOMPtr<nsISecureBrowserUI> secureUI = do_GetInterface(callbacks);
     319               4 :   if (secureUI) {
     320               0 :     secureUI.forget(result);
     321                 :     return;
     322                 :   }
     323                 : 
     324               8 :   nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(callbacks);
     325               4 :   if (item) {
     326               0 :     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     327               0 :     (void) item->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
     328                 :       
     329               0 :     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(rootItem);
     330               0 :     if (docShell) {
     331               0 :       (void) docShell->GetSecurityUI(result);
     332                 :     }
     333                 :   }
     334                 : }
     335                 : 
     336                 : NS_IMETHODIMP
     337               0 : nsNSSSocketInfo::GetSecurityState(PRUint32* state)
     338                 : {
     339               0 :   *state = mSecurityState;
     340               0 :   return NS_OK;
     341                 : }
     342                 : 
     343                 : nsresult
     344               4 : nsNSSSocketInfo::SetSecurityState(PRUint32 aState)
     345                 : {
     346               4 :   mSecurityState = aState;
     347               4 :   return NS_OK;
     348                 : }
     349                 : 
     350                 : /* attribute unsigned long countSubRequestsHighSecurity; */
     351               0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsHighSecurity(PRInt32 *aSubRequestsHighSecurity)
     352                 : {
     353               0 :   *aSubRequestsHighSecurity = mSubRequestsHighSecurity;
     354               0 :   return NS_OK;
     355                 : }
     356               0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsHighSecurity(PRInt32 aSubRequestsHighSecurity)
     357                 : {
     358               0 :   mSubRequestsHighSecurity = aSubRequestsHighSecurity;
     359               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     360                 : }
     361                 : 
     362                 : /* attribute unsigned long countSubRequestsLowSecurity; */
     363               0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsLowSecurity(PRInt32 *aSubRequestsLowSecurity)
     364                 : {
     365               0 :   *aSubRequestsLowSecurity = mSubRequestsLowSecurity;
     366               0 :   return NS_OK;
     367                 : }
     368               0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsLowSecurity(PRInt32 aSubRequestsLowSecurity)
     369                 : {
     370               0 :   mSubRequestsLowSecurity = aSubRequestsLowSecurity;
     371               0 :   return NS_OK;
     372                 : }
     373                 : 
     374                 : /* attribute unsigned long countSubRequestsBrokenSecurity; */
     375               0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsBrokenSecurity(PRInt32 *aSubRequestsBrokenSecurity)
     376                 : {
     377               0 :   *aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
     378               0 :   return NS_OK;
     379                 : }
     380               0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsBrokenSecurity(PRInt32 aSubRequestsBrokenSecurity)
     381                 : {
     382               0 :   mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
     383               0 :   return NS_OK;
     384                 : }
     385                 : 
     386                 : /* attribute unsigned long countSubRequestsNoSecurity; */
     387               0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsNoSecurity(PRInt32 *aSubRequestsNoSecurity)
     388                 : {
     389               0 :   *aSubRequestsNoSecurity = mSubRequestsNoSecurity;
     390               0 :   return NS_OK;
     391                 : }
     392               0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsNoSecurity(PRInt32 aSubRequestsNoSecurity)
     393                 : {
     394               0 :   mSubRequestsNoSecurity = aSubRequestsNoSecurity;
     395               0 :   return NS_OK;
     396                 : }
     397               0 : NS_IMETHODIMP nsNSSSocketInfo::Flush()
     398                 : {
     399               0 :   return NS_OK;
     400                 : }
     401                 : 
     402                 : NS_IMETHODIMP
     403               0 : nsNSSSocketInfo::GetShortSecurityDescription(PRUnichar** aText) {
     404               0 :   if (mShortDesc.IsEmpty())
     405               0 :     *aText = nsnull;
     406                 :   else {
     407               0 :     *aText = ToNewUnicode(mShortDesc);
     408               0 :     NS_ENSURE_TRUE(*aText, NS_ERROR_OUT_OF_MEMORY);
     409                 :   }
     410               0 :   return NS_OK;
     411                 : }
     412                 : 
     413                 : nsresult
     414               4 : nsNSSSocketInfo::SetShortSecurityDescription(const PRUnichar* aText) {
     415               4 :   mShortDesc.Assign(aText);
     416               4 :   return NS_OK;
     417                 : }
     418                 : 
     419                 : NS_IMETHODIMP
     420               0 : nsNSSSocketInfo::GetErrorMessage(PRUnichar** aText)
     421                 : {
     422               0 :   NS_ENSURE_ARG_POINTER(aText);
     423               0 :   *aText = nsnull;
     424                 : 
     425               0 :   if (!NS_IsMainThread()) {
     426               0 :     NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
     427               0 :     return NS_ERROR_NOT_SAME_THREAD;
     428                 :   }
     429                 : 
     430               0 :   MutexAutoLock lock(mMutex);
     431                 : 
     432               0 :   nsresult rv = formatErrorMessage(lock);
     433               0 :   NS_ENSURE_SUCCESS(rv, rv);
     434                 : 
     435               0 :   *aText = ToNewUnicode(mErrorMessageCached);
     436               0 :   return *aText != nsnull ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     437                 : }
     438                 : 
     439                 : void
     440               4 : nsNSSSocketInfo::SetNegotiatedNPN(const char *value, PRUint32 length)
     441                 : {
     442               4 :   if (!value)
     443               4 :     mNegotiatedNPN.Truncate();
     444                 :   else
     445               0 :     mNegotiatedNPN.Assign(value, length);
     446               4 :   mNPNCompleted = true;
     447               4 : }
     448                 : 
     449                 : NS_IMETHODIMP
     450              16 : nsNSSSocketInfo::GetNegotiatedNPN(nsACString &aNegotiatedNPN)
     451                 : {
     452              16 :   if (!mNPNCompleted)
     453              12 :     return NS_ERROR_NOT_CONNECTED;
     454                 : 
     455               4 :   aNegotiatedNPN = mNegotiatedNPN;
     456               4 :   return NS_OK;
     457                 : }
     458                 : 
     459                 : NS_IMETHODIMP
     460               0 : nsNSSSocketInfo::JoinConnection(const nsACString & npnProtocol,
     461                 :                                 const nsACString & hostname,
     462                 :                                 PRInt32 port,
     463                 :                                 bool *_retval NS_OUTPARAM)
     464                 : {
     465               0 :   *_retval = false;
     466                 : 
     467                 :   // Different ports may not be joined together
     468               0 :   if (port != mPort)
     469               0 :     return NS_OK;
     470                 : 
     471                 :   // Make sure NPN has been completed and matches requested npnProtocol
     472               0 :   if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
     473               0 :     return NS_OK;
     474                 : 
     475                 :   // If this is the same hostname then the certicate status does not
     476                 :   // need to be considered. They are joinable.
     477               0 :   if (mHostName && hostname.Equals(mHostName)) {
     478               0 :     *_retval = true;
     479               0 :     return NS_OK;
     480                 :   }
     481                 : 
     482                 :   // Before checking the server certificate we need to make sure the
     483                 :   // handshake has completed.
     484               0 :   if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
     485               0 :     return NS_OK;
     486                 : 
     487                 :   // If the cert has error bits (e.g. it is untrusted) then do not join.
     488                 :   // The value of mHaveCertErrorBits is only reliable because we know that
     489                 :   // the handshake completed.
     490               0 :   if (SSLStatus()->mHaveCertErrorBits)
     491               0 :     return NS_OK;
     492                 : 
     493                 :   // If the connection is using client certificates then do not join
     494                 :   // because the user decides on whether to send client certs to hosts on a
     495                 :   // per-domain basis.
     496               0 :   if (mSentClientCert)
     497               0 :     return NS_OK;
     498                 : 
     499                 :   // Ensure that the server certificate covers the hostname that would
     500                 :   // like to join this connection
     501                 : 
     502               0 :   CERTCertificate *nssCert = nsnull;
     503               0 :   CERTCertificateCleaner nsscertCleaner(nssCert);
     504                 : 
     505               0 :   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
     506               0 :   if (cert2)
     507               0 :     nssCert = cert2->GetCert();
     508                 : 
     509               0 :   if (!nssCert)
     510               0 :     return NS_OK;
     511                 : 
     512               0 :   if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
     513                 :       SECSuccess)
     514               0 :     return NS_OK;
     515                 : 
     516                 :   // All tests pass - this is joinable
     517               0 :   mJoined = true;
     518               0 :   *_retval = true;
     519               0 :   return NS_OK;
     520                 : }
     521                 : 
     522                 : static nsresult
     523                 : formatPlainErrorMessage(nsXPIDLCString const & host, PRInt32 port,
     524                 :                         PRErrorCode err, nsString &returnedMessage);
     525                 : 
     526                 : static nsresult
     527                 : formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
     528                 :                                   PRErrorCode errorCodeToReport, 
     529                 :                                   const nsXPIDLCString & host, PRInt32 port,
     530                 :                                   nsString & returnedMessage);
     531                 : 
     532                 : // XXX: uses nsNSSComponent string bundles off the main thread when called by
     533                 : //      nsNSSSocketInfo::Write(). When we remove the error message from the
     534                 : //      serialization of nsNSSSocketInfo (bug 697781) we can inline
     535                 : //      formatErrorMessage into GetErrorMessage().
     536                 : nsresult
     537               4 : nsNSSSocketInfo::formatErrorMessage(MutexAutoLock const & proofOfLock)
     538                 : {
     539               4 :   if (mErrorCode == 0 || !mErrorMessageCached.IsEmpty()) {
     540               4 :     return NS_OK;
     541                 :   }
     542                 : 
     543                 :   nsresult rv;
     544               0 :   NS_ConvertASCIItoUTF16 hostNameU(mHostName);
     545               0 :   NS_ASSERTION(mErrorMessageType != OverridableCertErrorMessage || 
     546                 :                 (mSSLStatus && mSSLStatus->mServerCert &&
     547                 :                  mSSLStatus->mHaveCertErrorBits),
     548                 :                 "GetErrorMessage called for cert error without cert");
     549               0 :   if (mErrorMessageType == OverridableCertErrorMessage && 
     550               0 :       mSSLStatus && mSSLStatus->mServerCert) {
     551               0 :     rv = formatOverridableCertErrorMessage(*mSSLStatus, mErrorCode,
     552                 :                                            mHostName, mPort,
     553               0 :                                            mErrorMessageCached);
     554                 :   } else {
     555                 :     rv = formatPlainErrorMessage(mHostName, mPort, mErrorCode,
     556               0 :                                  mErrorMessageCached);
     557                 :   }
     558                 : 
     559               0 :   if (NS_FAILED(rv)) {
     560               0 :     mErrorMessageCached.Truncate();
     561                 :   }
     562                 : 
     563               0 :   return rv;
     564                 : }
     565                 : 
     566                 : /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
     567               0 : NS_IMETHODIMP nsNSSSocketInfo::GetInterface(const nsIID & uuid, void * *result)
     568                 : {
     569               0 :   if (!NS_IsMainThread()) {
     570               0 :     NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
     571               0 :     return NS_ERROR_NOT_SAME_THREAD;
     572                 :   }
     573                 : 
     574                 :   nsresult rv;
     575               0 :   if (!mCallbacks) {
     576               0 :     nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
     577               0 :     if (!ir)
     578               0 :       return NS_ERROR_OUT_OF_MEMORY;
     579                 : 
     580               0 :     rv = ir->GetInterface(uuid, result);
     581                 :   } else {
     582               0 :     rv = mCallbacks->GetInterface(uuid, result);
     583                 :   }
     584               0 :   return rv;
     585                 : }
     586                 : 
     587                 : nsresult
     588               0 : nsNSSSocketInfo::GetForSTARTTLS(bool* aForSTARTTLS)
     589                 : {
     590               0 :   *aForSTARTTLS = mForSTARTTLS;
     591               0 :   return NS_OK;
     592                 : }
     593                 : 
     594                 : nsresult
     595               4 : nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
     596                 : {
     597               4 :   mForSTARTTLS = aForSTARTTLS;
     598               4 :   return NS_OK;
     599                 : }
     600                 : 
     601                 : NS_IMETHODIMP
     602               0 : nsNSSSocketInfo::ProxyStartSSL()
     603                 : {
     604               0 :   return ActivateSSL();
     605                 : }
     606                 : 
     607                 : NS_IMETHODIMP
     608               0 : nsNSSSocketInfo::StartTLS()
     609                 : {
     610               0 :   return ActivateSSL();
     611                 : }
     612                 : 
     613                 : NS_IMETHODIMP
     614               4 : nsNSSSocketInfo::SetNPNList(nsTArray<nsCString> &protocolArray)
     615                 : {
     616               8 :   nsNSSShutDownPreventionLock locker;
     617               4 :   if (isAlreadyShutDown())
     618               0 :     return NS_ERROR_NOT_AVAILABLE;
     619               4 :   if (!mFd)
     620               0 :     return NS_ERROR_FAILURE;
     621                 : 
     622                 :   // the npn list is a concatenated list of 8 bit byte strings.
     623               8 :   nsCString npnList;
     624                 : 
     625              12 :   for (PRUint32 index = 0; index < protocolArray.Length(); ++index) {
     626              16 :     if (protocolArray[index].IsEmpty() ||
     627               8 :         protocolArray[index].Length() > 255)
     628               0 :       return NS_ERROR_ILLEGAL_VALUE;
     629                 : 
     630               8 :     npnList.Append(protocolArray[index].Length());
     631               8 :     npnList.Append(protocolArray[index]);
     632                 :   }
     633                 :   
     634               4 :   if (SSL_SetNextProtoNego(
     635                 :         mFd,
     636               4 :         reinterpret_cast<const unsigned char *>(npnList.get()),
     637               8 :         npnList.Length()) != SECSuccess)
     638               0 :     return NS_ERROR_FAILURE;
     639                 : 
     640               4 :   return NS_OK;
     641                 : }
     642                 : 
     643                 : static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
     644                 : #define NSSSOCKETINFOMAGIC { 0xa9863a23, 0x26b8, 0x4a9c, \
     645                 :   { 0x83, 0xf1, 0xe9, 0xda, 0xdb, 0x36, 0xb8, 0x30 } }
     646                 : static NS_DEFINE_CID(kNSSSocketInfoMagic, NSSSOCKETINFOMAGIC);
     647                 : 
     648                 : NS_IMETHODIMP
     649               4 : nsNSSSocketInfo::Write(nsIObjectOutputStream* stream) {
     650               4 :   stream->WriteID(kNSSSocketInfoMagic);
     651                 : 
     652               8 :   MutexAutoLock lock(mMutex);
     653                 : 
     654               8 :   nsRefPtr<nsSSLStatus> status = mSSLStatus;
     655               8 :   nsCOMPtr<nsISerializable> certSerializable;
     656                 : 
     657                 :   // Write a redundant copy of the certificate for backward compatibility
     658                 :   // with previous versions, which also unnecessarily wrote it.
     659                 :   //
     660                 :   // As we are reading the object our self, not using ReadObject, we have
     661                 :   // to store it here 'manually' as well, mimicking our object stream
     662                 :   // implementation.
     663                 : 
     664               4 :   if (status) {
     665               8 :     nsCOMPtr<nsIX509Cert> cert = status->mServerCert;
     666               4 :     certSerializable = do_QueryInterface(cert);
     667                 : 
     668               4 :     if (!certSerializable) {
     669               0 :       NS_ERROR("certificate is missing or isn't serializable");
     670               0 :       return NS_ERROR_UNEXPECTED;
     671                 :     }
     672                 :   } else {
     673               0 :     NS_WARNING("Serializing nsNSSSocketInfo without mSSLStatus");
     674                 :   }
     675                 : 
     676                 :   // Store the flag if there is the certificate present
     677               4 :   stream->WriteBoolean(certSerializable);
     678               4 :   if (certSerializable) {
     679               4 :     stream->WriteID(kNSSCertificateCID);
     680               4 :     stream->WriteID(NS_GET_IID(nsISupports));
     681               4 :     certSerializable->Write(stream);
     682                 :   }
     683                 : 
     684                 :   // Store the version number of the binary stream data format.
     685                 :   // The 0xFFFF0000 mask is included to the version number
     686                 :   // to distinguish version number from mSecurityState
     687                 :   // field stored in times before versioning has been introduced.
     688                 :   // This mask value has been chosen as mSecurityState could
     689                 :   // never be assigned such value.
     690               4 :   PRUint32 version = 3;
     691               4 :   stream->Write32(version | 0xFFFF0000);
     692               4 :   stream->Write32(mSecurityState);
     693               4 :   stream->WriteWStringZ(mShortDesc.get());
     694                 : 
     695                 :   // XXX: uses nsNSSComponent string bundles off the main thread
     696               4 :   nsresult rv = formatErrorMessage(lock); 
     697               4 :   NS_ENSURE_SUCCESS(rv, rv);
     698               4 :   stream->WriteWStringZ(mErrorMessageCached.get());
     699                 : 
     700               4 :   stream->WriteCompoundObject(NS_ISUPPORTS_CAST(nsISSLStatus*, status),
     701               8 :                               NS_GET_IID(nsISupports), true);
     702                 : 
     703               4 :   stream->Write32((PRUint32)mSubRequestsHighSecurity);
     704               4 :   stream->Write32((PRUint32)mSubRequestsLowSecurity);
     705               4 :   stream->Write32((PRUint32)mSubRequestsBrokenSecurity);
     706               4 :   stream->Write32((PRUint32)mSubRequestsNoSecurity);
     707               4 :   return NS_OK;
     708                 : }
     709                 : 
     710               0 : static bool CheckUUIDEquals(PRUint32 m0,
     711                 :                             nsIObjectInputStream* stream,
     712                 :                             const nsCID& id)
     713                 : {
     714                 :   nsID tempID;
     715               0 :   tempID.m0 = m0;
     716               0 :   stream->Read16(&tempID.m1);
     717               0 :   stream->Read16(&tempID.m2);
     718               0 :   for (int i = 0; i < 8; ++i)
     719               0 :     stream->Read8(&tempID.m3[i]);
     720               0 :   return tempID.Equals(id);
     721                 : }
     722                 : 
     723                 : NS_IMETHODIMP
     724               0 : nsNSSSocketInfo::Read(nsIObjectInputStream* stream) {
     725                 :   nsresult rv;
     726                 : 
     727                 :   PRUint32 version;
     728                 :   bool certificatePresent;
     729                 : 
     730                 :   // Check what we have here...
     731                 :   PRUint32 UUID_0;
     732               0 :   stream->Read32(&UUID_0);
     733               0 :   if (UUID_0 == kNSSSocketInfoMagic.m0) {
     734                 :     // It seems this stream begins with our magic ID, check it really is there
     735               0 :     if (!CheckUUIDEquals(UUID_0, stream, kNSSSocketInfoMagic))
     736               0 :       return NS_ERROR_FAILURE;
     737                 : 
     738                 :     // OK, this seems to be our stream, now continue to check there is
     739                 :     // the certificate
     740               0 :     stream->ReadBoolean(&certificatePresent);
     741               0 :     stream->Read32(&UUID_0);
     742                 :   }
     743                 :   else {
     744                 :     // There is no magic, assume there is a certificate present as in versions
     745                 :     // prior to those with the magic didn't store that flag; we check the 
     746                 :     // certificate is present by cheking the CID then
     747               0 :     certificatePresent = true;
     748                 :   }
     749                 : 
     750               0 :   if (certificatePresent && UUID_0 == kNSSCertificateCID.m0) {
     751                 :     // It seems there is the certificate CID present, check it now; we only
     752                 :     // have this single certificate implementation at this time.
     753               0 :     if (!CheckUUIDEquals(UUID_0, stream, kNSSCertificateCID))
     754               0 :       return NS_ERROR_FAILURE;
     755                 : 
     756                 :     // OK, we have read the CID of the certificate, check the interface ID
     757                 :     nsID tempID;
     758               0 :     stream->ReadID(&tempID);
     759               0 :     if (!tempID.Equals(NS_GET_IID(nsISupports)))
     760               0 :       return NS_ERROR_FAILURE;
     761                 : 
     762                 :     nsCOMPtr<nsISerializable> serializable =
     763               0 :         do_CreateInstance(kNSSCertificateCID, &rv);
     764               0 :     NS_ENSURE_SUCCESS(rv, rv);
     765                 : 
     766                 :     // This is the redundant copy of the certificate; just ignore it
     767               0 :     serializable->Read(stream);
     768                 : 
     769                 :     // We are done with reading the certificate, now read the version
     770                 :     // as we did before.
     771               0 :     stream->Read32(&version);
     772                 :   }
     773                 :   else {
     774                 :     // There seems not to be the certificate present in the stream.
     775               0 :     version = UUID_0;
     776                 :   }
     777                 : 
     778               0 :   MutexAutoLock lock(mMutex);
     779                 : 
     780                 :   // If the version field we have just read is not masked with 0xFFFF0000
     781                 :   // then it is stored mSecurityState field and this is version 1 of
     782                 :   // the binary data stream format.
     783               0 :   if ((version & 0xFFFF0000) == 0xFFFF0000) {
     784               0 :     version &= ~0xFFFF0000;
     785               0 :     stream->Read32(&mSecurityState);
     786                 :   }
     787                 :   else {
     788               0 :     mSecurityState = version;
     789               0 :     version = 1;
     790                 :   }
     791               0 :   stream->ReadString(mShortDesc);
     792               0 :   stream->ReadString(mErrorMessageCached);
     793               0 :   mErrorCode = 0;
     794                 : 
     795               0 :   nsCOMPtr<nsISupports> obj;
     796               0 :   stream->ReadObject(true, getter_AddRefs(obj));
     797                 :   
     798               0 :   mSSLStatus = reinterpret_cast<nsSSLStatus*>(obj.get());
     799                 : 
     800               0 :   if (!mSSLStatus) {
     801               0 :     NS_WARNING("deserializing nsNSSSocketInfo without mSSLStatus");
     802                 :   }
     803                 : 
     804               0 :   if (version >= 2) {
     805               0 :     stream->Read32((PRUint32*)&mSubRequestsHighSecurity);
     806               0 :     stream->Read32((PRUint32*)&mSubRequestsLowSecurity);
     807               0 :     stream->Read32((PRUint32*)&mSubRequestsBrokenSecurity);
     808               0 :     stream->Read32((PRUint32*)&mSubRequestsNoSecurity);
     809                 :   }
     810                 :   else {
     811               0 :     mSubRequestsHighSecurity = 0;
     812               0 :     mSubRequestsLowSecurity = 0;
     813               0 :     mSubRequestsBrokenSecurity = 0;
     814               0 :     mSubRequestsNoSecurity = 0;
     815                 :   }
     816               0 :   return NS_OK;
     817                 : }
     818                 : 
     819                 : NS_IMETHODIMP
     820               0 : nsNSSSocketInfo::GetInterfaces(PRUint32 *count, nsIID * **array)
     821                 : {
     822               0 :   *count = 0;
     823               0 :   *array = nsnull;
     824               0 :   return NS_OK;
     825                 : }
     826                 : 
     827                 : NS_IMETHODIMP
     828               0 : nsNSSSocketInfo::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
     829                 : {
     830               0 :   *_retval = nsnull;
     831               0 :   return NS_OK;
     832                 : }
     833                 : 
     834                 : NS_IMETHODIMP
     835               0 : nsNSSSocketInfo::GetContractID(char * *aContractID)
     836                 : {
     837               0 :   *aContractID = nsnull;
     838               0 :   return NS_OK;
     839                 : }
     840                 : 
     841                 : NS_IMETHODIMP
     842               0 : nsNSSSocketInfo::GetClassDescription(char * *aClassDescription)
     843                 : {
     844               0 :   *aClassDescription = nsnull;
     845               0 :   return NS_OK;
     846                 : }
     847                 : 
     848                 : NS_IMETHODIMP
     849               0 : nsNSSSocketInfo::GetClassID(nsCID * *aClassID)
     850                 : {
     851               0 :   *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
     852               0 :   if (!*aClassID)
     853               0 :     return NS_ERROR_OUT_OF_MEMORY;
     854               0 :   return GetClassIDNoAlloc(*aClassID);
     855                 : }
     856                 : 
     857                 : NS_IMETHODIMP
     858               0 : nsNSSSocketInfo::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
     859                 : {
     860               0 :   *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
     861               0 :   return NS_OK;
     862                 : }
     863                 : 
     864                 : NS_IMETHODIMP
     865               0 : nsNSSSocketInfo::GetFlags(PRUint32 *aFlags)
     866                 : {
     867               0 :   *aFlags = 0;
     868               0 :   return NS_OK;
     869                 : }
     870                 : 
     871                 : static NS_DEFINE_CID(kNSSSocketInfoCID, NS_NSSSOCKETINFO_CID);
     872                 : 
     873                 : NS_IMETHODIMP
     874               4 : nsNSSSocketInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
     875                 : {
     876               4 :   *aClassIDNoAlloc = kNSSSocketInfoCID;
     877               4 :   return NS_OK;
     878                 : }
     879                 : 
     880               0 : nsresult nsNSSSocketInfo::ActivateSSL()
     881                 : {
     882               0 :   nsNSSShutDownPreventionLock locker;
     883               0 :   if (isAlreadyShutDown())
     884               0 :     return NS_ERROR_NOT_AVAILABLE;
     885                 : 
     886               0 :   if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
     887               0 :     return NS_ERROR_FAILURE;            
     888               0 :   if (SECSuccess != SSL_ResetHandshake(mFd, false))
     889               0 :     return NS_ERROR_FAILURE;
     890                 : 
     891               0 :   mHandshakePending = true;
     892                 : 
     893               0 :   return NS_OK;
     894                 : }
     895                 : 
     896               0 : nsresult nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
     897                 : {
     898               0 :   *aFilePtr = mFd;
     899               0 :   return NS_OK;
     900                 : }
     901                 : 
     902               4 : nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
     903                 : {
     904               4 :   mFd = aFilePtr;
     905               4 :   return NS_OK;
     906                 : }
     907                 : 
     908                 : class PreviousCertRunnable : public SyncRunnableBase
     909              16 : {
     910                 : public:
     911               4 :   PreviousCertRunnable(nsIInterfaceRequestor * callbacks)
     912               4 :     : mCallbacks(callbacks)
     913                 :   {
     914               4 :   }
     915                 : 
     916               4 :   virtual void RunOnTargetThread()
     917                 :   {
     918               8 :     nsCOMPtr<nsISecureBrowserUI> secureUI;
     919               4 :     getSecureBrowserUI(mCallbacks, getter_AddRefs(secureUI));
     920               8 :     nsCOMPtr<nsISSLStatusProvider> statusProvider = do_QueryInterface(secureUI);
     921               4 :     if (statusProvider) {
     922               0 :       nsCOMPtr<nsISSLStatus> status;
     923               0 :       (void) statusProvider->GetSSLStatus(getter_AddRefs(status));
     924               0 :       if (status) {
     925               0 :         (void) status->GetServerCert(getter_AddRefs(mPreviousCert));
     926                 :       }
     927                 :     }
     928               4 :   }
     929                 : 
     930                 :   nsCOMPtr<nsIX509Cert> mPreviousCert; // out
     931                 : private:
     932                 :   nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
     933                 : };
     934                 : 
     935               4 : void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
     936                 : {
     937               4 :   NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
     938               4 :   *_result = nsnull;
     939                 : 
     940              12 :   nsRefPtr<PreviousCertRunnable> runnable = new PreviousCertRunnable(mCallbacks);
     941               4 :   nsresult rv = runnable->DispatchToMainThreadAndWait();
     942               4 :   NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
     943               4 :   runnable->mPreviousCert.forget(_result);
     944               4 : }
     945                 : 
     946                 : void
     947               4 : nsNSSSocketInfo::SetCertVerificationWaiting()
     948                 : {
     949                 :   // mCertVerificationState may be before_cert_verification for the first
     950                 :   // handshake on the connection, or after_cert_verification for subsequent
     951                 :   // renegotiation handshakes.
     952               4 :   NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
     953                 :                "Invalid state transition to waiting_for_cert_verification");
     954               4 :   mCertVerificationState = waiting_for_cert_verification;
     955               4 :   mCertVerificationStarted = PR_IntervalNow();
     956               4 : }
     957                 : 
     958                 : // Be careful that SetCertVerificationResult does NOT get called while we are
     959                 : // processing a SSL callback function, because SSL_AuthCertificateComplete will
     960                 : // attempt to acquire locks that are already held by libssl when it calls
     961                 : // callbacks.
     962                 : void
     963               4 : nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
     964                 :                                            SSLErrorMessageType errorMessageType)
     965                 : {
     966               4 :   NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
     967                 :                "Invalid state transition to cert_verification_finished");
     968                 : 
     969               4 :   mCertVerificationEnded = PR_IntervalNow();
     970                 : 
     971               4 :   if (mFd) {
     972               4 :     SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
     973                 :     // Only replace errorCode if there was originally no error
     974               4 :     if (rv != SECSuccess && errorCode == 0) {
     975               0 :       errorCode = PR_GetError();
     976               0 :       errorMessageType = PlainErrorMessage;
     977               0 :       if (errorCode == 0) {
     978               0 :         NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
     979               0 :         errorCode = PR_INVALID_STATE_ERROR;
     980                 :       }
     981                 :     }
     982                 :   }
     983                 : 
     984               4 :   if (errorCode) {
     985               0 :     SetCanceled(errorCode, errorMessageType);
     986                 :   }
     987                 : 
     988               4 :   mCertVerificationState = after_cert_verification;
     989               4 : }
     990                 : 
     991               4 : nsresult nsNSSSocketInfo::GetSSLStatus(nsISSLStatus** _result)
     992                 : {
     993               4 :   NS_ENSURE_ARG_POINTER(_result);
     994                 : 
     995               4 :   *_result = mSSLStatus;
     996               4 :   NS_IF_ADDREF(*_result);
     997                 : 
     998               4 :   return NS_OK;
     999                 : }
    1000                 : 
    1001               4 : nsresult nsNSSSocketInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
    1002                 : {
    1003               4 :   mSSLStatus = aSSLStatus;
    1004                 : 
    1005               4 :   return NS_OK;
    1006                 : }
    1007                 : 
    1008              12 : void nsNSSSocketInfo::SetHandshakeInProgress(bool aIsIn)
    1009                 : {
    1010              12 :   mHandshakeInProgress = aIsIn;
    1011                 : 
    1012              12 :   if (mHandshakeInProgress && !mHandshakeStartTime)
    1013                 :   {
    1014               4 :     mHandshakeStartTime = PR_IntervalNow();
    1015                 :   }
    1016              12 : }
    1017                 : 
    1018               0 : void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
    1019                 : {
    1020               0 :   mAllowTLSIntoleranceTimeout = aAllow;
    1021               0 : }
    1022                 : 
    1023                 : #define HANDSHAKE_TIMEOUT_SECONDS 25
    1024                 : 
    1025             270 : bool nsNSSSocketInfo::HandshakeTimeout()
    1026                 : {
    1027             270 :   if (mCertVerificationState == waiting_for_cert_verification) {
    1028                 :     // Do not do a TLS interlerance timeout during cert verification because:
    1029                 :     //
    1030                 :     //  * If we would have timed out, but cert verification is still ongoing,
    1031                 :     //    then the handshake probably already completed, and it is probably the
    1032                 :     //    certificate validation (OCSP responder or similar) that is timing
    1033                 :     //    out.
    1034                 :     //  * If certificate validation AND the handshake is slow, then that is a
    1035                 :     //    good indication that the network is bad, and so the problem probably
    1036                 :     //    isn't the server being TLS intolerant.
    1037                 :     //  * When we timeout, we return non-zero flags from PR_Poll, which will
    1038                 :     //    cause the application to try to read from and/or write to the socket,
    1039                 :     //    possibly in a loop. But, it is likely that the socket is blocked on
    1040                 :     //    cert authentication, so those read and/or write calls would result in
    1041                 :     //    PR_WOULD_BLOCK_ERROR, causing the application to spin.
    1042               4 :     return false;
    1043                 :   }
    1044                 : 
    1045             266 :   if (!mHandshakeInProgress || !mAllowTLSIntoleranceTimeout)
    1046             258 :     return false;
    1047                 : 
    1048               8 :   PRIntervalTime now = PR_IntervalNow();
    1049                 :   PRIntervalTime certVerificationTime =
    1050               8 :       mCertVerificationEnded - mCertVerificationStarted;
    1051               8 :   PRIntervalTime totalTime = now - mHandshakeStartTime;
    1052                 :   PRIntervalTime totalTimeExceptCertVerificationTime =
    1053               8 :       totalTime - certVerificationTime;
    1054                 : 
    1055                 :   return totalTimeExceptCertVerificationTime > 
    1056               8 :       PR_SecondsToInterval(HANDSHAKE_TIMEOUT_SECONDS);
    1057                 : }
    1058                 : 
    1059             328 : void nsSSLIOLayerHelpers::Cleanup()
    1060                 : {
    1061             328 :   if (mTLSIntolerantSites) {
    1062             328 :     delete mTLSIntolerantSites;
    1063             328 :     mTLSIntolerantSites = nsnull;
    1064                 :   }
    1065                 : 
    1066             328 :   if (mTLSTolerantSites) {
    1067             328 :     delete mTLSTolerantSites;
    1068             328 :     mTLSTolerantSites = nsnull;
    1069                 :   }
    1070                 : 
    1071             328 :   if (mRenegoUnrestrictedSites) {
    1072             328 :     delete mRenegoUnrestrictedSites;
    1073             328 :     mRenegoUnrestrictedSites = nsnull;
    1074                 :   }
    1075                 : 
    1076             328 :   if (mutex) {
    1077             328 :     delete mutex;
    1078             328 :     mutex = nsnull;
    1079                 :   }
    1080                 : 
    1081             328 :   if (mHostsWithCertErrors) {
    1082             328 :     delete mHostsWithCertErrors;
    1083             328 :     mHostsWithCertErrors = nsnull;
    1084                 :   }
    1085             328 : }
    1086                 : 
    1087                 : /* Formats an error message for non-certificate-related SSL errors
    1088                 :  * and non-overridable certificate errors (both are of type
    1089                 :  * PlainErrormMessage). Use formatOverridableCertErrorMessage
    1090                 :  * for overridable cert errors.
    1091                 :  */
    1092                 : static nsresult
    1093               0 : formatPlainErrorMessage(const nsXPIDLCString &host, PRInt32 port,
    1094                 :                         PRErrorCode err, nsString &returnedMessage)
    1095                 : {
    1096                 :   const PRUnichar *params[1];
    1097                 :   nsresult rv;
    1098                 : 
    1099               0 :   nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
    1100               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1101                 : 
    1102               0 :   if (host.Length())
    1103                 :   {
    1104               0 :     nsString hostWithPort;
    1105                 : 
    1106                 :     // For now, hide port when it's 443 and we're reporting the error.
    1107                 :     // In the future a better mechanism should be used
    1108                 :     // to make a decision about showing the port number, possibly by requiring
    1109                 :     // the context object to implement a specific interface.
    1110                 :     // The motivation is that Mozilla browser would like to hide the port number
    1111                 :     // in error pages in the common case.
    1112                 : 
    1113               0 :     hostWithPort.AssignASCII(host);
    1114               0 :     if (port != 443) {
    1115               0 :       hostWithPort.AppendLiteral(":");
    1116               0 :       hostWithPort.AppendInt(port);
    1117                 :     }
    1118               0 :     params[0] = hostWithPort.get();
    1119                 : 
    1120               0 :     nsString formattedString;
    1121               0 :     rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix", 
    1122                 :                                                   params, 1, 
    1123               0 :                                                   formattedString);
    1124               0 :     if (NS_SUCCEEDED(rv))
    1125                 :     {
    1126               0 :       returnedMessage.Append(formattedString);
    1127               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
    1128                 :     }
    1129                 :   }
    1130                 : 
    1131               0 :   nsString explanation;
    1132               0 :   rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
    1133               0 :   if (NS_SUCCEEDED(rv))
    1134               0 :     returnedMessage.Append(explanation);
    1135                 : 
    1136               0 :   return NS_OK;
    1137                 : }
    1138                 : 
    1139                 : static void
    1140               0 : AppendErrorTextUntrusted(PRErrorCode errTrust,
    1141                 :                          const nsString &host,
    1142                 :                          nsIX509Cert* ix509,
    1143                 :                          nsINSSComponent *component,
    1144                 :                          nsString &returnedMessage)
    1145                 : {
    1146               0 :   const char *errorID = nsnull;
    1147               0 :   nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
    1148               0 :   if (cert3) {
    1149                 :     bool isSelfSigned;
    1150               0 :     if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
    1151                 :         && isSelfSigned) {
    1152               0 :       errorID = "certErrorTrust_SelfSigned";
    1153                 :     }
    1154                 :   }
    1155                 : 
    1156               0 :   if (!errorID) {
    1157               0 :     switch (errTrust) {
    1158                 :       case SEC_ERROR_UNKNOWN_ISSUER:
    1159                 :       {
    1160               0 :         nsCOMPtr<nsIArray> chain;
    1161               0 :         ix509->GetChain(getter_AddRefs(chain));
    1162               0 :         PRUint32 length = 0;
    1163               0 :         if (chain && NS_FAILED(chain->GetLength(&length)))
    1164               0 :           length = 0;
    1165               0 :         if (length == 1)
    1166               0 :           errorID = "certErrorTrust_MissingChain";
    1167                 :         else
    1168               0 :           errorID = "certErrorTrust_UnknownIssuer";
    1169                 :         break;
    1170                 :       }
    1171                 :       case SEC_ERROR_INADEQUATE_KEY_USAGE:
    1172                 :         // Should get an individual string in the future
    1173                 :         // For now, use the same as CaInvalid
    1174                 :       case SEC_ERROR_CA_CERT_INVALID:
    1175               0 :         errorID = "certErrorTrust_CaInvalid";
    1176               0 :         break;
    1177                 :       case SEC_ERROR_UNTRUSTED_ISSUER:
    1178               0 :         errorID = "certErrorTrust_Issuer";
    1179               0 :         break;
    1180                 :       case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
    1181               0 :         errorID = "certErrorTrust_ExpiredIssuer";
    1182               0 :         break;
    1183                 :       case SEC_ERROR_UNTRUSTED_CERT:
    1184                 :       default:
    1185               0 :         errorID = "certErrorTrust_Untrusted";
    1186               0 :         break;
    1187                 :     }
    1188                 :   }
    1189                 : 
    1190               0 :   nsString formattedString;
    1191                 :   nsresult rv = component->GetPIPNSSBundleString(errorID, 
    1192               0 :                                                  formattedString);
    1193               0 :   if (NS_SUCCEEDED(rv))
    1194                 :   {
    1195               0 :     returnedMessage.Append(formattedString);
    1196               0 :     returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1197                 :   }
    1198               0 : }
    1199                 : 
    1200                 : // returns TRUE if SAN was used to produce names
    1201                 : // return FALSE if nothing was produced
    1202                 : // names => a single name or a list of names
    1203                 : // multipleNames => whether multiple names were delivered
    1204                 : static bool
    1205               0 : GetSubjectAltNames(CERTCertificate *nssCert,
    1206                 :                    nsINSSComponent *component,
    1207                 :                    nsString &allNames,
    1208                 :                    PRUint32 &nameCount)
    1209                 : {
    1210               0 :   allNames.Truncate();
    1211               0 :   nameCount = 0;
    1212                 : 
    1213               0 :   PRArenaPool *san_arena = nsnull;
    1214               0 :   SECItem altNameExtension = {siBuffer, NULL, 0 };
    1215               0 :   CERTGeneralName *sanNameList = nsnull;
    1216                 : 
    1217                 :   nsresult rv;
    1218                 :   rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
    1219               0 :                               &altNameExtension);
    1220               0 :   if (rv != SECSuccess)
    1221               0 :     return false;
    1222                 : 
    1223               0 :   san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    1224               0 :   if (!san_arena)
    1225               0 :     return false;
    1226                 : 
    1227               0 :   sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
    1228               0 :   if (!sanNameList)
    1229               0 :     return false;
    1230                 : 
    1231               0 :   SECITEM_FreeItem(&altNameExtension, false);
    1232                 : 
    1233               0 :   CERTGeneralName *current = sanNameList;
    1234               0 :   do {
    1235               0 :     nsAutoString name;
    1236               0 :     switch (current->type) {
    1237                 :       case certDNSName:
    1238               0 :         name.AssignASCII((char*)current->name.other.data, current->name.other.len);
    1239               0 :         if (!allNames.IsEmpty()) {
    1240               0 :           allNames.Append(NS_LITERAL_STRING(" , "));
    1241                 :         }
    1242               0 :         ++nameCount;
    1243               0 :         allNames.Append(name);
    1244               0 :         break;
    1245                 : 
    1246                 :       case certIPAddress:
    1247                 :         {
    1248                 :           char buf[INET6_ADDRSTRLEN];
    1249                 :           PRNetAddr addr;
    1250               0 :           if (current->name.other.len == 4) {
    1251               0 :             addr.inet.family = PR_AF_INET;
    1252               0 :             memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
    1253               0 :             PR_NetAddrToString(&addr, buf, sizeof(buf));
    1254               0 :             name.AssignASCII(buf);
    1255               0 :           } else if (current->name.other.len == 16) {
    1256               0 :             addr.ipv6.family = PR_AF_INET6;
    1257               0 :             memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
    1258               0 :             PR_NetAddrToString(&addr, buf, sizeof(buf));
    1259               0 :             name.AssignASCII(buf);
    1260                 :           } else {
    1261                 :             /* invalid IP address */
    1262                 :           }
    1263               0 :           if (!name.IsEmpty()) {
    1264               0 :             if (!allNames.IsEmpty()) {
    1265               0 :               allNames.Append(NS_LITERAL_STRING(" , "));
    1266                 :             }
    1267               0 :             ++nameCount;
    1268               0 :             allNames.Append(name);
    1269                 :           }
    1270               0 :           break;
    1271                 :         }
    1272                 : 
    1273                 :       default: // all other types of names are ignored
    1274               0 :         break;
    1275                 :     }
    1276               0 :     current = CERT_GetNextGeneralName(current);
    1277                 :   } while (current != sanNameList); // double linked
    1278                 : 
    1279               0 :   PORT_FreeArena(san_arena, false);
    1280               0 :   return true;
    1281                 : }
    1282                 : 
    1283                 : static void
    1284               0 : AppendErrorTextMismatch(const nsString &host,
    1285                 :                         nsIX509Cert* ix509,
    1286                 :                         nsINSSComponent *component,
    1287                 :                         nsString &returnedMessage)
    1288                 : {
    1289                 :   const PRUnichar *params[1];
    1290                 :   nsresult rv;
    1291                 : 
    1292               0 :   CERTCertificate *nssCert = NULL;
    1293               0 :   CERTCertificateCleaner nssCertCleaner(nssCert);
    1294                 : 
    1295               0 :   nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
    1296               0 :   if (cert2)
    1297               0 :     nssCert = cert2->GetCert();
    1298                 : 
    1299               0 :   if (!nssCert) {
    1300                 :     // We are unable to extract the valid names, say "not valid for name".
    1301               0 :     params[0] = host.get();
    1302               0 :     nsString formattedString;
    1303                 :     rv = component->PIPBundleFormatStringFromName("certErrorMismatch", 
    1304                 :                                                   params, 1, 
    1305               0 :                                                   formattedString);
    1306               0 :     if (NS_SUCCEEDED(rv)) {
    1307               0 :       returnedMessage.Append(formattedString);
    1308               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1309                 :     }
    1310                 :     return;
    1311                 :   }
    1312                 : 
    1313               0 :   nsString allNames;
    1314               0 :   PRUint32 nameCount = 0;
    1315               0 :   bool useSAN = false;
    1316                 : 
    1317               0 :   if (nssCert)
    1318               0 :     useSAN = GetSubjectAltNames(nssCert, component, allNames, nameCount);
    1319                 : 
    1320               0 :   if (!useSAN) {
    1321               0 :     char *certName = nsnull;
    1322                 :     // currently CERT_FindNSStringExtension is not being exported by NSS.
    1323                 :     // If it gets exported, enable the following line.
    1324                 :     //   certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
    1325                 :     // However, it has been discussed to treat the extension as obsolete and ignore it.
    1326               0 :     if (!certName)
    1327               0 :       certName = CERT_GetCommonName(&nssCert->subject);
    1328               0 :     if (certName) {
    1329               0 :       ++nameCount;
    1330               0 :       allNames.AssignASCII(certName);
    1331               0 :       PORT_Free(certName);
    1332                 :     }
    1333                 :   }
    1334                 : 
    1335               0 :   if (nameCount > 1) {
    1336               0 :     nsString message;
    1337                 :     rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple", 
    1338               0 :                                           message);
    1339               0 :     if (NS_SUCCEEDED(rv)) {
    1340               0 :       returnedMessage.Append(message);
    1341               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n  "));
    1342               0 :       returnedMessage.Append(allNames);
    1343               0 :       returnedMessage.Append(NS_LITERAL_STRING("  \n"));
    1344                 :     }
    1345                 :   }
    1346               0 :   else if (nameCount == 1) {
    1347                 :     const PRUnichar *params[1];
    1348               0 :     params[0] = allNames.get();
    1349                 : 
    1350               0 :     nsString formattedString;
    1351                 :     rv = component->PIPBundleFormatStringFromName("certErrorMismatchSingle2", 
    1352                 :                                                   params, 1, 
    1353               0 :                                                   formattedString);
    1354               0 :     if (NS_SUCCEEDED(rv)) {
    1355               0 :       returnedMessage.Append(formattedString);
    1356               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1357                 :     }
    1358                 :   }
    1359                 :   else { // nameCount == 0
    1360               0 :     nsString message;
    1361                 :     nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames",
    1362               0 :                                                    message);
    1363               0 :     if (NS_SUCCEEDED(rv)) {
    1364               0 :       returnedMessage.Append(message);
    1365               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1366                 :     }
    1367                 :   }
    1368                 : }
    1369                 : 
    1370                 : static void
    1371               0 : GetDateBoundary(nsIX509Cert* ix509,
    1372                 :                 nsString &formattedDate,
    1373                 :                 nsString &nowDate,
    1374                 :                 bool &trueExpired_falseNotYetValid)
    1375                 : {
    1376               0 :   trueExpired_falseNotYetValid = true;
    1377               0 :   formattedDate.Truncate();
    1378                 : 
    1379                 :   PRTime notAfter, notBefore, timeToUse;
    1380               0 :   nsCOMPtr<nsIX509CertValidity> validity;
    1381                 :   nsresult rv;
    1382                 : 
    1383               0 :   rv = ix509->GetValidity(getter_AddRefs(validity));
    1384               0 :   if (NS_FAILED(rv))
    1385                 :     return;
    1386                 : 
    1387               0 :   rv = validity->GetNotAfter(&notAfter);
    1388               0 :   if (NS_FAILED(rv))
    1389                 :     return;
    1390                 : 
    1391               0 :   rv = validity->GetNotBefore(&notBefore);
    1392               0 :   if (NS_FAILED(rv))
    1393                 :     return;
    1394                 : 
    1395               0 :   PRTime now = PR_Now();
    1396               0 :   if (LL_CMP(now, >, notAfter)) {
    1397               0 :     timeToUse = notAfter;
    1398                 :   } else {
    1399               0 :     timeToUse = notBefore;
    1400               0 :     trueExpired_falseNotYetValid = false;
    1401                 :   }
    1402                 : 
    1403               0 :   nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv));
    1404               0 :   if (NS_FAILED(rv))
    1405                 :     return;
    1406                 : 
    1407               0 :   dateTimeFormat->FormatPRTime(nsnull, kDateFormatShort, 
    1408                 :                                kTimeFormatNoSeconds, timeToUse, 
    1409               0 :                                formattedDate);
    1410               0 :   dateTimeFormat->FormatPRTime(nsnull, kDateFormatShort,
    1411                 :                                kTimeFormatNoSeconds, now,
    1412               0 :                                nowDate);
    1413                 : }
    1414                 : 
    1415                 : static void
    1416               0 : AppendErrorTextTime(nsIX509Cert* ix509,
    1417                 :                     nsINSSComponent *component,
    1418                 :                     nsString &returnedMessage)
    1419                 : {
    1420               0 :   nsAutoString formattedDate, nowDate;
    1421                 :   bool trueExpired_falseNotYetValid;
    1422               0 :   GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
    1423                 : 
    1424                 :   const PRUnichar *params[2];
    1425               0 :   params[0] = formattedDate.get(); // might be empty, if helper function had a problem 
    1426               0 :   params[1] = nowDate.get();
    1427                 : 
    1428                 :   const char *key = trueExpired_falseNotYetValid ? 
    1429               0 :                     "certErrorExpiredNow" : "certErrorNotYetValidNow";
    1430                 :   nsresult rv;
    1431               0 :   nsString formattedString;
    1432                 :   rv = component->PIPBundleFormatStringFromName(
    1433                 :            key,
    1434                 :            params, 
    1435                 :            ArrayLength(params),
    1436               0 :            formattedString);
    1437               0 :   if (NS_SUCCEEDED(rv))
    1438                 :   {
    1439               0 :     returnedMessage.Append(formattedString);
    1440               0 :     returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1441                 :   }
    1442               0 : }
    1443                 : 
    1444                 : static void
    1445               0 : AppendErrorTextCode(PRErrorCode errorCodeToReport,
    1446                 :                     nsINSSComponent *component,
    1447                 :                     nsString &returnedMessage)
    1448                 : {
    1449               0 :   const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
    1450               0 :   if (codeName)
    1451                 :   {
    1452               0 :     nsCString error_id(codeName);
    1453               0 :     ToLowerCase(error_id);
    1454               0 :     NS_ConvertASCIItoUTF16 idU(error_id);
    1455                 : 
    1456                 :     const PRUnichar *params[1];
    1457               0 :     params[0] = idU.get();
    1458                 : 
    1459               0 :     nsString formattedString;
    1460                 :     nsresult rv;
    1461                 :     rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix", 
    1462                 :                                                   params, 1, 
    1463               0 :                                                   formattedString);
    1464               0 :     if (NS_SUCCEEDED(rv)) {
    1465               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1466               0 :       returnedMessage.Append(formattedString);
    1467               0 :       returnedMessage.Append(NS_LITERAL_STRING("\n"));
    1468                 :     }
    1469                 :     else {
    1470               0 :       returnedMessage.Append(NS_LITERAL_STRING(" ("));
    1471               0 :       returnedMessage.Append(idU);
    1472               0 :       returnedMessage.Append(NS_LITERAL_STRING(")"));
    1473                 :     }
    1474                 :   }
    1475               0 : }
    1476                 : 
    1477                 : /* Formats an error message for overridable certificate errors (of type
    1478                 :  * OverridableCertErrorMessage). Use formatPlainErrorMessage to format
    1479                 :  * non-overridable cert errors and non-cert-related errors.
    1480                 :  */
    1481                 : static nsresult
    1482               0 : formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
    1483                 :                                   PRErrorCode errorCodeToReport, 
    1484                 :                                   const nsXPIDLCString & host, PRInt32 port,
    1485                 :                                   nsString & returnedMessage)
    1486                 : {
    1487                 :   const PRUnichar *params[1];
    1488                 :   nsresult rv;
    1489               0 :   nsAutoString hostWithPort;
    1490               0 :   nsAutoString hostWithoutPort;
    1491                 : 
    1492                 :   // For now, hide port when it's 443 and we're reporting the error.
    1493                 :   // In the future a better mechanism should be used
    1494                 :   // to make a decision about showing the port number, possibly by requiring
    1495                 :   // the context object to implement a specific interface.
    1496                 :   // The motivation is that Mozilla browser would like to hide the port number
    1497                 :   // in error pages in the common case.
    1498                 :   
    1499               0 :   hostWithoutPort.AppendASCII(host);
    1500               0 :   if (port == 443) {
    1501               0 :     params[0] = hostWithoutPort.get();
    1502                 :   } else {
    1503               0 :     hostWithPort.AppendASCII(host);
    1504               0 :     hostWithPort.Append(':');
    1505               0 :     hostWithPort.AppendInt(port);
    1506               0 :     params[0] = hostWithPort.get();
    1507                 :   }
    1508                 : 
    1509               0 :   nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
    1510               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1511                 : 
    1512               0 :   returnedMessage.Truncate();
    1513               0 :   rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
    1514               0 :                                                 returnedMessage);
    1515               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1516                 : 
    1517               0 :   returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
    1518                 : 
    1519               0 :   nsRefPtr<nsIX509Cert> ix509;
    1520               0 :   rv = sslStatus.GetServerCert(getter_AddRefs(ix509));
    1521               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1522                 : 
    1523                 :   bool isUntrusted;
    1524               0 :   rv = sslStatus.GetIsUntrusted(&isUntrusted);
    1525               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1526               0 :   if (isUntrusted) {
    1527                 :     AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509, 
    1528               0 :                              component, returnedMessage);
    1529                 :   }
    1530                 : 
    1531                 :   bool isDomainMismatch;
    1532               0 :   rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
    1533               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1534               0 :   if (isDomainMismatch) {
    1535               0 :     AppendErrorTextMismatch(hostWithoutPort, ix509, component, returnedMessage);
    1536                 :   }
    1537                 : 
    1538                 :   bool isNotValidAtThisTime;
    1539               0 :   rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
    1540               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1541               0 :   if (isNotValidAtThisTime) {
    1542               0 :     AppendErrorTextTime(ix509, component, returnedMessage);
    1543                 :   }
    1544                 : 
    1545               0 :   AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
    1546                 : 
    1547               0 :   return NS_OK;
    1548                 : }
    1549                 : 
    1550                 : static void
    1551               0 : nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRErrorCode err)
    1552                 : {
    1553               0 :   if (!NS_IsMainThread()) {
    1554               0 :     NS_ERROR("nsHandleSSLError called off the main thread");
    1555               0 :     return;
    1556                 :   }
    1557                 : 
    1558                 :   // SetCanceled is only called by the main thread or the socket transport
    1559                 :   // thread. Whenever this function is called on the main thread, the SSL
    1560                 :   // thread is blocked on it. So, no mutex is necessary for
    1561                 :   // SetCanceled()/GetError*().
    1562               0 :   if (socketInfo->GetErrorCode()) {
    1563                 :     // If the socket has been flagged as canceled,
    1564                 :     // the code who did was responsible for setting the error code.
    1565               0 :     return;
    1566                 :   }
    1567                 : 
    1568                 :   nsresult rv;
    1569               0 :   NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
    1570               0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
    1571               0 :   if (NS_FAILED(rv))
    1572                 :     return;
    1573                 : 
    1574               0 :   nsXPIDLCString hostName;
    1575               0 :   socketInfo->GetHostName(getter_Copies(hostName));
    1576                 : 
    1577                 :   PRInt32 port;
    1578               0 :   socketInfo->GetPort(&port);
    1579                 : 
    1580                 :   // Try to get a nsISSLErrorListener implementation from the socket consumer.
    1581               0 :   nsCOMPtr<nsIInterfaceRequestor> cb;
    1582               0 :   socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
    1583               0 :   if (cb) {
    1584               0 :     nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
    1585               0 :     if (sel) {
    1586               0 :       nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
    1587               0 :       nsCString hostWithPortString = hostName;
    1588               0 :       hostWithPortString.AppendLiteral(":");
    1589               0 :       hostWithPortString.AppendInt(port);
    1590                 :     
    1591               0 :       bool suppressMessage = false; // obsolete, ignored
    1592               0 :       rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
    1593                 :     }
    1594                 :   }
    1595                 : 
    1596               0 :   socketInfo->SetCanceled(err, PlainErrorMessage);
    1597                 : }
    1598                 : 
    1599                 : namespace {
    1600                 : 
    1601                 : enum Operation { reading, writing, not_reading_or_writing };
    1602                 : 
    1603                 : PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
    1604                 :                        PRFileDesc* ssl_layer_fd,
    1605                 :                        nsNSSSocketInfo *socketInfo);
    1606                 : 
    1607                 : nsNSSSocketInfo *
    1608             326 : getSocketInfoIfRunning(PRFileDesc * fd, Operation op,
    1609                 :                        const nsNSSShutDownPreventionLock & /*proofOfLock*/)
    1610                 : {
    1611             326 :   if (!fd || !fd->lower || !fd->secret ||
    1612                 :       fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
    1613               0 :     NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
    1614               0 :     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    1615               0 :     return nsnull;
    1616                 :   }
    1617                 : 
    1618             326 :   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
    1619                 : 
    1620             326 :   if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
    1621               0 :     PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
    1622               0 :     return nsnull;
    1623                 :   }
    1624                 : 
    1625             326 :   if (socketInfo->GetErrorCode()) {
    1626               0 :     PRErrorCode err = socketInfo->GetErrorCode();
    1627               0 :     PR_SetError(err, 0);
    1628               0 :     if (op == reading || op == writing) {
    1629                 :       // We must do TLS intolerance checks for reads and writes, for timeouts
    1630                 :       // in particular.
    1631               0 :       (void) checkHandshake(-1, op == reading, fd, socketInfo);
    1632                 :     }
    1633                 : 
    1634                 :     // If we get here, it is probably because cert verification failed and this
    1635                 :     // is the first I/O attempt since that failure.
    1636               0 :     return nsnull;
    1637                 :   }
    1638                 : 
    1639             326 :   return socketInfo;
    1640                 : }
    1641                 : 
    1642                 : } // unnnamed namespace
    1643                 : 
    1644                 : static PRStatus PR_CALLBACK
    1645               4 : nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
    1646                 :                     PRIntervalTime timeout)
    1647                 : {
    1648               4 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
    1649               8 :   nsNSSShutDownPreventionLock locker;
    1650               4 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    1651               0 :     return PR_FAILURE;
    1652                 :   
    1653               4 :   PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
    1654               4 :   if (status != PR_SUCCESS) {
    1655               4 :     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
    1656                 :                                       (void*)fd, PR_GetError()));
    1657               4 :     return status;
    1658                 :   }
    1659                 : 
    1660               0 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));
    1661               0 :   return status;
    1662                 : }
    1663                 : 
    1664                 : // nsPSMRememberCertErrorsTable
    1665                 : 
    1666             328 : nsPSMRememberCertErrorsTable::nsPSMRememberCertErrorsTable()
    1667                 : {
    1668             328 :   mErrorHosts.Init(16);
    1669             328 : }
    1670                 : 
    1671                 : nsresult
    1672               8 : nsPSMRememberCertErrorsTable::GetHostPortKey(nsNSSSocketInfo* infoObject,
    1673                 :                                              nsCAutoString &result)
    1674                 : {
    1675                 :   nsresult rv;
    1676                 : 
    1677               8 :   result.Truncate();
    1678                 : 
    1679              16 :   nsXPIDLCString hostName;
    1680               8 :   rv = infoObject->GetHostName(getter_Copies(hostName));
    1681               8 :   NS_ENSURE_SUCCESS(rv, rv);
    1682                 : 
    1683                 :   PRInt32 port;
    1684               8 :   rv = infoObject->GetPort(&port);
    1685               8 :   NS_ENSURE_SUCCESS(rv, rv);
    1686                 : 
    1687               8 :   result.Assign(hostName);
    1688               8 :   result.Append(':');
    1689               8 :   result.AppendInt(port);
    1690                 : 
    1691               8 :   return NS_OK;
    1692                 : }
    1693                 : 
    1694                 : void
    1695               4 : nsPSMRememberCertErrorsTable::RememberCertHasError(nsNSSSocketInfo* infoObject,
    1696                 :                                                    nsSSLStatus* status,
    1697                 :                                                    SECStatus certVerificationResult)
    1698                 : {
    1699                 :   nsresult rv;
    1700                 : 
    1701               8 :   nsCAutoString hostPortKey;
    1702               4 :   rv = GetHostPortKey(infoObject, hostPortKey);
    1703               4 :   if (NS_FAILED(rv))
    1704                 :     return;
    1705                 : 
    1706               4 :   if (certVerificationResult != SECSuccess) {
    1707               0 :     NS_ASSERTION(status,
    1708                 :         "Must have nsSSLStatus object when remembering flags");
    1709                 : 
    1710               0 :     if (!status)
    1711                 :       return;
    1712                 : 
    1713                 :     CertStateBits bits;
    1714               0 :     bits.mIsDomainMismatch = status->mIsDomainMismatch;
    1715               0 :     bits.mIsNotValidAtThisTime = status->mIsNotValidAtThisTime;
    1716               0 :     bits.mIsUntrusted = status->mIsUntrusted;
    1717               0 :     mErrorHosts.Put(hostPortKey, bits);
    1718                 :   }
    1719                 :   else {
    1720               4 :     mErrorHosts.Remove(hostPortKey);
    1721                 :   }
    1722                 : }
    1723                 : 
    1724                 : void
    1725               4 : nsPSMRememberCertErrorsTable::LookupCertErrorBits(nsNSSSocketInfo* infoObject,
    1726                 :                                                   nsSSLStatus* status)
    1727                 : {
    1728                 :   // Get remembered error bits from our cache, because of SSL session caching
    1729                 :   // the NSS library potentially hasn't notified us for this socket.
    1730               4 :   if (status->mHaveCertErrorBits)
    1731                 :     // Rather do not modify bits if already set earlier
    1732               0 :     return;
    1733                 : 
    1734                 :   nsresult rv;
    1735                 : 
    1736               8 :   nsCAutoString hostPortKey;
    1737               4 :   rv = GetHostPortKey(infoObject, hostPortKey);
    1738               4 :   if (NS_FAILED(rv))
    1739                 :     return;
    1740                 : 
    1741                 :   CertStateBits bits;
    1742               4 :   if (!mErrorHosts.Get(hostPortKey, &bits))
    1743                 :     // No record was found, this host had no cert errors
    1744                 :     return;
    1745                 : 
    1746                 :   // This host had cert errors, update the bits correctly
    1747               0 :   status->mHaveCertErrorBits = true;
    1748               0 :   status->mIsDomainMismatch = bits.mIsDomainMismatch;
    1749               0 :   status->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
    1750               0 :   status->mIsUntrusted = bits.mIsUntrusted;
    1751                 : }
    1752                 : 
    1753                 : void
    1754               4 : nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key)
    1755                 : {
    1756                 :   PRInt32 port;
    1757               4 :   socketInfo->GetPort(&port);
    1758                 : 
    1759               8 :   nsXPIDLCString host;
    1760               4 :   socketInfo->GetHostName(getter_Copies(host));
    1761                 : 
    1762               4 :   key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
    1763               4 : }
    1764                 : 
    1765                 : // Call this function to report a site that is possibly TLS intolerant.
    1766                 : // This function will return true, if the given socket is currently using TLS.
    1767                 : bool
    1768               0 : nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo)
    1769                 : {
    1770               0 :   nsCAutoString key;
    1771               0 :   getSiteKey(socketInfo, key);
    1772                 : 
    1773               0 :   if (!socketInfo->IsTLSEnabled()) {
    1774                 :     // We did not offer TLS but failed with an intolerant error using
    1775                 :     // a different protocol. To give TLS a try on next connection attempt again
    1776                 :     // drop this site from the list of intolerant sites. TLS failure might be 
    1777                 :     // caused only by a traffic congestion while the server is TLS tolerant.
    1778               0 :     removeIntolerantSite(key);
    1779               0 :     return false;
    1780                 :   }
    1781                 : 
    1782               0 :   if (socketInfo->IsSSL3Enabled()) {
    1783                 :     // Add this site to the list of TLS intolerant sites.
    1784               0 :     addIntolerantSite(key);
    1785                 :   }
    1786                 :   
    1787               0 :   return socketInfo->IsTLSEnabled();
    1788                 : }
    1789                 : 
    1790                 : void
    1791               4 : nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo *socketInfo)
    1792                 : {
    1793               4 :   if (!socketInfo->IsTLSEnabled())
    1794               0 :     return;
    1795                 : 
    1796               8 :   nsCAutoString key;
    1797               4 :   getSiteKey(socketInfo, key);
    1798                 : 
    1799               8 :   MutexAutoLock lock(*mutex);
    1800               4 :   nsSSLIOLayerHelpers::mTLSTolerantSites->PutEntry(key);
    1801                 : }
    1802                 : 
    1803                 : static PRStatus PR_CALLBACK
    1804               4 : nsSSLIOLayerClose(PRFileDesc *fd)
    1805                 : {
    1806               8 :   nsNSSShutDownPreventionLock locker;
    1807               4 :   if (!fd)
    1808               0 :     return PR_FAILURE;
    1809                 : 
    1810               4 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
    1811                 :   
    1812               4 :   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
    1813               4 :   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
    1814                 : 
    1815               4 :   return socketInfo->CloseSocketAndDestroy(locker);
    1816                 : }
    1817                 : 
    1818               4 : PRStatus nsNSSSocketInfo::CloseSocketAndDestroy(
    1819                 :   const nsNSSShutDownPreventionLock & /*proofOfLock*/)
    1820                 : {
    1821               4 :   nsNSSShutDownList::trackSSLSocketClose();
    1822                 : 
    1823               4 :   PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
    1824                 : 
    1825               4 :   PRStatus status = mFd->methods->close(mFd);
    1826                 :   
    1827                 :   // the nsNSSSocketInfo instance can out-live the connection, so we need some
    1828                 :   // indication that the connection has been closed. mFd == nsnull is that
    1829                 :   // indication. This is needed, for example, when the connection is closed
    1830                 :   // before we have finished validating the server's certificate.
    1831               4 :   mFd = nsnull;
    1832                 :   
    1833               4 :   if (status != PR_SUCCESS) return status;
    1834                 : 
    1835               4 :   popped->identity = PR_INVALID_IO_LAYER;
    1836               4 :   NS_RELEASE_THIS();
    1837               4 :   popped->dtor(popped);
    1838                 : 
    1839               4 :   return PR_SUCCESS;
    1840                 : }
    1841                 : 
    1842                 : #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
    1843                 : /* Dumps a (potentially binary) buffer using SSM_DEBUG. 
    1844                 :    (We could have used the version in ssltrace.c, but that's
    1845                 :    specifically tailored to SSLTRACE. Sigh. */
    1846                 : #define DUMPBUF_LINESIZE 24
    1847                 : static void
    1848                 : nsDumpBuffer(unsigned char *buf, PRIntn len)
    1849                 : {
    1850                 :   char hexbuf[DUMPBUF_LINESIZE*3+1];
    1851                 :   char chrbuf[DUMPBUF_LINESIZE+1];
    1852                 :   static const char *hex = "0123456789abcdef";
    1853                 :   PRIntn i = 0, l = 0;
    1854                 :   char ch, *c, *h;
    1855                 :   if (len == 0)
    1856                 :     return;
    1857                 :   hexbuf[DUMPBUF_LINESIZE*3] = '\0';
    1858                 :   chrbuf[DUMPBUF_LINESIZE] = '\0';
    1859                 :   (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
    1860                 :   (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
    1861                 :   h = hexbuf;
    1862                 :   c = chrbuf;
    1863                 : 
    1864                 :   while (i < len)
    1865                 :   {
    1866                 :     ch = buf[i];
    1867                 : 
    1868                 :     if (l == DUMPBUF_LINESIZE)
    1869                 :     {
    1870                 :       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
    1871                 :       (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
    1872                 :       (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
    1873                 :       h = hexbuf;
    1874                 :       c = chrbuf;
    1875                 :       l = 0;
    1876                 :     }
    1877                 : 
    1878                 :     /* Convert a character to hex. */
    1879                 :     *h++ = hex[(ch >> 4) & 0xf];
    1880                 :     *h++ = hex[ch & 0xf];
    1881                 :     h++;
    1882                 :         
    1883                 :     /* Put the character (if it's printable) into the character buffer. */
    1884                 :     if ((ch >= 0x20) && (ch <= 0x7e))
    1885                 :       *c++ = ch;
    1886                 :     else
    1887                 :       *c++ = '.';
    1888                 :     i++; l++;
    1889                 :   }
    1890                 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
    1891                 : }
    1892                 : 
    1893                 : #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
    1894                 : #else
    1895                 : #define DEBUG_DUMP_BUFFER(buf,len)
    1896                 : #endif
    1897                 : 
    1898                 : static bool
    1899               0 : isNonSSLErrorThatWeAllowToRetry(PRInt32 err, bool withInitialCleartext)
    1900                 : {
    1901               0 :   switch (err)
    1902                 :   {
    1903                 :     case PR_CONNECT_RESET_ERROR:
    1904               0 :       if (!withInitialCleartext)
    1905               0 :         return true;
    1906               0 :       break;
    1907                 :     
    1908                 :     case PR_END_OF_FILE_ERROR:
    1909               0 :       return true;
    1910                 :   }
    1911                 : 
    1912               0 :   return false;
    1913                 : }
    1914                 : 
    1915                 : static bool
    1916               0 : isTLSIntoleranceError(PRInt32 err, bool withInitialCleartext)
    1917                 : {
    1918                 :   // This function is supposed to decide, which error codes should
    1919                 :   // be used to conclude server is TLS intolerant.
    1920                 :   // Note this only happens during the initial SSL handshake.
    1921                 :   // 
    1922                 :   // When not using a proxy we'll see a connection reset error.
    1923                 :   // When using a proxy, we'll see an end of file error.
    1924                 :   // In addition check for some error codes where it is reasonable
    1925                 :   // to retry without TLS.
    1926                 : 
    1927               0 :   if (isNonSSLErrorThatWeAllowToRetry(err, withInitialCleartext))
    1928               0 :     return true;
    1929                 : 
    1930               0 :   switch (err)
    1931                 :   {
    1932                 :     case SSL_ERROR_BAD_MAC_ALERT:
    1933                 :     case SSL_ERROR_BAD_MAC_READ:
    1934                 :     case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
    1935                 :     case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
    1936                 :     case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
    1937                 :     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
    1938                 :     case SSL_ERROR_NO_CYPHER_OVERLAP:
    1939                 :     case SSL_ERROR_BAD_SERVER:
    1940                 :     case SSL_ERROR_BAD_BLOCK_PADDING:
    1941                 :     case SSL_ERROR_UNSUPPORTED_VERSION:
    1942                 :     case SSL_ERROR_PROTOCOL_VERSION_ALERT:
    1943                 :     case SSL_ERROR_RX_MALFORMED_FINISHED:
    1944                 :     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
    1945                 :     case SSL_ERROR_DECODE_ERROR_ALERT:
    1946                 :     case SSL_ERROR_RX_UNKNOWN_ALERT:
    1947               0 :       return true;
    1948                 :   }
    1949                 :   
    1950               0 :   return false;
    1951                 : }
    1952                 : 
    1953                 : class SSLErrorRunnable : public SyncRunnableBase
    1954               0 : {
    1955                 :  public:
    1956               0 :   SSLErrorRunnable(nsNSSSocketInfo * infoObject, PRErrorCode errorCode)
    1957               0 :     : mInfoObject(infoObject), mErrorCode(errorCode)
    1958                 :   {
    1959               0 :   }
    1960                 : 
    1961               0 :   virtual void RunOnTargetThread()
    1962                 :   {
    1963               0 :     nsHandleSSLError(mInfoObject, mErrorCode);
    1964               0 :   }
    1965                 :   
    1966                 :   nsRefPtr<nsNSSSocketInfo> mInfoObject;
    1967                 :   const PRErrorCode mErrorCode;
    1968                 : };
    1969                 : 
    1970                 : namespace {
    1971                 : 
    1972              32 : PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
    1973                 :                        PRFileDesc* ssl_layer_fd,
    1974                 :                        nsNSSSocketInfo *socketInfo)
    1975                 : {
    1976                 :   // This is where we work around all of those SSL servers that don't 
    1977                 :   // conform to the SSL spec and shutdown a connection when we request
    1978                 :   // SSL v3.1 (aka TLS).  The spec says the client says what version
    1979                 :   // of the protocol we're willing to perform, in our case SSL v3.1
    1980                 :   // In its response, the server says which version it wants to perform.
    1981                 :   // Many servers out there only know how to do v3.0.  Next, we're supposed
    1982                 :   // to send back the version of the protocol we requested (ie v3.1).  At
    1983                 :   // this point many servers's implementations are broken and they shut
    1984                 :   // down the connection when they don't see the version they sent back.
    1985                 :   // This is supposed to prevent a man in the middle from forcing one
    1986                 :   // side to dumb down to a lower level of the protocol.  Unfortunately,
    1987                 :   // there are enough broken servers out there that such a gross work-around
    1988                 :   // is necessary.  :(
    1989                 : 
    1990                 :   // Additional comment added in August 2006:
    1991                 :   // When we begun to use TLS hello extensions, we encountered a new class of
    1992                 :   // broken server, which simply stall for a very long time.
    1993                 :   // We would like to shorten the timeout, but limit this shorter timeout 
    1994                 :   // to the handshake phase.
    1995                 :   // When we arrive here for the first time (for a given socket),
    1996                 :   // we know the connection is established, and the application code
    1997                 :   // tried the first read or write. This triggers the beginning of the
    1998                 :   // SSL handshake phase at the SSL FD level.
    1999                 :   // We'll make a note of the current time,
    2000                 :   // and use this to measure the elapsed time since handshake begin.
    2001                 : 
    2002                 :   // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
    2003                 :   // Simply retry.
    2004                 :   // This depends on the fact that Cert UI will not be shown again,
    2005                 :   // should the user override the bad cert.
    2006                 : 
    2007                 :   bool handleHandshakeResultNow;
    2008              32 :   socketInfo->GetHandshakePending(&handleHandshakeResultNow);
    2009                 : 
    2010              32 :   bool wantRetry = false;
    2011                 : 
    2012              32 :   if (0 > bytesTransfered) {
    2013              16 :     PRInt32 err = PR_GetError();
    2014                 : 
    2015              16 :     if (handleHandshakeResultNow) {
    2016               8 :       if (PR_WOULD_BLOCK_ERROR == err) {
    2017               8 :         socketInfo->SetHandshakeInProgress(true);
    2018               8 :         return bytesTransfered;
    2019                 :       }
    2020                 : 
    2021               0 :       if (!wantRetry // no decision yet
    2022               0 :           && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
    2023                 :       {
    2024               0 :         wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
    2025                 :       }
    2026                 :     }
    2027                 :     
    2028                 :     // This is the common place where we trigger non-cert-errors on a SSL
    2029                 :     // socket. This might be reached at any time of the connection.
    2030                 :     //
    2031                 :     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
    2032                 :     // do the synchronous dispatch to the main thread unnecessarily after we've
    2033                 :     // already handled a certificate error. (SSLErrorRunnable calls
    2034                 :     // nsHandleSSLError, which has logic to avoid replacing the error message,
    2035                 :     // so without the !socketInfo->GetErrorCode(), it would just be an
    2036                 :     // expensive no-op.)
    2037               8 :     if (!wantRetry && (IS_SSL_ERROR(err) || IS_SEC_ERROR(err)) &&
    2038               0 :         !socketInfo->GetErrorCode()) {
    2039                 :       nsRefPtr<SyncRunnableBase> runnable = new SSLErrorRunnable(socketInfo,
    2040               0 :                                                                  err);
    2041               0 :       (void) runnable->DispatchToMainThreadAndWait();
    2042                 :     }
    2043                 :   }
    2044              16 :   else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
    2045                 :   {
    2046               0 :     if (handleHandshakeResultNow)
    2047                 :     {
    2048               0 :       if (!wantRetry // no decision yet
    2049               0 :           && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
    2050                 :       {
    2051                 :         wantRetry = 
    2052               0 :           nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
    2053                 :       }
    2054                 :     }
    2055                 :   }
    2056                 : 
    2057              24 :   if (wantRetry) {
    2058                 :     // We want to cause the network layer to retry the connection.
    2059               0 :     PR_SetError(PR_CONNECT_RESET_ERROR, 0);
    2060               0 :     if (wasReading)
    2061               0 :       bytesTransfered = -1;
    2062                 :   }
    2063                 : 
    2064                 :   // TLS intolerant servers only cause the first transfer to fail, so let's 
    2065                 :   // set the HandshakePending attribute to false so that we don't try the logic
    2066                 :   // above again in a subsequent transfer.
    2067              24 :   if (handleHandshakeResultNow) {
    2068               4 :     socketInfo->SetHandshakePending(false);
    2069               4 :     socketInfo->SetHandshakeInProgress(false);
    2070                 :   }
    2071                 :   
    2072              24 :   return bytesTransfered;
    2073                 : }
    2074                 : 
    2075                 : }
    2076                 : 
    2077                 : static PRInt16 PR_CALLBACK
    2078             270 : nsSSLIOLayerPoll(PRFileDesc * fd, PRInt16 in_flags, PRInt16 *out_flags)
    2079                 : {
    2080             540 :   nsNSSShutDownPreventionLock locker;
    2081                 : 
    2082             270 :   if (!out_flags)
    2083                 :   {
    2084               0 :     NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
    2085               0 :     return 0;
    2086                 :   }
    2087                 : 
    2088             270 :   *out_flags = 0;
    2089                 : 
    2090                 :   nsNSSSocketInfo * socketInfo =
    2091             270 :     getSocketInfoIfRunning(fd, not_reading_or_writing, locker);
    2092                 : 
    2093             270 :   if (!socketInfo) {
    2094                 :     // If we get here, it is probably because certificate validation failed
    2095                 :     // and this is the first I/O operation after the failure. 
    2096               0 :     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
    2097                 :             ("[%p] polling SSL socket right after certificate verification failed "
    2098                 :                   "or NSS shutdown or SDR logout %d\n",
    2099                 :              fd, (int) in_flags));
    2100                 : 
    2101               0 :     NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
    2102                 :                  "caller did not poll for EXCEPT (canceled)");
    2103                 :     // Since this poll method cannot return errors, we want the caller to call
    2104                 :     // PR_Send/PR_Recv right away to get the error, so we tell that we are
    2105                 :     // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning). 
    2106               0 :     *out_flags = in_flags | PR_POLL_EXCEPT; // see also bug 480619 
    2107               0 :     return in_flags;
    2108                 :   }
    2109                 : 
    2110             270 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
    2111                 :          (socketInfo->IsWaitingForCertVerification()
    2112                 :             ?  "[%p] polling SSL socket during certificate verification using lower %d\n"
    2113                 :             :  "[%p] poll SSL socket using lower %d\n",
    2114                 :          fd, (int) in_flags));
    2115                 : 
    2116                 :   // See comments in HandshakeTimeout before moving and/or changing this block
    2117             270 :   if (socketInfo->HandshakeTimeout()) {
    2118               0 :     NS_WARNING("SSL handshake timed out");
    2119               0 :     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] handshake timed out\n", fd));
    2120               0 :     NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
    2121                 :                  "caller did not poll for EXCEPT (handshake timeout)");
    2122               0 :     *out_flags = in_flags | PR_POLL_EXCEPT;
    2123               0 :     socketInfo->SetCanceled(PR_CONNECT_RESET_ERROR, PlainErrorMessage);
    2124               0 :     return in_flags;
    2125                 :   }
    2126                 : 
    2127                 :   // We want the handshake to continue during certificate validation, so we
    2128                 :   // don't need to do anything special here. libssl automatically blocks when
    2129                 :   // it reaches any point that would be unsafe to send/receive something before
    2130                 :   // cert validation is complete.
    2131             270 :   PRInt16 result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
    2132             270 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
    2133                 :                                     (void*)fd, (int) result));
    2134             270 :   return result;
    2135                 : }
    2136                 : 
    2137                 : bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
    2138                 : PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
    2139                 : PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
    2140                 : Mutex *nsSSLIOLayerHelpers::mutex = nsnull;
    2141                 : nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
    2142                 : nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSTolerantSites = nsnull;
    2143                 : nsPSMRememberCertErrorsTable *nsSSLIOLayerHelpers::mHostsWithCertErrors = nsnull;
    2144                 : nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mRenegoUnrestrictedSites = nsnull;
    2145                 : bool nsSSLIOLayerHelpers::mTreatUnsafeNegotiationAsBroken = false;
    2146                 : PRInt32 nsSSLIOLayerHelpers::mWarnLevelMissingRFC5746 = 1;
    2147                 : 
    2148               0 : static PRIntn _PSM_InvalidInt(void)
    2149                 : {
    2150               0 :     PR_ASSERT(!"I/O method is invalid");
    2151               0 :     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    2152               0 :     return -1;
    2153                 : }
    2154                 : 
    2155               0 : static PRInt64 _PSM_InvalidInt64(void)
    2156                 : {
    2157               0 :     PR_ASSERT(!"I/O method is invalid");
    2158               0 :     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    2159               0 :     return -1;
    2160                 : }
    2161                 : 
    2162               0 : static PRStatus _PSM_InvalidStatus(void)
    2163                 : {
    2164               0 :     PR_ASSERT(!"I/O method is invalid");
    2165               0 :     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    2166               0 :     return PR_FAILURE;
    2167                 : }
    2168                 : 
    2169               0 : static PRFileDesc *_PSM_InvalidDesc(void)
    2170                 : {
    2171               0 :     PR_ASSERT(!"I/O method is invalid");
    2172               0 :     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
    2173               0 :     return NULL;
    2174                 : }
    2175                 : 
    2176               8 : static PRStatus PR_CALLBACK PSMGetsockname(PRFileDesc *fd, PRNetAddr *addr)
    2177                 : {
    2178              16 :   nsNSSShutDownPreventionLock locker;
    2179               8 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    2180               0 :     return PR_FAILURE;
    2181                 : 
    2182               8 :   return fd->lower->methods->getsockname(fd->lower, addr);
    2183                 : }
    2184                 : 
    2185               0 : static PRStatus PR_CALLBACK PSMGetpeername(PRFileDesc *fd, PRNetAddr *addr)
    2186                 : {
    2187               0 :   nsNSSShutDownPreventionLock locker;
    2188               0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    2189               0 :     return PR_FAILURE;
    2190                 : 
    2191               0 :   return fd->lower->methods->getpeername(fd->lower, addr);
    2192                 : }
    2193                 : 
    2194               0 : static PRStatus PR_CALLBACK PSMGetsocketoption(PRFileDesc *fd, 
    2195                 :                                         PRSocketOptionData *data)
    2196                 : {
    2197               0 :   nsNSSShutDownPreventionLock locker;
    2198               0 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    2199               0 :     return PR_FAILURE;
    2200                 : 
    2201               0 :   return fd->lower->methods->getsocketoption(fd, data);
    2202                 : }
    2203                 : 
    2204               8 : static PRStatus PR_CALLBACK PSMSetsocketoption(PRFileDesc *fd, 
    2205                 :                                         const PRSocketOptionData *data)
    2206                 : {
    2207              16 :   nsNSSShutDownPreventionLock locker;
    2208               8 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
    2209               0 :     return PR_FAILURE;
    2210                 : 
    2211               8 :   return fd->lower->methods->setsocketoption(fd, data);
    2212                 : }
    2213                 : 
    2214              16 : static PRInt32 PR_CALLBACK PSMRecv(PRFileDesc *fd, void *buf, PRInt32 amount,
    2215                 :     PRIntn flags, PRIntervalTime timeout)
    2216                 : {
    2217              32 :   nsNSSShutDownPreventionLock locker;
    2218              16 :   nsNSSSocketInfo *socketInfo = getSocketInfoIfRunning(fd, reading, locker);
    2219              16 :   if (!socketInfo)
    2220               0 :     return -1;
    2221                 : 
    2222              16 :   if (flags != PR_MSG_PEEK && flags != 0) {
    2223               0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    2224               0 :     return -1;
    2225                 :   }
    2226                 : 
    2227                 :   PRInt32 bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
    2228              16 :                                                timeout);
    2229                 : 
    2230              16 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*)fd, bytesRead));
    2231                 : 
    2232                 : #ifdef DEBUG_SSL_VERBOSE
    2233                 :   DEBUG_DUMP_BUFFER((unsigned char*)buf, bytesRead);
    2234                 : #endif
    2235                 : 
    2236              16 :   return checkHandshake(bytesRead, true, fd, socketInfo);
    2237                 : }
    2238                 : 
    2239              16 : static PRInt32 PR_CALLBACK PSMSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
    2240                 :     PRIntn flags, PRIntervalTime timeout)
    2241                 : {
    2242              32 :   nsNSSShutDownPreventionLock locker;
    2243              16 :   nsNSSSocketInfo *socketInfo = getSocketInfoIfRunning(fd, writing, locker);
    2244              16 :   if (!socketInfo)
    2245               0 :     return -1;
    2246                 : 
    2247              16 :   if (flags != 0) {
    2248               0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    2249               0 :     return -1;
    2250                 :   }
    2251                 : 
    2252                 : #ifdef DEBUG_SSL_VERBOSE
    2253                 :   DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
    2254                 : #endif
    2255                 : 
    2256                 :   PRInt32 bytesWritten = fd->lower->methods->send(fd->lower, buf, amount,
    2257              16 :                                                   flags, timeout);
    2258                 : 
    2259              16 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n",
    2260                 :          fd, bytesWritten));
    2261                 : 
    2262              16 :   return checkHandshake(bytesWritten, false, fd, socketInfo);
    2263                 : }
    2264                 : 
    2265                 : static PRInt32 PR_CALLBACK
    2266               8 : nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
    2267                 : {
    2268               8 :   return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    2269                 : }
    2270                 : 
    2271                 : static PRInt32 PR_CALLBACK
    2272              16 : nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, PRInt32 amount)
    2273                 : {
    2274              16 :   return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    2275                 : }
    2276                 : 
    2277               4 : static PRStatus PR_CALLBACK PSMConnectcontinue(PRFileDesc *fd, PRInt16 out_flags)
    2278                 : {
    2279               8 :   nsNSSShutDownPreventionLock locker;
    2280               4 :   if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker)) {
    2281               0 :     return PR_FAILURE;
    2282                 :   }
    2283                 : 
    2284               4 :   return fd->lower->methods->connectcontinue(fd, out_flags);
    2285                 : }
    2286                 : 
    2287               4 : static PRIntn PSMAvailable(void)
    2288                 : {
    2289                 :   // This is called through PR_Available(), but is not implemented in PSM
    2290               4 :   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    2291               4 :   return -1;
    2292                 : }
    2293                 : 
    2294               0 : static PRInt64 PSMAvailable64(void)
    2295                 : {
    2296                 :   // This is called through PR_Available(), but is not implemented in PSM
    2297               0 :   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    2298               0 :   return -1;
    2299                 : }
    2300                 : 
    2301             328 : nsresult nsSSLIOLayerHelpers::Init()
    2302                 : {
    2303             328 :   if (!nsSSLIOLayerInitialized) {
    2304             328 :     nsSSLIOLayerInitialized = true;
    2305             328 :     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
    2306             328 :     nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
    2307                 : 
    2308             328 :     nsSSLIOLayerMethods.available = (PRAvailableFN)PSMAvailable;
    2309             328 :     nsSSLIOLayerMethods.available64 = (PRAvailable64FN)PSMAvailable64;
    2310             328 :     nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
    2311             328 :     nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
    2312             328 :     nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
    2313             328 :     nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
    2314             328 :     nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
    2315             328 :     nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
    2316             328 :     nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
    2317             328 :     nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
    2318             328 :     nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
    2319             328 :     nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
    2320             328 :     nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
    2321             328 :     nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
    2322             328 :     nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
    2323             328 :     nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
    2324             328 :     nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
    2325                 : 
    2326             328 :     nsSSLIOLayerMethods.getsockname = PSMGetsockname;
    2327             328 :     nsSSLIOLayerMethods.getpeername = PSMGetpeername;
    2328             328 :     nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
    2329             328 :     nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
    2330             328 :     nsSSLIOLayerMethods.recv = PSMRecv;
    2331             328 :     nsSSLIOLayerMethods.send = PSMSend;
    2332             328 :     nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
    2333                 : 
    2334             328 :     nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
    2335             328 :     nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
    2336             328 :     nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
    2337             328 :     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
    2338             328 :     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
    2339                 :   }
    2340                 : 
    2341             328 :   mutex = new Mutex("nsSSLIOLayerHelpers.mutex");
    2342                 : 
    2343             328 :   mTLSIntolerantSites = new nsTHashtable<nsCStringHashKey>();
    2344             328 :   if (!mTLSIntolerantSites)
    2345               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2346                 : 
    2347             328 :   mTLSIntolerantSites->Init(1);
    2348                 : 
    2349             328 :   mTLSTolerantSites = new nsTHashtable<nsCStringHashKey>();
    2350             328 :   if (!mTLSTolerantSites)
    2351               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2352                 : 
    2353                 :   // Initialize the tolerant site hashtable to 16 items at the start seems
    2354                 :   // reasonable as most servers are TLS tolerant. We just want to lower 
    2355                 :   // the rate of hashtable array reallocation.
    2356             328 :   mTLSTolerantSites->Init(16);
    2357                 : 
    2358             328 :   mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
    2359             328 :   if (!mRenegoUnrestrictedSites)
    2360               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2361                 : 
    2362             328 :   mRenegoUnrestrictedSites->Init(1);
    2363                 : 
    2364             328 :   mTreatUnsafeNegotiationAsBroken = false;
    2365                 :   
    2366             328 :   mHostsWithCertErrors = new nsPSMRememberCertErrorsTable();
    2367             328 :   if (!mHostsWithCertErrors || !mHostsWithCertErrors->mErrorHosts.IsInitialized())
    2368               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2369                 : 
    2370             328 :   return NS_OK;
    2371                 : }
    2372                 : 
    2373               0 : void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
    2374                 : {
    2375               0 :   MutexAutoLock lock(*mutex);
    2376                 :   // Remember intolerant site only if it is not known as tolerant
    2377               0 :   if (!mTLSTolerantSites->Contains(str))
    2378               0 :     nsSSLIOLayerHelpers::mTLSIntolerantSites->PutEntry(str);
    2379               0 : }
    2380                 : 
    2381               0 : void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
    2382                 : {
    2383               0 :   MutexAutoLock lock(*mutex);
    2384               0 :   nsSSLIOLayerHelpers::mTLSIntolerantSites->RemoveEntry(str);
    2385               0 : }
    2386                 : 
    2387               4 : bool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
    2388                 : {
    2389               8 :   MutexAutoLock lock(*mutex);
    2390               4 :   return mTLSIntolerantSites->Contains(str);
    2391                 : }
    2392                 : 
    2393             328 : void nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString &str)
    2394                 : {
    2395             656 :   MutexAutoLock lock(*mutex);
    2396                 :   
    2397             328 :   if (mRenegoUnrestrictedSites) {
    2398             328 :     delete mRenegoUnrestrictedSites;
    2399             328 :     mRenegoUnrestrictedSites = nsnull;
    2400                 :   }
    2401                 : 
    2402             328 :   mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
    2403             328 :   if (!mRenegoUnrestrictedSites)
    2404                 :     return;
    2405                 :   
    2406             328 :   mRenegoUnrestrictedSites->Init(1);
    2407                 :   
    2408             328 :   nsCCharSeparatedTokenizer toker(str, ',');
    2409                 : 
    2410             656 :   while (toker.hasMoreTokens()) {
    2411               0 :     const nsCSubstring &host = toker.nextToken();
    2412               0 :     if (!host.IsEmpty()) {
    2413               0 :       mRenegoUnrestrictedSites->PutEntry(host);
    2414                 :     }
    2415                 :   }
    2416                 : }
    2417                 : 
    2418               4 : bool nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString &str)
    2419                 : {
    2420               8 :   MutexAutoLock lock(*mutex);
    2421               4 :   return mRenegoUnrestrictedSites->Contains(str);
    2422                 : }
    2423                 : 
    2424             328 : void nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
    2425                 : {
    2426             656 :   MutexAutoLock lock(*mutex);
    2427             328 :   mTreatUnsafeNegotiationAsBroken = broken;
    2428             328 : }
    2429                 : 
    2430               0 : bool nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
    2431                 : {
    2432               0 :   MutexAutoLock lock(*mutex);
    2433               0 :   return mTreatUnsafeNegotiationAsBroken;
    2434                 : }
    2435                 : 
    2436             328 : void nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(PRInt32 level)
    2437                 : {
    2438             656 :   MutexAutoLock lock(*mutex);
    2439             328 :   mWarnLevelMissingRFC5746 = level;
    2440             328 : }
    2441                 : 
    2442               0 : PRInt32 nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746()
    2443                 : {
    2444               0 :   MutexAutoLock lock(*mutex);
    2445               0 :   return mWarnLevelMissingRFC5746;
    2446                 : }
    2447                 : 
    2448                 : nsresult
    2449               4 : nsSSLIOLayerNewSocket(PRInt32 family,
    2450                 :                       const char *host,
    2451                 :                       PRInt32 port,
    2452                 :                       const char *proxyHost,
    2453                 :                       PRInt32 proxyPort,
    2454                 :                       PRFileDesc **fd,
    2455                 :                       nsISupports** info,
    2456                 :                       bool forSTARTTLS,
    2457                 :                       bool anonymousLoad)
    2458                 : {
    2459                 : 
    2460               4 :   PRFileDesc* sock = PR_OpenTCPSocket(family);
    2461               4 :   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
    2462                 : 
    2463                 :   nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
    2464               4 :                                         sock, info, forSTARTTLS, anonymousLoad);
    2465               4 :   if (NS_FAILED(rv)) {
    2466               0 :     PR_Close(sock);
    2467               0 :     return rv;
    2468                 :   }
    2469                 : 
    2470               4 :   *fd = sock;
    2471               4 :   return NS_OK;
    2472                 : }
    2473                 : 
    2474                 : /*
    2475                 :  * Function: SECStatus nsConvertCANamesToStrings()
    2476                 :  * Purpose: creates CA names strings from (CERTDistNames* caNames)
    2477                 :  *
    2478                 :  * Arguments and return values
    2479                 :  * - arena: arena to allocate strings on
    2480                 :  * - caNameStrings: filled with CA names strings on return
    2481                 :  * - caNames: CERTDistNames to extract strings from
    2482                 :  * - return: SECSuccess if successful; error code otherwise
    2483                 :  *
    2484                 :  * Note: copied in its entirety from Nova code
    2485                 :  */
    2486               0 : SECStatus nsConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings,
    2487                 :                                       CERTDistNames* caNames)
    2488                 : {
    2489                 :     SECItem* dername;
    2490                 :     SECStatus rv;
    2491                 :     int headerlen;
    2492                 :     PRUint32 contentlen;
    2493                 :     SECItem newitem;
    2494                 :     int n;
    2495                 :     char* namestring;
    2496                 : 
    2497               0 :     for (n = 0; n < caNames->nnames; n++) {
    2498               0 :         newitem.data = NULL;
    2499               0 :         dername = &caNames->names[n];
    2500                 : 
    2501               0 :         rv = DER_Lengths(dername, &headerlen, &contentlen);
    2502                 : 
    2503               0 :         if (rv != SECSuccess) {
    2504               0 :             goto loser;
    2505                 :         }
    2506                 : 
    2507               0 :         if (headerlen + contentlen != dername->len) {
    2508                 :             /* This must be from an enterprise 2.x server, which sent
    2509                 :              * incorrectly formatted der without the outer wrapper of
    2510                 :              * type and length.  Fix it up by adding the top level
    2511                 :              * header.
    2512                 :              */
    2513               0 :             if (dername->len <= 127) {
    2514               0 :                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 2);
    2515               0 :                 if (newitem.data == NULL) {
    2516               0 :                     goto loser;
    2517                 :                 }
    2518               0 :                 newitem.data[0] = (unsigned char)0x30;
    2519               0 :                 newitem.data[1] = (unsigned char)dername->len;
    2520               0 :                 (void)memcpy(&newitem.data[2], dername->data, dername->len);
    2521                 :             }
    2522               0 :             else if (dername->len <= 255) {
    2523               0 :                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 3);
    2524               0 :                 if (newitem.data == NULL) {
    2525               0 :                     goto loser;
    2526                 :                 }
    2527               0 :                 newitem.data[0] = (unsigned char)0x30;
    2528               0 :                 newitem.data[1] = (unsigned char)0x81;
    2529               0 :                 newitem.data[2] = (unsigned char)dername->len;
    2530               0 :                 (void)memcpy(&newitem.data[3], dername->data, dername->len);
    2531                 :             }
    2532                 :             else {
    2533                 :                 /* greater than 256, better be less than 64k */
    2534               0 :                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 4);
    2535               0 :                 if (newitem.data == NULL) {
    2536               0 :                     goto loser;
    2537                 :                 }
    2538               0 :                 newitem.data[0] = (unsigned char)0x30;
    2539               0 :                 newitem.data[1] = (unsigned char)0x82;
    2540               0 :                 newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
    2541               0 :                 newitem.data[3] = (unsigned char)(dername->len & 0xff);
    2542               0 :                 memcpy(&newitem.data[4], dername->data, dername->len);
    2543                 :             }
    2544               0 :             dername = &newitem;
    2545                 :         }
    2546                 : 
    2547               0 :         namestring = CERT_DerNameToAscii(dername);
    2548               0 :         if (namestring == NULL) {
    2549                 :             /* XXX - keep going until we fail to convert the name */
    2550               0 :             caNameStrings[n] = const_cast<char*>("");
    2551                 :         }
    2552                 :         else {
    2553               0 :             caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
    2554               0 :             PR_Free(namestring);
    2555               0 :             if (caNameStrings[n] == NULL) {
    2556               0 :                 goto loser;
    2557                 :             }
    2558                 :         }
    2559                 : 
    2560               0 :         if (newitem.data != NULL) {
    2561               0 :             PR_Free(newitem.data);
    2562                 :         }
    2563                 :     }
    2564                 : 
    2565               0 :     return SECSuccess;
    2566                 : loser:
    2567               0 :     if (newitem.data != NULL) {
    2568               0 :         PR_Free(newitem.data);
    2569                 :     }
    2570               0 :     return SECFailure;
    2571                 : }
    2572                 : 
    2573                 : /*
    2574                 :  * structs and ASN1 templates for the limited scope-of-use extension
    2575                 :  *
    2576                 :  * CertificateScopeEntry ::= SEQUENCE {
    2577                 :  *     name GeneralName, -- pattern, as for NameConstraints
    2578                 :  *     portNumber INTEGER OPTIONAL }
    2579                 :  *
    2580                 :  * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
    2581                 :  */
    2582                 : /*
    2583                 :  * CERTCertificateScopeEntry: struct for scope entry that can be consumed by
    2584                 :  *                            the code
    2585                 :  * certCertificateScopeOfUse: struct that represents the decoded extension data
    2586                 :  */
    2587                 : typedef struct {
    2588                 :     SECItem derConstraint;
    2589                 :     SECItem derPort;
    2590                 :     CERTGeneralName* constraint; /* decoded constraint */
    2591                 :     PRIntn port; /* decoded port number */
    2592                 : } CERTCertificateScopeEntry;
    2593                 : 
    2594                 : typedef struct {
    2595                 :     CERTCertificateScopeEntry** entries;
    2596                 : } certCertificateScopeOfUse;
    2597                 : 
    2598                 : /* corresponding ASN1 templates */
    2599                 : static const SEC_ASN1Template cert_CertificateScopeEntryTemplate[] = {
    2600                 :     { SEC_ASN1_SEQUENCE, 
    2601                 :       0, NULL, sizeof(CERTCertificateScopeEntry) },
    2602                 :     { SEC_ASN1_ANY,
    2603                 :       offsetof(CERTCertificateScopeEntry, derConstraint) },
    2604                 :     { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
    2605                 :       offsetof(CERTCertificateScopeEntry, derPort) },
    2606                 :     { 0 }
    2607                 : };
    2608                 : 
    2609                 : static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate[] = {
    2610                 :     { SEC_ASN1_SEQUENCE_OF, 0, cert_CertificateScopeEntryTemplate }
    2611                 : };
    2612                 : 
    2613                 : #if 0
    2614                 : /* 
    2615                 :  * decodes the extension data and create CERTCertificateScopeEntry that can
    2616                 :  * be consumed by the code
    2617                 :  */
    2618                 : static
    2619                 : SECStatus cert_DecodeScopeOfUseEntries(PRArenaPool* arena, SECItem* extData,
    2620                 :                                        CERTCertificateScopeEntry*** entries,
    2621                 :                                        int* numEntries)
    2622                 : {
    2623                 :     certCertificateScopeOfUse* scope = NULL;
    2624                 :     SECStatus rv = SECSuccess;
    2625                 :     int i;
    2626                 : 
    2627                 :     *entries = NULL; /* in case of failure */
    2628                 :     *numEntries = 0; /* ditto */
    2629                 : 
    2630                 :     scope = (certCertificateScopeOfUse*)
    2631                 :         PORT_ArenaZAlloc(arena, sizeof(certCertificateScopeOfUse));
    2632                 :     if (scope == NULL) {
    2633                 :         goto loser;
    2634                 :     }
    2635                 : 
    2636                 :     rv = SEC_ASN1DecodeItem(arena, (void*)scope, 
    2637                 :                             cert_CertificateScopeOfUseTemplate, extData);
    2638                 :     if (rv != SECSuccess) {
    2639                 :         goto loser;
    2640                 :     }
    2641                 : 
    2642                 :     *entries = scope->entries;
    2643                 :     PR_ASSERT(*entries != NULL);
    2644                 : 
    2645                 :     /* first, let's count 'em. */
    2646                 :     for (i = 0; (*entries)[i] != NULL; i++) ;
    2647                 :     *numEntries = i;
    2648                 : 
    2649                 :     /* convert certCertificateScopeEntry sequence into what we can readily
    2650                 :      * use
    2651                 :      */
    2652                 :     for (i = 0; i < *numEntries; i++) {
    2653                 :         (*entries)[i]->constraint = 
    2654                 :             CERT_DecodeGeneralName(arena, &((*entries)[i]->derConstraint), 
    2655                 :                                    NULL);
    2656                 :         if ((*entries)[i]->derPort.data != NULL) {
    2657                 :             (*entries)[i]->port = 
    2658                 :                 (int)DER_GetInteger(&((*entries)[i]->derPort));
    2659                 :         }
    2660                 :         else {
    2661                 :             (*entries)[i]->port = 0;
    2662                 :         }
    2663                 :     }
    2664                 : 
    2665                 :     goto done;
    2666                 : loser:
    2667                 :     if (rv == SECSuccess) {
    2668                 :         rv = SECFailure;
    2669                 :     }
    2670                 : done:
    2671                 :     return rv;
    2672                 : }
    2673                 : 
    2674                 : static SECStatus cert_DecodeCertIPAddress(SECItem* genname, 
    2675                 :                                           PRUint32* constraint, PRUint32* mask)
    2676                 : {
    2677                 :     /* in case of failure */
    2678                 :     *constraint = 0;
    2679                 :     *mask = 0;
    2680                 : 
    2681                 :     PR_ASSERT(genname->data != NULL);
    2682                 :     if (genname->data == NULL) {
    2683                 :         return SECFailure;
    2684                 :     }
    2685                 :     if (genname->len != 8) {
    2686                 :         /* the length must be 4 byte IP address with 4 byte subnet mask */
    2687                 :         return SECFailure;
    2688                 :     }
    2689                 : 
    2690                 :     /* get them in the right order */
    2691                 :     *constraint = PR_ntohl((PRUint32)(*genname->data));
    2692                 :     *mask = PR_ntohl((PRUint32)(*(genname->data + 4)));
    2693                 : 
    2694                 :     return SECSuccess;
    2695                 : }
    2696                 : 
    2697                 : static char* _str_to_lower(char* string)
    2698                 : {
    2699                 : #ifdef XP_WIN
    2700                 :     return _strlwr(string);
    2701                 : #else
    2702                 :     int i;
    2703                 :     for (i = 0; string[i] != '\0'; i++) {
    2704                 :         string[i] = tolower(string[i]);
    2705                 :     }
    2706                 :     return string;
    2707                 : #endif
    2708                 : }
    2709                 : 
    2710                 : /*
    2711                 :  * Sees if the client certificate has a restriction in presenting the cert
    2712                 :  * to the host: returns true if there is no restriction or if the hostname
    2713                 :  * (and the port) satisfies the restriction, or false if the hostname (and
    2714                 :  * the port) does not satisfy the restriction
    2715                 :  */
    2716                 : static bool CERT_MatchesScopeOfUse(CERTCertificate* cert, char* hostname,
    2717                 :                                      char* hostIP, PRIntn port)
    2718                 : {
    2719                 :     bool rv = true; /* whether the cert can be presented */
    2720                 :     SECStatus srv;
    2721                 :     SECItem extData;
    2722                 :     PRArenaPool* arena = NULL;
    2723                 :     CERTCertificateScopeEntry** entries = NULL;
    2724                 :     /* arrays of decoded scope entries */
    2725                 :     int numEntries = 0;
    2726                 :     int i;
    2727                 :     char* hostLower = NULL;
    2728                 :     PRUint32 hostIPAddr = 0;
    2729                 : 
    2730                 :     PR_ASSERT((cert != NULL) && (hostname != NULL) && (hostIP != NULL));
    2731                 : 
    2732                 :     /* find cert extension */
    2733                 :     srv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
    2734                 :                                  &extData);
    2735                 :     if (srv != SECSuccess) {
    2736                 :         /* most of the time, this means the extension was not found: also,
    2737                 :          * since this is not a critical extension (as of now) we may simply
    2738                 :          * return true
    2739                 :          */
    2740                 :         goto done;
    2741                 :     }
    2742                 : 
    2743                 :     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    2744                 :     if (arena == NULL) {
    2745                 :         goto done;
    2746                 :     }
    2747                 : 
    2748                 :     /* decode the scope of use entries into pairs of GeneralNames and
    2749                 :      * an optional port numbers
    2750                 :      */
    2751                 :     srv = cert_DecodeScopeOfUseEntries(arena, &extData, &entries, &numEntries);
    2752                 :     if (srv != SECSuccess) {
    2753                 :         /* XXX What should we do when we failed to decode the extension?  This
    2754                 :          *     may mean either the extension was malformed or some (unlikely)
    2755                 :          *     fatal error on our part: my argument is that if the extension 
    2756                 :          *     was malformed the extension "disqualifies" as a valid 
    2757                 :          *     constraint and we may present the cert
    2758                 :          */
    2759                 :         goto done;
    2760                 :     }
    2761                 : 
    2762                 :     /* loop over these structures */
    2763                 :     for (i = 0; i < numEntries; i++) {
    2764                 :         /* determine whether the GeneralName is a DNS pattern, an IP address 
    2765                 :          * constraint, or else
    2766                 :          */
    2767                 :         CERTGeneralName* genname = entries[i]->constraint;
    2768                 : 
    2769                 :         /* if constraint is NULL, don't bother looking */
    2770                 :         if (genname == NULL) {
    2771                 :             /* this is not a failure: just continue */
    2772                 :             continue;
    2773                 :         }
    2774                 : 
    2775                 :         switch (genname->type) {
    2776                 :         case certDNSName: {
    2777                 :             /* we have a DNS name constraint; we should use only the host name
    2778                 :              * information
    2779                 :              */
    2780                 :             char* pattern = NULL;
    2781                 :             char* substring = NULL;
    2782                 : 
    2783                 :             /* null-terminate the string */
    2784                 :             genname->name.other.data[genname->name.other.len] = '\0';
    2785                 :             pattern = _str_to_lower((char*)genname->name.other.data);
    2786                 : 
    2787                 :             if (hostLower == NULL) {
    2788                 :                 /* so that it's done only if necessary and only once */
    2789                 :                 hostLower = _str_to_lower(PL_strdup(hostname));
    2790                 :             }
    2791                 : 
    2792                 :             /* the hostname satisfies the constraint */
    2793                 :             if (((substring = strstr(hostLower, pattern)) != NULL) &&
    2794                 :                 /* the hostname contains the pattern */
    2795                 :                 (strlen(substring) == strlen(pattern)) &&
    2796                 :                 /* the hostname ends with the pattern */
    2797                 :                 ((substring == hostLower) || (*(substring-1) == '.'))) {
    2798                 :                 /* the hostname either is identical to the pattern or
    2799                 :                  * belongs to a subdomain
    2800                 :                  */
    2801                 :                 rv = true;
    2802                 :             }
    2803                 :             else {
    2804                 :                 rv = false;
    2805                 :             }
    2806                 :             /* clean up strings if necessary */
    2807                 :             break;
    2808                 :         }
    2809                 :         case certIPAddress: {
    2810                 :             PRUint32 constraint;
    2811                 :             PRUint32 mask;
    2812                 :             PRNetAddr addr;
    2813                 :             
    2814                 :             if (hostIPAddr == 0) {
    2815                 :                 /* so that it's done only if necessary and only once */
    2816                 :                 PR_StringToNetAddr(hostIP, &addr);
    2817                 :                 hostIPAddr = addr.inet.ip;
    2818                 :             }
    2819                 : 
    2820                 :             if (cert_DecodeCertIPAddress(&(genname->name.other), &constraint, 
    2821                 :                                          &mask) != SECSuccess) {
    2822                 :                 continue;
    2823                 :             }
    2824                 :             if ((hostIPAddr & mask) == (constraint & mask)) {
    2825                 :                 rv = true;
    2826                 :             }
    2827                 :             else {
    2828                 :                 rv = false;
    2829                 :             }
    2830                 :             break;
    2831                 :         }
    2832                 :         default:
    2833                 :             /* ill-formed entry: abort */
    2834                 :             continue; /* go to the next entry */
    2835                 :         }
    2836                 : 
    2837                 :         if (!rv) {
    2838                 :             /* we do not need to check the port: go to the next entry */
    2839                 :             continue;
    2840                 :         }
    2841                 : 
    2842                 :         /* finally, check the optional port number */
    2843                 :         if ((entries[i]->port != 0) && (port != entries[i]->port)) {
    2844                 :             /* port number does not match */
    2845                 :             rv = false;
    2846                 :             continue;
    2847                 :         }
    2848                 : 
    2849                 :         /* we have a match */
    2850                 :         PR_ASSERT(rv);
    2851                 :         break;
    2852                 :     }
    2853                 : done:
    2854                 :     /* clean up entries */
    2855                 :     if (arena != NULL) {
    2856                 :         PORT_FreeArena(arena, false);
    2857                 :     }
    2858                 :     if (hostLower != NULL) {
    2859                 :         PR_Free(hostLower);
    2860                 :     }
    2861                 :     return rv;
    2862                 : }
    2863                 : #endif
    2864                 : 
    2865                 : /*
    2866                 :  * Function: SSMStatus SSM_SetUserCertChoice()
    2867                 : 
    2868                 :  * Purpose: sets certChoice by reading the preference
    2869                 :  *
    2870                 :  * Arguments and return values
    2871                 :  * - conn: SSMSSLDataConnection
    2872                 :  * - returns: SSM_SUCCESS if successful; SSM_FAILURE otherwise
    2873                 :  *
    2874                 :  * Note: If done properly, this function will read the identifier strings
    2875                 :  *               for ASK and AUTO modes, read the selected strings from the
    2876                 :  *               preference, compare the strings, and determine in which mode it is
    2877                 :  *               in.
    2878                 :  *       We currently use ASK mode for UI apps and AUTO mode for UI-less
    2879                 :  *       apps without really asking for preferences.
    2880                 :  */
    2881               0 : nsresult nsGetUserCertChoice(SSM_UserCertChoice* certChoice)
    2882                 : {
    2883               0 :         char *mode=NULL;
    2884                 :         nsresult ret;
    2885                 : 
    2886               0 :         NS_ENSURE_ARG_POINTER(certChoice);
    2887                 : 
    2888               0 :         nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
    2889                 : 
    2890               0 :         ret = pref->GetCharPref("security.default_personal_cert", &mode);
    2891               0 :         if (NS_FAILED(ret)) {
    2892               0 :                 goto loser;
    2893                 :         }
    2894                 : 
    2895               0 :     if (PL_strcmp(mode, "Select Automatically") == 0) {
    2896               0 :                 *certChoice = AUTO;
    2897                 :         }
    2898               0 :     else if (PL_strcmp(mode, "Ask Every Time") == 0) {
    2899               0 :         *certChoice = ASK;
    2900                 :     }
    2901                 :     else {
    2902                 :       // Most likely we see a nickname from a migrated cert.
    2903                 :       // We do not currently support that, ask the user which cert to use.
    2904               0 :                   *certChoice = ASK;
    2905                 :         }
    2906                 : 
    2907                 : loser:
    2908               0 :         if (mode) {
    2909               0 :                 nsMemory::Free(mode);
    2910                 :         }
    2911               0 :         return ret;
    2912                 : }
    2913                 : 
    2914               0 : static bool hasExplicitKeyUsageNonRepudiation(CERTCertificate *cert)
    2915                 : {
    2916                 :   /* There is no extension, v1 or v2 certificate */
    2917               0 :   if (!cert->extensions)
    2918               0 :     return false;
    2919                 : 
    2920                 :   SECStatus srv;
    2921                 :   SECItem keyUsageItem;
    2922               0 :   keyUsageItem.data = NULL;
    2923                 : 
    2924               0 :   srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
    2925               0 :   if (srv == SECFailure)
    2926               0 :     return false;
    2927                 : 
    2928               0 :   unsigned char keyUsage = keyUsageItem.data[0];
    2929               0 :   PORT_Free (keyUsageItem.data);
    2930                 : 
    2931               0 :   return !!(keyUsage & KU_NON_REPUDIATION);
    2932                 : }
    2933                 : 
    2934                 : class ClientAuthDataRunnable : public SyncRunnableBase
    2935               0 : {
    2936                 : public:
    2937               0 :   ClientAuthDataRunnable(CERTDistNames* caNames,
    2938                 :                          CERTCertificate** pRetCert,
    2939                 :                          SECKEYPrivateKey** pRetKey,
    2940                 :                          nsNSSSocketInfo * info,
    2941                 :                          CERTCertificate * serverCert) 
    2942                 :     : mRV(SECFailure)
    2943                 :     , mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
    2944                 :     , mPRetCert(pRetCert)
    2945                 :     , mPRetKey(pRetKey)
    2946                 :     , mCANames(caNames)
    2947                 :     , mSocketInfo(info)
    2948               0 :     , mServerCert(serverCert)
    2949                 :   {
    2950               0 :   }
    2951                 : 
    2952                 :   SECStatus mRV;                        // out
    2953                 :   PRErrorCode mErrorCodeToReport;       // out
    2954                 :   CERTCertificate** const mPRetCert;    // in/out
    2955                 :   SECKEYPrivateKey** const mPRetKey;    // in/out
    2956                 : protected:
    2957                 :   virtual void RunOnTargetThread();
    2958                 : private:
    2959                 :   CERTDistNames* const mCANames;        // in
    2960                 :   nsNSSSocketInfo * const mSocketInfo;  // in
    2961                 :   CERTCertificate * const mServerCert;  // in
    2962                 : };
    2963                 : 
    2964                 : /*
    2965                 :  * Function: SECStatus SSM_SSLGetClientAuthData()
    2966                 :  * Purpose: this callback function is used to pull client certificate
    2967                 :  *                      information upon server request
    2968                 :  *
    2969                 :  * Arguments and return values
    2970                 :  * - arg: SSL data connection
    2971                 :  * - socket: SSL socket we're dealing with
    2972                 :  * - caNames: list of CA names
    2973                 :  * - pRetCert: returns a pointer to a pointer to a valid certificate if
    2974                 :  *                         successful; otherwise NULL
    2975                 :  * - pRetKey: returns a pointer to a pointer to the corresponding key if
    2976                 :  *                        successful; otherwise NULL
    2977                 :  * - returns: SECSuccess if successful; error code otherwise
    2978                 :  */
    2979               0 : SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
    2980                 :                                                                    CERTDistNames* caNames,
    2981                 :                                                                    CERTCertificate** pRetCert,
    2982                 :                                                                    SECKEYPrivateKey** pRetKey)
    2983                 : {
    2984               0 :   nsNSSShutDownPreventionLock locker;
    2985                 : 
    2986               0 :   if (!socket || !caNames || !pRetCert || !pRetKey) {
    2987               0 :     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    2988               0 :     return SECFailure;
    2989                 :   }
    2990                 : 
    2991                 :   nsRefPtr<nsNSSSocketInfo> info
    2992               0 :         = reinterpret_cast<nsNSSSocketInfo*>(socket->higher->secret);
    2993                 : 
    2994               0 :   CERTCertificate* serverCert = SSL_PeerCertificate(socket);
    2995               0 :   if (!serverCert) {
    2996                 :     NS_NOTREACHED("Missing server certificate should have been detected during "
    2997               0 :                   "server cert authentication.");
    2998               0 :     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
    2999               0 :     return SECFailure;
    3000                 :   }
    3001                 : 
    3002               0 :   if (info->GetJoined()) {
    3003                 :     // We refuse to send a client certificate when there are multiple hostnames
    3004                 :     // joined on this connection, because we only show the user one hostname
    3005                 :     // (mHostName) in the client certificate UI.
    3006                 : 
    3007               0 :     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
    3008                 :            ("[%p] Not returning client cert due to previous join\n", socket));
    3009               0 :     *pRetCert = nsnull;
    3010               0 :     *pRetKey = nsnull;
    3011               0 :     return SECSuccess;
    3012                 :   }
    3013                 : 
    3014                 :   // XXX: This should be done asynchronously; see bug 696976
    3015                 :   nsRefPtr<ClientAuthDataRunnable> runnable =
    3016               0 :     new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert);
    3017               0 :   nsresult rv = runnable->DispatchToMainThreadAndWait();
    3018               0 :   if (NS_FAILED(rv)) {
    3019               0 :     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
    3020               0 :     return SECFailure;
    3021                 :   }
    3022                 :   
    3023               0 :   if (runnable->mRV != SECSuccess) {
    3024               0 :     PR_SetError(runnable->mErrorCodeToReport, 0);
    3025               0 :   } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
    3026                 :     // Make joinConnection prohibit joining after we've sent a client cert
    3027               0 :     info->SetSentClientCert();
    3028                 :   }
    3029                 : 
    3030               0 :   return runnable->mRV;
    3031                 : }
    3032                 : 
    3033               0 : void ClientAuthDataRunnable::RunOnTargetThread()
    3034                 : {
    3035               0 :   PRArenaPool* arena = NULL;
    3036                 :   char** caNameStrings;
    3037               0 :   CERTCertificate* cert = NULL;
    3038               0 :   SECKEYPrivateKey* privKey = NULL;
    3039               0 :   CERTCertList* certList = NULL;
    3040                 :   CERTCertListNode* node;
    3041               0 :   CERTCertNicknames* nicknames = NULL;
    3042               0 :   char* extracted = NULL;
    3043               0 :   PRIntn keyError = 0; /* used for private key retrieval error */
    3044                 :   SSM_UserCertChoice certChoice;
    3045               0 :   PRInt32 NumberOfCerts = 0;
    3046               0 :   void * wincx = mSocketInfo;
    3047                 : 
    3048                 :   /* create caNameStrings */
    3049               0 :   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    3050               0 :   if (arena == NULL) {
    3051               0 :     goto loser;
    3052                 :   }
    3053                 : 
    3054                 :   caNameStrings = (char**)PORT_ArenaAlloc(arena, 
    3055               0 :                                           sizeof(char*)*(mCANames->nnames));
    3056               0 :   if (caNameStrings == NULL) {
    3057               0 :     goto loser;
    3058                 :   }
    3059                 : 
    3060               0 :   mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
    3061               0 :   if (mRV != SECSuccess) {
    3062               0 :     goto loser;
    3063                 :   }
    3064                 : 
    3065                 :   /* get the preference */
    3066               0 :   if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
    3067               0 :     goto loser;
    3068                 :   }
    3069                 : 
    3070                 :   /* find valid user cert and key pair */       
    3071               0 :   if (certChoice == AUTO) {
    3072                 :     /* automatically find the right cert */
    3073                 : 
    3074                 :     /* find all user certs that are valid and for SSL */
    3075                 :     certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
    3076                 :                                          certUsageSSLClient, false,
    3077               0 :                                          true, wincx);
    3078               0 :     if (certList == NULL) {
    3079               0 :       goto noCert;
    3080                 :     }
    3081                 : 
    3082                 :     /* filter the list to those issued by CAs supported by the server */
    3083                 :     mRV = CERT_FilterCertListByCANames(certList, mCANames->nnames,
    3084               0 :                                        caNameStrings, certUsageSSLClient);
    3085               0 :     if (mRV != SECSuccess) {
    3086               0 :       goto noCert;
    3087                 :     }
    3088                 : 
    3089                 :     /* make sure the list is not empty */
    3090               0 :     node = CERT_LIST_HEAD(certList);
    3091               0 :     if (CERT_LIST_END(node, certList)) {
    3092               0 :       goto noCert;
    3093                 :     }
    3094                 : 
    3095               0 :     CERTCertificate* low_prio_nonrep_cert = NULL;
    3096               0 :     CERTCertificateCleaner low_prio_cleaner(low_prio_nonrep_cert);
    3097                 : 
    3098                 :     /* loop through the list until we find a cert with a key */
    3099               0 :     while (!CERT_LIST_END(node, certList)) {
    3100                 :       /* if the certificate has restriction and we do not satisfy it
    3101                 :        * we do not use it
    3102                 :        */
    3103                 : #if 0           /* XXX This must be re-enabled */
    3104                 :       if (!CERT_MatchesScopeOfUse(node->cert, mSocketInfo->GetHostName,
    3105                 :                                   info->GetHostIP, info->GetHostPort)) {
    3106                 :           node = CERT_LIST_NEXT(node);
    3107                 :           continue;
    3108                 :       }
    3109                 : #endif
    3110                 : 
    3111               0 :       privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
    3112               0 :       if (privKey != NULL) {
    3113               0 :         if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
    3114               0 :           SECKEY_DestroyPrivateKey(privKey);
    3115               0 :           privKey = NULL;
    3116                 :           // Not a prefered cert
    3117               0 :           if (!low_prio_nonrep_cert) // did not yet find a low prio cert
    3118               0 :             low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
    3119                 :         }
    3120                 :         else {
    3121                 :           // this is a good cert to present
    3122               0 :           cert = CERT_DupCertificate(node->cert);
    3123               0 :           break;
    3124                 :         }
    3125                 :       }
    3126               0 :       keyError = PR_GetError();
    3127               0 :       if (keyError == SEC_ERROR_BAD_PASSWORD) {
    3128                 :           /* problem with password: bail */
    3129                 :           goto loser;
    3130                 :       }
    3131                 : 
    3132               0 :       node = CERT_LIST_NEXT(node);
    3133                 :     }
    3134                 : 
    3135               0 :     if (!cert && low_prio_nonrep_cert) {
    3136               0 :       cert = low_prio_nonrep_cert;
    3137               0 :       low_prio_nonrep_cert = NULL; // take it away from the cleaner
    3138               0 :       privKey = PK11_FindKeyByAnyCert(cert, wincx);
    3139                 :     }
    3140                 : 
    3141               0 :     if (cert == NULL) {
    3142                 :         goto noCert;
    3143                 :     }
    3144                 :   }
    3145                 :   else { // Not Auto => ask
    3146                 :     /* Get the SSL Certificate */
    3147                 : 
    3148               0 :     nsXPIDLCString hostname;
    3149               0 :     mSocketInfo->GetHostName(getter_Copies(hostname));
    3150                 : 
    3151                 :     nsresult rv;
    3152               0 :     NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
    3153               0 :     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
    3154               0 :     nsRefPtr<nsClientAuthRememberService> cars;
    3155               0 :     if (nssComponent) {
    3156               0 :       nssComponent->GetClientAuthRememberService(getter_AddRefs(cars));
    3157                 :     }
    3158                 : 
    3159               0 :     bool hasRemembered = false;
    3160               0 :     nsCString rememberedDBKey;
    3161               0 :     if (cars) {
    3162                 :       bool found;
    3163                 :       nsresult rv = cars->HasRememberedDecision(hostname, mServerCert,
    3164               0 :                                                 rememberedDBKey, &found);
    3165               0 :       if (NS_SUCCEEDED(rv) && found) {
    3166               0 :         hasRemembered = true;
    3167                 :       }
    3168                 :     }
    3169                 : 
    3170               0 :     bool canceled = false;
    3171                 : 
    3172               0 : if (hasRemembered)
    3173                 : {
    3174               0 :     if (rememberedDBKey.IsEmpty())
    3175                 :     {
    3176               0 :       canceled = true;
    3177                 :     }
    3178                 :     else
    3179                 :     {
    3180               0 :       nsCOMPtr<nsIX509CertDB> certdb;
    3181               0 :       certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
    3182               0 :       if (certdb)
    3183                 :       {
    3184               0 :         nsCOMPtr<nsIX509Cert> found_cert;
    3185                 :         nsresult find_rv = 
    3186               0 :           certdb->FindCertByDBKey(rememberedDBKey.get(), nsnull,
    3187               0 :                                   getter_AddRefs(found_cert));
    3188               0 :         if (NS_SUCCEEDED(find_rv) && found_cert) {
    3189               0 :           nsNSSCertificate *obj_cert = reinterpret_cast<nsNSSCertificate *>(found_cert.get());
    3190               0 :           if (obj_cert) {
    3191               0 :             cert = obj_cert->GetCert();
    3192                 : 
    3193                 : #ifdef DEBUG_kaie
    3194                 :             nsAutoString nick, nickWithSerial, details;
    3195                 :             if (NS_SUCCEEDED(obj_cert->FormatUIStrings(nick, 
    3196                 :                                                        nickWithSerial, 
    3197                 :                                                        details))) {
    3198                 :               NS_LossyConvertUTF16toASCII asc(nickWithSerial);
    3199                 :               fprintf(stderr, "====> remembered serial %s\n", asc.get());
    3200                 :             }
    3201                 : #endif
    3202                 : 
    3203                 :           }
    3204                 :         }
    3205                 :         
    3206               0 :         if (!cert) {
    3207               0 :           hasRemembered = false;
    3208                 :         }
    3209                 :       }
    3210                 :     }
    3211                 : }
    3212                 : 
    3213               0 : if (!hasRemembered)
    3214                 : {
    3215                 :     /* user selects a cert to present */
    3216               0 :     nsIClientAuthDialogs *dialogs = NULL;
    3217               0 :     PRInt32 selectedIndex = -1;
    3218               0 :     PRUnichar **certNicknameList = NULL;
    3219               0 :     PRUnichar **certDetailsList = NULL;
    3220                 : 
    3221                 :     /* find all user certs that are for SSL */
    3222                 :     /* note that we are allowing expired certs in this list */
    3223                 :     certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
    3224                 :                                          certUsageSSLClient, false, 
    3225               0 :                                          false, wincx);
    3226               0 :     if (certList == NULL) {
    3227                 :       goto noCert;
    3228                 :     }
    3229                 : 
    3230               0 :     if (mCANames->nnames != 0) {
    3231                 :       /* filter the list to those issued by CAs supported by the 
    3232                 :        * server 
    3233                 :        */
    3234                 :       mRV = CERT_FilterCertListByCANames(certList, mCANames->nnames, 
    3235                 :                                         caNameStrings, 
    3236               0 :                                         certUsageSSLClient);
    3237               0 :       if (mRV != SECSuccess) {
    3238                 :         goto loser;
    3239                 :       }
    3240                 :     }
    3241                 : 
    3242               0 :     if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
    3243                 :       /* list is empty - no matching certs */
    3244                 :       goto noCert;
    3245                 :     }
    3246                 : 
    3247                 :     /* filter it further for hostname restriction */
    3248               0 :     node = CERT_LIST_HEAD(certList);
    3249               0 :     while (!CERT_LIST_END(node, certList)) {
    3250               0 :       ++NumberOfCerts;
    3251                 : #if 0 /* XXX Fix this */
    3252                 :       if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
    3253                 :                                   conn->hostIP, conn->port)) {
    3254                 :         CERTCertListNode* removed = node;
    3255                 :         node = CERT_LIST_NEXT(removed);
    3256                 :         CERT_RemoveCertListNode(removed);
    3257                 :       }
    3258                 :       else {
    3259                 :         node = CERT_LIST_NEXT(node);
    3260                 :       }
    3261                 : #endif
    3262               0 :       node = CERT_LIST_NEXT(node);
    3263                 :     }
    3264               0 :     if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
    3265                 :       goto noCert;
    3266                 :     }
    3267                 : 
    3268               0 :     nicknames = getNSSCertNicknamesFromCertList(certList);
    3269                 : 
    3270               0 :     if (nicknames == NULL) {
    3271                 :       goto loser;
    3272                 :     }
    3273                 : 
    3274               0 :     NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
    3275                 : 
    3276                 :     /* Get CN and O of the subject and O of the issuer */
    3277               0 :     char *ccn = CERT_GetCommonName(&mServerCert->subject);
    3278               0 :     void *v = ccn;
    3279               0 :     voidCleaner ccnCleaner(v);
    3280               0 :     NS_ConvertUTF8toUTF16 cn(ccn);
    3281                 : 
    3282                 :     PRInt32 port;
    3283               0 :     mSocketInfo->GetPort(&port);
    3284                 : 
    3285               0 :     nsString cn_host_port;
    3286               0 :     if (ccn && strcmp(ccn, hostname) == 0) {
    3287               0 :       cn_host_port.Append(cn);
    3288               0 :       cn_host_port.AppendLiteral(":");
    3289               0 :       cn_host_port.AppendInt(port);
    3290                 :     }
    3291                 :     else {
    3292               0 :       cn_host_port.Append(cn);
    3293               0 :       cn_host_port.AppendLiteral(" (");
    3294               0 :       cn_host_port.AppendLiteral(":");
    3295               0 :       cn_host_port.AppendInt(port);
    3296               0 :       cn_host_port.AppendLiteral(")");
    3297                 :     }
    3298                 : 
    3299               0 :     char *corg = CERT_GetOrgName(&mServerCert->subject);
    3300               0 :     NS_ConvertUTF8toUTF16 org(corg);
    3301               0 :     if (corg) PORT_Free(corg);
    3302                 : 
    3303               0 :     char *cissuer = CERT_GetOrgName(&mServerCert->issuer);
    3304               0 :     NS_ConvertUTF8toUTF16 issuer(cissuer);
    3305               0 :     if (cissuer) PORT_Free(cissuer);
    3306                 : 
    3307               0 :     certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
    3308               0 :     if (!certNicknameList)
    3309                 :       goto loser;
    3310               0 :     certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
    3311               0 :     if (!certDetailsList) {
    3312               0 :       nsMemory::Free(certNicknameList);
    3313                 :       goto loser;
    3314                 :     }
    3315                 : 
    3316                 :     PRInt32 CertsToUse;
    3317               0 :     for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
    3318               0 :          !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
    3319                 :          node = CERT_LIST_NEXT(node)
    3320                 :         )
    3321                 :     {
    3322               0 :       nsRefPtr<nsNSSCertificate> tempCert = nsNSSCertificate::Create(node->cert);
    3323                 : 
    3324               0 :       if (!tempCert)
    3325               0 :         continue;
    3326                 :       
    3327               0 :       NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
    3328               0 :       nsAutoString nickWithSerial, details;
    3329                 :       
    3330               0 :       if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
    3331               0 :         continue;
    3332                 : 
    3333               0 :       certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
    3334               0 :       if (!certNicknameList[CertsToUse])
    3335               0 :         continue;
    3336               0 :       certDetailsList[CertsToUse] = ToNewUnicode(details);
    3337               0 :       if (!certDetailsList[CertsToUse]) {
    3338               0 :         nsMemory::Free(certNicknameList[CertsToUse]);
    3339               0 :         continue;
    3340                 :       }
    3341                 : 
    3342               0 :       ++CertsToUse;
    3343                 :     }
    3344                 : 
    3345                 :     /* Throw up the client auth dialog and get back the index of the selected cert */
    3346                 :     rv = getNSSDialogs((void**)&dialogs, 
    3347                 :                        NS_GET_IID(nsIClientAuthDialogs),
    3348               0 :                        NS_CLIENTAUTHDIALOGS_CONTRACTID);
    3349                 : 
    3350               0 :     if (NS_FAILED(rv)) {
    3351               0 :       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
    3352               0 :       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
    3353                 :       goto loser;
    3354                 :     }
    3355                 : 
    3356                 :     {
    3357               0 :       nsPSMUITracker tracker;
    3358               0 :       if (tracker.isUIForbidden()) {
    3359               0 :         rv = NS_ERROR_NOT_AVAILABLE;
    3360                 :       }
    3361                 :       else {
    3362                 :         rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port.get(),
    3363                 :                                         org.get(), issuer.get(), 
    3364                 :                                         (const PRUnichar**)certNicknameList,
    3365                 :                                         (const PRUnichar**)certDetailsList,
    3366               0 :                                         CertsToUse, &selectedIndex, &canceled);
    3367                 :       }
    3368                 :     }
    3369                 : 
    3370               0 :     NS_RELEASE(dialogs);
    3371               0 :     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
    3372               0 :     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
    3373                 :     
    3374               0 :     if (NS_FAILED(rv)) goto loser;
    3375                 : 
    3376                 :     // even if the user has canceled, we want to remember that, to avoid repeating prompts
    3377               0 :     bool wantRemember = false;
    3378               0 :     mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
    3379                 : 
    3380                 :     int i;
    3381               0 :     if (!canceled)
    3382               0 :     for (i = 0, node = CERT_LIST_HEAD(certList);
    3383               0 :          !CERT_LIST_END(node, certList);
    3384                 :          ++i, node = CERT_LIST_NEXT(node)) {
    3385                 : 
    3386               0 :       if (i == selectedIndex) {
    3387               0 :         cert = CERT_DupCertificate(node->cert);
    3388               0 :         break;
    3389                 :       }
    3390                 :     }
    3391                 : 
    3392               0 :     if (cars && wantRemember) {
    3393               0 :       cars->RememberDecision(hostname, mServerCert, canceled ? 0 : cert);
    3394                 :     }
    3395                 : }
    3396                 : 
    3397               0 :     if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
    3398                 : 
    3399               0 :     if (cert == NULL) {
    3400                 :       goto loser;
    3401                 :     }
    3402                 : 
    3403                 :     /* go get the private key */
    3404               0 :     privKey = PK11_FindKeyByAnyCert(cert, wincx);
    3405               0 :     if (privKey == NULL) {
    3406               0 :       keyError = PR_GetError();
    3407               0 :       if (keyError == SEC_ERROR_BAD_PASSWORD) {
    3408                 :           /* problem with password: bail */
    3409                 :           goto loser;
    3410                 :       }
    3411                 :       else {
    3412                 :           goto noCert;
    3413                 :       }
    3414                 :     }
    3415                 :   }
    3416               0 :   goto done;
    3417                 : 
    3418                 : noCert:
    3419                 : loser:
    3420               0 :   if (mRV == SECSuccess) {
    3421               0 :     mRV = SECFailure;
    3422                 :   }
    3423               0 :   if (cert != NULL) {
    3424               0 :     CERT_DestroyCertificate(cert);
    3425               0 :     cert = NULL;
    3426                 :   }
    3427                 : done:
    3428               0 :   int error = PR_GetError();
    3429                 : 
    3430               0 :   if (extracted != NULL) {
    3431               0 :     PR_Free(extracted);
    3432                 :   }
    3433               0 :   if (nicknames != NULL) {
    3434               0 :     CERT_FreeNicknames(nicknames);
    3435                 :   }
    3436               0 :   if (certList != NULL) {
    3437               0 :     CERT_DestroyCertList(certList);
    3438                 :   }
    3439               0 :   if (arena != NULL) {
    3440               0 :     PORT_FreeArena(arena, false);
    3441                 :   }
    3442                 : 
    3443               0 :   *mPRetCert = cert;
    3444               0 :   *mPRetKey = privKey;
    3445                 : 
    3446               0 :   if (mRV == SECFailure) {
    3447               0 :     mErrorCodeToReport = error;
    3448                 :   }
    3449               0 : }
    3450                 : 
    3451                 : void
    3452               0 : nsNSSSocketInfo::SetStatusErrorBits(nsIX509Cert & cert,
    3453                 :                                     PRUint32 collected_errors)
    3454                 : {
    3455               0 :   MutexAutoLock lock(mMutex);
    3456                 : 
    3457               0 :   if (!mSSLStatus)
    3458               0 :     mSSLStatus = new nsSSLStatus();
    3459                 : 
    3460               0 :   mSSLStatus->mServerCert = &cert;
    3461                 : 
    3462               0 :   mSSLStatus->mHaveCertErrorBits = true;
    3463               0 :   mSSLStatus->mIsDomainMismatch = 
    3464               0 :     collected_errors & nsICertOverrideService::ERROR_MISMATCH;
    3465               0 :   mSSLStatus->mIsNotValidAtThisTime = 
    3466               0 :     collected_errors & nsICertOverrideService::ERROR_TIME;
    3467               0 :   mSSLStatus->mIsUntrusted = 
    3468               0 :     collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
    3469                 : 
    3470                 :   nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
    3471               0 :     this, mSSLStatus, SECFailure);
    3472               0 : }
    3473                 : 
    3474                 : static PRFileDesc*
    3475               4 : nsSSLIOLayerImportFD(PRFileDesc *fd,
    3476                 :                      nsNSSSocketInfo *infoObject,
    3477                 :                      const char *host,
    3478                 :                      bool anonymousLoad)
    3479                 : {
    3480               8 :   nsNSSShutDownPreventionLock locker;
    3481               4 :   PRFileDesc* sslSock = SSL_ImportFD(nsnull, fd);
    3482               4 :   if (!sslSock) {
    3483               0 :     NS_ASSERTION(false, "NSS: Error importing socket");
    3484               0 :     return nsnull;
    3485                 :   }
    3486               4 :   SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
    3487               4 :   SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
    3488                 : 
    3489                 :   // Disable this hook if we connect anonymously. See bug 466080.
    3490               4 :   if (anonymousLoad) {
    3491               0 :       SSL_GetClientAuthDataHook(sslSock, NULL, infoObject);
    3492                 :   } else {
    3493                 :       SSL_GetClientAuthDataHook(sslSock, 
    3494                 :                             (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData,
    3495               4 :                             infoObject);
    3496                 :   }
    3497               4 :   if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook,
    3498               4 :                                             infoObject)) {
    3499               0 :     NS_NOTREACHED("failed to configure AuthCertificateHook");
    3500               0 :     goto loser;
    3501                 :   }
    3502                 : 
    3503               4 :   if (SECSuccess != SSL_SetURL(sslSock, host)) {
    3504               0 :     NS_NOTREACHED("SSL_SetURL failed");
    3505               0 :     goto loser;
    3506                 :   }
    3507               4 :   return sslSock;
    3508                 : loser:
    3509               0 :   if (sslSock) {
    3510               0 :     PR_Close(sslSock);
    3511                 :   }
    3512               0 :   return nsnull;
    3513                 : }
    3514                 : 
    3515                 : static nsresult
    3516               4 : nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS, 
    3517                 :                        const char *proxyHost, const char *host, PRInt32 port,
    3518                 :                        bool anonymousLoad, nsNSSSocketInfo *infoObject)
    3519                 : {
    3520               8 :   nsNSSShutDownPreventionLock locker;
    3521               4 :   if (forSTARTTLS || proxyHost) {
    3522               0 :     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
    3523               0 :       return NS_ERROR_FAILURE;
    3524                 :     }
    3525               0 :     infoObject->SetHasCleartextPhase(true);
    3526                 :   }
    3527                 : 
    3528                 :   // Let's see if we're trying to connect to a site we know is
    3529                 :   // TLS intolerant.
    3530               8 :   nsCAutoString key;
    3531               4 :   key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
    3532                 : 
    3533               4 :   if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key)) {
    3534               0 :     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, false))
    3535               0 :       return NS_ERROR_FAILURE;
    3536                 : 
    3537               0 :     infoObject->SetAllowTLSIntoleranceTimeout(false);
    3538                 :       
    3539                 :     // We assume that protocols that use the STARTTLS mechanism should support
    3540                 :     // modern hellos. For other protocols, if we suspect a site 
    3541                 :     // does not support TLS, let's also use V2 hellos.
    3542                 :     // One advantage of this approach, if a site only supports the older
    3543                 :     // hellos, it is more likely that we will get a reasonable error code
    3544                 :     // on our single retry attempt.
    3545                 :   }
    3546                 : 
    3547                 :   PRBool enabled;
    3548               4 :   if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_SSL3, &enabled)) {
    3549               0 :     return NS_ERROR_FAILURE;
    3550                 :   }
    3551               4 :   infoObject->SetSSL3Enabled(enabled);
    3552               4 :   if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
    3553               0 :     return NS_ERROR_FAILURE;
    3554                 :   }
    3555               4 :   infoObject->SetTLSEnabled(enabled);
    3556                 : 
    3557               4 :   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
    3558               0 :     return NS_ERROR_FAILURE;
    3559                 :   }
    3560                 :   
    3561               4 :   if (nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(nsDependentCString(host))) {
    3562               0 :     if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
    3563               0 :       return NS_ERROR_FAILURE;
    3564                 :     }
    3565               0 :     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
    3566               0 :       return NS_ERROR_FAILURE;
    3567                 :     }
    3568                 :   }
    3569                 : 
    3570                 :   // Set the Peer ID so that SSL proxy connections work properly.
    3571                 :   char *peerId;
    3572               4 :   if (anonymousLoad) {  // See bug #466080. Separate the caches.
    3573               0 :       peerId = PR_smprintf("anon:%s:%d", host, port);
    3574                 :   } else {
    3575               4 :       peerId = PR_smprintf("%s:%d", host, port);
    3576                 :   }
    3577                 :   
    3578               4 :   if (SECSuccess != SSL_SetSockPeerID(fd, peerId)) {
    3579               0 :     PR_smprintf_free(peerId);
    3580               0 :     return NS_ERROR_FAILURE;
    3581                 :   }
    3582                 : 
    3583               4 :   PR_smprintf_free(peerId);
    3584               4 :   return NS_OK;
    3585                 : }
    3586                 : 
    3587                 : nsresult
    3588               4 : nsSSLIOLayerAddToSocket(PRInt32 family,
    3589                 :                         const char* host,
    3590                 :                         PRInt32 port,
    3591                 :                         const char* proxyHost,
    3592                 :                         PRInt32 proxyPort,
    3593                 :                         PRFileDesc* fd,
    3594                 :                         nsISupports** info,
    3595                 :                         bool forSTARTTLS,
    3596                 :                         bool anonymousLoad)
    3597                 : {
    3598               8 :   nsNSSShutDownPreventionLock locker;
    3599               4 :   PRFileDesc* layer = nsnull;
    3600                 :   nsresult rv;
    3601                 : 
    3602               4 :   nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
    3603               4 :   if (!infoObject) return NS_ERROR_FAILURE;
    3604                 :   
    3605               4 :   NS_ADDREF(infoObject);
    3606               4 :   infoObject->SetForSTARTTLS(forSTARTTLS);
    3607               4 :   infoObject->SetHostName(host);
    3608               4 :   infoObject->SetPort(port);
    3609                 : 
    3610               4 :   PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host, anonymousLoad);
    3611               4 :   if (!sslSock) {
    3612               0 :     NS_ASSERTION(false, "NSS: Error importing socket");
    3613               0 :     goto loser;
    3614                 :   }
    3615                 : 
    3616               4 :   infoObject->SetFileDescPtr(sslSock);
    3617                 : 
    3618                 :   rv = nsSSLIOLayerSetOptions(sslSock,
    3619                 :                               forSTARTTLS, proxyHost, host, port, anonymousLoad,
    3620               4 :                               infoObject);
    3621                 : 
    3622               4 :   if (NS_FAILED(rv))
    3623               0 :     goto loser;
    3624                 : 
    3625                 :   /* Now, layer ourselves on top of the SSL socket... */
    3626                 :   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
    3627               4 :                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
    3628               4 :   if (!layer)
    3629               0 :     goto loser;
    3630                 :   
    3631               4 :   layer->secret = (PRFilePrivate*) infoObject;
    3632               4 :   rv = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
    3633                 :   
    3634               4 :   if (NS_FAILED(rv)) {
    3635               0 :     goto loser;
    3636                 :   }
    3637                 :   
    3638               4 :   nsNSSShutDownList::trackSSLSocketCreate();
    3639                 : 
    3640               4 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*)sslSock));
    3641               4 :   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
    3642                 : 
    3643                 :   // We are going use a clear connection first //
    3644               4 :   if (forSTARTTLS || proxyHost) {
    3645               0 :     infoObject->SetHandshakePending(false);
    3646                 :   }
    3647                 : 
    3648               4 :   return NS_OK;
    3649                 :  loser:
    3650               0 :   NS_IF_RELEASE(infoObject);
    3651               0 :   if (layer) {
    3652               0 :     layer->dtor(layer);
    3653                 :   }
    3654               0 :   return NS_ERROR_FAILURE;
    3655                 : }

Generated by: LCOV version 1.7