security/manager/ssl/src/nsPKCS11Slot.cpp

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:fe642c71a8e7
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 #include "nsPK11TokenDB.h"
7
8 #include "nsCOMPtr.h"
9 #include "nsISupportsArray.h"
10 #include "nsString.h"
11 #include "nsReadableUtils.h"
12 #include "nsCRT.h"
13
14 #include "secmod.h"
15
16 #ifdef PR_LOGGING
17 extern PRLogModuleInfo* gPIPNSSLog;
18 #endif
19
20 NS_IMPL_ISUPPORTS(nsPKCS11Slot, nsIPKCS11Slot)
21
22 nsPKCS11Slot::nsPKCS11Slot(PK11SlotInfo *slot)
23 {
24 nsNSSShutDownPreventionLock locker;
25 if (isAlreadyShutDown())
26 return;
27
28 PK11_ReferenceSlot(slot);
29 mSlot = slot;
30 mSeries = PK11_GetSlotSeries(slot);
31 refreshSlotInfo();
32 }
33
34 void
35 nsPKCS11Slot::refreshSlotInfo()
36 {
37 CK_SLOT_INFO slot_info;
38 if (PK11_GetSlotInfo(mSlot, &slot_info) == SECSuccess) {
39 // Set the Description field
40 const char *ccDesc = (const char*)slot_info.slotDescription;
41 const nsACString &cDesc = Substring(
42 ccDesc,
43 ccDesc+PL_strnlen(ccDesc, sizeof(slot_info.slotDescription)));
44 mSlotDesc = NS_ConvertUTF8toUTF16(cDesc);
45 mSlotDesc.Trim(" ", false, true);
46 // Set the Manufacturer field
47 const char *ccManID = (const char*)slot_info.manufacturerID;
48 const nsACString &cManID = Substring(
49 ccManID,
50 ccManID+PL_strnlen(ccManID, sizeof(slot_info.manufacturerID)));
51 mSlotManID = NS_ConvertUTF8toUTF16(cManID);
52 mSlotManID.Trim(" ", false, true);
53 // Set the Hardware Version field
54 mSlotHWVersion = EmptyString();
55 mSlotHWVersion.AppendInt(slot_info.hardwareVersion.major);
56 mSlotHWVersion.AppendLiteral(".");
57 mSlotHWVersion.AppendInt(slot_info.hardwareVersion.minor);
58 // Set the Firmware Version field
59 mSlotFWVersion = EmptyString();
60 mSlotFWVersion.AppendInt(slot_info.firmwareVersion.major);
61 mSlotFWVersion.AppendLiteral(".");
62 mSlotFWVersion.AppendInt(slot_info.firmwareVersion.minor);
63 }
64
65 }
66
67 nsPKCS11Slot::~nsPKCS11Slot()
68 {
69 nsNSSShutDownPreventionLock locker;
70 if (isAlreadyShutDown()) {
71 return;
72 }
73 destructorSafeDestroyNSSReference();
74 shutdown(calledFromObject);
75 }
76
77 void nsPKCS11Slot::virtualDestroyNSSReference()
78 {
79 destructorSafeDestroyNSSReference();
80 }
81
82 void nsPKCS11Slot::destructorSafeDestroyNSSReference()
83 {
84 if (mSlot) {
85 PK11_FreeSlot(mSlot);
86 mSlot = nullptr;
87 }
88 }
89
90 /* readonly attribute wstring name; */
91 NS_IMETHODIMP
92 nsPKCS11Slot::GetName(char16_t **aName)
93 {
94 nsNSSShutDownPreventionLock locker;
95 if (isAlreadyShutDown())
96 return NS_ERROR_NOT_AVAILABLE;
97
98 char *csn = PK11_GetSlotName(mSlot);
99 if (*csn) {
100 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(csn));
101 } else if (PK11_HasRootCerts(mSlot)) {
102 // This is a workaround to an Root Module bug - the root certs module has
103 // no slot name. Not bothering to localize, because this is a workaround
104 // and for now all the slot names returned by NSS are char * anyway.
105 *aName = ToNewUnicode(NS_LITERAL_STRING("Root Certificates"));
106 } else {
107 // same as above, this is a catch-all
108 *aName = ToNewUnicode(NS_LITERAL_STRING("Unnamed Slot"));
109 }
110 if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
111 return NS_OK;
112 }
113
114 /* readonly attribute wstring desc; */
115 NS_IMETHODIMP
116 nsPKCS11Slot::GetDesc(char16_t **aDesc)
117 {
118 nsNSSShutDownPreventionLock locker;
119 if (isAlreadyShutDown())
120 return NS_ERROR_NOT_AVAILABLE;
121
122 if (mSeries != PK11_GetSlotSeries(mSlot)) {
123 refreshSlotInfo();
124 }
125
126 *aDesc = ToNewUnicode(mSlotDesc);
127 if (!*aDesc) return NS_ERROR_OUT_OF_MEMORY;
128 return NS_OK;
129 }
130
131 /* readonly attribute wstring manID; */
132 NS_IMETHODIMP
133 nsPKCS11Slot::GetManID(char16_t **aManID)
134 {
135 if (mSeries != PK11_GetSlotSeries(mSlot)) {
136 refreshSlotInfo();
137 }
138 *aManID = ToNewUnicode(mSlotManID);
139 if (!*aManID) return NS_ERROR_OUT_OF_MEMORY;
140 return NS_OK;
141 }
142
143 /* readonly attribute wstring HWVersion; */
144 NS_IMETHODIMP
145 nsPKCS11Slot::GetHWVersion(char16_t **aHWVersion)
146 {
147 if (mSeries != PK11_GetSlotSeries(mSlot)) {
148 refreshSlotInfo();
149 }
150 *aHWVersion = ToNewUnicode(mSlotHWVersion);
151 if (!*aHWVersion) return NS_ERROR_OUT_OF_MEMORY;
152 return NS_OK;
153 }
154
155 /* readonly attribute wstring FWVersion; */
156 NS_IMETHODIMP
157 nsPKCS11Slot::GetFWVersion(char16_t **aFWVersion)
158 {
159 if (mSeries != PK11_GetSlotSeries(mSlot)) {
160 refreshSlotInfo();
161 }
162 *aFWVersion = ToNewUnicode(mSlotFWVersion);
163 if (!*aFWVersion) return NS_ERROR_OUT_OF_MEMORY;
164 return NS_OK;
165 }
166
167 /* nsIPK11Token getToken (); */
168 NS_IMETHODIMP
169 nsPKCS11Slot::GetToken(nsIPK11Token **_retval)
170 {
171 nsNSSShutDownPreventionLock locker;
172 if (isAlreadyShutDown())
173 return NS_ERROR_NOT_AVAILABLE;
174
175 nsCOMPtr<nsIPK11Token> token = new nsPK11Token(mSlot);
176 *_retval = token;
177 NS_ADDREF(*_retval);
178 return NS_OK;
179 }
180
181 /* readonly attribute wstring tokenName; */
182 NS_IMETHODIMP
183 nsPKCS11Slot::GetTokenName(char16_t **aName)
184 {
185 nsNSSShutDownPreventionLock locker;
186 if (isAlreadyShutDown())
187 return NS_ERROR_NOT_AVAILABLE;
188
189 if (!PK11_IsPresent(mSlot)) {
190 *aName = nullptr;
191 return NS_OK;
192 }
193
194 if (mSeries != PK11_GetSlotSeries(mSlot)) {
195 refreshSlotInfo();
196 }
197
198
199 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot)));
200 if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
201 return NS_OK;
202 }
203
204 NS_IMETHODIMP
205 nsPKCS11Slot::GetStatus(uint32_t *_retval)
206 {
207 nsNSSShutDownPreventionLock locker;
208 if (isAlreadyShutDown())
209 return NS_ERROR_NOT_AVAILABLE;
210
211 if (PK11_IsDisabled(mSlot))
212 *_retval = SLOT_DISABLED;
213 else if (!PK11_IsPresent(mSlot))
214 *_retval = SLOT_NOT_PRESENT;
215 else if (PK11_NeedLogin(mSlot) && PK11_NeedUserInit(mSlot))
216 *_retval = SLOT_UNINITIALIZED;
217 else if (PK11_NeedLogin(mSlot) && !PK11_IsLoggedIn(mSlot, nullptr))
218 *_retval = SLOT_NOT_LOGGED_IN;
219 else if (PK11_NeedLogin(mSlot))
220 *_retval = SLOT_LOGGED_IN;
221 else
222 *_retval = SLOT_READY;
223 return NS_OK;
224 }
225
226 NS_IMPL_ISUPPORTS(nsPKCS11Module, nsIPKCS11Module)
227
228 nsPKCS11Module::nsPKCS11Module(SECMODModule *module)
229 {
230 nsNSSShutDownPreventionLock locker;
231 if (isAlreadyShutDown())
232 return;
233
234 SECMOD_ReferenceModule(module);
235 mModule = module;
236 }
237
238 nsPKCS11Module::~nsPKCS11Module()
239 {
240 nsNSSShutDownPreventionLock locker;
241 if (isAlreadyShutDown()) {
242 return;
243 }
244 destructorSafeDestroyNSSReference();
245 shutdown(calledFromObject);
246 }
247
248 void nsPKCS11Module::virtualDestroyNSSReference()
249 {
250 destructorSafeDestroyNSSReference();
251 }
252
253 void nsPKCS11Module::destructorSafeDestroyNSSReference()
254 {
255 if (mModule) {
256 SECMOD_DestroyModule(mModule);
257 mModule = nullptr;
258 }
259 }
260
261 /* readonly attribute wstring name; */
262 NS_IMETHODIMP
263 nsPKCS11Module::GetName(char16_t **aName)
264 {
265 nsNSSShutDownPreventionLock locker;
266 if (isAlreadyShutDown())
267 return NS_ERROR_NOT_AVAILABLE;
268
269 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->commonName));
270 return NS_OK;
271 }
272
273 /* readonly attribute wstring libName; */
274 NS_IMETHODIMP
275 nsPKCS11Module::GetLibName(char16_t **aName)
276 {
277 nsNSSShutDownPreventionLock locker;
278 if (isAlreadyShutDown())
279 return NS_ERROR_NOT_AVAILABLE;
280
281 if ( mModule->dllName ) {
282 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->dllName));
283 } else {
284 *aName = nullptr;
285 }
286 return NS_OK;
287 }
288
289 /* nsIPKCS11Slot findSlotByName(in wstring name); */
290 NS_IMETHODIMP
291 nsPKCS11Module::FindSlotByName(const char16_t *aName,
292 nsIPKCS11Slot **_retval)
293 {
294 nsNSSShutDownPreventionLock locker;
295 if (isAlreadyShutDown())
296 return NS_ERROR_NOT_AVAILABLE;
297
298 char *asciiname = ToNewUTF8String(nsDependentString(aName));
299 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
300 PK11SlotInfo *slotinfo = nullptr;
301 PK11SlotList *slotList = PK11_FindSlotsByNames(mModule->dllName,
302 asciiname /* slotName */, nullptr /* token Name */, false);
303 if (!slotList) {
304 /* name must be the token name */
305 slotList = PK11_FindSlotsByNames(mModule->dllName,
306 nullptr /*slot Name */, asciiname /* token Name */, false);
307 }
308 if (slotList) {
309 /* should only be one */
310 if (slotList->head && slotList->head->slot) {
311 slotinfo = PK11_ReferenceSlot(slotList->head->slot);
312 }
313 PK11_FreeSlotList(slotList);
314 }
315 if (!slotinfo) {
316 // workaround - the builtin module has no name
317 if (!asciiname) {
318 return NS_ERROR_FAILURE;
319 } else if (nsCRT::strcmp(asciiname, "Root Certificates") == 0) {
320 slotinfo = PK11_ReferenceSlot(mModule->slots[0]);
321 } else {
322 // give up
323 nsMemory::Free(asciiname);
324 return NS_ERROR_FAILURE;
325 }
326 }
327 nsMemory::Free(asciiname);
328 nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotinfo);
329 PK11_FreeSlot(slotinfo);
330 *_retval = slot;
331 NS_ADDREF(*_retval);
332 return NS_OK;
333 }
334
335 /* nsIEnumerator listSlots (); */
336 NS_IMETHODIMP
337 nsPKCS11Module::ListSlots(nsIEnumerator **_retval)
338 {
339 nsNSSShutDownPreventionLock locker;
340 if (isAlreadyShutDown())
341 return NS_ERROR_NOT_AVAILABLE;
342
343 nsresult rv = NS_OK;
344 int i;
345 /* get isupports array */
346 nsCOMPtr<nsISupportsArray> array;
347 rv = NS_NewISupportsArray(getter_AddRefs(array));
348 if (NS_FAILED(rv)) return rv;
349 /* applications which allow new slot creation (which Firefox now does
350 * since it uses the WaitForSlotEvent call) need to hold the
351 * ModuleList Read lock to prevent the slot array from changing out
352 * from under it. */
353 SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
354 SECMOD_GetReadLock(lock);
355 for (i=0; i<mModule->slotCount; i++) {
356 if (mModule->slots[i]) {
357 nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(mModule->slots[i]);
358 array->AppendElement(slot);
359 }
360 }
361 SECMOD_ReleaseReadLock(lock);
362 rv = array->Enumerate(_retval);
363 return rv;
364 }
365
366 NS_IMPL_ISUPPORTS(nsPKCS11ModuleDB, nsIPKCS11ModuleDB, nsICryptoFIPSInfo)
367
368 nsPKCS11ModuleDB::nsPKCS11ModuleDB()
369 {
370 }
371
372 nsPKCS11ModuleDB::~nsPKCS11ModuleDB()
373 {
374 }
375
376 /* nsIPKCS11Module getInternal (); */
377 NS_IMETHODIMP
378 nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module **_retval)
379 {
380 nsNSSShutDownPreventionLock locker;
381 SECMODModule *nssMod =
382 SECMOD_CreateModule(nullptr, SECMOD_INT_NAME, nullptr, SECMOD_INT_FLAGS);
383 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod);
384 SECMOD_DestroyModule(nssMod);
385 *_retval = module;
386 NS_ADDREF(*_retval);
387 return NS_OK;
388 }
389
390 /* nsIPKCS11Module getInternalFIPS (); */
391 NS_IMETHODIMP
392 nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module **_retval)
393 {
394 nsNSSShutDownPreventionLock locker;
395 SECMODModule *nssMod =
396 SECMOD_CreateModule(nullptr, SECMOD_FIPS_NAME, nullptr, SECMOD_FIPS_FLAGS);
397 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod);
398 SECMOD_DestroyModule(nssMod);
399 *_retval = module;
400 NS_ADDREF(*_retval);
401 return NS_OK;
402 }
403
404 /* nsIPKCS11Module findModuleByName(in wstring name); */
405 NS_IMETHODIMP
406 nsPKCS11ModuleDB::FindModuleByName(const char16_t *aName,
407 nsIPKCS11Module **_retval)
408 {
409 nsNSSShutDownPreventionLock locker;
410 NS_ConvertUTF16toUTF8 aUtf8Name(aName);
411 SECMODModule *mod =
412 SECMOD_FindModule(const_cast<char *>(aUtf8Name.get()));
413 if (!mod)
414 return NS_ERROR_FAILURE;
415 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod);
416 SECMOD_DestroyModule(mod);
417 *_retval = module;
418 NS_ADDREF(*_retval);
419 return NS_OK;
420 }
421
422 /* This is essentially the same as nsIPK11Token::findTokenByName, except
423 * that it returns an nsIPKCS11Slot, which may be desired.
424 */
425 /* nsIPKCS11Module findSlotByName(in wstring name); */
426 NS_IMETHODIMP
427 nsPKCS11ModuleDB::FindSlotByName(const char16_t *aName,
428 nsIPKCS11Slot **_retval)
429 {
430 nsNSSShutDownPreventionLock locker;
431 NS_ConvertUTF16toUTF8 aUtf8Name(aName);
432 PK11SlotInfo *slotinfo =
433 PK11_FindSlotByName(const_cast<char*>(aUtf8Name.get()));
434 if (!slotinfo)
435 return NS_ERROR_FAILURE;
436 nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotinfo);
437 PK11_FreeSlot(slotinfo);
438 *_retval = slot;
439 NS_ADDREF(*_retval);
440 return NS_OK;
441 }
442
443 /* nsIEnumerator listModules (); */
444 NS_IMETHODIMP
445 nsPKCS11ModuleDB::ListModules(nsIEnumerator **_retval)
446 {
447 nsNSSShutDownPreventionLock locker;
448 nsresult rv = NS_OK;
449 /* get isupports array */
450 nsCOMPtr<nsISupportsArray> array;
451 rv = NS_NewISupportsArray(getter_AddRefs(array));
452 if (NS_FAILED(rv)) return rv;
453 /* get the default list of modules */
454 SECMODModuleList *list = SECMOD_GetDefaultModuleList();
455 /* lock down the list for reading */
456 SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
457 SECMOD_GetReadLock(lock);
458 while (list) {
459 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
460 array->AppendElement(module);
461 list = list->next;
462 }
463 /* Get the modules in the database that didn't load */
464 list = SECMOD_GetDeadModuleList();
465 while (list) {
466 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
467 array->AppendElement(module);
468 list = list->next;
469 }
470 SECMOD_ReleaseReadLock(lock);
471 rv = array->Enumerate(_retval);
472 return rv;
473 }
474
475 NS_IMETHODIMP nsPKCS11ModuleDB::GetCanToggleFIPS(bool *aCanToggleFIPS)
476 {
477 nsNSSShutDownPreventionLock locker;
478 *aCanToggleFIPS = SECMOD_CanDeleteInternalModule();
479 return NS_OK;
480 }
481
482
483 /* void toggleFIPSMode (); */
484 NS_IMETHODIMP nsPKCS11ModuleDB::ToggleFIPSMode()
485 {
486 nsNSSShutDownPreventionLock locker;
487 // The way to toggle FIPS mode in NSS is extremely obscure.
488 // Basically, we delete the internal module, and voila it
489 // gets replaced with the opposite module, ie if it was
490 // FIPS before, then it becomes non-FIPS next.
491 SECMODModule *internal;
492
493 // This function returns us a pointer to a local copy of
494 // the internal module stashed in NSS. We don't want to
495 // delete it since it will cause much pain in NSS.
496 internal = SECMOD_GetInternalModule();
497 if (!internal)
498 return NS_ERROR_FAILURE;
499
500 SECStatus srv = SECMOD_DeleteInternalModule(internal->commonName);
501 if (srv != SECSuccess)
502 return NS_ERROR_FAILURE;
503
504 return NS_OK;
505 }
506
507 /* readonly attribute boolean isFIPSEnabled; */
508 NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSEnabled(bool *aIsFIPSEnabled)
509 {
510 nsNSSShutDownPreventionLock locker;
511 *aIsFIPSEnabled = PK11_IsFIPS();
512 return NS_OK;
513 }
514
515 NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSModeActive(bool *aIsFIPSModeActive)
516 {
517 return GetIsFIPSEnabled(aIsFIPSModeActive);
518 }

mercurial