Back to index

lightning-sunbird  0.9+nobinonly
nsNSSIOLayer.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Brian Ryner <bryner@brianryner.com>
00025  *   Javier Delgadillo <javi@netscape.com>
00026  *   Kai Engert <kengert@redhat.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsNSSComponent.h"
00043 #include "nsNSSIOLayer.h"
00044 #include "nsNSSCallbacks.h"
00045 
00046 #include "prlog.h"
00047 #include "prnetdb.h"
00048 #include "nsIPrompt.h"
00049 #include "nsIPrefService.h"
00050 #include "nsIPrefBranch.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsIWebProgressListener.h"
00053 #include "nsIChannel.h"
00054 #include "nsIBadCertListener.h"
00055 #include "nsNSSCertificate.h"
00056 #include "nsIProxyObjectManager.h"
00057 #include "nsProxiedService.h"
00058 #include "nsIDateTimeFormat.h"
00059 #include "nsDateTimeFormatCID.h"
00060 #include "nsIClientAuthDialogs.h"
00061 #include "nsClientAuthRemember.h"
00062 
00063 #include "nsXPIDLString.h"
00064 #include "nsReadableUtils.h"
00065 #include "nsVoidArray.h"
00066 #include "nsHashSets.h"
00067 #include "nsCRT.h"
00068 #include "nsPrintfCString.h"
00069 #include "nsAutoLock.h"
00070 #include "nsSSLThread.h"
00071 #include "nsNSSShutDown.h"
00072 #include "nsNSSCertHelper.h"
00073 #include "nsNSSCleaner.h"
00074 
00075 #include "ssl.h"
00076 #include "secerr.h"
00077 #include "sslerr.h"
00078 #include "secder.h"
00079 #include "secasn1.h"
00080 #include "certdb.h"
00081 #include "cert.h"
00082 #include "keyhi.h"
00083 
00084 
00085 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal 
00086                             //reports when doing SSL read/write
00087                             
00088 //#define DUMP_BUFFER  //Enable this define along with
00089                        //DEBUG_SSL_VERBOSE to dump SSL
00090                        //read/write buffer to a log.
00091                        //Uses PR_LOG except on Mac where
00092                        //we always write out to our own
00093                        //file.
00094 
00095 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
00096 
00097 /* SSM_UserCertChoice: enum for cert choice info */
00098 typedef enum {ASK, AUTO} SSM_UserCertChoice;
00099 
00100 
00101 static SECStatus PR_CALLBACK
00102 nsNSS_SSLGetClientAuthData(void *arg, PRFileDesc *socket,
00103                                              CERTDistNames *caNames,
00104                                              CERTCertificate **pRetCert,
00105                                              SECKEYPrivateKey **pRetKey);
00106 static SECStatus PR_CALLBACK
00107 nsNSS_SSLGetClientAuthData(void *arg, PRFileDesc *socket,
00108                                              CERTDistNames *caNames,
00109                                              CERTCertificate **pRetCert,
00110                                              SECKEYPrivateKey **pRetKey);
00111 #ifdef PR_LOGGING
00112 extern PRLogModuleInfo* gPIPNSSLog;
00113 #endif
00114 
00115 #if defined(DEBUG_SSL_VERBOSE) && defined (XP_MAC)
00116 
00117 #ifdef PR_LOG
00118 #undef PR_LOG
00119 #endif
00120 
00121 static PRFileDesc *gMyLogFile = nsnull;
00122 #define MAC_LOG_FILE "MAC PIPNSS Log File"
00123 
00124 void MyLogFunction(const char *fmt, ...)
00125 {
00126   
00127   va_list ap;
00128   va_start(ap,fmt);
00129   if (gMyLogFile == nsnull)
00130     gMyLogFile = PR_Open(MAC_LOG_FILE, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
00131                          0600);
00132   if (!gMyLogFile)
00133       return;
00134   PR_vfprintf(gMyLogFile, fmt, ap);
00135   va_end(ap);
00136 }
00137 
00138 #define PR_LOG(module,level,args) MyLogFunction args
00139 #endif
00140 
00141 
00142 nsSSLSocketThreadData::nsSSLSocketThreadData()
00143 : mSSLState(ssl_idle)
00144 , mPRErrorCode(PR_SUCCESS)
00145 , mSSLDataBuffer(nsnull)
00146 , mSSLDataBufferAllocatedSize(0)
00147 , mSSLRequestedTransferAmount(0)
00148 , mSSLRemainingReadResultData(nsnull)
00149 , mSSLResultRemainingBytes(0)
00150 , mReplacedSSLFileDesc(nsnull)
00151 , mOneBytePendingFromEarlierWrite(PR_FALSE)
00152 , mThePendingByte(0)
00153 , mOriginalRequestedTransferAmount(0)
00154 {
00155 }
00156 
00157 nsSSLSocketThreadData::~nsSSLSocketThreadData()
00158 {
00159   NS_ASSERTION(mSSLState != ssl_pending_write
00160                &&
00161                mSSLState != ssl_pending_read, 
00162                "oops??? ssl socket is not idle at the time it is being destroyed");
00163 }
00164 
00165 PRBool nsSSLSocketThreadData::ensure_buffer_size(PRInt32 amount)
00166 {
00167   if (amount > mSSLDataBufferAllocatedSize) {
00168     if (mSSLDataBuffer) {
00169       mSSLDataBuffer = (char*)nsMemory::Realloc(mSSLDataBuffer, amount);
00170     }
00171     else {
00172       mSSLDataBuffer = (char*)nsMemory::Alloc(amount);
00173     }
00174     
00175     if (!mSSLDataBuffer)
00176       return PR_FALSE;
00177 
00178     mSSLDataBufferAllocatedSize = amount;
00179   }
00180   
00181   return PR_TRUE;
00182 }
00183 
00184 nsNSSSocketInfo::nsNSSSocketInfo()
00185   : mFd(nsnull),
00186     mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
00187     mForSTARTTLS(PR_FALSE),
00188     mHandshakePending(PR_TRUE),
00189     mCanceled(PR_FALSE),
00190     mHasCleartextPhase(PR_FALSE),
00191     mHandshakeInProgress(PR_FALSE),
00192     mAllowTLSIntoleranceTimeout(PR_TRUE),
00193     mBadCertUIStatus(bcuis_not_shown),
00194     mHandshakeStartTime(0),
00195     mPort(0),
00196     mCAChain(nsnull)
00197 {
00198   mThreadData = new nsSSLSocketThreadData;
00199 }
00200 
00201 nsNSSSocketInfo::~nsNSSSocketInfo()
00202 {
00203   delete mThreadData;
00204 
00205   nsNSSShutDownPreventionLock locker;
00206   if (isAlreadyShutDown())
00207     return;
00208 
00209   destructorSafeDestroyNSSReference();
00210   shutdown(calledFromObject);
00211 }
00212 
00213 void nsNSSSocketInfo::virtualDestroyNSSReference()
00214 {
00215   destructorSafeDestroyNSSReference();
00216 }
00217 
00218 void nsNSSSocketInfo::destructorSafeDestroyNSSReference()
00219 {
00220   if (isAlreadyShutDown())
00221     return;
00222 
00223   if (mCAChain) {
00224     CERT_DestroyCertList(mCAChain);
00225     mCAChain = nsnull;
00226   }
00227 }
00228 
00229 NS_IMPL_THREADSAFE_ISUPPORTS5(nsNSSSocketInfo,
00230                               nsITransportSecurityInfo,
00231                               nsISSLSocketControl,
00232                               nsIInterfaceRequestor,
00233                               nsISSLStatusProvider,
00234                               nsIClientAuthUserDecision)
00235 
00236 nsresult
00237 nsNSSSocketInfo::GetHandshakePending(PRBool *aHandshakePending)
00238 {
00239   *aHandshakePending = mHandshakePending;
00240   return NS_OK;
00241 }
00242 
00243 nsresult
00244 nsNSSSocketInfo::SetHandshakePending(PRBool aHandshakePending)
00245 {
00246   mHandshakePending = aHandshakePending;
00247   return NS_OK;
00248 }
00249 
00250 nsresult
00251 nsNSSSocketInfo::SetHostName(const char* host)
00252 {
00253   mHostName.Adopt(host ? nsCRT::strdup(host) : 0);
00254   return NS_OK;
00255 }
00256 
00257 nsresult
00258 nsNSSSocketInfo::GetHostName(char **host)
00259 {
00260   *host = (mHostName) ? nsCRT::strdup(mHostName) : nsnull;
00261   return NS_OK;
00262 }
00263 
00264 nsresult
00265 nsNSSSocketInfo::SetPort(PRInt32 aPort)
00266 {
00267   mPort = aPort;
00268   return NS_OK;
00269 }
00270 
00271 nsresult
00272 nsNSSSocketInfo::GetPort(PRInt32 *aPort)
00273 {
00274   *aPort = mPort;
00275   return NS_OK;
00276 }
00277 
00278 void nsNSSSocketInfo::SetCanceled(PRBool aCanceled)
00279 {
00280   mCanceled = aCanceled;
00281 }
00282 
00283 PRBool nsNSSSocketInfo::GetCanceled()
00284 {
00285   return mCanceled;
00286 }
00287 
00288 NS_IMETHODIMP nsNSSSocketInfo::GetRememberClientAuthCertificate(PRBool *aRememberClientAuthCertificate)
00289 {
00290   NS_ENSURE_ARG_POINTER(aRememberClientAuthCertificate);
00291   *aRememberClientAuthCertificate = mRememberClientAuthCertificate;
00292   return NS_OK;
00293 }
00294 
00295 NS_IMETHODIMP nsNSSSocketInfo::SetRememberClientAuthCertificate(PRBool aRememberClientAuthCertificate)
00296 {
00297   mRememberClientAuthCertificate = aRememberClientAuthCertificate;
00298   return NS_OK;
00299 }
00300 
00301 void nsNSSSocketInfo::SetHasCleartextPhase(PRBool aHasCleartextPhase)
00302 {
00303   mHasCleartextPhase = aHasCleartextPhase;
00304 }
00305 
00306 PRBool nsNSSSocketInfo::GetHasCleartextPhase()
00307 {
00308   return mHasCleartextPhase;
00309 }
00310 
00311 NS_IMETHODIMP
00312 nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
00313 {
00314   *aCallbacks = mCallbacks;
00315   NS_IF_ADDREF(*aCallbacks);
00316   return NS_OK;
00317 }
00318 
00319 NS_IMETHODIMP
00320 nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
00321 {
00322   if (!aCallbacks) {
00323     mCallbacks = nsnull;
00324     return NS_OK;
00325   }
00326 
00327   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00328   if (!proxyman) 
00329     return NS_ERROR_FAILURE;
00330 
00331   nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
00332   proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
00333                               NS_GET_IID(nsIInterfaceRequestor),
00334                               NS_STATIC_CAST(nsIInterfaceRequestor*,aCallbacks),
00335                               PROXY_SYNC,
00336                               getter_AddRefs(proxiedCallbacks));
00337 
00338   mCallbacks = proxiedCallbacks;
00339   return NS_OK;
00340 }
00341 
00342 NS_IMETHODIMP
00343 nsNSSSocketInfo::GetSecurityState(PRUint32* state)
00344 {
00345   *state = mSecurityState;
00346   return NS_OK;
00347 }
00348 
00349 nsresult
00350 nsNSSSocketInfo::SetSecurityState(PRUint32 aState)
00351 {
00352   mSecurityState = aState;
00353   return NS_OK;
00354 }
00355 
00356 NS_IMETHODIMP
00357 nsNSSSocketInfo::GetShortSecurityDescription(PRUnichar** aText) {
00358   if (mShortDesc.IsEmpty())
00359     *aText = nsnull;
00360   else {
00361     *aText = ToNewUnicode(mShortDesc);
00362     NS_ENSURE_TRUE(*aText, NS_ERROR_OUT_OF_MEMORY);
00363   }
00364   return NS_OK;
00365 }
00366 
00367 nsresult
00368 nsNSSSocketInfo::SetShortSecurityDescription(const PRUnichar* aText) {
00369   mShortDesc.Assign(aText);
00370   return NS_OK;
00371 }
00372 
00373 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
00374 NS_IMETHODIMP nsNSSSocketInfo::GetInterface(const nsIID & uuid, void * *result)
00375 {
00376   nsresult rv;
00377   if (!mCallbacks) {
00378     nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
00379     if (!ir)
00380       return NS_ERROR_OUT_OF_MEMORY;
00381 
00382     rv = ir->GetInterface(uuid, result);
00383   } else {
00384     // Proxy of the channel callbacks should probably go here, rather
00385     // than in the password callback code
00386 
00387     rv = mCallbacks->GetInterface(uuid, result);
00388   }
00389   return rv;
00390 }
00391 
00392 NS_IMETHODIMP
00393 nsNSSSocketInfo::GetForceHandshake(PRBool* forceHandshake)
00394 {
00395   *forceHandshake = PR_FALSE;
00396   return NS_OK;
00397 }
00398 
00399 NS_IMETHODIMP
00400 nsNSSSocketInfo::SetForceHandshake(PRBool forceHandshake)
00401 {
00402   (void)forceHandshake;
00403   return NS_OK;
00404 }
00405 
00406 nsresult
00407 nsNSSSocketInfo::GetForSTARTTLS(PRBool* aForSTARTTLS)
00408 {
00409   *aForSTARTTLS = mForSTARTTLS;
00410   return NS_OK;
00411 }
00412 
00413 nsresult
00414 nsNSSSocketInfo::SetForSTARTTLS(PRBool aForSTARTTLS)
00415 {
00416   mForSTARTTLS = aForSTARTTLS;
00417   return NS_OK;
00418 }
00419 
00420 NS_IMETHODIMP
00421 nsNSSSocketInfo::ProxyStartSSL()
00422 {
00423   return ActivateSSL();
00424 }
00425 
00426 NS_IMETHODIMP
00427 nsNSSSocketInfo::StartTLS()
00428 {
00429   return ActivateSSL();
00430 }
00431 
00432 nsresult nsNSSSocketInfo::ActivateSSL()
00433 {
00434   nsNSSShutDownPreventionLock locker;
00435   if (isAlreadyShutDown())
00436     return NS_ERROR_NOT_AVAILABLE;
00437 
00438   nsresult rv = nsSSLThread::requestActivateSSL(this);
00439   
00440   if (NS_FAILED(rv))
00441     return rv;
00442 
00443   mHandshakePending = PR_TRUE;
00444 
00445   return NS_OK;
00446 }
00447 
00448 nsresult nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
00449 {
00450   *aFilePtr = mFd;
00451   return NS_OK;
00452 }
00453 
00454 nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
00455 {
00456   mFd = aFilePtr;
00457   return NS_OK;
00458 }
00459 
00460 nsresult nsNSSSocketInfo::GetSSLStatus(nsISupports** _result)
00461 {
00462   NS_ASSERTION(_result, "non-NULL destination required");
00463 
00464   *_result = mSSLStatus;
00465   NS_IF_ADDREF(*_result);
00466 
00467   return NS_OK;
00468 }
00469 
00470 nsresult nsNSSSocketInfo::RememberCAChain(CERTCertList *aCertList)
00471 {
00472   nsNSSShutDownPreventionLock locker;
00473   if (isAlreadyShutDown())
00474     return NS_ERROR_NOT_AVAILABLE;
00475 
00476   if (mCAChain) {
00477     CERT_DestroyCertList(mCAChain);
00478   }
00479   mCAChain = aCertList;
00480   return NS_OK;
00481 }
00482 
00483 nsresult nsNSSSocketInfo::SetSSLStatus(nsISSLStatus *aSSLStatus)
00484 {
00485   mSSLStatus = aSSLStatus;
00486 
00487   return NS_OK;
00488 }
00489 
00490 void nsNSSSocketInfo::SetHandshakeInProgress(PRBool aIsIn)
00491 {
00492   mHandshakeInProgress = aIsIn;
00493 
00494   if (mHandshakeInProgress && !mHandshakeStartTime)
00495   {
00496     mHandshakeStartTime = PR_IntervalNow();
00497   }
00498 }
00499 
00500 void nsNSSSocketInfo::SetBadCertUIStatus(nsNSSSocketInfo::BadCertUIStatusType aNewStatus)
00501 {
00502   if (mBadCertUIStatus == bcuis_active && 
00503       aNewStatus == bcuis_was_shown)
00504   {
00505     // we were blocked and going back to unblocked,
00506     // so let's reset the handshake start time, in order to ensure
00507     // we do not count the amount of time while the UI was shown.
00508     mHandshakeStartTime = PR_IntervalNow();
00509   }
00510 
00511   mBadCertUIStatus = aNewStatus;
00512 }
00513 
00514 void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(PRBool aAllow)
00515 {
00516   mAllowTLSIntoleranceTimeout = aAllow;
00517 }
00518 
00519 #define HANDSHAKE_TIMEOUT_SECONDS 25
00520 
00521 PRBool nsNSSSocketInfo::HandshakeTimeout()
00522 {
00523   if (!mHandshakeInProgress || !mAllowTLSIntoleranceTimeout || 
00524       mBadCertUIStatus == bcuis_active)
00525     return PR_FALSE;
00526 
00527   return ((PRIntervalTime)(PR_IntervalNow() - mHandshakeStartTime)
00528           > PR_SecondsToInterval(HANDSHAKE_TIMEOUT_SECONDS));
00529 }
00530 
00531 void nsSSLIOLayerHelpers::Cleanup()
00532 {
00533   if (mTLSIntolerantSites) {
00534     delete mTLSIntolerantSites;
00535     mTLSIntolerantSites = nsnull;
00536   }
00537 
00538   if (mSharedPollableEvent)
00539     PR_DestroyPollableEvent(mSharedPollableEvent);
00540 
00541   if (mutex)
00542     PR_DestroyLock(mutex);
00543 }
00544 
00545 static nsresult
00546 displayAlert(nsAFlatString &formattedString, nsNSSSocketInfo *infoObject)
00547 {
00548        
00549        // The interface requestor object may not be safe, so
00550     // proxy the call to get the nsIPrompt.
00551 
00552      nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00553      if (!proxyman) 
00554        return NS_ERROR_FAILURE;
00555  
00556      nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
00557      proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
00558                                  NS_GET_IID(nsIInterfaceRequestor),
00559                                  NS_STATIC_CAST(nsIInterfaceRequestor*,infoObject),
00560                                  PROXY_SYNC,
00561                                  getter_AddRefs(proxiedCallbacks));
00562 
00563      nsCOMPtr<nsIPrompt> prompt (do_GetInterface(proxiedCallbacks));
00564   
00565      if (!prompt)
00566        return NS_ERROR_NO_INTERFACE;
00567 
00568      nsCOMPtr<nsIPrompt> proxyPrompt;
00569      // Finally, get a proxy for the nsIPrompt
00570      proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
00571                                  NS_GET_IID(nsIPrompt),
00572                                  prompt,
00573                                  PROXY_SYNC,
00574                                  getter_AddRefs(proxyPrompt));
00575      proxyPrompt->Alert(nsnull, formattedString.get());
00576      return NS_OK;
00577      
00578 }
00579 
00580 static nsresult
00581 nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRInt32 err)
00582 {
00583   if (socketInfo->GetCanceled()) {
00584     // If the socket has been flagged as canceled,
00585     // the code who did was responsible for showing
00586     // an error message (if desired).
00587     return NS_OK;
00588   }
00589 
00590   nsresult rv;
00591   NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
00592   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
00593   if (NS_FAILED(rv))
00594     return rv;
00595 
00596   char buf[80];
00597   PR_snprintf(buf, 80, "%ld", err);
00598   NS_ConvertASCIItoUCS2 errorCode(buf);
00599 
00600   nsXPIDLCString hostName;
00601   socketInfo->GetHostName(getter_Copies(hostName));
00602   NS_ConvertASCIItoUCS2 hostNameU(hostName);
00603 
00604   NS_DEFINE_CID(StringBundleServiceCID,  NS_STRINGBUNDLESERVICE_CID);
00605   nsCOMPtr<nsIStringBundleService> service = 
00606                               do_GetService(StringBundleServiceCID, &rv);
00607   nsCOMPtr<nsIStringBundle> brandBundle;
00608   service->CreateBundle("chrome://branding/locale/brand.properties",
00609                         getter_AddRefs(brandBundle));
00610   nsXPIDLString brandShortName;
00611   brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
00612                                  getter_Copies(brandShortName));
00613     
00614   const PRUnichar *params[2];
00615   nsAutoString formattedString;
00616 
00617   switch (err) {
00618   case SSL_ERROR_SSL_DISABLED:
00619     params[0] = brandShortName.get();
00620     params[1] = hostNameU.get();
00621     nssComponent->PIPBundleFormatStringFromName("SSL_Disabled",
00622                                                 params, 2, formattedString);
00623     break;
00624   case SSL_ERROR_SSL2_DISABLED:
00625     params[0] = brandShortName.get();
00626     params[1] = hostNameU.get();
00627     nssComponent->PIPBundleFormatStringFromName("SSL2_Disabled",
00628                                                 params, 2, formattedString);
00629     break;
00630   case SSL_ERROR_EXPORT_ONLY_SERVER:
00631   case SSL_ERROR_US_ONLY_SERVER:
00632   case SSL_ERROR_NO_CYPHER_OVERLAP:
00633   case SSL_ERROR_UNSUPPORTED_VERSION:
00634   case SSL_ERROR_UNKNOWN_CIPHER_SUITE:
00635   case SSL_ERROR_NO_CIPHERS_SUPPORTED:
00636   case SSL_ERROR_FORTEZZA_PQG:
00637     params[0] = brandShortName.get();
00638     params[1] = hostNameU.get();
00639     nssComponent->PIPBundleFormatStringFromName("SSL_NoMatchingCiphers",
00640                                                 params, 2, formattedString);
00641                                                   
00642     break;
00643 
00644   //Clients Cert Rejected
00645   case SSL_ERROR_REVOKED_CERT_ALERT :
00646     params[0] = hostNameU.get();
00647     nssComponent->PIPBundleFormatStringFromName("UsersCertRevoked",
00648                                                 params, 1, formattedString);
00649     break;
00650 
00651   case SSL_ERROR_EXPIRED_CERT_ALERT:
00652     params[0] = hostNameU.get();
00653     nssComponent->PIPBundleFormatStringFromName("UsersCertExpired",
00654                                                 params, 1, formattedString);
00655     break;
00656 
00657   case SSL_ERROR_BAD_CERT_ALERT:
00658   case SSL_ERROR_UNSUPPORTED_CERT_ALERT:
00659   case SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT:
00660     params[0] = hostNameU.get();
00661     params[1] = errorCode.get();
00662     nssComponent->PIPBundleFormatStringFromName("UsersCertRejected",
00663                                                 params, 2, formattedString);
00664     break;
00665 
00666   //Errors related to Peers Certificate
00667   case SEC_ERROR_CRL_EXPIRED:
00668     params[0] = hostNameU.get();
00669     nssComponent->PIPBundleFormatStringFromName("CRLExpired", 
00670                                                 params, 1, formattedString);
00671     break;
00672 
00673   case SEC_ERROR_CRL_NOT_YET_VALID:
00674     params[0] = hostNameU.get();
00675     nssComponent->PIPBundleFormatStringFromName("CRLNotYetValid", 
00676                                                 params, 1, formattedString);
00677     break;
00678 
00679   case SEC_ERROR_CRL_INVALID:
00680     params[0] = hostNameU.get();
00681     nssComponent->PIPBundleFormatStringFromName("CRLSNotValid", 
00682                                                 params, 1, formattedString);
00683     break;
00684 
00685   case SEC_ERROR_CRL_BAD_SIGNATURE:
00686     params[0] = hostNameU.get();
00687     nssComponent->PIPBundleFormatStringFromName("CRLSigNotValid", 
00688                                                 params, 1, formattedString);
00689     break;
00690 
00691   case SEC_ERROR_OCSP_MALFORMED_REQUEST:
00692     params[0] = hostNameU.get();
00693     nssComponent->PIPBundleFormatStringFromName("OCSPMalformedRequest", 
00694                                              params, 1, formattedString);
00695     break;
00696 
00697   case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG:
00698     params[0] = hostNameU.get();
00699     nssComponent->PIPBundleFormatStringFromName("OCSPRequestNeedsSig", 
00700                                              params, 1, formattedString);
00701     break;
00702 
00703   case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST:
00704     params[0] = hostNameU.get();
00705     nssComponent->PIPBundleFormatStringFromName("OCSPUnauthorizedReq", 
00706                                              params, 1, formattedString);
00707     break;
00708 
00709   case SEC_ERROR_OCSP_SERVER_ERROR:
00710     params[0] = hostNameU.get();
00711     nssComponent->PIPBundleFormatStringFromName("OCSPServerError", 
00712                                              params, 1, formattedString);
00713     break;
00714 
00715   case SEC_ERROR_OCSP_TRY_SERVER_LATER:
00716     params[0] = hostNameU.get();
00717     nssComponent->PIPBundleFormatStringFromName("OCSPTryServerLater", 
00718                                              params, 1, formattedString);
00719     break;
00720   
00721   case SEC_ERROR_OCSP_FUTURE_RESPONSE:
00722     params[0] = hostNameU.get();
00723     nssComponent->PIPBundleFormatStringFromName("OCSPFutureResponse", 
00724                                              params, 1, formattedString);
00725     break;
00726 
00727   case SEC_ERROR_OCSP_OLD_RESPONSE:
00728     params[0] = hostNameU.get();
00729     nssComponent->PIPBundleFormatStringFromName("OCSPOldResponse", 
00730                                              params, 1, formattedString);
00731     break;
00732 
00733   case SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE:
00734   case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
00735   case SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS:
00736   case SEC_ERROR_OCSP_MALFORMED_RESPONSE:
00737     params[0] = hostNameU.get();
00738     params[1] = errorCode.get();
00739     nssComponent->PIPBundleFormatStringFromName("OCSPCorruptedResponse", 
00740                                              params, 2, formattedString);
00741     break;
00742 
00743   case SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE:
00744     params[0] = hostNameU.get();
00745     nssComponent->PIPBundleFormatStringFromName("OCSPUnauthorizedResponse", 
00746                                              params, 1, formattedString);
00747     break;
00748     
00749   case SEC_ERROR_OCSP_UNKNOWN_CERT:
00750     params[0] = hostNameU.get();
00751     nssComponent->PIPBundleFormatStringFromName("OCSPUnknownCert", 
00752                                              params, 1, formattedString);
00753     break;
00754 
00755 
00756   case SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER:
00757     params[0] = hostNameU.get();
00758     nssComponent->PIPBundleFormatStringFromName("OCSPNoDefaultResponder", 
00759                                              params, 1, formattedString);
00760     break;
00761   
00762   case PR_DIRECTORY_LOOKUP_ERROR:
00763     params[0] = hostNameU.get();
00764     nssComponent->PIPBundleFormatStringFromName("OCSPDirLookup", 
00765                                              params, 1, formattedString);
00766     break;
00767 
00768   case SEC_ERROR_REVOKED_CERTIFICATE:
00769     params[0] = hostNameU.get();
00770     nssComponent->PIPBundleFormatStringFromName("PeersCertRevoked", 
00771                                              params, 1, formattedString);
00772     break;
00773 
00774   case SEC_ERROR_UNTRUSTED_CERT:
00775     params[0] = hostNameU.get();
00776          nssComponent->PIPBundleFormatStringFromName("PeersCertUntrusted", 
00777                                             params, 1, formattedString);
00778          break;
00779 
00780   case SSL_ERROR_BAD_CERT_DOMAIN:
00781     params[0] = hostNameU.get();
00782          nssComponent->PIPBundleFormatStringFromName("PeersCertWrongDomain", 
00783                                             params, 1, formattedString);
00784          break;
00785 
00786   case SEC_ERROR_EXPIRED_CERTIFICATE:
00787     params[0] = hostNameU.get();
00788          nssComponent->PIPBundleFormatStringFromName("PeersCertExpired", 
00789                                             params, 1, formattedString);
00790          break;
00791 
00792   case SEC_ERROR_BAD_SIGNATURE:
00793     params[0] = hostNameU.get();
00794     nssComponent->PIPBundleFormatStringFromName("PeersCertBadSignature", 
00795                                                 params, 1, formattedString);
00796     break;
00797 
00798   //A generic error handler for peer cert
00799   case SEC_ERROR_UNKNOWN_CERT:
00800   case SEC_ERROR_BAD_KEY:
00801   case SEC_ERROR_CERT_USAGES_INVALID:
00802   case SEC_ERROR_INADEQUATE_KEY_USAGE:
00803   case SEC_ERROR_INADEQUATE_CERT_TYPE:
00804   case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
00805   case SEC_ERROR_CERT_NOT_VALID:
00806   case SEC_ERROR_CERT_ADDR_MISMATCH:
00807   case SSL_ERROR_BAD_CERTIFICATE:
00808   case SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE:
00809   case SSL_ERROR_WRONG_CERTIFICATE:
00810   case SSL_ERROR_CERT_KEA_MISMATCH:
00811   case SEC_ERROR_EXTENSION_VALUE_INVALID :
00812   case SEC_ERROR_EXTENSION_NOT_FOUND:
00813   case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
00814     params[0] = hostNameU.get();
00815     params[1] = errorCode.get();
00816     nssComponent->PIPBundleFormatStringFromName("PeersCertNoGood", 
00817                                                params, 2, formattedString);
00818          break;
00819 
00820   case SSL_ERROR_BAD_MAC_READ:
00821     params[0] = brandShortName.get();
00822     nssComponent->PIPBundleFormatStringFromName("BadMac",
00823                                                 params, 1, formattedString);
00824     break;
00825 
00826   case SSL_ERROR_BAD_MAC_ALERT:
00827     params[0] = hostNameU.get();
00828     nssComponent->PIPBundleFormatStringFromName("BadMac",
00829                                                 params, 1, formattedString);
00830     break;
00831 
00832   //Connection Reset by peer
00833   case SSL_ERROR_CLOSE_NOTIFY_ALERT:
00834   case SSL_ERROR_SOCKET_WRITE_FAILURE:
00835     params[0] = hostNameU.get();
00836     params[1] = errorCode.get();
00837     nssComponent->PIPBundleFormatStringFromName("PeerResetConnection",
00838                                                 params, 2, formattedString);
00839     break;
00840 
00841   //Connection reset by host
00842   case SEC_ERROR_USER_CANCELLED:
00843   case SEC_ERROR_MESSAGE_SEND_ABORTED:
00844     nssComponent->GetPIPNSSBundleString("HostResetConnection", formattedString);
00845     break;
00846 
00847   //Bad password
00848   case SEC_ERROR_BAD_PASSWORD:
00849   case SEC_ERROR_RETRY_PASSWORD:
00850     nssComponent->GetPIPNSSBundleString("BadPassword", formattedString);
00851     break;
00852 
00853   //Bad Database
00854   case SEC_ERROR_BAD_DATABASE:
00855   case SEC_ERROR_NO_KEY:
00856   case SEC_ERROR_CERT_NO_RESPONSE:
00857     params[0] = errorCode.get();
00858     nssComponent->PIPBundleFormatStringFromName("BadDatabase",
00859                                                 params, 1, formattedString);
00860     break;
00861 
00862   //Malformed or unxepected data or message was received from server
00863   case SSL_ERROR_BAD_SERVER:
00864   case SSL_ERROR_BAD_BLOCK_PADDING:
00865   case SSL_ERROR_RX_RECORD_TOO_LONG:
00866   case SSL_ERROR_TX_RECORD_TOO_LONG:
00867   case SSL_ERROR_RX_MALFORMED_HELLO_REQUEST:
00868   case SSL_ERROR_RX_MALFORMED_SERVER_HELLO:
00869   case SSL_ERROR_RX_MALFORMED_CERTIFICATE:
00870   case SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH:
00871   case SSL_ERROR_RX_MALFORMED_CERT_REQUEST:
00872   case SSL_ERROR_RX_MALFORMED_HELLO_DONE:
00873   case SSL_ERROR_RX_MALFORMED_FINISHED:
00874   case SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER:
00875   case SSL_ERROR_RX_MALFORMED_ALERT:
00876   case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
00877   case SSL_ERROR_RX_MALFORMED_APPLICATION_DATA:
00878   case SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST:
00879   case SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO:
00880   case SSL_ERROR_RX_UNEXPECTED_CERTIFICATE:
00881   case SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH:
00882   case SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST:
00883   case SSL_ERROR_RX_UNEXPECTED_HELLO_DONE:
00884   case SSL_ERROR_RX_UNEXPECTED_FINISHED:
00885   case SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER:
00886   case SSL_ERROR_RX_UNEXPECTED_ALERT:
00887   case SSL_ERROR_RX_UNEXPECTED_HANDSHAKE:
00888   case SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA:
00889   case SSL_ERROR_RX_UNKNOWN_RECORD_TYPE:
00890   case SSL_ERROR_RX_UNKNOWN_HANDSHAKE:
00891   case SSL_ERROR_RX_UNKNOWN_ALERT:
00892     params[0] = hostNameU.get();
00893     params[1] = errorCode.get();
00894     nssComponent->PIPBundleFormatStringFromName("BadServer",
00895                                                 params, 2, formattedString);
00896     break;
00897 
00898   //Alert for Malformed or unexpected data or message recieved by server
00899   case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
00900   case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT:
00901   case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
00902   case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
00903     params[0] = hostNameU.get();
00904     params[1] = errorCode.get();
00905     nssComponent->PIPBundleFormatStringFromName("BadClient",
00906                                                 params, 2, formattedString);
00907     break;
00908 
00909   case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
00910     nssComponent->GetPIPNSSBundleString("HostReusedIssuerSerial", formattedString);
00911     break;
00912 
00913   default:
00914     params[0] = hostNameU.get();
00915     params[1] = errorCode.get(); 
00916     nssComponent->PIPBundleFormatStringFromName("SSLGenericError",
00917                                                 params, 2, formattedString);
00918       
00919   }
00920 
00921   {
00922     nsPSMUITracker tracker;
00923     if (tracker.isUIForbidden()) {
00924       rv = NS_ERROR_NOT_AVAILABLE;
00925     }
00926     else {
00927       rv = displayAlert(formattedString, socketInfo);
00928     }
00929   }
00930   return rv;
00931 }
00932 
00933 
00934 static PRStatus PR_CALLBACK
00935 nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
00936                     PRIntervalTime timeout)
00937 {
00938   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
00939   nsNSSShutDownPreventionLock locker;
00940   if (!fd || !fd->lower)
00941     return PR_FAILURE;
00942   
00943   PRStatus status = PR_SUCCESS;
00944 
00945 #if defined(XP_BEOS)
00946   // Due to BeOS net_server's lack of support for nonblocking sockets,
00947   // we must execute this entire connect as a blocking operation - bug 70217
00948  
00949   PRSocketOptionData sockopt;
00950   sockopt.option = PR_SockOpt_Nonblocking;
00951   PR_GetSocketOption(fd, &sockopt);
00952   PRBool oldBlockVal = sockopt.value.non_blocking;
00953   sockopt.option = PR_SockOpt_Nonblocking;
00954   sockopt.value.non_blocking = PR_FALSE;
00955   PR_SetSocketOption(fd, &sockopt);
00956 #endif
00957   
00958   status = fd->lower->methods->connect(fd->lower, addr, 
00959 #if defined(XP_BEOS)  // bug 70217
00960                                        PR_INTERVAL_NO_TIMEOUT);
00961 #else
00962                                        timeout);
00963 #endif
00964   if (status != PR_SUCCESS) {
00965     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
00966                                       (void*)fd, PR_GetError()));
00967 #if defined(XP_BEOS)  // bug 70217
00968     goto loser;
00969 #else
00970     return status;
00971 #endif
00972   }
00973   
00974   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));
00975 
00976 #if defined(XP_BEOS)  // bug 70217
00977  loser:
00978   // We put the Nonblocking bit back to the value it was when 
00979   // we entered this function.
00980   NS_ASSERTION(sockopt.option == PR_SockOpt_Nonblocking,
00981                "sockopt.option was re-set to an unexpected value");
00982   sockopt.value.non_blocking = oldBlockVal;
00983   PR_SetSocketOption(fd, &sockopt);
00984 #endif
00985 
00986   return status;
00987 }
00988 
00989 // Call this function to report a site that is possibly TLS intolerant.
00990 // This function will return true, if the given socket is currently using TLS.
00991 PRBool
00992 nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
00993 {
00994   PRBool currentlyUsesTLS = PR_FALSE;
00995 
00996   SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
00997   if (currentlyUsesTLS) {
00998     // Add this site to the list of TLS intolerant sites.
00999     PRInt32 port;
01000     nsXPIDLCString host;
01001     socketInfo->GetPort(&port);
01002     socketInfo->GetHostName(getter_Copies(host));
01003     nsCAutoString key;
01004     key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
01005 
01006     addIntolerantSite(key);
01007   }
01008   
01009   return currentlyUsesTLS;
01010 }
01011 
01012 static PRStatus PR_CALLBACK
01013 nsSSLIOLayerClose(PRFileDesc *fd)
01014 {
01015   nsNSSShutDownPreventionLock locker;
01016   if (!fd)
01017     return PR_FAILURE;
01018 
01019   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
01020   
01021   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01022   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01023 
01024   return nsSSLThread::requestClose(socketInfo);
01025 }
01026 
01027 PRStatus nsNSSSocketInfo::CloseSocketAndDestroy()
01028 {
01029   nsNSSShutDownPreventionLock locker;
01030 
01031   nsNSSShutDownList::trackSSLSocketClose();
01032 
01033   PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
01034 
01035   if (GetHandshakeInProgress()) {
01036     nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(mFd->lower, this);
01037   }
01038 
01039   PRStatus status = mFd->methods->close(mFd);
01040   if (status != PR_SUCCESS) return status;
01041 
01042   popped->identity = PR_INVALID_IO_LAYER;
01043   NS_RELEASE_THIS();
01044   popped->dtor(popped);
01045 
01046   return PR_SUCCESS;
01047 }
01048 
01049 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
01050 /* Dumps a (potentially binary) buffer using SSM_DEBUG. 
01051    (We could have used the version in ssltrace.c, but that's
01052    specifically tailored to SSLTRACE. Sigh. */
01053 #define DUMPBUF_LINESIZE 24
01054 static void
01055 nsDumpBuffer(unsigned char *buf, PRIntn len)
01056 {
01057   char hexbuf[DUMPBUF_LINESIZE*3+1];
01058   char chrbuf[DUMPBUF_LINESIZE+1];
01059   static const char *hex = "0123456789abcdef";
01060   PRIntn i = 0, l = 0;
01061   char ch, *c, *h;
01062   if (len == 0)
01063     return;
01064   hexbuf[DUMPBUF_LINESIZE*3] = '\0';
01065   chrbuf[DUMPBUF_LINESIZE] = '\0';
01066   (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
01067   (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
01068   h = hexbuf;
01069   c = chrbuf;
01070 
01071   while (i < len)
01072   {
01073     ch = buf[i];
01074 
01075     if (l == DUMPBUF_LINESIZE)
01076     {
01077       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
01078       (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
01079       (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
01080       h = hexbuf;
01081       c = chrbuf;
01082       l = 0;
01083     }
01084 
01085     /* Convert a character to hex. */
01086     *h++ = hex[(ch >> 4) & 0xf];
01087     *h++ = hex[ch & 0xf];
01088     h++;
01089         
01090     /* Put the character (if it's printable) into the character buffer. */
01091     if ((ch >= 0x20) && (ch <= 0x7e))
01092       *c++ = ch;
01093     else
01094       *c++ = '.';
01095     i++; l++;
01096   }
01097   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
01098 }
01099 
01100 #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
01101 #else
01102 #define DEBUG_DUMP_BUFFER(buf,len)
01103 #endif
01104 
01105 static PRBool
01106 isNonSSLErrorThatWeAllowToRetry(PRInt32 err, PRBool withInitialCleartext)
01107 {
01108   switch (err)
01109   {
01110     case PR_CONNECT_RESET_ERROR:
01111       if (!withInitialCleartext)
01112         return PR_TRUE;
01113       break;
01114     
01115     case PR_END_OF_FILE_ERROR:
01116       return PR_TRUE;
01117   }
01118 
01119   return PR_FALSE;
01120 }
01121 
01122 static PRBool
01123 isTLSIntoleranceError(PRInt32 err, PRBool withInitialCleartext)
01124 {
01125   // This function is supposed to decide, which error codes should
01126   // be used to conclude server is TLS intolerant.
01127   // Note this only happens during the initial SSL handshake.
01128   // 
01129   // When not using a proxy we'll see a connection reset error.
01130   // When using a proxy, we'll see an end of file error.
01131   // In addition check for some error codes where it is reasonable
01132   // to retry without TLS.
01133 
01134   if (isNonSSLErrorThatWeAllowToRetry(err, withInitialCleartext))
01135     return PR_TRUE;
01136 
01137   switch (err)
01138   {
01139     case SSL_ERROR_BAD_MAC_ALERT:
01140     case SSL_ERROR_BAD_MAC_READ:
01141     case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
01142     case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
01143     case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
01144     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
01145     case SSL_ERROR_NO_CYPHER_OVERLAP:
01146     case SSL_ERROR_BAD_SERVER:
01147     case SSL_ERROR_BAD_BLOCK_PADDING:
01148     case SSL_ERROR_UNSUPPORTED_VERSION:
01149     case SSL_ERROR_PROTOCOL_VERSION_ALERT:
01150     case SSL_ERROR_RX_MALFORMED_FINISHED:
01151     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
01152     case SSL_ERROR_DECODE_ERROR_ALERT:
01153     case SSL_ERROR_RX_UNKNOWN_ALERT:
01154       return PR_TRUE;
01155   }
01156   
01157   return PR_FALSE;
01158 }
01159 
01160 static PRBool
01161 isClosedConnectionAfterBadCertUIWasShown(PRInt32 bytesTransfered, 
01162                                          PRBool wasReading, 
01163                                          PRInt32 err, 
01164                                          nsNSSSocketInfo::BadCertUIStatusType aBadCertUIStatus)
01165 {
01166   if (aBadCertUIStatus != nsNSSSocketInfo::bcuis_not_shown)
01167   {
01168     // Bad cert UI was shown for this socket.
01169     // Server timeout possible.
01170     // Retry on a simple connection close.
01171 
01172     if (wasReading && 0 == bytesTransfered)
01173       return PR_TRUE;
01174 
01175     if (0 > bytesTransfered)
01176     {
01177       switch (err)
01178       {
01179         case PR_CONNECT_RESET_ERROR:
01180         case PR_END_OF_FILE_ERROR:
01181           return PR_TRUE;
01182         default:
01183           break;
01184       }
01185     }
01186   }
01187 
01188   return PR_FALSE;
01189 }
01190 
01191 PRInt32
01192 nsSSLThread::checkHandshake(PRInt32 bytesTransfered, 
01193                             PRBool wasReading,
01194                             PRFileDesc* ssl_layer_fd, 
01195                             nsNSSSocketInfo *socketInfo)
01196 {
01197   // This is where we work around all of those SSL servers that don't 
01198   // conform to the SSL spec and shutdown a connection when we request
01199   // SSL v3.1 (aka TLS).  The spec says the client says what version
01200   // of the protocol we're willing to perform, in our case SSL v3.1
01201   // In its response, the server says which version it wants to perform.
01202   // Many servers out there only know how to do v3.0.  Next, we're supposed
01203   // to send back the version of the protocol we requested (ie v3.1).  At
01204   // this point many servers's implementations are broken and they shut
01205   // down the connection when they don't see the version they sent back.
01206   // This is supposed to prevent a man in the middle from forcing one
01207   // side to dumb down to a lower level of the protocol.  Unfortunately,
01208   // there are enough broken servers out there that such a gross work-around
01209   // is necessary.  :(
01210 
01211   // Additional comment added in August 2006:
01212   // When we begun to use TLS hello extensions, we encountered a new class of
01213   // broken server, which simply stall for a very long time.
01214   // We would like to shorten the timeout, but limit this shorter timeout 
01215   // to the handshake phase.
01216   // When we arrive here for the first time (for a given socket),
01217   // we know the connection is established, and the application code
01218   // tried the first read or write. This triggers the beginning of the
01219   // SSL handshake phase at the SSL FD level.
01220   // We'll make a note of the current time,
01221   // and use this to measure the elapsed time since handshake begin.
01222 
01223   // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
01224   // Simply retry.
01225   // This depends on the fact that Cert UI will not be shown again,
01226   // should the user override the bad cert.
01227 
01228   PRBool handleHandshakeResultNow;
01229   socketInfo->GetHandshakePending(&handleHandshakeResultNow);
01230 
01231   PRBool wantRetry = PR_FALSE;
01232 
01233   if (0 > bytesTransfered) {
01234     PRInt32 err = PR_GetError();
01235 
01236     if (handleHandshakeResultNow) {
01237       if (PR_WOULD_BLOCK_ERROR == err) {
01238         socketInfo->SetHandshakeInProgress(PR_TRUE);
01239         return bytesTransfered;
01240       }
01241 
01242       wantRetry = 
01243         isClosedConnectionAfterBadCertUIWasShown(bytesTransfered, 
01244                                                  wasReading, 
01245                                                  err, 
01246                                                  socketInfo->GetBadCertUIStatus());
01247 
01248       if (!wantRetry // no decision yet
01249           && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
01250       {
01251         wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
01252       }
01253     }
01254     
01255     // This is the common place where we trigger an error message on a SSL socket.
01256     // This might be reached at any time of the connection.
01257     if (!wantRetry && (IS_SSL_ERROR(err) || IS_SEC_ERROR(err))) {
01258       nsHandleSSLError(socketInfo, err);
01259     }
01260   }
01261   else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
01262   {
01263     if (handleHandshakeResultNow)
01264     {
01265       wantRetry = 
01266         isClosedConnectionAfterBadCertUIWasShown(bytesTransfered, 
01267                                                  wasReading, 
01268                                                  0, 
01269                                                  socketInfo->GetBadCertUIStatus());
01270 
01271       if (!wantRetry // no decision yet
01272           && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
01273       {
01274         wantRetry = 
01275           nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
01276       }
01277     }
01278   }
01279 
01280   if (wantRetry) {
01281     // We want to cause the network layer to retry the connection.
01282     PR_SetError(PR_CONNECT_RESET_ERROR, 0);
01283     if (wasReading)
01284       bytesTransfered = -1;
01285   }
01286 
01287   // TLS intolerant servers only cause the first transfer to fail, so let's 
01288   // set the HandshakePending attribute to false so that we don't try the logic
01289   // above again in a subsequent transfer.
01290   if (handleHandshakeResultNow) {
01291     socketInfo->SetHandshakePending(PR_FALSE);
01292     socketInfo->SetHandshakeInProgress(PR_FALSE);
01293   }
01294   
01295   return bytesTransfered;
01296 }
01297 
01298 static PRInt16 PR_CALLBACK
01299 nsSSLIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
01300 {
01301   nsNSSShutDownPreventionLock locker;
01302 
01303   if (!out_flags)
01304   {
01305     NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
01306     return 0;
01307   }
01308 
01309   *out_flags = 0;
01310 
01311   if (!fd)
01312   {
01313     NS_WARNING("nsSSLIOLayerPoll called with null fd");
01314     return 0;
01315   }
01316 
01317   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01318   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01319 
01320   return nsSSLThread::requestPoll(socketInfo, in_flags, out_flags);
01321 }
01322 
01323 static PRInt32 PR_CALLBACK
01324 nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
01325 {
01326   nsNSSShutDownPreventionLock locker;
01327   if (!fd || !fd->lower) {
01328     return PR_FAILURE;
01329   }
01330 
01331   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01332   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01333 
01334   return nsSSLThread::requestRead(socketInfo, buf, amount);
01335 }
01336 
01337 static PRInt32 PR_CALLBACK
01338 nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, PRInt32 amount)
01339 {
01340   nsNSSShutDownPreventionLock locker;
01341   if (!fd || !fd->lower) {
01342     return PR_FAILURE;
01343   }
01344 
01345 #ifdef DEBUG_SSL_VERBOSE
01346   DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
01347 #endif
01348   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01349   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01350 
01351   return nsSSLThread::requestWrite(socketInfo, buf, amount);
01352 }
01353 
01354 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
01355 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
01356 PRLock *nsSSLIOLayerHelpers::mutex = nsnull;
01357 nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
01358 PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull;
01359 nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
01360 PRBool nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_FALSE;
01361 
01362 static PRIntn _PSM_InvalidInt(void)
01363 {
01364     PR_ASSERT(!"I/O method is invalid");
01365     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
01366     return -1;
01367 }
01368 
01369 static PRInt64 _PSM_InvalidInt64(void)
01370 {
01371     PR_ASSERT(!"I/O method is invalid");
01372     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
01373     return -1;
01374 }
01375 
01376 static PRStatus _PSM_InvalidStatus(void)
01377 {
01378     PR_ASSERT(!"I/O method is invalid");
01379     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
01380     return PR_FAILURE;
01381 }
01382 
01383 static PRFileDesc *_PSM_InvalidDesc(void)
01384 {
01385     PR_ASSERT(!"I/O method is invalid");
01386     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
01387     return NULL;
01388 }
01389 
01390 static PRStatus PR_CALLBACK PSMGetsockname(PRFileDesc *fd, PRNetAddr *addr)
01391 {
01392   nsNSSShutDownPreventionLock locker;
01393   if (!fd || !fd->lower) {
01394     return PR_FAILURE;
01395   }
01396 
01397   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01398   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01399 
01400   return nsSSLThread::requestGetsockname(socketInfo, addr);
01401 }
01402 
01403 static PRStatus PR_CALLBACK PSMGetpeername(PRFileDesc *fd, PRNetAddr *addr)
01404 {
01405   nsNSSShutDownPreventionLock locker;
01406   if (!fd || !fd->lower) {
01407     return PR_FAILURE;
01408   }
01409 
01410   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01411   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01412 
01413   return nsSSLThread::requestGetpeername(socketInfo, addr);
01414 }
01415 
01416 static PRStatus PR_CALLBACK PSMGetsocketoption(PRFileDesc *fd, 
01417                                         PRSocketOptionData *data)
01418 {
01419   nsNSSShutDownPreventionLock locker;
01420   if (!fd || !fd->lower) {
01421     return PR_FAILURE;
01422   }
01423 
01424   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01425   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01426 
01427   return nsSSLThread::requestGetsocketoption(socketInfo, data);
01428 }
01429 
01430 static PRStatus PR_CALLBACK PSMSetsocketoption(PRFileDesc *fd, 
01431                                         const PRSocketOptionData *data)
01432 {
01433   nsNSSShutDownPreventionLock locker;
01434   if (!fd || !fd->lower) {
01435     return PR_FAILURE;
01436   }
01437 
01438   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01439   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01440 
01441   return nsSSLThread::requestSetsocketoption(socketInfo, data);
01442 }
01443 
01444 static PRInt32 PR_CALLBACK PSMRecv(PRFileDesc *fd, void *buf, PRInt32 amount,
01445     PRIntn flags, PRIntervalTime timeout)
01446 {
01447   nsNSSShutDownPreventionLock locker;
01448   if (!fd || !fd->lower) {
01449     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
01450     return -1;
01451   }
01452 
01453   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01454   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01455 
01456   if (flags == PR_MSG_PEEK) {
01457     return nsSSLThread::requestRecvMsgPeek(socketInfo, buf, amount, flags, timeout);
01458   }
01459 
01460   return fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
01461 }
01462 
01463 static PRInt32 PR_CALLBACK PSMSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
01464     PRIntn flags, PRIntervalTime timeout)
01465 {
01466   nsNSSShutDownPreventionLock locker;
01467   if (!fd || !fd->lower) {
01468     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
01469     return -1;
01470   }
01471 
01472   return fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
01473 }
01474 
01475 static PRStatus PR_CALLBACK PSMConnectcontinue(PRFileDesc *fd, PRInt16 out_flags)
01476 {
01477   nsNSSShutDownPreventionLock locker;
01478   if (!fd || !fd->lower) {
01479     return PR_FAILURE;
01480   }
01481 
01482   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
01483   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
01484 
01485   return nsSSLThread::requestConnectcontinue(socketInfo, out_flags);
01486 }
01487 
01488 nsresult nsSSLIOLayerHelpers::Init()
01489 {
01490   nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
01491   nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
01492 
01493   nsSSLIOLayerMethods.available = (PRAvailableFN)_PSM_InvalidInt;
01494   nsSSLIOLayerMethods.available64 = (PRAvailable64FN)_PSM_InvalidInt64;
01495   nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
01496   nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
01497   nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
01498   nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
01499   nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
01500   nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
01501   nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
01502   nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
01503   nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
01504   nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
01505   nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
01506   nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
01507   nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
01508   nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
01509   nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
01510 
01511   nsSSLIOLayerMethods.getsockname = PSMGetsockname;
01512   nsSSLIOLayerMethods.getpeername = PSMGetpeername;
01513   nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
01514   nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
01515   nsSSLIOLayerMethods.recv = PSMRecv;
01516   nsSSLIOLayerMethods.send = PSMSend;
01517   nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
01518 
01519   nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
01520   nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
01521   nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
01522   nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
01523   nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
01524 
01525   mutex = PR_NewLock();
01526   if (!mutex)
01527     return NS_ERROR_OUT_OF_MEMORY;
01528 
01529   mSharedPollableEvent = PR_NewPollableEvent();
01530 
01531   // if we can not get a pollable event, we'll have to do busy waiting
01532 
01533   mTLSIntolerantSites = new nsCStringHashSet();
01534   if (!mTLSIntolerantSites)
01535     return NS_ERROR_OUT_OF_MEMORY;
01536 
01537   mTLSIntolerantSites->Init(1);
01538 
01539   return NS_OK;
01540 }
01541 
01542 void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
01543 {
01544   nsAutoLock lock(mutex);
01545   nsSSLIOLayerHelpers::mTLSIntolerantSites->Put(str);
01546 }
01547 
01548 PRBool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
01549 {
01550   nsAutoLock lock(mutex);
01551   return mTLSIntolerantSites->Contains(str);
01552 }
01553 
01554 nsresult
01555 nsSSLIOLayerNewSocket(PRInt32 family,
01556                       const char *host,
01557                       PRInt32 port,
01558                       const char *proxyHost,
01559                       PRInt32 proxyPort,
01560                       PRFileDesc **fd,
01561                       nsISupports** info,
01562                       PRBool forSTARTTLS)
01563 {
01564 
01565   PRFileDesc* sock = PR_OpenTCPSocket(family);
01566   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
01567 
01568   nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
01569                                         sock, info, forSTARTTLS);
01570   if (NS_FAILED(rv)) {
01571     PR_Close(sock);
01572     return rv;
01573   }
01574 
01575   *fd = sock;
01576   return NS_OK;
01577 }
01578 
01579 static nsresult
01580 addCertToDB(CERTCertificate *peerCert, PRInt16 addType)
01581 {
01582   CERTCertTrust trust;
01583   SECStatus rv;
01584   nsresult retVal = NS_ERROR_FAILURE;
01585   char *nickname;
01586   
01587   switch (addType) {
01588     case nsIBadCertListener::ADD_TRUSTED_PERMANENTLY:
01589       nickname = nsNSSCertificate::defaultServerNickname(peerCert);
01590       if (nsnull == nickname)
01591         break;
01592       memset((void*)&trust, 0, sizeof(trust));
01593       rv = CERT_DecodeTrustString(&trust, "P"); 
01594       if (rv != SECSuccess) {
01595         return NS_ERROR_FAILURE;
01596       }
01597       rv = CERT_AddTempCertToPerm(peerCert, nickname, &trust);
01598       if (rv == SECSuccess)
01599         retVal = NS_OK;
01600       PR_Free(nickname);
01601       break;
01602     case nsIBadCertListener::ADD_TRUSTED_FOR_SESSION:
01603       // XXX We need an API from NSS to do this so 
01604       //     that we don't have to access the fields 
01605       //     in the cert directly.
01606       peerCert->keepSession = PR_TRUE;
01607       CERTCertTrust *trustPtr;
01608       if (!peerCert->trust) {
01609         trustPtr = (CERTCertTrust*)PORT_ArenaZAlloc(peerCert->arena,
01610                                                     sizeof(CERTCertTrust));
01611         if (!trustPtr)
01612           break;
01613 
01614         peerCert->trust = trustPtr;
01615       } else {
01616         trustPtr = peerCert->trust;
01617       }
01618       rv = CERT_DecodeTrustString(trustPtr, "P");
01619       if (rv != SECSuccess)
01620         break;
01621 
01622       retVal = NS_OK;      
01623       break;
01624     default:
01625       PR_ASSERT(!"Invalid value for addType passed to addCertDB");
01626       break;
01627   }
01628   return retVal;
01629 }
01630 
01631 static PRBool
01632 nsContinueDespiteCertError(nsNSSSocketInfo  *infoObject,
01633                            PRFileDesc       *sslSocket,
01634                            int               error,
01635                            nsNSSCertificate *nssCert)
01636 {
01637   PRBool retVal = PR_FALSE;
01638   nsIBadCertListener *badCertHandler = nsnull;
01639   PRInt16 addType = nsIBadCertListener::UNINIT_ADD_FLAG;
01640   nsresult rv;
01641 
01642   if (!nssCert)
01643     return PR_FALSE;
01644 
01645   // Try to get a nsIBadCertListener implementation from the socket consumer
01646   // first.  If that fails, fallback to the default UI.
01647   nsCOMPtr<nsIInterfaceRequestor> callbacks;
01648   infoObject->GetNotificationCallbacks(getter_AddRefs(callbacks));
01649   if (callbacks) {
01650     nsCOMPtr<nsIBadCertListener> handler = do_GetInterface(callbacks);
01651     if (handler)
01652       NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
01653                            NS_GET_IID(nsIBadCertListener),
01654                            handler,
01655                            PROXY_SYNC,
01656                            (void**)&badCertHandler);
01657   }
01658   if (!badCertHandler) {
01659     rv = getNSSDialogs((void**)&badCertHandler, 
01660                        NS_GET_IID(nsIBadCertListener),
01661                        NS_BADCERTLISTENER_CONTRACTID);
01662     if (NS_FAILED(rv)) 
01663       return PR_FALSE;
01664   }
01665   nsIInterfaceRequestor *csi = NS_STATIC_CAST(nsIInterfaceRequestor*,
01666                                                  infoObject);
01667   nsIX509Cert *callBackCert = NS_STATIC_CAST(nsIX509Cert*, nssCert);
01668   CERTCertificate *peerCert = nssCert->GetCert();
01669   NS_ASSERTION(peerCert, "Got nsnull cert back from nsNSSCertificate");
01670   switch (error) {
01671   case SEC_ERROR_UNKNOWN_ISSUER:
01672   case SEC_ERROR_CA_CERT_INVALID:
01673   case SEC_ERROR_UNTRUSTED_ISSUER:
01674   /* This is a temporay fix for bug# - We are showing a unknown ca dialog,
01675      when actually the ca cert has expired/not yet valid. We need to change
01676      this in future - need to define a proper ui for this situation
01677   */
01678   case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
01679     {
01680       nsPSMUITracker tracker;
01681       if (tracker.isUIForbidden()) {
01682         rv = NS_ERROR_NOT_AVAILABLE;
01683       }
01684       else {
01685         rv = badCertHandler->ConfirmUnknownIssuer(csi, callBackCert, &addType, &retVal);
01686       }
01687     }
01688     break;
01689   case SSL_ERROR_BAD_CERT_DOMAIN:
01690     {
01691       nsXPIDLCString url; url.Adopt(SSL_RevealURL(sslSocket));
01692       NS_ASSERTION(url.get(), "could not find valid URL in ssl socket");
01693       {
01694         nsPSMUITracker tracker;
01695         if (tracker.isUIForbidden()) {
01696           rv = NS_ERROR_NOT_AVAILABLE;
01697         }
01698         else {
01699         rv = badCertHandler->ConfirmMismatchDomain(csi, url,
01700                                             callBackCert, &retVal);
01701         }
01702       }
01703       if (NS_SUCCEEDED(rv) && retVal) {
01704         rv = CERT_AddOKDomainName(peerCert, url);
01705       }
01706     }
01707     break;
01708   case SEC_ERROR_EXPIRED_CERTIFICATE:
01709     {
01710       nsPSMUITracker tracker;
01711       if (tracker.isUIForbidden()) {
01712         rv = NS_ERROR_NOT_AVAILABLE;
01713       }
01714       else {
01715         rv = badCertHandler->ConfirmCertExpired(csi, callBackCert, & retVal);
01716       }
01717     }
01718     if (rv == SECSuccess && retVal) {
01719       // XXX We need an NSS API for this equivalent functionality.
01720       //     Having to reach inside the cert is evil.
01721       peerCert->timeOK = PR_TRUE;
01722     }
01723     break;
01724   case SEC_ERROR_CRL_EXPIRED:
01725     {
01726       nsXPIDLCString url; url.Adopt(SSL_RevealURL(sslSocket));
01727       NS_ASSERTION(url, "could not find valid URL in ssl socket");
01728       {
01729         nsPSMUITracker tracker;
01730         if (tracker.isUIForbidden()) {
01731           rv = NS_ERROR_NOT_AVAILABLE;
01732         }
01733         else {
01734           rv = badCertHandler->NotifyCrlNextupdate(csi, url, callBackCert);
01735         }
01736       }
01737       retVal = PR_FALSE;
01738     }
01739     break;
01740   default:
01741     nsHandleSSLError(infoObject,error);
01742     retVal = PR_FALSE;
01743 
01744   }
01745   if (retVal && addType != nsIBadCertListener::UNINIT_ADD_FLAG) {
01746     addCertToDB(peerCert, addType);
01747   }
01748   NS_RELEASE(badCertHandler);
01749   CERT_DestroyCertificate(peerCert);
01750   return NS_FAILED(rv) ? PR_FALSE : retVal;
01751 }
01752 
01753 static SECStatus
01754 verifyCertAgain(CERTCertificate *cert, 
01755                 PRFileDesc      *sslSocket,
01756                 nsNSSSocketInfo *infoObject)
01757 {
01758   SECStatus rv;
01759 
01760   // If we get here, the user has accepted the cert so
01761   // far, so we don't check the signature again.
01762   rv = CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert,
01763                           PR_FALSE, certificateUsageSSLServer,
01764                           (void*)infoObject, NULL);
01765 
01766   if (rv != SECSuccess) {
01767     return rv;
01768   }
01769   
01770   // Check the name field against the desired hostname.
01771   char *hostname = SSL_RevealURL(sslSocket); 
01772   if (hostname && hostname[0]) {
01773     rv = CERT_VerifyCertName(cert, hostname);
01774   } else {
01775     rv = SECFailure;
01776   }
01777 
01778   if (rv != SECSuccess) {
01779     PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
01780   }
01781   PR_FREEIF(hostname);
01782   return rv;
01783 }
01784 /*
01785  * Function: SECStatus nsConvertCANamesToStrings()
01786  * Purpose: creates CA names strings from (CERTDistNames* caNames)
01787  *
01788  * Arguments and return values
01789  * - arena: arena to allocate strings on
01790  * - caNameStrings: filled with CA names strings on return
01791  * - caNames: CERTDistNames to extract strings from
01792  * - return: SECSuccess if successful; error code otherwise
01793  *
01794  * Note: copied in its entirety from Nova code
01795  */
01796 SECStatus nsConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings,
01797                                       CERTDistNames* caNames)
01798 {
01799     SECItem* dername;
01800     SECStatus rv;
01801     int headerlen;
01802     uint32 contentlen;
01803     SECItem newitem;
01804     int n;
01805     char* namestring;
01806 
01807     for (n = 0; n < caNames->nnames; n++) {
01808         newitem.data = NULL;
01809         dername = &caNames->names[n];
01810 
01811         rv = DER_Lengths(dername, &headerlen, &contentlen);
01812 
01813         if (rv != SECSuccess) {
01814             goto loser;
01815         }
01816 
01817         if (headerlen + contentlen != dername->len) {
01818             /* This must be from an enterprise 2.x server, which sent
01819              * incorrectly formatted der without the outer wrapper of
01820              * type and length.  Fix it up by adding the top level
01821              * header.
01822              */
01823             if (dername->len <= 127) {
01824                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 2);
01825                 if (newitem.data == NULL) {
01826                     goto loser;
01827                 }
01828                 newitem.data[0] = (unsigned char)0x30;
01829                 newitem.data[1] = (unsigned char)dername->len;
01830                 (void)memcpy(&newitem.data[2], dername->data, dername->len);
01831             }
01832             else if (dername->len <= 255) {
01833                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 3);
01834                 if (newitem.data == NULL) {
01835                     goto loser;
01836                 }
01837                 newitem.data[0] = (unsigned char)0x30;
01838                 newitem.data[1] = (unsigned char)0x81;
01839                 newitem.data[2] = (unsigned char)dername->len;
01840                 (void)memcpy(&newitem.data[3], dername->data, dername->len);
01841             }
01842             else {
01843                 /* greater than 256, better be less than 64k */
01844                 newitem.data = (unsigned char *) PR_Malloc(dername->len + 4);
01845                 if (newitem.data == NULL) {
01846                     goto loser;
01847                 }
01848                 newitem.data[0] = (unsigned char)0x30;
01849                 newitem.data[1] = (unsigned char)0x82;
01850                 newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
01851                 newitem.data[3] = (unsigned char)(dername->len & 0xff);
01852                 memcpy(&newitem.data[4], dername->data, dername->len);
01853             }
01854             dername = &newitem;
01855         }
01856 
01857         namestring = CERT_DerNameToAscii(dername);
01858         if (namestring == NULL) {
01859             /* XXX - keep going until we fail to convert the name */
01860             caNameStrings[n] = "";
01861         }
01862         else {
01863             caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
01864             PR_Free(namestring);
01865             if (caNameStrings[n] == NULL) {
01866                 goto loser;
01867             }
01868         }
01869 
01870         if (newitem.data != NULL) {
01871             PR_Free(newitem.data);
01872         }
01873     }
01874 
01875     return SECSuccess;
01876 loser:
01877     if (newitem.data != NULL) {
01878         PR_Free(newitem.data);
01879     }
01880     return SECFailure;
01881 }
01882 
01883 /*
01884  * structs and ASN1 templates for the limited scope-of-use extension
01885  *
01886  * CertificateScopeEntry ::= SEQUENCE {
01887  *     name GeneralName, -- pattern, as for NameConstraints
01888  *     portNumber INTEGER OPTIONAL }
01889  *
01890  * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
01891  */
01892 /*
01893  * CERTCertificateScopeEntry: struct for scope entry that can be consumed by
01894  *                            the code
01895  * certCertificateScopeOfUse: struct that represents the decoded extension data
01896  */
01897 typedef struct {
01898     SECItem derConstraint;
01899     SECItem derPort;
01900     CERTGeneralName* constraint; /* decoded constraint */
01901     PRIntn port; /* decoded port number */
01902 } CERTCertificateScopeEntry;
01903 
01904 typedef struct {
01905     CERTCertificateScopeEntry** entries;
01906 } certCertificateScopeOfUse;
01907 
01908 /* corresponding ASN1 templates */
01909 static const SEC_ASN1Template cert_CertificateScopeEntryTemplate[] = {
01910     { SEC_ASN1_SEQUENCE, 
01911       0, NULL, sizeof(CERTCertificateScopeEntry) },
01912     { SEC_ASN1_ANY,
01913       offsetof(CERTCertificateScopeEntry, derConstraint) },
01914     { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
01915       offsetof(CERTCertificateScopeEntry, derPort) },
01916     { 0 }
01917 };
01918 
01919 static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate[] = {
01920     { SEC_ASN1_SEQUENCE_OF, 0, cert_CertificateScopeEntryTemplate }
01921 };
01922 
01923 #if 0
01924 /* 
01925  * decodes the extension data and create CERTCertificateScopeEntry that can
01926  * be consumed by the code
01927  */
01928 static
01929 SECStatus cert_DecodeScopeOfUseEntries(PRArenaPool* arena, SECItem* extData,
01930                                        CERTCertificateScopeEntry*** entries,
01931                                        int* numEntries)
01932 {
01933     certCertificateScopeOfUse* scope = NULL;
01934     SECStatus rv = SECSuccess;
01935     int i;
01936 
01937     *entries = NULL; /* in case of failure */
01938     *numEntries = 0; /* ditto */
01939 
01940     scope = (certCertificateScopeOfUse*)
01941         PORT_ArenaZAlloc(arena, sizeof(certCertificateScopeOfUse));
01942     if (scope == NULL) {
01943         goto loser;
01944     }
01945 
01946     rv = SEC_ASN1DecodeItem(arena, (void*)scope, 
01947                             cert_CertificateScopeOfUseTemplate, extData);
01948     if (rv != SECSuccess) {
01949         goto loser;
01950     }
01951 
01952     *entries = scope->entries;
01953     PR_ASSERT(*entries != NULL);
01954 
01955     /* first, let's count 'em. */
01956     for (i = 0; (*entries)[i] != NULL; i++) ;
01957     *numEntries = i;
01958 
01959     /* convert certCertificateScopeEntry sequence into what we can readily
01960      * use
01961      */
01962     for (i = 0; i < *numEntries; i++) {
01963         (*entries)[i]->constraint = 
01964             CERT_DecodeGeneralName(arena, &((*entries)[i]->derConstraint), 
01965                                    NULL);
01966         if ((*entries)[i]->derPort.data != NULL) {
01967             (*entries)[i]->port = 
01968                 (int)DER_GetInteger(&((*entries)[i]->derPort));
01969         }
01970         else {
01971             (*entries)[i]->port = 0;
01972         }
01973     }
01974 
01975     goto done;
01976 loser:
01977     if (rv == SECSuccess) {
01978         rv = SECFailure;
01979     }
01980 done:
01981     return rv;
01982 }
01983 
01984 static SECStatus cert_DecodeCertIPAddress(SECItem* genname, 
01985                                           PRUint32* constraint, PRUint32* mask)
01986 {
01987     /* in case of failure */
01988     *constraint = 0;
01989     *mask = 0;
01990 
01991     PR_ASSERT(genname->data != NULL);
01992     if (genname->data == NULL) {
01993         return SECFailure;
01994     }
01995     if (genname->len != 8) {
01996         /* the length must be 4 byte IP address with 4 byte subnet mask */
01997         return SECFailure;
01998     }
01999 
02000     /* get them in the right order */
02001     *constraint = PR_ntohl((PRUint32)(*genname->data));
02002     *mask = PR_ntohl((PRUint32)(*(genname->data + 4)));
02003 
02004     return SECSuccess;
02005 }
02006 
02007 static char* _str_to_lower(char* string)
02008 {
02009 #ifdef XP_WIN
02010     return _strlwr(string);
02011 #else
02012     int i;
02013     for (i = 0; string[i] != '\0'; i++) {
02014         string[i] = tolower(string[i]);
02015     }
02016     return string;
02017 #endif
02018 }
02019 
02020 /*
02021  * Sees if the client certificate has a restriction in presenting the cert
02022  * to the host: returns PR_TRUE if there is no restriction or if the hostname
02023  * (and the port) satisfies the restriction, or PR_FALSE if the hostname (and
02024  * the port) does not satisfy the restriction
02025  */
02026 static PRBool CERT_MatchesScopeOfUse(CERTCertificate* cert, char* hostname,
02027                                      char* hostIP, PRIntn port)
02028 {
02029     PRBool rv = PR_TRUE; /* whether the cert can be presented */
02030     SECStatus srv;
02031     SECItem extData;
02032     PRArenaPool* arena = NULL;
02033     CERTCertificateScopeEntry** entries = NULL;
02034     /* arrays of decoded scope entries */
02035     int numEntries = 0;
02036     int i;
02037     char* hostLower = NULL;
02038     PRUint32 hostIPAddr = 0;
02039 
02040     PR_ASSERT((cert != NULL) && (hostname != NULL) && (hostIP != NULL));
02041 
02042     /* find cert extension */
02043     srv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
02044                                  &extData);
02045     if (srv != SECSuccess) {
02046         /* most of the time, this means the extension was not found: also,
02047          * since this is not a critical extension (as of now) we may simply
02048          * return PR_TRUE
02049          */
02050         goto done;
02051     }
02052 
02053     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02054     if (arena == NULL) {
02055         goto done;
02056     }
02057 
02058     /* decode the scope of use entries into pairs of GeneralNames and
02059      * an optional port numbers
02060      */
02061     srv = cert_DecodeScopeOfUseEntries(arena, &extData, &entries, &numEntries);
02062     if (srv != SECSuccess) {
02063         /* XXX What should we do when we failed to decode the extension?  This
02064          *     may mean either the extension was malformed or some (unlikely)
02065          *     fatal error on our part: my argument is that if the extension 
02066          *     was malformed the extension "disqualifies" as a valid 
02067          *     constraint and we may present the cert
02068          */
02069         goto done;
02070     }
02071 
02072     /* loop over these structures */
02073     for (i = 0; i < numEntries; i++) {
02074         /* determine whether the GeneralName is a DNS pattern, an IP address 
02075          * constraint, or else
02076          */
02077         CERTGeneralName* genname = entries[i]->constraint;
02078 
02079         /* if constraint is NULL, don't bother looking */
02080         if (genname == NULL) {
02081             /* this is not a failure: just continue */
02082             continue;
02083         }
02084 
02085         switch (genname->type) {
02086         case certDNSName: {
02087             /* we have a DNS name constraint; we should use only the host name
02088              * information
02089              */
02090             char* pattern = NULL;
02091             char* substring = NULL;
02092 
02093             /* null-terminate the string */
02094             genname->name.other.data[genname->name.other.len] = '\0';
02095             pattern = _str_to_lower((char*)genname->name.other.data);
02096 
02097             if (hostLower == NULL) {
02098                 /* so that it's done only if necessary and only once */
02099                 hostLower = _str_to_lower(PL_strdup(hostname));
02100             }
02101 
02102             /* the hostname satisfies the constraint */
02103             if (((substring = strstr(hostLower, pattern)) != NULL) &&
02104                 /* the hostname contains the pattern */
02105                 (strlen(substring) == strlen(pattern)) &&
02106                 /* the hostname ends with the pattern */
02107                 ((substring == hostLower) || (*(substring-1) == '.'))) {
02108                 /* the hostname either is identical to the pattern or
02109                  * belongs to a subdomain
02110                  */
02111                 rv = PR_TRUE;
02112             }
02113             else {
02114                 rv = PR_FALSE;
02115             }
02116             /* clean up strings if necessary */
02117             break;
02118         }
02119         case certIPAddress: {
02120             PRUint32 constraint;
02121             PRUint32 mask;
02122             PRNetAddr addr;
02123             
02124             if (hostIPAddr == 0) {
02125                 /* so that it's done only if necessary and only once */
02126                 PR_StringToNetAddr(hostIP, &addr);
02127                 hostIPAddr = addr.inet.ip;
02128             }
02129 
02130             if (cert_DecodeCertIPAddress(&(genname->name.other), &constraint, 
02131                                          &mask) != SECSuccess) {
02132                 continue;
02133             }
02134             if ((hostIPAddr & mask) == (constraint & mask)) {
02135                 rv = PR_TRUE;
02136             }
02137             else {
02138                 rv = PR_FALSE;
02139             }
02140             break;
02141         }
02142         default:
02143             /* ill-formed entry: abort */
02144             continue; /* go to the next entry */
02145         }
02146 
02147         if (!rv) {
02148             /* we do not need to check the port: go to the next entry */
02149             continue;
02150         }
02151 
02152         /* finally, check the optional port number */
02153         if ((entries[i]->port != 0) && (port != entries[i]->port)) {
02154             /* port number does not match */
02155             rv = PR_FALSE;
02156             continue;
02157         }
02158 
02159         /* we have a match */
02160         PR_ASSERT(rv);
02161         break;
02162     }
02163 done:
02164     /* clean up entries */
02165     if (arena != NULL) {
02166         PORT_FreeArena(arena, PR_FALSE);
02167     }
02168     if (hostLower != NULL) {
02169         PR_Free(hostLower);
02170     }
02171     return rv;
02172 }
02173 #endif
02174 
02175 /*
02176  * Function: SSMStatus SSM_SetUserCertChoice()
02177 
02178  * Purpose: sets certChoice by reading the preference
02179  *
02180  * Arguments and return values
02181  * - conn: SSMSSLDataConnection
02182  * - returns: SSM_SUCCESS if successful; SSM_FAILURE otherwise
02183  *
02184  * Note: If done properly, this function will read the identifier strings
02185  *             for ASK and AUTO modes, read the selected strings from the
02186  *             preference, compare the strings, and determine in which mode it is
02187  *             in.
02188  *       We currently use ASK mode for UI apps and AUTO mode for UI-less
02189  *       apps without really asking for preferences.
02190  */
02191 nsresult nsGetUserCertChoice(SSM_UserCertChoice* certChoice)
02192 {
02193        char *mode=NULL;
02194        nsresult ret;
02195 
02196        NS_ENSURE_ARG_POINTER(certChoice);
02197 
02198        nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
02199 
02200        ret = pref->GetCharPref("security.default_personal_cert", &mode);
02201        if (NS_FAILED(ret)) {
02202               goto loser;
02203        }
02204 
02205     if (PL_strcmp(mode, "Select Automatically") == 0) {
02206               *certChoice = AUTO;
02207        }
02208     else if (PL_strcmp(mode, "Ask Every Time") == 0) {
02209         *certChoice = ASK;
02210     }
02211     else {
02212       // Most likely we see a nickname from a migrated cert.
02213       // We do not currently support that, ask the user which cert to use.
02214                 *certChoice = ASK;
02215        }
02216 
02217 loser:
02218        if (mode) {
02219               nsMemory::Free(mode);
02220        }
02221        return ret;
02222 }
02223 
02224 static PRBool hasExplicitKeyUsageNonRepudiation(CERTCertificate *cert)
02225 {
02226   /* There is no extension, v1 or v2 certificate */
02227   if (!cert->extensions)
02228     return PR_FALSE;
02229 
02230   SECStatus srv;
02231   SECItem keyUsageItem;
02232   keyUsageItem.data = NULL;
02233 
02234   srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
02235   if (srv == SECFailure)
02236     return PR_FALSE;
02237 
02238   unsigned char keyUsage = keyUsageItem.data[0];
02239   PORT_Free (keyUsageItem.data);
02240 
02241   return (keyUsage & KU_NON_REPUDIATION);
02242 }
02243 
02244 /*
02245  * Function: SECStatus SSM_SSLGetClientAuthData()
02246  * Purpose: this callback function is used to pull client certificate
02247  *                   information upon server request
02248  *
02249  * Arguments and return values
02250  * - arg: SSL data connection
02251  * - socket: SSL socket we're dealing with
02252  * - caNames: list of CA names
02253  * - pRetCert: returns a pointer to a pointer to a valid certificate if
02254  *                      successful; otherwise NULL
02255  * - pRetKey: returns a pointer to a pointer to the corresponding key if
02256  *                     successful; otherwise NULL
02257  * - returns: SECSuccess if successful; error code otherwise
02258  */
02259 SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
02260                                                            CERTDistNames* caNames,
02261                                                            CERTCertificate** pRetCert,
02262                                                            SECKEYPrivateKey** pRetKey)
02263 {
02264   nsNSSShutDownPreventionLock locker;
02265   void* wincx = NULL;
02266   SECStatus ret = SECFailure;
02267   nsNSSSocketInfo* info = NULL;
02268   PRArenaPool* arena = NULL;
02269   char** caNameStrings;
02270   CERTCertificate* cert = NULL;
02271   SECKEYPrivateKey* privKey = NULL;
02272   CERTCertList* certList = NULL;
02273   CERTCertListNode* node;
02274   CERTCertNicknames* nicknames = NULL;
02275   char* extracted = NULL;
02276   PRIntn keyError = 0; /* used for private key retrieval error */
02277   SSM_UserCertChoice certChoice;
02278   PRUint32 NumberOfCerts = 0;
02279        
02280   /* do some argument checking */
02281   if (socket == NULL || caNames == NULL || pRetCert == NULL ||
02282       pRetKey == NULL) {
02283     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
02284     return SECFailure;
02285   }
02286 
02287   /* get PKCS11 pin argument */
02288   wincx = SSL_RevealPinArg(socket);
02289   if (wincx == NULL) {
02290     return SECFailure;
02291   }
02292 
02293   /* get the socket info */
02294   info = (nsNSSSocketInfo*)socket->higher->secret;
02295 
02296   /* create caNameStrings */
02297   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02298   if (arena == NULL) {
02299     goto loser;
02300   }
02301 
02302   caNameStrings = (char**)PORT_ArenaAlloc(arena, 
02303                                           sizeof(char*)*(caNames->nnames));
02304   if (caNameStrings == NULL) {
02305     goto loser;
02306   }
02307 
02308 
02309   ret = nsConvertCANamesToStrings(arena, caNameStrings, caNames);
02310   if (ret != SECSuccess) {
02311     goto loser;
02312   }
02313 
02314   /* get the preference */
02315   if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
02316     goto loser;
02317   }
02318 
02319   /* find valid user cert and key pair */ 
02320   if (certChoice == AUTO) {
02321     /* automatically find the right cert */
02322 
02323     /* find all user certs that are valid and for SSL */
02324     certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
02325                                          certUsageSSLClient, PR_FALSE,
02326                                          PR_TRUE, wincx);
02327     if (certList == NULL) {
02328       goto noCert;
02329     }
02330 
02331     /* filter the list to those issued by CAs supported by the server */
02332     ret = CERT_FilterCertListByCANames(certList, caNames->nnames,
02333                                        caNameStrings, certUsageSSLClient);
02334     if (ret != SECSuccess) {
02335       goto noCert;
02336     }
02337 
02338     /* make sure the list is not empty */
02339     node = CERT_LIST_HEAD(certList);
02340     if (CERT_LIST_END(node, certList)) {
02341       goto noCert;
02342     }
02343 
02344     CERTCertificate* low_prio_nonrep_cert = NULL;
02345     CERTCertificateCleaner low_prio_cleaner(low_prio_nonrep_cert);
02346 
02347     /* loop through the list until we find a cert with a key */
02348     while (!CERT_LIST_END(node, certList)) {
02349       /* if the certificate has restriction and we do not satisfy it
02350        * we do not use it
02351        */
02352 #if 0         /* XXX This must be re-enabled */
02353       if (!CERT_MatchesScopeOfUse(node->cert, info->GetHostName,
02354                                   info->GetHostIP, info->GetHostPort)) {
02355           node = CERT_LIST_NEXT(node);
02356           continue;
02357       }
02358 #endif
02359 
02360       privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
02361       if (privKey != NULL) {
02362         if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
02363           SECKEY_DestroyPrivateKey(privKey);
02364           privKey = NULL;
02365           // Not a prefered cert
02366           if (!low_prio_nonrep_cert) // did not yet find a low prio cert
02367             low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
02368         }
02369         else {
02370           // this is a good cert to present
02371           cert = CERT_DupCertificate(node->cert);
02372           break;
02373         }
02374       }
02375       keyError = PR_GetError();
02376       if (keyError == SEC_ERROR_BAD_PASSWORD) {
02377           /* problem with password: bail */
02378           goto loser;
02379       }
02380 
02381       node = CERT_LIST_NEXT(node);
02382     }
02383 
02384     if (!cert && low_prio_nonrep_cert) {
02385       cert = low_prio_nonrep_cert;
02386       low_prio_nonrep_cert = NULL; // take it away from the cleaner
02387       privKey = PK11_FindKeyByAnyCert(cert, wincx);
02388     }
02389 
02390     if (cert == NULL) {
02391         goto noCert;
02392     }
02393   }
02394   else { // Not Auto => ask
02395     /* Get the SSL Certificate */
02396     CERTCertificate* serverCert = NULL;
02397     CERTCertificateCleaner serverCertCleaner(serverCert);
02398     serverCert = SSL_PeerCertificate(socket);
02399     if (serverCert == NULL) {
02400       /* couldn't get the server cert: what do I do? */
02401       goto loser;
02402     }
02403 
02404     nsXPIDLCString hostname;
02405     info->GetHostName(getter_Copies(hostname));
02406 
02407     nsresult rv;
02408     NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
02409     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
02410     nsRefPtr<nsClientAuthRememberService> cars;
02411     if (nssComponent) {
02412       nssComponent->GetClientAuthRememberService(getter_AddRefs(cars));
02413     }
02414 
02415     PRBool hasRemembered = PR_FALSE;
02416     nsCString rememberedNickname;
02417     if (cars) {
02418       PRBool found;
02419       nsresult rv = cars->HasRememberedDecision(hostname, 
02420                                                 serverCert,
02421                                                 rememberedNickname, &found);
02422       if (NS_SUCCEEDED(rv) && found) {
02423         hasRemembered = PR_TRUE;
02424       }
02425     }
02426 
02427     PRBool canceled = PR_FALSE;
02428 
02429 if (hasRemembered)
02430 {
02431   if (rememberedNickname.IsEmpty())
02432     canceled = PR_TRUE;
02433   else {
02434     char *const_nickname = const_cast<char*>(rememberedNickname.get());
02435     cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), const_nickname);
02436   }
02437 }
02438 else
02439 {
02440     /* user selects a cert to present */
02441     nsIClientAuthDialogs *dialogs = NULL;
02442     PRInt32 selectedIndex = -1;
02443     PRUnichar **certNicknameList = NULL;
02444     PRUnichar **certDetailsList = NULL;
02445 
02446     /* find all user certs that are for SSL */
02447     /* note that we are allowing expired certs in this list */
02448     certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), 
02449                                          certUsageSSLClient, PR_FALSE, 
02450                                          PR_FALSE, wincx);
02451     if (certList == NULL) {
02452       goto noCert;
02453     }
02454 
02455     if (caNames->nnames != 0) {
02456       /* filter the list to those issued by CAs supported by the 
02457        * server 
02458        */
02459       ret = CERT_FilterCertListByCANames(certList, caNames->nnames, 
02460                                         caNameStrings, 
02461                                         certUsageSSLClient);
02462       if (ret != SECSuccess) {
02463         goto loser;
02464       }
02465     }
02466 
02467     if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
02468       /* list is empty - no matching certs */
02469       goto noCert;
02470     }
02471 
02472     /* filter it further for hostname restriction */
02473     node = CERT_LIST_HEAD(certList);
02474     while (!CERT_LIST_END(node, certList)) {
02475       ++NumberOfCerts;
02476 #if 0 /* XXX Fix this */
02477       if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
02478                                   conn->hostIP, conn->port)) {
02479         CERTCertListNode* removed = node;
02480         node = CERT_LIST_NEXT(removed);
02481         CERT_RemoveCertListNode(removed);
02482       }
02483       else {
02484         node = CERT_LIST_NEXT(node);
02485       }
02486 #endif
02487       node = CERT_LIST_NEXT(node);
02488     }
02489     if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
02490       goto noCert;
02491     }
02492 
02493     nicknames = getNSSCertNicknamesFromCertList(certList);
02494 
02495     if (nicknames == NULL) {
02496       goto loser;
02497     }
02498 
02499     NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
02500 
02501     /* Get CN and O of the subject and O of the issuer */
02502     char *ccn = CERT_GetCommonName(&serverCert->subject);
02503     NS_ConvertUTF8toUCS2 cn(ccn);
02504     if (ccn) PORT_Free(ccn);
02505 
02506     char *corg = CERT_GetOrgName(&serverCert->subject);
02507     NS_ConvertUTF8toUCS2 org(corg);
02508     if (corg) PORT_Free(corg);
02509 
02510     char *cissuer = CERT_GetOrgName(&serverCert->issuer);
02511     NS_ConvertUTF8toUCS2 issuer(cissuer);
02512     if (cissuer) PORT_Free(cissuer);
02513 
02514     certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
02515     if (!certNicknameList)
02516       goto loser;
02517     certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
02518     if (!certDetailsList) {
02519       nsMemory::Free(certNicknameList);
02520       goto loser;
02521     }
02522 
02523     PRInt32 CertsToUse;
02524     for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
02525          !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
02526          node = CERT_LIST_NEXT(node)
02527         )
02528     {
02529       nsRefPtr<nsNSSCertificate> tempCert = new nsNSSCertificate(node->cert);
02530 
02531       if (!tempCert)
02532         continue;
02533       
02534       NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
02535       nsAutoString nickWithSerial, details;
02536       
02537       if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
02538         continue;
02539 
02540       if (hasExplicitKeyUsageNonRepudiation(node->cert))
02541         nickWithSerial.Append(NS_LITERAL_STRING(" [NR]"));
02542 
02543       certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
02544       if (!certNicknameList[CertsToUse])
02545         continue;
02546       certDetailsList[CertsToUse] = ToNewUnicode(details);
02547       if (!certDetailsList[CertsToUse]) {
02548         nsMemory::Free(certNicknameList[CertsToUse]);
02549         continue;
02550       }
02551 
02552       ++CertsToUse;
02553     }
02554 
02555     /* Throw up the client auth dialog and get back the index of the selected cert */
02556     rv = getNSSDialogs((void**)&dialogs, 
02557                        NS_GET_IID(nsIClientAuthDialogs),
02558                        NS_CLIENTAUTHDIALOGS_CONTRACTID);
02559 
02560     if (NS_FAILED(rv)) {
02561       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
02562       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
02563       goto loser;
02564     }
02565 
02566     {
02567       nsPSMUITracker tracker;
02568       if (tracker.isUIForbidden()) {
02569         rv = NS_ERROR_NOT_AVAILABLE;
02570       }
02571       else {
02572         rv = dialogs->ChooseCertificate(info, cn.get(), org.get(), issuer.get(), 
02573           (const PRUnichar**)certNicknameList, (const PRUnichar**)certDetailsList,
02574           CertsToUse, &selectedIndex, &canceled);
02575       }
02576     }
02577 
02578     NS_RELEASE(dialogs);
02579     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
02580     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
02581     
02582     if (NS_FAILED(rv)) goto loser;
02583 
02584     // even if the user has canceled, we want to remember that, to avoid repeating prompts
02585     PRBool wantRemember = PR_FALSE;
02586     info->GetRememberClientAuthCertificate(&wantRemember);
02587 
02588     int i;
02589     if (!canceled)
02590     for (i = 0, node = CERT_LIST_HEAD(certList);
02591          !CERT_LIST_END(node, certList);
02592          ++i, node = CERT_LIST_NEXT(node)) {
02593 
02594       if (i == selectedIndex) {
02595         cert = CERT_DupCertificate(node->cert);
02596         break;
02597       }
02598     }
02599 
02600     if (cars && wantRemember) {
02601       cars->RememberDecision(hostname, 
02602                              serverCert, 
02603                              canceled ? 0 : cert);
02604     }
02605 }
02606 
02607     if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
02608 
02609     if (cert == NULL) {
02610       goto loser;
02611     }
02612 
02613     /* go get the private key */
02614     privKey = PK11_FindKeyByAnyCert(cert, wincx);
02615     if (privKey == NULL) {
02616       keyError = PR_GetError();
02617       if (keyError == SEC_ERROR_BAD_PASSWORD) {
02618           /* problem with password: bail */
02619           goto loser;
02620       }
02621       else {
02622           goto noCert;
02623       }
02624     }
02625   }
02626   goto done;
02627 
02628 noCert:
02629 loser:
02630   if (ret == SECSuccess) {
02631     ret = SECFailure;
02632   }
02633   if (cert != NULL) {
02634     CERT_DestroyCertificate(cert);
02635     cert = NULL;
02636   }
02637 done:
02638   if (extracted != NULL) {
02639     PR_Free(extracted);
02640   }
02641   if (nicknames != NULL) {
02642     CERT_FreeNicknames(nicknames);
02643   }
02644   if (certList != NULL) {
02645     CERT_DestroyCertList(certList);
02646   }
02647   if (arena != NULL) {
02648     PORT_FreeArena(arena, PR_FALSE);
02649   }
02650 
02651   *pRetCert = cert;
02652   *pRetKey = privKey;
02653 
02654   return ret;
02655 }
02656 
02657 static SECStatus
02658 nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
02659 {
02660   nsNSSShutDownPreventionLock locker;
02661   SECStatus rv = SECFailure;
02662   int error;
02663   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo *)arg;
02664   CERTCertificate *peerCert;
02665   nsNSSCertificate *nssCert;
02666 
02667   error = PR_GetError();
02668   peerCert = SSL_PeerCertificate(sslSocket);
02669   nssCert = new nsNSSCertificate(peerCert);
02670   if (!nssCert) {
02671     return SECFailure;
02672   } 
02673   NS_ADDREF(nssCert);
02674   infoObject->SetBadCertUIStatus(nsNSSSocketInfo::bcuis_active);
02675   while (rv != SECSuccess) {
02676      //Func nsContinueDespiteCertError does the same set of checks as func.
02677      //nsCertErrorNeedsDialog. So, removing call to nsCertErrorNeedsDialog
02678      if (!nsContinueDespiteCertError(infoObject, sslSocket, 
02679                                     error, nssCert)) {
02680       break;
02681     }
02682     rv = verifyCertAgain(peerCert, sslSocket, infoObject);
02683        error = PR_GetError();
02684   }
02685   infoObject->SetBadCertUIStatus(nsNSSSocketInfo::bcuis_was_shown);
02686   NS_RELEASE(nssCert);
02687   CERT_DestroyCertificate(peerCert); 
02688   if (rv != SECSuccess) {
02689     // if the cert is bad, we don't want to connect
02690     infoObject->SetCanceled(PR_TRUE);
02691   }
02692   return rv;
02693 }
02694 
02695 static PRFileDesc*
02696 nsSSLIOLayerImportFD(PRFileDesc *fd,
02697                      nsNSSSocketInfo *infoObject,
02698                      const char *host)
02699 {
02700   nsNSSShutDownPreventionLock locker;
02701   PRFileDesc* sslSock = SSL_ImportFD(nsnull, fd);
02702   if (!sslSock) {
02703     NS_ASSERTION(PR_FALSE, "NSS: Error importing socket");
02704     return nsnull;
02705   }
02706   SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
02707   SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
02708   SSL_GetClientAuthDataHook(sslSock, 
02709                             (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData,
02710                             infoObject);
02711   SSL_AuthCertificateHook(sslSock, AuthCertificateCallback, 0);
02712 
02713   PRInt32 ret = SSL_SetURL(sslSock, host);
02714   if (ret == -1) {
02715     NS_ASSERTION(PR_FALSE, "NSS: Error setting server name");
02716     goto loser;
02717   }
02718   return sslSock;
02719 loser:
02720   if (sslSock) {
02721     PR_Close(sslSock);
02722   }
02723   return nsnull;
02724 }
02725 
02726 static nsresult
02727 nsSSLIOLayerSetOptions(PRFileDesc *fd, PRBool forSTARTTLS, 
02728                        const char *proxyHost, const char *host, PRInt32 port,
02729                        nsNSSSocketInfo *infoObject)
02730 {
02731   nsNSSShutDownPreventionLock locker;
02732   if (forSTARTTLS || proxyHost) {
02733     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, PR_FALSE)) {
02734       return NS_ERROR_FAILURE;
02735     }
02736     infoObject->SetHasCleartextPhase(PR_TRUE);
02737   }
02738 
02739   if (forSTARTTLS) {
02740     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_SSL2, PR_FALSE)) {
02741       return NS_ERROR_FAILURE;
02742     }
02743     if (SECSuccess != SSL_OptionSet(fd, SSL_V2_COMPATIBLE_HELLO, PR_FALSE)) {
02744       return NS_ERROR_FAILURE;
02745     }
02746   }
02747 
02748   // Let's see if we're trying to connect to a site we know is
02749   // TLS intolerant.
02750   nsCAutoString key;
02751   key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
02752 
02753   if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key)) {
02754     if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, PR_FALSE))
02755       return NS_ERROR_FAILURE;
02756 
02757     infoObject->SetAllowTLSIntoleranceTimeout(PR_FALSE);
02758       
02759     // We assume that protocols that use the STARTTLS mechanism should support
02760     // modern hellos. For other protocols, if we suspect a site 
02761     // does not support TLS, let's also use V2 hellos.
02762     // One advantage of this approach, if a site only supports the older
02763     // hellos, it is more likely that we will get a reasonable error code
02764     // on our single retry attempt.
02765     
02766     if (!forSTARTTLS &&
02767         SECSuccess != SSL_OptionSet(fd, SSL_V2_COMPATIBLE_HELLO, PR_TRUE))
02768       return NS_ERROR_FAILURE;
02769   }
02770 
02771   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE)) {
02772     return NS_ERROR_FAILURE;
02773   }
02774   if (SECSuccess != SSL_BadCertHook(fd, (SSLBadCertHandler) nsNSSBadCertHandler,
02775                                     infoObject)) {
02776     return NS_ERROR_FAILURE;
02777   }
02778 
02779   // Set the Peer ID so that SSL proxy connections work properly.
02780   char *peerId = PR_smprintf("%s:%d", host, port);
02781   if (SECSuccess != SSL_SetSockPeerID(fd, peerId)) {
02782     PR_smprintf_free(peerId);
02783     return NS_ERROR_FAILURE;
02784   }
02785 
02786   PR_smprintf_free(peerId);
02787   return NS_OK;
02788 }
02789 
02790 nsresult
02791 nsSSLIOLayerAddToSocket(PRInt32 family,
02792                         const char* host,
02793                         PRInt32 port,
02794                         const char* proxyHost,
02795                         PRInt32 proxyPort,
02796                         PRFileDesc* fd,
02797                         nsISupports** info,
02798                         PRBool forSTARTTLS)
02799 {
02800   nsNSSShutDownPreventionLock locker;
02801   PRFileDesc* layer = nsnull;
02802   nsresult rv;
02803 
02804   nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
02805   if (!infoObject) return NS_ERROR_FAILURE;
02806   
02807   NS_ADDREF(infoObject);
02808   infoObject->SetForSTARTTLS(forSTARTTLS);
02809   infoObject->SetHostName(host);
02810   infoObject->SetPort(port);
02811 
02812   PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
02813   if (!sslSock) {
02814     NS_ASSERTION(PR_FALSE, "NSS: Error importing socket");
02815     goto loser;
02816   }
02817 
02818   infoObject->SetFileDescPtr(sslSock);
02819 
02820   rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, proxyHost, host, port,
02821                               infoObject);
02822 
02823   if (NS_FAILED(rv))
02824     goto loser;
02825 
02826   /* Now, layer ourselves on top of the SSL socket... */
02827   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
02828                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
02829   if (!layer)
02830     goto loser;
02831   
02832   layer->secret = (PRFilePrivate*) infoObject;
02833   rv = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
02834   
02835   if (NS_FAILED(rv)) {
02836     goto loser;
02837   }
02838   
02839   nsNSSShutDownList::trackSSLSocketCreate();
02840 
02841   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*)sslSock));
02842   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
02843 
02844   // We are going use a clear connection first //
02845   if (forSTARTTLS || proxyHost) {
02846     infoObject->SetHandshakePending(PR_FALSE);
02847   }
02848 
02849   return NS_OK;
02850  loser:
02851   NS_IF_RELEASE(infoObject);
02852   if (layer) {
02853     layer->dtor(layer);
02854   }
02855   return NS_ERROR_FAILURE;
02856 }