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