nsPKCS11Slot.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "nsPKCS11Slot.h"
  5. #include <string.h>
  6. #include "mozilla/Casting.h"
  7. #include "mozilla/Logging.h"
  8. #include "mozilla/Telemetry.h"
  9. #include "mozilla/Unused.h"
  10. #include "nsCOMPtr.h"
  11. #include "nsIMutableArray.h"
  12. #include "nsPK11TokenDB.h"
  13. #include "nsPromiseFlatString.h"
  14. #include "secmod.h"
  15. using mozilla::LogLevel;
  16. extern mozilla::LazyLogModule gPIPNSSLog;
  17. NS_IMPL_ISUPPORTS(nsPKCS11Slot, nsIPKCS11Slot)
  18. nsPKCS11Slot::nsPKCS11Slot(PK11SlotInfo* slot)
  19. {
  20. MOZ_ASSERT(slot);
  21. nsNSSShutDownPreventionLock locker;
  22. if (isAlreadyShutDown())
  23. return;
  24. mSlot.reset(PK11_ReferenceSlot(slot));
  25. mSeries = PK11_GetSlotSeries(slot);
  26. Unused << refreshSlotInfo(locker);
  27. }
  28. nsresult
  29. nsPKCS11Slot::refreshSlotInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/)
  30. {
  31. CK_SLOT_INFO slotInfo;
  32. nsresult rv = MapSECStatus(PK11_GetSlotInfo(mSlot.get(), &slotInfo));
  33. if (NS_FAILED(rv)) {
  34. return rv;
  35. }
  36. // Set the Description field
  37. const char* ccDesc =
  38. mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(slotInfo.slotDescription);
  39. mSlotDesc.Assign(ccDesc, strnlen(ccDesc, sizeof(slotInfo.slotDescription)));
  40. mSlotDesc.Trim(" ", false, true);
  41. // Set the Manufacturer field
  42. const char* ccManID =
  43. mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(slotInfo.manufacturerID);
  44. mSlotManufacturerID.Assign(
  45. ccManID,
  46. strnlen(ccManID, sizeof(slotInfo.manufacturerID)));
  47. mSlotManufacturerID.Trim(" ", false, true);
  48. // Set the Hardware Version field
  49. mSlotHWVersion.Truncate();
  50. mSlotHWVersion.AppendInt(slotInfo.hardwareVersion.major);
  51. mSlotHWVersion.Append('.');
  52. mSlotHWVersion.AppendInt(slotInfo.hardwareVersion.minor);
  53. // Set the Firmware Version field
  54. mSlotFWVersion.Truncate();
  55. mSlotFWVersion.AppendInt(slotInfo.firmwareVersion.major);
  56. mSlotFWVersion.Append('.');
  57. mSlotFWVersion.AppendInt(slotInfo.firmwareVersion.minor);
  58. return NS_OK;
  59. }
  60. nsPKCS11Slot::~nsPKCS11Slot()
  61. {
  62. nsNSSShutDownPreventionLock locker;
  63. if (isAlreadyShutDown()) {
  64. return;
  65. }
  66. destructorSafeDestroyNSSReference();
  67. shutdown(ShutdownCalledFrom::Object);
  68. }
  69. void
  70. nsPKCS11Slot::virtualDestroyNSSReference()
  71. {
  72. destructorSafeDestroyNSSReference();
  73. }
  74. void
  75. nsPKCS11Slot::destructorSafeDestroyNSSReference()
  76. {
  77. mSlot = nullptr;
  78. }
  79. nsresult
  80. nsPKCS11Slot::GetAttributeHelper(const nsACString& attribute,
  81. /*out*/ nsACString& xpcomOutParam)
  82. {
  83. nsNSSShutDownPreventionLock locker;
  84. if (isAlreadyShutDown()) {
  85. return NS_ERROR_NOT_AVAILABLE;
  86. }
  87. if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
  88. nsresult rv = refreshSlotInfo(locker);
  89. if (NS_FAILED(rv)) {
  90. return rv;
  91. }
  92. }
  93. xpcomOutParam = attribute;
  94. return NS_OK;
  95. }
  96. NS_IMETHODIMP
  97. nsPKCS11Slot::GetName(/*out*/ nsACString& name)
  98. {
  99. nsNSSShutDownPreventionLock locker;
  100. if (isAlreadyShutDown())
  101. return NS_ERROR_NOT_AVAILABLE;
  102. // |csn| is non-owning.
  103. char* csn = PK11_GetSlotName(mSlot.get());
  104. if (csn && *csn) {
  105. name = csn;
  106. } else if (PK11_HasRootCerts(mSlot.get())) {
  107. // This is a workaround to an Root Module bug - the root certs module has
  108. // no slot name. Not bothering to localize, because this is a workaround
  109. // and for now all the slot names returned by NSS are char * anyway.
  110. name = NS_LITERAL_CSTRING("Root Certificates");
  111. } else {
  112. // same as above, this is a catch-all
  113. name = NS_LITERAL_CSTRING("Unnamed Slot");
  114. }
  115. return NS_OK;
  116. }
  117. NS_IMETHODIMP
  118. nsPKCS11Slot::GetDesc(/*out*/ nsACString& desc)
  119. {
  120. return GetAttributeHelper(mSlotDesc, desc);
  121. }
  122. NS_IMETHODIMP
  123. nsPKCS11Slot::GetManID(/*out*/ nsACString& manufacturerID)
  124. {
  125. return GetAttributeHelper(mSlotManufacturerID, manufacturerID);
  126. }
  127. NS_IMETHODIMP
  128. nsPKCS11Slot::GetHWVersion(/*out*/ nsACString& hwVersion)
  129. {
  130. return GetAttributeHelper(mSlotHWVersion, hwVersion);
  131. }
  132. NS_IMETHODIMP
  133. nsPKCS11Slot::GetFWVersion(/*out*/ nsACString& fwVersion)
  134. {
  135. return GetAttributeHelper(mSlotFWVersion, fwVersion);
  136. }
  137. NS_IMETHODIMP
  138. nsPKCS11Slot::GetToken(nsIPK11Token** _retval)
  139. {
  140. NS_ENSURE_ARG_POINTER(_retval);
  141. nsNSSShutDownPreventionLock locker;
  142. if (isAlreadyShutDown())
  143. return NS_ERROR_NOT_AVAILABLE;
  144. nsCOMPtr<nsIPK11Token> token = new nsPK11Token(mSlot.get());
  145. token.forget(_retval);
  146. return NS_OK;
  147. }
  148. NS_IMETHODIMP
  149. nsPKCS11Slot::GetTokenName(/*out*/ nsACString& tokenName)
  150. {
  151. nsNSSShutDownPreventionLock locker;
  152. if (isAlreadyShutDown())
  153. return NS_ERROR_NOT_AVAILABLE;
  154. if (!PK11_IsPresent(mSlot.get())) {
  155. tokenName.SetIsVoid(true);
  156. return NS_OK;
  157. }
  158. if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
  159. nsresult rv = refreshSlotInfo(locker);
  160. if (NS_FAILED(rv)) {
  161. return rv;
  162. }
  163. }
  164. tokenName = PK11_GetTokenName(mSlot.get());
  165. return NS_OK;
  166. }
  167. NS_IMETHODIMP
  168. nsPKCS11Slot::GetStatus(uint32_t* _retval)
  169. {
  170. NS_ENSURE_ARG_POINTER(_retval);
  171. nsNSSShutDownPreventionLock locker;
  172. if (isAlreadyShutDown())
  173. return NS_ERROR_NOT_AVAILABLE;
  174. if (PK11_IsDisabled(mSlot.get())) {
  175. *_retval = SLOT_DISABLED;
  176. } else if (!PK11_IsPresent(mSlot.get())) {
  177. *_retval = SLOT_NOT_PRESENT;
  178. } else if (PK11_NeedLogin(mSlot.get()) && PK11_NeedUserInit(mSlot.get())) {
  179. *_retval = SLOT_UNINITIALIZED;
  180. } else if (PK11_NeedLogin(mSlot.get()) &&
  181. !PK11_IsLoggedIn(mSlot.get(), nullptr)) {
  182. *_retval = SLOT_NOT_LOGGED_IN;
  183. } else if (PK11_NeedLogin(mSlot.get())) {
  184. *_retval = SLOT_LOGGED_IN;
  185. } else {
  186. *_retval = SLOT_READY;
  187. }
  188. return NS_OK;
  189. }
  190. NS_IMPL_ISUPPORTS(nsPKCS11Module, nsIPKCS11Module)
  191. nsPKCS11Module::nsPKCS11Module(SECMODModule* module)
  192. {
  193. MOZ_ASSERT(module);
  194. nsNSSShutDownPreventionLock locker;
  195. if (isAlreadyShutDown())
  196. return;
  197. mModule.reset(SECMOD_ReferenceModule(module));
  198. }
  199. nsPKCS11Module::~nsPKCS11Module()
  200. {
  201. nsNSSShutDownPreventionLock locker;
  202. if (isAlreadyShutDown()) {
  203. return;
  204. }
  205. destructorSafeDestroyNSSReference();
  206. shutdown(ShutdownCalledFrom::Object);
  207. }
  208. void
  209. nsPKCS11Module::virtualDestroyNSSReference()
  210. {
  211. destructorSafeDestroyNSSReference();
  212. }
  213. void
  214. nsPKCS11Module::destructorSafeDestroyNSSReference()
  215. {
  216. mModule = nullptr;
  217. }
  218. NS_IMETHODIMP
  219. nsPKCS11Module::GetName(/*out*/ nsACString& name)
  220. {
  221. nsNSSShutDownPreventionLock locker;
  222. if (isAlreadyShutDown())
  223. return NS_ERROR_NOT_AVAILABLE;
  224. name = mModule->commonName;
  225. return NS_OK;
  226. }
  227. NS_IMETHODIMP
  228. nsPKCS11Module::GetLibName(/*out*/ nsACString& libName)
  229. {
  230. nsNSSShutDownPreventionLock locker;
  231. if (isAlreadyShutDown())
  232. return NS_ERROR_NOT_AVAILABLE;
  233. if (mModule->dllName) {
  234. libName = mModule->dllName;
  235. } else {
  236. libName.SetIsVoid(true);
  237. }
  238. return NS_OK;
  239. }
  240. NS_IMETHODIMP
  241. nsPKCS11Module::FindSlotByName(const nsACString& name,
  242. /*out*/ nsIPKCS11Slot** _retval)
  243. {
  244. NS_ENSURE_ARG_POINTER(_retval);
  245. nsNSSShutDownPreventionLock locker;
  246. if (isAlreadyShutDown())
  247. return NS_ERROR_NOT_AVAILABLE;
  248. const nsCString& flatName = PromiseFlatCString(name);
  249. MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Getting \"%s\"", flatName.get()));
  250. UniquePK11SlotInfo slotInfo;
  251. UniquePK11SlotList slotList(PK11_FindSlotsByNames(mModule->dllName,
  252. flatName.get() /*slotName*/,
  253. nullptr /*tokenName*/,
  254. false));
  255. if (!slotList) {
  256. /* name must be the token name */
  257. slotList.reset(PK11_FindSlotsByNames(mModule->dllName, nullptr /*slotName*/,
  258. flatName.get() /*tokenName*/, false));
  259. }
  260. if (slotList && slotList->head && slotList->head->slot) {
  261. slotInfo.reset(PK11_ReferenceSlot(slotList->head->slot));
  262. }
  263. if (!slotInfo) {
  264. // workaround - the builtin module has no name
  265. if (!flatName.EqualsLiteral("Root Certificates")) {
  266. // Give up.
  267. return NS_ERROR_FAILURE;
  268. }
  269. slotInfo.reset(PK11_ReferenceSlot(mModule->slots[0]));
  270. }
  271. nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
  272. slot.forget(_retval);
  273. return NS_OK;
  274. }
  275. NS_IMETHODIMP
  276. nsPKCS11Module::ListSlots(nsISimpleEnumerator** _retval)
  277. {
  278. NS_ENSURE_ARG_POINTER(_retval);
  279. nsNSSShutDownPreventionLock locker;
  280. if (isAlreadyShutDown()) {
  281. return NS_ERROR_NOT_AVAILABLE;
  282. }
  283. nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
  284. if (!array) {
  285. return NS_ERROR_FAILURE;
  286. }
  287. /* applications which allow new slot creation (which Firefox now does
  288. * since it uses the WaitForSlotEvent call) need to hold the
  289. * ModuleList Read lock to prevent the slot array from changing out
  290. * from under it. */
  291. AutoSECMODListReadLock lock;
  292. for (int i = 0; i < mModule->slotCount; i++) {
  293. if (mModule->slots[i]) {
  294. nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(mModule->slots[i]);
  295. nsresult rv = array->AppendElement(slot, false);
  296. if (NS_FAILED(rv)) {
  297. return rv;
  298. }
  299. }
  300. }
  301. return array->Enumerate(_retval);
  302. }
  303. NS_IMPL_ISUPPORTS(nsPKCS11ModuleDB, nsIPKCS11ModuleDB, nsICryptoFIPSInfo)
  304. nsPKCS11ModuleDB::nsPKCS11ModuleDB()
  305. {
  306. }
  307. nsPKCS11ModuleDB::~nsPKCS11ModuleDB()
  308. {
  309. nsNSSShutDownPreventionLock locker;
  310. if (isAlreadyShutDown()) {
  311. return;
  312. }
  313. shutdown(ShutdownCalledFrom::Object);
  314. }
  315. NS_IMETHODIMP
  316. nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module** _retval)
  317. {
  318. NS_ENSURE_ARG_POINTER(_retval);
  319. nsNSSShutDownPreventionLock locker;
  320. if (isAlreadyShutDown()) {
  321. return NS_ERROR_NOT_AVAILABLE;
  322. }
  323. UniqueSECMODModule nssMod(
  324. SECMOD_CreateModule(nullptr, SECMOD_INT_NAME, nullptr, SECMOD_INT_FLAGS));
  325. if (!nssMod) {
  326. return NS_ERROR_FAILURE;
  327. }
  328. nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
  329. module.forget(_retval);
  330. return NS_OK;
  331. }
  332. NS_IMETHODIMP
  333. nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module** _retval)
  334. {
  335. NS_ENSURE_ARG_POINTER(_retval);
  336. nsNSSShutDownPreventionLock locker;
  337. if (isAlreadyShutDown()) {
  338. return NS_ERROR_NOT_AVAILABLE;
  339. }
  340. UniqueSECMODModule nssMod(
  341. SECMOD_CreateModule(nullptr, SECMOD_FIPS_NAME, nullptr, SECMOD_FIPS_FLAGS));
  342. if (!nssMod) {
  343. return NS_ERROR_FAILURE;
  344. }
  345. nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
  346. module.forget(_retval);
  347. return NS_OK;
  348. }
  349. NS_IMETHODIMP
  350. nsPKCS11ModuleDB::FindModuleByName(const nsACString& name,
  351. /*out*/ nsIPKCS11Module** _retval)
  352. {
  353. NS_ENSURE_ARG_POINTER(_retval);
  354. nsNSSShutDownPreventionLock locker;
  355. if (isAlreadyShutDown()) {
  356. return NS_ERROR_NOT_AVAILABLE;
  357. }
  358. UniqueSECMODModule mod(SECMOD_FindModule(PromiseFlatCString(name).get()));
  359. if (!mod) {
  360. return NS_ERROR_FAILURE;
  361. }
  362. nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod.get());
  363. module.forget(_retval);
  364. return NS_OK;
  365. }
  366. /* This is essentially the same as nsIPK11Token::findTokenByName, except
  367. * that it returns an nsIPKCS11Slot, which may be desired.
  368. */
  369. NS_IMETHODIMP
  370. nsPKCS11ModuleDB::FindSlotByName(const nsACString& name,
  371. /*out*/ nsIPKCS11Slot** _retval)
  372. {
  373. NS_ENSURE_ARG_POINTER(_retval);
  374. nsNSSShutDownPreventionLock locker;
  375. if (isAlreadyShutDown()) {
  376. return NS_ERROR_NOT_AVAILABLE;
  377. }
  378. UniquePK11SlotInfo slotInfo(
  379. PK11_FindSlotByName(PromiseFlatCString(name).get()));
  380. if (!slotInfo) {
  381. return NS_ERROR_FAILURE;
  382. }
  383. nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
  384. slot.forget(_retval);
  385. return NS_OK;
  386. }
  387. NS_IMETHODIMP
  388. nsPKCS11ModuleDB::ListModules(nsISimpleEnumerator** _retval)
  389. {
  390. NS_ENSURE_ARG_POINTER(_retval);
  391. nsNSSShutDownPreventionLock locker;
  392. if (isAlreadyShutDown()) {
  393. return NS_ERROR_NOT_AVAILABLE;
  394. }
  395. nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
  396. if (!array) {
  397. return NS_ERROR_FAILURE;
  398. }
  399. /* lock down the list for reading */
  400. AutoSECMODListReadLock lock;
  401. for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
  402. list = list->next) {
  403. nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
  404. nsresult rv = array->AppendElement(module, false);
  405. if (NS_FAILED(rv)) {
  406. return rv;
  407. }
  408. }
  409. /* Get the modules in the database that didn't load */
  410. for (SECMODModuleList* list = SECMOD_GetDeadModuleList(); list;
  411. list = list->next) {
  412. nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
  413. nsresult rv = array->AppendElement(module, false);
  414. if (NS_FAILED(rv)) {
  415. return rv;
  416. }
  417. }
  418. return array->Enumerate(_retval);
  419. }
  420. NS_IMETHODIMP
  421. nsPKCS11ModuleDB::GetCanToggleFIPS(bool* aCanToggleFIPS)
  422. {
  423. NS_ENSURE_ARG_POINTER(aCanToggleFIPS);
  424. nsNSSShutDownPreventionLock locker;
  425. if (isAlreadyShutDown()) {
  426. return NS_ERROR_NOT_AVAILABLE;
  427. }
  428. *aCanToggleFIPS = SECMOD_CanDeleteInternalModule();
  429. return NS_OK;
  430. }
  431. NS_IMETHODIMP
  432. nsPKCS11ModuleDB::ToggleFIPSMode()
  433. {
  434. nsNSSShutDownPreventionLock locker;
  435. if (isAlreadyShutDown()) {
  436. return NS_ERROR_NOT_AVAILABLE;
  437. }
  438. // The way to toggle FIPS mode in NSS is extremely obscure. Basically, we
  439. // delete the internal module, and it gets replaced with the opposite module
  440. // (i.e. if it was FIPS before, then it becomes non-FIPS next).
  441. // SECMOD_GetInternalModule() returns a pointer to a local copy of the
  442. // internal module stashed in NSS. We don't want to delete it since it will
  443. // cause much pain in NSS.
  444. SECMODModule* internal = SECMOD_GetInternalModule();
  445. if (!internal) {
  446. return NS_ERROR_FAILURE;
  447. }
  448. if (SECMOD_DeleteInternalModule(internal->commonName) != SECSuccess) {
  449. return NS_ERROR_FAILURE;
  450. }
  451. return NS_OK;
  452. }
  453. NS_IMETHODIMP
  454. nsPKCS11ModuleDB::GetIsFIPSEnabled(bool* aIsFIPSEnabled)
  455. {
  456. NS_ENSURE_ARG_POINTER(aIsFIPSEnabled);
  457. nsNSSShutDownPreventionLock locker;
  458. if (isAlreadyShutDown()) {
  459. return NS_ERROR_NOT_AVAILABLE;
  460. }
  461. *aIsFIPSEnabled = PK11_IsFIPS();
  462. return NS_OK;
  463. }
  464. NS_IMETHODIMP
  465. nsPKCS11ModuleDB::GetIsFIPSModeActive(bool* aIsFIPSModeActive)
  466. {
  467. return GetIsFIPSEnabled(aIsFIPSModeActive);
  468. }