PageRenderTime 124ms CodeModel.GetById 21ms app.highlight 88ms RepoModel.GetById 1ms app.codeStats 2ms

/security/manager/ssl/src/nsNSSComponent.cpp

http://github.com/zpao/v8monkey
C++ | 3481 lines | 2587 code | 585 blank | 309 comment | 453 complexity | 66116bc7232cc97e1ff3ed29287b7653 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 *   Hubbie Shaw
  25 *   Doug Turner <dougt@netscape.com>
  26 *   Mitch Stoltz <mstoltz@netscape.com>
  27 *   Brian Ryner <bryner@brianryner.com>
  28 *   Kai Engert <kaie@netscape.com>
  29 *   Vipul Gupta <vipul.gupta@sun.com>
  30 *   Douglas Stebila <douglas@stebila.ca>
  31 *   Kai Engert <kengert@redhat.com>
  32 *
  33 * Alternatively, the contents of this file may be used under the terms of
  34 * either the GNU General Public License Version 2 or later (the "GPL"), or
  35 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  36 * in which case the provisions of the GPL or the LGPL are applicable instead
  37 * of those above. If you wish to allow use of your version of this file only
  38 * under the terms of either the GPL or the LGPL, and not to allow others to
  39 * use your version of this file under the terms of the MPL, indicate your
  40 * decision by deleting the provisions above and replace them with the notice
  41 * and other provisions required by the GPL or the LGPL. If you do not delete
  42 * the provisions above, a recipient may use your version of this file under
  43 * the terms of any one of the MPL, the GPL or the LGPL.
  44 *
  45 * ***** END LICENSE BLOCK ***** */
  46
  47#include "nsNSSComponent.h"
  48#include "nsNSSCallbacks.h"
  49#include "nsNSSIOLayer.h"
  50#include "nsCertVerificationThread.h"
  51
  52#include "nsNetUtil.h"
  53#include "nsAppDirectoryServiceDefs.h"
  54#include "nsDirectoryService.h"
  55#include "nsIStreamListener.h"
  56#include "nsIStringBundle.h"
  57#include "nsIDirectoryService.h"
  58#include "nsIDOMNode.h"
  59#include "nsCURILoader.h"
  60#include "nsDirectoryServiceDefs.h"
  61#include "nsIX509Cert.h"
  62#include "nsIX509CertDB.h"
  63#include "nsIProfileChangeStatus.h"
  64#include "nsNSSCertificate.h"
  65#include "nsNSSHelper.h"
  66#include "nsSmartCardMonitor.h"
  67#include "prlog.h"
  68#include "nsIPrefService.h"
  69#include "nsIPrefBranch.h"
  70#include "nsIDateTimeFormat.h"
  71#include "nsDateTimeFormatCID.h"
  72#include "nsIDOMEvent.h"
  73#include "nsIDOMDocument.h"
  74#include "nsIDOMWindow.h"
  75#include "nsIDOMWindowCollection.h"
  76#include "nsIDOMSmartCardEvent.h"
  77#include "nsIDOMCrypto.h"
  78#include "nsThreadUtils.h"
  79#include "nsAutoPtr.h"
  80#include "nsCRT.h"
  81#include "nsCRLInfo.h"
  82#include "nsCertOverrideService.h"
  83
  84#include "nsIWindowWatcher.h"
  85#include "nsIPrompt.h"
  86#include "nsIPrincipal.h"
  87#include "nsReadableUtils.h"
  88#include "nsIDateTimeFormat.h"
  89#include "prtypes.h"
  90#include "nsIEntropyCollector.h"
  91#include "nsIBufEntropyCollector.h"
  92#include "nsIServiceManager.h"
  93#include "nsILocalFile.h"
  94#include "nsITokenPasswordDialogs.h"
  95#include "nsICRLManager.h"
  96#include "nsNSSShutDown.h"
  97#include "nsSmartCardEvent.h"
  98#include "nsIKeyModule.h"
  99
 100#include "nss.h"
 101#include "pk11func.h"
 102#include "ssl.h"
 103#include "sslproto.h"
 104#include "secmod.h"
 105#include "sechash.h"
 106#include "secmime.h"
 107#include "ocsp.h"
 108#include "cms.h"
 109#include "nssckbi.h"
 110#include "base64.h"
 111#include "secerr.h"
 112#include "sslerr.h"
 113#include "cert.h"
 114
 115#include "nsXULAppAPI.h"
 116
 117#ifdef XP_WIN
 118#include "nsILocalFileWin.h"
 119#endif
 120
 121extern "C" {
 122#include "pkcs12.h"
 123#include "p12plcy.h"
 124}
 125
 126using namespace mozilla;
 127
 128#ifdef PR_LOGGING
 129PRLogModuleInfo* gPIPNSSLog = nsnull;
 130#endif
 131
 132#define NS_CRYPTO_HASH_BUFFER_SIZE 4096
 133
 134static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 135int nsNSSComponent::mInstanceCount = 0;
 136bool nsNSSComponent::globalConstFlagUsePKIXVerification = false;
 137
 138// XXX tmp callback for slot password
 139extern char * PR_CALLBACK 
 140pk11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void *arg);
 141
 142#define PIPNSS_STRBUNDLE_URL "chrome://pipnss/locale/pipnss.properties"
 143#define NSSERR_STRBUNDLE_URL "chrome://pipnss/locale/nsserrors.properties"
 144
 145static PLHashNumber PR_CALLBACK certHashtable_keyHash(const void *key)
 146{
 147  if (!key)
 148    return 0;
 149  
 150  SECItem *certKey = (SECItem*)key;
 151  
 152  // lazy hash function, sum up all char values of SECItem
 153  
 154  PLHashNumber hash = 0;
 155  unsigned int i = 0;
 156  unsigned char *c = certKey->data;
 157  
 158  for (i = 0; i < certKey->len; ++i, ++c) {
 159    hash += *c;
 160  }
 161  
 162  return hash;
 163}
 164
 165static PRIntn PR_CALLBACK certHashtable_keyCompare(const void *k1, const void *k2)
 166{
 167  // return type is a bool, answering the question "are the keys equal?"
 168
 169  if (!k1 || !k2)
 170    return false;
 171  
 172  SECItem *certKey1 = (SECItem*)k1;
 173  SECItem *certKey2 = (SECItem*)k2;
 174  
 175  if (certKey1->len != certKey2->len) {
 176    return false;
 177  }
 178  
 179  unsigned int i = 0;
 180  unsigned char *c1 = certKey1->data;
 181  unsigned char *c2 = certKey2->data;
 182  
 183  for (i = 0; i < certKey1->len; ++i, ++c1, ++c2) {
 184    if (*c1 != *c2) {
 185      return false;
 186    }
 187  }
 188  
 189  return true;
 190}
 191
 192static PRIntn PR_CALLBACK certHashtable_valueCompare(const void *v1, const void *v2)
 193{
 194  // two values are identical if their keys are identical
 195  
 196  if (!v1 || !v2)
 197    return false;
 198  
 199  CERTCertificate *cert1 = (CERTCertificate*)v1;
 200  CERTCertificate *cert2 = (CERTCertificate*)v2;
 201  
 202  return certHashtable_keyCompare(&cert1->certKey, &cert2->certKey);
 203}
 204
 205static PRIntn PR_CALLBACK certHashtable_clearEntry(PLHashEntry *he, PRIntn /*index*/, void * /*userdata*/)
 206{
 207  if (he && he->value) {
 208    CERT_DestroyCertificate((CERTCertificate*)he->value);
 209  }
 210  
 211  return HT_ENUMERATE_NEXT;
 212}
 213
 214class CRLDownloadEvent : public nsRunnable {
 215public:
 216  CRLDownloadEvent(const nsCSubstring &urlString, nsIStreamListener *listener)
 217    : mURLString(urlString)
 218    , mListener(listener)
 219  {}
 220
 221  // Note that nsNSSComponent is a singleton object across all threads, 
 222  // and automatic downloads are always scheduled sequentially - that is, 
 223  // once one crl download is complete, the next one is scheduled
 224  NS_IMETHOD Run()
 225  {
 226    if (!mListener || mURLString.IsEmpty())
 227      return NS_OK;
 228
 229    nsCOMPtr<nsIURI> uri;
 230    nsresult rv = NS_NewURI(getter_AddRefs(uri), mURLString);
 231    if (NS_SUCCEEDED(rv)){
 232      NS_OpenURI(mListener, nsnull, uri);
 233    }
 234
 235    return NS_OK;
 236  }
 237
 238private:
 239  nsCString mURLString;
 240  nsCOMPtr<nsIStreamListener> mListener;
 241};
 242
 243//This class is used to run the callback code
 244//passed to the event handlers for smart card notification
 245class nsTokenEventRunnable : public nsIRunnable {
 246public:
 247  nsTokenEventRunnable(const nsAString &aType, const nsAString &aTokenName);
 248  virtual ~nsTokenEventRunnable();
 249
 250  NS_IMETHOD Run ();
 251  NS_DECL_ISUPPORTS
 252private:
 253  nsString mType;
 254  nsString mTokenName;
 255};
 256
 257// ISuuports implementation for nsTokenEventRunnable
 258NS_IMPL_THREADSAFE_ISUPPORTS1(nsTokenEventRunnable, nsIRunnable)
 259
 260nsTokenEventRunnable::nsTokenEventRunnable(const nsAString &aType, 
 261   const nsAString &aTokenName): mType(aType), mTokenName(aTokenName) { }
 262
 263nsTokenEventRunnable::~nsTokenEventRunnable() { }
 264
 265//Implementation that runs the callback passed to 
 266//crypto.generateCRMFRequest as an event.
 267NS_IMETHODIMP
 268nsTokenEventRunnable::Run()
 269{ 
 270  nsresult rv;
 271  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
 272  if (NS_FAILED(rv))
 273    return rv;
 274
 275  return nssComponent->DispatchEvent(mType, mTokenName);
 276}
 277
 278bool nsPSMInitPanic::isPanic = false;
 279
 280// We must ensure that the nsNSSComponent has been loaded before
 281// creating any other components.
 282bool EnsureNSSInitialized(EnsureNSSOperator op)
 283{
 284  if (nsPSMInitPanic::GetPanic())
 285    return false;
 286
 287  if (GeckoProcessType_Default != XRE_GetProcessType())
 288  {
 289    if (op == nssEnsureOnChromeOnly)
 290    {
 291      // If the component needs PSM/NSS initialized only on the chrome process,
 292      // pretend we successfully initiated it but in reality we bypass it.
 293      // It's up to the programmer to check for process type in such components
 294      // and take care not to call anything that needs NSS/PSM initiated.
 295      return true;
 296    }
 297
 298    NS_ERROR("Trying to initialize PSM/NSS in a non-chrome process!");
 299    return false;
 300  }
 301
 302  static bool loading = false;
 303  static PRInt32 haveLoaded = 0;
 304
 305  switch (op)
 306  {
 307    // In following 4 cases we are protected by monitor of XPCOM component
 308    // manager - we are inside of do_GetService call for nss component, so it is
 309    // safe to move with the flags here.
 310  case nssLoadingComponent:
 311    if (loading)
 312      return false; // We are reentered during nss component creation
 313    loading = true;
 314    return true;
 315
 316  case nssInitSucceeded:
 317    NS_ASSERTION(loading, "Bad call to EnsureNSSInitialized(nssInitSucceeded)");
 318    loading = false;
 319    PR_AtomicSet(&haveLoaded, 1);
 320    return true;
 321
 322  case nssInitFailed:
 323    NS_ASSERTION(loading, "Bad call to EnsureNSSInitialized(nssInitFailed)");
 324    loading = false;
 325    // no break
 326
 327  case nssShutdown:
 328    PR_AtomicSet(&haveLoaded, 0);
 329    return false;
 330
 331    // In this case we are called from a component to ensure nss initilization.
 332    // If the component has not yet been loaded and is not currently loading
 333    // call do_GetService for nss component to ensure it.
 334  case nssEnsure:
 335  case nssEnsureOnChromeOnly:
 336    // We are reentered during nss component creation or nss component is already up
 337    if (PR_AtomicAdd(&haveLoaded, 0) || loading)
 338      return true;
 339
 340    {
 341    nsCOMPtr<nsINSSComponent> nssComponent
 342      = do_GetService(PSM_COMPONENT_CONTRACTID);
 343
 344    // Nss component failed to initialize, inform the caller of that fact.
 345    // Flags are appropriately set by component constructor itself.
 346    if (!nssComponent)
 347      return false;
 348
 349    bool isInitialized;
 350    nsresult rv = nssComponent->IsNSSInitialized(&isInitialized);
 351    return NS_SUCCEEDED(rv) && isInitialized;
 352    }
 353
 354  default:
 355    NS_ASSERTION(false, "Bad operator to EnsureNSSInitialized");
 356    return false;
 357  }
 358}
 359
 360nsNSSComponent::nsNSSComponent()
 361  :mutex("nsNSSComponent.mutex"),
 362   mNSSInitialized(false),
 363   mCrlTimerLock("nsNSSComponent.mCrlTimerLock"),
 364   mThreadList(nsnull),
 365   mCertVerificationThread(NULL)
 366{
 367#ifdef PR_LOGGING
 368  if (!gPIPNSSLog)
 369    gPIPNSSLog = PR_NewLogModule("pipnss");
 370#endif
 371  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::ctor\n"));
 372  mUpdateTimerInitialized = false;
 373  crlDownloadTimerOn = false;
 374  crlsScheduledForDownload = nsnull;
 375  mTimer = nsnull;
 376  mObserversRegistered = false;
 377
 378  // In order to keep startup time lower, we delay loading and 
 379  // registering all identity data until first needed.
 380  memset(&mIdentityInfoCallOnce, 0, sizeof(PRCallOnceType));
 381
 382  NS_ASSERTION( (0 == mInstanceCount), "nsNSSComponent is a singleton, but instantiated multiple times!");
 383  ++mInstanceCount;
 384  hashTableCerts = nsnull;
 385  mShutdownObjectList = nsNSSShutDownList::construct();
 386  mIsNetworkDown = false;
 387}
 388
 389void 
 390nsNSSComponent::deleteBackgroundThreads()
 391{
 392  if (mCertVerificationThread)
 393  {
 394    mCertVerificationThread->requestExit();
 395    delete mCertVerificationThread;
 396    mCertVerificationThread = nsnull;
 397  }
 398}
 399
 400void
 401nsNSSComponent::createBackgroundThreads()
 402{
 403  NS_ASSERTION(mCertVerificationThread == nsnull,
 404               "Cert verification thread already created.");
 405
 406  mCertVerificationThread = new nsCertVerificationThread;
 407  nsresult rv = mCertVerificationThread->startThread();
 408  if (NS_FAILED(rv)) {
 409    delete mCertVerificationThread;
 410    mCertVerificationThread = nsnull;
 411  }
 412}
 413
 414nsNSSComponent::~nsNSSComponent()
 415{
 416  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor\n"));
 417
 418  deleteBackgroundThreads();
 419
 420  if (mUpdateTimerInitialized) {
 421    {
 422      MutexAutoLock lock(mCrlTimerLock);
 423      if (crlDownloadTimerOn) {
 424        mTimer->Cancel();
 425      }
 426      crlDownloadTimerOn = false;
 427    }
 428    if(crlsScheduledForDownload != nsnull){
 429      crlsScheduledForDownload->Reset();
 430      delete crlsScheduledForDownload;
 431    }
 432
 433    mUpdateTimerInitialized = false;
 434  }
 435
 436  // All cleanup code requiring services needs to happen in xpcom_shutdown
 437
 438  ShutdownNSS();
 439  nsSSLIOLayerHelpers::Cleanup();
 440  --mInstanceCount;
 441  delete mShutdownObjectList;
 442
 443  // We are being freed, drop the haveLoaded flag to re-enable
 444  // potential nss initialization later.
 445  EnsureNSSInitialized(nssShutdown);
 446
 447  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor finished\n"));
 448}
 449
 450NS_IMETHODIMP
 451nsNSSComponent::PostEvent(const nsAString &eventType, 
 452                                                  const nsAString &tokenName)
 453{
 454  nsCOMPtr<nsIRunnable> runnable = 
 455                               new nsTokenEventRunnable(eventType, tokenName);
 456  if (!runnable) {
 457    return NS_ERROR_OUT_OF_MEMORY;
 458  }
 459
 460  return NS_DispatchToMainThread(runnable);
 461}
 462
 463
 464NS_IMETHODIMP
 465nsNSSComponent::DispatchEvent(const nsAString &eventType,
 466                                                 const nsAString &tokenName)
 467{
 468  // 'Dispatch' the event to all the windows. 'DispatchEventToWindow()' will
 469  // first check to see if a given window has requested crypto events.
 470  nsresult rv;
 471  nsCOMPtr<nsIWindowWatcher> windowWatcher =
 472                            do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
 473
 474  if (NS_FAILED(rv)) {
 475    return rv;
 476  }
 477
 478  nsCOMPtr<nsISimpleEnumerator> enumerator;
 479  rv = windowWatcher->GetWindowEnumerator(getter_AddRefs(enumerator));
 480  if (NS_FAILED(rv)) {
 481    return rv;
 482  }
 483
 484  bool hasMoreWindows;
 485
 486  while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreWindows))
 487         && hasMoreWindows) {
 488    nsCOMPtr<nsISupports> supports;
 489    enumerator->GetNext(getter_AddRefs(supports));
 490    nsCOMPtr<nsIDOMWindow> domWin(do_QueryInterface(supports));
 491    if (domWin) {
 492      nsresult rv2 = DispatchEventToWindow(domWin, eventType, tokenName);
 493      if (NS_FAILED(rv2)) {
 494        // return the last failure, don't let a single failure prevent
 495        // continued delivery of events.
 496        rv = rv2;
 497      }
 498    }
 499  }
 500  return rv;
 501}
 502
 503nsresult
 504nsNSSComponent::DispatchEventToWindow(nsIDOMWindow *domWin,
 505                      const nsAString &eventType, const nsAString &tokenName)
 506{
 507  // first walk the children and dispatch their events 
 508  {
 509    nsresult rv;
 510    nsCOMPtr<nsIDOMWindowCollection> frames;
 511    rv = domWin->GetFrames(getter_AddRefs(frames));
 512    if (NS_FAILED(rv)) {
 513      return rv;
 514    }
 515
 516    PRUint32 length;
 517    frames->GetLength(&length);
 518    PRUint32 i;
 519    for (i = 0; i < length; i++) {
 520      nsCOMPtr<nsIDOMWindow> childWin;
 521      frames->Item(i, getter_AddRefs(childWin));
 522      DispatchEventToWindow(childWin, eventType, tokenName);
 523    }
 524  }
 525
 526  // check if we've enabled smart card events on this window
 527  // NOTE: it's not an error to say that we aren't going to dispatch
 528  // the event.
 529  {
 530    nsCOMPtr<nsIDOMWindow> domWindow = domWin;
 531    if (!domWindow) {
 532      return NS_OK; // nope, it's not an internal window
 533    }
 534
 535    nsCOMPtr<nsIDOMCrypto> crypto;
 536    domWindow->GetCrypto(getter_AddRefs(crypto));
 537    if (!crypto) {
 538      return NS_OK; // nope, it doesn't have a crypto property
 539    }
 540
 541    bool boolrv;
 542    crypto->GetEnableSmartCardEvents(&boolrv);
 543    if (!boolrv) {
 544      return NS_OK; // nope, it's not enabled.
 545    }
 546  }
 547
 548  // dispatch the event ...
 549
 550  nsresult rv;
 551  // find the document
 552  nsCOMPtr<nsIDOMDocument> doc;
 553  rv = domWin->GetDocument(getter_AddRefs(doc));
 554  if (doc == nsnull) {
 555    return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
 556  }
 557
 558  // create the event
 559  nsCOMPtr<nsIDOMEvent> event;
 560  rv = doc->CreateEvent(NS_LITERAL_STRING("Events"), 
 561                        getter_AddRefs(event));
 562  if (NS_FAILED(rv)) {
 563    return rv;
 564  }
 565
 566  event->InitEvent(eventType, false, true);
 567
 568  // create the Smart Card Event;
 569  nsCOMPtr<nsIDOMSmartCardEvent> smartCardEvent = 
 570                                          new nsSmartCardEvent(tokenName);
 571  // init the smart card event, fail here if we can't complete the 
 572  // initialization.
 573  if (!smartCardEvent) {
 574    return NS_ERROR_OUT_OF_MEMORY;
 575  }
 576
 577  rv = smartCardEvent->Init(event);
 578  if (NS_FAILED(rv)) {
 579    return rv;
 580  }
 581
 582  // Send it 
 583  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(doc, &rv);
 584  if (NS_FAILED(rv)) {
 585    return rv;
 586  }
 587
 588  bool boolrv;
 589  rv = target->DispatchEvent(smartCardEvent, &boolrv);
 590  return rv;
 591}
 592
 593
 594NS_IMETHODIMP
 595nsNSSComponent::PIPBundleFormatStringFromName(const char *name,
 596                                              const PRUnichar **params,
 597                                              PRUint32 numParams,
 598                                              nsAString &outString)
 599{
 600  nsresult rv = NS_ERROR_FAILURE;
 601
 602  if (mPIPNSSBundle && name) {
 603    nsXPIDLString result;
 604    rv = mPIPNSSBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(name).get(),
 605                                             params, numParams,
 606                                             getter_Copies(result));
 607    if (NS_SUCCEEDED(rv)) {
 608      outString = result;
 609    }
 610  }
 611  return rv;
 612}
 613
 614NS_IMETHODIMP
 615nsNSSComponent::GetPIPNSSBundleString(const char *name,
 616                                      nsAString &outString)
 617{
 618  nsresult rv = NS_ERROR_FAILURE;
 619
 620  outString.SetLength(0);
 621  if (mPIPNSSBundle && name) {
 622    nsXPIDLString result;
 623    rv = mPIPNSSBundle->GetStringFromName(NS_ConvertASCIItoUTF16(name).get(),
 624                                          getter_Copies(result));
 625    if (NS_SUCCEEDED(rv)) {
 626      outString = result;
 627      rv = NS_OK;
 628    }
 629  }
 630
 631  return rv;
 632}
 633
 634NS_IMETHODIMP
 635nsNSSComponent::NSSBundleFormatStringFromName(const char *name,
 636                                              const PRUnichar **params,
 637                                              PRUint32 numParams,
 638                                              nsAString &outString)
 639{
 640  nsresult rv = NS_ERROR_FAILURE;
 641
 642  if (mNSSErrorsBundle && name) {
 643    nsXPIDLString result;
 644    rv = mNSSErrorsBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(name).get(),
 645                                                params, numParams,
 646                                                getter_Copies(result));
 647    if (NS_SUCCEEDED(rv)) {
 648      outString = result;
 649    }
 650  }
 651  return rv;
 652}
 653
 654NS_IMETHODIMP
 655nsNSSComponent::GetNSSBundleString(const char *name,
 656                                   nsAString &outString)
 657{
 658  nsresult rv = NS_ERROR_FAILURE;
 659
 660  outString.SetLength(0);
 661  if (mNSSErrorsBundle && name) {
 662    nsXPIDLString result;
 663    rv = mNSSErrorsBundle->GetStringFromName(NS_ConvertASCIItoUTF16(name).get(),
 664                                             getter_Copies(result));
 665    if (NS_SUCCEEDED(rv)) {
 666      outString = result;
 667      rv = NS_OK;
 668    }
 669  }
 670
 671  return rv;
 672}
 673
 674void
 675nsNSSComponent::LaunchSmartCardThreads()
 676{
 677  nsNSSShutDownPreventionLock locker;
 678  {
 679    SECMODModuleList *list;
 680    SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
 681    if (!lock) {
 682        PR_LOG(gPIPNSSLog, PR_LOG_ERROR,
 683               ("Couldn't get the module list lock, can't launch smart card threads\n"));
 684        return;
 685    }
 686    SECMOD_GetReadLock(lock);
 687    list = SECMOD_GetDefaultModuleList();
 688
 689    while (list) {
 690      SECMODModule *module = list->module;
 691      LaunchSmartCardThread(module);
 692      list = list->next;
 693    }
 694    SECMOD_ReleaseReadLock(lock);
 695  }
 696}
 697
 698NS_IMETHODIMP
 699nsNSSComponent::LaunchSmartCardThread(SECMODModule *module)
 700{
 701  SmartCardMonitoringThread *newThread;
 702  if (SECMOD_HasRemovableSlots(module)) {
 703    if (mThreadList == nsnull) {
 704      mThreadList = new SmartCardThreadList();
 705      if (!mThreadList) {
 706        return NS_ERROR_OUT_OF_MEMORY;
 707      }
 708    }
 709    newThread = new SmartCardMonitoringThread(module);
 710    if (!newThread) {
 711	return NS_ERROR_OUT_OF_MEMORY;
 712    }
 713    // newThread is adopted by the add.
 714    return mThreadList->Add(newThread);
 715  }
 716  return NS_OK;
 717}
 718
 719NS_IMETHODIMP
 720nsNSSComponent::ShutdownSmartCardThread(SECMODModule *module)
 721{
 722  if (!mThreadList) {
 723    return NS_OK;
 724  }
 725  mThreadList->Remove(module);
 726  return NS_OK;
 727}
 728
 729void
 730nsNSSComponent::ShutdownSmartCardThreads()
 731{
 732  delete mThreadList;
 733  mThreadList = nsnull;
 734}
 735
 736static char *
 737nss_addEscape(const char *string, char quote)
 738{
 739    char *newString = 0;
 740    int escapes = 0, size = 0;
 741    const char *src;
 742    char *dest;
 743
 744    for (src=string; *src ; src++) {
 745        if ((*src == quote) || (*src == '\\')) {
 746          escapes++;
 747        }
 748        size++;
 749    }
 750
 751    newString = (char*)PORT_ZAlloc(escapes+size+1);
 752    if (newString == NULL) {
 753        return NULL;
 754    }
 755
 756    for (src=string, dest=newString; *src; src++,dest++) {
 757        if ((*src == quote) || (*src == '\\')) {
 758            *dest++ = '\\';
 759        }
 760        *dest = *src;
 761    }
 762
 763    return newString;
 764}
 765
 766void
 767nsNSSComponent::InstallLoadableRoots()
 768{
 769  nsNSSShutDownPreventionLock locker;
 770  SECMODModule *RootsModule = nsnull;
 771
 772  // In the past we used SECMOD_AddNewModule to load our module containing
 773  // root CA certificates. This caused problems, refer to bug 176501.
 774  // On startup, we fix our database and clean any stored module reference,
 775  // and will use SECMOD_LoadUserModule to temporarily load it
 776  // for the session. (This approach requires to clean up 
 777  // using SECMOD_UnloadUserModule at the end of the session.)
 778
 779  {
 780    // Find module containing root certs
 781
 782    SECMODModuleList *list;
 783    SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
 784    if (!lock) {
 785        PR_LOG(gPIPNSSLog, PR_LOG_ERROR,
 786               ("Couldn't get the module list lock, can't install loadable roots\n"));
 787        return;
 788    }
 789    SECMOD_GetReadLock(lock);
 790    list = SECMOD_GetDefaultModuleList();
 791
 792    while (!RootsModule && list) {
 793      SECMODModule *module = list->module;
 794
 795      for (int i=0; i < module->slotCount; i++) {
 796        PK11SlotInfo *slot = module->slots[i];
 797        if (PK11_IsPresent(slot)) {
 798          if (PK11_HasRootCerts(slot)) {
 799            RootsModule = SECMOD_ReferenceModule(module);
 800            break;
 801          }
 802        }
 803      }
 804
 805      list = list->next;
 806    }
 807    SECMOD_ReleaseReadLock(lock);
 808  }
 809
 810  if (RootsModule) {
 811    PRInt32 modType;
 812    SECMOD_DeleteModule(RootsModule->commonName, &modType);
 813    SECMOD_DestroyModule(RootsModule);
 814    RootsModule = nsnull;
 815  }
 816
 817  // Find the best Roots module for our purposes.
 818  // Prefer the application's installation directory,
 819  // but also ensure the library is at least the version we expect.
 820
 821  nsresult rv;
 822  nsAutoString modName;
 823  rv = GetPIPNSSBundleString("RootCertModuleName", modName);
 824  if (NS_FAILED(rv)) return;
 825
 826  nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
 827  if (!directoryService)
 828    return;
 829
 830  static const char nss_lib[] = "nss3";
 831  const char *possible_ckbi_locations[] = {
 832    nss_lib, // This special value means: search for ckbi in the directory
 833             // where nss3 is.
 834    NS_XPCOM_CURRENT_PROCESS_DIR,
 835    NS_GRE_DIR,
 836    0 // This special value means: 
 837      //   search for ckbi in the directories on the shared
 838      //   library/DLL search path
 839  };
 840
 841  for (size_t il = 0; il < sizeof(possible_ckbi_locations)/sizeof(const char*); ++il) {
 842    nsCOMPtr<nsILocalFile> mozFile;
 843    char *fullLibraryPath = nsnull;
 844
 845    if (!possible_ckbi_locations[il])
 846    {
 847      fullLibraryPath = PR_GetLibraryName(nsnull, "nssckbi");
 848    }
 849    else
 850    {
 851      if (possible_ckbi_locations[il] == nss_lib) {
 852        // Get the location of the nss3 library.
 853        char *nss_path = PR_GetLibraryFilePathname(DLL_PREFIX "nss3" DLL_SUFFIX,
 854                                                   (PRFuncPtr) NSS_Initialize);
 855        if (!nss_path) {
 856          continue;
 857        }
 858        // Get the directory containing the nss3 library.
 859        nsCOMPtr<nsILocalFile> nssLib(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
 860        if (NS_SUCCEEDED(rv)) {
 861          rv = nssLib->InitWithNativePath(nsDependentCString(nss_path));
 862        }
 863        PR_Free(nss_path);
 864        if (NS_SUCCEEDED(rv)) {
 865          nsCOMPtr<nsIFile> file;
 866          if (NS_SUCCEEDED(nssLib->GetParent(getter_AddRefs(file)))) {
 867            mozFile = do_QueryInterface(file);
 868          }
 869        }
 870      } else {
 871        directoryService->Get( possible_ckbi_locations[il],
 872                               NS_GET_IID(nsILocalFile), 
 873                               getter_AddRefs(mozFile));
 874      }
 875  
 876      if (!mozFile) {
 877        continue;
 878      }
 879
 880      nsCAutoString processDir;
 881      mozFile->GetNativePath(processDir);
 882      fullLibraryPath = PR_GetLibraryName(processDir.get(), "nssckbi");
 883    }
 884
 885    if (!fullLibraryPath) {
 886      continue;
 887    }
 888
 889    char *escaped_fullLibraryPath = nss_addEscape(fullLibraryPath, '\"');
 890    if (!escaped_fullLibraryPath) {
 891      PR_FreeLibraryName(fullLibraryPath); // allocated by NSPR
 892      continue;
 893    }
 894
 895    /* If a module exists with the same name, delete it. */
 896    NS_ConvertUTF16toUTF8 modNameUTF8(modName);
 897    int modType;
 898    SECMOD_DeleteModule(const_cast<char*>(modNameUTF8.get()), &modType);
 899
 900    nsCString pkcs11moduleSpec;
 901    pkcs11moduleSpec.Append(NS_LITERAL_CSTRING("name=\""));
 902    pkcs11moduleSpec.Append(modNameUTF8.get());
 903    pkcs11moduleSpec.Append(NS_LITERAL_CSTRING("\" library=\""));
 904    pkcs11moduleSpec.Append(escaped_fullLibraryPath);
 905    pkcs11moduleSpec.Append(NS_LITERAL_CSTRING("\""));
 906
 907    PR_FreeLibraryName(fullLibraryPath); // allocated by NSPR
 908    PORT_Free(escaped_fullLibraryPath);
 909
 910    RootsModule =
 911      SECMOD_LoadUserModule(const_cast<char*>(pkcs11moduleSpec.get()), 
 912                            nsnull, // no parent 
 913                            false); // do not recurse
 914
 915    if (RootsModule) {
 916      bool found = (RootsModule->loaded);
 917
 918      SECMOD_DestroyModule(RootsModule);
 919      RootsModule = nsnull;
 920
 921      if (found) {
 922        break;
 923      }
 924    }
 925  }
 926}
 927
 928void 
 929nsNSSComponent::UnloadLoadableRoots()
 930{
 931  nsresult rv;
 932  nsAutoString modName;
 933  rv = GetPIPNSSBundleString("RootCertModuleName", modName);
 934  if (NS_FAILED(rv)) return;
 935
 936  NS_ConvertUTF16toUTF8 modNameUTF8(modName);
 937  SECMODModule *RootsModule = SECMOD_FindModule(modNameUTF8.get());
 938
 939  if (RootsModule) {
 940    SECMOD_UnloadUserModule(RootsModule);
 941    SECMOD_DestroyModule(RootsModule);
 942  }
 943}
 944
 945nsresult
 946nsNSSComponent::ConfigureInternalPKCS11Token()
 947{
 948  nsNSSShutDownPreventionLock locker;
 949  nsAutoString manufacturerID;
 950  nsAutoString libraryDescription;
 951  nsAutoString tokenDescription;
 952  nsAutoString privateTokenDescription;
 953  nsAutoString slotDescription;
 954  nsAutoString privateSlotDescription;
 955  nsAutoString fips140TokenDescription;
 956  nsAutoString fips140SlotDescription;
 957
 958  nsresult rv;
 959  rv = GetPIPNSSBundleString("ManufacturerID", manufacturerID);
 960  if (NS_FAILED(rv)) return rv;
 961
 962  rv = GetPIPNSSBundleString("LibraryDescription", libraryDescription);
 963  if (NS_FAILED(rv)) return rv;
 964
 965  rv = GetPIPNSSBundleString("TokenDescription", tokenDescription);
 966  if (NS_FAILED(rv)) return rv;
 967
 968  rv = GetPIPNSSBundleString("PrivateTokenDescription", privateTokenDescription);
 969  if (NS_FAILED(rv)) return rv;
 970
 971  rv = GetPIPNSSBundleString("SlotDescription", slotDescription);
 972  if (NS_FAILED(rv)) return rv;
 973
 974  rv = GetPIPNSSBundleString("PrivateSlotDescription", privateSlotDescription);
 975  if (NS_FAILED(rv)) return rv;
 976
 977  rv = GetPIPNSSBundleString("Fips140TokenDescription", fips140TokenDescription);
 978  if (NS_FAILED(rv)) return rv;
 979
 980  rv = GetPIPNSSBundleString("Fips140SlotDescription", fips140SlotDescription);
 981  if (NS_FAILED(rv)) return rv;
 982
 983  PK11_ConfigurePKCS11(NS_ConvertUTF16toUTF8(manufacturerID).get(),
 984                       NS_ConvertUTF16toUTF8(libraryDescription).get(),
 985                       NS_ConvertUTF16toUTF8(tokenDescription).get(),
 986                       NS_ConvertUTF16toUTF8(privateTokenDescription).get(),
 987                       NS_ConvertUTF16toUTF8(slotDescription).get(),
 988                       NS_ConvertUTF16toUTF8(privateSlotDescription).get(),
 989                       NS_ConvertUTF16toUTF8(fips140TokenDescription).get(),
 990                       NS_ConvertUTF16toUTF8(fips140SlotDescription).get(),
 991                       0, 0);
 992  return NS_OK;
 993}
 994
 995nsresult
 996nsNSSComponent::InitializePIPNSSBundle()
 997{
 998  // Called during init only, no mutex required.
 999
1000  nsresult rv;
1001  nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
1002  if (NS_FAILED(rv) || !bundleService) 
1003    return NS_ERROR_FAILURE;
1004  
1005  bundleService->CreateBundle(PIPNSS_STRBUNDLE_URL,
1006                              getter_AddRefs(mPIPNSSBundle));
1007  if (!mPIPNSSBundle)
1008    rv = NS_ERROR_FAILURE;
1009
1010  bundleService->CreateBundle(NSSERR_STRBUNDLE_URL,
1011                              getter_AddRefs(mNSSErrorsBundle));
1012  if (!mNSSErrorsBundle)
1013    rv = NS_ERROR_FAILURE;
1014
1015  return rv;
1016}
1017
1018nsresult
1019nsNSSComponent::RegisterPSMContentListener()
1020{
1021  // Called during init only, no mutex required.
1022
1023  nsresult rv = NS_OK;
1024  if (!mPSMContentListener) {
1025    nsCOMPtr<nsIURILoader> dispatcher(do_GetService(NS_URI_LOADER_CONTRACTID));
1026    if (dispatcher) {
1027      mPSMContentListener = do_CreateInstance(NS_PSMCONTENTLISTEN_CONTRACTID);
1028      rv = dispatcher->RegisterContentListener(mPSMContentListener);
1029    }
1030  }
1031  return rv;
1032}
1033
1034/* Table of pref names and SSL cipher ID */
1035typedef struct {
1036  const char* pref;
1037  long id;
1038} CipherPref;
1039
1040static CipherPref CipherPrefs[] = {
1041 /* SSL3/TLS cipher suites*/
1042 {"security.ssl3.rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5}, // 128-bit RC4 encryption with RSA and an MD5 MAC
1043 {"security.ssl3.rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA}, // 128-bit RC4 encryption with RSA and a SHA1 MAC
1044 {"security.ssl3.rsa_fips_des_ede3_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with RSA and a SHA1 MAC (FIPS)
1045 {"security.ssl3.rsa_des_ede3_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with RSA and a SHA1 MAC
1046 {"security.ssl3.rsa_fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA and a SHA1 MAC (FIPS)
1047 {"security.ssl3.rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA and a SHA1 MAC
1048 {"security.ssl3.rsa_1024_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA}, // 56-bit RC4 encryption with RSA and a SHA1 MAC (export)
1049 {"security.ssl3.rsa_1024_des_cbc_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA and a SHA1 MAC (export)
1050 {"security.ssl3.rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5}, // 40-bit RC4 encryption with RSA and an MD5 MAC (export)
1051 {"security.ssl3.rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5}, // 40-bit RC2 encryption with RSA and an MD5 MAC (export)
1052 /* Extra SSL3/TLS cipher suites */
1053 {"security.ssl3.dhe_rsa_camellia_256_sha", TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA}, // 256-bit Camellia encryption with RSA, DHE, and a SHA1 MAC
1054 {"security.ssl3.dhe_dss_camellia_256_sha", TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA}, // 256-bit Camellia encryption with DSA, DHE, and a SHA1 MAC
1055 {"security.ssl3.rsa_camellia_256_sha", TLS_RSA_WITH_CAMELLIA_256_CBC_SHA}, // 256-bit Camellia encryption with RSA and a SHA1 MAC
1056 {"security.ssl3.dhe_rsa_aes_256_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with RSA, DHE, and a SHA1 MAC
1057 {"security.ssl3.dhe_dss_aes_256_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with DSA, DHE, and a SHA1 MAC
1058 {"security.ssl3.rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with RSA and a SHA1 MAC
1059   /* TLS_DHE_DSS_WITH_RC4_128_SHA // 128-bit RC4 encryption with DSA, DHE, and a SHA1 MAC
1060      If this cipher gets included at a later time, it should get added at this position */
1061 {"security.ssl3.ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with ECDHE-ECDSA and a SHA1 MAC
1062 {"security.ssl3.ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with ECDHE-ECDSA and a SHA1 MAC
1063 {"security.ssl3.ecdhe_ecdsa_des_ede3_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with ECDHE-ECDSA and a SHA1 MAC
1064 {"security.ssl3.ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, // 128-bit RC4 encryption with ECDHE-ECDSA and a SHA1 MAC
1065 {"security.ssl3.ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA}, // No encryption with ECDHE-ECDSA and a SHA1 MAC
1066 {"security.ssl3.ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with ECDHE-RSA and a SHA1 MAC
1067 {"security.ssl3.ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with ECDHE-RSA and a SHA1 MAC
1068 {"security.ssl3.ecdhe_rsa_des_ede3_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with ECDHE-RSA and a SHA1 MAC
1069 {"security.ssl3.ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, // 128-bit RC4 encryption with ECDHE-RSA and a SHA1 MAC
1070 {"security.ssl3.ecdhe_rsa_null_sha", TLS_ECDHE_RSA_WITH_NULL_SHA}, // No encryption with ECDHE-RSA and a SHA1 MAC
1071 {"security.ssl3.ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with ECDH-ECDSA and a SHA1 MAC
1072 {"security.ssl3.ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with ECDH-ECDSA and a SHA1 MAC
1073 {"security.ssl3.ecdh_ecdsa_des_ede3_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with ECDH-ECDSA and a SHA1 MAC
1074 {"security.ssl3.ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA}, // 128-bit RC4 encryption with ECDH-ECDSA and a SHA1 MAC
1075 {"security.ssl3.ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA}, // No encryption with ECDH-ECDSA and a SHA1 MAC
1076 {"security.ssl3.ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with ECDH-RSA and a SHA1 MAC
1077 {"security.ssl3.ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with ECDH-RSA and a SHA1 MAC
1078 {"security.ssl3.ecdh_rsa_des_ede3_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with ECDH-RSA and a SHA1 MAC
1079 {"security.ssl3.ecdh_rsa_rc4_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA}, // 128-bit RC4 encryption with ECDH-RSA and a SHA1 MAC
1080 {"security.ssl3.ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA}, // No encryption with ECDH-RSA and a SHA1 MAC
1081 {"security.ssl3.dhe_rsa_camellia_128_sha", TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA}, // 128-bit Camellia encryption with RSA, DHE, and a SHA1 MAC
1082 {"security.ssl3.dhe_dss_camellia_128_sha", TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA}, // 128-bit Camellia encryption with DSA, DHE, and a SHA1 MAC
1083 {"security.ssl3.rsa_camellia_128_sha", TLS_RSA_WITH_CAMELLIA_128_CBC_SHA}, // 128-bit Camellia encryption with RSA and a SHA1 MAC
1084 {"security.ssl3.dhe_rsa_aes_128_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with RSA, DHE, and a SHA1 MAC
1085 {"security.ssl3.dhe_dss_aes_128_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with DSA, DHE, and a SHA1 MAC
1086 {"security.ssl3.rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with RSA and a SHA1 MAC
1087 {"security.ssl3.dhe_rsa_des_ede3_sha", SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with RSA, DHE, and a SHA1 MAC
1088 {"security.ssl3.dhe_dss_des_ede3_sha", SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with DSA, DHE, and a SHA1 MAC
1089 {"security.ssl3.dhe_rsa_des_sha", SSL_DHE_RSA_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA, DHE, and a SHA1 MAC
1090 {"security.ssl3.dhe_dss_des_sha", SSL_DHE_DSS_WITH_DES_CBC_SHA}, // 56-bit DES encryption with DSA, DHE, and a SHA1 MAC
1091 {"security.ssl3.rsa_null_sha", SSL_RSA_WITH_NULL_SHA}, // No encryption with RSA authentication and a SHA1 MAC
1092 {"security.ssl3.rsa_null_md5", SSL_RSA_WITH_NULL_MD5}, // No encryption with RSA authentication and an MD5 MAC
1093 {"security.ssl3.rsa_seed_sha", TLS_RSA_WITH_SEED_CBC_SHA}, // SEED encryption with RSA and a SHA1 MAC
1094 {NULL, 0} /* end marker */
1095};
1096
1097static void
1098setNonPkixOcspEnabled(PRInt32 ocspEnabled, nsIPrefBranch * pref)
1099{
1100  switch (ocspEnabled) {
1101  case 0:
1102    CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
1103    CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
1104    break;
1105  case 1:
1106    CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
1107    CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
1108    break;
1109  case 2:
1110    {
1111      char *signingCA = nsnull;
1112      char *url = nsnull;
1113
1114      // Get the signing CA and service url //
1115      pref->GetCharPref("security.OCSP.signingCA", &signingCA);
1116      pref->GetCharPref("security.OCSP.URL", &url);
1117
1118      // Set OCSP up
1119      CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
1120      CERT_SetOCSPDefaultResponder(CERT_GetDefaultCertDB(), url, signingCA);
1121      CERT_EnableOCSPDefaultResponder(CERT_GetDefaultCertDB());
1122
1123      nsMemory::Free(signingCA);
1124      nsMemory::Free(url);
1125    }
1126    break;
1127  }
1128}
1129
1130#define CRL_DOWNLOAD_DEFAULT false
1131#define OCSP_ENABLED_DEFAULT 1
1132#define OCSP_REQUIRED_DEFAULT 0
1133#define FRESH_REVOCATION_REQUIRED_DEFAULT false
1134#define MISSING_CERT_DOWNLOAD_DEFAULT false
1135#define FIRST_REVO_METHOD_DEFAULT "ocsp"
1136#define USE_NSS_LIBPKIX_DEFAULT false
1137
1138// Caller must hold a lock on nsNSSComponent::mutex when calling this function
1139void nsNSSComponent::setValidationOptions(nsIPrefBranch * pref)
1140{
1141  nsNSSShutDownPreventionLock locker;
1142  nsresult rv;
1143
1144  bool crlDownloading;
1145  rv = pref->GetBoolPref("security.CRL_download.enabled", &crlDownloading);
1146  if (NS_FAILED(rv))
1147    crlDownloading = CRL_DOWNLOAD_DEFAULT;
1148  
1149  PRInt32 ocspEnabled;
1150  rv = pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
1151  // 0 = disabled, 1 = enabled, 
1152  // 2 = enabled with given default responder
1153  if (NS_FAILED(rv))
1154    ocspEnabled = OCSP_ENABLED_DEFAULT;
1155
1156  bool ocspRequired;
1157  rv = pref->GetBoolPref("security.OCSP.require", &ocspRequired);
1158  if (NS_FAILED(rv))
1159    ocspRequired = OCSP_REQUIRED_DEFAULT;
1160
1161  bool anyFreshRequired;
1162  rv = pref->GetBoolPref("security.fresh_revocation_info.require", &anyFreshRequired);
1163  if (NS_FAILED(rv))
1164    anyFreshRequired = FRESH_REVOCATION_REQUIRED_DEFAULT;
1165  
1166  bool aiaDownloadEnabled;
1167  rv = pref->GetBoolPref("security.missing_cert_download.enabled", &aiaDownloadEnabled);
1168  if (NS_FAILED(rv))
1169    aiaDownloadEnabled = MISSING_CERT_DOWNLOAD_DEFAULT;
1170
1171  nsCString firstNetworkRevo;
1172  rv = pref->GetCharPref("security.first_network_revocation_method", getter_Copies(firstNetworkRevo));
1173  if (NS_FAILED(rv))
1174    firstNetworkRevo = FIRST_REVO_METHOD_DEFAULT;
1175  
1176  setNonPkixOcspEnabled(ocspEnabled, pref);
1177  
1178  CERT_SetOCSPFailureMode( ocspRequired ?
1179                           ocspMode_FailureIsVerificationFailure
1180                           : ocspMode_FailureIsNotAVerificationFailure);
1181
1182  nsRefPtr<nsCERTValInParamWrapper> newCVIN = new nsCERTValInParamWrapper;
1183  if (NS_SUCCEEDED(newCVIN->Construct(
1184      aiaDownloadEnabled ? 
1185        nsCERTValInParamWrapper::missing_cert_download_on : nsCERTValInParamWrapper::missing_cert_download_off,
1186      crlDownloading ?
1187        nsCERTValInParamWrapper::crl_download_allowed : nsCERTValInParamWrapper::crl_local_only,
1188      ocspEnabled ? 
1189        nsCERTValInParamWrapper::ocsp_on : nsCERTValInParamWrapper::ocsp_off,
1190      ocspRequired ? 
1191        nsCERTValInParamWrapper::ocsp_strict : nsCERTValInParamWrapper::ocsp_relaxed,
1192      anyFreshRequired ?
1193        nsCERTValInParamWrapper::any_revo_strict : nsCERTValInParamWrapper::any_revo_relaxed,
1194      firstNetworkRevo.get()))) {
1195    // Swap to new defaults, and will cause the old defaults to be released,
1196    // as soon as any concurrent use of the old default objects has finished.
1197    mDefaultCERTValInParam = newCVIN;
1198  }
1199
1200  /*
1201    * The new defaults might change the validity of already established SSL sessions,
1202    * let's not reuse them.
1203    */
1204  SSL_ClearSessionCache();
1205}
1206
1207NS_IMETHODIMP
1208nsNSSComponent::SkipOcsp()
1209{
1210  nsNSSShutDownPreventionLock locker;
1211  CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
1212
1213  SECStatus rv = CERT_DisableOCSPChecking(certdb);
1214  return (rv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
1215}
1216
1217NS_IMETHODIMP
1218nsNSSComponent::SkipOcspOff()
1219{
1220  nsNSSShutDownPreventionLock locker;
1221  PRInt32 ocspEnabled;
1222  if (NS_FAILED(mPrefBranch->GetIntPref("security.OCSP.enabled", &ocspEnabled)))
1223    ocspEnabled = OCSP_ENABLED_DEFAULT;
1224  // 0 = disabled, 1 = enabled, 
1225  // 2 = enabled with given default responder
1226  
1227  setNonPkixOcspEnabled(ocspEnabled, mPrefBranch);
1228
1229  if (ocspEnabled)
1230    SSL_ClearSessionCache();
1231
1232  return NS_OK;
1233}
1234
1235nsresult
1236nsNSSComponent::PostCRLImportEvent(const nsCSubstring &urlString,
1237                                   nsIStreamListener *listener)
1238{
1239  //Create the event
1240  nsCOMPtr<nsIRunnable> event = new CRLDownloadEvent(urlString, listener);
1241  if (!event)
1242    return NS_ERROR_OUT_OF_MEMORY;
1243
1244  //Get a handle to the ui thread
1245  return NS_DispatchToMainThread(event);
1246}
1247
1248nsresult
1249nsNSSComponent::DownloadCRLDirectly(nsAutoString url, nsAutoString key)
1250{
1251  //This api is meant to support direct interactive update of crl from the crl manager
1252  //or other such ui.
1253  nsCOMPtr<nsIStreamListener> listener =
1254      new PSMContentDownloader(PSMContentDownloader::PKCS7_CRL);
1255  
1256  NS_ConvertUTF16toUTF8 url8(url);
1257  return PostCRLImportEvent(url8, listener);
1258}
1259
1260nsresult nsNSSComponent::DownloadCrlSilently()
1261{
1262  //Add this attempt to the hashtable
1263  nsStringKey hashKey(mCrlUpdateKey.get());
1264  crlsScheduledForDownload->Put(&hashKey,(void *)nsnull);
1265    
1266  //Set up the download handler
1267  nsRefPtr<PSMContentDownloader> psmDownloader =
1268      new PSMContentDownloader(PSMContentDownloader::PKCS7_CRL);
1269  psmDownloader->setSilentDownload(true);
1270  psmDownloader->setCrlAutodownloadKey(mCrlUpdateKey);
1271  
1272  //Now get the url string
1273  NS_ConvertUTF16toUTF8 url8(mDownloadURL);
1274  return PostCRLImportEvent(url8, psmDownloader);
1275}
1276
1277nsresult nsNSSComponent::getParamsForNextCrlToDownload(nsAutoString *url, PRTime *time, nsAutoString *key)
1278{
1279  const char *updateEnabledPref = CRL_AUTOUPDATE_ENABLED_PREF;
1280  const char *updateTimePref = CRL_AUTOUPDATE_TIME_PREF;
1281  const char *updateURLPref = CRL_AUTOUPDATE_URL_PREF;
1282  char **allCrlsToBeUpdated;
1283  PRUint32 noOfCrls;
1284  PRTime nearestUpdateTime = 0;
1285  nsAutoString crlKey;
1286  char *tempUrl;
1287  nsresult rv;
1288  
1289  nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
1290  if(NS_FAILED(rv)){
1291    return rv;
1292  }
1293
1294  rv = pref->GetChildList(updateEnabledPref, &noOfCrls, &allCrlsToBeUpdated);
1295  if ( (NS_FAILED(rv)) || (noOfCrls==0) ){
1296    return NS_ERROR_FAILURE;
1297  }
1298
1299  for(PRUint32 i=0;i<noOfCrls;i++) {
1300    //First check if update pref is enabled for this crl
1301    bool autoUpdateEnabled = false;
1302    rv = pref->GetBoolPref(*(allCrlsToBeUpdated+i), &autoUpdateEnabled);
1303    if (NS_FAILED(rv) || !autoUpdateEnabled) {
1304      continue;
1305    }
1306
1307    nsAutoString tempCrlKey;
1308
1309    //Now, generate the crl key. Same key would be used as hashkey as well
1310    nsCAutoString enabledPrefCString(*(allCrlsToBeUpdated+i));
1311    enabledPrefCString.ReplaceSubstring(updateEnabledPref,".");
1312    tempCrlKey.AssignWithConversion(enabledPrefCString.get());
1313      
1314    //Check if this crl has already been scheduled. Its presence in the hashtable
1315    //implies that it has been scheduled already this client session, and
1316    //is either in the process of being downloaded, or its download failed
1317    //for some reason. In the second case, we will not retry in the current client session
1318    nsStringKey hashKey(tempCrlKey.get());
1319    if(crlsScheduledForDownload->Exists(&hashKey)){
1320      continue;
1321    }
1322
1323    char *tempTimeString;
1324    PRTime tempTime;
1325    nsCAutoString timingPrefCString(updateTimePref);
1326    timingPrefCString.AppendWithConversion(tempCrlKey);
1327    rv = pref->GetCharPref(timingPrefCString.get(), &tempTimeString);
1328    if (NS_FAILED(rv)){
1329      continue;
1330    }
1331    rv = PR_ParseTimeString(tempTimeString,true, &tempTime);
1332    nsMemory::Free(tempTimeString);
1333    if (NS_FAILED(rv)){
1334      continue;
1335    }
1336
1337    if(nearestUpdateTime == 0 || tempTime < nearestUpdateTime){
1338      nsCAutoString urlPrefCString(updateURLPref);
1339      urlPrefCString.AppendWithConversion(tempCrlKey);
1340      rv = pref->GetCharPref(urlPrefCString.get(), &tempUrl);
1341      if (NS_FAILED(rv) || (!tempUrl)){
1342        continue;
1343      }
1344      nearestUpdateTime = tempTime;
1345      crlKey = tempCrlKey;
1346    }
1347  }
1348
1349  if(noOfCrls > 0)
1350    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(noOfCrls, allCrlsToBeUpdated);
1351
1352  if(nearestUpdateTime > 0){
1353    *time = nearestUpdateTime;
1354    url->AssignWithConversion((const char *)tempUrl);
1355    nsMemory::Free(tempUrl);
1356    *key = crlKey;
1357    rv = NS_OK;
1358  } else{
1359    rv = NS_ERROR_FAILURE;
1360  }
1361
1362  return rv;
1363}
1364
1365NS_IMETHODIMP
1366nsNSSComponent::Notify(nsITimer *timer)
1367{
1368  nsresult rv;
1369
1370  //Timer has fired. So set the flag accordingly
1371  {
1372    MutexAutoLock lock(mCrlTimerLock);
1373    crlDownloadTimerOn = false;
1374  }
1375
1376  //First, handle this download
1377  rv = DownloadCrlSilently();
1378
1379  //Dont Worry if successful or not
1380  //Set the next timer
1381  DefineNextTimer();
1382  return NS_OK;
1383}
1384
1385nsresult
1386nsNSSComponent::RemoveCrlFromList(nsAutoString key)
1387{
1388  nsStringKey hashKey(key.get());
1389  if(crlsScheduledForDownload->Exists(&hashKey)){
1390    crlsScheduledForDownload->Remove(&hashKey);
1391  }
1392  return NS_OK;
1393}
1394
1395nsresult
1396nsNSSComponent::DefineNextTimer()
1397{
1398  PRTime nextFiring;
1399  PRTime now = PR_Now();
1400  PRUint64 diff;
1401  PRUint32 interval;
1402  PRUint32 primaryDelay = CRL_AUTOUPDATE_DEFAULT_DELAY;
1403  nsresult rv;
1404
1405  if(!mTimer){
1406    mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
1407    if(NS_FAILED(rv))
1408      return rv;
1409  }
1410
1411  //If some timer is already running, cancel it. Thus, the request that came last,
1412  //wins. This would ensure that in no way we end up setting two different timers
1413  //This part should be synchronized because this function might be called from separate
1414  //threads
1415
1416  MutexAutoLock lock(mCrlTimerLock);
1417
1418  if (crlDownloadTimerOn) {
1419    mTimer->Cancel();
1420  }
1421
1422  rv = getParamsForNextCrlToDownload(&mDownloadURL, &nextFiring, &mCrlUpdateKey);
1423  //If there are no more crls to be updated any time in future
1424  if(NS_FAILED(rv)){
1425    // Return - no error - just implies nothing to schedule
1426    return NS_OK;
1427  }
1428     
1429  //Define the firing interval, from NOW
1430  if ( now < nextFiring) {
1431    LL_SUB(diff,nextFiring,now);
1432    LL_L2UI(interval, diff);
1433    //Now, we are doing 32 operations - so, don't need LL_ functions...
1434    interval = interval/PR_USEC_PER_MSEC;
1435  }else {
1436    interval = primaryDelay;
1437  }
1438  
1439  mTimer->InitWithCallback(static_cast<nsITimerCallback*>(this), 
1440                           interval,
1441                           nsITimer::TYPE_ONE_SHOT);
1442  crlDownloadTimerOn = true;
1443
1444  return NS_OK;
1445}
1446
1447//Note that the StopCRLUpdateTimer and InitializeCRLUpdateTimer functions should never be called
1448//simultaneously from diff threads - they are NOT threadsafe. But, since there is no chance of 
1449//that happening, there is not much benefit it trying to make it so at this point
1450nsresult
1451nsNSSComponent::StopCRLUpdateTimer()
1452{
1453  
1454  //If it is at all running. 
1455  if (mUpdateTimerInitialized) {
1456    if(crlsScheduledForDownload != nsnull){
1457      crlsScheduledForDownload->Reset();
1458      delete crlsScheduledForDownload;
1459      crlsScheduledForDownload = nsnull;
1460    }
1461    {
1462      MutexAutoLock lock(mCrlTimerLock);
1463      if (crlDownloadTimerOn) {
1464        mTimer->Cancel();
1465      }
1466      crlDownloadTimerOn = false;
1467    }
1468    mUpdateTimerInitialized = false;
1469  }
1470
1471  return NS_OK;
1472}
1473
1474nsresult
1475nsNSSComponent::InitializeCRLUpdateTimer()
1476{
1477  nsresult rv;
1478    
1479  //First check if this is already initialized. Then we stop it.
1480  if (!mUpdateTimerInitialized) {
1481    mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
1482    if(NS_FAILED(rv)){
1483      return rv;
1484    }
1485    crlsScheduledForDownload = new nsHashtable(16, true);
1486    DefineNextTimer();
1487    mUpdateTimerInitialized = true;  
1488  } 
1489
1490  return NS_OK;
1491}
1492
1493#ifdef XP_MACOSX
1494void
1495nsNSSComponent::TryCFM2MachOMigration(nsIFile *cfmPath, nsIFile *machoPath)
1496{
1497  // We will modify the parameters.
1498  //
1499  // If neither cert7.db, cert8.db, key3.db, are available, 
1500  // copy from filenames that were used in the old days
1501  // test for key3.db first, since a new profile might only contain cert8.db, 
1502  // but not cert7.db - this optimizes number of tests
1503
1504  NS_NAMED_LITERAL_CSTRING(cstr_key3db, "key3.db");
1505  NS_NAMED_LITERAL_CSTRING(cstr_cert7db, "cert7.db");
1506  NS_NAMED_LITERAL_CSTRING(cstr_cert8db, "cert8.db");
1507  NS_NAMED_LITERAL_CSTRING(cstr_keydatabase3, "Key Database3");
1508  NS_NAMED_LITERAL_CSTRING(cstr_certificate7, "Certificates7");
1509  NS_NAMED_LITERAL_CSTRING(cstr_certificate8, "Certificates8");
1510
1511  bool bExists;
1512  nsresult rv;
1513
1514  nsCOMPtr<nsIFile> macho_key3db;
1515  rv = machoPath->Clone(getter_AddRefs(macho_key3db));
1516  if (NS_FAILED(rv)) {
1517    return;
1518  }
1519
1520  macho_key3db->AppendNative(cstr_key3db);
1521  rv = macho_key3db->Exists(&bExists);
1522  if (NS_FAILED(rv) || bExists) {
1523    return;
1524  }
1525
1526  nsCOMPtr<nsIFile> macho_cert7db;
1527  rv = machoPath->Clone(getter_AddRefs(macho_cert7db));
1528  if (NS_FAILED(rv)) {
1529    return;
1530  }
1531
1532  macho_cert7db->AppendNative(cstr_cert7db);
1533  rv = macho_cert7db->Exists(&bExists);
1534  if (NS_FAILED(rv) || bExists) {
1535    return;
1536  }
1537
1538  nsCOMPtr<nsIFile> macho_cert8db;
1539  rv = machoPath->Clone(getter_AddRefs(macho_cert8db));
1540  if (NS_FAILED(rv)) {
1541    return;
1542  }
1543
1544  macho_cert8db->AppendNative(cstr_cert8db);
1545  rv = macho_cert7db->Exists(&bExists);
1546  if (NS_FAILED(rv) || bExists) {
1547    return;
1548  }
1549
1550  // None of the new files exist. Try to copy any available old files.
1551
1552  nsCOMPtr<nsIFile> cfm_key3;
1553  rv = cfmPath->Clone(getter_AddRefs(cfm_key3));
1554  if (NS_FAILED(rv)) {
1555    return;
1556  }
1557
1558  cfm_key3->AppendNative(cstr_keydatabase3);
1559  rv = cfm_key3->Exists(&bExists);
1560  if (NS_FAILED(rv)) {
1561    return;
1562  }
1563
1564  if (bExists) {
1565    cfm_key3->CopyToFollowingLinksNative(machoPath, cstr_key3db);
1566  }
1567
1568  nsCOMPtr<nsIFile> cfm_cert7;
1569  rv = cfmPath->Clone(getter_Ad

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