Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(831)

Side by Side Diff: nss/lib/pk11wrap/pk11slot.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/pk11wrap/pk11skey.c ('k') | nss/lib/pk11wrap/pk11util.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 * Deal with PKCS #11 Slots.
6 */
7 #include "seccomon.h"
8 #include "secmod.h"
9 #include "nssilock.h"
10 #include "secmodi.h"
11 #include "secmodti.h"
12 #include "pkcs11t.h"
13 #include "pk11func.h"
14 #include "secitem.h"
15 #include "secerr.h"
16
17 #include "dev.h"
18 #include "dev3hack.h"
19 #include "pkim.h"
20 #include "utilpars.h"
21
22
23 /*************************************************************
24 * local static and global data
25 *************************************************************/
26
27 /*
28 * This array helps parsing between names, mechanisms, and flags.
29 * to make the config files understand more entries, add them
30 * to this table.
31 */
32 const PK11DefaultArrayEntry PK11_DefaultArray[] = {
33 { "RSA", SECMOD_RSA_FLAG, CKM_RSA_PKCS },
34 { "DSA", SECMOD_DSA_FLAG, CKM_DSA },
35 { "ECC", SECMOD_ECC_FLAG, CKM_ECDSA },
36 { "DH", SECMOD_DH_FLAG, CKM_DH_PKCS_DERIVE },
37 { "RC2", SECMOD_RC2_FLAG, CKM_RC2_CBC },
38 { "RC4", SECMOD_RC4_FLAG, CKM_RC4 },
39 { "DES", SECMOD_DES_FLAG, CKM_DES_CBC },
40 { "AES", SECMOD_AES_FLAG, CKM_AES_CBC },
41 { "Camellia", SECMOD_CAMELLIA_FLAG, CKM_CAMELLIA_CBC },
42 { "SEED", SECMOD_SEED_FLAG, CKM_SEED_CBC },
43 { "RC5", SECMOD_RC5_FLAG, CKM_RC5_CBC },
44 { "SHA-1", SECMOD_SHA1_FLAG, CKM_SHA_1 },
45 /* { "SHA224", SECMOD_SHA256_FLAG, CKM_SHA224 }, */
46 { "SHA256", SECMOD_SHA256_FLAG, CKM_SHA256 },
47 /* { "SHA384", SECMOD_SHA512_FLAG, CKM_SHA384 }, */
48 { "SHA512", SECMOD_SHA512_FLAG, CKM_SHA512 },
49 { "MD5", SECMOD_MD5_FLAG, CKM_MD5 },
50 { "MD2", SECMOD_MD2_FLAG, CKM_MD2 },
51 { "SSL", SECMOD_SSL_FLAG, CKM_SSL3_PRE_MASTER_KEY_GEN },
52 { "TLS", SECMOD_TLS_FLAG, CKM_TLS_MASTER_KEY_DERIVE },
53 { "SKIPJACK", SECMOD_FORTEZZA_FLAG, CKM_SKIPJACK_CBC64 },
54 { "Publicly-readable certs", SECMOD_FRIENDLY_FLAG, CKM_INVALID_MECHANISM },
55 { "Random Num Generator", SECMOD_RANDOM_FLAG, CKM_FAKE_RANDOM },
56 };
57 const int num_pk11_default_mechanisms =
58 sizeof(PK11_DefaultArray) / sizeof(PK11_DefaultArray[0]);
59
60 const PK11DefaultArrayEntry *
61 PK11_GetDefaultArray(int *size)
62 {
63 if (size) {
64 *size = num_pk11_default_mechanisms;
65 }
66 return PK11_DefaultArray;
67 }
68
69 /*
70 * These slotlists are lists of modules which provide default support for
71 * a given algorithm or mechanism.
72 */
73 static PK11SlotList
74 pk11_seedSlotList,
75 pk11_camelliaSlotList,
76 pk11_aesSlotList,
77 pk11_desSlotList,
78 pk11_rc4SlotList,
79 pk11_rc2SlotList,
80 pk11_rc5SlotList,
81 pk11_sha1SlotList,
82 pk11_md5SlotList,
83 pk11_md2SlotList,
84 pk11_rsaSlotList,
85 pk11_dsaSlotList,
86 pk11_dhSlotList,
87 pk11_ecSlotList,
88 pk11_ideaSlotList,
89 pk11_sslSlotList,
90 pk11_tlsSlotList,
91 pk11_randomSlotList,
92 pk11_sha256SlotList,
93 pk11_sha512SlotList; /* slots do SHA512 and SHA384 */
94
95 /************************************************************
96 * Generic Slot List and Slot List element manipulations
97 ************************************************************/
98
99 /*
100 * allocate a new list
101 */
102 PK11SlotList *
103 PK11_NewSlotList(void)
104 {
105 PK11SlotList *list;
106
107 list = (PK11SlotList *)PORT_Alloc(sizeof(PK11SlotList));
108 if (list == NULL) return NULL;
109 list->head = NULL;
110 list->tail = NULL;
111 list->lock = PZ_NewLock(nssILockList);
112 if (list->lock == NULL) {
113 PORT_Free(list);
114 return NULL;
115 }
116
117 return list;
118 }
119
120 /*
121 * free a list element when all the references go away.
122 */
123 SECStatus
124 PK11_FreeSlotListElement(PK11SlotList *list, PK11SlotListElement *le)
125 {
126 PRBool freeit = PR_FALSE;
127
128 if (list == NULL || le == NULL) {
129 PORT_SetError(SEC_ERROR_INVALID_ARGS);
130 return SECFailure;
131 }
132
133 PZ_Lock(list->lock);
134 if (le->refCount-- == 1) {
135 freeit = PR_TRUE;
136 }
137 PZ_Unlock(list->lock);
138 if (freeit) {
139 PK11_FreeSlot(le->slot);
140 PORT_Free(le);
141 }
142 return SECSuccess;
143 }
144
145 static void
146 pk11_FreeSlotListStatic(PK11SlotList *list)
147 {
148 PK11SlotListElement *le, *next ;
149 if (list == NULL) return;
150
151 for (le = list->head ; le; le = next) {
152 next = le->next;
153 PK11_FreeSlotListElement(list,le);
154 }
155 if (list->lock) {
156 PZ_DestroyLock(list->lock);
157 }
158 list->lock = NULL;
159 list->head = NULL;
160 }
161
162 /*
163 * if we are freeing the list, we must be the only ones with a pointer
164 * to the list.
165 */
166 void
167 PK11_FreeSlotList(PK11SlotList *list)
168 {
169 pk11_FreeSlotListStatic(list);
170 PORT_Free(list);
171 }
172
173 /*
174 * add a slot to a list
175 * "slot" is the slot to be added. Ownership is not transferred.
176 * "sorted" indicates whether or not the slot should be inserted according to
177 * cipherOrder of the associated module. PR_FALSE indicates that the slot
178 * should be inserted to the head of the list.
179 */
180 SECStatus
181 PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot, PRBool sorted)
182 {
183 PK11SlotListElement *le;
184 PK11SlotListElement *element;
185
186 le = (PK11SlotListElement *) PORT_Alloc(sizeof(PK11SlotListElement));
187 if (le == NULL) return SECFailure;
188
189 le->slot = PK11_ReferenceSlot(slot);
190 le->prev = NULL;
191 le->refCount = 1;
192 PZ_Lock(list->lock);
193 element = list->head;
194 /* Insertion sort, with higher cipherOrders are sorted first in the list */
195 while (element && sorted && (element->slot->module->cipherOrder >
196 le->slot->module->cipherOrder)) {
197 element = element->next;
198 }
199 if (element) {
200 le->prev = element->prev;
201 element->prev = le;
202 le->next = element;
203 } else {
204 le->prev = list->tail;
205 le->next = NULL;
206 list->tail = le;
207 }
208 if (le->prev) le->prev->next = le;
209 if (list->head == element) list->head = le;
210 PZ_Unlock(list->lock);
211
212 return SECSuccess;
213 }
214
215 /*
216 * remove a slot entry from the list
217 */
218 SECStatus
219 PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le)
220 {
221 PZ_Lock(list->lock);
222 if (le->prev) le->prev->next = le->next; else list->head = le->next;
223 if (le->next) le->next->prev = le->prev; else list->tail = le->prev;
224 le->next = le->prev = NULL;
225 PZ_Unlock(list->lock);
226 PK11_FreeSlotListElement(list,le);
227 return SECSuccess;
228 }
229
230 /*
231 * Move a list to the end of the target list.
232 * NOTE: There is no locking here... This assumes BOTH lists are private copy
233 * lists. It also does not re-sort the target list.
234 */
235 SECStatus
236 pk11_MoveListToList(PK11SlotList *target,PK11SlotList *src)
237 {
238 if (src->head == NULL) return SECSuccess;
239
240 if (target->tail == NULL) {
241 target->head = src->head;
242 } else {
243 target->tail->next = src->head;
244 }
245 src->head->prev = target->tail;
246 target->tail = src->tail;
247 src->head = src->tail = NULL;
248 return SECSuccess;
249 }
250
251 /*
252 * get an element from the list with a reference. You must own the list.
253 */
254 PK11SlotListElement *
255 PK11_GetFirstRef(PK11SlotList *list)
256 {
257 PK11SlotListElement *le;
258
259 le = list->head;
260 if (le != NULL) (le)->refCount++;
261 return le;
262 }
263
264 /*
265 * get the next element from the list with a reference. You must own the list.
266 */
267 PK11SlotListElement *
268 PK11_GetNextRef(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
269 {
270 PK11SlotListElement *new_le;
271 new_le = le->next;
272 if (new_le) new_le->refCount++;
273 PK11_FreeSlotListElement(list,le);
274 return new_le;
275 }
276
277 /*
278 * get an element safely from the list. This just makes sure that if
279 * this element is not deleted while we deal with it.
280 */
281 PK11SlotListElement *
282 PK11_GetFirstSafe(PK11SlotList *list)
283 {
284 PK11SlotListElement *le;
285
286 PZ_Lock(list->lock);
287 le = list->head;
288 if (le != NULL) (le)->refCount++;
289 PZ_Unlock(list->lock);
290 return le;
291 }
292
293 /*
294 * NOTE: if this element gets deleted, we can no longer safely traverse using
295 * it's pointers. We can either terminate the loop, or restart from the
296 * beginning. This is controlled by the restart option.
297 */
298 PK11SlotListElement *
299 PK11_GetNextSafe(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
300 {
301 PK11SlotListElement *new_le;
302 PZ_Lock(list->lock);
303 new_le = le->next;
304 if (le->next == NULL) {
305 /* if the prev and next fields are NULL then either this element
306 * has been removed and we need to walk the list again (if restart
307 * is true) or this was the only element on the list */
308 if ((le->prev == NULL) && restart && (list->head != le)) {
309 new_le = list->head;
310 }
311 }
312 if (new_le) new_le->refCount++;
313 PZ_Unlock(list->lock);
314 PK11_FreeSlotListElement(list,le);
315 return new_le;
316 }
317
318
319 /*
320 * Find the element that holds this slot
321 */
322 PK11SlotListElement *
323 PK11_FindSlotElement(PK11SlotList *list,PK11SlotInfo *slot)
324 {
325 PK11SlotListElement *le;
326
327 for (le = PK11_GetFirstSafe(list); le;
328 le = PK11_GetNextSafe(list,le,PR_TRUE)) {
329 if (le->slot == slot) return le;
330 }
331 return NULL;
332 }
333
334 /************************************************************
335 * Generic Slot Utilities
336 ************************************************************/
337 /*
338 * Create a new slot structure
339 */
340 PK11SlotInfo *
341 PK11_NewSlotInfo(SECMODModule *mod)
342 {
343 PK11SlotInfo *slot;
344
345 slot = (PK11SlotInfo *)PORT_Alloc(sizeof(PK11SlotInfo));
346 if (slot == NULL) return slot;
347
348 slot->sessionLock = mod->isThreadSafe ?
349 PZ_NewLock(nssILockSession) : mod->refLock;
350 if (slot->sessionLock == NULL) {
351 PORT_Free(slot);
352 return NULL;
353 }
354 slot->freeListLock = PZ_NewLock(nssILockFreelist);
355 if (slot->freeListLock == NULL) {
356 if (mod->isThreadSafe) {
357 PZ_DestroyLock(slot->sessionLock);
358 }
359 PORT_Free(slot);
360 return NULL;
361 }
362 slot->freeSymKeysWithSessionHead = NULL;
363 slot->freeSymKeysHead = NULL;
364 slot->keyCount = 0;
365 slot->maxKeyCount = 0;
366 slot->functionList = NULL;
367 slot->needTest = PR_TRUE;
368 slot->isPerm = PR_FALSE;
369 slot->isHW = PR_FALSE;
370 slot->isInternal = PR_FALSE;
371 slot->isThreadSafe = PR_FALSE;
372 slot->disabled = PR_FALSE;
373 slot->series = 1;
374 slot->wrapKey = 0;
375 slot->wrapMechanism = CKM_INVALID_MECHANISM;
376 slot->refKeys[0] = CK_INVALID_HANDLE;
377 slot->reason = PK11_DIS_NONE;
378 slot->readOnly = PR_TRUE;
379 slot->needLogin = PR_FALSE;
380 slot->hasRandom = PR_FALSE;
381 slot->defRWSession = PR_FALSE;
382 slot->protectedAuthPath = PR_FALSE;
383 slot->flags = 0;
384 slot->session = CK_INVALID_SESSION;
385 slot->slotID = 0;
386 slot->defaultFlags = 0;
387 slot->refCount = 1;
388 slot->askpw = 0;
389 slot->timeout = 0;
390 slot->mechanismList = NULL;
391 slot->mechanismCount = 0;
392 slot->cert_array = NULL;
393 slot->cert_count = 0;
394 slot->slot_name[0] = 0;
395 slot->token_name[0] = 0;
396 PORT_Memset(slot->serial,' ',sizeof(slot->serial));
397 slot->module = NULL;
398 slot->authTransact = 0;
399 slot->authTime = LL_ZERO;
400 slot->minPassword = 0;
401 slot->maxPassword = 0;
402 slot->hasRootCerts = PR_FALSE;
403 slot->hasRootTrust = PR_FALSE;
404 slot->nssToken = NULL;
405 return slot;
406 }
407
408 /* create a new reference to a slot so it doesn't go away */
409 PK11SlotInfo *
410 PK11_ReferenceSlot(PK11SlotInfo *slot)
411 {
412 PR_ATOMIC_INCREMENT(&slot->refCount);
413 return slot;
414 }
415
416 /* Destroy all info on a slot we have built up */
417 void
418 PK11_DestroySlot(PK11SlotInfo *slot)
419 {
420 /* free up the cached keys and sessions */
421 PK11_CleanKeyList(slot);
422
423 /* free up all the sessions on this slot */
424 if (slot->functionList) {
425 PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
426 }
427
428 if (slot->mechanismList) {
429 PORT_Free(slot->mechanismList);
430 }
431 if (slot->isThreadSafe && slot->sessionLock) {
432 PZ_DestroyLock(slot->sessionLock);
433 }
434 slot->sessionLock = NULL;
435 if (slot->freeListLock) {
436 PZ_DestroyLock(slot->freeListLock);
437 slot->freeListLock = NULL;
438 }
439
440 /* finally Tell our parent module that we've gone away so it can unload */
441 if (slot->module) {
442 SECMOD_SlotDestroyModule(slot->module,PR_TRUE);
443 }
444
445 /* ok, well not quit finally... now we free the memory */
446 PORT_Free(slot);
447 }
448
449
450 /* We're all done with the slot, free it */
451 void
452 PK11_FreeSlot(PK11SlotInfo *slot)
453 {
454 if (PR_ATOMIC_DECREMENT(&slot->refCount) == 0) {
455 PK11_DestroySlot(slot);
456 }
457 }
458
459 void
460 PK11_EnterSlotMonitor(PK11SlotInfo *slot) {
461 PZ_Lock(slot->sessionLock);
462 }
463
464 void
465 PK11_ExitSlotMonitor(PK11SlotInfo *slot) {
466 PZ_Unlock(slot->sessionLock);
467 }
468
469 /***********************************************************
470 * Functions to find specific slots.
471 ***********************************************************/
472 PRBool
473 SECMOD_HasRootCerts(void)
474 {
475 SECMODModuleList *mlp;
476 SECMODModuleList *modules;
477 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
478 int i;
479 PRBool found = PR_FALSE;
480
481 if (!moduleLock) {
482 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
483 return found;
484 }
485
486 /* work through all the slots */
487 SECMOD_GetReadLock(moduleLock);
488 modules = SECMOD_GetDefaultModuleList();
489 for(mlp = modules; mlp != NULL; mlp = mlp->next) {
490 for (i=0; i < mlp->module->slotCount; i++) {
491 PK11SlotInfo *tmpSlot = mlp->module->slots[i];
492 if (PK11_IsPresent(tmpSlot)) {
493 if (tmpSlot->hasRootCerts) {
494 found = PR_TRUE;
495 break;
496 }
497 }
498 }
499 if (found) break;
500 }
501 SECMOD_ReleaseReadLock(moduleLock);
502
503 return found;
504 }
505
506 /***********************************************************
507 * Functions to find specific slots.
508 ***********************************************************/
509 PK11SlotList *
510 PK11_FindSlotsByNames(const char *dllName, const char* slotName,
511 const char* tokenName, PRBool presentOnly)
512 {
513 SECMODModuleList *mlp;
514 SECMODModuleList *modules;
515 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
516 int i;
517 PK11SlotList* slotList = NULL;
518 PRUint32 slotcount = 0;
519 SECStatus rv = SECSuccess;
520
521 if (!moduleLock) {
522 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
523 return slotList;
524 }
525
526 slotList = PK11_NewSlotList();
527 if (!slotList) {
528 PORT_SetError(SEC_ERROR_NO_MEMORY);
529 return slotList;
530 }
531
532 if ( ((NULL == dllName) || (0 == *dllName)) &&
533 ((NULL == slotName) || (0 == *slotName)) &&
534 ((NULL == tokenName) || (0 == *tokenName)) ) {
535 /* default to softoken */
536 PK11_AddSlotToList(slotList, PK11_GetInternalKeySlot(), PR_TRUE);
537 return slotList;
538 }
539
540 /* work through all the slots */
541 SECMOD_GetReadLock(moduleLock);
542 modules = SECMOD_GetDefaultModuleList();
543 for (mlp = modules; mlp != NULL; mlp = mlp->next) {
544 PORT_Assert(mlp->module);
545 if (!mlp->module) {
546 rv = SECFailure;
547 break;
548 }
549 if ((!dllName) || (mlp->module->dllName &&
550 (0 == PORT_Strcmp(mlp->module->dllName, dllName)))) {
551 for (i=0; i < mlp->module->slotCount; i++) {
552 PK11SlotInfo *tmpSlot = (mlp->module->slots?mlp->module->slots[i ]:NULL);
553 PORT_Assert(tmpSlot);
554 if (!tmpSlot) {
555 rv = SECFailure;
556 break;
557 }
558 if ((PR_FALSE == presentOnly || PK11_IsPresent(tmpSlot)) &&
559 ( (!tokenName) ||
560 (0==PORT_Strcmp(tmpSlot->token_name, tokenName)) ) &&
561 ( (!slotName) ||
562 (0==PORT_Strcmp(tmpSlot->slot_name, slotName)) ) ) {
563 if (tmpSlot) {
564 PK11_AddSlotToList(slotList, tmpSlot, PR_TRUE);
565 slotcount++;
566 }
567 }
568 }
569 }
570 }
571 SECMOD_ReleaseReadLock(moduleLock);
572
573 if ( (0 == slotcount) || (SECFailure == rv) ) {
574 PORT_SetError(SEC_ERROR_NO_TOKEN);
575 PK11_FreeSlotList(slotList);
576 slotList = NULL;
577 }
578
579 if (SECFailure == rv) {
580 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
581 }
582
583 return slotList;
584 }
585
586 PK11SlotInfo *
587 PK11_FindSlotByName(const char *name)
588 {
589 SECMODModuleList *mlp;
590 SECMODModuleList *modules;
591 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
592 int i;
593 PK11SlotInfo *slot = NULL;
594
595 if (!moduleLock) {
596 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
597 return slot;
598 }
599 if ((name == NULL) || (*name == 0)) {
600 return PK11_GetInternalKeySlot();
601 }
602
603 /* work through all the slots */
604 SECMOD_GetReadLock(moduleLock);
605 modules = SECMOD_GetDefaultModuleList();
606 for(mlp = modules; mlp != NULL; mlp = mlp->next) {
607 for (i=0; i < mlp->module->slotCount; i++) {
608 PK11SlotInfo *tmpSlot = mlp->module->slots[i];
609 if (PK11_IsPresent(tmpSlot)) {
610 if (PORT_Strcmp(tmpSlot->token_name,name) == 0) {
611 slot = PK11_ReferenceSlot(tmpSlot);
612 break;
613 }
614 }
615 }
616 if (slot != NULL) break;
617 }
618 SECMOD_ReleaseReadLock(moduleLock);
619
620 if (slot == NULL) {
621 PORT_SetError(SEC_ERROR_NO_TOKEN);
622 }
623
624 return slot;
625 }
626
627
628 PK11SlotInfo *
629 PK11_FindSlotBySerial(char *serial)
630 {
631 SECMODModuleList *mlp;
632 SECMODModuleList *modules;
633 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
634 int i;
635 PK11SlotInfo *slot = NULL;
636
637 if (!moduleLock) {
638 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
639 return slot;
640 }
641 /* work through all the slots */
642 SECMOD_GetReadLock(moduleLock);
643 modules = SECMOD_GetDefaultModuleList();
644 for(mlp = modules; mlp != NULL; mlp = mlp->next) {
645 for (i=0; i < mlp->module->slotCount; i++) {
646 PK11SlotInfo *tmpSlot = mlp->module->slots[i];
647 if (PK11_IsPresent(tmpSlot)) {
648 if (PORT_Memcmp(tmpSlot->serial,serial,
649 sizeof(tmpSlot->serial)) == 0) {
650 slot = PK11_ReferenceSlot(tmpSlot);
651 break;
652 }
653 }
654 }
655 if (slot != NULL) break;
656 }
657 SECMOD_ReleaseReadLock(moduleLock);
658
659 if (slot == NULL) {
660 PORT_SetError(SEC_ERROR_NO_TOKEN);
661 }
662
663 return slot;
664 }
665
666 /*
667 * notification stub. If we ever get interested in any events that
668 * the pkcs11 functions may pass back to use, we can catch them here...
669 * currently pdata is a slotinfo structure.
670 */
671 CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event,
672 CK_VOID_PTR pdata)
673 {
674 return CKR_OK;
675 }
676
677 /*
678 * grab a new RW session
679 * !!! has a side effect of grabbing the Monitor if either the slot's default
680 * session is RW or the slot is not thread safe. Monitor is release in function
681 * below
682 */
683 CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot)
684 {
685 CK_SESSION_HANDLE rwsession;
686 CK_RV crv;
687 PRBool haveMonitor = PR_FALSE;
688
689 if (!slot->isThreadSafe || slot->defRWSession) {
690 PK11_EnterSlotMonitor(slot);
691 haveMonitor = PR_TRUE;
692 }
693 if (slot->defRWSession) {
694 PORT_Assert(slot->session != CK_INVALID_SESSION);
695 if (slot->session != CK_INVALID_SESSION)
696 return slot->session;
697 }
698
699 crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
700 CKF_RW_SESSION|CKF_SERIAL_SESSION,
701 slot, pk11_notify,&rwsession);
702 PORT_Assert(rwsession != CK_INVALID_SESSION || crv != CKR_OK);
703 if (crv != CKR_OK || rwsession == CK_INVALID_SESSION) {
704 if (crv == CKR_OK)
705 crv = CKR_DEVICE_ERROR;
706 if (haveMonitor)
707 PK11_ExitSlotMonitor(slot);
708 PORT_SetError(PK11_MapError(crv));
709 return CK_INVALID_SESSION;
710 }
711 if (slot->defRWSession) { /* we have the monitor */
712 slot->session = rwsession;
713 }
714 return rwsession;
715 }
716
717 PRBool
718 PK11_RWSessionHasLock(PK11SlotInfo *slot,CK_SESSION_HANDLE session_handle)
719 {
720 PRBool hasLock;
721 hasLock = (PRBool)(!slot->isThreadSafe ||
722 (slot->defRWSession && slot->session != CK_INVALID_SESSION));
723 return hasLock;
724 }
725
726 static PRBool
727 pk11_RWSessionIsDefault(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
728 {
729 PRBool isDefault;
730 isDefault = (PRBool)(slot->session == rwsession &&
731 slot->defRWSession &&
732 slot->session != CK_INVALID_SESSION);
733 return isDefault;
734 }
735
736 /*
737 * close the rwsession and restore our readonly session
738 * !!! has a side effect of releasing the Monitor if either the slot's default
739 * session is RW or the slot is not thread safe.
740 */
741 void
742 PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
743 {
744 PORT_Assert(rwsession != CK_INVALID_SESSION);
745 if (rwsession != CK_INVALID_SESSION) {
746 PRBool doExit = PK11_RWSessionHasLock(slot, rwsession);
747 if (!pk11_RWSessionIsDefault(slot, rwsession))
748 PK11_GETTAB(slot)->C_CloseSession(rwsession);
749 if (doExit)
750 PK11_ExitSlotMonitor(slot);
751 }
752 }
753
754 /************************************************************
755 * Manage the built-In Slot Lists
756 ************************************************************/
757
758 /* Init the static built int slot list (should actually integrate
759 * with PK11_NewSlotList */
760 static void
761 pk11_InitSlotListStatic(PK11SlotList *list)
762 {
763 list->lock = PZ_NewLock(nssILockList);
764 list->head = NULL;
765 }
766
767
768 /* initialize the system slotlists */
769 SECStatus
770 PK11_InitSlotLists(void)
771 {
772 pk11_InitSlotListStatic(&pk11_seedSlotList);
773 pk11_InitSlotListStatic(&pk11_camelliaSlotList);
774 pk11_InitSlotListStatic(&pk11_aesSlotList);
775 pk11_InitSlotListStatic(&pk11_desSlotList);
776 pk11_InitSlotListStatic(&pk11_rc4SlotList);
777 pk11_InitSlotListStatic(&pk11_rc2SlotList);
778 pk11_InitSlotListStatic(&pk11_rc5SlotList);
779 pk11_InitSlotListStatic(&pk11_md5SlotList);
780 pk11_InitSlotListStatic(&pk11_md2SlotList);
781 pk11_InitSlotListStatic(&pk11_sha1SlotList);
782 pk11_InitSlotListStatic(&pk11_rsaSlotList);
783 pk11_InitSlotListStatic(&pk11_dsaSlotList);
784 pk11_InitSlotListStatic(&pk11_dhSlotList);
785 pk11_InitSlotListStatic(&pk11_ecSlotList);
786 pk11_InitSlotListStatic(&pk11_ideaSlotList);
787 pk11_InitSlotListStatic(&pk11_sslSlotList);
788 pk11_InitSlotListStatic(&pk11_tlsSlotList);
789 pk11_InitSlotListStatic(&pk11_randomSlotList);
790 pk11_InitSlotListStatic(&pk11_sha256SlotList);
791 pk11_InitSlotListStatic(&pk11_sha512SlotList);
792 return SECSuccess;
793 }
794
795 void
796 PK11_DestroySlotLists(void)
797 {
798 pk11_FreeSlotListStatic(&pk11_seedSlotList);
799 pk11_FreeSlotListStatic(&pk11_camelliaSlotList);
800 pk11_FreeSlotListStatic(&pk11_aesSlotList);
801 pk11_FreeSlotListStatic(&pk11_desSlotList);
802 pk11_FreeSlotListStatic(&pk11_rc4SlotList);
803 pk11_FreeSlotListStatic(&pk11_rc2SlotList);
804 pk11_FreeSlotListStatic(&pk11_rc5SlotList);
805 pk11_FreeSlotListStatic(&pk11_md5SlotList);
806 pk11_FreeSlotListStatic(&pk11_md2SlotList);
807 pk11_FreeSlotListStatic(&pk11_sha1SlotList);
808 pk11_FreeSlotListStatic(&pk11_rsaSlotList);
809 pk11_FreeSlotListStatic(&pk11_dsaSlotList);
810 pk11_FreeSlotListStatic(&pk11_dhSlotList);
811 pk11_FreeSlotListStatic(&pk11_ecSlotList);
812 pk11_FreeSlotListStatic(&pk11_ideaSlotList);
813 pk11_FreeSlotListStatic(&pk11_sslSlotList);
814 pk11_FreeSlotListStatic(&pk11_tlsSlotList);
815 pk11_FreeSlotListStatic(&pk11_randomSlotList);
816 pk11_FreeSlotListStatic(&pk11_sha256SlotList);
817 pk11_FreeSlotListStatic(&pk11_sha512SlotList);
818 return;
819 }
820
821 /* return a system slot list based on mechanism */
822 PK11SlotList *
823 PK11_GetSlotList(CK_MECHANISM_TYPE type)
824 {
825 /* XXX a workaround for Bugzilla bug #55267 */
826 #if defined(HPUX) && defined(__LP64__)
827 if (CKM_INVALID_MECHANISM == type)
828 return NULL;
829 #endif
830 switch (type) {
831 case CKM_SEED_CBC:
832 case CKM_SEED_ECB:
833 return &pk11_seedSlotList;
834 case CKM_CAMELLIA_CBC:
835 case CKM_CAMELLIA_ECB:
836 return &pk11_camelliaSlotList;
837 case CKM_AES_CBC:
838 case CKM_AES_CCM:
839 case CKM_AES_CTR:
840 case CKM_AES_CTS:
841 case CKM_AES_GCM:
842 case CKM_AES_ECB:
843 return &pk11_aesSlotList;
844 case CKM_DES_CBC:
845 case CKM_DES_ECB:
846 case CKM_DES3_ECB:
847 case CKM_DES3_CBC:
848 return &pk11_desSlotList;
849 case CKM_RC4:
850 return &pk11_rc4SlotList;
851 case CKM_RC5_CBC:
852 return &pk11_rc5SlotList;
853 case CKM_SHA_1:
854 return &pk11_sha1SlotList;
855 case CKM_SHA224:
856 case CKM_SHA256:
857 return &pk11_sha256SlotList;
858 case CKM_SHA384:
859 case CKM_SHA512:
860 return &pk11_sha512SlotList;
861 case CKM_MD5:
862 return &pk11_md5SlotList;
863 case CKM_MD2:
864 return &pk11_md2SlotList;
865 case CKM_RC2_ECB:
866 case CKM_RC2_CBC:
867 return &pk11_rc2SlotList;
868 case CKM_RSA_PKCS:
869 case CKM_RSA_PKCS_KEY_PAIR_GEN:
870 case CKM_RSA_X_509:
871 return &pk11_rsaSlotList;
872 case CKM_DSA:
873 return &pk11_dsaSlotList;
874 case CKM_DH_PKCS_KEY_PAIR_GEN:
875 case CKM_DH_PKCS_DERIVE:
876 return &pk11_dhSlotList;
877 case CKM_ECDSA:
878 case CKM_ECDSA_SHA1:
879 case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
880 case CKM_ECDH1_DERIVE:
881 return &pk11_ecSlotList;
882 case CKM_SSL3_PRE_MASTER_KEY_GEN:
883 case CKM_SSL3_MASTER_KEY_DERIVE:
884 case CKM_SSL3_SHA1_MAC:
885 case CKM_SSL3_MD5_MAC:
886 return &pk11_sslSlotList;
887 case CKM_TLS_MASTER_KEY_DERIVE:
888 case CKM_TLS_KEY_AND_MAC_DERIVE:
889 case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
890 return &pk11_tlsSlotList;
891 case CKM_IDEA_CBC:
892 case CKM_IDEA_ECB:
893 return &pk11_ideaSlotList;
894 case CKM_FAKE_RANDOM:
895 return &pk11_randomSlotList;
896 }
897 return NULL;
898 }
899
900 /*
901 * load the static SlotInfo structures used to select a PKCS11 slot.
902 * preSlotInfo has a list of all the default flags for the slots on this
903 * module.
904 */
905 void
906 PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
907 {
908 int i;
909
910 for (i=0; i < count; i++) {
911 if (psi[i].slotID == slot->slotID)
912 break;
913 }
914
915 if (i == count) return;
916
917 slot->defaultFlags = psi[i].defaultFlags;
918 slot->askpw = psi[i].askpw;
919 slot->timeout = psi[i].timeout;
920 slot->hasRootCerts = psi[i].hasRootCerts;
921
922 /* if the slot is already disabled, don't load them into the
923 * default slot lists. We get here so we can save the default
924 * list value. */
925 if (slot->disabled) return;
926
927 /* if the user has disabled us, don't load us in */
928 if (slot->defaultFlags & PK11_DISABLE_FLAG) {
929 slot->disabled = PR_TRUE;
930 slot->reason = PK11_DIS_USER_SELECTED;
931 /* free up sessions and things?? */
932 return;
933 }
934
935 for (i=0; i < num_pk11_default_mechanisms; i++) {
936 if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
937 CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
938 PK11SlotList *slotList = PK11_GetSlotList(mechanism);
939
940 if (slotList) PK11_AddSlotToList(slotList,slot,PR_FALSE);
941 }
942 }
943
944 return;
945 }
946
947
948 /*
949 * update a slot to its new attribute according to the slot list
950 * returns: SECSuccess if nothing to do or add/delete is successful
951 */
952 SECStatus
953 PK11_UpdateSlotAttribute(PK11SlotInfo *slot,
954 const PK11DefaultArrayEntry *entry,
955 PRBool add)
956 /* add: PR_TRUE if want to turn on */
957 {
958 SECStatus result = SECSuccess;
959 PK11SlotList *slotList = PK11_GetSlotList(entry->mechanism);
960
961 if (add) { /* trying to turn on a mechanism */
962
963 /* turn on the default flag in the slot */
964 slot->defaultFlags |= entry->flag;
965
966 /* add this slot to the list */
967 if (slotList!=NULL)
968 result = PK11_AddSlotToList(slotList, slot, PR_FALSE);
969
970 } else { /* trying to turn off */
971
972 /* turn OFF the flag in the slot */
973 slot->defaultFlags &= ~entry->flag;
974
975 if (slotList) {
976 /* find the element in the list & delete it */
977 PK11SlotListElement *le = PK11_FindSlotElement(slotList, slot);
978
979 /* remove the slot from the list */
980 if (le)
981 result = PK11_DeleteSlotFromList(slotList, le);
982 }
983 }
984 return result;
985 }
986
987 /*
988 * clear a slot off of all of it's default list
989 */
990 void
991 PK11_ClearSlotList(PK11SlotInfo *slot)
992 {
993 int i;
994
995 if (slot->disabled) return;
996 if (slot->defaultFlags == 0) return;
997
998 for (i=0; i < num_pk11_default_mechanisms; i++) {
999 if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
1000 CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
1001 PK11SlotList *slotList = PK11_GetSlotList(mechanism);
1002 PK11SlotListElement *le = NULL;
1003
1004 if (slotList) le = PK11_FindSlotElement(slotList,slot);
1005
1006 if (le) {
1007 PK11_DeleteSlotFromList(slotList,le);
1008 PK11_FreeSlotListElement(slotList,le);
1009 }
1010 }
1011 }
1012 }
1013
1014
1015 /******************************************************************
1016 * Slot initialization
1017 ******************************************************************/
1018 /*
1019 * turn a PKCS11 Static Label into a string
1020 */
1021 char *
1022 PK11_MakeString(PLArenaPool *arena,char *space,
1023 char *staticString,int stringLen)
1024 {
1025 int i;
1026 char *newString;
1027 for(i=(stringLen-1); i >= 0; i--) {
1028 if (staticString[i] != ' ') break;
1029 }
1030 /* move i to point to the last space */
1031 i++;
1032 if (arena) {
1033 newString = (char*)PORT_ArenaAlloc(arena,i+1 /* space for NULL */);
1034 } else if (space) {
1035 newString = space;
1036 } else {
1037 newString = (char*)PORT_Alloc(i+1 /* space for NULL */);
1038 }
1039 if (newString == NULL) return NULL;
1040
1041 if (i) PORT_Memcpy(newString,staticString, i);
1042 newString[i] = 0;
1043
1044 return newString;
1045 }
1046
1047 /*
1048 * Reads in the slots mechanism list for later use
1049 */
1050 SECStatus
1051 PK11_ReadMechanismList(PK11SlotInfo *slot)
1052 {
1053 CK_ULONG count;
1054 CK_RV crv;
1055 PRUint32 i;
1056
1057 if (slot->mechanismList) {
1058 PORT_Free(slot->mechanismList);
1059 slot->mechanismList = NULL;
1060 }
1061 slot->mechanismCount = 0;
1062
1063 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1064 crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,NULL,&count);
1065 if (crv != CKR_OK) {
1066 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1067 PORT_SetError(PK11_MapError(crv));
1068 return SECFailure;
1069 }
1070
1071 slot->mechanismList = (CK_MECHANISM_TYPE *)
1072 PORT_Alloc(count *sizeof(CK_MECHANISM_TYPE));
1073 if (slot->mechanismList == NULL) {
1074 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1075 return SECFailure;
1076 }
1077 crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,
1078 slot->mechanismList, &count);
1079 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1080 if (crv != CKR_OK) {
1081 PORT_Free(slot->mechanismList);
1082 slot->mechanismList = NULL;
1083 PORT_SetError(PK11_MapError(crv));
1084 return SECSuccess;
1085 }
1086 slot->mechanismCount = count;
1087 PORT_Memset(slot->mechanismBits, 0, sizeof(slot->mechanismBits));
1088
1089 for (i=0; i < count; i++) {
1090 CK_MECHANISM_TYPE mech = slot->mechanismList[i];
1091 if (mech < 0x7ff) {
1092 slot->mechanismBits[mech & 0xff] |= 1 << (mech >> 8);
1093 }
1094 }
1095 return SECSuccess;
1096 }
1097
1098 /*
1099 * initialize a new token
1100 * unlike initialize slot, this can be called multiple times in the lifetime
1101 * of NSS. It reads the information associated with a card or token,
1102 * that is not going to change unless the card or token changes.
1103 */
1104 SECStatus
1105 PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts)
1106 {
1107 CK_TOKEN_INFO tokenInfo;
1108 CK_RV crv;
1109 SECStatus rv;
1110 PRStatus status;
1111
1112 /* set the slot flags to the current token values */
1113 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1114 crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
1115 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1116 if (crv != CKR_OK) {
1117 PORT_SetError(PK11_MapError(crv));
1118 return SECFailure;
1119 }
1120
1121 /* set the slot flags to the current token values */
1122 slot->series++; /* allow other objects to detect that the
1123 * slot is different */
1124 slot->flags = tokenInfo.flags;
1125 slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ?
1126 PR_TRUE : PR_FALSE);
1127 slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ?
1128 PR_TRUE : PR_FALSE);
1129
1130
1131 slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
1132 slot->protectedAuthPath =
1133 ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
1134 ? PR_TRUE : PR_FALSE);
1135 slot->lastLoginCheck = 0;
1136 slot->lastState = 0;
1137 /* on some platforms Active Card incorrectly sets the
1138 * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
1139 if (slot->isActiveCard) {
1140 slot->protectedAuthPath = PR_FALSE;
1141 }
1142 (void)PK11_MakeString(NULL,slot->token_name,
1143 (char *)tokenInfo.label, sizeof(tokenInfo.label));
1144 slot->minPassword = tokenInfo.ulMinPinLen;
1145 slot->maxPassword = tokenInfo.ulMaxPinLen;
1146 PORT_Memcpy(slot->serial,tokenInfo.serialNumber,sizeof(slot->serial));
1147
1148 nssToken_UpdateName(slot->nssToken);
1149
1150 slot->defRWSession = (PRBool)((!slot->readOnly) &&
1151 (tokenInfo.ulMaxSessionCount == 1));
1152 rv = PK11_ReadMechanismList(slot);
1153 if (rv != SECSuccess) return rv;
1154
1155 slot->hasRSAInfo = PR_FALSE;
1156 slot->RSAInfoFlags = 0;
1157
1158 /* initialize the maxKeyCount value */
1159 if (tokenInfo.ulMaxSessionCount == 0) {
1160 slot->maxKeyCount = 800; /* should be #define or a config param */
1161 } else if (tokenInfo.ulMaxSessionCount < 20) {
1162 /* don't have enough sessions to keep that many keys around */
1163 slot->maxKeyCount = 0;
1164 } else {
1165 slot->maxKeyCount = tokenInfo.ulMaxSessionCount/2;
1166 }
1167
1168 /* Make sure our session handle is valid */
1169 if (slot->session == CK_INVALID_SESSION) {
1170 /* we know we don't have a valid session, go get one */
1171 CK_SESSION_HANDLE session;
1172
1173 /* session should be Readonly, serial */
1174 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1175 crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
1176 (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
1177 slot,pk11_notify,&session);
1178 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1179 if (crv != CKR_OK) {
1180 PORT_SetError(PK11_MapError(crv));
1181 return SECFailure;
1182 }
1183 slot->session = session;
1184 } else {
1185 /* The session we have may be defunct (the token associated with it)
1186 * has been removed */
1187 CK_SESSION_INFO sessionInfo;
1188
1189 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1190 crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo);
1191 if (crv == CKR_DEVICE_ERROR) {
1192 PK11_GETTAB(slot)->C_CloseSession(slot->session);
1193 crv = CKR_SESSION_CLOSED;
1194 }
1195 if ((crv==CKR_SESSION_CLOSED) || (crv==CKR_SESSION_HANDLE_INVALID)) {
1196 crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
1197 (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
1198 slot,pk11_notify,&slot->session);
1199 if (crv != CKR_OK) {
1200 PORT_SetError(PK11_MapError(crv));
1201 slot->session = CK_INVALID_SESSION;
1202 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1203 return SECFailure;
1204 }
1205 }
1206 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1207 }
1208
1209 status = nssToken_Refresh(slot->nssToken);
1210 if (status != PR_SUCCESS)
1211 return SECFailure;
1212
1213 if (!(slot->isInternal) && (slot->hasRandom)) {
1214 /* if this slot has a random number generater, use it to add entropy
1215 * to the internal slot. */
1216 PK11SlotInfo *int_slot = PK11_GetInternalSlot();
1217
1218 if (int_slot) {
1219 unsigned char random_bytes[32];
1220
1221 /* if this slot can issue random numbers, get some entropy from
1222 * that random number generater and give it to our internal token.
1223 */
1224 PK11_EnterSlotMonitor(slot);
1225 crv = PK11_GETTAB(slot)->C_GenerateRandom
1226 (slot->session,random_bytes, sizeof(random_bytes));
1227 PK11_ExitSlotMonitor(slot);
1228 if (crv == CKR_OK) {
1229 PK11_EnterSlotMonitor(int_slot);
1230 PK11_GETTAB(int_slot)->C_SeedRandom(int_slot->session,
1231 random_bytes, sizeof(random_bytes));
1232 PK11_ExitSlotMonitor(int_slot);
1233 }
1234
1235 /* Now return the favor and send entropy to the token's random
1236 * number generater */
1237 PK11_EnterSlotMonitor(int_slot);
1238 crv = PK11_GETTAB(int_slot)->C_GenerateRandom(int_slot->session,
1239 random_bytes, sizeof(random_bytes));
1240 PK11_ExitSlotMonitor(int_slot);
1241 if (crv == CKR_OK) {
1242 PK11_EnterSlotMonitor(slot);
1243 crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session,
1244 random_bytes, sizeof(random_bytes));
1245 PK11_ExitSlotMonitor(slot);
1246 }
1247 PK11_FreeSlot(int_slot);
1248 }
1249 }
1250 /* work around a problem in softoken where it incorrectly
1251 * reports databases opened read only as read/write. */
1252 if (slot->isInternal && !slot->readOnly) {
1253 CK_SESSION_HANDLE session = CK_INVALID_SESSION;
1254
1255 /* try to open a R/W session */
1256 crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
1257 CKF_RW_SESSION|CKF_SERIAL_SESSION, slot, pk11_notify ,&session);
1258 /* what a well behaved token should return if you open
1259 * a RW session on a read only token */
1260 if (crv == CKR_TOKEN_WRITE_PROTECTED) {
1261 slot->readOnly = PR_TRUE;
1262 } else if (crv == CKR_OK) {
1263 CK_SESSION_INFO sessionInfo;
1264
1265 /* Because of a second bug in softoken, which silently returns
1266 * a RO session, we need to check what type of session we got. */
1267 crv = PK11_GETTAB(slot)->C_GetSessionInfo(session, &sessionInfo);
1268 if (crv == CKR_OK) {
1269 if ((sessionInfo.flags & CKF_RW_SESSION) == 0) {
1270 /* session was readonly, so this softoken slot must be * readonly */
1271 slot->readOnly = PR_TRUE;
1272 }
1273 }
1274 PK11_GETTAB(slot)->C_CloseSession(session);
1275 }
1276 }
1277
1278 return SECSuccess;
1279 }
1280
1281 /*
1282 * initialize a new token
1283 * unlike initialize slot, this can be called multiple times in the lifetime
1284 * of NSS. It reads the information associated with a card or token,
1285 * that is not going to change unless the card or token changes.
1286 */
1287 SECStatus
1288 PK11_TokenRefresh(PK11SlotInfo *slot)
1289 {
1290 CK_TOKEN_INFO tokenInfo;
1291 CK_RV crv;
1292
1293 /* set the slot flags to the current token values */
1294 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1295 crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
1296 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1297 if (crv != CKR_OK) {
1298 PORT_SetError(PK11_MapError(crv));
1299 return SECFailure;
1300 }
1301
1302 slot->flags = tokenInfo.flags;
1303 slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ?
1304 PR_TRUE : PR_FALSE);
1305 slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ?
1306 PR_TRUE : PR_FALSE);
1307 slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
1308 slot->protectedAuthPath =
1309 ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
1310 ? PR_TRUE : PR_FALSE);
1311 /* on some platforms Active Card incorrectly sets the
1312 * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
1313 if (slot->isActiveCard) {
1314 slot->protectedAuthPath = PR_FALSE;
1315 }
1316 return SECSuccess;
1317 }
1318
1319 static PRBool
1320 pk11_isRootSlot(PK11SlotInfo *slot)
1321 {
1322 CK_ATTRIBUTE findTemp[1];
1323 CK_ATTRIBUTE *attrs;
1324 CK_OBJECT_CLASS oclass = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
1325 int tsize;
1326 CK_OBJECT_HANDLE handle;
1327
1328 attrs = findTemp;
1329 PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass)); attrs++;
1330 tsize = attrs - findTemp;
1331 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
1332
1333 handle = pk11_FindObjectByTemplate(slot,findTemp,tsize);
1334 if (handle == CK_INVALID_HANDLE) {
1335 return PR_FALSE;
1336 }
1337 return PR_TRUE;
1338 }
1339
1340 /*
1341 * Initialize the slot :
1342 * This initialization code is called on each slot a module supports when
1343 * it is loaded. It does the bringup initialization. The difference between
1344 * this and InitToken is Init slot does those one time initialization stuff,
1345 * usually associated with the reader, while InitToken may get called multiple
1346 * times as tokens are removed and re-inserted.
1347 */
1348 void
1349 PK11_InitSlot(SECMODModule *mod, CK_SLOT_ID slotID, PK11SlotInfo *slot)
1350 {
1351 SECStatus rv;
1352 CK_SLOT_INFO slotInfo;
1353
1354 slot->functionList = mod->functionList;
1355 slot->isInternal = mod->internal;
1356 slot->slotID = slotID;
1357 slot->isThreadSafe = mod->isThreadSafe;
1358 slot->hasRSAInfo = PR_FALSE;
1359
1360 if (PK11_GETTAB(slot)->C_GetSlotInfo(slotID,&slotInfo) != CKR_OK) {
1361 slot->disabled = PR_TRUE;
1362 slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1363 return;
1364 }
1365
1366 /* test to make sure claimed mechanism work */
1367 slot->needTest = mod->internal ? PR_FALSE : PR_TRUE;
1368 slot->module = mod; /* NOTE: we don't make a reference here because
1369 * modules have references to their slots. This
1370 * works because modules keep implicit references
1371 * from their slots, and won't unload and disappear
1372 * until all their slots have been freed */
1373 (void)PK11_MakeString(NULL,slot->slot_name,
1374 (char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
1375 slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT);
1376 #define ACTIVE_CARD "ActivCard SA"
1377 slot->isActiveCard = (PRBool)(PORT_Strncmp((char *)slotInfo.manufacturerID,
1378 ACTIVE_CARD, sizeof(ACTIVE_CARD)-1) == 0);
1379 if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == 0) {
1380 slot->isPerm = PR_TRUE;
1381 /* permanment slots must have the token present always */
1382 if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
1383 slot->disabled = PR_TRUE;
1384 slot->reason = PK11_DIS_TOKEN_NOT_PRESENT;
1385 return; /* nothing else to do */
1386 }
1387 }
1388 /* if the token is present, initialize it */
1389 if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
1390 rv = PK11_InitToken(slot,PR_TRUE);
1391 /* the only hard failures are on permanent devices, or function
1392 * verify failures... function verify failures are already handled
1393 * by tokenInit */
1394 if ((rv != SECSuccess) && (slot->isPerm) && (!slot->disabled)) {
1395 slot->disabled = PR_TRUE;
1396 slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1397 }
1398 if (rv == SECSuccess && pk11_isRootSlot(slot)) {
1399 if (!slot->hasRootCerts) {
1400 slot->module->trustOrder = 100;
1401 }
1402 slot->hasRootCerts= PR_TRUE;
1403 }
1404 }
1405 }
1406
1407
1408
1409 /*********************************************************************
1410 * Slot mapping utility functions.
1411 *********************************************************************/
1412
1413 /*
1414 * determine if the token is present. If the token is present, make sure
1415 * we have a valid session handle. Also set the value of needLogin
1416 * appropriately.
1417 */
1418 static PRBool
1419 pk11_IsPresentCertLoad(PK11SlotInfo *slot, PRBool loadCerts)
1420 {
1421 CK_SLOT_INFO slotInfo;
1422 CK_SESSION_INFO sessionInfo;
1423 CK_RV crv;
1424
1425 /* disabled slots are never present */
1426 if (slot->disabled) {
1427 return PR_FALSE;
1428 }
1429
1430 /* permanent slots are always present */
1431 if (slot->isPerm && (slot->session != CK_INVALID_SESSION)) {
1432 return PR_TRUE;
1433 }
1434
1435 if (slot->nssToken) {
1436 return nssToken_IsPresent(slot->nssToken);
1437 }
1438
1439 /* removable slots have a flag that says they are present */
1440 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1441 if (PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,&slotInfo) != CKR_OK) {
1442 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1443 return PR_FALSE;
1444 }
1445 if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
1446 /* if the slot is no longer present, close the session */
1447 if (slot->session != CK_INVALID_SESSION) {
1448 PK11_GETTAB(slot)->C_CloseSession(slot->session);
1449 slot->session = CK_INVALID_SESSION;
1450 }
1451 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1452 return PR_FALSE;
1453 }
1454
1455 /* use the session Info to determine if the card has been removed and then
1456 * re-inserted */
1457 if (slot->session != CK_INVALID_SESSION) {
1458 if (slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1459 crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
1460 if (crv != CKR_OK) {
1461 PK11_GETTAB(slot)->C_CloseSession(slot->session);
1462 slot->session = CK_INVALID_SESSION;
1463 }
1464 if (slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1465 }
1466 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1467
1468 /* card has not been removed, current token info is correct */
1469 if (slot->session != CK_INVALID_SESSION) return PR_TRUE;
1470
1471 /* initialize the token info state */
1472 if (PK11_InitToken(slot,loadCerts) != SECSuccess) {
1473 return PR_FALSE;
1474 }
1475
1476 return PR_TRUE;
1477 }
1478
1479 /*
1480 * old version of the routine
1481 */
1482 PRBool
1483 PK11_IsPresent(PK11SlotInfo *slot) {
1484 return pk11_IsPresentCertLoad(slot,PR_TRUE);
1485 }
1486
1487 /* is the slot disabled? */
1488 PRBool
1489 PK11_IsDisabled(PK11SlotInfo *slot)
1490 {
1491 return slot->disabled;
1492 }
1493
1494 /* and why? */
1495 PK11DisableReasons
1496 PK11_GetDisabledReason(PK11SlotInfo *slot)
1497 {
1498 return slot->reason;
1499 }
1500
1501 /* returns PR_TRUE if successfully disable the slot */
1502 /* returns PR_FALSE otherwise */
1503 PRBool PK11_UserDisableSlot(PK11SlotInfo *slot) {
1504
1505 /* Prevent users from disabling the internal module. */
1506 if (slot->isInternal) {
1507 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1508 return PR_FALSE;
1509 }
1510
1511 slot->defaultFlags |= PK11_DISABLE_FLAG;
1512 slot->disabled = PR_TRUE;
1513 slot->reason = PK11_DIS_USER_SELECTED;
1514
1515 return PR_TRUE;
1516 }
1517
1518 PRBool PK11_UserEnableSlot(PK11SlotInfo *slot) {
1519
1520 slot->defaultFlags &= ~PK11_DISABLE_FLAG;
1521 slot->disabled = PR_FALSE;
1522 slot->reason = PK11_DIS_NONE;
1523 return PR_TRUE;
1524 }
1525
1526 PRBool PK11_HasRootCerts(PK11SlotInfo *slot) {
1527 return slot->hasRootCerts;
1528 }
1529
1530 /* Get the module this slot is attached to */
1531 SECMODModule *
1532 PK11_GetModule(PK11SlotInfo *slot)
1533 {
1534 return slot->module;
1535 }
1536
1537 /* return the default flags of a slot */
1538 unsigned long
1539 PK11_GetDefaultFlags(PK11SlotInfo *slot)
1540 {
1541 return slot->defaultFlags;
1542 }
1543
1544 /*
1545 * The following wrapper functions allow us to export an opaque slot
1546 * function to the rest of libsec and the world... */
1547 PRBool
1548 PK11_IsReadOnly(PK11SlotInfo *slot)
1549 {
1550 return slot->readOnly;
1551 }
1552
1553 PRBool
1554 PK11_IsHW(PK11SlotInfo *slot)
1555 {
1556 return slot->isHW;
1557 }
1558
1559 PRBool
1560 PK11_IsRemovable(PK11SlotInfo *slot)
1561 {
1562 return !slot->isPerm;
1563 }
1564
1565 PRBool
1566 PK11_IsInternal(PK11SlotInfo *slot)
1567 {
1568 return slot->isInternal;
1569 }
1570
1571 PRBool
1572 PK11_IsInternalKeySlot(PK11SlotInfo *slot)
1573 {
1574 PK11SlotInfo *int_slot;
1575 PRBool result;
1576
1577 if (!slot->isInternal) {
1578 return PR_FALSE;
1579 }
1580
1581 int_slot = PK11_GetInternalKeySlot();
1582 result = (int_slot == slot) ? PR_TRUE : PR_FALSE;
1583 PK11_FreeSlot(int_slot);
1584 return result;
1585 }
1586
1587 PRBool
1588 PK11_NeedLogin(PK11SlotInfo *slot)
1589 {
1590 return slot->needLogin;
1591 }
1592
1593 PRBool
1594 PK11_IsFriendly(PK11SlotInfo *slot)
1595 {
1596 /* internal slot always has public readable certs */
1597 return (PRBool)(slot->isInternal ||
1598 ((slot->defaultFlags & SECMOD_FRIENDLY_FLAG) ==
1599 SECMOD_FRIENDLY_FLAG));
1600 }
1601
1602 char *
1603 PK11_GetTokenName(PK11SlotInfo *slot)
1604 {
1605 return slot->token_name;
1606 }
1607
1608 char *
1609 PK11_GetSlotName(PK11SlotInfo *slot)
1610 {
1611 return slot->slot_name;
1612 }
1613
1614 int
1615 PK11_GetSlotSeries(PK11SlotInfo *slot)
1616 {
1617 return slot->series;
1618 }
1619
1620 int
1621 PK11_GetCurrentWrapIndex(PK11SlotInfo *slot)
1622 {
1623 return slot->wrapKey;
1624 }
1625
1626 CK_SLOT_ID
1627 PK11_GetSlotID(PK11SlotInfo *slot)
1628 {
1629 return slot->slotID;
1630 }
1631
1632 SECMODModuleID
1633 PK11_GetModuleID(PK11SlotInfo *slot)
1634 {
1635 return slot->module->moduleID;
1636 }
1637
1638 static void
1639 pk11_zeroTerminatedToBlankPadded(CK_CHAR *buffer, size_t buffer_size)
1640 {
1641 CK_CHAR *walk = buffer;
1642 CK_CHAR *end = buffer + buffer_size;
1643
1644 /* find the NULL */
1645 while (walk < end && *walk != '\0') {
1646 walk++;
1647 }
1648
1649 /* clear out the buffer */
1650 while (walk < end) {
1651 *walk++ = ' ';
1652 }
1653 }
1654
1655 /* return the slot info structure */
1656 SECStatus
1657 PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info)
1658 {
1659 CK_RV crv;
1660
1661 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1662 /*
1663 * some buggy drivers do not fill the buffer completely,
1664 * erase the buffer first
1665 */
1666 PORT_Memset(info->slotDescription,' ',sizeof(info->slotDescription));
1667 PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
1668 crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,info);
1669 pk11_zeroTerminatedToBlankPadded(info->slotDescription,
1670 sizeof(info->slotDescription));
1671 pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
1672 sizeof(info->manufacturerID));
1673 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1674 if (crv != CKR_OK) {
1675 PORT_SetError(PK11_MapError(crv));
1676 return SECFailure;
1677 }
1678 return SECSuccess;
1679 }
1680
1681 /* return the token info structure */
1682 SECStatus
1683 PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info)
1684 {
1685 CK_RV crv;
1686 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
1687 /*
1688 * some buggy drivers do not fill the buffer completely,
1689 * erase the buffer first
1690 */
1691 PORT_Memset(info->label,' ',sizeof(info->label));
1692 PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
1693 PORT_Memset(info->model,' ',sizeof(info->model));
1694 PORT_Memset(info->serialNumber,' ',sizeof(info->serialNumber));
1695 crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,info);
1696 pk11_zeroTerminatedToBlankPadded(info->label,sizeof(info->label));
1697 pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
1698 sizeof(info->manufacturerID));
1699 pk11_zeroTerminatedToBlankPadded(info->model,sizeof(info->model));
1700 pk11_zeroTerminatedToBlankPadded(info->serialNumber,
1701 sizeof(info->serialNumber));
1702 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
1703 if (crv != CKR_OK) {
1704 PORT_SetError(PK11_MapError(crv));
1705 return SECFailure;
1706 }
1707 return SECSuccess;
1708 }
1709
1710 /* Find out if we need to initialize the user's pin */
1711 PRBool
1712 PK11_NeedUserInit(PK11SlotInfo *slot)
1713 {
1714 PRBool needUserInit = (PRBool) ((slot->flags & CKF_USER_PIN_INITIALIZED)
1715 == 0);
1716
1717 if (needUserInit) {
1718 CK_TOKEN_INFO info;
1719 SECStatus rv;
1720
1721 /* see if token has been initialized off line */
1722 rv = PK11_GetTokenInfo(slot, &info);
1723 if (rv == SECSuccess) {
1724 slot->flags = info.flags;
1725 }
1726 }
1727 return (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
1728 }
1729
1730 static PK11SlotInfo *pk11InternalKeySlot = NULL;
1731
1732 /*
1733 * Set a new default internal keyslot. If one has already been set, clear it.
1734 * Passing NULL falls back to the NSS normally selected default internal key
1735 * slot.
1736 */
1737 void
1738 pk11_SetInternalKeySlot(PK11SlotInfo *slot)
1739 {
1740 if (pk11InternalKeySlot) {
1741 PK11_FreeSlot(pk11InternalKeySlot);
1742 }
1743 pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
1744 }
1745
1746 /*
1747 * Set a new default internal keyslot if the normal key slot has not already
1748 * been overridden. Subsequent calls to this function will be ignored unless
1749 * pk11_SetInternalKeySlot is used to clear the current default.
1750 */
1751 void
1752 pk11_SetInternalKeySlotIfFirst(PK11SlotInfo *slot)
1753 {
1754 if (pk11InternalKeySlot) {
1755 return;
1756 }
1757 pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
1758 }
1759
1760 /*
1761 * Swap out a default internal keyslot. Caller owns the Slot Reference
1762 */
1763 PK11SlotInfo *
1764 pk11_SwapInternalKeySlot(PK11SlotInfo *slot)
1765 {
1766 PK11SlotInfo *swap = pk11InternalKeySlot;
1767
1768 pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
1769 return swap;
1770 }
1771
1772
1773 /* get the internal key slot. FIPS has only one slot for both key slots and
1774 * default slots */
1775 PK11SlotInfo *
1776 PK11_GetInternalKeySlot(void)
1777 {
1778 SECMODModule *mod;
1779
1780 if (pk11InternalKeySlot) {
1781 return PK11_ReferenceSlot(pk11InternalKeySlot);
1782 }
1783
1784 mod = SECMOD_GetInternalModule();
1785 PORT_Assert(mod != NULL);
1786 if (!mod) {
1787 PORT_SetError( SEC_ERROR_NO_MODULE );
1788 return NULL;
1789 }
1790 return PK11_ReferenceSlot(mod->isFIPS ? mod->slots[0] : mod->slots[1]);
1791 }
1792
1793 /* get the internal default slot */
1794 PK11SlotInfo *
1795 PK11_GetInternalSlot(void)
1796 {
1797 SECMODModule * mod = SECMOD_GetInternalModule();
1798 PORT_Assert(mod != NULL);
1799 if (!mod) {
1800 PORT_SetError( SEC_ERROR_NO_MODULE );
1801 return NULL;
1802 }
1803 if (mod->isFIPS) {
1804 return PK11_GetInternalKeySlot();
1805 }
1806 return PK11_ReferenceSlot(mod->slots[0]);
1807 }
1808
1809 /*
1810 * check if a given slot supports the requested mechanism
1811 */
1812 PRBool
1813 PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type)
1814 {
1815 int i;
1816
1817 /* CKM_FAKE_RANDOM is not a real PKCS mechanism. It's a marker to
1818 * tell us we're looking form someone that has implemented get
1819 * random bits */
1820 if (type == CKM_FAKE_RANDOM) {
1821 return slot->hasRandom;
1822 }
1823
1824 /* for most mechanism, bypass the linear lookup */
1825 if (type < 0x7ff) {
1826 return (slot->mechanismBits[type & 0xff] & (1 << (type >> 8))) ?
1827 PR_TRUE : PR_FALSE;
1828 }
1829
1830 for (i=0; i < (int) slot->mechanismCount; i++) {
1831 if (slot->mechanismList[i] == type) return PR_TRUE;
1832 }
1833 return PR_FALSE;
1834 }
1835
1836 /*
1837 * Return true if a token that can do the desired mechanism exists.
1838 * This allows us to have hardware tokens that can do function XYZ magically
1839 * allow SSL Ciphers to appear if they are plugged in.
1840 */
1841 PRBool
1842 PK11_TokenExists(CK_MECHANISM_TYPE type)
1843 {
1844 SECMODModuleList *mlp;
1845 SECMODModuleList *modules;
1846 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
1847 PK11SlotInfo *slot;
1848 PRBool found = PR_FALSE;
1849 int i;
1850
1851 if (!moduleLock) {
1852 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1853 return found;
1854 }
1855 /* we only need to know if there is a token that does this mechanism.
1856 * check the internal module first because it's fast, and supports
1857 * almost everything. */
1858 slot = PK11_GetInternalSlot();
1859 if (slot) {
1860 found = PK11_DoesMechanism(slot,type);
1861 PK11_FreeSlot(slot);
1862 }
1863 if (found) return PR_TRUE; /* bypass getting module locks */
1864
1865 SECMOD_GetReadLock(moduleLock);
1866 modules = SECMOD_GetDefaultModuleList();
1867 for(mlp = modules; mlp != NULL && (!found); mlp = mlp->next) {
1868 for (i=0; i < mlp->module->slotCount; i++) {
1869 slot = mlp->module->slots[i];
1870 if (PK11_IsPresent(slot)) {
1871 if (PK11_DoesMechanism(slot,type)) {
1872 found = PR_TRUE;
1873 break;
1874 }
1875 }
1876 }
1877 }
1878 SECMOD_ReleaseReadLock(moduleLock);
1879 return found;
1880 }
1881
1882 /*
1883 * get all the currently available tokens in a list.
1884 * that can perform the given mechanism. If mechanism is CKM_INVALID_MECHANISM,
1885 * get all the tokens. Make sure tokens that need authentication are put at
1886 * the end of this list.
1887 */
1888 PK11SlotList *
1889 PK11_GetAllTokens(CK_MECHANISM_TYPE type, PRBool needRW, PRBool loadCerts,
1890 void *wincx)
1891 {
1892 PK11SlotList * list;
1893 PK11SlotList * loginList;
1894 PK11SlotList * friendlyList;
1895 SECMODModuleList * mlp;
1896 SECMODModuleList * modules;
1897 SECMODListLock * moduleLock;
1898 int i;
1899 #if defined( XP_WIN32 )
1900 int j = 0;
1901 PRInt32 waste[16];
1902 #endif
1903
1904 moduleLock = SECMOD_GetDefaultModuleListLock();
1905 if (!moduleLock) {
1906 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1907 return NULL;
1908 }
1909
1910 list = PK11_NewSlotList();
1911 loginList = PK11_NewSlotList();
1912 friendlyList = PK11_NewSlotList();
1913 if ((list == NULL) || (loginList == NULL) || (friendlyList == NULL)) {
1914 if (list) PK11_FreeSlotList(list);
1915 if (loginList) PK11_FreeSlotList(loginList);
1916 if (friendlyList) PK11_FreeSlotList(friendlyList);
1917 return NULL;
1918 }
1919
1920 SECMOD_GetReadLock(moduleLock);
1921
1922 modules = SECMOD_GetDefaultModuleList();
1923 for(mlp = modules; mlp != NULL; mlp = mlp->next) {
1924
1925 #if defined( XP_WIN32 )
1926 /* This is works around some horrible cache/page thrashing problems
1927 ** on Win32. Without this, this loop can take up to 6 seconds at
1928 ** 100% CPU on a Pentium-Pro 200. The thing this changes is to
1929 ** increase the size of the stack frame and modify it.
1930 ** Moving the loop code itself seems to have no effect.
1931 ** Dunno why this combination makes a difference, but it does.
1932 */
1933 waste[ j & 0xf] = j++;
1934 #endif
1935
1936 for (i = 0; i < mlp->module->slotCount; i++) {
1937 PK11SlotInfo *slot = mlp->module->slots[i];
1938
1939 if (pk11_IsPresentCertLoad(slot, loadCerts)) {
1940 if (needRW && slot->readOnly) continue;
1941 if ((type == CKM_INVALID_MECHANISM)
1942 || PK11_DoesMechanism(slot, type)) {
1943 if (pk11_LoginStillRequired(slot,wincx)) {
1944 if (PK11_IsFriendly(slot)) {
1945 PK11_AddSlotToList(friendlyList, slot, PR_TRUE);
1946 } else {
1947 PK11_AddSlotToList(loginList, slot, PR_TRUE);
1948 }
1949 } else {
1950 PK11_AddSlotToList(list, slot, PR_TRUE);
1951 }
1952 }
1953 }
1954 }
1955 }
1956 SECMOD_ReleaseReadLock(moduleLock);
1957
1958 pk11_MoveListToList(list,friendlyList);
1959 PK11_FreeSlotList(friendlyList);
1960 pk11_MoveListToList(list,loginList);
1961 PK11_FreeSlotList(loginList);
1962
1963 return list;
1964 }
1965
1966 /*
1967 * NOTE: This routine is working from a private List generated by
1968 * PK11_GetAllTokens. That is why it does not need to lock.
1969 */
1970 PK11SlotList *
1971 PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type,PRBool needRW,void *wincx)
1972 {
1973 PK11SlotList *list = PK11_GetAllTokens(type,needRW,PR_TRUE,wincx);
1974 PK11SlotListElement *le, *next ;
1975 SECStatus rv;
1976
1977 if (list == NULL) return list;
1978
1979 for (le = list->head ; le; le = next) {
1980 next = le->next; /* save the pointer here in case we have to
1981 * free the element later */
1982 rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
1983 if (rv != SECSuccess) {
1984 PK11_DeleteSlotFromList(list,le);
1985 continue;
1986 }
1987 }
1988 return list;
1989 }
1990
1991 /*
1992 * returns true if the slot doesn't conform to the requested attributes
1993 */
1994 PRBool
1995 pk11_filterSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
1996 CK_FLAGS mechanismInfoFlags, unsigned int keySize)
1997 {
1998 CK_MECHANISM_INFO mechanism_info;
1999 CK_RV crv = CKR_OK;
2000
2001 /* handle the only case where we don't actually fetch the mechanisms
2002 * on the fly */
2003 if ((keySize == 0) && (mechanism == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
2004 mechanism_info.flags = slot->RSAInfoFlags;
2005 } else {
2006 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
2007 crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, mechanism,
2008 &mechanism_info);
2009 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
2010 /* if we were getting the RSA flags, save them */
2011 if ((crv == CKR_OK) && (mechanism == CKM_RSA_PKCS)
2012 && (!slot->hasRSAInfo)) {
2013 slot->RSAInfoFlags = mechanism_info.flags;
2014 slot->hasRSAInfo = PR_TRUE;
2015 }
2016 }
2017 /* couldn't get the mechanism info */
2018 if (crv != CKR_OK ) {
2019 return PR_TRUE;
2020 }
2021 if (keySize && ((mechanism_info.ulMinKeySize > keySize)
2022 || (mechanism_info.ulMaxKeySize < keySize)) ) {
2023 /* Token can do mechanism, but not at the key size we
2024 * want */
2025 return PR_TRUE;
2026 }
2027 if (mechanismInfoFlags && ((mechanism_info.flags & mechanismInfoFlags) !=
2028 mechanismInfoFlags) ) {
2029 return PR_TRUE;
2030 }
2031 return PR_FALSE;
2032 }
2033
2034
2035 /*
2036 * Find the best slot which supports the given set of mechanisms and key sizes.
2037 * In normal cases this should grab the first slot on the list with no fuss.
2038 * The size array is presumed to match one for one with the mechanism type
2039 * array, which allows you to specify the required key size for each
2040 * mechanism in the list. Whether key size is in bits or bytes is mechanism
2041 * dependent. Typically asymetric keys are in bits and symetric keys are in
2042 * bytes.
2043 */
2044 PK11SlotInfo *
2045 PK11_GetBestSlotMultipleWithAttributes(CK_MECHANISM_TYPE *type,
2046 CK_FLAGS *mechanismInfoFlags, unsigned int *keySize,
2047 unsigned int mech_count, void *wincx)
2048 {
2049 PK11SlotList *list = NULL;
2050 PK11SlotListElement *le ;
2051 PK11SlotInfo *slot = NULL;
2052 PRBool freeit = PR_FALSE;
2053 PRBool listNeedLogin = PR_FALSE;
2054 unsigned int i;
2055 SECStatus rv;
2056
2057 list = PK11_GetSlotList(type[0]);
2058
2059 if ((list == NULL) || (list->head == NULL)) {
2060 /* We need to look up all the tokens for the mechanism */
2061 list = PK11_GetAllTokens(type[0],PR_FALSE,PR_TRUE,wincx);
2062 freeit = PR_TRUE;
2063 }
2064
2065 /* no one can do it! */
2066 if (list == NULL) {
2067 PORT_SetError(SEC_ERROR_NO_TOKEN);
2068 return NULL;
2069 }
2070
2071 PORT_SetError(0);
2072
2073
2074 listNeedLogin = PR_FALSE;
2075 for (i=0; i < mech_count; i++) {
2076 if ((type[i] != CKM_FAKE_RANDOM) &&
2077 (type[i] != CKM_SHA_1) &&
2078 (type[i] != CKM_SHA224) &&
2079 (type[i] != CKM_SHA256) &&
2080 (type[i] != CKM_SHA384) &&
2081 (type[i] != CKM_SHA512) &&
2082 (type[i] != CKM_MD5) &&
2083 (type[i] != CKM_MD2)) {
2084 listNeedLogin = PR_TRUE;
2085 break;
2086 }
2087 }
2088
2089 for (le = PK11_GetFirstSafe(list); le;
2090 le = PK11_GetNextSafe(list,le,PR_TRUE)) {
2091 if (PK11_IsPresent(le->slot)) {
2092 PRBool doExit = PR_FALSE;
2093 for (i=0; i < mech_count; i++) {
2094 if (!PK11_DoesMechanism(le->slot,type[i])) {
2095 doExit = PR_TRUE;
2096 break;
2097 }
2098 if ((mechanismInfoFlags && mechanismInfoFlags[i]) ||
2099 (keySize && keySize[i])) {
2100 if (pk11_filterSlot(le->slot, type[i],
2101 mechanismInfoFlags ? mechanismInfoFlags[i] : 0,
2102 keySize ? keySize[i] : 0)) {
2103 doExit = PR_TRUE;
2104 break;
2105 }
2106 }
2107 }
2108
2109 if (doExit) continue;
2110
2111 if (listNeedLogin && le->slot->needLogin) {
2112 rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
2113 if (rv != SECSuccess) continue;
2114 }
2115 slot = le->slot;
2116 PK11_ReferenceSlot(slot);
2117 PK11_FreeSlotListElement(list,le);
2118 if (freeit) { PK11_FreeSlotList(list); }
2119 return slot;
2120 }
2121 }
2122 if (freeit) { PK11_FreeSlotList(list); }
2123 if (PORT_GetError() == 0) {
2124 PORT_SetError(SEC_ERROR_NO_TOKEN);
2125 }
2126 return NULL;
2127 }
2128
2129 PK11SlotInfo *
2130 PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type,
2131 unsigned int mech_count, void *wincx)
2132 {
2133 return PK11_GetBestSlotMultipleWithAttributes(type, NULL, NULL,
2134 mech_count, wincx);
2135 }
2136
2137 /* original get best slot now calls the multiple version with only one type */
2138 PK11SlotInfo *
2139 PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
2140 {
2141 return PK11_GetBestSlotMultipleWithAttributes(&type, NULL, NULL, 1, wincx);
2142 }
2143
2144 PK11SlotInfo *
2145 PK11_GetBestSlotWithAttributes(CK_MECHANISM_TYPE type, CK_FLAGS mechanismFlags,
2146 unsigned int keySize, void *wincx)
2147 {
2148 return PK11_GetBestSlotMultipleWithAttributes(&type, &mechanismFlags,
2149 &keySize, 1, wincx);
2150 }
2151
2152 int
2153 PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism)
2154 {
2155 CK_MECHANISM_INFO mechanism_info;
2156 CK_RV crv;
2157
2158 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
2159 crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
2160 mechanism,&mechanism_info);
2161 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
2162 if (crv != CKR_OK) return 0;
2163
2164 if (mechanism_info.ulMinKeySize == mechanism_info.ulMaxKeySize)
2165 return 0;
2166 return mechanism_info.ulMaxKeySize;
2167 }
2168
2169
2170 /*
2171 * This function uses the existing PKCS #11 module to find the
2172 * longest supported key length in the preferred token for a mechanism.
2173 * This varies from the above function in that 1) it returns the key length
2174 * even for fixed key algorithms, and 2) it looks through the tokens
2175 * generally rather than for a specific token. This is used in liu of
2176 * a PK11_GetKeyLength function in pk11mech.c since we can actually read
2177 * supported key lengths from PKCS #11.
2178 *
2179 * For symmetric key operations the length is returned in bytes.
2180 */
2181 int
2182 PK11_GetMaxKeyLength(CK_MECHANISM_TYPE mechanism)
2183 {
2184 CK_MECHANISM_INFO mechanism_info;
2185 PK11SlotList *list = NULL;
2186 PK11SlotListElement *le ;
2187 PRBool freeit = PR_FALSE;
2188 int keyLength = 0;
2189
2190 list = PK11_GetSlotList(mechanism);
2191
2192 if ((list == NULL) || (list->head == NULL)) {
2193 /* We need to look up all the tokens for the mechanism */
2194 list = PK11_GetAllTokens(mechanism,PR_FALSE,PR_FALSE,NULL);
2195 freeit = PR_TRUE;
2196 }
2197
2198 /* no tokens recognize this mechanism */
2199 if (list == NULL) {
2200 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
2201 return 0;
2202 }
2203
2204 for (le = PK11_GetFirstSafe(list); le;
2205 le = PK11_GetNextSafe(list,le,PR_TRUE)) {
2206 PK11SlotInfo *slot = le->slot;
2207 CK_RV crv;
2208 if (PK11_IsPresent(slot)) {
2209 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
2210 crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
2211 mechanism,&mechanism_info);
2212 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
2213 if ((crv == CKR_OK) && (mechanism_info.ulMaxKeySize != 0)
2214 && (mechanism_info.ulMaxKeySize != 0xffffffff)) {
2215 keyLength = mechanism_info.ulMaxKeySize;
2216 break;
2217 }
2218 }
2219 }
2220 if (le)
2221 PK11_FreeSlotListElement(list, le);
2222 if (freeit)
2223 PK11_FreeSlotList(list);
2224 return keyLength;
2225 }
2226
2227 SECStatus
2228 PK11_SeedRandom(PK11SlotInfo *slot, unsigned char *data, int len) {
2229 CK_RV crv;
2230
2231 PK11_EnterSlotMonitor(slot);
2232 crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session, data, (CK_ULONG)len);
2233 PK11_ExitSlotMonitor(slot);
2234 if (crv != CKR_OK) {
2235 PORT_SetError(PK11_MapError(crv));
2236 return SECFailure;
2237 }
2238 return SECSuccess;
2239 }
2240
2241
2242 SECStatus
2243 PK11_GenerateRandomOnSlot(PK11SlotInfo *slot, unsigned char *data, int len) {
2244 CK_RV crv;
2245
2246 if (!slot->isInternal) PK11_EnterSlotMonitor(slot);
2247 crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session,data,
2248 (CK_ULONG)len);
2249 if (!slot->isInternal) PK11_ExitSlotMonitor(slot);
2250 if (crv != CKR_OK) {
2251 PORT_SetError(PK11_MapError(crv));
2252 return SECFailure;
2253 }
2254 return SECSuccess;
2255 }
2256
2257 /* Attempts to update the Best Slot for "FAKE RANDOM" generation.
2258 ** If that's not the internal slot, then it also attempts to update the
2259 ** internal slot.
2260 ** The return value indicates if the INTERNAL slot was updated OK.
2261 */
2262 SECStatus
2263 PK11_RandomUpdate(void *data, size_t bytes)
2264 {
2265 PK11SlotInfo *slot;
2266 PRBool bestIsInternal;
2267 SECStatus status;
2268
2269 slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
2270 if (slot == NULL) {
2271 slot = PK11_GetInternalSlot();
2272 if (!slot)
2273 return SECFailure;
2274 }
2275
2276 bestIsInternal = PK11_IsInternal(slot);
2277 status = PK11_SeedRandom(slot, data, bytes);
2278 PK11_FreeSlot(slot);
2279
2280 if (!bestIsInternal) {
2281 /* do internal slot, too. */
2282 slot = PK11_GetInternalSlot(); /* can't fail */
2283 status = PK11_SeedRandom(slot, data, bytes);
2284 PK11_FreeSlot(slot);
2285 }
2286 return status;
2287 }
2288
2289
2290 SECStatus
2291 PK11_GenerateRandom(unsigned char *data,int len) {
2292 PK11SlotInfo *slot;
2293 SECStatus rv;
2294
2295 slot = PK11_GetBestSlot(CKM_FAKE_RANDOM,NULL);
2296 if (slot == NULL) return SECFailure;
2297
2298 rv = PK11_GenerateRandomOnSlot(slot, data, len);
2299 PK11_FreeSlot(slot);
2300 return rv;
2301 }
2302
2303 /*
2304 * Reset the token to it's initial state. For the internal module, this will
2305 * Purge your keydb, and reset your cert db certs to USER_INIT.
2306 */
2307 SECStatus
2308 PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd)
2309 {
2310 unsigned char tokenName[32];
2311 int tokenNameLen;
2312 CK_RV crv;
2313
2314 /* reconstruct the token name */
2315 tokenNameLen = PORT_Strlen(slot->token_name);
2316 if (tokenNameLen > sizeof(tokenName)) {
2317 tokenNameLen = sizeof(tokenName);
2318 }
2319
2320 PORT_Memcpy(tokenName,slot->token_name,tokenNameLen);
2321 if (tokenNameLen < sizeof(tokenName)) {
2322 PORT_Memset(&tokenName[tokenNameLen],' ',
2323 sizeof(tokenName)-tokenNameLen);
2324 }
2325
2326 /* initialize the token */
2327 PK11_EnterSlotMonitor(slot);
2328
2329 /* first shutdown the token. Existing sessions will get closed here */
2330 PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
2331 slot->session = CK_INVALID_SESSION;
2332
2333 /* now re-init the token */
2334 crv = PK11_GETTAB(slot)->C_InitToken(slot->slotID,
2335 (unsigned char *)sso_pwd, sso_pwd ? PORT_Strlen(sso_pwd): 0, tokenName);
2336
2337 /* finally bring the token back up */
2338 PK11_InitToken(slot,PR_TRUE);
2339 PK11_ExitSlotMonitor(slot);
2340 if (crv != CKR_OK) {
2341 PORT_SetError(PK11_MapError(crv));
2342 return SECFailure;
2343 }
2344 nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
2345 slot->nssToken);
2346 return SECSuccess;
2347 }
2348 void
2349 PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst)
2350 {
2351 sl->nssToken = nsst;
2352 }
2353
2354 NSSToken *
2355 PK11Slot_GetNSSToken(PK11SlotInfo *sl)
2356 {
2357 return sl->nssToken;
2358 }
2359
2360 /*
2361 * wait for a token to change it's state. The application passes in the expected
2362 * new state in event.
2363 */
2364 PK11TokenStatus
2365 PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event,
2366 PRIntervalTime timeout, PRIntervalTime latency, int series)
2367 {
2368 PRIntervalTime first_time = 0;
2369 PRBool first_time_set = PR_FALSE;
2370 PRBool waitForRemoval;
2371
2372 if (slot->isPerm) {
2373 return PK11TokenNotRemovable;
2374 }
2375 if (latency == 0) {
2376 latency = PR_SecondsToInterval(5);
2377 }
2378 waitForRemoval = (PRBool) (event == PK11TokenRemovedOrChangedEvent);
2379
2380 if (series == 0) {
2381 series = PK11_GetSlotSeries(slot);
2382 }
2383 while (PK11_IsPresent(slot) == waitForRemoval ) {
2384 PRIntervalTime interval;
2385
2386 if (waitForRemoval && series != PK11_GetSlotSeries(slot)) {
2387 return PK11TokenChanged;
2388 }
2389 if (timeout == PR_INTERVAL_NO_WAIT) {
2390 return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
2391 }
2392 if (timeout != PR_INTERVAL_NO_TIMEOUT ) {
2393 interval = PR_IntervalNow();
2394 if (!first_time_set) {
2395 first_time = interval;
2396 first_time_set = PR_TRUE;
2397 }
2398 if ((interval-first_time) > timeout) {
2399 return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
2400 }
2401 }
2402 PR_Sleep(latency);
2403 }
2404 return waitForRemoval ? PK11TokenRemoved : PK11TokenPresent;
2405 }
OLDNEW
« no previous file with comments | « nss/lib/pk11wrap/pk11skey.c ('k') | nss/lib/pk11wrap/pk11util.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698