michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPKCS11Slot.h" michael@0: #include "nsPK11TokenDB.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsISupportsArray.h" michael@0: #include "nsString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsCRT.h" michael@0: michael@0: #include "secmod.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gPIPNSSLog; michael@0: #endif michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPKCS11Slot, nsIPKCS11Slot) michael@0: michael@0: nsPKCS11Slot::nsPKCS11Slot(PK11SlotInfo *slot) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return; michael@0: michael@0: PK11_ReferenceSlot(slot); michael@0: mSlot = slot; michael@0: mSeries = PK11_GetSlotSeries(slot); michael@0: refreshSlotInfo(); michael@0: } michael@0: michael@0: void michael@0: nsPKCS11Slot::refreshSlotInfo() michael@0: { michael@0: CK_SLOT_INFO slot_info; michael@0: if (PK11_GetSlotInfo(mSlot, &slot_info) == SECSuccess) { michael@0: // Set the Description field michael@0: const char *ccDesc = (const char*)slot_info.slotDescription; michael@0: const nsACString &cDesc = Substring( michael@0: ccDesc, michael@0: ccDesc+PL_strnlen(ccDesc, sizeof(slot_info.slotDescription))); michael@0: mSlotDesc = NS_ConvertUTF8toUTF16(cDesc); michael@0: mSlotDesc.Trim(" ", false, true); michael@0: // Set the Manufacturer field michael@0: const char *ccManID = (const char*)slot_info.manufacturerID; michael@0: const nsACString &cManID = Substring( michael@0: ccManID, michael@0: ccManID+PL_strnlen(ccManID, sizeof(slot_info.manufacturerID))); michael@0: mSlotManID = NS_ConvertUTF8toUTF16(cManID); michael@0: mSlotManID.Trim(" ", false, true); michael@0: // Set the Hardware Version field michael@0: mSlotHWVersion = EmptyString(); michael@0: mSlotHWVersion.AppendInt(slot_info.hardwareVersion.major); michael@0: mSlotHWVersion.AppendLiteral("."); michael@0: mSlotHWVersion.AppendInt(slot_info.hardwareVersion.minor); michael@0: // Set the Firmware Version field michael@0: mSlotFWVersion = EmptyString(); michael@0: mSlotFWVersion.AppendInt(slot_info.firmwareVersion.major); michael@0: mSlotFWVersion.AppendLiteral("."); michael@0: mSlotFWVersion.AppendInt(slot_info.firmwareVersion.minor); michael@0: } michael@0: michael@0: } michael@0: michael@0: nsPKCS11Slot::~nsPKCS11Slot() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void nsPKCS11Slot::virtualDestroyNSSReference() michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void nsPKCS11Slot::destructorSafeDestroyNSSReference() michael@0: { michael@0: if (mSlot) { michael@0: PK11_FreeSlot(mSlot); michael@0: mSlot = nullptr; michael@0: } michael@0: } michael@0: michael@0: /* readonly attribute wstring name; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetName(char16_t **aName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: char *csn = PK11_GetSlotName(mSlot); michael@0: if (*csn) { michael@0: *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(csn)); michael@0: } else if (PK11_HasRootCerts(mSlot)) { michael@0: // This is a workaround to an Root Module bug - the root certs module has michael@0: // no slot name. Not bothering to localize, because this is a workaround michael@0: // and for now all the slot names returned by NSS are char * anyway. michael@0: *aName = ToNewUnicode(NS_LITERAL_STRING("Root Certificates")); michael@0: } else { michael@0: // same as above, this is a catch-all michael@0: *aName = ToNewUnicode(NS_LITERAL_STRING("Unnamed Slot")); michael@0: } michael@0: if (!*aName) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring desc; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetDesc(char16_t **aDesc) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshSlotInfo(); michael@0: } michael@0: michael@0: *aDesc = ToNewUnicode(mSlotDesc); michael@0: if (!*aDesc) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring manID; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetManID(char16_t **aManID) michael@0: { michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshSlotInfo(); michael@0: } michael@0: *aManID = ToNewUnicode(mSlotManID); michael@0: if (!*aManID) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring HWVersion; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetHWVersion(char16_t **aHWVersion) michael@0: { michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshSlotInfo(); michael@0: } michael@0: *aHWVersion = ToNewUnicode(mSlotHWVersion); michael@0: if (!*aHWVersion) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring FWVersion; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetFWVersion(char16_t **aFWVersion) michael@0: { michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshSlotInfo(); michael@0: } michael@0: *aFWVersion = ToNewUnicode(mSlotFWVersion); michael@0: if (!*aFWVersion) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIPK11Token getToken (); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetToken(nsIPK11Token **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsCOMPtr token = new nsPK11Token(mSlot); michael@0: *_retval = token; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenName; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetTokenName(char16_t **aName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (!PK11_IsPresent(mSlot)) { michael@0: *aName = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshSlotInfo(); michael@0: } michael@0: michael@0: michael@0: *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot))); michael@0: if (!*aName) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPKCS11Slot::GetStatus(uint32_t *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (PK11_IsDisabled(mSlot)) michael@0: *_retval = SLOT_DISABLED; michael@0: else if (!PK11_IsPresent(mSlot)) michael@0: *_retval = SLOT_NOT_PRESENT; michael@0: else if (PK11_NeedLogin(mSlot) && PK11_NeedUserInit(mSlot)) michael@0: *_retval = SLOT_UNINITIALIZED; michael@0: else if (PK11_NeedLogin(mSlot) && !PK11_IsLoggedIn(mSlot, nullptr)) michael@0: *_retval = SLOT_NOT_LOGGED_IN; michael@0: else if (PK11_NeedLogin(mSlot)) michael@0: *_retval = SLOT_LOGGED_IN; michael@0: else michael@0: *_retval = SLOT_READY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPKCS11Module, nsIPKCS11Module) michael@0: michael@0: nsPKCS11Module::nsPKCS11Module(SECMODModule *module) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return; michael@0: michael@0: SECMOD_ReferenceModule(module); michael@0: mModule = module; michael@0: } michael@0: michael@0: nsPKCS11Module::~nsPKCS11Module() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void nsPKCS11Module::virtualDestroyNSSReference() michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void nsPKCS11Module::destructorSafeDestroyNSSReference() michael@0: { michael@0: if (mModule) { michael@0: SECMOD_DestroyModule(mModule); michael@0: mModule = nullptr; michael@0: } michael@0: } michael@0: michael@0: /* readonly attribute wstring name; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Module::GetName(char16_t **aName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->commonName)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring libName; */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Module::GetLibName(char16_t **aName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if ( mModule->dllName ) { michael@0: *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->dllName)); michael@0: } else { michael@0: *aName = nullptr; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIPKCS11Slot findSlotByName(in wstring name); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Module::FindSlotByName(const char16_t *aName, michael@0: nsIPKCS11Slot **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: char *asciiname = ToNewUTF8String(nsDependentString(aName)); michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname)); michael@0: PK11SlotInfo *slotinfo = nullptr; michael@0: PK11SlotList *slotList = PK11_FindSlotsByNames(mModule->dllName, michael@0: asciiname /* slotName */, nullptr /* token Name */, false); michael@0: if (!slotList) { michael@0: /* name must be the token name */ michael@0: slotList = PK11_FindSlotsByNames(mModule->dllName, michael@0: nullptr /*slot Name */, asciiname /* token Name */, false); michael@0: } michael@0: if (slotList) { michael@0: /* should only be one */ michael@0: if (slotList->head && slotList->head->slot) { michael@0: slotinfo = PK11_ReferenceSlot(slotList->head->slot); michael@0: } michael@0: PK11_FreeSlotList(slotList); michael@0: } michael@0: if (!slotinfo) { michael@0: // workaround - the builtin module has no name michael@0: if (!asciiname) { michael@0: return NS_ERROR_FAILURE; michael@0: } else if (nsCRT::strcmp(asciiname, "Root Certificates") == 0) { michael@0: slotinfo = PK11_ReferenceSlot(mModule->slots[0]); michael@0: } else { michael@0: // give up michael@0: nsMemory::Free(asciiname); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: nsMemory::Free(asciiname); michael@0: nsCOMPtr slot = new nsPKCS11Slot(slotinfo); michael@0: PK11_FreeSlot(slotinfo); michael@0: *_retval = slot; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIEnumerator listSlots (); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11Module::ListSlots(nsIEnumerator **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: int i; michael@0: /* get isupports array */ michael@0: nsCOMPtr array; michael@0: rv = NS_NewISupportsArray(getter_AddRefs(array)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: /* applications which allow new slot creation (which Firefox now does michael@0: * since it uses the WaitForSlotEvent call) need to hold the michael@0: * ModuleList Read lock to prevent the slot array from changing out michael@0: * from under it. */ michael@0: SECMODListLock *lock = SECMOD_GetDefaultModuleListLock(); michael@0: SECMOD_GetReadLock(lock); michael@0: for (i=0; islotCount; i++) { michael@0: if (mModule->slots[i]) { michael@0: nsCOMPtr slot = new nsPKCS11Slot(mModule->slots[i]); michael@0: array->AppendElement(slot); michael@0: } michael@0: } michael@0: SECMOD_ReleaseReadLock(lock); michael@0: rv = array->Enumerate(_retval); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPKCS11ModuleDB, nsIPKCS11ModuleDB, nsICryptoFIPSInfo) michael@0: michael@0: nsPKCS11ModuleDB::nsPKCS11ModuleDB() michael@0: { michael@0: } michael@0: michael@0: nsPKCS11ModuleDB::~nsPKCS11ModuleDB() michael@0: { michael@0: } michael@0: michael@0: /* nsIPKCS11Module getInternal (); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: SECMODModule *nssMod = michael@0: SECMOD_CreateModule(nullptr, SECMOD_INT_NAME, nullptr, SECMOD_INT_FLAGS); michael@0: nsCOMPtr module = new nsPKCS11Module(nssMod); michael@0: SECMOD_DestroyModule(nssMod); michael@0: *_retval = module; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIPKCS11Module getInternalFIPS (); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: SECMODModule *nssMod = michael@0: SECMOD_CreateModule(nullptr, SECMOD_FIPS_NAME, nullptr, SECMOD_FIPS_FLAGS); michael@0: nsCOMPtr module = new nsPKCS11Module(nssMod); michael@0: SECMOD_DestroyModule(nssMod); michael@0: *_retval = module; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIPKCS11Module findModuleByName(in wstring name); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11ModuleDB::FindModuleByName(const char16_t *aName, michael@0: nsIPKCS11Module **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: NS_ConvertUTF16toUTF8 aUtf8Name(aName); michael@0: SECMODModule *mod = michael@0: SECMOD_FindModule(const_cast(aUtf8Name.get())); michael@0: if (!mod) michael@0: return NS_ERROR_FAILURE; michael@0: nsCOMPtr module = new nsPKCS11Module(mod); michael@0: SECMOD_DestroyModule(mod); michael@0: *_retval = module; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* This is essentially the same as nsIPK11Token::findTokenByName, except michael@0: * that it returns an nsIPKCS11Slot, which may be desired. michael@0: */ michael@0: /* nsIPKCS11Module findSlotByName(in wstring name); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11ModuleDB::FindSlotByName(const char16_t *aName, michael@0: nsIPKCS11Slot **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: NS_ConvertUTF16toUTF8 aUtf8Name(aName); michael@0: PK11SlotInfo *slotinfo = michael@0: PK11_FindSlotByName(const_cast(aUtf8Name.get())); michael@0: if (!slotinfo) michael@0: return NS_ERROR_FAILURE; michael@0: nsCOMPtr slot = new nsPKCS11Slot(slotinfo); michael@0: PK11_FreeSlot(slotinfo); michael@0: *_retval = slot; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* nsIEnumerator listModules (); */ michael@0: NS_IMETHODIMP michael@0: nsPKCS11ModuleDB::ListModules(nsIEnumerator **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: nsresult rv = NS_OK; michael@0: /* get isupports array */ michael@0: nsCOMPtr array; michael@0: rv = NS_NewISupportsArray(getter_AddRefs(array)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: /* get the default list of modules */ michael@0: SECMODModuleList *list = SECMOD_GetDefaultModuleList(); michael@0: /* lock down the list for reading */ michael@0: SECMODListLock *lock = SECMOD_GetDefaultModuleListLock(); michael@0: SECMOD_GetReadLock(lock); michael@0: while (list) { michael@0: nsCOMPtr module = new nsPKCS11Module(list->module); michael@0: array->AppendElement(module); michael@0: list = list->next; michael@0: } michael@0: /* Get the modules in the database that didn't load */ michael@0: list = SECMOD_GetDeadModuleList(); michael@0: while (list) { michael@0: nsCOMPtr module = new nsPKCS11Module(list->module); michael@0: array->AppendElement(module); michael@0: list = list->next; michael@0: } michael@0: SECMOD_ReleaseReadLock(lock); michael@0: rv = array->Enumerate(_retval); michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPKCS11ModuleDB::GetCanToggleFIPS(bool *aCanToggleFIPS) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: *aCanToggleFIPS = SECMOD_CanDeleteInternalModule(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: /* void toggleFIPSMode (); */ michael@0: NS_IMETHODIMP nsPKCS11ModuleDB::ToggleFIPSMode() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: // The way to toggle FIPS mode in NSS is extremely obscure. michael@0: // Basically, we delete the internal module, and voila it michael@0: // gets replaced with the opposite module, ie if it was michael@0: // FIPS before, then it becomes non-FIPS next. michael@0: SECMODModule *internal; michael@0: michael@0: // This function returns us a pointer to a local copy of michael@0: // the internal module stashed in NSS. We don't want to michael@0: // delete it since it will cause much pain in NSS. michael@0: internal = SECMOD_GetInternalModule(); michael@0: if (!internal) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: SECStatus srv = SECMOD_DeleteInternalModule(internal->commonName); michael@0: if (srv != SECSuccess) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute boolean isFIPSEnabled; */ michael@0: NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSEnabled(bool *aIsFIPSEnabled) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: *aIsFIPSEnabled = PK11_IsFIPS(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSModeActive(bool *aIsFIPSModeActive) michael@0: { michael@0: return GetIsFIPSEnabled(aIsFIPSModeActive); michael@0: }