Back to index

lightning-sunbird  0.9+nobinonly
nsPKCS11Slot.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Ian McGreer <mcgreer@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsPKCS11Slot.h"
00039 #include "nsPK11TokenDB.h"
00040 
00041 #include "nsCOMPtr.h"
00042 #include "nsISupportsArray.h"
00043 #include "nsString.h"
00044 #include "nsReadableUtils.h"
00045 #include "nsCRT.h"
00046 
00047 #include "secmod.h"
00048 
00049 #ifdef PR_LOGGING
00050 extern PRLogModuleInfo* gPIPNSSLog;
00051 #endif
00052 
00053 NS_IMPL_ISUPPORTS1(nsPKCS11Slot, nsIPKCS11Slot)
00054 
00055 nsPKCS11Slot::nsPKCS11Slot(PK11SlotInfo *slot)
00056 {
00057   nsNSSShutDownPreventionLock locker;
00058   if (isAlreadyShutDown())
00059     return;
00060 
00061   PK11_ReferenceSlot(slot);
00062   mSlot = slot;
00063   mSeries = PK11_GetSlotSeries(slot);
00064   refreshSlotInfo();
00065 }
00066 
00067 void
00068 nsPKCS11Slot::refreshSlotInfo()
00069 {
00070   CK_SLOT_INFO slot_info;
00071   if (PK11_GetSlotInfo(mSlot, &slot_info) == SECSuccess) {
00072     // Set the Description field
00073     const char *ccDesc = (const char*)slot_info.slotDescription;
00074     const nsACString &cDesc = Substring(
00075       ccDesc, 
00076       ccDesc+PL_strnlen(ccDesc, sizeof(slot_info.slotDescription)));
00077     mSlotDesc = NS_ConvertUTF8toUCS2(cDesc);
00078     mSlotDesc.Trim(" ", PR_FALSE, PR_TRUE);
00079     // Set the Manufacturer field
00080     const char *ccManID = (const char*)slot_info.manufacturerID;
00081     const nsACString &cManID = Substring(
00082       ccManID, 
00083       ccManID+PL_strnlen(ccManID, sizeof(slot_info.manufacturerID)));
00084     mSlotManID = NS_ConvertUTF8toUCS2(cManID);
00085     mSlotManID.Trim(" ", PR_FALSE, PR_TRUE);
00086     // Set the Hardware Version field
00087     mSlotHWVersion = EmptyString();
00088     mSlotHWVersion.AppendInt(slot_info.hardwareVersion.major);
00089     mSlotHWVersion.AppendLiteral(".");
00090     mSlotHWVersion.AppendInt(slot_info.hardwareVersion.minor);
00091     // Set the Firmware Version field
00092     mSlotFWVersion = EmptyString();
00093     mSlotFWVersion.AppendInt(slot_info.firmwareVersion.major);
00094     mSlotFWVersion.AppendLiteral(".");
00095     mSlotFWVersion.AppendInt(slot_info.firmwareVersion.minor);
00096   }
00097 
00098 }
00099 
00100 nsPKCS11Slot::~nsPKCS11Slot()
00101 {
00102   nsNSSShutDownPreventionLock locker;
00103   if (isAlreadyShutDown())
00104     return;
00105 
00106   destructorSafeDestroyNSSReference();
00107   shutdown(calledFromObject);
00108 }
00109 
00110 void nsPKCS11Slot::virtualDestroyNSSReference()
00111 {
00112   destructorSafeDestroyNSSReference();
00113 }
00114 
00115 void nsPKCS11Slot::destructorSafeDestroyNSSReference()
00116 {
00117   if (isAlreadyShutDown())
00118     return;
00119 
00120   if (mSlot) {
00121     PK11_FreeSlot(mSlot);
00122     mSlot = nsnull;
00123   }
00124 }
00125 
00126 /* readonly attribute wstring name; */
00127 NS_IMETHODIMP 
00128 nsPKCS11Slot::GetName(PRUnichar **aName)
00129 {
00130   nsNSSShutDownPreventionLock locker;
00131   if (isAlreadyShutDown())
00132     return NS_ERROR_NOT_AVAILABLE;
00133 
00134   char *csn = PK11_GetSlotName(mSlot);
00135   if (*csn) {
00136     *aName = ToNewUnicode(NS_ConvertUTF8toUCS2(csn));
00137   } else if (PK11_HasRootCerts(mSlot)) {
00138     // This is a workaround to an Root Module bug - the root certs module has
00139     // no slot name.  Not bothering to localize, because this is a workaround
00140     // and for now all the slot names returned by NSS are char * anyway.
00141     *aName = ToNewUnicode(NS_LITERAL_STRING("Root Certificates"));
00142   } else {
00143     // same as above, this is a catch-all
00144     *aName = ToNewUnicode(NS_LITERAL_STRING("Unnamed Slot"));
00145   }
00146   if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
00147   return NS_OK;
00148 }
00149 
00150 /* readonly attribute wstring desc; */
00151 NS_IMETHODIMP 
00152 nsPKCS11Slot::GetDesc(PRUnichar **aDesc)
00153 {
00154   nsNSSShutDownPreventionLock locker;
00155   if (isAlreadyShutDown())
00156     return NS_ERROR_NOT_AVAILABLE;
00157 
00158   if (mSeries != PK11_GetSlotSeries(mSlot)) {
00159     refreshSlotInfo();
00160   }
00161 
00162   *aDesc = ToNewUnicode(mSlotDesc);
00163   if (!*aDesc) return NS_ERROR_OUT_OF_MEMORY;
00164   return NS_OK;
00165 }
00166 
00167 /* readonly attribute wstring manID; */
00168 NS_IMETHODIMP 
00169 nsPKCS11Slot::GetManID(PRUnichar **aManID)
00170 {
00171   if (mSeries != PK11_GetSlotSeries(mSlot)) {
00172     refreshSlotInfo();
00173   }
00174   *aManID = ToNewUnicode(mSlotManID);
00175   if (!*aManID) return NS_ERROR_OUT_OF_MEMORY;
00176   return NS_OK;
00177 }
00178 
00179 /* readonly attribute wstring HWVersion; */
00180 NS_IMETHODIMP 
00181 nsPKCS11Slot::GetHWVersion(PRUnichar **aHWVersion)
00182 {
00183   if (mSeries != PK11_GetSlotSeries(mSlot)) {
00184     refreshSlotInfo();
00185   }
00186   *aHWVersion = ToNewUnicode(mSlotHWVersion);
00187   if (!*aHWVersion) return NS_ERROR_OUT_OF_MEMORY;
00188   return NS_OK;
00189 }
00190 
00191 /* readonly attribute wstring FWVersion; */
00192 NS_IMETHODIMP 
00193 nsPKCS11Slot::GetFWVersion(PRUnichar **aFWVersion)
00194 {
00195   if (mSeries != PK11_GetSlotSeries(mSlot)) {
00196     refreshSlotInfo();
00197   }
00198   *aFWVersion = ToNewUnicode(mSlotFWVersion);
00199   if (!*aFWVersion) return NS_ERROR_OUT_OF_MEMORY;
00200   return NS_OK;
00201 }
00202 
00203 /* nsIPK11Token getToken (); */
00204 NS_IMETHODIMP 
00205 nsPKCS11Slot::GetToken(nsIPK11Token **_retval)
00206 {
00207   nsNSSShutDownPreventionLock locker;
00208   if (isAlreadyShutDown())
00209     return NS_ERROR_NOT_AVAILABLE;
00210 
00211   nsCOMPtr<nsIPK11Token> token = new nsPK11Token(mSlot);
00212   if (!token)
00213     return NS_ERROR_OUT_OF_MEMORY;
00214   *_retval = token;
00215   NS_ADDREF(*_retval);
00216   return NS_OK;
00217 }
00218 
00219 /* readonly attribute wstring tokenName; */
00220 NS_IMETHODIMP 
00221 nsPKCS11Slot::GetTokenName(PRUnichar **aName)
00222 {
00223   nsNSSShutDownPreventionLock locker;
00224   if (isAlreadyShutDown())
00225     return NS_ERROR_NOT_AVAILABLE;
00226 
00227   if (!PK11_IsPresent(mSlot)) {
00228     *aName = nsnull;
00229     return NS_OK;
00230   }
00231 
00232   if (mSeries != PK11_GetSlotSeries(mSlot)) {
00233     refreshSlotInfo();
00234   }
00235 
00236 
00237   *aName = ToNewUnicode(NS_ConvertUTF8toUCS2(PK11_GetTokenName(mSlot)));
00238   if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
00239   return NS_OK;
00240 }
00241 
00242 NS_IMETHODIMP
00243 nsPKCS11Slot::GetStatus(PRUint32 *_retval)
00244 {
00245   nsNSSShutDownPreventionLock locker;
00246   if (isAlreadyShutDown())
00247     return NS_ERROR_NOT_AVAILABLE;
00248 
00249   if (PK11_IsDisabled(mSlot))
00250     *_retval = SLOT_DISABLED;
00251   else if (!PK11_IsPresent(mSlot))
00252     *_retval = SLOT_NOT_PRESENT;
00253   else if (PK11_NeedLogin(mSlot) && PK11_NeedUserInit(mSlot))
00254     *_retval = SLOT_UNINITIALIZED;
00255   else if (PK11_NeedLogin(mSlot) && !PK11_IsLoggedIn(mSlot, NULL))
00256     *_retval = SLOT_NOT_LOGGED_IN;
00257   else if (PK11_NeedLogin(mSlot))
00258     *_retval = SLOT_LOGGED_IN;
00259   else
00260     *_retval = SLOT_READY;
00261   return NS_OK;
00262 }
00263 
00264 NS_IMPL_ISUPPORTS1(nsPKCS11Module, nsIPKCS11Module)
00265 
00266 nsPKCS11Module::nsPKCS11Module(SECMODModule *module)
00267 {
00268   nsNSSShutDownPreventionLock locker;
00269   if (isAlreadyShutDown())
00270     return;
00271 
00272   SECMOD_ReferenceModule(module);
00273   mModule = module;
00274 }
00275 
00276 nsPKCS11Module::~nsPKCS11Module()
00277 {
00278   nsNSSShutDownPreventionLock locker;
00279   if (isAlreadyShutDown())
00280     return;
00281 
00282   destructorSafeDestroyNSSReference();
00283   shutdown(calledFromObject);
00284 }
00285 
00286 void nsPKCS11Module::virtualDestroyNSSReference()
00287 {
00288   destructorSafeDestroyNSSReference();
00289 }
00290 
00291 void nsPKCS11Module::destructorSafeDestroyNSSReference()
00292 {
00293   if (isAlreadyShutDown())
00294     return;
00295 
00296   if (mModule) {
00297     SECMOD_DestroyModule(mModule);
00298     mModule = nsnull;
00299   }
00300 }
00301 
00302 /* readonly attribute wstring name; */
00303 NS_IMETHODIMP 
00304 nsPKCS11Module::GetName(PRUnichar **aName)
00305 {
00306   nsNSSShutDownPreventionLock locker;
00307   if (isAlreadyShutDown())
00308     return NS_ERROR_NOT_AVAILABLE;
00309 
00310   *aName = ToNewUnicode(NS_ConvertUTF8toUCS2(mModule->commonName));
00311   return NS_OK;
00312 }
00313 
00314 /* readonly attribute wstring libName; */
00315 NS_IMETHODIMP 
00316 nsPKCS11Module::GetLibName(PRUnichar **aName)
00317 {
00318   nsNSSShutDownPreventionLock locker;
00319   if (isAlreadyShutDown())
00320     return NS_ERROR_NOT_AVAILABLE;
00321 
00322   if ( mModule->dllName ) {
00323     *aName = ToNewUnicode(NS_ConvertUTF8toUCS2(mModule->dllName));
00324   } else {
00325     *aName = NULL;
00326   }
00327   return NS_OK;
00328 }
00329 
00330 /*  nsIPKCS11Slot findSlotByName(in wstring name); */
00331 NS_IMETHODIMP 
00332 nsPKCS11Module::FindSlotByName(const PRUnichar *aName,
00333                                nsIPKCS11Slot **_retval)
00334 {
00335   nsNSSShutDownPreventionLock locker;
00336   if (isAlreadyShutDown())
00337     return NS_ERROR_NOT_AVAILABLE;
00338 
00339   char *asciiname = ToNewUTF8String(nsDependentString(aName));
00340   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
00341   PK11SlotInfo *slotinfo = NULL;
00342   PK11SlotList *slotList = PK11_FindSlotsByNames(mModule->dllName, 
00343         asciiname /* slotName */, NULL /* token Name */, PR_FALSE);
00344   if (!slotList) {
00345     /* name must be the token name */
00346     slotList = PK11_FindSlotsByNames(mModule->dllName, 
00347         NULL /*slot Name */, asciiname /* token Name */, PR_FALSE);
00348   }
00349   if (slotList) {
00350     /* should only be one */
00351     if (slotList->head && slotList->head->slot) {
00352       slotinfo =  PK11_ReferenceSlot(slotList->head->slot);
00353     }
00354     PK11_FreeSlotList(slotList);
00355   }
00356   if (!slotinfo) {
00357     // workaround - the builtin module has no name
00358     if (asciiname == nsnull) {
00359       return NS_ERROR_FAILURE;
00360     } else if (nsCRT::strcmp(asciiname, "Root Certificates") == 0) {
00361       slotinfo = PK11_ReferenceSlot(mModule->slots[0]);
00362     } else {
00363       // give up
00364       nsMemory::Free(asciiname);
00365       return NS_ERROR_FAILURE;
00366     }
00367   } 
00368   nsMemory::Free(asciiname);
00369   nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotinfo);
00370   PK11_FreeSlot(slotinfo);
00371   if (!slot)
00372     return NS_ERROR_OUT_OF_MEMORY;
00373   *_retval = slot;
00374   NS_ADDREF(*_retval);
00375   return NS_OK;
00376 }
00377 
00378 /* nsIEnumerator listSlots (); */
00379 NS_IMETHODIMP 
00380 nsPKCS11Module::ListSlots(nsIEnumerator **_retval)
00381 {
00382   nsNSSShutDownPreventionLock locker;
00383   if (isAlreadyShutDown())
00384     return NS_ERROR_NOT_AVAILABLE;
00385 
00386   nsresult rv = NS_OK;
00387   int i;
00388   /* get isupports array */
00389   nsCOMPtr<nsISupportsArray> array;
00390   rv = NS_NewISupportsArray(getter_AddRefs(array));
00391   if (NS_FAILED(rv)) return rv;
00392   /* applications which allow new slot creation (which Firefox now does
00393    * since it uses the WaitForSlotEvent call) need to hold the
00394    * ModuleList Read lock to prevent the slot array from changing out
00395    * from under it. */
00396   SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
00397   SECMOD_GetReadLock(lock);
00398   for (i=0; i<mModule->slotCount; i++) {
00399     if (mModule->slots[i]) {
00400       nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(mModule->slots[i]);
00401       array->AppendElement(slot);
00402     }
00403   }
00404   SECMOD_ReleaseReadLock(lock);
00405   rv = array->Enumerate(_retval);
00406   return rv;
00407 }
00408 
00409 NS_IMPL_ISUPPORTS2(nsPKCS11ModuleDB, nsIPKCS11ModuleDB, nsICryptoFIPSInfo)
00410 
00411 nsPKCS11ModuleDB::nsPKCS11ModuleDB()
00412 {
00413 }
00414 
00415 nsPKCS11ModuleDB::~nsPKCS11ModuleDB()
00416 {
00417 }
00418 
00419 /* nsIPKCS11Module getInternal (); */
00420 NS_IMETHODIMP 
00421 nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module **_retval)
00422 {
00423   nsNSSShutDownPreventionLock locker;
00424   SECMODModule *nssMod = 
00425     SECMOD_CreateModule(NULL,SECMOD_INT_NAME, NULL,SECMOD_INT_FLAGS);
00426   nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod);
00427   SECMOD_DestroyModule(nssMod);
00428   if (!module)
00429     return NS_ERROR_OUT_OF_MEMORY;
00430   *_retval = module;
00431   NS_ADDREF(*_retval);
00432   return NS_OK;
00433 }
00434 
00435 /* nsIPKCS11Module getInternalFIPS (); */
00436 NS_IMETHODIMP 
00437 nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module **_retval)
00438 {
00439   nsNSSShutDownPreventionLock locker;
00440   SECMODModule *nssMod = 
00441     SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME, NULL, SECMOD_FIPS_FLAGS);
00442   nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod);
00443   SECMOD_DestroyModule(nssMod);
00444   if (!module)
00445     return NS_ERROR_OUT_OF_MEMORY;
00446   *_retval = module;
00447   NS_ADDREF(*_retval);
00448   return NS_OK;
00449 }
00450 
00451 /* nsIPKCS11Module findModuleByName(in wstring name); */
00452 NS_IMETHODIMP 
00453 nsPKCS11ModuleDB::FindModuleByName(const PRUnichar *aName,
00454                                    nsIPKCS11Module **_retval)
00455 {
00456   nsNSSShutDownPreventionLock locker;
00457   NS_ConvertUCS2toUTF8 aUtf8Name(aName);
00458   SECMODModule *mod =
00459     SECMOD_FindModule(NS_CONST_CAST(char *, aUtf8Name.get()));
00460   if (!mod)
00461     return NS_ERROR_FAILURE;
00462   nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod);
00463   SECMOD_DestroyModule(mod);
00464   if (!module)
00465     return NS_ERROR_OUT_OF_MEMORY;
00466   *_retval = module;
00467   NS_ADDREF(*_retval);
00468   return NS_OK;
00469 }
00470 
00471 /* This is essentially the same as nsIPK11Token::findTokenByName, except
00472  * that it returns an nsIPKCS11Slot, which may be desired.
00473  */
00474 /* nsIPKCS11Module findSlotByName(in wstring name); */
00475 NS_IMETHODIMP 
00476 nsPKCS11ModuleDB::FindSlotByName(const PRUnichar *aName,
00477                                  nsIPKCS11Slot **_retval)
00478 {
00479   nsNSSShutDownPreventionLock locker;
00480   NS_ConvertUCS2toUTF8 aUtf8Name(aName);
00481   PK11SlotInfo *slotinfo =
00482    PK11_FindSlotByName(NS_CONST_CAST(char*, aUtf8Name.get()));
00483   if (!slotinfo)
00484     return NS_ERROR_FAILURE;
00485   nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotinfo);
00486   PK11_FreeSlot(slotinfo);
00487   if (!slot)
00488     return NS_ERROR_OUT_OF_MEMORY;
00489   *_retval = slot;
00490   NS_ADDREF(*_retval);
00491   return NS_OK;
00492 }
00493 
00494 /* nsIEnumerator listModules (); */
00495 NS_IMETHODIMP 
00496 nsPKCS11ModuleDB::ListModules(nsIEnumerator **_retval)
00497 {
00498   nsNSSShutDownPreventionLock locker;
00499   nsresult rv = NS_OK;
00500   /* get isupports array */
00501   nsCOMPtr<nsISupportsArray> array;
00502   rv = NS_NewISupportsArray(getter_AddRefs(array));
00503   if (NS_FAILED(rv)) return rv;
00504   /* get the default list of modules */
00505   SECMODModuleList *list = SECMOD_GetDefaultModuleList();
00506   /* lock down the list for reading */
00507   SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
00508   SECMOD_GetReadLock(lock);
00509   while (list) {
00510     nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
00511     array->AppendElement(module);
00512     list = list->next;
00513   }
00514   /* Get the modules in the database that didn't load */
00515   list = SECMOD_GetDeadModuleList();
00516   while (list) {
00517     nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
00518     array->AppendElement(module);
00519     list = list->next;
00520   }
00521   SECMOD_ReleaseReadLock(lock);
00522   rv = array->Enumerate(_retval);
00523   return rv;
00524 }
00525 
00526 NS_IMETHODIMP nsPKCS11ModuleDB::GetCanToggleFIPS(PRBool *aCanToggleFIPS)
00527 {
00528   nsNSSShutDownPreventionLock locker;
00529   *aCanToggleFIPS = SECMOD_CanDeleteInternalModule();
00530   return NS_OK;
00531 }
00532 
00533 
00534 /* void toggleFIPSMode (); */
00535 NS_IMETHODIMP nsPKCS11ModuleDB::ToggleFIPSMode()
00536 {
00537   nsNSSShutDownPreventionLock locker;
00538   // The way to toggle FIPS mode in NSS is extremely obscure.
00539   // Basically, we delete the internal module, and voila it
00540   // gets replaced with the opposite module, ie if it was 
00541   // FIPS before, then it becomes non-FIPS next.
00542   SECMODModule *internal;
00543 
00544   // This function returns us a pointer to a local copy of 
00545   // the internal module stashed in NSS.  We don't want to
00546   // delete it since it will cause much pain in NSS.
00547   internal = SECMOD_GetInternalModule();
00548   if (!internal)
00549     return NS_ERROR_FAILURE;
00550 
00551   SECStatus srv = SECMOD_DeleteInternalModule(internal->commonName);
00552   if (srv != SECSuccess)
00553     return NS_ERROR_FAILURE;
00554 
00555   return NS_OK;
00556 }
00557 
00558 /* readonly attribute boolean isFIPSEnabled; */
00559 NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSEnabled(PRBool *aIsFIPSEnabled)
00560 {
00561   nsNSSShutDownPreventionLock locker;
00562   *aIsFIPSEnabled = PK11_IsFIPS();
00563   return NS_OK;
00564 }
00565 
00566 NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSModeActive(PRBool *aIsFIPSModeActive)
00567 {
00568   return GetIsFIPSEnabled(aIsFIPSModeActive);
00569 }