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