PageRenderTime 138ms CodeModel.GetById 18ms app.highlight 105ms 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

Large files files are truncated, but you can click here to view the full 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 b

Large files files are truncated, but you can click here to view the full file