PageRenderTime 218ms CodeModel.GetById 10ms app.highlight 183ms RepoModel.GetById 1ms app.codeStats 1ms

/security/manager/ssl/src/nsNSSIOLayer.cpp

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