Back to index

lightning-sunbird  0.9+nobinonly
pk11slot.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  * Deal with PKCS #11 Slots.
00039  */
00040 #include "seccomon.h"
00041 #include "secmod.h"
00042 #include "nssilock.h"
00043 #include "secmodi.h"
00044 #include "secmodti.h"
00045 #include "pkcs11t.h"
00046 #include "pk11func.h"
00047 #include "secitem.h"
00048 #include "secerr.h"
00049 
00050 #include "dev.h" 
00051 #include "dev3hack.h" 
00052 #include "pkim.h"
00053 
00054 
00055 /*************************************************************
00056  * local static and global data
00057  *************************************************************/
00058 
00059 /*
00060  * This array helps parsing between names, mechanisms, and flags.
00061  * to make the config files understand more entries, add them
00062  * to this table. (NOTE: we need function to export this table and it's size)
00063  */
00064 PK11DefaultArrayEntry PK11_DefaultArray[] = {
00065        { "RSA", SECMOD_RSA_FLAG, CKM_RSA_PKCS },
00066        { "DSA", SECMOD_DSA_FLAG, CKM_DSA },
00067        { "DH", SECMOD_DH_FLAG, CKM_DH_PKCS_DERIVE },
00068        { "RC2", SECMOD_RC2_FLAG, CKM_RC2_CBC },
00069        { "RC4", SECMOD_RC4_FLAG, CKM_RC4 },
00070        { "DES", SECMOD_DES_FLAG, CKM_DES_CBC },
00071        { "AES", SECMOD_AES_FLAG, CKM_AES_CBC },
00072        { "RC5", SECMOD_RC5_FLAG, CKM_RC5_CBC },
00073        { "SHA-1", SECMOD_SHA1_FLAG, CKM_SHA_1 },
00074        { "SHA256", SECMOD_SHA256_FLAG, CKM_SHA256 },
00075 /*     { "SHA384", SECMOD_SHA512_FLAG, CKM_SHA384 }, */
00076        { "SHA512", SECMOD_SHA512_FLAG, CKM_SHA512 },
00077        { "MD5", SECMOD_MD5_FLAG, CKM_MD5 },
00078        { "MD2", SECMOD_MD2_FLAG, CKM_MD2 },
00079        { "SSL", SECMOD_SSL_FLAG, CKM_SSL3_PRE_MASTER_KEY_GEN },
00080        { "TLS", SECMOD_TLS_FLAG, CKM_TLS_MASTER_KEY_DERIVE },
00081        { "SKIPJACK", SECMOD_FORTEZZA_FLAG, CKM_SKIPJACK_CBC64 },
00082        { "Publicly-readable certs", SECMOD_FRIENDLY_FLAG, CKM_INVALID_MECHANISM },
00083        { "Random Num Generator", SECMOD_RANDOM_FLAG, CKM_FAKE_RANDOM },
00084 };
00085 const int num_pk11_default_mechanisms = 
00086                 sizeof(PK11_DefaultArray) / sizeof(PK11_DefaultArray[0]);
00087 
00088 PK11DefaultArrayEntry *
00089 PK11_GetDefaultArray(int *size)
00090 {
00091     if (size) {
00092        *size = num_pk11_default_mechanisms;
00093     }
00094     return PK11_DefaultArray;
00095 }
00096 
00097 /*
00098  * These  slotlists are lists of modules which provide default support for
00099  *  a given algorithm or mechanism.
00100  */
00101 static PK11SlotList pk11_aesSlotList,
00102     pk11_desSlotList,
00103     pk11_rc4SlotList,
00104     pk11_rc2SlotList,
00105     pk11_rc5SlotList,
00106     pk11_sha1SlotList,
00107     pk11_md5SlotList,
00108     pk11_md2SlotList,
00109     pk11_rsaSlotList,
00110     pk11_dsaSlotList,
00111     pk11_dhSlotList,
00112     pk11_ecSlotList,
00113     pk11_ideaSlotList,
00114     pk11_sslSlotList,
00115     pk11_tlsSlotList,
00116     pk11_randomSlotList,
00117     pk11_sha256SlotList,
00118     pk11_sha512SlotList;    /* slots do SHA512 and SHA384 */
00119 
00120 /************************************************************
00121  * Generic Slot List and Slot List element manipulations
00122  ************************************************************/
00123 
00124 /*
00125  * allocate a new list 
00126  */
00127 PK11SlotList *
00128 PK11_NewSlotList(void)
00129 {
00130     PK11SlotList *list;
00131  
00132     list = (PK11SlotList *)PORT_Alloc(sizeof(PK11SlotList));
00133     if (list == NULL) return NULL;
00134     list->head = NULL;
00135     list->tail = NULL;
00136     list->lock = PZ_NewLock(nssILockList);
00137     if (list->lock == NULL) {
00138        PORT_Free(list);
00139        return NULL;
00140     }
00141 
00142     return list;
00143 }
00144 
00145 /*
00146  * free a list element when all the references go away.
00147  */
00148 SECStatus
00149 PK11_FreeSlotListElement(PK11SlotList *list, PK11SlotListElement *le)
00150 {
00151     PRBool freeit = PR_FALSE;
00152 
00153     if (list == NULL || le == NULL) {
00154        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00155        return SECFailure;
00156     }
00157 
00158     PZ_Lock(list->lock);
00159     if (le->refCount-- == 1) {
00160        freeit = PR_TRUE;
00161     }
00162     PZ_Unlock(list->lock);
00163     if (freeit) {
00164        PK11_FreeSlot(le->slot);
00165        PORT_Free(le);
00166     }
00167     return SECSuccess;
00168 }
00169 
00170 static void
00171 pk11_FreeSlotListStatic(PK11SlotList *list)
00172 {
00173     PK11SlotListElement *le, *next ;
00174     if (list == NULL) return;
00175 
00176     for (le = list->head ; le; le = next) {
00177        next = le->next;
00178        PK11_FreeSlotListElement(list,le);
00179     }
00180     if (list->lock) {
00181        PZ_DestroyLock(list->lock);
00182     }
00183     list->lock = NULL;
00184     list->head = NULL;
00185 }
00186 
00187 /*
00188  * if we are freeing the list, we must be the only ones with a pointer
00189  * to the list.
00190  */
00191 void
00192 PK11_FreeSlotList(PK11SlotList *list)
00193 {
00194     pk11_FreeSlotListStatic(list);
00195     PORT_Free(list);
00196 }
00197 
00198 /*
00199  * add a slot to a list
00200  */
00201 SECStatus
00202 PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot)
00203 {
00204     PK11SlotListElement *le;
00205 
00206     le = (PK11SlotListElement *) PORT_Alloc(sizeof(PK11SlotListElement));
00207     if (le == NULL) return SECFailure;
00208 
00209     le->slot = PK11_ReferenceSlot(slot);
00210     le->prev = NULL;
00211     le->refCount = 1;
00212     PZ_Lock(list->lock);
00213     if (list->head) list->head->prev = le; else list->tail = le;
00214     le->next = list->head;
00215     list->head = le;
00216     PZ_Unlock(list->lock);
00217 
00218     return SECSuccess;
00219 }
00220 
00221 /*
00222  * remove a slot entry from the list
00223  */
00224 SECStatus
00225 PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le)
00226 {
00227     PZ_Lock(list->lock);
00228     if (le->prev) le->prev->next = le->next; else list->head = le->next;
00229     if (le->next) le->next->prev = le->prev; else list->tail = le->prev;
00230     le->next = le->prev = NULL;
00231     PZ_Unlock(list->lock);
00232     PK11_FreeSlotListElement(list,le);
00233     return SECSuccess;
00234 }
00235 
00236 /*
00237  * Move a list to the end of the target list. NOTE: There is no locking
00238  * here... This assumes BOTH lists are private copy lists.
00239  */
00240 SECStatus
00241 PK11_MoveListToList(PK11SlotList *target,PK11SlotList *src)
00242 {
00243     if (src->head == NULL) return SECSuccess;
00244 
00245     if (target->tail == NULL) {
00246        target->head = src->head;
00247     } else {
00248        target->tail->next = src->head;
00249     }
00250     src->head->prev = target->tail;
00251     target->tail = src->tail;
00252     src->head = src->tail = NULL;
00253     return SECSuccess;
00254 }
00255 
00256 /*
00257  * get an element from the list with a reference. You must own the list.
00258  */
00259 PK11SlotListElement *
00260 PK11_GetFirstRef(PK11SlotList *list)
00261 {
00262     PK11SlotListElement *le;
00263 
00264     le = list->head;
00265     if (le != NULL) (le)->refCount++;
00266     return le;
00267 }
00268 
00269 /*
00270  * get the next element from the list with a reference. You must own the list.
00271  */
00272 PK11SlotListElement *
00273 PK11_GetNextRef(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
00274 {
00275     PK11SlotListElement *new_le;
00276     new_le = le->next;
00277     if (new_le) new_le->refCount++;
00278     PK11_FreeSlotListElement(list,le);
00279     return new_le;
00280 }
00281 
00282 /*
00283  * get an element safely from the list. This just makes sure that if
00284  * this element is not deleted while we deal with it.
00285  */
00286 PK11SlotListElement *
00287 PK11_GetFirstSafe(PK11SlotList *list)
00288 {
00289     PK11SlotListElement *le;
00290 
00291     PZ_Lock(list->lock);
00292     le = list->head;
00293     if (le != NULL) (le)->refCount++;
00294     PZ_Unlock(list->lock);
00295     return le;
00296 }
00297 
00298 /*
00299  * NOTE: if this element gets deleted, we can no longer safely traverse using
00300  * it's pointers. We can either terminate the loop, or restart from the
00301  * beginning. This is controlled by the restart option.
00302  */
00303 PK11SlotListElement *
00304 PK11_GetNextSafe(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
00305 {
00306     PK11SlotListElement *new_le;
00307     PZ_Lock(list->lock);
00308     new_le = le->next;
00309     if (le->next == NULL) {
00310        /* if the prev and next fields are NULL then either this element
00311         * has been removed and we need to walk the list again (if restart
00312         * is true) or this was the only element on the list */
00313        if ((le->prev == NULL) && restart &&  (list->head != le)) {
00314            new_le = list->head;
00315        }
00316     }
00317     if (new_le) new_le->refCount++;
00318     PZ_Unlock(list->lock);
00319     PK11_FreeSlotListElement(list,le);
00320     return new_le;
00321 }
00322 
00323 
00324 /*
00325  * Find the element that holds this slot
00326  */
00327 PK11SlotListElement *
00328 PK11_FindSlotElement(PK11SlotList *list,PK11SlotInfo *slot)
00329 {
00330     PK11SlotListElement *le;
00331 
00332     for (le = PK11_GetFirstSafe(list); le;
00333                             le = PK11_GetNextSafe(list,le,PR_TRUE)) {
00334        if (le->slot == slot) return le;
00335     }
00336     return NULL;
00337 }
00338 
00339 /************************************************************
00340  * Generic Slot Utilities
00341  ************************************************************/
00342 /*
00343  * Create a new slot structure
00344  */
00345 PK11SlotInfo *
00346 PK11_NewSlotInfo(SECMODModule *mod)
00347 {
00348     PK11SlotInfo *slot;
00349 
00350     slot = (PK11SlotInfo *)PORT_Alloc(sizeof(PK11SlotInfo));
00351     if (slot == NULL) return slot;
00352 
00353     slot->sessionLock = mod->isThreadSafe ?
00354        PZ_NewLock(nssILockSession) : mod->refLock;
00355     if (slot->sessionLock == NULL) {
00356        PORT_Free(slot);
00357        return NULL;
00358     }
00359     slot->freeListLock = PZ_NewLock(nssILockFreelist);
00360     if (slot->freeListLock == NULL) {
00361        if (mod->isThreadSafe) {
00362            PZ_DestroyLock(slot->sessionLock);
00363        }
00364        PORT_Free(slot);
00365        return NULL;
00366     }
00367     slot->freeSymKeysWithSessionHead = NULL;
00368     slot->freeSymKeysHead = NULL;
00369     slot->keyCount = 0;
00370     slot->maxKeyCount = 0;
00371     slot->functionList = NULL;
00372     slot->needTest = PR_TRUE;
00373     slot->isPerm = PR_FALSE;
00374     slot->isHW = PR_FALSE;
00375     slot->isInternal = PR_FALSE;
00376     slot->isThreadSafe = PR_FALSE;
00377     slot->disabled = PR_FALSE;
00378     slot->series = 1;
00379     slot->wrapKey = 0;
00380     slot->wrapMechanism = CKM_INVALID_MECHANISM;
00381     slot->refKeys[0] = CK_INVALID_HANDLE;
00382     slot->reason = PK11_DIS_NONE;
00383     slot->readOnly = PR_TRUE;
00384     slot->needLogin = PR_FALSE;
00385     slot->hasRandom = PR_FALSE;
00386     slot->defRWSession = PR_FALSE;
00387     slot->protectedAuthPath = PR_FALSE;
00388     slot->flags = 0;
00389     slot->session = CK_INVALID_SESSION;
00390     slot->slotID = 0;
00391     slot->defaultFlags = 0;
00392     slot->refCount = 1;
00393     slot->askpw = 0;
00394     slot->timeout = 0;
00395     slot->mechanismList = NULL;
00396     slot->mechanismCount = 0;
00397     slot->cert_array = NULL;
00398     slot->cert_count = 0;
00399     slot->slot_name[0] = 0;
00400     slot->token_name[0] = 0;
00401     PORT_Memset(slot->serial,' ',sizeof(slot->serial));
00402     slot->module = NULL;
00403     slot->authTransact = 0;
00404     slot->authTime = LL_ZERO;
00405     slot->minPassword = 0;
00406     slot->maxPassword = 0;
00407     slot->hasRootCerts = PR_FALSE;
00408     slot->nssToken = NULL;
00409     return slot;
00410 }
00411     
00412 /* create a new reference to a slot so it doesn't go away */
00413 PK11SlotInfo *
00414 PK11_ReferenceSlot(PK11SlotInfo *slot)
00415 {
00416     PR_AtomicIncrement(&slot->refCount);
00417     return slot;
00418 }
00419 
00420 /* Destroy all info on a slot we have built up */
00421 void
00422 PK11_DestroySlot(PK11SlotInfo *slot)
00423 {
00424    /* free up the cached keys and sessions */
00425    PK11_CleanKeyList(slot);
00426    
00427    /* free up all the sessions on this slot */
00428    if (slot->functionList) {
00429        PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
00430    }
00431 
00432    if (slot->mechanismList) {
00433        PORT_Free(slot->mechanismList);
00434    }
00435    if (slot->isThreadSafe && slot->sessionLock) {
00436        PZ_DestroyLock(slot->sessionLock);
00437    }
00438    slot->sessionLock = NULL;
00439    if (slot->freeListLock) {
00440        PZ_DestroyLock(slot->freeListLock);
00441        slot->freeListLock = NULL;
00442    }
00443 
00444    /* finally Tell our parent module that we've gone away so it can unload */
00445    if (slot->module) {
00446        SECMOD_SlotDestroyModule(slot->module,PR_TRUE);
00447    }
00448 
00449    /* ok, well not quit finally... now we free the memory */
00450    PORT_Free(slot);
00451 }
00452 
00453 
00454 /* We're all done with the slot, free it */
00455 void
00456 PK11_FreeSlot(PK11SlotInfo *slot)
00457 {
00458     if (PR_AtomicDecrement(&slot->refCount) == 0) {
00459        PK11_DestroySlot(slot);
00460     }
00461 }
00462 
00463 void
00464 PK11_EnterSlotMonitor(PK11SlotInfo *slot) {
00465     PZ_Lock(slot->sessionLock);
00466 }
00467 
00468 void
00469 PK11_ExitSlotMonitor(PK11SlotInfo *slot) {
00470     PZ_Unlock(slot->sessionLock);
00471 }
00472 
00473 /***********************************************************
00474  * Functions to find specific slots.
00475  ***********************************************************/
00476 PRBool
00477 SECMOD_HasRootCerts(void)
00478 {
00479    SECMODModuleList *mlp;
00480    SECMODModuleList *modules = SECMOD_GetDefaultModuleList();
00481    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
00482    int i;
00483    PRBool found = PR_FALSE;
00484 
00485    /* work through all the slots */
00486    SECMOD_GetReadLock(moduleLock);
00487    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
00488        for (i=0; i < mlp->module->slotCount; i++) {
00489            PK11SlotInfo *tmpSlot = mlp->module->slots[i];
00490            if (PK11_IsPresent(tmpSlot)) {
00491               if (tmpSlot->hasRootCerts) {
00492                   found = PR_TRUE;
00493                   break;
00494               }
00495            }
00496        }
00497        if (found) break;
00498     }
00499     SECMOD_ReleaseReadLock(moduleLock);
00500 
00501     return found;
00502 }
00503 
00504 /***********************************************************
00505  * Functions to find specific slots.
00506  ***********************************************************/
00507 PK11SlotList *
00508 PK11_FindSlotsByNames(const char *dllName, const char* slotName,
00509                         const char* tokenName, PRBool presentOnly)
00510 {
00511     SECMODModuleList *mlp;
00512     SECMODModuleList *modules = SECMOD_GetDefaultModuleList();
00513     SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
00514     int i;
00515     PK11SlotList* slotList = NULL;
00516     PRUint32 slotcount = 0;
00517     SECStatus rv = SECSuccess;
00518 
00519     slotList = PK11_NewSlotList();
00520     if (!slotList) {
00521         PORT_SetError(SEC_ERROR_NO_MEMORY);
00522         return NULL;
00523     }
00524 
00525     if ( ((NULL == dllName) || (0 == *dllName)) &&
00526         ((NULL == slotName) || (0 == *slotName)) &&
00527         ((NULL == tokenName) || (0 == *tokenName)) ) {
00528         /* default to softoken */
00529         PK11_AddSlotToList(slotList, PK11_GetInternalKeySlot());
00530         return slotList;
00531     }
00532 
00533     /* work through all the slots */
00534     SECMOD_GetReadLock(moduleLock);
00535     for (mlp = modules; mlp != NULL; mlp = mlp->next) {
00536         PORT_Assert(mlp->module);
00537         if (!mlp->module) {
00538             rv = SECFailure;
00539             break;
00540         }
00541         if ((!dllName) || (mlp->module->dllName &&
00542             (0 == PORT_Strcmp(mlp->module->dllName, dllName)))) {
00543             for (i=0; i < mlp->module->slotCount; i++) {
00544                 PK11SlotInfo *tmpSlot = (mlp->module->slots?mlp->module->slots[i]:NULL);
00545                 PORT_Assert(tmpSlot);
00546                 if (!tmpSlot) {
00547                     rv = SECFailure;
00548                     break;
00549                 }
00550                 if ((PR_FALSE == presentOnly || PK11_IsPresent(tmpSlot)) &&
00551                     ( (!tokenName) || (tmpSlot->token_name &&
00552                     (0==PORT_Strcmp(tmpSlot->token_name, tokenName)))) &&
00553                     ( (!slotName) || (tmpSlot->slot_name &&
00554                     (0==PORT_Strcmp(tmpSlot->slot_name, slotName)))) ) {
00555                     PK11SlotInfo* slot = PK11_ReferenceSlot(tmpSlot);
00556                     if (slot) {
00557                         PK11_AddSlotToList(slotList, slot);
00558                         slotcount++;
00559                     }
00560                 }
00561             }
00562         }
00563     }
00564     SECMOD_ReleaseReadLock(moduleLock);
00565 
00566     if ( (0 == slotcount) || (SECFailure == rv) ) {
00567         PORT_SetError(SEC_ERROR_NO_TOKEN);
00568         PK11_FreeSlotList(slotList);
00569         slotList = NULL;
00570     }
00571 
00572     if (SECFailure == rv) {
00573         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00574     }
00575 
00576     return slotList;
00577 }
00578 
00579 PK11SlotInfo *
00580 PK11_FindSlotByName(const char *name)
00581 {
00582    SECMODModuleList *mlp;
00583    SECMODModuleList *modules = SECMOD_GetDefaultModuleList();
00584    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
00585    int i;
00586    PK11SlotInfo *slot = NULL;
00587 
00588    if ((name == NULL) || (*name == 0)) {
00589        return PK11_GetInternalKeySlot();
00590    }
00591 
00592    /* work through all the slots */
00593    SECMOD_GetReadLock(moduleLock);
00594    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
00595        for (i=0; i < mlp->module->slotCount; i++) {
00596            PK11SlotInfo *tmpSlot = mlp->module->slots[i];
00597            if (PK11_IsPresent(tmpSlot)) {
00598               if (PORT_Strcmp(tmpSlot->token_name,name) == 0) {
00599                   slot = PK11_ReferenceSlot(tmpSlot);
00600                   break;
00601               }
00602            }
00603        }
00604        if (slot != NULL) break;
00605     }
00606     SECMOD_ReleaseReadLock(moduleLock);
00607 
00608     if (slot == NULL) {
00609        PORT_SetError(SEC_ERROR_NO_TOKEN);
00610     }
00611 
00612     return slot;
00613 }
00614 
00615 
00616 PK11SlotInfo *
00617 PK11_FindSlotBySerial(char *serial)
00618 {
00619    SECMODModuleList *mlp;
00620    SECMODModuleList *modules = SECMOD_GetDefaultModuleList();
00621    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
00622    int i;
00623    PK11SlotInfo *slot = NULL;
00624 
00625    /* work through all the slots */
00626    SECMOD_GetReadLock(moduleLock);
00627    for(mlp = modules; mlp != NULL; mlp = mlp->next) {
00628        for (i=0; i < mlp->module->slotCount; i++) {
00629            PK11SlotInfo *tmpSlot = mlp->module->slots[i];
00630            if (PK11_IsPresent(tmpSlot)) {
00631               if (PORT_Memcmp(tmpSlot->serial,serial,
00632                                    sizeof(tmpSlot->serial)) == 0) {
00633                   slot = PK11_ReferenceSlot(tmpSlot);
00634                   break;
00635               }
00636            }
00637        }
00638        if (slot != NULL) break;
00639     }
00640     SECMOD_ReleaseReadLock(moduleLock);
00641 
00642     if (slot == NULL) {
00643        PORT_SetError(SEC_ERROR_NO_TOKEN);
00644     }
00645 
00646     return slot;
00647 }
00648 
00649 /*
00650  * notification stub. If we ever get interested in any events that
00651  * the pkcs11 functions may pass back to use, we can catch them here...
00652  * currently pdata is a slotinfo structure.
00653  */
00654 CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event,
00655                                                   CK_VOID_PTR pdata)
00656 {
00657     return CKR_OK;
00658 }
00659 
00660 /*
00661  * grab a new RW session
00662  * !!! has a side effect of grabbing the Monitor if either the slot's default
00663  * session is RW or the slot is not thread safe. Monitor is release in function
00664  * below
00665  */
00666 CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot)
00667 {
00668     CK_SESSION_HANDLE rwsession;
00669     CK_RV crv;
00670     PRBool haveMonitor = PR_FALSE;
00671 
00672     if (!slot->isThreadSafe || slot->defRWSession) {
00673        PK11_EnterSlotMonitor(slot);
00674        haveMonitor = PR_TRUE;
00675     }
00676     if (slot->defRWSession) {
00677        PORT_Assert(slot->session != CK_INVALID_SESSION);
00678        if (slot->session != CK_INVALID_SESSION) 
00679            return slot->session;
00680     }
00681 
00682     crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
00683                             CKF_RW_SESSION|CKF_SERIAL_SESSION,
00684                                      slot, pk11_notify,&rwsession);
00685     PORT_Assert(rwsession != CK_INVALID_SESSION || crv != CKR_OK);
00686     if (crv != CKR_OK || rwsession == CK_INVALID_SESSION) {
00687        if (crv == CKR_OK) 
00688            crv = CKR_DEVICE_ERROR;
00689        if (haveMonitor)
00690            PK11_ExitSlotMonitor(slot);
00691        PORT_SetError(PK11_MapError(crv));
00692        return CK_INVALID_SESSION;
00693     }
00694     if (slot->defRWSession) { /* we have the monitor */
00695        slot->session = rwsession;
00696     }
00697     return rwsession;
00698 }
00699 
00700 PRBool
00701 PK11_RWSessionHasLock(PK11SlotInfo *slot,CK_SESSION_HANDLE session_handle) 
00702 {
00703     PRBool hasLock;
00704     hasLock = (PRBool)(!slot->isThreadSafe || 
00705              (slot->defRWSession && slot->session != CK_INVALID_SESSION));
00706     return hasLock;
00707 }
00708 
00709 static PRBool
00710 pk11_RWSessionIsDefault(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
00711 {
00712     PRBool isDefault;
00713     isDefault = (PRBool)(slot->session == rwsession &&
00714                         slot->defRWSession && 
00715                       slot->session != CK_INVALID_SESSION);
00716     return isDefault;
00717 }
00718 
00719 /*
00720  * close the rwsession and restore our readonly session
00721  * !!! has a side effect of releasing the Monitor if either the slot's default
00722  * session is RW or the slot is not thread safe.
00723  */
00724 void
00725 PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
00726 {
00727     PORT_Assert(rwsession != CK_INVALID_SESSION);
00728     if (rwsession != CK_INVALID_SESSION) {
00729        PRBool doExit = PK11_RWSessionHasLock(slot, rwsession);
00730        if (!pk11_RWSessionIsDefault(slot, rwsession))
00731            PK11_GETTAB(slot)->C_CloseSession(rwsession);
00732        if (doExit)
00733            PK11_ExitSlotMonitor(slot);
00734     }
00735 }
00736 
00737 /************************************************************
00738  * Manage the built-In Slot Lists
00739  ************************************************************/
00740 
00741 /* Init the static built int slot list (should actually integrate
00742  * with PK11_NewSlotList */
00743 static void
00744 pk11_InitSlotListStatic(PK11SlotList *list)
00745 {
00746     list->lock = PZ_NewLock(nssILockList);
00747     list->head = NULL;
00748 }
00749 
00750 
00751 /* initialize the system slotlists */
00752 SECStatus
00753 PK11_InitSlotLists(void)
00754 {
00755     pk11_InitSlotListStatic(&pk11_aesSlotList);
00756     pk11_InitSlotListStatic(&pk11_desSlotList);
00757     pk11_InitSlotListStatic(&pk11_rc4SlotList);
00758     pk11_InitSlotListStatic(&pk11_rc2SlotList);
00759     pk11_InitSlotListStatic(&pk11_rc5SlotList);
00760     pk11_InitSlotListStatic(&pk11_md5SlotList);
00761     pk11_InitSlotListStatic(&pk11_md2SlotList);
00762     pk11_InitSlotListStatic(&pk11_sha1SlotList);
00763     pk11_InitSlotListStatic(&pk11_rsaSlotList);
00764     pk11_InitSlotListStatic(&pk11_dsaSlotList);
00765     pk11_InitSlotListStatic(&pk11_dhSlotList);
00766     pk11_InitSlotListStatic(&pk11_ecSlotList);
00767     pk11_InitSlotListStatic(&pk11_ideaSlotList);
00768     pk11_InitSlotListStatic(&pk11_sslSlotList);
00769     pk11_InitSlotListStatic(&pk11_tlsSlotList);
00770     pk11_InitSlotListStatic(&pk11_randomSlotList);
00771     pk11_InitSlotListStatic(&pk11_sha256SlotList);
00772     pk11_InitSlotListStatic(&pk11_sha512SlotList);
00773     return SECSuccess;
00774 }
00775 
00776 void
00777 PK11_DestroySlotLists(void)
00778 {
00779     pk11_FreeSlotListStatic(&pk11_aesSlotList);
00780     pk11_FreeSlotListStatic(&pk11_desSlotList);
00781     pk11_FreeSlotListStatic(&pk11_rc4SlotList);
00782     pk11_FreeSlotListStatic(&pk11_rc2SlotList);
00783     pk11_FreeSlotListStatic(&pk11_rc5SlotList);
00784     pk11_FreeSlotListStatic(&pk11_md5SlotList);
00785     pk11_FreeSlotListStatic(&pk11_md2SlotList);
00786     pk11_FreeSlotListStatic(&pk11_sha1SlotList);
00787     pk11_FreeSlotListStatic(&pk11_rsaSlotList);
00788     pk11_FreeSlotListStatic(&pk11_dsaSlotList);
00789     pk11_FreeSlotListStatic(&pk11_dhSlotList);
00790     pk11_FreeSlotListStatic(&pk11_ecSlotList);
00791     pk11_FreeSlotListStatic(&pk11_ideaSlotList);
00792     pk11_FreeSlotListStatic(&pk11_sslSlotList);
00793     pk11_FreeSlotListStatic(&pk11_tlsSlotList);
00794     pk11_FreeSlotListStatic(&pk11_randomSlotList);
00795     pk11_FreeSlotListStatic(&pk11_sha256SlotList);
00796     pk11_FreeSlotListStatic(&pk11_sha512SlotList);
00797     return;
00798 }
00799 
00800 /* return a system slot list based on mechanism */
00801 PK11SlotList *
00802 PK11_GetSlotList(CK_MECHANISM_TYPE type)
00803 {
00804 /* XXX a workaround for Bugzilla bug #55267 */
00805 #if defined(HPUX) && defined(__LP64__)
00806     if (CKM_INVALID_MECHANISM == type)
00807         return NULL;
00808 #endif
00809     switch (type) {
00810     case CKM_AES_CBC:
00811     case CKM_AES_ECB:
00812        return &pk11_aesSlotList;
00813     case CKM_DES_CBC:
00814     case CKM_DES_ECB:
00815     case CKM_DES3_ECB:
00816     case CKM_DES3_CBC:
00817        return &pk11_desSlotList;
00818     case CKM_RC4:
00819        return &pk11_rc4SlotList;
00820     case CKM_RC5_CBC:
00821        return &pk11_rc5SlotList;
00822     case CKM_SHA_1:
00823        return &pk11_sha1SlotList;
00824     case CKM_SHA256:
00825        return &pk11_sha256SlotList;
00826     case CKM_SHA384:
00827     case CKM_SHA512:
00828        return &pk11_sha512SlotList;
00829     case CKM_MD5:
00830        return &pk11_md5SlotList;
00831     case CKM_MD2:
00832        return &pk11_md2SlotList;
00833     case CKM_RC2_ECB:
00834     case CKM_RC2_CBC:
00835        return &pk11_rc2SlotList;
00836     case CKM_RSA_PKCS:
00837     case CKM_RSA_PKCS_KEY_PAIR_GEN:
00838     case CKM_RSA_X_509:
00839        return &pk11_rsaSlotList;
00840     case CKM_DSA:
00841        return &pk11_dsaSlotList;
00842     case CKM_DH_PKCS_KEY_PAIR_GEN:
00843     case CKM_DH_PKCS_DERIVE:
00844        return &pk11_dhSlotList;
00845     case CKM_ECDSA:
00846     case CKM_ECDSA_SHA1:
00847     case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
00848     case CKM_ECDH1_DERIVE:
00849        return &pk11_ecSlotList;
00850     case CKM_SSL3_PRE_MASTER_KEY_GEN:
00851     case CKM_SSL3_MASTER_KEY_DERIVE:
00852     case CKM_SSL3_SHA1_MAC:
00853     case CKM_SSL3_MD5_MAC:
00854        return &pk11_sslSlotList;
00855     case CKM_TLS_MASTER_KEY_DERIVE:
00856     case CKM_TLS_KEY_AND_MAC_DERIVE:
00857        return &pk11_tlsSlotList;
00858     case CKM_IDEA_CBC:
00859     case CKM_IDEA_ECB:
00860        return &pk11_ideaSlotList;
00861     case CKM_FAKE_RANDOM:
00862        return &pk11_randomSlotList;
00863     }
00864     return NULL;
00865 }
00866 
00867 /*
00868  * load the static SlotInfo structures used to select a PKCS11 slot.
00869  * preSlotInfo has a list of all the default flags for the slots on this
00870  * module.
00871  */
00872 void
00873 PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
00874 {
00875     int i;
00876 
00877     for (i=0; i < count; i++) {
00878        if (psi[i].slotID == slot->slotID)
00879            break;
00880     }
00881 
00882     if (i == count) return;
00883 
00884     slot->defaultFlags = psi[i].defaultFlags;
00885     slot->askpw = psi[i].askpw;
00886     slot->timeout = psi[i].timeout;
00887     slot->hasRootCerts = psi[i].hasRootCerts;
00888 
00889     /* if the slot is already disabled, don't load them into the
00890      * default slot lists. We get here so we can save the default
00891      * list value. */
00892     if (slot->disabled) return;
00893 
00894     /* if the user has disabled us, don't load us in */
00895     if (slot->defaultFlags & PK11_DISABLE_FLAG) {
00896        slot->disabled = PR_TRUE;
00897        slot->reason = PK11_DIS_USER_SELECTED;
00898        /* free up sessions and things?? */
00899        return;
00900     }
00901 
00902     for (i=0; i < num_pk11_default_mechanisms; i++) {
00903        if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
00904            CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
00905            PK11SlotList *slotList = PK11_GetSlotList(mechanism);
00906 
00907            if (slotList) PK11_AddSlotToList(slotList,slot);
00908        }
00909     }
00910 
00911     return;
00912 }
00913 
00914 
00915 /*
00916  * update a slot to its new attribute according to the slot list
00917  * returns: SECSuccess if nothing to do or add/delete is successful
00918  */
00919 SECStatus
00920 PK11_UpdateSlotAttribute(PK11SlotInfo *slot, PK11DefaultArrayEntry *entry,
00921                         PRBool add)  
00922                         /* add: PR_TRUE if want to turn on */
00923 {
00924     SECStatus result = SECSuccess;
00925     PK11SlotList *slotList = PK11_GetSlotList(entry->mechanism);
00926 
00927     if (add) { /* trying to turn on a mechanism */
00928                  
00929         /* turn on the default flag in the slot */
00930         slot->defaultFlags |= entry->flag;
00931         
00932         /* add this slot to the list */
00933         if (slotList!=NULL)
00934             result = PK11_AddSlotToList(slotList, slot);
00935         
00936     } else { /* trying to turn off */
00937             
00938         /* turn OFF the flag in the slot */ 
00939         slot->defaultFlags &= ~entry->flag;
00940         
00941         if (slotList) {
00942             /* find the element in the list & delete it */
00943             PK11SlotListElement *le = PK11_FindSlotElement(slotList, slot);
00944 
00945             /* remove the slot from the list */
00946             if (le)
00947                 result = PK11_DeleteSlotFromList(slotList, le);
00948         }
00949     }
00950     return result;
00951 }
00952 
00953 /*
00954  * clear a slot off of all of it's default list
00955  */
00956 void
00957 PK11_ClearSlotList(PK11SlotInfo *slot)
00958 {
00959     int i;
00960 
00961     if (slot->disabled) return;
00962     if (slot->defaultFlags == 0) return;
00963 
00964     for (i=0; i < num_pk11_default_mechanisms; i++) {
00965        if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
00966            CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
00967            PK11SlotList *slotList = PK11_GetSlotList(mechanism);
00968            PK11SlotListElement *le = NULL;
00969 
00970            if (slotList) le = PK11_FindSlotElement(slotList,slot);
00971 
00972            if (le) {
00973               PK11_DeleteSlotFromList(slotList,le);
00974               PK11_FreeSlotListElement(slotList,le);
00975            }
00976        }
00977     }
00978 }
00979 
00980 
00981 /******************************************************************
00982  *           Slot initialization
00983  ******************************************************************/
00984 /*
00985  * turn a PKCS11 Static Label into a string
00986  */
00987 char *
00988 PK11_MakeString(PRArenaPool *arena,char *space,
00989                                    char *staticString,int stringLen)
00990 {
00991        int i;
00992        char *newString;
00993        for(i=(stringLen-1); i >= 0; i--) {
00994          if (staticString[i] != ' ') break;
00995        }
00996        /* move i to point to the last space */
00997        i++;
00998        if (arena) {
00999            newString = (char*)PORT_ArenaAlloc(arena,i+1 /* space for NULL */);
01000        } else if (space) {
01001            newString = space;
01002        } else {
01003            newString = (char*)PORT_Alloc(i+1 /* space for NULL */);
01004        }
01005        if (newString == NULL) return NULL;
01006 
01007        if (i) PORT_Memcpy(newString,staticString, i);
01008        newString[i] = 0;
01009 
01010        return newString;
01011 }
01012 
01013 /*
01014  * verify that slot implements Mechanism mech properly by checking against
01015  * our internal implementation
01016  */
01017 PRBool
01018 PK11_VerifyMechanism(PK11SlotInfo *slot,PK11SlotInfo *intern,
01019   CK_MECHANISM_TYPE mech, SECItem *data, SECItem *iv)
01020 {
01021     PK11Context *test = NULL, *reference = NULL;
01022     PK11SymKey *symKey = NULL, *testKey = NULL;
01023     SECItem *param = NULL;
01024     unsigned char encTest[8];
01025     unsigned char encRef[8];
01026     int outLenTest,outLenRef;
01027     int key_size = 0;
01028     PRBool verify = PR_FALSE;
01029     SECStatus rv;
01030 
01031     if ((mech == CKM_RC2_CBC) || (mech == CKM_RC2_ECB) || (mech == CKM_RC4)) {
01032        key_size = 16;
01033     }
01034 
01035     /* initialize the mechanism parameter */
01036     param = PK11_ParamFromIV(mech,iv);
01037     if (param == NULL) goto loser;
01038 
01039     /* load the keys and contexts */
01040     symKey = PK11_KeyGen(intern,mech,NULL, key_size, NULL);
01041     if (symKey == NULL) goto loser;
01042 
01043     reference = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symKey, param);
01044     if (reference == NULL) goto loser;
01045 
01046     testKey = pk11_CopyToSlot(slot, mech, CKA_ENCRYPT, symKey);
01047     if (testKey == NULL) goto loser;
01048 
01049     test = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, testKey, param);
01050     if (test == NULL) goto loser;
01051     SECITEM_FreeItem(param,PR_TRUE); param = NULL;
01052 
01053     /* encrypt the test data */
01054     rv = PK11_CipherOp(test,encTest,&outLenTest,sizeof(encTest),
01055                                                  data->data,data->len);
01056     if (rv != SECSuccess) goto loser;
01057     rv = PK11_CipherOp(reference,encRef,&outLenRef,sizeof(encRef),
01058                                                  data->data,data->len);
01059     if (rv != SECSuccess) goto loser;
01060 
01061     PK11_DestroyContext(reference,PR_TRUE); reference = NULL;
01062     PK11_DestroyContext(test,PR_TRUE); test = NULL;
01063 
01064     if (outLenTest != outLenRef) goto loser;
01065     if (PORT_Memcmp(encTest, encRef, outLenTest) != 0) goto loser;
01066 
01067     verify = PR_TRUE;
01068 
01069 loser:
01070     if (test) PK11_DestroyContext(test,PR_TRUE);
01071     if (symKey) PK11_FreeSymKey(symKey);
01072     if (testKey) PK11_FreeSymKey(testKey);
01073     if (reference) PK11_DestroyContext(reference,PR_TRUE);
01074     if (param) SECITEM_FreeItem(param,PR_TRUE);
01075 
01076     return verify;
01077 }
01078 
01079 /*
01080  * this code verifies that the advertised mechanisms are what they
01081  * seem to be.
01082  */
01083 #define MAX_MECH_LIST_SIZE 30      /* we only know of about 30 odd mechanisms */
01084 PRBool
01085 PK11_VerifySlotMechanisms(PK11SlotInfo *slot)
01086 {
01087     CK_MECHANISM_TYPE mechListArray[MAX_MECH_LIST_SIZE];
01088     CK_MECHANISM_TYPE *mechList = mechListArray;
01089     static SECItem data;
01090     static SECItem iv;
01091     static unsigned char dataV[8];
01092     static unsigned char ivV[8];
01093     static PRBool generated = PR_FALSE;
01094     CK_ULONG count;
01095     int i;
01096     CK_RV crv;
01097 
01098     PRBool alloced = PR_FALSE;
01099     PK11SlotInfo *intern = PK11_GetInternalSlot();
01100 
01101     /* if we couldn't initialize an internal module, 
01102      * we can't check external ones */
01103     if (intern == NULL) return PR_FALSE;
01104 
01105     /* first get the count of mechanisms */
01106     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01107     crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,NULL,&count);
01108     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01109     if (crv != CKR_OK) {
01110        PK11_FreeSlot(intern);
01111        return PR_FALSE;
01112     }
01113 
01114 
01115     /* don't blow up just because the card supports more mechanisms than
01116      * we know about, just alloc space for them */
01117     if (count > MAX_MECH_LIST_SIZE) {
01118        mechList = (CK_MECHANISM_TYPE *)
01119                          PORT_Alloc(count *sizeof(CK_MECHANISM_TYPE));
01120        alloced = PR_TRUE;
01121        if (mechList == NULL) {
01122            PK11_FreeSlot(intern);
01123            return PR_FALSE;
01124        }
01125     }
01126     /* get the list */
01127     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01128     crv =PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID, mechList, &count);
01129     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01130     if (crv != CKR_OK) {
01131        if (alloced) PORT_Free(mechList);
01132        PK11_FreeSlot(intern);
01133        return PR_FALSE;
01134     }
01135 
01136     if (!generated) {
01137        data.data = dataV;
01138        data.len = sizeof(dataV);
01139        iv.data = ivV;
01140        iv.len = sizeof(ivV);
01141        /* ok, this is a cheat, we know our internal random number generater
01142         * is thread safe */
01143        PK11_GETTAB(intern)->C_GenerateRandom(intern->session,
01144                                                  data.data, data.len);
01145        PK11_GETTAB(intern)->C_GenerateRandom(intern->session,
01146                                                  iv.data, iv.len);
01147     }
01148     for (i=0; i < (int) count; i++) {
01149        switch (mechList[i]) {
01150        case CKM_DES_CBC:
01151        case CKM_DES_ECB:
01152        case CKM_RC4:
01153        case CKM_RC2_CBC:
01154        case CKM_RC2_ECB:
01155            if (!PK11_VerifyMechanism(slot,intern,mechList[i],&data,&iv)){
01156               if (alloced) PORT_Free(mechList);
01157               PK11_FreeSlot(intern);
01158               return PR_FALSE;
01159            }
01160        }
01161     }
01162     if (alloced) PORT_Free(mechList);
01163     PK11_FreeSlot(intern);
01164     return PR_TRUE;
01165 }
01166 
01167 /*
01168  * See if we need to run the verify test, do so if necessary. If we fail,
01169  * disable the slot.
01170  */    
01171 SECStatus
01172 pk11_CheckVerifyTest(PK11SlotInfo *slot)
01173 {
01174     PK11_EnterSlotMonitor(slot);
01175     if (slot->needTest) {
01176        slot->needTest = PR_FALSE; 
01177        PK11_ExitSlotMonitor(slot);
01178        if (!PK11_VerifySlotMechanisms(slot)) {
01179            (void)PK11_GETTAB(slot)->C_CloseSession(slot->session);
01180            slot->session = CK_INVALID_SESSION;
01181            PK11_ClearSlotList(slot);
01182            slot->disabled = PR_TRUE;
01183            slot->reason = PK11_DIS_TOKEN_VERIFY_FAILED;
01184            slot->needTest = PR_TRUE;
01185            PORT_SetError(SEC_ERROR_IO);
01186            return SECFailure;
01187        }
01188     } else {
01189        PK11_ExitSlotMonitor(slot);
01190     }
01191     return SECSuccess;
01192 }
01193 
01194 /*
01195  * Reads in the slots mechanism list for later use
01196  */
01197 SECStatus
01198 PK11_ReadMechanismList(PK11SlotInfo *slot)
01199 {
01200     CK_ULONG count;
01201     CK_RV crv;
01202     PRUint32 i;
01203 
01204     if (slot->mechanismList) {
01205        PORT_Free(slot->mechanismList);
01206        slot->mechanismList = NULL;
01207     }
01208     slot->mechanismCount = 0;
01209 
01210     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01211     crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,NULL,&count);
01212     if (crv != CKR_OK) {
01213        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01214        PORT_SetError(PK11_MapError(crv));
01215        return SECFailure;
01216     }
01217 
01218     slot->mechanismList = (CK_MECHANISM_TYPE *)
01219                          PORT_Alloc(count *sizeof(CK_MECHANISM_TYPE));
01220     if (slot->mechanismList == NULL) {
01221        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01222        return SECFailure;
01223     }
01224     crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,
01225                                           slot->mechanismList, &count);
01226     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01227     if (crv != CKR_OK) {
01228        PORT_Free(slot->mechanismList);
01229        slot->mechanismList = NULL;
01230        PORT_SetError(PK11_MapError(crv));
01231        return SECSuccess;
01232     }
01233     slot->mechanismCount = count;
01234     PORT_Memset(slot->mechanismBits, 0, sizeof(slot->mechanismBits));
01235 
01236     for (i=0; i < count; i++) {
01237        CK_MECHANISM_TYPE mech = slot->mechanismList[i];
01238        if (mech < 0x7ff) {
01239            slot->mechanismBits[mech & 0xff] |= 1 << (mech >> 8);
01240        }
01241     }
01242     return SECSuccess;
01243 }
01244 
01245 /*
01246  * initialize a new token
01247  * unlike initialize slot, this can be called multiple times in the lifetime
01248  * of NSS. It reads the information associated with a card or token,
01249  * that is not going to change unless the card or token changes.
01250  */
01251 SECStatus
01252 PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts)
01253 {
01254     CK_TOKEN_INFO tokenInfo;
01255     CK_RV crv;
01256     char *tmp;
01257     SECStatus rv;
01258 
01259     /* set the slot flags to the current token values */
01260     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01261     crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
01262     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01263     if (crv != CKR_OK) {
01264        PORT_SetError(PK11_MapError(crv));
01265        return SECFailure;
01266     }
01267 
01268     /* set the slot flags to the current token values */
01269     slot->series++; /* allow other objects to detect that the 
01270                     * slot is different */
01271     slot->flags = tokenInfo.flags;
01272     slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ? 
01273                                                  PR_TRUE : PR_FALSE);
01274     slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ? 
01275                                                  PR_TRUE : PR_FALSE);
01276     slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
01277     slot->protectedAuthPath =
01278               ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) 
01279                                                  ? PR_TRUE : PR_FALSE);
01280     slot->lastLoginCheck = 0;
01281     slot->lastState = 0;
01282     /* on some platforms Active Card incorrectly sets the 
01283      * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
01284     if (slot->isActiveCard) {
01285        slot->protectedAuthPath = PR_FALSE;
01286     }
01287     tmp = PK11_MakeString(NULL,slot->token_name,
01288                      (char *)tokenInfo.label, sizeof(tokenInfo.label));
01289     slot->minPassword = tokenInfo.ulMinPinLen;
01290     slot->maxPassword = tokenInfo.ulMaxPinLen;
01291     PORT_Memcpy(slot->serial,tokenInfo.serialNumber,sizeof(slot->serial));
01292 
01293     nssToken_UpdateName(slot->nssToken);
01294 
01295     slot->defRWSession = (PRBool)((!slot->readOnly) && 
01296                                    (tokenInfo.ulMaxSessionCount == 1));
01297     rv = PK11_ReadMechanismList(slot);
01298     if (rv != SECSuccess) return rv;
01299 
01300     slot->hasRSAInfo = PR_FALSE;
01301     slot->RSAInfoFlags = 0;
01302 
01303     /* initialize the maxKeyCount value */
01304     if (tokenInfo.ulMaxSessionCount == 0) {
01305        slot->maxKeyCount = 800; /* should be #define or a config param */
01306     } else if (tokenInfo.ulMaxSessionCount < 20) {
01307        /* don't have enough sessions to keep that many keys around */
01308        slot->maxKeyCount = 0;
01309     } else {
01310        slot->maxKeyCount = tokenInfo.ulMaxSessionCount/2;
01311     }
01312 
01313     /* Make sure our session handle is valid */
01314     if (slot->session == CK_INVALID_SESSION) {
01315        /* we know we don't have a valid session, go get one */
01316        CK_SESSION_HANDLE session;
01317 
01318        /* session should be Readonly, serial */
01319        if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01320        crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
01321              (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
01322                               slot,pk11_notify,&session);
01323        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01324        if (crv != CKR_OK) {
01325            PORT_SetError(PK11_MapError(crv));
01326            return SECFailure;
01327        }
01328        slot->session = session;
01329     } else {
01330        /* The session we have may be defunct (the token associated with it)
01331         * has been removed   */
01332        CK_SESSION_INFO sessionInfo;
01333 
01334        if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01335        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo);
01336         if (crv == CKR_DEVICE_ERROR) {
01337            PK11_GETTAB(slot)->C_CloseSession(slot->session);
01338            crv = CKR_SESSION_CLOSED;
01339        }
01340        if ((crv==CKR_SESSION_CLOSED) || (crv==CKR_SESSION_HANDLE_INVALID)) {
01341            crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
01342              (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
01343                                    slot,pk11_notify,&slot->session);
01344            if (crv != CKR_OK) {
01345                PORT_SetError(PK11_MapError(crv));
01346               slot->session = CK_INVALID_SESSION;
01347               if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01348               return SECFailure;
01349            }
01350        }
01351        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01352     }
01353 
01354     nssToken_Refresh(slot->nssToken);
01355 
01356     if (!(slot->needLogin)) {
01357        return pk11_CheckVerifyTest(slot);
01358     }
01359 
01360 
01361     if (!(slot->isInternal) && (slot->hasRandom)) {
01362        /* if this slot has a random number generater, use it to add entropy
01363         * to the internal slot. */
01364        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
01365 
01366        if (int_slot) {
01367            unsigned char random_bytes[32];
01368 
01369            /* if this slot can issue random numbers, get some entropy from
01370             * that random number generater and give it to our internal token.
01371             */
01372            PK11_EnterSlotMonitor(slot);
01373            crv = PK11_GETTAB(slot)->C_GenerateRandom
01374                      (slot->session,random_bytes, sizeof(random_bytes));
01375            PK11_ExitSlotMonitor(slot);
01376            if (crv == CKR_OK) {
01377                PK11_EnterSlotMonitor(int_slot);
01378               PK11_GETTAB(int_slot)->C_SeedRandom(int_slot->session,
01379                                    random_bytes, sizeof(random_bytes));
01380                PK11_ExitSlotMonitor(int_slot);
01381            }
01382 
01383            /* Now return the favor and send entropy to the token's random 
01384             * number generater */
01385            PK11_EnterSlotMonitor(int_slot);
01386            crv = PK11_GETTAB(int_slot)->C_GenerateRandom(int_slot->session,
01387                                    random_bytes, sizeof(random_bytes));
01388            PK11_ExitSlotMonitor(int_slot);
01389            if (crv == CKR_OK) {
01390                PK11_EnterSlotMonitor(slot);
01391               PK11_GETTAB(slot)->C_SeedRandom(slot->session,
01392                                    random_bytes, sizeof(random_bytes));
01393                PK11_ExitSlotMonitor(slot);
01394            }
01395            PK11_FreeSlot(int_slot);
01396        }
01397     }
01398 
01399        
01400     return SECSuccess;
01401 }
01402 
01403 /*
01404  * initialize a new token
01405  * unlike initialize slot, this can be called multiple times in the lifetime
01406  * of NSS. It reads the information associated with a card or token,
01407  * that is not going to change unless the card or token changes.
01408  */
01409 SECStatus
01410 PK11_TokenRefresh(PK11SlotInfo *slot)
01411 {
01412     CK_TOKEN_INFO tokenInfo;
01413     CK_RV crv;
01414 
01415     /* set the slot flags to the current token values */
01416     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01417     crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
01418     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01419     if (crv != CKR_OK) {
01420        PORT_SetError(PK11_MapError(crv));
01421        return SECFailure;
01422     }
01423 
01424     slot->flags = tokenInfo.flags;
01425     slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ? 
01426                                                  PR_TRUE : PR_FALSE);
01427     slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ? 
01428                                                  PR_TRUE : PR_FALSE);
01429     slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
01430     slot->protectedAuthPath =
01431               ((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) 
01432                                                  ? PR_TRUE : PR_FALSE);
01433     /* on some platforms Active Card incorrectly sets the 
01434      * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
01435     if (slot->isActiveCard) {
01436        slot->protectedAuthPath = PR_FALSE;
01437     }
01438     return SECSuccess;
01439 }
01440 
01441 static PRBool
01442 pk11_isRootSlot(PK11SlotInfo *slot) 
01443 {
01444     CK_ATTRIBUTE findTemp[1];
01445     CK_ATTRIBUTE *attrs;
01446     CK_OBJECT_CLASS oclass = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
01447     int tsize;
01448     CK_OBJECT_HANDLE handle;
01449 
01450     attrs = findTemp;
01451     PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass)); attrs++;
01452     tsize = attrs - findTemp;
01453     PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
01454 
01455     handle = pk11_FindObjectByTemplate(slot,findTemp,tsize);
01456     if (handle == CK_INVALID_HANDLE) {
01457        return PR_FALSE;
01458     }
01459     return PR_TRUE;
01460 }
01461 
01462 /*
01463  * Initialize the slot :
01464  * This initialization code is called on each slot a module supports when
01465  * it is loaded. It does the bringup initialization. The difference between
01466  * this and InitToken is Init slot does those one time initialization stuff,
01467  * usually associated with the reader, while InitToken may get called multiple
01468  * times as tokens are removed and re-inserted.
01469  */
01470 void
01471 PK11_InitSlot(SECMODModule *mod,CK_SLOT_ID slotID,PK11SlotInfo *slot)
01472 {
01473     SECStatus rv;
01474     char *tmp;
01475     CK_SLOT_INFO slotInfo;
01476 
01477     slot->functionList = mod->functionList;
01478     slot->isInternal = mod->internal;
01479     slot->slotID = slotID;
01480     slot->isThreadSafe = mod->isThreadSafe;
01481     slot->hasRSAInfo = PR_FALSE;
01482     
01483     if (PK11_GETTAB(slot)->C_GetSlotInfo(slotID,&slotInfo) != CKR_OK) {
01484        slot->disabled = PR_TRUE;
01485        slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
01486        return;
01487     }
01488 
01489     /* test to make sure claimed mechanism work */
01490     slot->needTest = mod->internal ? PR_FALSE : PR_TRUE;
01491     slot->module = mod; /* NOTE: we don't make a reference here because
01492                       * modules have references to their slots. This
01493                       * works because modules keep implicit references
01494                       * from their slots, and won't unload and disappear
01495                       * until all their slots have been freed */
01496     tmp = PK11_MakeString(NULL,slot->slot_name,
01497         (char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
01498     slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT);
01499 #define ACTIVE_CARD "ActivCard SA"
01500     slot->isActiveCard = (PRBool)(PORT_Strncmp((char *)slotInfo.manufacturerID,
01501                             ACTIVE_CARD, sizeof(ACTIVE_CARD)-1) == 0);
01502     if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == 0) {
01503        slot->isPerm = PR_TRUE;
01504        /* permanment slots must have the token present always */
01505        if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
01506            slot->disabled = PR_TRUE;
01507            slot->reason = PK11_DIS_TOKEN_NOT_PRESENT;
01508            return; /* nothing else to do */
01509        }
01510     }
01511     /* if the token is present, initialize it */
01512     if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
01513        rv = PK11_InitToken(slot,PR_TRUE);
01514        /* the only hard failures are on permanent devices, or function
01515         * verify failures... function verify failures are already handled
01516         * by tokenInit */
01517        if ((rv != SECSuccess) && (slot->isPerm) && (!slot->disabled)) {
01518            slot->disabled = PR_TRUE;
01519            slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
01520        }
01521     }
01522     if (pk11_isRootSlot(slot)) {
01523        if (!slot->hasRootCerts) {
01524            slot->module->trustOrder = 100;
01525        }
01526        slot->hasRootCerts= PR_TRUE;
01527     }
01528 }
01529 
01530        
01531 
01532 /*********************************************************************
01533  *            Slot mapping utility functions.
01534  *********************************************************************/
01535 
01536 /*
01537  * determine if the token is present. If the token is present, make sure
01538  * we have a valid session handle. Also set the value of needLogin 
01539  * appropriately.
01540  */
01541 static PRBool
01542 pk11_IsPresentCertLoad(PK11SlotInfo *slot, PRBool loadCerts)
01543 {
01544     CK_SLOT_INFO slotInfo;
01545     CK_SESSION_INFO sessionInfo;
01546     CK_RV crv;
01547 
01548     /* disabled slots are never present */
01549     if (slot->disabled) {
01550        return PR_FALSE;
01551     }
01552 
01553     /* permanent slots are always present */
01554     if (slot->isPerm && (slot->session != CK_INVALID_SESSION)) {
01555        return PR_TRUE;
01556     }
01557 
01558     if (slot->nssToken) {
01559        return nssToken_IsPresent(slot->nssToken);
01560     }
01561 
01562     /* removable slots have a flag that says they are present */
01563     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01564     if (PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,&slotInfo) != CKR_OK) {
01565         if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01566        return PR_FALSE;
01567     }
01568     if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
01569        /* if the slot is no longer present, close the session */
01570        if (slot->session != CK_INVALID_SESSION) {
01571            PK11_GETTAB(slot)->C_CloseSession(slot->session);
01572            slot->session = CK_INVALID_SESSION;
01573        }
01574         if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01575        return PR_FALSE;
01576     }
01577 
01578     /* use the session Info to determine if the card has been removed and then
01579      * re-inserted */
01580     if (slot->session != CK_INVALID_SESSION) {
01581        if (slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01582        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
01583        if (crv != CKR_OK) {
01584            PK11_GETTAB(slot)->C_CloseSession(slot->session);
01585            slot->session = CK_INVALID_SESSION;
01586        }
01587         if (slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01588     }
01589     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01590 
01591     /* card has not been removed, current token info is correct */
01592     if (slot->session != CK_INVALID_SESSION) return PR_TRUE;
01593 
01594     /* initialize the token info state */
01595     if (PK11_InitToken(slot,loadCerts) != SECSuccess) {
01596        return PR_FALSE;
01597     }
01598 
01599     return PR_TRUE;
01600 }
01601 
01602 /*
01603  * old version of the routine
01604  */
01605 PRBool
01606 PK11_IsPresent(PK11SlotInfo *slot) {
01607    return pk11_IsPresentCertLoad(slot,PR_TRUE);
01608 }
01609 
01610 /* is the slot disabled? */
01611 PRBool
01612 PK11_IsDisabled(PK11SlotInfo *slot)
01613 {
01614     return slot->disabled;
01615 }
01616 
01617 /* and why? */
01618 PK11DisableReasons
01619 PK11_GetDisabledReason(PK11SlotInfo *slot)
01620 {
01621     return slot->reason;
01622 }
01623 
01624 /* returns PR_TRUE if successfully disable the slot */
01625 /* returns PR_FALSE otherwise */
01626 PRBool PK11_UserDisableSlot(PK11SlotInfo *slot) {
01627 
01628     slot->defaultFlags |= PK11_DISABLE_FLAG;
01629     slot->disabled = PR_TRUE;
01630     slot->reason = PK11_DIS_USER_SELECTED;
01631     
01632     return PR_TRUE;
01633 }
01634 
01635 PRBool PK11_UserEnableSlot(PK11SlotInfo *slot) {
01636 
01637     slot->defaultFlags &= ~PK11_DISABLE_FLAG;
01638     slot->disabled = PR_FALSE;
01639     slot->reason = PK11_DIS_NONE;
01640     return PR_TRUE;
01641 }
01642 
01643 PRBool PK11_HasRootCerts(PK11SlotInfo *slot) {
01644     return slot->hasRootCerts;
01645 }
01646 
01647 /* Get the module this slot is attached to */
01648 SECMODModule *
01649 PK11_GetModule(PK11SlotInfo *slot)
01650 {
01651        return slot->module;
01652 }
01653 
01654 /* return the default flags of a slot */
01655 unsigned long
01656 PK11_GetDefaultFlags(PK11SlotInfo *slot)
01657 {
01658        return slot->defaultFlags;
01659 }
01660 
01661 /*
01662  * The following wrapper functions allow us to export an opaque slot
01663  * function to the rest of libsec and the world... */
01664 PRBool
01665 PK11_IsReadOnly(PK11SlotInfo *slot)
01666 {
01667     return slot->readOnly;
01668 }
01669 
01670 PRBool
01671 PK11_IsHW(PK11SlotInfo *slot)
01672 {
01673     return slot->isHW;
01674 }
01675 
01676 PRBool
01677 PK11_IsInternal(PK11SlotInfo *slot)
01678 {
01679     return slot->isInternal;
01680 }
01681 
01682 PRBool
01683 PK11_NeedLogin(PK11SlotInfo *slot)
01684 {
01685     return slot->needLogin;
01686 }
01687 
01688 PRBool
01689 PK11_IsFriendly(PK11SlotInfo *slot)
01690 {
01691     /* internal slot always has public readable certs */
01692     return (PRBool)(slot->isInternal || 
01693                   ((slot->defaultFlags & SECMOD_FRIENDLY_FLAG) == 
01694                    SECMOD_FRIENDLY_FLAG));
01695 }
01696 
01697 char *
01698 PK11_GetTokenName(PK11SlotInfo *slot)
01699 {
01700      return slot->token_name;
01701 }
01702 
01703 char *
01704 PK11_GetSlotName(PK11SlotInfo *slot)
01705 {
01706      return slot->slot_name;
01707 }
01708 
01709 int
01710 PK11_GetSlotSeries(PK11SlotInfo *slot)
01711 {
01712     return slot->series;
01713 }
01714 
01715 int
01716 PK11_GetCurrentWrapIndex(PK11SlotInfo *slot)
01717 {
01718     return slot->wrapKey;
01719 }
01720 
01721 CK_SLOT_ID
01722 PK11_GetSlotID(PK11SlotInfo *slot)
01723 {
01724     return slot->slotID;
01725 }
01726 
01727 SECMODModuleID
01728 PK11_GetModuleID(PK11SlotInfo *slot)
01729 {
01730     return slot->module->moduleID;
01731 }
01732 
01733 static void
01734 pk11_zeroTerminatedToBlankPadded(CK_CHAR *buffer, size_t buffer_size)
01735 {
01736     CK_CHAR *walk = buffer;
01737     CK_CHAR *end = buffer + buffer_size;
01738 
01739     /* find the NULL */
01740     while (walk < end && *walk != '\0') {
01741        walk++;
01742     }
01743 
01744     /* clear out the buffer */
01745     while (walk < end) {
01746        *walk++ = ' ';
01747     }
01748 }
01749 
01750 /* return the slot info structure */
01751 SECStatus
01752 PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info)
01753 {
01754     CK_RV crv;
01755 
01756     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01757     /*
01758      * some buggy drivers do not fill the buffer completely, 
01759      * erase the buffer first
01760      */
01761     PORT_Memset(info->slotDescription,' ',sizeof(info->slotDescription));
01762     PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
01763     crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,info);
01764     pk11_zeroTerminatedToBlankPadded(info->slotDescription,
01765                                    sizeof(info->slotDescription));
01766     pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
01767                                    sizeof(info->manufacturerID));
01768     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01769     if (crv != CKR_OK) {
01770        PORT_SetError(PK11_MapError(crv));
01771        return SECFailure;
01772     }
01773     return SECSuccess;
01774 }
01775 
01776 /*  return the token info structure */
01777 SECStatus
01778 PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info)
01779 {
01780     CK_RV crv;
01781     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01782     /*
01783      * some buggy drivers do not fill the buffer completely, 
01784      * erase the buffer first
01785      */
01786     PORT_Memset(info->label,' ',sizeof(info->label));
01787     PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
01788     PORT_Memset(info->model,' ',sizeof(info->model));
01789     PORT_Memset(info->serialNumber,' ',sizeof(info->serialNumber));
01790     crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,info);
01791     pk11_zeroTerminatedToBlankPadded(info->label,sizeof(info->label));
01792     pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
01793                                    sizeof(info->manufacturerID));
01794     pk11_zeroTerminatedToBlankPadded(info->model,sizeof(info->model));
01795     pk11_zeroTerminatedToBlankPadded(info->serialNumber,
01796                                    sizeof(info->serialNumber));
01797     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01798     if (crv != CKR_OK) {
01799        PORT_SetError(PK11_MapError(crv));
01800        return SECFailure;
01801     }
01802     return SECSuccess;
01803 }
01804 
01805 /* Find out if we need to initialize the user's pin */
01806 PRBool
01807 PK11_NeedUserInit(PK11SlotInfo *slot)
01808 {
01809     PRBool needUserInit = (PRBool) ((slot->flags & CKF_USER_PIN_INITIALIZED) 
01810                                    == 0);
01811 
01812     if (needUserInit) {
01813        CK_TOKEN_INFO info;
01814        SECStatus rv;
01815 
01816        /* see if token has been initialized off line */
01817        rv = PK11_GetTokenInfo(slot, &info);
01818        if (rv == SECSuccess) {
01819            slot->flags = info.flags;
01820        }
01821     }
01822     return (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
01823 }
01824 
01825 /* get the internal key slot. FIPS has only one slot for both key slots and
01826  * default slots */
01827 PK11SlotInfo *
01828 PK11_GetInternalKeySlot(void)
01829 {
01830     SECMODModule *mod = SECMOD_GetInternalModule();
01831     PORT_Assert(mod != NULL);
01832     if (!mod) {
01833        PORT_SetError( SEC_ERROR_NO_MODULE );
01834        return NULL;
01835     }
01836     return PK11_ReferenceSlot(mod->isFIPS ? mod->slots[0] : mod->slots[1]);
01837 }
01838 
01839 /* get the internal default slot */
01840 PK11SlotInfo *
01841 PK11_GetInternalSlot(void) 
01842 {
01843     SECMODModule * mod = SECMOD_GetInternalModule();
01844     PORT_Assert(mod != NULL);
01845     if (!mod) {
01846        PORT_SetError( SEC_ERROR_NO_MODULE );
01847        return NULL;
01848     }
01849     return PK11_ReferenceSlot(mod->slots[0]);
01850 }
01851 
01852 /*
01853  * check if a given slot supports the requested mechanism
01854  */
01855 PRBool
01856 PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type)
01857 {
01858     int i;
01859 
01860     /* CKM_FAKE_RANDOM is not a real PKCS mechanism. It's a marker to
01861      * tell us we're looking form someone that has implemented get
01862      * random bits */
01863     if (type == CKM_FAKE_RANDOM) {
01864        return slot->hasRandom;
01865     }
01866 
01867     /* for most mechanism, bypass the linear lookup */
01868     if (type < 0x7ff) {
01869        return (slot->mechanismBits[type & 0xff] & (1 << (type >> 8)))  ?
01870               PR_TRUE : PR_FALSE;
01871     }
01872           
01873     for (i=0; i < (int) slot->mechanismCount; i++) {
01874        if (slot->mechanismList[i] == type) return PR_TRUE;
01875     }
01876     return PR_FALSE;
01877 }
01878 
01879 /*
01880  * Return true if a token that can do the desired mechanism exists.
01881  * This allows us to have hardware tokens that can do function XYZ magically
01882  * allow SSL Ciphers to appear if they are plugged in.
01883  */
01884 PRBool
01885 PK11_TokenExists(CK_MECHANISM_TYPE type)
01886 {
01887     SECMODModuleList *mlp;
01888     SECMODModuleList *modules = SECMOD_GetDefaultModuleList();
01889     SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
01890     PK11SlotInfo *slot;
01891     PRBool found = PR_FALSE;
01892     int i;
01893 
01894     /* we only need to know if there is a token that does this mechanism.
01895      * check the internal module first because it's fast, and supports 
01896      * almost everything. */
01897     slot = PK11_GetInternalSlot();
01898     if (slot) {
01899        found = PK11_DoesMechanism(slot,type);
01900        PK11_FreeSlot(slot);
01901     }
01902     if (found) return PR_TRUE; /* bypass getting module locks */
01903 
01904     SECMOD_GetReadLock(moduleLock);
01905     for(mlp = modules; mlp != NULL && (!found); mlp = mlp->next) {
01906        for (i=0; i < mlp->module->slotCount; i++) {
01907            slot = mlp->module->slots[i];
01908            if (PK11_IsPresent(slot)) {
01909               if (PK11_DoesMechanism(slot,type)) {
01910                   found = PR_TRUE;
01911                   break;
01912               }
01913            }
01914        }
01915     }
01916     SECMOD_ReleaseReadLock(moduleLock);
01917     return found;
01918 }
01919 
01920 /*
01921  * get all the currently available tokens in a list.
01922  * that can perform the given mechanism. If mechanism is CKM_INVALID_MECHANISM,
01923  * get all the tokens. Make sure tokens that need authentication are put at
01924  * the end of this list.
01925  */
01926 PK11SlotList *
01927 PK11_GetAllTokens(CK_MECHANISM_TYPE type, PRBool needRW, PRBool loadCerts, 
01928                   void *wincx)
01929 {
01930     PK11SlotList *     list         = PK11_NewSlotList();
01931     PK11SlotList *     loginList    = PK11_NewSlotList();
01932     PK11SlotList *     friendlyList = PK11_NewSlotList();
01933     SECMODModuleList * mlp;
01934     SECMODModuleList * modules      = SECMOD_GetDefaultModuleList();
01935     SECMODListLock *   moduleLock   = SECMOD_GetDefaultModuleListLock();
01936     int                i;
01937 #if defined( XP_WIN32 ) 
01938     int                j            = 0;
01939     PRInt32            waste[16];
01940 #endif
01941 
01942     if ((list == NULL)  || (loginList == NULL) || (friendlyList == NULL)) {
01943        if (list) PK11_FreeSlotList(list);
01944        if (loginList) PK11_FreeSlotList(loginList);
01945        if (friendlyList) PK11_FreeSlotList(friendlyList);
01946        return NULL;
01947     }
01948 
01949     SECMOD_GetReadLock(moduleLock);
01950     for(mlp = modules; mlp != NULL; mlp = mlp->next) {
01951 
01952 #if defined( XP_WIN32 ) 
01953        /* This is works around some horrible cache/page thrashing problems 
01954        ** on Win32.  Without this, this loop can take up to 6 seconds at 
01955        ** 100% CPU on a Pentium-Pro 200.  The thing this changes is to 
01956        ** increase the size of the stack frame and modify it.  
01957        ** Moving the loop code itself seems to have no effect.
01958        ** Dunno why this combination makes a difference, but it does.
01959        */
01960        waste[ j & 0xf] = j++; 
01961 #endif
01962 
01963        for (i = 0; i < mlp->module->slotCount; i++) {
01964            PK11SlotInfo *slot = mlp->module->slots[i];
01965 
01966            if (pk11_IsPresentCertLoad(slot, loadCerts)) {
01967               if (needRW &&  slot->readOnly) continue;
01968               if ((type == CKM_INVALID_MECHANISM) 
01969                                    || PK11_DoesMechanism(slot, type)) {
01970                   if (pk11_LoginStillRequired(slot,wincx)) {
01971                      if (PK11_IsFriendly(slot)) {
01972                          PK11_AddSlotToList(friendlyList, slot);
01973                      } else {
01974                          PK11_AddSlotToList(loginList, slot);
01975                      }
01976                   } else {
01977                      PK11_AddSlotToList(list, slot);
01978                   }
01979               }
01980            }
01981        }
01982     }
01983     SECMOD_ReleaseReadLock(moduleLock);
01984 
01985     PK11_MoveListToList(list,friendlyList);
01986     PK11_FreeSlotList(friendlyList);
01987     PK11_MoveListToList(list,loginList);
01988     PK11_FreeSlotList(loginList);
01989 
01990     return list;
01991 }
01992 
01993 /*
01994  * NOTE: This routine is working from a private List generated by 
01995  * PK11_GetAllTokens. That is why it does not need to lock.
01996  */
01997 PK11SlotList *
01998 PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type,PRBool needRW,void *wincx)
01999 {
02000     PK11SlotList *list = PK11_GetAllTokens(type,needRW,PR_TRUE,wincx);
02001     PK11SlotListElement *le, *next ;
02002     SECStatus rv;
02003 
02004     if (list == NULL) return list;
02005 
02006     for (le = list->head ; le; le = next) {
02007        next = le->next; /* save the pointer here in case we have to 
02008                        * free the element later */
02009         rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
02010        if (rv != SECSuccess) {
02011            PK11_DeleteSlotFromList(list,le);
02012            continue;
02013        }
02014     }
02015     return list;
02016 }
02017 
02018 
02019 /*
02020  * find the best slot which supports the given
02021  * Mechanism. In normal cases this should grab the first slot on the list
02022  * with no fuss.
02023  */
02024 PK11SlotInfo *
02025 PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int mech_count, void *wincx)
02026 {
02027     PK11SlotList *list = NULL;
02028     PK11SlotListElement *le ;
02029     PK11SlotInfo *slot = NULL;
02030     PRBool freeit = PR_FALSE;
02031     PRBool listNeedLogin = PR_FALSE;
02032     int i;
02033     SECStatus rv;
02034 
02035     list = PK11_GetSlotList(type[0]);
02036 
02037     if ((list == NULL) || (list->head == NULL)) {
02038        /* We need to look up all the tokens for the mechanism */
02039        list = PK11_GetAllTokens(type[0],PR_FALSE,PR_TRUE,wincx);
02040        freeit = PR_TRUE;
02041     }
02042 
02043     /* no one can do it! */
02044     if (list == NULL) {
02045        PORT_SetError(SEC_ERROR_NO_TOKEN);
02046        return NULL;
02047     }
02048 
02049     PORT_SetError(0);
02050 
02051 
02052     listNeedLogin = PR_FALSE;
02053     for (i=0; i < mech_count; i++) {
02054        if ((type[i] != CKM_FAKE_RANDOM) && 
02055            (type[i] != CKM_SHA_1) &&
02056            (type[i] != CKM_SHA256) &&
02057            (type[i] != CKM_SHA384) &&
02058            (type[i] != CKM_SHA512) &&
02059            (type[i] != CKM_MD5) && 
02060            (type[i] != CKM_MD2)) {
02061            listNeedLogin = PR_TRUE;
02062            break;
02063        }
02064     }
02065 
02066     for (le = PK11_GetFirstSafe(list); le;
02067                             le = PK11_GetNextSafe(list,le,PR_TRUE)) {
02068        if (PK11_IsPresent(le->slot)) {
02069            PRBool doExit = PR_FALSE;
02070            for (i=0; i < mech_count; i++) {
02071               if (!PK11_DoesMechanism(le->slot,type[i])) {
02072                   doExit = PR_TRUE;
02073                   break;
02074               }
02075            }
02076            if (doExit) continue;
02077              
02078            if (listNeedLogin && le->slot->needLogin) {
02079               rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
02080               if (rv != SECSuccess) continue;
02081            }
02082            slot = le->slot;
02083            PK11_ReferenceSlot(slot);
02084            PK11_FreeSlotListElement(list,le);
02085            if (freeit) { PK11_FreeSlotList(list); }
02086            return slot;
02087        }
02088     }
02089     if (freeit) { PK11_FreeSlotList(list); }
02090     if (PORT_GetError() == 0) {
02091        PORT_SetError(SEC_ERROR_NO_TOKEN);
02092     }
02093     return NULL;
02094 }
02095 
02096 /* original get best slot now calls the multiple version with only one type */
02097 PK11SlotInfo *
02098 PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
02099 {
02100     return PK11_GetBestSlotMultiple(&type, 1, wincx);
02101 }
02102 
02103 int
02104 PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism)
02105 {
02106     CK_MECHANISM_INFO mechanism_info;
02107     CK_RV crv;
02108 
02109     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
02110     crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
02111                                mechanism,&mechanism_info);
02112     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
02113     if (crv != CKR_OK) return 0;
02114 
02115     if (mechanism_info.ulMinKeySize == mechanism_info.ulMaxKeySize) 
02116               return 0;
02117     return mechanism_info.ulMaxKeySize;
02118 }
02119 
02120 SECStatus
02121 PK11_SeedRandom(PK11SlotInfo *slot, unsigned char *data, int len) {
02122     CK_RV crv;
02123 
02124     PK11_EnterSlotMonitor(slot);
02125     crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session, data, (CK_ULONG)len);
02126     PK11_ExitSlotMonitor(slot);
02127     if (crv != CKR_OK) {
02128        PORT_SetError(PK11_MapError(crv));
02129        return SECFailure;
02130     }
02131     return SECSuccess;
02132 }
02133 
02134 
02135 SECStatus
02136 PK11_GenerateRandomOnSlot(PK11SlotInfo *slot, unsigned char *data, int len) {
02137     CK_RV crv;
02138 
02139     if (!slot->isInternal) PK11_EnterSlotMonitor(slot);
02140     crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session,data, 
02141                                                  (CK_ULONG)len);
02142     if (!slot->isInternal) PK11_ExitSlotMonitor(slot);
02143     if (crv != CKR_OK) {
02144        PORT_SetError(PK11_MapError(crv));
02145        return  SECFailure;
02146     }
02147     return SECSuccess;
02148 }
02149 
02150 /* Attempts to update the Best Slot for "FAKE RANDOM" generation.
02151 ** If that's not the internal slot, then it also attempts to update the
02152 ** internal slot.
02153 ** The return value indicates if the INTERNAL slot was updated OK.
02154 */
02155 SECStatus
02156 PK11_RandomUpdate(void *data, size_t bytes)
02157 {
02158     PK11SlotInfo *slot;
02159     PRBool        bestIsInternal;
02160     SECStatus     status;
02161 
02162     slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
02163     if (slot == NULL) {
02164        slot = PK11_GetInternalSlot();
02165        if (!slot)
02166            return SECFailure;
02167     }
02168 
02169     bestIsInternal = PK11_IsInternal(slot);
02170     status = PK11_SeedRandom(slot, data, bytes);
02171     PK11_FreeSlot(slot);
02172 
02173     if (!bestIsInternal) {
02174        /* do internal slot, too. */
02175        slot = PK11_GetInternalSlot();     /* can't fail */
02176        status = PK11_SeedRandom(slot, data, bytes);
02177        PK11_FreeSlot(slot);
02178     }
02179     return status;
02180 }
02181 
02182 
02183 SECStatus
02184 PK11_GenerateRandom(unsigned char *data,int len) {
02185     PK11SlotInfo *slot;
02186     SECStatus rv;
02187 
02188     slot = PK11_GetBestSlot(CKM_FAKE_RANDOM,NULL);
02189     if (slot == NULL) return SECFailure;
02190 
02191     rv = PK11_GenerateRandomOnSlot(slot, data, len);
02192     PK11_FreeSlot(slot);
02193     return rv;
02194 }
02195 
02196 /*
02197  * Reset the token to it's initial state. For the internal module, this will
02198  * Purge your keydb, and reset your cert db certs to USER_INIT.
02199  */
02200 SECStatus 
02201 PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd)
02202 {
02203     unsigned char tokenName[32];
02204     int tokenNameLen;
02205     CK_RV crv;
02206 
02207     /* reconstruct the token name */
02208     tokenNameLen = PORT_Strlen(slot->token_name);
02209     if (tokenNameLen > sizeof(tokenName)) {
02210        tokenNameLen = sizeof(tokenName);
02211     }
02212 
02213     PORT_Memcpy(tokenName,slot->token_name,tokenNameLen);
02214     if (tokenNameLen < sizeof(tokenName)) {
02215        PORT_Memset(&tokenName[tokenNameLen],' ',
02216                                     sizeof(tokenName)-tokenNameLen);
02217     }
02218 
02219     /* initialize the token */    
02220     PK11_EnterSlotMonitor(slot);
02221 
02222     /* first shutdown the token. Existing sessions will get closed here */
02223     PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
02224     slot->session = CK_INVALID_SESSION;
02225 
02226     /* now re-init the token */ 
02227     crv = PK11_GETTAB(slot)->C_InitToken(slot->slotID,
02228        (unsigned char *)sso_pwd, sso_pwd ? PORT_Strlen(sso_pwd): 0, tokenName);
02229 
02230     /* finally bring the token back up */
02231     PK11_InitToken(slot,PR_TRUE);
02232     PK11_ExitSlotMonitor(slot);
02233     if (crv != CKR_OK) {
02234        PORT_SetError(PK11_MapError(crv));
02235        return SECFailure;
02236     }
02237     nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
02238                                              slot->nssToken);
02239     return SECSuccess;
02240 }
02241 void
02242 PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst) 
02243 {
02244     sl->nssToken = nsst;
02245 }
02246 
02247 NSSToken *
02248 PK11Slot_GetNSSToken(PK11SlotInfo *sl) 
02249 {
02250     return sl->nssToken;
02251 }
02252 
02253 /*
02254  * wait for a token to change it's state. The application passes in the expected
02255  * new state in event. 
02256  */
02257 PK11TokenStatus
02258 PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event, 
02259        PRIntervalTime timeout, PRIntervalTime latency, int series)
02260 {
02261    PRIntervalTime first_time = 0;
02262    PRBool first_time_set = PR_FALSE;
02263    PRBool waitForRemoval;
02264 
02265    if (slot->isPerm) {
02266        return PK11TokenNotRemovable;
02267    }
02268    if (latency == 0) {
02269        latency = PR_SecondsToInterval(5);
02270    }
02271    waitForRemoval = (PRBool) (event == PK11TokenRemovedOrChangedEvent);
02272 
02273    if (series == 0) {
02274        series = PK11_GetSlotSeries(slot);
02275    }
02276    while (PK11_IsPresent(slot) == waitForRemoval ) {
02277        PRIntervalTime interval;
02278 
02279        if (waitForRemoval && series != PK11_GetSlotSeries(slot)) {
02280            return PK11TokenChanged;
02281        }
02282        if (timeout == PR_INTERVAL_NO_WAIT) {
02283            return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
02284        }
02285        if (timeout != PR_INTERVAL_NO_TIMEOUT ) {
02286            interval = PR_IntervalNow();
02287            if (!first_time_set) {
02288               first_time = interval;
02289               first_time_set = PR_TRUE;
02290            }
02291            if ((interval-first_time) > timeout) {
02292               return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
02293            }
02294        }
02295        PR_Sleep(latency);
02296    }
02297    return waitForRemoval ? PK11TokenRemoved : PK11TokenPresent;
02298 }