Bug 452390 Tracemonkey will crash if the compiler doesn't have FASTCALL r=danderson
[wine-gecko.git] / security / manager / ssl / src / nsPKCS11Slot.cpp
blob7bae04c80b86667f8a6240d40e485e8d1ec34320
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Ian McGreer <mcgreer@netscape.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsPKCS11Slot.h"
39 #include "nsPK11TokenDB.h"
41 #include "nsCOMPtr.h"
42 #include "nsISupportsArray.h"
43 #include "nsString.h"
44 #include "nsReadableUtils.h"
45 #include "nsCRT.h"
47 #include "secmod.h"
49 #ifdef PR_LOGGING
50 extern PRLogModuleInfo* gPIPNSSLog;
51 #endif
53 NS_IMPL_ISUPPORTS1(nsPKCS11Slot, nsIPKCS11Slot)
55 nsPKCS11Slot::nsPKCS11Slot(PK11SlotInfo *slot)
57 nsNSSShutDownPreventionLock locker;
58 if (isAlreadyShutDown())
59 return;
61 PK11_ReferenceSlot(slot);
62 mSlot = slot;
63 mSeries = PK11_GetSlotSeries(slot);
64 refreshSlotInfo();
67 void
68 nsPKCS11Slot::refreshSlotInfo()
70 CK_SLOT_INFO slot_info;
71 if (PK11_GetSlotInfo(mSlot, &slot_info) == SECSuccess) {
72 // Set the Description field
73 const char *ccDesc = (const char*)slot_info.slotDescription;
74 const nsACString &cDesc = Substring(
75 ccDesc,
76 ccDesc+PL_strnlen(ccDesc, sizeof(slot_info.slotDescription)));
77 mSlotDesc = NS_ConvertUTF8toUTF16(cDesc);
78 mSlotDesc.Trim(" ", PR_FALSE, PR_TRUE);
79 // Set the Manufacturer field
80 const char *ccManID = (const char*)slot_info.manufacturerID;
81 const nsACString &cManID = Substring(
82 ccManID,
83 ccManID+PL_strnlen(ccManID, sizeof(slot_info.manufacturerID)));
84 mSlotManID = NS_ConvertUTF8toUTF16(cManID);
85 mSlotManID.Trim(" ", PR_FALSE, PR_TRUE);
86 // Set the Hardware Version field
87 mSlotHWVersion = EmptyString();
88 mSlotHWVersion.AppendInt(slot_info.hardwareVersion.major);
89 mSlotHWVersion.AppendLiteral(".");
90 mSlotHWVersion.AppendInt(slot_info.hardwareVersion.minor);
91 // Set the Firmware Version field
92 mSlotFWVersion = EmptyString();
93 mSlotFWVersion.AppendInt(slot_info.firmwareVersion.major);
94 mSlotFWVersion.AppendLiteral(".");
95 mSlotFWVersion.AppendInt(slot_info.firmwareVersion.minor);
100 nsPKCS11Slot::~nsPKCS11Slot()
102 nsNSSShutDownPreventionLock locker;
103 if (isAlreadyShutDown())
104 return;
106 destructorSafeDestroyNSSReference();
107 shutdown(calledFromObject);
110 void nsPKCS11Slot::virtualDestroyNSSReference()
112 destructorSafeDestroyNSSReference();
115 void nsPKCS11Slot::destructorSafeDestroyNSSReference()
117 if (isAlreadyShutDown())
118 return;
120 if (mSlot) {
121 PK11_FreeSlot(mSlot);
122 mSlot = nsnull;
126 /* readonly attribute wstring name; */
127 NS_IMETHODIMP
128 nsPKCS11Slot::GetName(PRUnichar **aName)
130 nsNSSShutDownPreventionLock locker;
131 if (isAlreadyShutDown())
132 return NS_ERROR_NOT_AVAILABLE;
134 char *csn = PK11_GetSlotName(mSlot);
135 if (*csn) {
136 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(csn));
137 } else if (PK11_HasRootCerts(mSlot)) {
138 // This is a workaround to an Root Module bug - the root certs module has
139 // no slot name. Not bothering to localize, because this is a workaround
140 // and for now all the slot names returned by NSS are char * anyway.
141 *aName = ToNewUnicode(NS_LITERAL_STRING("Root Certificates"));
142 } else {
143 // same as above, this is a catch-all
144 *aName = ToNewUnicode(NS_LITERAL_STRING("Unnamed Slot"));
146 if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
147 return NS_OK;
150 /* readonly attribute wstring desc; */
151 NS_IMETHODIMP
152 nsPKCS11Slot::GetDesc(PRUnichar **aDesc)
154 nsNSSShutDownPreventionLock locker;
155 if (isAlreadyShutDown())
156 return NS_ERROR_NOT_AVAILABLE;
158 if (mSeries != PK11_GetSlotSeries(mSlot)) {
159 refreshSlotInfo();
162 *aDesc = ToNewUnicode(mSlotDesc);
163 if (!*aDesc) return NS_ERROR_OUT_OF_MEMORY;
164 return NS_OK;
167 /* readonly attribute wstring manID; */
168 NS_IMETHODIMP
169 nsPKCS11Slot::GetManID(PRUnichar **aManID)
171 if (mSeries != PK11_GetSlotSeries(mSlot)) {
172 refreshSlotInfo();
174 *aManID = ToNewUnicode(mSlotManID);
175 if (!*aManID) return NS_ERROR_OUT_OF_MEMORY;
176 return NS_OK;
179 /* readonly attribute wstring HWVersion; */
180 NS_IMETHODIMP
181 nsPKCS11Slot::GetHWVersion(PRUnichar **aHWVersion)
183 if (mSeries != PK11_GetSlotSeries(mSlot)) {
184 refreshSlotInfo();
186 *aHWVersion = ToNewUnicode(mSlotHWVersion);
187 if (!*aHWVersion) return NS_ERROR_OUT_OF_MEMORY;
188 return NS_OK;
191 /* readonly attribute wstring FWVersion; */
192 NS_IMETHODIMP
193 nsPKCS11Slot::GetFWVersion(PRUnichar **aFWVersion)
195 if (mSeries != PK11_GetSlotSeries(mSlot)) {
196 refreshSlotInfo();
198 *aFWVersion = ToNewUnicode(mSlotFWVersion);
199 if (!*aFWVersion) return NS_ERROR_OUT_OF_MEMORY;
200 return NS_OK;
203 /* nsIPK11Token getToken (); */
204 NS_IMETHODIMP
205 nsPKCS11Slot::GetToken(nsIPK11Token **_retval)
207 nsNSSShutDownPreventionLock locker;
208 if (isAlreadyShutDown())
209 return NS_ERROR_NOT_AVAILABLE;
211 nsCOMPtr<nsIPK11Token> token = new nsPK11Token(mSlot);
212 if (!token)
213 return NS_ERROR_OUT_OF_MEMORY;
214 *_retval = token;
215 NS_ADDREF(*_retval);
216 return NS_OK;
219 /* readonly attribute wstring tokenName; */
220 NS_IMETHODIMP
221 nsPKCS11Slot::GetTokenName(PRUnichar **aName)
223 nsNSSShutDownPreventionLock locker;
224 if (isAlreadyShutDown())
225 return NS_ERROR_NOT_AVAILABLE;
227 if (!PK11_IsPresent(mSlot)) {
228 *aName = nsnull;
229 return NS_OK;
232 if (mSeries != PK11_GetSlotSeries(mSlot)) {
233 refreshSlotInfo();
237 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot)));
238 if (!*aName) return NS_ERROR_OUT_OF_MEMORY;
239 return NS_OK;
242 NS_IMETHODIMP
243 nsPKCS11Slot::GetStatus(PRUint32 *_retval)
245 nsNSSShutDownPreventionLock locker;
246 if (isAlreadyShutDown())
247 return NS_ERROR_NOT_AVAILABLE;
249 if (PK11_IsDisabled(mSlot))
250 *_retval = SLOT_DISABLED;
251 else if (!PK11_IsPresent(mSlot))
252 *_retval = SLOT_NOT_PRESENT;
253 else if (PK11_NeedLogin(mSlot) && PK11_NeedUserInit(mSlot))
254 *_retval = SLOT_UNINITIALIZED;
255 else if (PK11_NeedLogin(mSlot) && !PK11_IsLoggedIn(mSlot, NULL))
256 *_retval = SLOT_NOT_LOGGED_IN;
257 else if (PK11_NeedLogin(mSlot))
258 *_retval = SLOT_LOGGED_IN;
259 else
260 *_retval = SLOT_READY;
261 return NS_OK;
264 NS_IMPL_ISUPPORTS1(nsPKCS11Module, nsIPKCS11Module)
266 nsPKCS11Module::nsPKCS11Module(SECMODModule *module)
268 nsNSSShutDownPreventionLock locker;
269 if (isAlreadyShutDown())
270 return;
272 SECMOD_ReferenceModule(module);
273 mModule = module;
276 nsPKCS11Module::~nsPKCS11Module()
278 nsNSSShutDownPreventionLock locker;
279 if (isAlreadyShutDown())
280 return;
282 destructorSafeDestroyNSSReference();
283 shutdown(calledFromObject);
286 void nsPKCS11Module::virtualDestroyNSSReference()
288 destructorSafeDestroyNSSReference();
291 void nsPKCS11Module::destructorSafeDestroyNSSReference()
293 if (isAlreadyShutDown())
294 return;
296 if (mModule) {
297 SECMOD_DestroyModule(mModule);
298 mModule = nsnull;
302 /* readonly attribute wstring name; */
303 NS_IMETHODIMP
304 nsPKCS11Module::GetName(PRUnichar **aName)
306 nsNSSShutDownPreventionLock locker;
307 if (isAlreadyShutDown())
308 return NS_ERROR_NOT_AVAILABLE;
310 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->commonName));
311 return NS_OK;
314 /* readonly attribute wstring libName; */
315 NS_IMETHODIMP
316 nsPKCS11Module::GetLibName(PRUnichar **aName)
318 nsNSSShutDownPreventionLock locker;
319 if (isAlreadyShutDown())
320 return NS_ERROR_NOT_AVAILABLE;
322 if ( mModule->dllName ) {
323 *aName = ToNewUnicode(NS_ConvertUTF8toUTF16(mModule->dllName));
324 } else {
325 *aName = NULL;
327 return NS_OK;
330 /* nsIPKCS11Slot findSlotByName(in wstring name); */
331 NS_IMETHODIMP
332 nsPKCS11Module::FindSlotByName(const PRUnichar *aName,
333 nsIPKCS11Slot **_retval)
335 nsNSSShutDownPreventionLock locker;
336 if (isAlreadyShutDown())
337 return NS_ERROR_NOT_AVAILABLE;
339 char *asciiname = ToNewUTF8String(nsDependentString(aName));
340 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
341 PK11SlotInfo *slotinfo = NULL;
342 PK11SlotList *slotList = PK11_FindSlotsByNames(mModule->dllName,
343 asciiname /* slotName */, NULL /* token Name */, PR_FALSE);
344 if (!slotList) {
345 /* name must be the token name */
346 slotList = PK11_FindSlotsByNames(mModule->dllName,
347 NULL /*slot Name */, asciiname /* token Name */, PR_FALSE);
349 if (slotList) {
350 /* should only be one */
351 if (slotList->head && slotList->head->slot) {
352 slotinfo = PK11_ReferenceSlot(slotList->head->slot);
354 PK11_FreeSlotList(slotList);
356 if (!slotinfo) {
357 // workaround - the builtin module has no name
358 if (asciiname == nsnull) {
359 return NS_ERROR_FAILURE;
360 } else if (nsCRT::strcmp(asciiname, "Root Certificates") == 0) {
361 slotinfo = PK11_ReferenceSlot(mModule->slots[0]);
362 } else {
363 // give up
364 nsMemory::Free(asciiname);
365 return NS_ERROR_FAILURE;
368 nsMemory::Free(asciiname);
369 nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotinfo);
370 PK11_FreeSlot(slotinfo);
371 if (!slot)
372 return NS_ERROR_OUT_OF_MEMORY;
373 *_retval = slot;
374 NS_ADDREF(*_retval);
375 return NS_OK;
378 /* nsIEnumerator listSlots (); */
379 NS_IMETHODIMP
380 nsPKCS11Module::ListSlots(nsIEnumerator **_retval)
382 nsNSSShutDownPreventionLock locker;
383 if (isAlreadyShutDown())
384 return NS_ERROR_NOT_AVAILABLE;
386 nsresult rv = NS_OK;
387 int i;
388 /* get isupports array */
389 nsCOMPtr<nsISupportsArray> array;
390 rv = NS_NewISupportsArray(getter_AddRefs(array));
391 if (NS_FAILED(rv)) return rv;
392 /* applications which allow new slot creation (which Firefox now does
393 * since it uses the WaitForSlotEvent call) need to hold the
394 * ModuleList Read lock to prevent the slot array from changing out
395 * from under it. */
396 SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
397 SECMOD_GetReadLock(lock);
398 for (i=0; i<mModule->slotCount; i++) {
399 if (mModule->slots[i]) {
400 nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(mModule->slots[i]);
401 array->AppendElement(slot);
404 SECMOD_ReleaseReadLock(lock);
405 rv = array->Enumerate(_retval);
406 return rv;
409 NS_IMPL_ISUPPORTS2(nsPKCS11ModuleDB, nsIPKCS11ModuleDB, nsICryptoFIPSInfo)
411 nsPKCS11ModuleDB::nsPKCS11ModuleDB()
415 nsPKCS11ModuleDB::~nsPKCS11ModuleDB()
419 /* nsIPKCS11Module getInternal (); */
420 NS_IMETHODIMP
421 nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module **_retval)
423 nsNSSShutDownPreventionLock locker;
424 SECMODModule *nssMod =
425 SECMOD_CreateModule(NULL,SECMOD_INT_NAME, NULL,SECMOD_INT_FLAGS);
426 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod);
427 SECMOD_DestroyModule(nssMod);
428 if (!module)
429 return NS_ERROR_OUT_OF_MEMORY;
430 *_retval = module;
431 NS_ADDREF(*_retval);
432 return NS_OK;
435 /* nsIPKCS11Module getInternalFIPS (); */
436 NS_IMETHODIMP
437 nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module **_retval)
439 nsNSSShutDownPreventionLock locker;
440 SECMODModule *nssMod =
441 SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME, NULL, SECMOD_FIPS_FLAGS);
442 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod);
443 SECMOD_DestroyModule(nssMod);
444 if (!module)
445 return NS_ERROR_OUT_OF_MEMORY;
446 *_retval = module;
447 NS_ADDREF(*_retval);
448 return NS_OK;
451 /* nsIPKCS11Module findModuleByName(in wstring name); */
452 NS_IMETHODIMP
453 nsPKCS11ModuleDB::FindModuleByName(const PRUnichar *aName,
454 nsIPKCS11Module **_retval)
456 nsNSSShutDownPreventionLock locker;
457 NS_ConvertUTF16toUTF8 aUtf8Name(aName);
458 SECMODModule *mod =
459 SECMOD_FindModule(const_cast<char *>(aUtf8Name.get()));
460 if (!mod)
461 return NS_ERROR_FAILURE;
462 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod);
463 SECMOD_DestroyModule(mod);
464 if (!module)
465 return NS_ERROR_OUT_OF_MEMORY;
466 *_retval = module;
467 NS_ADDREF(*_retval);
468 return NS_OK;
471 /* This is essentially the same as nsIPK11Token::findTokenByName, except
472 * that it returns an nsIPKCS11Slot, which may be desired.
474 /* nsIPKCS11Module findSlotByName(in wstring name); */
475 NS_IMETHODIMP
476 nsPKCS11ModuleDB::FindSlotByName(const PRUnichar *aName,
477 nsIPKCS11Slot **_retval)
479 nsNSSShutDownPreventionLock locker;
480 NS_ConvertUTF16toUTF8 aUtf8Name(aName);
481 PK11SlotInfo *slotinfo =
482 PK11_FindSlotByName(const_cast<char*>(aUtf8Name.get()));
483 if (!slotinfo)
484 return NS_ERROR_FAILURE;
485 nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotinfo);
486 PK11_FreeSlot(slotinfo);
487 if (!slot)
488 return NS_ERROR_OUT_OF_MEMORY;
489 *_retval = slot;
490 NS_ADDREF(*_retval);
491 return NS_OK;
494 /* nsIEnumerator listModules (); */
495 NS_IMETHODIMP
496 nsPKCS11ModuleDB::ListModules(nsIEnumerator **_retval)
498 nsNSSShutDownPreventionLock locker;
499 nsresult rv = NS_OK;
500 /* get isupports array */
501 nsCOMPtr<nsISupportsArray> array;
502 rv = NS_NewISupportsArray(getter_AddRefs(array));
503 if (NS_FAILED(rv)) return rv;
504 /* get the default list of modules */
505 SECMODModuleList *list = SECMOD_GetDefaultModuleList();
506 /* lock down the list for reading */
507 SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
508 SECMOD_GetReadLock(lock);
509 while (list) {
510 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
511 array->AppendElement(module);
512 list = list->next;
514 /* Get the modules in the database that didn't load */
515 list = SECMOD_GetDeadModuleList();
516 while (list) {
517 nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
518 array->AppendElement(module);
519 list = list->next;
521 SECMOD_ReleaseReadLock(lock);
522 rv = array->Enumerate(_retval);
523 return rv;
526 NS_IMETHODIMP nsPKCS11ModuleDB::GetCanToggleFIPS(PRBool *aCanToggleFIPS)
528 nsNSSShutDownPreventionLock locker;
529 *aCanToggleFIPS = SECMOD_CanDeleteInternalModule();
530 return NS_OK;
534 /* void toggleFIPSMode (); */
535 NS_IMETHODIMP nsPKCS11ModuleDB::ToggleFIPSMode()
537 nsNSSShutDownPreventionLock locker;
538 // The way to toggle FIPS mode in NSS is extremely obscure.
539 // Basically, we delete the internal module, and voila it
540 // gets replaced with the opposite module, ie if it was
541 // FIPS before, then it becomes non-FIPS next.
542 SECMODModule *internal;
544 // This function returns us a pointer to a local copy of
545 // the internal module stashed in NSS. We don't want to
546 // delete it since it will cause much pain in NSS.
547 internal = SECMOD_GetInternalModule();
548 if (!internal)
549 return NS_ERROR_FAILURE;
551 SECStatus srv = SECMOD_DeleteInternalModule(internal->commonName);
552 if (srv != SECSuccess)
553 return NS_ERROR_FAILURE;
555 return NS_OK;
558 /* readonly attribute boolean isFIPSEnabled; */
559 NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSEnabled(PRBool *aIsFIPSEnabled)
561 nsNSSShutDownPreventionLock locker;
562 *aIsFIPSEnabled = PK11_IsFIPS();
563 return NS_OK;
566 NS_IMETHODIMP nsPKCS11ModuleDB::GetIsFIPSModeActive(PRBool *aIsFIPSModeActive)
568 return GetIsFIPSEnabled(aIsFIPSModeActive);