Back to index

lightning-sunbird  0.9+nobinonly
nsNSSComponent.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Hubbie Shaw
00025  *   Doug Turner <dougt@netscape.com>
00026  *   Mitch Stoltz <mstoltz@netscape.com>
00027  *   Brian Ryner <bryner@brianryner.com>
00028  *   Kai Engert <kaie@netscape.com>
00029  *   Vipul Gupta <vipul.gupta@sun.com>
00030  *   Douglas Stebila <douglas@stebila.ca>
00031  *   Kai Engert <kengert@redhat.com>
00032  *
00033  * Alternatively, the contents of this file may be used under the terms of
00034  * either the GNU General Public License Version 2 or later (the "GPL"), or
00035  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00036  * in which case the provisions of the GPL or the LGPL are applicable instead
00037  * of those above. If you wish to allow use of your version of this file only
00038  * under the terms of either the GPL or the LGPL, and not to allow others to
00039  * use your version of this file under the terms of the MPL, indicate your
00040  * decision by deleting the provisions above and replace them with the notice
00041  * and other provisions required by the GPL or the LGPL. If you do not delete
00042  * the provisions above, a recipient may use your version of this file under
00043  * the terms of any one of the MPL, the GPL or the LGPL.
00044  *
00045  * ***** END LICENSE BLOCK ***** */
00046 
00047 #include "nsNSSComponent.h"
00048 #include "nsNSSCallbacks.h"
00049 #include "nsNSSIOLayer.h"
00050 #include "nsSSLThread.h"
00051 #include "nsCertVerificationThread.h"
00052 #include "nsNSSEvent.h"
00053 
00054 #include "nsNetUtil.h"
00055 #include "nsAppDirectoryServiceDefs.h"
00056 #include "nsDirectoryService.h"
00057 #include "nsIStreamListener.h"
00058 #include "nsIStringBundle.h"
00059 #include "nsIDirectoryService.h"
00060 #include "nsIDOMNode.h"
00061 #include "nsCURILoader.h"
00062 #include "nsDirectoryServiceDefs.h"
00063 #include "nsIProxyObjectManager.h"
00064 #include "nsIX509Cert.h"
00065 #include "nsIX509CertDB.h"
00066 #include "nsIProfileChangeStatus.h"
00067 #include "nsNSSCertificate.h"
00068 #include "nsNSSHelper.h"
00069 #include "nsSmartCardMonitor.h"
00070 #include "prlog.h"
00071 #include "nsIPrefService.h"
00072 #include "nsIPrefBranch.h"
00073 #include "nsIPrefBranch2.h"
00074 #include "nsIDateTimeFormat.h"
00075 #include "nsDateTimeFormatCID.h"
00076 #include "nsAutoLock.h"
00077 #include "nsIEventQueue.h"
00078 #include "nsIDOMEvent.h"
00079 #include "nsIDOMDocument.h"
00080 #include "nsIDOMDocumentEvent.h"
00081 #include "nsIDOMWindow.h"
00082 #include "nsIDOMWindowCollection.h"
00083 #include "nsIDOMWindowInternal.h"
00084 #include "nsIDOMSmartCardEvent.h"
00085 #include "nsIDOMCrypto.h"
00086 #include "nsIRunnable.h"
00087 #include "plevent.h"
00088 #include "nsCRT.h"
00089 #include "nsCRLInfo.h"
00090 
00091 #include "nsIWindowWatcher.h"
00092 #include "nsIPrompt.h"
00093 #include "nsProxiedService.h"
00094 #include "nsIPrincipal.h"
00095 #include "nsReadableUtils.h"
00096 #include "nsIDateTimeFormat.h"
00097 #include "prtypes.h"
00098 #include "nsInt64.h"
00099 #include "nsTime.h"
00100 #include "nsIEntropyCollector.h"
00101 #include "nsIBufEntropyCollector.h"
00102 #include "nsIServiceManager.h"
00103 #include "nsILocalFile.h"
00104 #include "nsITokenPasswordDialogs.h"
00105 #include "nsICRLManager.h"
00106 #include "nsNSSShutDown.h"
00107 #include "nsSmartCardEvent.h"
00108 #include "nsICryptoHash.h"
00109 
00110 #include "nss.h"
00111 #include "pk11func.h"
00112 #include "ssl.h"
00113 #include "sslproto.h"
00114 #include "secmod.h"
00115 #include "sechash.h"
00116 #include "secmime.h"
00117 #include "ocsp.h"
00118 #include "cms.h"
00119 #include "nssckbi.h"
00120 #include "base64.h"
00121 
00122 extern "C" {
00123 #include "pkcs12.h"
00124 #include "p12plcy.h"
00125 }
00126 
00127 #ifdef PR_LOGGING
00128 PRLogModuleInfo* gPIPNSSLog = nsnull;
00129 #endif
00130 
00131 #define NS_CRYPTO_HASH_BUFFER_SIZE 4096
00132 
00133 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00134 int nsNSSComponent::mInstanceCount = 0;
00135 
00136 // XXX tmp callback for slot password
00137 extern char * PR_CALLBACK 
00138 pk11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void *arg);
00139 
00140 #define PIPNSS_STRBUNDLE_URL "chrome://pipnss/locale/pipnss.properties"
00141 
00142 
00143 static PLHashNumber PR_CALLBACK certHashtable_keyHash(const void *key)
00144 {
00145   if (!key)
00146     return 0;
00147   
00148   SECItem *certKey = (SECItem*)key;
00149   
00150   // lazy hash function, sum up all char values of SECItem
00151   
00152   PLHashNumber hash = 0;
00153   unsigned int i = 0;
00154   unsigned char *c = certKey->data;
00155   
00156   for (i = 0; i < certKey->len; ++i, ++c) {
00157     hash += *c;
00158   }
00159   
00160   return hash;
00161 }
00162 
00163 static PRIntn PR_CALLBACK certHashtable_keyCompare(const void *k1, const void *k2)
00164 {
00165   // return type is a bool, answering the question "are the keys equal?"
00166 
00167   if (!k1 || !k2)
00168     return PR_FALSE;
00169   
00170   SECItem *certKey1 = (SECItem*)k1;
00171   SECItem *certKey2 = (SECItem*)k2;
00172   
00173   if (certKey1->len != certKey2->len) {
00174     return PR_FALSE;
00175   }
00176   
00177   unsigned int i = 0;
00178   unsigned char *c1 = certKey1->data;
00179   unsigned char *c2 = certKey2->data;
00180   
00181   for (i = 0; i < certKey1->len; ++i, ++c1, ++c2) {
00182     if (*c1 != *c2) {
00183       return PR_FALSE;
00184     }
00185   }
00186   
00187   return PR_TRUE;
00188 }
00189 
00190 static PRIntn PR_CALLBACK certHashtable_valueCompare(const void *v1, const void *v2)
00191 {
00192   // two values are identical if their keys are identical
00193   
00194   if (!v1 || !v2)
00195     return PR_FALSE;
00196   
00197   CERTCertificate *cert1 = (CERTCertificate*)v1;
00198   CERTCertificate *cert2 = (CERTCertificate*)v2;
00199   
00200   return certHashtable_keyCompare(&cert1->certKey, &cert2->certKey);
00201 }
00202 
00203 static PRIntn PR_CALLBACK certHashtable_clearEntry(PLHashEntry *he, PRIntn /*index*/, void * /*userdata*/)
00204 {
00205   if (he && he->value) {
00206     CERT_DestroyCertificate((CERTCertificate*)he->value);
00207   }
00208   
00209   return HT_ENUMERATE_NEXT;
00210 }
00211 
00212 struct CRLDownloadEvent : PLEvent {
00213   nsCAutoString *urlString;
00214   nsIStreamListener *psmDownloader;
00215 };
00216 
00217 // Note that nsNSSComponent is a singleton object across all threads, 
00218 // and automatic downloads are always scheduled sequentially - that is, 
00219 // once one crl download is complete, the next one is scheduled
00220 static void PR_CALLBACK HandleCRLImportPLEvent(CRLDownloadEvent *aEvent)
00221 {
00222   nsresult rv;
00223   nsIURI *pURL;
00224   
00225   if((aEvent->psmDownloader==nsnull) || (aEvent->urlString==nsnull) )
00226     return;
00227 
00228   rv = NS_NewURI(&pURL, aEvent->urlString->get());
00229   if(NS_SUCCEEDED(rv)){
00230     NS_OpenURI(aEvent->psmDownloader, nsnull, pURL);
00231   }
00232 }
00233 
00234 static void PR_CALLBACK DestroyCRLImportPLEvent(CRLDownloadEvent* aEvent)
00235 {
00236   delete aEvent->urlString;
00237   delete aEvent;
00238 }
00239 
00240 //This class is used to run the callback code
00241 //passed to the event handlers for smart card notification
00242 class nsTokenEventRunnable : public nsIRunnable {
00243 public:
00244   nsTokenEventRunnable(const nsAString &aType, const nsAString &aTokenName);
00245   virtual ~nsTokenEventRunnable();
00246 
00247   NS_IMETHOD Run ();
00248   NS_DECL_ISUPPORTS
00249 private:
00250   nsString mType;
00251   nsString mTokenName;
00252 };
00253 
00254 // ISuuports implementation for nsTokenEventRunnable
00255 NS_IMPL_THREADSAFE_ISUPPORTS1(nsTokenEventRunnable, nsIRunnable)
00256 
00257 nsTokenEventRunnable::nsTokenEventRunnable(const nsAString &aType, 
00258    const nsAString &aTokenName): mType(aType), mTokenName(aTokenName) { }
00259 
00260 nsTokenEventRunnable::~nsTokenEventRunnable() { }
00261 
00262 //Implementation that runs the callback passed to 
00263 //crypto.generateCRMFRequest as an event.
00264 NS_IMETHODIMP
00265 nsTokenEventRunnable::Run()
00266 { 
00267   nsresult rv;
00268   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00269   if (NS_FAILED(rv))
00270     return rv;
00271 
00272   return nssComponent->DispatchEvent(mType, mTokenName);
00273 }
00274 
00275 nsNSSComponent::nsNSSComponent()
00276   :mNSSInitialized(PR_FALSE), mThreadList(nsnull)
00277 {
00278   mutex = PR_NewLock();
00279   
00280 #ifdef PR_LOGGING
00281   if (!gPIPNSSLog)
00282     gPIPNSSLog = PR_NewLogModule("pipnss");
00283 #endif
00284   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::ctor\n"));
00285   mUpdateTimerInitialized = PR_FALSE;
00286   crlDownloadTimerOn = PR_FALSE;
00287   crlsScheduledForDownload = nsnull;
00288   mTimer = nsnull;
00289   mCrlTimerLock = nsnull;
00290   mObserversRegistered = PR_FALSE;
00291 
00292   nsSSLIOLayerHelpers::Init();
00293   mClientAuthRememberService = new nsClientAuthRememberService;
00294   if (mClientAuthRememberService)
00295     mClientAuthRememberService->Init();
00296   
00297   NS_ASSERTION( (0 == mInstanceCount), "nsNSSComponent is a singleton, but instantiated multiple times!");
00298   ++mInstanceCount;
00299   hashTableCerts = nsnull;
00300   mShutdownObjectList = nsNSSShutDownList::construct();
00301   mIsNetworkDown = PR_FALSE;
00302   mSSLThread = new nsSSLThread();
00303   if (mSSLThread)
00304     mSSLThread->startThread();
00305   mCertVerificationThread = new nsCertVerificationThread();
00306   if (mCertVerificationThread)
00307     mCertVerificationThread->startThread();
00308 }
00309 
00310 nsNSSComponent::~nsNSSComponent()
00311 {
00312   if (mSSLThread)
00313   {
00314     mSSLThread->requestExit();
00315     delete mSSLThread;
00316     mSSLThread = nsnull;
00317   }
00318   
00319   if (mCertVerificationThread)
00320   {
00321     mCertVerificationThread->requestExit();
00322     delete mCertVerificationThread;
00323     mCertVerificationThread = nsnull;
00324   }
00325 
00326   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor\n"));
00327 
00328   if(mUpdateTimerInitialized == PR_TRUE){
00329     PR_Lock(mCrlTimerLock);
00330     if(crlDownloadTimerOn == PR_TRUE){
00331       mTimer->Cancel();
00332     }
00333     crlDownloadTimerOn = PR_FALSE;
00334     PR_Unlock(mCrlTimerLock);
00335     PR_DestroyLock(mCrlTimerLock);
00336     if(crlsScheduledForDownload != nsnull){
00337       crlsScheduledForDownload->Reset();
00338       delete crlsScheduledForDownload;
00339     }
00340 
00341     mUpdateTimerInitialized = PR_FALSE;
00342   }
00343 
00344   // All cleanup code requiring services needs to happen in xpcom_shutdown
00345 
00346   ShutdownNSS();
00347   nsSSLIOLayerHelpers::Cleanup();
00348   --mInstanceCount;
00349   delete mShutdownObjectList;
00350 
00351   if (mutex) {
00352     PR_DestroyLock(mutex);
00353     mutex = nsnull;
00354   }
00355 
00356   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor finished\n"));
00357 }
00358 
00359 NS_IMETHODIMP
00360 nsNSSComponent::PostEvent(const nsAString &eventType, 
00361                                                   const nsAString &tokenName)
00362 {
00363   nsresult rv;
00364   nsTokenEventRunnable *runnable = 
00365                                new nsTokenEventRunnable(eventType, tokenName);
00366   if (!runnable) {
00367     return NS_ERROR_OUT_OF_MEMORY;
00368   }
00369 
00370   rv = nsNSSEventPostToUIEventQueue(runnable);
00371   if (NS_FAILED(rv))
00372     delete runnable;
00373 
00374   return rv;
00375 }
00376 
00377 
00378 NS_IMETHODIMP
00379 nsNSSComponent::DispatchEvent(const nsAString &eventType,
00380                                                  const nsAString &tokenName)
00381 {
00382   // 'Dispatch' the event to all the windows. 'DispatchEventToWindow()' will
00383   // first check to see if a given window has requested crypto events.
00384   nsresult rv;
00385   nsCOMPtr<nsIWindowWatcher> windowWatcher =
00386                             do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
00387 
00388   if (NS_FAILED(rv)) {
00389     return rv;
00390   }
00391 
00392   nsCOMPtr<nsISimpleEnumerator> enumerator;
00393   rv = windowWatcher->GetWindowEnumerator(getter_AddRefs(enumerator));
00394   if (NS_FAILED(rv)) {
00395     return rv;
00396   }
00397 
00398   PRBool hasMoreWindows;
00399 
00400   while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreWindows))
00401          && hasMoreWindows) {
00402     nsCOMPtr<nsISupports> supports;
00403     enumerator->GetNext(getter_AddRefs(supports));
00404     nsCOMPtr<nsIDOMWindow> domWin(do_QueryInterface(supports));
00405     if (domWin) {
00406       nsresult rv2 = DispatchEventToWindow(domWin, eventType, tokenName);
00407       if (NS_FAILED(rv2)) {
00408         // return the last failure, don't let a single failure prevent
00409         // continued delivery of events.
00410         rv = rv2;
00411       }
00412     }
00413   }
00414   return rv;
00415 }
00416 
00417 nsresult
00418 nsNSSComponent::DispatchEventToWindow(nsIDOMWindow *domWin,
00419                       const nsAString &eventType, const nsAString &tokenName)
00420 {
00421   // first walk the children and dispatch their events 
00422   {
00423     nsresult rv;
00424     nsCOMPtr<nsIDOMWindowCollection> frames;
00425     rv = domWin->GetFrames(getter_AddRefs(frames));
00426     if (NS_FAILED(rv)) {
00427       return rv;
00428     }
00429 
00430     PRUint32 length;
00431     frames->GetLength(&length);
00432     PRUint32 i;
00433     for (i = 0; i < length; i++) {
00434       nsCOMPtr<nsIDOMWindow> childWin;
00435       frames->Item(i, getter_AddRefs(childWin));
00436       DispatchEventToWindow(childWin, eventType, tokenName);
00437     }
00438   }
00439 
00440   // check if we've enabled smart card events on this window
00441   // NOTE: it's not an error to say that we aren't going to dispatch
00442   // the event.
00443   {
00444     nsCOMPtr<nsIDOMWindowInternal> intWindow = do_QueryInterface(domWin);
00445     if (!intWindow) {
00446       return NS_OK; // nope, it's not an internal window
00447     }
00448 
00449     nsCOMPtr<nsIDOMCrypto> crypto;
00450     intWindow->GetCrypto(getter_AddRefs(crypto));
00451     if (!crypto) {
00452       return NS_OK; // nope, it doesn't have a crypto property
00453     }
00454 
00455     PRBool boolrv;
00456     crypto->GetEnableSmartCardEvents(&boolrv);
00457     if (!boolrv) {
00458       return NS_OK; // nope, it's not enabled.
00459     }
00460   }
00461 
00462   // dispatch the event ...
00463 
00464   nsresult rv;
00465   // find the document
00466   nsCOMPtr<nsIDOMDocument> doc;
00467   rv = domWin->GetDocument(getter_AddRefs(doc));
00468   if (doc == nsnull) {
00469     return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
00470   }
00471 
00472   // create the event
00473   nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(doc, &rv);
00474   if (NS_FAILED(rv)) {
00475     return rv;
00476   }
00477 
00478   nsCOMPtr<nsIDOMEvent> event;
00479   rv = docEvent->CreateEvent(NS_LITERAL_STRING("Events"), 
00480                              getter_AddRefs(event));
00481   if (NS_FAILED(rv)) {
00482     return rv;
00483   }
00484 
00485   event->InitEvent(eventType, false, true);
00486 
00487   // create the Smart Card Event;
00488   nsCOMPtr<nsIDOMSmartCardEvent> smartCardEvent = 
00489                                           new nsSmartCardEvent(tokenName);
00490   // init the smart card event, fail here if we can't complete the 
00491   // initialization.
00492   if (!smartCardEvent) {
00493     return NS_ERROR_OUT_OF_MEMORY;
00494   }
00495 
00496   rv = smartCardEvent->Init(event);
00497   if (NS_FAILED(rv)) {
00498     return rv;
00499   }
00500 
00501   // Send it 
00502   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(doc, &rv);
00503   if (NS_FAILED(rv)) {
00504     return rv;
00505   }
00506 
00507   PRBool boolrv;
00508   rv = target->DispatchEvent(smartCardEvent, &boolrv);
00509   return rv;
00510 }
00511 
00512 
00513 static void setOCSPOptions(nsIPrefBranch * pref);
00514 
00515 NS_IMETHODIMP
00516 nsNSSComponent::PIPBundleFormatStringFromName(const char *name,
00517                                               const PRUnichar **params,
00518                                               PRUint32 numParams,
00519                                               nsAString &outString)
00520 {
00521   nsresult rv = NS_ERROR_FAILURE;
00522 
00523   if (mPIPNSSBundle && name) {
00524     nsXPIDLString result;
00525     rv = mPIPNSSBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(name).get(),
00526                                              params, numParams,
00527                                              getter_Copies(result));
00528     if (NS_SUCCEEDED(rv)) {
00529       outString = result;
00530     }
00531   }
00532   return rv;
00533 }
00534 
00535 NS_IMETHODIMP
00536 nsNSSComponent::GetPIPNSSBundleString(const char *name,
00537                                       nsAString &outString)
00538 {
00539   nsresult rv = NS_ERROR_FAILURE;
00540 
00541   outString.SetLength(0);
00542   if (mPIPNSSBundle && name) {
00543     nsXPIDLString result;
00544     rv = mPIPNSSBundle->GetStringFromName(NS_ConvertASCIItoUTF16(name).get(),
00545                                           getter_Copies(result));
00546     if (NS_SUCCEEDED(rv)) {
00547       outString = result;
00548       rv = NS_OK;
00549     }
00550   }
00551 
00552   return rv;
00553 }
00554 
00555 
00556 NS_IMETHODIMP
00557 nsNSSComponent::SkipOcsp()
00558 {
00559   nsNSSShutDownPreventionLock locker;
00560   CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
00561 
00562   SECStatus rv = CERT_DisableOCSPChecking(certdb);
00563   return (rv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
00564 }
00565 
00566 NS_IMETHODIMP
00567 nsNSSComponent::SkipOcspOff()
00568 {
00569   setOCSPOptions(mPrefBranch);
00570   return NS_OK;
00571 }
00572 
00573 void
00574 nsNSSComponent::LaunchSmartCardThreads()
00575 {
00576   nsNSSShutDownPreventionLock locker;
00577   {
00578     SECMODModuleList *list = SECMOD_GetDefaultModuleList();
00579     SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
00580     SECMOD_GetReadLock(lock);
00581 
00582     while (list) {
00583       SECMODModule *module = list->module;
00584       LaunchSmartCardThread(module);
00585       list = list->next;
00586     }
00587     SECMOD_ReleaseReadLock(lock);
00588   }
00589 }
00590 
00591 NS_IMETHODIMP
00592 nsNSSComponent::LaunchSmartCardThread(SECMODModule *module)
00593 {
00594   SmartCardMonitoringThread *newThread;
00595   if (SECMOD_HasRemovableSlots(module)) {
00596     if (mThreadList == nsnull) {
00597       mThreadList = new SmartCardThreadList();
00598       if (!mThreadList) {
00599         return NS_ERROR_OUT_OF_MEMORY;
00600       }
00601     }
00602     newThread = new SmartCardMonitoringThread(module);
00603     if (!newThread) {
00604        return NS_ERROR_OUT_OF_MEMORY;
00605     }
00606     // newThread is adopted by the add.
00607     return mThreadList->Add(newThread);
00608   }
00609   return NS_OK;
00610 }
00611 
00612 NS_IMETHODIMP
00613 nsNSSComponent::ShutdownSmartCardThread(SECMODModule *module)
00614 {
00615   if (!mThreadList) {
00616     return NS_OK;
00617   }
00618   mThreadList->Remove(module);
00619   return NS_OK;
00620 }
00621 
00622 void
00623 nsNSSComponent::ShutdownSmartCardThreads()
00624 {
00625   delete mThreadList;
00626   mThreadList = nsnull;
00627 }
00628 
00629 void
00630 nsNSSComponent::InstallLoadableRoots()
00631 {
00632   nsNSSShutDownPreventionLock locker;
00633   SECMODModule *RootsModule = nsnull;
00634 
00635   {
00636     // Find module containing root certs
00637 
00638     SECMODModuleList *list = SECMOD_GetDefaultModuleList();
00639     SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
00640     SECMOD_GetReadLock(lock);
00641 
00642     while (!RootsModule && list) {
00643       SECMODModule *module = list->module;
00644 
00645       for (int i=0; i < module->slotCount; i++) {
00646         PK11SlotInfo *slot = module->slots[i];
00647         if (PK11_IsPresent(slot)) {
00648           if (PK11_HasRootCerts(slot)) {
00649             RootsModule = SECMOD_ReferenceModule(module);
00650             break;
00651           }
00652         }
00653       }
00654 
00655       list = list->next;
00656     }
00657     SECMOD_ReleaseReadLock(lock);
00658   }
00659 
00660   if (RootsModule) {
00661     // Check version, and unload module if it is too old
00662 
00663     CK_INFO info;
00664     if (SECSuccess != PK11_GetModInfo(RootsModule, &info)) {
00665       // Do not use this module
00666       SECMOD_DestroyModule(RootsModule);
00667       RootsModule = nsnull;
00668     }
00669     else {
00670       // NSS_BUILTINS_LIBRARY_VERSION_MAJOR and NSS_BUILTINS_LIBRARY_VERSION_MINOR
00671       // define the version we expect to have.
00672       // Later version are fine.
00673       // Older versions are not ok, and we will replace with our own version.
00674 
00675       if (
00676             (info.libraryVersion.major < NSS_BUILTINS_LIBRARY_VERSION_MAJOR)
00677           || 
00678             (info.libraryVersion.major == NSS_BUILTINS_LIBRARY_VERSION_MAJOR
00679              && info.libraryVersion.minor < NSS_BUILTINS_LIBRARY_VERSION_MINOR)
00680          ) {
00681         PRInt32 modType;
00682         SECMOD_DeleteModule(RootsModule->commonName, &modType);
00683         SECMOD_DestroyModule(RootsModule);
00684 
00685         RootsModule = nsnull;
00686       }
00687     }
00688   }
00689 
00690   if (RootsModule) {
00691     SECMOD_DestroyModule(RootsModule);
00692   } else { /* !RootsModule */
00693     // Load roots module from our installation path
00694   
00695     nsresult rv;
00696     nsAutoString modName;
00697     rv = GetPIPNSSBundleString("RootCertModuleName", modName);
00698     if (NS_FAILED(rv)) return;
00699 
00700     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
00701     if (!directoryService)
00702       return;
00703 
00704     const char *possible_ckbi_locations[] = {
00705       NS_GRE_DIR,
00706       NS_XPCOM_CURRENT_PROCESS_DIR,
00707       0 // This special value means: 
00708         //   search for ckbi in the directories on the shared
00709         //   library/DLL search path
00710     };
00711 
00712     for (size_t il = 0; il < sizeof(possible_ckbi_locations)/sizeof(const char*); ++il) {
00713       nsCOMPtr<nsILocalFile> mozFile;
00714       char *fullModuleName = nsnull;
00715 
00716       if (!possible_ckbi_locations[il])
00717       {
00718         fullModuleName = PR_GetLibraryName(nsnull, "nssckbi");
00719       }
00720       else
00721       {
00722         directoryService->Get( possible_ckbi_locations[il],
00723                                NS_GET_IID(nsILocalFile), 
00724                                getter_AddRefs(mozFile));
00725     
00726         if (!mozFile) {
00727           continue;
00728         }
00729 
00730         nsCAutoString processDir;
00731         mozFile->GetNativePath(processDir);
00732         fullModuleName = PR_GetLibraryName(processDir.get(), "nssckbi");
00733       }
00734 
00735       /* If a module exists with the same name, delete it. */
00736       NS_ConvertUCS2toUTF8 modNameUTF8(modName);
00737       int modType;
00738       SECMOD_DeleteModule(NS_CONST_CAST(char*, modNameUTF8.get()), &modType);
00739       SECStatus rv_add = 
00740         SECMOD_AddNewModule(NS_CONST_CAST(char*, modNameUTF8.get()), fullModuleName, 0, 0);
00741       PR_FreeLibraryName(fullModuleName); // allocated by NSPR
00742       if (SECSuccess == rv_add) {
00743         // found a module, no need to try other directories
00744         break;
00745       }
00746     }
00747   }
00748 }
00749 
00750 nsresult
00751 nsNSSComponent::ConfigureInternalPKCS11Token()
00752 {
00753   nsNSSShutDownPreventionLock locker;
00754   nsAutoString manufacturerID;
00755   nsAutoString libraryDescription;
00756   nsAutoString tokenDescription;
00757   nsAutoString privateTokenDescription;
00758   nsAutoString slotDescription;
00759   nsAutoString privateSlotDescription;
00760   nsAutoString fipsSlotDescription;
00761   nsAutoString fipsPrivateSlotDescription;
00762 
00763   nsresult rv;
00764   rv = GetPIPNSSBundleString("ManufacturerID", manufacturerID);
00765   if (NS_FAILED(rv)) return rv;
00766 
00767   rv = GetPIPNSSBundleString("LibraryDescription", libraryDescription);
00768   if (NS_FAILED(rv)) return rv;
00769 
00770   rv = GetPIPNSSBundleString("TokenDescription", tokenDescription);
00771   if (NS_FAILED(rv)) return rv;
00772 
00773   rv = GetPIPNSSBundleString("PrivateTokenDescription", privateTokenDescription);
00774   if (NS_FAILED(rv)) return rv;
00775 
00776   rv = GetPIPNSSBundleString("SlotDescription", slotDescription);
00777   if (NS_FAILED(rv)) return rv;
00778 
00779   rv = GetPIPNSSBundleString("PrivateSlotDescription", privateSlotDescription);
00780   if (NS_FAILED(rv)) return rv;
00781 
00782   rv = GetPIPNSSBundleString("FipsSlotDescription", fipsSlotDescription);
00783   if (NS_FAILED(rv)) return rv;
00784 
00785   rv = GetPIPNSSBundleString("FipsPrivateSlotDescription", fipsPrivateSlotDescription);
00786   if (NS_FAILED(rv)) return rv;
00787 
00788   PK11_ConfigurePKCS11(NS_ConvertUCS2toUTF8(manufacturerID).get(),
00789                        NS_ConvertUCS2toUTF8(libraryDescription).get(),
00790                        NS_ConvertUCS2toUTF8(tokenDescription).get(),
00791                        NS_ConvertUCS2toUTF8(privateTokenDescription).get(),
00792                        NS_ConvertUCS2toUTF8(slotDescription).get(),
00793                        NS_ConvertUCS2toUTF8(privateSlotDescription).get(),
00794                        NS_ConvertUCS2toUTF8(fipsSlotDescription).get(),
00795                        NS_ConvertUCS2toUTF8(fipsPrivateSlotDescription).get(),
00796                        0, 0);
00797   return NS_OK;
00798 }
00799 
00800 nsresult
00801 nsNSSComponent::InitializePIPNSSBundle()
00802 {
00803   // Called during init only, no mutex required.
00804 
00805   nsresult rv;
00806   nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
00807   if (NS_FAILED(rv) || !bundleService) 
00808     return NS_ERROR_FAILURE;
00809   
00810   bundleService->CreateBundle(PIPNSS_STRBUNDLE_URL,
00811                               getter_AddRefs(mPIPNSSBundle));
00812   if (!mPIPNSSBundle)
00813     rv = NS_ERROR_FAILURE;
00814 
00815   return rv;
00816 }
00817 
00818 nsresult
00819 nsNSSComponent::RegisterPSMContentListener()
00820 {
00821   // Called during init only, no mutex required.
00822 
00823   nsresult rv = NS_OK;
00824   if (!mPSMContentListener) {
00825     nsCOMPtr<nsIURILoader> dispatcher(do_GetService(NS_URI_LOADER_CONTRACTID));
00826     if (dispatcher) {
00827       mPSMContentListener = do_CreateInstance(NS_PSMCONTENTLISTEN_CONTRACTID);
00828       rv = dispatcher->RegisterContentListener(mPSMContentListener);
00829     }
00830   }
00831   return rv;
00832 }
00833 
00834 /* Table of pref names and SSL cipher ID */
00835 typedef struct {
00836   const char* pref;
00837   long id;
00838 } CipherPref;
00839 
00840 static CipherPref CipherPrefs[] = {
00841 /* SSL2 cipher suites, all use RSA and an MD5 MAC */
00842  {"security.ssl2.rc4_128", SSL_EN_RC4_128_WITH_MD5}, // 128-bit RC4 encryption with RSA and an MD5 MAC
00843  {"security.ssl2.rc2_128", SSL_EN_RC2_128_CBC_WITH_MD5}, // 128-bit RC2 encryption with RSA and an MD5 MAC
00844  {"security.ssl2.des_ede3_192", SSL_EN_DES_192_EDE3_CBC_WITH_MD5}, // 168-bit Triple DES encryption with RSA and MD5 MAC 
00845  {"security.ssl2.des_64", SSL_EN_DES_64_CBC_WITH_MD5}, // 56-bit DES encryption with RSA and an MD5 MAC
00846  {"security.ssl2.rc4_40", SSL_EN_RC4_128_EXPORT40_WITH_MD5}, // 40-bit RC4 encryption with RSA and an MD5 MAC (export)
00847  {"security.ssl2.rc2_40", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5}, // 40-bit RC2 encryption with RSA and an MD5 MAC (export)
00848  /* Fortezza SSL3/TLS cipher suites, see bug 133502 */
00849  {"security.ssl3.fortezza_fortezza_sha", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
00850  {"security.ssl3.fortezza_rc4_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
00851  {"security.ssl3.fortezza_null_sha", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
00852  /* SSL3/TLS cipher suites*/
00853  {"security.ssl3.rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5}, // 128-bit RC4 encryption with RSA and an MD5 MAC
00854  {"security.ssl3.rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA}, // 128-bit RC4 encryption with RSA and a SHA1 MAC
00855  {"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)
00856  {"security.ssl3.rsa_des_ede3_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA}, // 168-bit Triple DES with RSA and a SHA1 MAC
00857  {"security.ssl3.rsa_fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA and a SHA1 MAC (FIPS)
00858  {"security.ssl3.rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA and a SHA1 MAC
00859  {"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)
00860  {"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)
00861  {"security.ssl3.rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5}, // 40-bit RC4 encryption with RSA and an MD5 MAC (export)
00862  {"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)
00863  /* Extra SSL3/TLS cipher suites */
00864  {"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
00865  {"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
00866  {"security.ssl3.rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA}, // 256-bit AES encryption with RSA and a SHA1 MAC
00867    /* TLS_DHE_DSS_WITH_RC4_128_SHA // 128-bit RC4 encryption with DSA, DHE, and a SHA1 MAC
00868       If this cipher gets included at a later time, it should get added at this position */
00869  {"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
00870  {"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
00871  {"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
00872  {"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
00873  {"security.ssl3.ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA}, // No encryption with ECDHE-ECDSA and a SHA1 MAC
00874  {"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
00875  {"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
00876  {"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
00877  {"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
00878  {"security.ssl3.ecdhe_rsa_null_sha", TLS_ECDHE_RSA_WITH_NULL_SHA}, // No encryption with ECDHE-RSA and a SHA1 MAC
00879  {"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
00880  {"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
00881  {"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
00882  {"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
00883  {"security.ssl3.ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA}, // No encryption with ECDH-ECDSA and a SHA1 MAC
00884  {"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
00885  {"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
00886  {"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
00887  {"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
00888  {"security.ssl3.ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA}, // No encryption with ECDH-RSA and a SHA1 MAC
00889  {"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
00890  {"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
00891  {"security.ssl3.rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA}, // 128-bit AES encryption with RSA and a SHA1 MAC
00892  {"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
00893  {"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
00894  {"security.ssl3.dhe_rsa_des_sha", SSL_DHE_RSA_WITH_DES_CBC_SHA}, // 56-bit DES encryption with RSA, DHE, and a SHA1 MAC
00895  {"security.ssl3.dhe_dss_des_sha", SSL_DHE_DSS_WITH_DES_CBC_SHA}, // 56-bit DES encryption with DSA, DHE, and a SHA1 MAC
00896  {"security.ssl3.rsa_null_sha", SSL_RSA_WITH_NULL_SHA}, // No encryption with RSA authentication and a SHA1 MAC
00897  {"security.ssl3.rsa_null_md5", SSL_RSA_WITH_NULL_MD5}, // No encryption with RSA authentication and an MD5 MAC
00898  {NULL, 0} /* end marker */
00899 };
00900 
00901 nsresult nsNSSComponent::GetNSSCipherIDFromPrefString(const nsACString &aPrefString, PRUint16 &aCipherId)
00902 {
00903   for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
00904     if (nsDependentCString(cp->pref) == aPrefString) {
00905       aCipherId = cp->id;
00906       return NS_OK;
00907     }
00908   }
00909   
00910   return NS_ERROR_NOT_AVAILABLE;
00911 }
00912 
00913 static void setOCSPOptions(nsIPrefBranch * pref)
00914 {
00915   nsNSSShutDownPreventionLock locker;
00916   // Set up OCSP //
00917   PRInt32 ocspEnabled;
00918   pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
00919   switch (ocspEnabled) {
00920   case 0:
00921     CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
00922     CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
00923     break;
00924   case 1:
00925     CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
00926     break;
00927   case 2:
00928     {
00929       char *signingCA = nsnull;
00930       char *url = nsnull;
00931 
00932       // Get the signing CA and service url //
00933       pref->GetCharPref("security.OCSP.signingCA", &signingCA);
00934       pref->GetCharPref("security.OCSP.URL", &url);
00935 
00936       // Set OCSP up
00937       CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
00938       CERT_SetOCSPDefaultResponder(CERT_GetDefaultCertDB(), url, signingCA);
00939       CERT_EnableOCSPDefaultResponder(CERT_GetDefaultCertDB());
00940 
00941       nsMemory::Free(signingCA);
00942       nsMemory::Free(url);
00943     }
00944     break;
00945   }
00946 }
00947 
00948 nsresult
00949 nsNSSComponent::PostCRLImportEvent(nsCAutoString *urlString, PSMContentDownloader *psmDownloader)
00950 {
00951   //Create the event
00952   CRLDownloadEvent *event = new CRLDownloadEvent;
00953   PL_InitEvent(event, this, (PLHandleEventProc)HandleCRLImportPLEvent, (PLDestroyEventProc)DestroyCRLImportPLEvent);
00954   event->urlString = urlString;
00955   event->psmDownloader = (nsIStreamListener *)psmDownloader;
00956   
00957   //Get a handle to the ui event queue
00958   
00959   nsCOMPtr<nsIEventQueue>uiQueue = nsNSSEventGetUIEventQueue();
00960 
00961   if (!uiQueue) {
00962     return NS_ERROR_FAILURE;
00963   }
00964 
00965   //Post the event
00966   return uiQueue->PostEvent(event);
00967 }
00968 
00969 nsresult
00970 nsNSSComponent::DownloadCRLDirectly(nsAutoString url, nsAutoString key)
00971 {
00972   //This api is meant to support direct interactive update of crl from the crl manager
00973   //or other such ui.
00974   PSMContentDownloader *psmDownloader = new PSMContentDownloader(PSMContentDownloader::PKCS7_CRL);
00975   
00976   nsCAutoString *urlString = new nsCAutoString();
00977   urlString->AssignWithConversion(url.get());
00978     
00979   return PostCRLImportEvent(urlString, psmDownloader);
00980 }
00981 
00982 nsresult nsNSSComponent::DownloadCrlSilently()
00983 {
00984   //Add this attempt to the hashtable
00985   nsStringKey hashKey(mCrlUpdateKey.get());
00986   crlsScheduledForDownload->Put(&hashKey,(void *)nsnull);
00987     
00988   //Set up the download handler
00989   PSMContentDownloader *psmDownloader = new PSMContentDownloader(PSMContentDownloader::PKCS7_CRL);
00990   psmDownloader->setSilentDownload(PR_TRUE);
00991   psmDownloader->setCrlAutodownloadKey(mCrlUpdateKey);
00992   
00993   //Now get the url string
00994   nsCAutoString *urlString = new nsCAutoString();
00995   urlString->AssignWithConversion(mDownloadURL);
00996 
00997   return PostCRLImportEvent(urlString, psmDownloader);
00998 }
00999 
01000 nsresult nsNSSComponent::getParamsForNextCrlToDownload(nsAutoString *url, PRTime *time, nsAutoString *key)
01001 {
01002   const char *updateEnabledPref = CRL_AUTOUPDATE_ENABLED_PREF;
01003   const char *updateTimePref = CRL_AUTOUPDATE_TIME_PREF;
01004   const char *updateURLPref = CRL_AUTOUPDATE_URL_PREF;
01005   char **allCrlsToBeUpdated;
01006   PRUint32 noOfCrls;
01007   PRTime nearestUpdateTime = 0;
01008   nsAutoString crlKey;
01009   char *tempUrl;
01010   nsresult rv;
01011   
01012   nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
01013   if(NS_FAILED(rv)){
01014     return rv;
01015   }
01016 
01017   rv = pref->GetChildList(updateEnabledPref, &noOfCrls, &allCrlsToBeUpdated);
01018   if ( (NS_FAILED(rv)) || (noOfCrls==0) ){
01019     return NS_ERROR_FAILURE;
01020   }
01021 
01022   for(PRUint32 i=0;i<noOfCrls;i++) {
01023     PRBool autoUpdateEnabled;
01024     nsAutoString tempCrlKey;
01025   
01026     //First check if update pref is enabled for this crl
01027     rv = pref->GetBoolPref(*(allCrlsToBeUpdated+i), &autoUpdateEnabled);
01028     if( (NS_FAILED(rv)) || (autoUpdateEnabled==PR_FALSE) ){
01029       continue;
01030     }
01031 
01032     //Now, generate the crl key. Same key would be used as hashkey as well
01033     nsCAutoString enabledPrefCString(*(allCrlsToBeUpdated+i));
01034     enabledPrefCString.ReplaceSubstring(updateEnabledPref,".");
01035     tempCrlKey.AssignWithConversion(enabledPrefCString.get());
01036       
01037     //Check if this crl has already been scheduled. Its presence in the hashtable
01038     //implies that it has been scheduled already this client session, and
01039     //is either in the process of being downloaded, or its download failed
01040     //for some reason. In the second case, we will not retry in the current client session
01041     nsStringKey hashKey(tempCrlKey.get());
01042     if(crlsScheduledForDownload->Exists(&hashKey)){
01043       continue;
01044     }
01045 
01046     char *tempTimeString;
01047     PRTime tempTime;
01048     nsCAutoString timingPrefCString(updateTimePref);
01049     timingPrefCString.AppendWithConversion(tempCrlKey);
01050     rv = pref->GetCharPref(timingPrefCString.get(), &tempTimeString);
01051     if (NS_FAILED(rv)){
01052       continue;
01053     }
01054     rv = PR_ParseTimeString(tempTimeString,PR_TRUE, &tempTime);
01055     nsMemory::Free(tempTimeString);
01056     if (NS_FAILED(rv)){
01057       continue;
01058     }
01059 
01060     if(nearestUpdateTime == 0 || tempTime < nearestUpdateTime){
01061       nsCAutoString urlPrefCString(updateURLPref);
01062       urlPrefCString.AppendWithConversion(tempCrlKey);
01063       rv = pref->GetCharPref(urlPrefCString.get(), &tempUrl);
01064       if (NS_FAILED(rv) || (!tempUrl)){
01065         continue;
01066       }
01067       nearestUpdateTime = tempTime;
01068       crlKey = tempCrlKey;
01069     }
01070   }
01071 
01072   if(noOfCrls > 0)
01073     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(noOfCrls, allCrlsToBeUpdated);
01074 
01075   if(nearestUpdateTime > 0){
01076     *time = nearestUpdateTime;
01077     url->AssignWithConversion((const char *)tempUrl);
01078     nsMemory::Free(tempUrl);
01079     *key = crlKey;
01080     rv = NS_OK;
01081   } else{
01082     rv = NS_ERROR_FAILURE;
01083   }
01084 
01085   return rv;
01086 }
01087 
01088 NS_IMETHODIMP
01089 nsNSSComponent::Notify(nsITimer *timer)
01090 {
01091   nsresult rv;
01092 
01093   //Timer has fired. So set the flag accordingly
01094   PR_Lock(mCrlTimerLock);
01095   crlDownloadTimerOn = PR_FALSE;
01096   PR_Unlock(mCrlTimerLock);
01097 
01098   //First, handle this download
01099   rv = DownloadCrlSilently();
01100 
01101   //Dont Worry if successful or not
01102   //Set the next timer
01103   DefineNextTimer();
01104   return NS_OK;
01105 }
01106 
01107 nsresult
01108 nsNSSComponent::RemoveCrlFromList(nsAutoString key)
01109 {
01110   nsStringKey hashKey(key.get());
01111   if(crlsScheduledForDownload->Exists(&hashKey)){
01112     crlsScheduledForDownload->Remove(&hashKey);
01113   }
01114   return NS_OK;
01115 }
01116 
01117 nsresult
01118 nsNSSComponent::DefineNextTimer()
01119 {
01120   PRTime nextFiring;
01121   PRTime now = PR_Now();
01122   PRUint64 diff;
01123   PRUint32 interval;
01124   PRUint32 primaryDelay = CRL_AUTOUPDATE_DEFAULT_DELAY;
01125   nsresult rv;
01126 
01127   if(!mTimer){
01128     mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
01129     if(NS_FAILED(rv))
01130       return rv;
01131   }
01132 
01133   //If some timer is already running, cancel it. Thus, the request that came last,
01134   //wins. This would ensure that in no way we end up setting two different timers
01135   //This part should be synchronized because this function might be called from separate
01136   //threads
01137 
01138   //Lock the lock
01139   PR_Lock(mCrlTimerLock);
01140 
01141   if(crlDownloadTimerOn == PR_TRUE){
01142     mTimer->Cancel();
01143   }
01144 
01145   rv = getParamsForNextCrlToDownload(&mDownloadURL, &nextFiring, &mCrlUpdateKey);
01146   //If there are no more crls to be updated any time in future
01147   if(NS_FAILED(rv)){
01148     //Free the lock and return - no error - just implies nothing to schedule
01149     PR_Unlock(mCrlTimerLock);
01150     return NS_OK;
01151   }
01152      
01153   //Define the firing interval, from NOW
01154   if ( now < nextFiring) {
01155     LL_SUB(diff,nextFiring,now);
01156     LL_L2UI(interval, diff);
01157     //Now, we are doing 32 operations - so, don't need LL_ functions...
01158     interval = interval/PR_USEC_PER_MSEC;
01159   }else {
01160     interval = primaryDelay;
01161   }
01162   
01163   mTimer->InitWithCallback(NS_STATIC_CAST(nsITimerCallback*, this), 
01164                            interval,
01165                            nsITimer::TYPE_ONE_SHOT);
01166   crlDownloadTimerOn = PR_TRUE;
01167   //Release
01168   PR_Unlock(mCrlTimerLock);
01169 
01170   return NS_OK;
01171 
01172 }
01173 
01174 //Note that the StopCRLUpdateTimer and InitializeCRLUpdateTimer functions should never be called
01175 //simultaneously from diff threads - they are NOT threadsafe. But, since there is no chance of 
01176 //that happening, there is not much benefit it trying to make it so at this point
01177 nsresult
01178 nsNSSComponent::StopCRLUpdateTimer()
01179 {
01180   
01181   //If it is at all running. 
01182   if(mUpdateTimerInitialized == PR_TRUE){
01183     if(crlsScheduledForDownload != nsnull){
01184       crlsScheduledForDownload->Reset();
01185       delete crlsScheduledForDownload;
01186       crlsScheduledForDownload = nsnull;
01187     }
01188 
01189     PR_Lock(mCrlTimerLock);
01190     if(crlDownloadTimerOn == PR_TRUE){
01191       mTimer->Cancel();
01192     }
01193     crlDownloadTimerOn = PR_FALSE;
01194     PR_Unlock(mCrlTimerLock);
01195     PR_DestroyLock(mCrlTimerLock);
01196 
01197     mUpdateTimerInitialized = PR_FALSE;
01198   }
01199 
01200   return NS_OK;
01201 }
01202 
01203 nsresult
01204 nsNSSComponent::InitializeCRLUpdateTimer()
01205 {
01206   nsresult rv;
01207     
01208   //First check if this is already initialized. Then we stop it.
01209   if(mUpdateTimerInitialized == PR_FALSE){
01210     mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
01211     if(NS_FAILED(rv)){
01212       return rv;
01213     }
01214     crlsScheduledForDownload = new nsHashtable(16, PR_TRUE);
01215     mCrlTimerLock = PR_NewLock();
01216     DefineNextTimer();
01217     mUpdateTimerInitialized = PR_TRUE;  
01218   } 
01219 
01220   return NS_OK;
01221 }
01222 
01223 #ifdef XP_MACOSX
01224 void
01225 nsNSSComponent::TryCFM2MachOMigration(nsIFile *cfmPath, nsIFile *machoPath)
01226 {
01227   // We will modify the parameters.
01228   //
01229   // If neither cert7.db, cert8.db, key3.db, are available, 
01230   // copy from filenames that were used in the old days
01231   // test for key3.db first, since a new profile might only contain cert8.db, 
01232   // but not cert7.db - this optimizes number of tests
01233 
01234   NS_NAMED_LITERAL_CSTRING(cstr_key3db, "key3.db");
01235   NS_NAMED_LITERAL_CSTRING(cstr_cert7db, "cert7.db");
01236   NS_NAMED_LITERAL_CSTRING(cstr_cert8db, "cert8.db");
01237   NS_NAMED_LITERAL_CSTRING(cstr_keydatabase3, "Key Database3");
01238   NS_NAMED_LITERAL_CSTRING(cstr_certificate7, "Certificates7");
01239   NS_NAMED_LITERAL_CSTRING(cstr_certificate8, "Certificates8");
01240 
01241   PRBool bExists;
01242   nsresult rv;
01243 
01244   nsCOMPtr<nsIFile> macho_key3db;
01245   rv = machoPath->Clone(getter_AddRefs(macho_key3db));
01246   if (NS_FAILED(rv)) {
01247     return;
01248   }
01249 
01250   macho_key3db->AppendNative(cstr_key3db);
01251   rv = macho_key3db->Exists(&bExists);
01252   if (NS_FAILED(rv) || bExists) {
01253     return;
01254   }
01255 
01256   nsCOMPtr<nsIFile> macho_cert7db;
01257   rv = machoPath->Clone(getter_AddRefs(macho_cert7db));
01258   if (NS_FAILED(rv)) {
01259     return;
01260   }
01261 
01262   macho_cert7db->AppendNative(cstr_cert7db);
01263   rv = macho_cert7db->Exists(&bExists);
01264   if (NS_FAILED(rv) || bExists) {
01265     return;
01266   }
01267 
01268   nsCOMPtr<nsIFile> macho_cert8db;
01269   rv = machoPath->Clone(getter_AddRefs(macho_cert8db));
01270   if (NS_FAILED(rv)) {
01271     return;
01272   }
01273 
01274   macho_cert8db->AppendNative(cstr_cert8db);
01275   rv = macho_cert7db->Exists(&bExists);
01276   if (NS_FAILED(rv) || bExists) {
01277     return;
01278   }
01279 
01280   // None of the new files exist. Try to copy any available old files.
01281 
01282   nsCOMPtr<nsIFile> cfm_key3;
01283   rv = cfmPath->Clone(getter_AddRefs(cfm_key3));
01284   if (NS_FAILED(rv)) {
01285     return;
01286   }
01287 
01288   cfm_key3->AppendNative(cstr_keydatabase3);
01289   rv = cfm_key3->Exists(&bExists);
01290   if (NS_FAILED(rv)) {
01291     return;
01292   }
01293 
01294   if (bExists) {
01295     cfm_key3->CopyToFollowingLinksNative(machoPath, cstr_key3db);
01296   }
01297 
01298   nsCOMPtr<nsIFile> cfm_cert7;
01299   rv = cfmPath->Clone(getter_AddRefs(cfm_cert7));
01300   if (NS_FAILED(rv)) {
01301     return;
01302   }
01303 
01304   cfm_cert7->AppendNative(cstr_certificate7);
01305   rv = cfm_cert7->Exists(&bExists);
01306   if (NS_FAILED(rv)) {
01307     return;
01308   }
01309 
01310   if (bExists) {
01311     cfm_cert7->CopyToFollowingLinksNative(machoPath, cstr_cert7db);
01312   }
01313 
01314   nsCOMPtr<nsIFile> cfm_cert8;
01315   rv = cfmPath->Clone(getter_AddRefs(cfm_cert8));
01316   if (NS_FAILED(rv)) {
01317     return;
01318   }
01319 
01320   cfm_cert8->AppendNative(cstr_certificate8);
01321   rv = cfm_cert8->Exists(&bExists);
01322   if (NS_FAILED(rv)) {
01323     return;
01324   }
01325 
01326   if (bExists) {
01327     cfm_cert8->CopyToFollowingLinksNative(machoPath, cstr_cert8db);
01328   }
01329 }
01330 #endif
01331 
01332 nsresult
01333 nsNSSComponent::InitializeNSS(PRBool showWarningBox)
01334 {
01335   // Can be called both during init and profile change.
01336   // Needs mutex protection.
01337 
01338   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::InitializeNSS\n"));
01339 
01340   // variables used for flow control within this function
01341 
01342   enum { problem_none, problem_no_rw, problem_no_security_at_all }
01343     which_nss_problem = problem_none;
01344 
01345   {
01346     nsAutoLock lock(mutex);
01347 
01348     // Init phase 1, prepare own variables used for NSS
01349 
01350     if (mNSSInitialized) {
01351       PR_ASSERT(!"Trying to initialize NSS twice"); // We should never try to 
01352                                                     // initialize NSS more than
01353                                                     // once in a process.
01354       return NS_ERROR_FAILURE;
01355     }
01356     
01357     hashTableCerts = PL_NewHashTable( 0, certHashtable_keyHash, certHashtable_keyCompare, 
01358       certHashtable_valueCompare, 0, 0 );
01359 
01360     nsresult rv;
01361     nsCAutoString profileStr;
01362     nsCOMPtr<nsIFile> profilePath;
01363 
01364     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
01365                                 getter_AddRefs(profilePath));
01366     if (NS_FAILED(rv)) {
01367       PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to get profile directory\n"));
01368       return rv;
01369     }
01370 
01371   // XP_MAC == CFM
01372   // XP_MACOSX == MachO
01373 
01374   #if defined(XP_MAC) && defined(XP_MACOSX)
01375   #error "This code assumes XP_MAC and XP_MACOSX will never be defined at the same time"
01376   #endif
01377 
01378   #if defined(XP_MAC) || defined(XP_MACOSX)
01379     // On Mac CFM we place all NSS DBs in the Security
01380     // Folder in the profile directory.
01381     nsCOMPtr<nsIFile> cfmSecurityPath;
01382     cfmSecurityPath = profilePath; // alias for easier code reading
01383     cfmSecurityPath->AppendNative(NS_LITERAL_CSTRING("Security"));
01384   #endif
01385 
01386   #if defined(XP_MAC)
01387     // on CFM, cfmSecurityPath and profilePath point to the same oject
01388     profilePath->Create(nsIFile::DIRECTORY_TYPE, 0); //This is for Mac, don't worry about
01389                                                      //permissions.
01390   #elif defined(XP_MACOSX)
01391     // On MachO, we need to access both directories,
01392     // and therefore need separate nsIFile instances.
01393     // Keep cfmSecurityPath instance, obtain new instance for MachO profilePath.
01394     rv = cfmSecurityPath->GetParent(getter_AddRefs(profilePath));
01395     if (NS_FAILED(rv))
01396       return rv;
01397   #endif
01398 
01399     rv = profilePath->GetNativePath(profileStr);
01400     if (NS_FAILED(rv)) 
01401       return rv;
01402 
01403   #if defined(XP_MACOSX)
01404     // function may modify the parameters
01405     // ignore return code from conversion, we continue anyway
01406     TryCFM2MachOMigration(cfmSecurityPath, profilePath);
01407   #endif
01408 
01409     PRBool supress_warning_preference = PR_FALSE;
01410     rv = mPrefBranch->GetBoolPref("security.suppress_nss_rw_impossible_warning", &supress_warning_preference);
01411 
01412     if (NS_FAILED(rv)) {
01413       supress_warning_preference = PR_FALSE;
01414     }
01415 
01416     // init phase 2, init calls to NSS library
01417 
01418     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization beginning\n"));
01419 
01420     // The call to ConfigureInternalPKCS11Token needs to be done before NSS is initialized, 
01421     // but affects only static data.
01422     // If we could assume i18n will not change between profiles, one call per application
01423     // run were sufficient. As I can't predict what happens in the future, let's repeat
01424     // this call for every re-init of NSS.
01425 
01426     ConfigureInternalPKCS11Token();
01427 
01428     SECStatus init_rv = ::NSS_InitReadWrite(profileStr.get());
01429 
01430     if (init_rv != SECSuccess) {
01431       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
01432 
01433       if (supress_warning_preference) {
01434         which_nss_problem = problem_none;
01435       }
01436       else {
01437         which_nss_problem = problem_no_rw;
01438       }
01439 
01440       // try to init r/o
01441       init_rv = NSS_Init(profileStr.get());
01442 
01443       if (init_rv != SECSuccess) {
01444         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init in r/o either\n"));
01445         which_nss_problem = problem_no_security_at_all;
01446 
01447         NSS_NoDB_Init(profileStr.get());
01448       }
01449     }
01450 
01451     // init phase 3, only if phase 2 was successful
01452 
01453     if (problem_no_security_at_all != which_nss_problem) {
01454 
01455       mNSSInitialized = PR_TRUE;
01456 
01457       ::NSS_SetDomesticPolicy();
01458       //  SSL_EnableCipher(SSL_RSA_WITH_NULL_MD5, SSL_ALLOWED);
01459       //  SSL_EnableCipher(SSL_RSA_WITH_NULL_SHA, SSL_ALLOWED);
01460 
01461       PK11_SetPasswordFunc(PK11PasswordPrompt);
01462 
01463       // Register an observer so we can inform NSS when these prefs change
01464       nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
01465       pbi->AddObserver("security.", this, PR_FALSE);
01466 
01467       PRBool enabled;
01468       mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
01469       SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
01470       SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
01471       mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
01472       SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
01473       mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
01474       SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
01475 
01476       // Disable any ciphers that NSS might have enabled by default
01477       for (PRUint16 i = 0; i < SSL_NumImplementedCiphers; ++i)
01478       {
01479         PRUint16 cipher_id = SSL_ImplementedCiphers[i];
01480         SSL_CipherPrefSetDefault(cipher_id, PR_FALSE);
01481       }
01482 
01483       // Now only set SSL/TLS ciphers we knew about at compile time
01484       for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
01485         mPrefBranch->GetBoolPref(cp->pref, &enabled);
01486 
01487         SSL_CipherPrefSetDefault(cp->id, enabled);
01488       }
01489 
01490       // Enable ciphers for PKCS#12
01491       SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
01492       SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
01493       SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
01494       SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
01495       SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
01496       SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
01497       SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
01498       PORT_SetUCS2_ASCIIConversionFunction(pip_ucs2_ascii_conversion_fn);
01499 
01500       // Set up OCSP //
01501       setOCSPOptions(mPrefBranch);
01502 
01503       mHttpForNSS.initTable();
01504       mHttpForNSS.registerHttpClient();
01505 
01506       InstallLoadableRoots();
01507 
01508       LaunchSmartCardThreads();
01509 
01510       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization done\n"));
01511     }
01512   }
01513 
01514   if (problem_none != which_nss_problem) {
01515     nsString message;
01516 
01517     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS problem, trying to bring up GUI error message\n"));
01518 
01519     // We might want to use different messages, depending on what failed.
01520     // For now, let's use the same message.
01521     if (showWarningBox) {
01522       ShowAlert(ai_nss_init_problem);
01523     }
01524   }
01525 
01526   return NS_OK;
01527 }
01528 
01529 nsresult
01530 nsNSSComponent::ShutdownNSS()
01531 {
01532   // Can be called both during init and profile change,
01533   // needs mutex protection.
01534   
01535   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::ShutdownNSS\n"));
01536 
01537   nsAutoLock lock(mutex);
01538   nsresult rv = NS_OK;
01539 
01540   if (hashTableCerts) {
01541     PL_HashTableEnumerateEntries(hashTableCerts, certHashtable_clearEntry, 0);
01542     PL_HashTableDestroy(hashTableCerts);
01543     hashTableCerts = nsnull;
01544   }
01545 
01546   if (mNSSInitialized) {
01547     mNSSInitialized = PR_FALSE;
01548 
01549     PK11_SetPasswordFunc((PK11PasswordFunc)nsnull);
01550     mHttpForNSS.unregisterHttpClient();
01551 
01552     if (mPrefBranch) {
01553       nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(mPrefBranch);
01554       pbi->RemoveObserver("security.", this);
01555     }
01556 
01557     ShutdownSmartCardThreads();
01558     SSL_ClearSessionCache();
01559     if (mClientAuthRememberService) {
01560       mClientAuthRememberService->ClearRememberedDecisions();
01561     }
01562     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("evaporating psm resources\n"));
01563     mShutdownObjectList->evaporateAllNSSResources();
01564     if (SECSuccess != ::NSS_Shutdown()) {
01565       PR_LOG(gPIPNSSLog, PR_LOG_ALWAYS, ("NSS SHUTDOWN FAILURE\n"));
01566       rv = NS_ERROR_FAILURE;
01567     }
01568     else {
01569       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS shutdown =====>> OK <<=====\n"));
01570     }
01571   }
01572 
01573   return rv;
01574 }
01575  
01576 NS_IMETHODIMP
01577 nsNSSComponent::Init()
01578 {
01579   // No mutex protection.
01580   // Assume Init happens before any concurrency on "this" can start.
01581 
01582   nsresult rv = NS_OK;
01583 
01584   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Beginning NSS initialization\n"));
01585 
01586   if (!mutex || !mShutdownObjectList || 
01587       !mSSLThread || !mCertVerificationThread)
01588   {
01589     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, out of memory in constructor\n"));
01590     return NS_ERROR_OUT_OF_MEMORY;
01591   }
01592 
01593   rv = InitializePIPNSSBundle();
01594   if (NS_FAILED(rv)) {
01595     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to create pipnss bundle.\n"));
01596     return rv;
01597   }      
01598 
01599   if (!mPrefBranch) {
01600     mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
01601     NS_ASSERTION(mPrefBranch, "Unable to get pref service");
01602   }
01603 
01604   // Do that before NSS init, to make sure we won't get unloaded.
01605   RegisterObservers();
01606 
01607   rv = InitializeNSS(PR_TRUE); // ok to show a warning box on failure
01608   if (NS_FAILED(rv)) {
01609     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to Initialize NSS.\n"));
01610     return rv;
01611   }
01612 
01613   InitializeCRLUpdateTimer();
01614   RegisterPSMContentListener();
01615 
01616   nsCOMPtr<nsIEntropyCollector> ec
01617       = do_GetService(NS_ENTROPYCOLLECTOR_CONTRACTID);
01618 
01619   nsCOMPtr<nsIBufEntropyCollector> bec;
01620 
01621   if (ec) {
01622     bec = do_QueryInterface(ec);
01623   }
01624 
01625   NS_ASSERTION(bec, "No buffering entropy collector.  "
01626                     "This means no entropy will be collected.");
01627   if (bec) {
01628     bec->ForwardTo(this);
01629   }
01630 
01631   return rv;
01632 }
01633 
01634 /* nsISupports Implementation for the class */
01635 NS_IMPL_THREADSAFE_ISUPPORTS6(nsNSSComponent,
01636                               nsISignatureVerifier,
01637                               nsIEntropyCollector,
01638                               nsINSSComponent,
01639                               nsIObserver,
01640                               nsISupportsWeakReference,
01641                               nsITimerCallback)
01642 
01643 
01644 /* Callback functions for decoder. For now, use empty/default functions. */
01645 static void ContentCallback(void *arg, 
01646                                            const char *buf,
01647                                            unsigned long len)
01648 {
01649 }
01650 
01651 static PK11SymKey * GetDecryptKeyCallback(void *arg, 
01652                                                  SECAlgorithmID *algid)
01653 {
01654   return nsnull;
01655 }
01656 
01657 static PRBool DecryptionAllowedCallback(SECAlgorithmID *algid,  
01658                                                PK11SymKey *bulkkey)
01659 {
01660   return SECMIME_DecryptionAllowed(algid, bulkkey);
01661 }
01662 
01663 static void * GetPasswordKeyCallback(void *arg, void *handle)
01664 {
01665   return NULL;
01666 }
01667 
01668 NS_IMETHODIMP
01669 nsNSSComponent::VerifySignature(const char* aRSABuf, PRUint32 aRSABufLen,
01670                                 const char* aPlaintext, PRUint32 aPlaintextLen,
01671                                 PRInt32* aErrorCode,
01672                                 nsIPrincipal** aPrincipal)
01673 {
01674   if (!aPrincipal || !aErrorCode) {
01675     return NS_ERROR_NULL_POINTER;
01676   }
01677 
01678   *aErrorCode = 0;
01679   *aPrincipal = nsnull;
01680 
01681   nsNSSShutDownPreventionLock locker;
01682   SEC_PKCS7ContentInfo * p7_info = nsnull; 
01683   unsigned char hash[SHA1_LENGTH]; 
01684 
01685   SECItem item;
01686   item.type = siEncodedCertBuffer;
01687   item.data = (unsigned char*)aRSABuf;
01688   item.len = aRSABufLen;
01689   p7_info = SEC_PKCS7DecodeItem(&item,
01690                                 ContentCallback, nsnull,
01691                                 GetPasswordKeyCallback, nsnull,
01692                                 GetDecryptKeyCallback, nsnull,
01693                                 DecryptionAllowedCallback);
01694 
01695   if (!p7_info) {
01696     return NS_ERROR_FAILURE;
01697   }
01698 
01699   // Make sure we call SEC_PKCS7DestroyContentInfo after this point;
01700   // otherwise we leak data in p7_info
01701   
01702   //-- If a plaintext was provided, hash it.
01703   SECItem digest;
01704   digest.data = nsnull;
01705   digest.len = 0;
01706 
01707   if (aPlaintext) {
01708     HASHContext* hash_ctxt;
01709     PRUint32 hashLen = 0;
01710 
01711     hash_ctxt = HASH_Create(HASH_AlgSHA1);
01712     HASH_Begin(hash_ctxt);
01713     HASH_Update(hash_ctxt,(const unsigned char*)aPlaintext, aPlaintextLen);
01714     HASH_End(hash_ctxt, hash, &hashLen, SHA1_LENGTH); 
01715     HASH_Destroy(hash_ctxt);
01716 
01717     digest.data = hash;
01718     digest.len = SHA1_LENGTH;
01719   }
01720 
01721   //-- Verify signature
01722   PRBool rv = SEC_PKCS7VerifyDetachedSignature(p7_info, certUsageObjectSigner,
01723                                                &digest, HASH_AlgSHA1, PR_FALSE);
01724   if (rv != PR_TRUE) {
01725     *aErrorCode = PR_GetError();
01726   }
01727 
01728   // Get the signing cert //
01729   CERTCertificate *cert = p7_info->content.signedData->signerInfos[0]->cert;
01730   nsresult rv2 = NS_OK;
01731   if (cert) {
01732     // Use |do { } while (0);| as a "more C++-ish" thing than goto;
01733     // this way we don't have to worry about goto across variable
01734     // declarations.  We have no loops in this code, so it's OK.
01735     do {
01736       nsCOMPtr<nsIX509Cert> pCert = new nsNSSCertificate(cert);
01737       if (!pCert) {
01738         rv2 = NS_ERROR_OUT_OF_MEMORY;
01739         break;
01740       }
01741 
01742       if (!mScriptSecurityManager) {
01743         nsAutoLock lock(mutex);
01744         // re-test the condition to prevent double initialization
01745         if (!mScriptSecurityManager) {
01746           mScriptSecurityManager = 
01747             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv2);
01748           if (NS_FAILED(rv2)) {
01749             break;
01750           }
01751         }
01752       }
01753 
01754       //-- Create a certificate principal with id and organization data
01755       nsAutoString fingerprint;
01756       rv2 = pCert->GetSha1Fingerprint(fingerprint);
01757       if (NS_FAILED(rv2)) {
01758         break;
01759       }
01760       nsAutoString orgName;
01761       rv2 = pCert->GetOrganization(orgName);
01762       if (NS_FAILED(rv2)) {
01763         break;
01764       }
01765       nsAutoString subjectName;
01766       rv2 = pCert->GetSubjectName(subjectName);
01767       if (NS_FAILED(rv2)) {
01768         break;
01769       }
01770     
01771       nsCOMPtr<nsIPrincipal> certPrincipal;
01772       rv2 = mScriptSecurityManager->
01773         GetCertificatePrincipal(NS_ConvertUTF16toUTF8(fingerprint),
01774                                 NS_ConvertUTF16toUTF8(subjectName),
01775                                 NS_ConvertUTF16toUTF8(orgName),
01776                                 pCert, nsnull, getter_AddRefs(certPrincipal));
01777       if (NS_FAILED(rv2) || !certPrincipal) {
01778         break;
01779       }
01780       
01781       certPrincipal.swap(*aPrincipal);
01782     } while (0);
01783   }
01784 
01785   SEC_PKCS7DestroyContentInfo(p7_info);
01786 
01787   return rv2;
01788 }
01789 
01790 NS_IMETHODIMP
01791 nsNSSComponent::RandomUpdate(void *entropy, PRInt32 bufLen)
01792 {
01793   nsNSSShutDownPreventionLock locker;
01794 
01795   // Asynchronous event happening often,
01796   // must not interfere with initialization or profile switch.
01797   
01798   nsAutoLock lock(mutex);
01799 
01800   if (!mNSSInitialized)
01801       return NS_ERROR_NOT_INITIALIZED;
01802 
01803   PK11_RandomUpdate(entropy, bufLen);
01804   return NS_OK;
01805 }
01806 
01807 #define PROFILE_CHANGE_NET_TEARDOWN_TOPIC "profile-change-net-teardown"
01808 #define PROFILE_CHANGE_NET_RESTORE_TOPIC "profile-change-net-restore"
01809 #define PROFILE_APPROVE_CHANGE_TOPIC "profile-approve-change"
01810 #define PROFILE_CHANGE_TEARDOWN_TOPIC "profile-change-teardown"
01811 #define PROFILE_CHANGE_TEARDOWN_VETO_TOPIC "profile-change-teardown-veto"
01812 #define PROFILE_BEFORE_CHANGE_TOPIC "profile-before-change"
01813 #define PROFILE_AFTER_CHANGE_TOPIC "profile-after-change"
01814 #define SESSION_LOGOUT_TOPIC "session-logout"
01815 
01816 NS_IMETHODIMP
01817 nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, 
01818                         const PRUnichar *someData)
01819 {
01820   if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) {
01821     if (mShutdownObjectList->isUIActive()) {
01822       ShowAlert(ai_crypto_ui_active);
01823       nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
01824       if (status) {
01825         status->VetoChange();
01826       }
01827     }
01828   }
01829   else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_TOPIC) == 0) {
01830     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("in PSM code, receiving change-teardown\n"));
01831 
01832     PRBool callVeto = PR_FALSE;
01833 
01834     if (!mShutdownObjectList->ifPossibleDisallowUI()) {
01835       callVeto = PR_TRUE;
01836       ShowAlert(ai_crypto_ui_active);
01837     }
01838     else if (mShutdownObjectList->areSSLSocketsActive()) {
01839       callVeto = PR_TRUE;
01840       ShowAlert(ai_sockets_still_active);
01841     }
01842 
01843     if (callVeto) {
01844       nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
01845       if (status) {
01846         status->VetoChange();
01847       }
01848     }
01849   }
01850   else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC) == 0) {
01851     mShutdownObjectList->allowUI();
01852   }
01853   else if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) {
01854     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving profile change topic\n"));
01855     NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
01856 
01857     PRBool needsCleanup = PR_TRUE;
01858 
01859     {
01860       nsAutoLock lock(mutex);
01861 
01862       if (!mNSSInitialized) {
01863         // Make sure we don't try to cleanup if we have already done so.
01864         // This makes sure we behave safely, in case we are notified
01865         // multiple times.
01866         needsCleanup = PR_FALSE;
01867       }
01868     }
01869     
01870     StopCRLUpdateTimer();
01871 
01872     if (needsCleanup) {
01873       if (NS_FAILED(ShutdownNSS())) {
01874         nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
01875         if (status) {
01876           status->ChangeFailed();
01877         }
01878       }
01879     }
01880     mShutdownObjectList->allowUI();
01881 
01882   }
01883   else if (nsCRT::strcmp(aTopic, PROFILE_AFTER_CHANGE_TOPIC) == 0) {
01884   
01885     PRBool needsInit = PR_TRUE;
01886 
01887     {
01888       nsAutoLock lock(mutex);
01889 
01890       if (mNSSInitialized) {
01891         // We have already initialized NSS before the profile came up,
01892         // no need to do it again
01893         needsInit = PR_FALSE;
01894       }
01895     }
01896     
01897     if (needsInit) {
01898       if (NS_FAILED(InitializeNSS(PR_FALSE))) { // do not show a warning box on failure
01899         PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to Initialize NSS after profile switch.\n"));
01900         nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
01901         if (status) {
01902           status->ChangeFailed();
01903         }
01904       }
01905     }
01906 
01907     InitializeCRLUpdateTimer();
01908   }
01909   else if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
01910 
01911     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent: XPCom shutdown observed\n"));
01912 
01913     // Cleanup code that requires services, it's too late in destructor.
01914 
01915     if (mPSMContentListener) {
01916       nsresult rv = NS_ERROR_FAILURE;
01917 
01918       nsCOMPtr<nsIURILoader> dispatcher(do_GetService(NS_URI_LOADER_CONTRACTID));
01919       if (dispatcher) {
01920         rv = dispatcher->UnRegisterContentListener(mPSMContentListener);
01921       }
01922       mPSMContentListener = nsnull;
01923     }
01924 
01925     nsCOMPtr<nsIEntropyCollector> ec
01926         = do_GetService(NS_ENTROPYCOLLECTOR_CONTRACTID);
01927 
01928     if (ec) {
01929       nsCOMPtr<nsIBufEntropyCollector> bec
01930         = do_QueryInterface(ec);
01931       if (bec) {
01932         bec->DontForward();
01933       }
01934     }
01935   }
01936   else if ((nsCRT::strcmp(aTopic, SESSION_LOGOUT_TOPIC) == 0) && mNSSInitialized) {
01937     nsNSSShutDownPreventionLock locker;
01938     PK11_LogoutAll();
01939     SSL_ClearSessionCache();
01940     LogoutAuthenticatedPK11();
01941   }
01942   else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) { 
01943     nsNSSShutDownPreventionLock locker;
01944     PRBool enabled;
01945     NS_ConvertUCS2toUTF8  prefName(someData);
01946 
01947     if (prefName.Equals("security.enable_ssl2")) {
01948       mPrefBranch->GetBoolPref("security.enable_ssl2", &enabled);
01949       SSL_OptionSetDefault(SSL_ENABLE_SSL2, enabled);
01950       SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, enabled);
01951     } else if (prefName.Equals("security.enable_ssl3")) {
01952       mPrefBranch->GetBoolPref("security.enable_ssl3", &enabled);
01953       SSL_OptionSetDefault(SSL_ENABLE_SSL3, enabled);
01954     } else if (prefName.Equals("security.enable_tls")) {
01955       mPrefBranch->GetBoolPref("security.enable_tls", &enabled);
01956       SSL_OptionSetDefault(SSL_ENABLE_TLS, enabled);
01957     } else if (prefName.Equals("security.OCSP.enabled")) {
01958       setOCSPOptions(mPrefBranch);
01959     } else {
01960       /* Look through the cipher table and set according to pref setting */
01961       for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
01962         if (prefName.Equals(cp->pref)) {
01963           mPrefBranch->GetBoolPref(cp->pref, &enabled);
01964           SSL_CipherPrefSetDefault(cp->id, enabled);
01965           break;
01966         }
01967       }
01968     }
01969   }
01970   else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) {
01971     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n"));
01972     if (mSSLThread)
01973       mSSLThread->requestExit();
01974     if (mCertVerificationThread)
01975       mCertVerificationThread->requestExit();
01976     mIsNetworkDown = PR_TRUE;
01977   }
01978   else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_RESTORE_TOPIC) == 0) {
01979     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network restore topic\n"));
01980     delete mSSLThread;
01981     mSSLThread = new nsSSLThread();
01982     if (mSSLThread)
01983       mSSLThread->startThread();
01984     delete mCertVerificationThread;
01985     mCertVerificationThread = new nsCertVerificationThread();
01986     if (mCertVerificationThread)
01987       mCertVerificationThread->startThread();
01988     mIsNetworkDown = PR_FALSE;
01989   }
01990 
01991   return NS_OK;
01992 }
01993 
01994 void nsNSSComponent::ShowAlert(AlertIdentifier ai)
01995 {
01996   nsString message;
01997   nsresult rv;
01998 
01999   switch (ai) {
02000     case ai_nss_init_problem:
02001       rv = GetPIPNSSBundleString("NSSInitProblem", message);
02002       break;
02003     case ai_sockets_still_active:
02004       rv = GetPIPNSSBundleString("ProfileSwitchSocketsStillActive", message);
02005       break;
02006     case ai_crypto_ui_active:
02007       rv = GetPIPNSSBundleString("ProfileSwitchCryptoUIActive", message);
02008       break;
02009     case ai_incomplete_logout:
02010       rv = GetPIPNSSBundleString("LogoutIncompleteUIActive", message);
02011       break;
02012     default:
02013       return;
02014   }
02015   
02016   if (NS_FAILED(rv))
02017     return;
02018 
02019   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
02020   if (!wwatch) {
02021     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can't get window watcher\n"));
02022   }
02023   else {
02024     nsCOMPtr<nsIPrompt> prompter;
02025     wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
02026     if (!prompter) {
02027       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can't get window prompter\n"));
02028     }
02029     else {
02030       nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
02031       if (!proxyman) {
02032         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can't get proxy manager\n"));
02033       }
02034       else {
02035         nsCOMPtr<nsIPrompt> proxyPrompt;
02036         proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIPrompt),
02037                                     prompter, PROXY_SYNC, getter_AddRefs(proxyPrompt));
02038         if (!proxyPrompt) {
02039           PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can't get proxy for nsIPrompt\n"));
02040         }
02041         else {
02042           proxyPrompt->Alert(nsnull, message.get());
02043         }
02044       }
02045     }
02046   }
02047 }
02048 
02049 nsresult nsNSSComponent::LogoutAuthenticatedPK11()
02050 {
02051   if (mClientAuthRememberService) {
02052     mClientAuthRememberService->ClearRememberedDecisions();
02053   }
02054   return mShutdownObjectList->doPK11Logout();
02055 }
02056 
02057 nsresult
02058 nsNSSComponent::RegisterObservers()
02059 {
02060   // Happens once during init only, no mutex protection.
02061 
02062   nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
02063   NS_ASSERTION(observerService, "could not get observer service");
02064   if (observerService) {
02065     mObserversRegistered = PR_TRUE;
02066     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent: adding observers\n"));
02067 
02068     // We are a service.
02069     // Once we are loaded, don't allow being removed from memory.
02070     // This makes sense, as initializing NSS is expensive.
02071 
02072     // By using PR_FALSE for parameter ownsWeak in AddObserver,
02073     // we make sure that we won't get unloaded until the application shuts down.
02074 
02075     observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
02076 
02077     observerService->AddObserver(this, PROFILE_APPROVE_CHANGE_TOPIC, PR_FALSE);
02078     observerService->AddObserver(this, PROFILE_CHANGE_TEARDOWN_TOPIC, PR_FALSE);
02079     observerService->AddObserver(this, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC, PR_FALSE);
02080     observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, PR_FALSE);
02081     observerService->AddObserver(this, PROFILE_AFTER_CHANGE_TOPIC, PR_FALSE);
02082     observerService->AddObserver(this, SESSION_LOGOUT_TOPIC, PR_FALSE);
02083     observerService->AddObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC, PR_FALSE);
02084     observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, PR_FALSE);
02085   }
02086   return NS_OK;
02087 }
02088 
02089 NS_IMETHODIMP
02090 nsNSSComponent::RememberCert(CERTCertificate *cert)
02091 {
02092   nsNSSShutDownPreventionLock locker;
02093 
02094   // Must not interfere with init / shutdown / profile switch.
02095 
02096   nsAutoLock lock(mutex);
02097 
02098   if (!hashTableCerts || !cert)
02099     return NS_OK;
02100   
02101   void *found = PL_HashTableLookup(hashTableCerts, (void*)&cert->certKey);
02102   
02103   if (found) {
02104     // we remember that cert already
02105     return NS_OK;
02106   }
02107   
02108   CERTCertificate *myDupCert = CERT_DupCertificate(cert);
02109   
02110   if (!myDupCert)
02111     return NS_ERROR_OUT_OF_MEMORY;
02112   
02113   if (!PL_HashTableAdd(hashTableCerts, (void*)&myDupCert->certKey, myDupCert)) {
02114     CERT_DestroyCertificate(myDupCert);
02115   }
02116   
02117   return NS_OK;
02118 }
02119 
02120 NS_IMETHODIMP
02121 nsNSSComponent::GetClientAuthRememberService(nsClientAuthRememberService **cars)
02122 {
02123   NS_ENSURE_ARG_POINTER(cars);
02124   NS_IF_ADDREF(*cars = mClientAuthRememberService);
02125   return NS_OK;
02126 }
02127 
02128 //---------------------------------------------
02129 // Implementing nsICryptoHash
02130 //---------------------------------------------
02131 
02132 nsCryptoHash::nsCryptoHash()
02133   : mHashContext(nsnull)
02134 {
02135 }
02136 
02137 nsCryptoHash::~nsCryptoHash()
02138 {
02139   if (mHashContext)
02140     HASH_Destroy(mHashContext);
02141 }
02142 
02143 NS_IMPL_ISUPPORTS1(nsCryptoHash, nsICryptoHash)
02144 
02145 NS_IMETHODIMP 
02146 nsCryptoHash::Init(PRUint32 algorithm)
02147 {
02148   if (mHashContext)
02149     HASH_Destroy(mHashContext);
02150 
02151   mHashContext = HASH_Create((HASH_HashType) algorithm);
02152   if (!mHashContext)
02153     return NS_ERROR_INVALID_ARG;
02154 
02155   HASH_Begin(mHashContext);
02156   return NS_OK; 
02157 }
02158 
02159 NS_IMETHODIMP
02160 nsCryptoHash::InitWithString(const nsACString & aAlgorithm)
02161 {
02162   if (aAlgorithm.LowerCaseEqualsLiteral("md2"))
02163     return Init(nsICryptoHash::MD2);
02164 
02165   if (aAlgorithm.LowerCaseEqualsLiteral("md5"))
02166     return Init(nsICryptoHash::MD5);
02167 
02168   if (aAlgorithm.LowerCaseEqualsLiteral("sha1"))
02169     return Init(nsICryptoHash::SHA1);
02170 
02171   if (aAlgorithm.LowerCaseEqualsLiteral("sha256"))
02172     return Init(nsICryptoHash::SHA256);
02173 
02174   if (aAlgorithm.LowerCaseEqualsLiteral("sha384"))
02175     return Init(nsICryptoHash::SHA384);
02176 
02177   if (aAlgorithm.LowerCaseEqualsLiteral("sha512"))
02178     return Init(nsICryptoHash::SHA512);
02179 
02180   return NS_ERROR_INVALID_ARG;
02181 }
02182 
02183 NS_IMETHODIMP
02184 nsCryptoHash::Update(const PRUint8 *data, PRUint32 len)
02185 {
02186   if (!mHashContext)
02187     return NS_ERROR_NOT_INITIALIZED;
02188 
02189   HASH_Update(mHashContext, data, len);
02190   return NS_OK; 
02191 }
02192 
02193 NS_IMETHODIMP
02194 nsCryptoHash::UpdateFromStream(nsIInputStream *data, PRUint32 len)
02195 {
02196   if (!mHashContext)
02197     return NS_ERROR_NOT_INITIALIZED;
02198 
02199   if (!data)
02200     return NS_ERROR_INVALID_ARG;
02201 
02202   PRUint32 n;
02203   nsresult rv = data->Available(&n);
02204   if (NS_FAILED(rv))
02205     return rv;
02206 
02207   // if the user has passed PR_UINT32_MAX, then read
02208   // everything in the stream
02209 
02210   if (len == PR_UINT32_MAX)
02211     len = n;
02212 
02213   // So, if the stream has NO data available for the hash,
02214   // or if the data available is less then what the caller
02215   // requested, we can not fulfill the hash update.  In this
02216   // case, just return NS_ERROR_NOT_AVAILABLE indicating
02217   // that there is not enough data in the stream to satisify
02218   // the request.
02219 
02220   if (n == 0 || n < len)
02221     return NS_ERROR_NOT_AVAILABLE;
02222   
02223   char buffer[NS_CRYPTO_HASH_BUFFER_SIZE];
02224   PRUint32 read;
02225   
02226   while(NS_SUCCEEDED(rv) && len>0)
02227   {
02228     read = PR_MIN(NS_CRYPTO_HASH_BUFFER_SIZE, len);
02229     
02230     rv = data->Read(buffer, read, &read);
02231     
02232     if (NS_SUCCEEDED(rv))
02233       rv = Update((const PRUint8*)buffer, read);
02234     
02235     len -= read;
02236   }
02237   
02238   return rv;
02239 }
02240 
02241 NS_IMETHODIMP
02242 nsCryptoHash::Finish(PRBool ascii, nsACString & _retval)
02243 {
02244   if (!mHashContext)
02245     return NS_ERROR_NOT_INITIALIZED;
02246   
02247   PRUint32 hashLen = 0;
02248   unsigned char buffer[HASH_LENGTH_MAX];
02249   unsigned char* pbuffer = buffer;
02250 
02251   HASH_End(mHashContext, pbuffer, &hashLen, HASH_LENGTH_MAX);
02252   HASH_Destroy(mHashContext);
02253 
02254   mHashContext = nsnull;
02255 
02256   if (ascii)
02257   {
02258     char *asciiData = BTOA_DataToAscii(buffer, hashLen);
02259     _retval.Assign(asciiData);
02260     PORT_Free(asciiData);
02261   }
02262   else
02263   {
02264     _retval.Assign((const char*)buffer, hashLen);
02265   }
02266 
02267   return NS_OK;
02268 }
02269 
02270 
02271 NS_IMPL_ISUPPORTS1(PipUIContext, nsIInterfaceRequestor)
02272 
02273 PipUIContext::PipUIContext()
02274 {
02275 }
02276 
02277 PipUIContext::~PipUIContext()
02278 {
02279 }
02280 
02281 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
02282 NS_IMETHODIMP PipUIContext::GetInterface(const nsIID & uuid, void * *result)
02283 {
02284   nsresult rv = NS_OK;
02285 
02286   if (uuid.Equals(NS_GET_IID(nsIPrompt))) {
02287     nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
02288     if (!proxyman) return NS_ERROR_FAILURE;
02289 
02290     nsCOMPtr<nsIPrompt> prompter;
02291     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
02292     if (wwatch) {
02293       wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
02294       if (prompter) {
02295         nsCOMPtr<nsIPrompt> proxyPrompt;
02296         proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIPrompt),
02297                                     prompter, PROXY_SYNC, getter_AddRefs(proxyPrompt));
02298         if (!proxyPrompt) return NS_ERROR_FAILURE;
02299         *result = proxyPrompt;
02300         NS_ADDREF((nsIPrompt*)*result);
02301       }
02302     }
02303   } else {
02304     rv = NS_ERROR_NO_INTERFACE;
02305   }
02306 
02307   return rv;
02308 }
02309 
02310 nsresult 
02311 getNSSDialogs(void **_result, REFNSIID aIID, const char *contract)
02312 {
02313   nsresult rv;
02314 
02315   nsCOMPtr<nsISupports> svc = do_GetService(contract, &rv);
02316   if (NS_FAILED(rv)) 
02317     return rv;
02318 
02319   nsCOMPtr<nsIProxyObjectManager> proxyman =
02320       do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
02321   if (NS_FAILED(rv))
02322     return rv;
02323  
02324   rv = proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
02325                                    aIID, svc, PROXY_SYNC,
02326                                    _result);
02327   return rv;
02328 }
02329 
02330 nsresult
02331 setPassword(PK11SlotInfo *slot, nsIInterfaceRequestor *ctx)
02332 {
02333   nsNSSShutDownPreventionLock locker;
02334   nsresult rv = NS_OK;
02335   
02336   if (PK11_NeedUserInit(slot)) {
02337     nsITokenPasswordDialogs *dialogs;
02338     PRBool canceled;
02339     NS_ConvertUTF8toUCS2 tokenName(PK11_GetTokenName(slot));
02340 
02341     rv = getNSSDialogs((void**)&dialogs,
02342                        NS_GET_IID(nsITokenPasswordDialogs),
02343                        NS_TOKENPASSWORDSDIALOG_CONTRACTID);
02344 
02345     if (NS_FAILED(rv)) goto loser;
02346 
02347     {
02348       nsPSMUITracker tracker;
02349       if (tracker.isUIForbidden()) {
02350         rv = NS_ERROR_NOT_AVAILABLE;
02351       }
02352       else {
02353         rv = dialogs->SetPassword(ctx,
02354                                   tokenName.get(),
02355                                   &canceled);
02356       }
02357     }
02358     NS_RELEASE(dialogs);
02359     if (NS_FAILED(rv)) goto loser;
02360 
02361     if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
02362   }
02363  loser:
02364   return rv;
02365 }
02366 
02367 
02368 PSMContentDownloader::PSMContentDownloader(PRUint32 type)
02369   : mByteData(nsnull),
02370     mType(type),
02371     mDoSilentDownload(PR_FALSE)
02372 {
02373 }
02374 
02375 PSMContentDownloader::~PSMContentDownloader()
02376 {
02377   if (mByteData)
02378     nsMemory::Free(mByteData);
02379 }
02380 
02381 /*NS_IMPL_ISUPPORTS1(CertDownloader, nsIStreamListener)*/
02382 NS_IMPL_ISUPPORTS1(PSMContentDownloader,nsIStreamListener)
02383 
02384 const PRInt32 kDefaultCertAllocLength = 2048;
02385 
02386 NS_IMETHODIMP
02387 PSMContentDownloader::OnStartRequest(nsIRequest* request, nsISupports* context)
02388 {
02389   nsresult rv;
02390   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDownloader::OnStartRequest\n"));
02391   nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
02392   if (!channel) return NS_ERROR_FAILURE;
02393 
02394   // Get the URI //
02395   channel->GetURI(getter_AddRefs(mURI));
02396 
02397   PRInt32 contentLength;
02398   rv = channel->GetContentLength(&contentLength);
02399   if (NS_FAILED(rv) || contentLength <= 0)
02400     contentLength = kDefaultCertAllocLength;
02401   
02402   mBufferOffset = 0;
02403   mBufferSize = 0;
02404   mByteData = (char*) nsMemory::Alloc(contentLength);
02405   if (!mByteData)
02406     return NS_ERROR_OUT_OF_MEMORY;
02407   
02408   mBufferSize = contentLength;
02409   return NS_OK;
02410 }
02411 
02412 NS_IMETHODIMP
02413 PSMContentDownloader::OnDataAvailable(nsIRequest* request,
02414                                 nsISupports* context,
02415                                 nsIInputStream *aIStream,
02416                                 PRUint32 aSourceOffset,
02417                                 PRUint32 aLength)
02418 {
02419   if (!mByteData)
02420     return NS_ERROR_OUT_OF_MEMORY;
02421   
02422   PRUint32 amt;
02423   nsresult err;
02424   //Do a check to see if we need to allocate more memory.
02425   if ((mBufferOffset + (PRInt32)aLength) > mBufferSize) {
02426       size_t newSize = (mBufferOffset + aLength) *2; // grow some more than needed
02427       char *newBuffer;
02428       newBuffer = (char*)nsMemory::Realloc(mByteData, newSize);
02429       if (newBuffer == nsnull) {
02430         return NS_ERROR_OUT_OF_MEMORY;
02431       }
02432       mByteData = newBuffer;
02433       mBufferSize = newSize;
02434   }
02435   
02436   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDownloader::OnDataAvailable\n"));
02437   do {
02438     err = aIStream->Read(mByteData+mBufferOffset,
02439                          aLength, &amt);
02440     if (NS_FAILED(err)) return err;
02441     if (amt == 0) break;
02442     
02443     aLength -= amt;
02444     mBufferOffset += amt;
02445     
02446   } while (aLength > 0);
02447   
02448   return NS_OK;
02449 }
02450 
02451 NS_IMETHODIMP
02452 PSMContentDownloader::OnStopRequest(nsIRequest* request,
02453                               nsISupports* context,
02454                               nsresult aStatus)
02455 {
02456   nsNSSShutDownPreventionLock locker;
02457   //Check if the download succeeded - it might have failed due to
02458   //network issues, etc.
02459   if (NS_FAILED(aStatus)){
02460     handleContentDownloadError(aStatus);
02461     return aStatus;
02462   }
02463 
02464   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CertDownloader::OnStopRequest\n"));
02465 
02466   nsCOMPtr<nsIX509CertDB> certdb;
02467   nsCOMPtr<nsICRLManager> crlManager;
02468 
02469   nsresult rv;
02470   nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
02471 
02472   switch (mType) {
02473   case PSMContentDownloader::X509_CA_CERT:
02474   case PSMContentDownloader::X509_USER_CERT:
02475   case PSMContentDownloader::X509_EMAIL_CERT:
02476     certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
02477     break;
02478 
02479   case PSMContentDownloader::PKCS7_CRL:
02480     crlManager = do_GetService(NS_CRLMANAGER_CONTRACTID);
02481 
02482   default:
02483     break;
02484   }
02485 
02486   switch (mType) {
02487   case PSMContentDownloader::X509_CA_CERT:
02488     return certdb->ImportCertificates((PRUint8*)mByteData, mBufferOffset, mType, ctx); 
02489   case PSMContentDownloader::X509_USER_CERT:
02490     return certdb->ImportUserCertificate((PRUint8*)mByteData, mBufferOffset, ctx);
02491   case PSMContentDownloader::X509_EMAIL_CERT:
02492     return certdb->ImportEmailCertificate((PRUint8*)mByteData, mBufferOffset, ctx); 
02493   case PSMContentDownloader::PKCS7_CRL:
02494     return crlManager->ImportCrl((PRUint8*)mByteData, mBufferOffset, mURI, SEC_CRL_TYPE, mDoSilentDownload, mCrlAutoDownloadKey.get());
02495   default:
02496     rv = NS_ERROR_FAILURE;
02497     break;
02498   }
02499   
02500   return rv;
02501 }
02502 
02503 
02504 nsresult
02505 PSMContentDownloader::handleContentDownloadError(nsresult errCode)
02506 {
02507   nsString tmpMessage;
02508   nsresult rv;
02509   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
02510   if(NS_FAILED(rv)){
02511     return rv;
02512   }
02513       
02514   //Handling errors for crl download only, for now.
02515   switch (mType){
02516   case PSMContentDownloader::PKCS7_CRL:
02517 
02518     //TO DO: Handle network errors in details
02519     //XXXXXXXXXXXXXXXXXX
02520     nssComponent->GetPIPNSSBundleString("CrlImportFailureNetworkProblem", tmpMessage);
02521       
02522     if(mDoSilentDownload == PR_TRUE){
02523       //This is the case for automatic download. Update failure history
02524       nsCAutoString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
02525       nsCAutoString updateErrDetailPrefStr(CRL_AUTOUPDATE_ERRDETAIL_PREF);
02526       PRUnichar *nameInDb;
02527       nsCString errMsg;
02528       PRInt32 errCnt;
02529 
02530       nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
02531       if(NS_FAILED(rv)){
02532         return rv;
02533       }
02534       
02535       nameInDb = (PRUnichar *)mCrlAutoDownloadKey.get();
02536       updateErrCntPrefStr.AppendWithConversion(nameInDb);
02537       updateErrDetailPrefStr.AppendWithConversion(nameInDb);  
02538       errMsg.AssignWithConversion(tmpMessage.get());
02539       
02540       rv = pref->GetIntPref(updateErrCntPrefStr.get(),&errCnt);
02541       if( (NS_FAILED(rv)) || (errCnt == 0) ){
02542         pref->SetIntPref(updateErrCntPrefStr.get(),1);
02543       }else{
02544         pref->SetIntPref(updateErrCntPrefStr.get(),errCnt+1);
02545       }
02546       pref->SetCharPref(updateErrDetailPrefStr.get(),errMsg.get());
02547       nsCOMPtr<nsIPrefService> prefSvc(do_QueryInterface(pref));
02548       prefSvc->SavePrefFile(nsnull);
02549     }else{
02550       nsString message;
02551       nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
02552       nsCOMPtr<nsIPrompt> prompter;
02553       if (wwatch){
02554         wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
02555         nssComponent->GetPIPNSSBundleString("CrlImportFailure1", message);
02556         message.Append(NS_LITERAL_STRING("\n").get());
02557         message.Append(tmpMessage);
02558         nssComponent->GetPIPNSSBundleString("CrlImportFailure2", tmpMessage);
02559         message.Append(NS_LITERAL_STRING("\n").get());
02560         message.Append(tmpMessage);
02561 
02562         if(prompter) {
02563           nsPSMUITracker tracker;
02564           if (!tracker.isUIForbidden()) {
02565             prompter->Alert(0, message.get());
02566           }
02567         }
02568       }
02569     }
02570     break;
02571   default:
02572     break;
02573   }
02574 
02575   return NS_OK;
02576 
02577 }
02578 
02579 void 
02580 PSMContentDownloader::setSilentDownload(PRBool flag)
02581 {
02582   mDoSilentDownload = flag;
02583 }
02584 
02585 void
02586 PSMContentDownloader::setCrlAutodownloadKey(nsAutoString key)
02587 {
02588   mCrlAutoDownloadKey = key;
02589 }
02590 
02591 
02592 /* other mime types that we should handle sometime:
02593    
02594    application/x-pkcs7-crl
02595    application/x-pkcs7-mime
02596    application/pkcs7-signature
02597    application/pre-encrypted
02598    
02599 */
02600 
02601 PRUint32
02602 getPSMContentType(const char * aContentType)
02603 { 
02604   // Don't forget to update RegisterPSMContentListeners in nsNSSModule.cpp 
02605   // for every supported content type.
02606   
02607   if (!nsCRT::strcasecmp(aContentType, "application/x-x509-ca-cert"))
02608     return PSMContentDownloader::X509_CA_CERT;
02609   else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-server-cert"))
02610     return PSMContentDownloader::X509_SERVER_CERT;
02611   else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-user-cert"))
02612     return PSMContentDownloader::X509_USER_CERT;
02613   else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-email-cert"))
02614     return PSMContentDownloader::X509_EMAIL_CERT;
02615   else if (!nsCRT::strcasecmp(aContentType, "application/x-pkcs7-crl"))
02616     return PSMContentDownloader::PKCS7_CRL;
02617   else if (!nsCRT::strcasecmp(aContentType, "application/x-x509-crl"))
02618     return PSMContentDownloader::PKCS7_CRL;
02619   else if (!nsCRT::strcasecmp(aContentType, "application/pkix-crl"))
02620     return PSMContentDownloader::PKCS7_CRL;
02621   return PSMContentDownloader::UNKNOWN_TYPE;
02622 }
02623 
02624 
02625 NS_IMPL_ISUPPORTS2(PSMContentListener,
02626                    nsIURIContentListener,
02627                    nsISupportsWeakReference) 
02628 
02629 PSMContentListener::PSMContentListener()
02630 {
02631   mLoadCookie = nsnull;
02632   mParentContentListener = nsnull;
02633 }
02634 
02635 PSMContentListener::~PSMContentListener()
02636 {
02637 }
02638 
02639 nsresult
02640 PSMContentListener::init()
02641 {
02642   return NS_OK;
02643 }
02644 
02645 NS_IMETHODIMP
02646 PSMContentListener::OnStartURIOpen(nsIURI *aURI, PRBool *aAbortOpen)
02647 {
02648   //if we don't want to handle the URI, return PR_TRUE in
02649   //*aAbortOpen
02650   return NS_OK;
02651 }
02652 
02653 NS_IMETHODIMP
02654 PSMContentListener::IsPreferred(const char * aContentType,
02655                                  char ** aDesiredContentType,
02656                                  PRBool * aCanHandleContent)
02657 {
02658   return CanHandleContent(aContentType, PR_TRUE,
02659                           aDesiredContentType, aCanHandleContent);
02660 }
02661 
02662 NS_IMETHODIMP
02663 PSMContentListener::CanHandleContent(const char * aContentType,
02664                                       PRBool aIsContentPreferred,
02665                                       char ** aDesiredContentType,
02666                                       PRBool * aCanHandleContent)
02667 {
02668   PRUint32 type;
02669   type = getPSMContentType(aContentType);
02670   if (type == PSMContentDownloader::UNKNOWN_TYPE) {
02671     *aCanHandleContent = PR_FALSE;
02672   } else {
02673     *aCanHandleContent = PR_TRUE;
02674   }
02675   return NS_OK;
02676 }
02677 
02678 NS_IMETHODIMP
02679 PSMContentListener::DoContent(const char * aContentType,
02680                                PRBool aIsContentPreferred,
02681                                nsIRequest * aRequest,
02682                                nsIStreamListener ** aContentHandler,
02683                                PRBool * aAbortProcess)
02684 {
02685   PSMContentDownloader *downLoader;
02686   PRUint32 type;
02687   type = getPSMContentType(aContentType);
02688   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("PSMContentListener::DoContent\n"));
02689   if (type != PSMContentDownloader::UNKNOWN_TYPE) {
02690     downLoader = new PSMContentDownloader(type);
02691     if (downLoader) {
02692       downLoader->QueryInterface(NS_GET_IID(nsIStreamListener), 
02693                                             (void **)aContentHandler);
02694       return NS_OK;
02695     }
02696   }
02697   return NS_ERROR_FAILURE;
02698 }
02699 
02700 NS_IMETHODIMP
02701 PSMContentListener::GetLoadCookie(nsISupports * *aLoadCookie)
02702 {
02703   *aLoadCookie = mLoadCookie;
02704   NS_IF_ADDREF(*aLoadCookie);
02705   return NS_OK;
02706 }
02707 
02708 NS_IMETHODIMP
02709 PSMContentListener::SetLoadCookie(nsISupports * aLoadCookie)
02710 {
02711   mLoadCookie = aLoadCookie;
02712   return NS_OK;
02713 }
02714 
02715 NS_IMETHODIMP
02716 PSMContentListener::GetParentContentListener(nsIURIContentListener ** aContentListener)
02717 {
02718   *aContentListener = mParentContentListener;
02719   NS_IF_ADDREF(*aContentListener);
02720   return NS_OK;
02721 }
02722 
02723 NS_IMETHODIMP
02724 PSMContentListener::SetParentContentListener(nsIURIContentListener * aContentListener)
02725 {
02726   mParentContentListener = aContentListener;
02727   return NS_OK;
02728 }