Back to index

lightning-sunbird  0.9+nobinonly
devutil.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  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: devutil.c,v $ $Revision: 1.26 $ $Date: 2005/01/20 02:25:47 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef DEVM_H
00042 #include "devm.h"
00043 #endif /* DEVM_H */
00044 
00045 #ifndef CKHELPER_H
00046 #include "ckhelper.h"
00047 #endif /* CKHELPER_H */
00048 
00049 NSS_IMPLEMENT nssCryptokiObject *
00050 nssCryptokiObject_Create (
00051   NSSToken *t, 
00052   nssSession *session,
00053   CK_OBJECT_HANDLE h
00054 )
00055 {
00056     PRStatus status;
00057     NSSSlot *slot;
00058     nssCryptokiObject *object;
00059     CK_BBOOL *isTokenObject;
00060     CK_ATTRIBUTE cert_template[] = {
00061        { CKA_TOKEN, NULL, 0 },
00062        { CKA_LABEL, NULL, 0 }
00063     };
00064     slot = nssToken_GetSlot(t);
00065     status = nssCKObject_GetAttributes(h, cert_template, 2,
00066                                        NULL, session, slot);
00067     nssSlot_Destroy(slot);
00068     if (status != PR_SUCCESS) {
00069        /* a failure here indicates a device error */
00070        return (nssCryptokiObject *)NULL;
00071     }
00072     object = nss_ZNEW(NULL, nssCryptokiObject);
00073     if (!object) {
00074        return (nssCryptokiObject *)NULL;
00075     }
00076     object->handle = h;
00077     object->token = nssToken_AddRef(t);
00078     isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
00079     object->isTokenObject = *isTokenObject;
00080     nss_ZFreeIf(isTokenObject);
00081     NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
00082     return object;
00083 }
00084 
00085 NSS_IMPLEMENT void
00086 nssCryptokiObject_Destroy (
00087   nssCryptokiObject *object
00088 )
00089 {
00090     if (object) {
00091        nssToken_Destroy(object->token);
00092        nss_ZFreeIf(object->label);
00093        nss_ZFreeIf(object);
00094     }
00095 }
00096 
00097 NSS_IMPLEMENT nssCryptokiObject *
00098 nssCryptokiObject_Clone (
00099   nssCryptokiObject *object
00100 )
00101 {
00102     nssCryptokiObject *rvObject;
00103     rvObject = nss_ZNEW(NULL, nssCryptokiObject);
00104     if (rvObject) {
00105        rvObject->handle = object->handle;
00106        rvObject->token = nssToken_AddRef(object->token);
00107        rvObject->isTokenObject = object->isTokenObject;
00108        if (object->label) {
00109            rvObject->label = nssUTF8_Duplicate(object->label, NULL);
00110        }
00111     }
00112     return rvObject;
00113 }
00114 
00115 NSS_EXTERN PRBool
00116 nssCryptokiObject_Equal (
00117   nssCryptokiObject *o1,
00118   nssCryptokiObject *o2
00119 )
00120 {
00121     return (o1->token == o2->token && o1->handle == o2->handle);
00122 }
00123 
00124 NSS_IMPLEMENT PRUint32
00125 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
00126 {
00127     PRInt32 i;
00128     for (i = bufLen - 1; i>=0; ) {
00129        if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') break;
00130        --i;
00131     }
00132     return (PRUint32)(i + 1);
00133 }
00134 
00135 /*
00136  * Slot arrays
00137  */
00138 
00139 NSS_IMPLEMENT NSSSlot **
00140 nssSlotArray_Clone (
00141   NSSSlot **slots
00142 )
00143 {
00144     NSSSlot **rvSlots = NULL;
00145     NSSSlot **sp = slots;
00146     PRUint32 count = 0;
00147     while (sp && *sp) count++;
00148     if (count > 0) {
00149        rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
00150        if (rvSlots) {
00151            sp = slots;
00152            count = 0;
00153            for (sp = slots; *sp; sp++) {
00154               rvSlots[count++] = nssSlot_AddRef(*sp);
00155            }
00156        }
00157     }
00158     return rvSlots;
00159 }
00160 
00161 #ifdef PURE_STAN_BUILD
00162 NSS_IMPLEMENT void
00163 nssModuleArray_Destroy (
00164   NSSModule **modules
00165 )
00166 {
00167     if (modules) {
00168        NSSModule **mp;
00169        for (mp = modules; *mp; mp++) {
00170            nssModule_Destroy(*mp);
00171        }
00172        nss_ZFreeIf(modules);
00173     }
00174 }
00175 #endif
00176 
00177 NSS_IMPLEMENT void
00178 nssSlotArray_Destroy (
00179   NSSSlot **slots
00180 )
00181 {
00182     if (slots) {
00183        NSSSlot **slotp;
00184        for (slotp = slots; *slotp; slotp++) {
00185            nssSlot_Destroy(*slotp);
00186        }
00187        nss_ZFreeIf(slots);
00188     }
00189 }
00190 
00191 NSS_IMPLEMENT void
00192 NSSSlotArray_Destroy (
00193   NSSSlot **slots
00194 )
00195 {
00196     nssSlotArray_Destroy(slots);
00197 }
00198 
00199 NSS_IMPLEMENT void
00200 nssTokenArray_Destroy (
00201   NSSToken **tokens
00202 )
00203 {
00204     if (tokens) {
00205        NSSToken **tokenp;
00206        for (tokenp = tokens; *tokenp; tokenp++) {
00207            nssToken_Destroy(*tokenp);
00208        }
00209        nss_ZFreeIf(tokens);
00210     }
00211 }
00212 
00213 NSS_IMPLEMENT void
00214 NSSTokenArray_Destroy (
00215   NSSToken **tokens
00216 )
00217 {
00218     nssTokenArray_Destroy(tokens);
00219 }
00220 
00221 NSS_IMPLEMENT void
00222 nssCryptokiObjectArray_Destroy (
00223   nssCryptokiObject **objects
00224 )
00225 {
00226     if (objects) {
00227        nssCryptokiObject **op;
00228        for (op = objects; *op; op++) {
00229            nssCryptokiObject_Destroy(*op);
00230        }
00231        nss_ZFreeIf(objects);
00232     }
00233 }
00234 
00235 #ifdef PURE_STAN_BUILD
00236 /*
00237  * Slot lists
00238  */
00239 
00240 struct nssSlotListNodeStr
00241 {
00242   PRCList link;
00243   NSSSlot *slot;
00244   PRUint32 order;
00245 };
00246 
00247 /* XXX separate slots with non-present tokens? */
00248 struct nssSlotListStr 
00249 {
00250   NSSArena *arena;
00251   PRBool i_allocated_arena;
00252   PZLock *lock;
00253   PRCList head;
00254   PRUint32 count;
00255 };
00256 
00257 NSS_IMPLEMENT nssSlotList *
00258 nssSlotList_Create (
00259   NSSArena *arenaOpt
00260 )
00261 {
00262     nssSlotList *rvList;
00263     NSSArena *arena;
00264     nssArenaMark *mark;
00265     if (arenaOpt) {
00266        arena = arenaOpt;
00267        mark = nssArena_Mark(arena);
00268        if (!mark) {
00269            return (nssSlotList *)NULL;
00270        }
00271     } else {
00272        arena = nssArena_Create();
00273        if (!arena) {
00274            return (nssSlotList *)NULL;
00275        }
00276     }
00277     rvList = nss_ZNEW(arena, nssSlotList);
00278     if (!rvList) {
00279        goto loser;
00280     }
00281     rvList->lock = PZ_NewLock(nssILockOther); /* XXX */
00282     if (!rvList->lock) {
00283        goto loser;
00284     }
00285     PR_INIT_CLIST(&rvList->head);
00286     rvList->arena = arena;
00287     rvList->i_allocated_arena = (arenaOpt == NULL);
00288     nssArena_Unmark(arena, mark);
00289     return rvList;
00290 loser:
00291     if (arenaOpt) {
00292        nssArena_Release(arena, mark);
00293     } else {
00294        nssArena_Destroy(arena);
00295     }
00296     return (nssSlotList *)NULL;
00297 }
00298 
00299 NSS_IMPLEMENT void
00300 nssSlotList_Destroy (
00301   nssSlotList *slotList
00302 )
00303 {
00304     PRCList *link;
00305     struct nssSlotListNodeStr *node;
00306     if (slotList) {
00307        link = PR_NEXT_LINK(&slotList->head);
00308        while (link != &slotList->head) {
00309            node = (struct nssSlotListNodeStr *)link;
00310            nssSlot_Destroy(node->slot);
00311            link = PR_NEXT_LINK(link);
00312        }
00313        if (slotList->i_allocated_arena) {
00314            nssArena_Destroy(slotList->arena);
00315        }
00316     }
00317 }
00318 
00319 /* XXX should do allocs outside of lock */
00320 NSS_IMPLEMENT PRStatus
00321 nssSlotList_Add (
00322   nssSlotList *slotList,
00323   NSSSlot *slot,
00324   PRUint32 order
00325 )
00326 {
00327     PRCList *link;
00328     struct nssSlotListNodeStr *node;
00329     PZ_Lock(slotList->lock);
00330     link = PR_NEXT_LINK(&slotList->head);
00331     while (link != &slotList->head) {
00332        node = (struct nssSlotListNodeStr *)link;
00333        if (order < node->order) {
00334            break;
00335        }
00336        link = PR_NEXT_LINK(link);
00337     }
00338     node = nss_ZNEW(slotList->arena, struct nssSlotListNodeStr);
00339     if (!node) {
00340        return PR_FAILURE;
00341     }
00342     PR_INIT_CLIST(&node->link);
00343     node->slot = nssSlot_AddRef(slot);
00344     node->order = order;
00345     PR_INSERT_AFTER(&node->link, link);
00346     slotList->count++;
00347     PZ_Unlock(slotList->lock);
00348     return PR_SUCCESS;
00349 }
00350 
00351 NSS_IMPLEMENT PRStatus
00352 nssSlotList_AddModuleSlots (
00353   nssSlotList *slotList,
00354   NSSModule *module,
00355   PRUint32 order
00356 )
00357 {
00358     nssArenaMark *mark = NULL;
00359     NSSSlot **sp, **slots = NULL;
00360     PRCList *link;
00361     struct nssSlotListNodeStr *node;
00362     PZ_Lock(slotList->lock);
00363     link = PR_NEXT_LINK(&slotList->head);
00364     while (link != &slotList->head) {
00365        node = (struct nssSlotListNodeStr *)link;
00366        if (order < node->order) {
00367            break;
00368        }
00369        link = PR_NEXT_LINK(link);
00370     }
00371     slots = nssModule_GetSlots(module);
00372     if (!slots) {
00373        PZ_Unlock(slotList->lock);
00374        return PR_SUCCESS;
00375     }
00376     mark = nssArena_Mark(slotList->arena);
00377     if (!mark) {
00378        goto loser;
00379     }
00380     for (sp = slots; *sp; sp++) {
00381        node = nss_ZNEW(slotList->arena, struct nssSlotListNodeStr);
00382        if (!node) {
00383            goto loser;
00384        }
00385        PR_INIT_CLIST(&node->link);
00386        node->slot = *sp; /* have ref from nssModule_GetSlots */
00387        node->order = order;
00388        PR_INSERT_AFTER(&node->link, link);
00389        slotList->count++;
00390     }
00391     PZ_Unlock(slotList->lock);
00392     nssArena_Unmark(slotList->arena, mark);
00393     return PR_SUCCESS;
00394 loser:
00395     PZ_Unlock(slotList->lock);
00396     if (mark) {
00397        nssArena_Release(slotList->arena, mark);
00398     }
00399     if (slots) {
00400        nssSlotArray_Destroy(slots);
00401     }
00402     return PR_FAILURE;
00403 }
00404 
00405 NSS_IMPLEMENT NSSSlot **
00406 nssSlotList_GetSlots (
00407   nssSlotList *slotList
00408 )
00409 {
00410     PRUint32 i;
00411     PRCList *link;
00412     struct nssSlotListNodeStr *node;
00413     NSSSlot **rvSlots = NULL;
00414     PZ_Lock(slotList->lock);
00415     rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, slotList->count + 1);
00416     if (!rvSlots) {
00417        PZ_Unlock(slotList->lock);
00418        return (NSSSlot **)NULL;
00419     }
00420     i = 0;
00421     link = PR_NEXT_LINK(&slotList->head);
00422     while (link != &slotList->head) {
00423        node = (struct nssSlotListNodeStr *)link;
00424        rvSlots[i] = nssSlot_AddRef(node->slot);
00425        link = PR_NEXT_LINK(link);
00426        i++;
00427     }
00428     PZ_Unlock(slotList->lock);
00429     return rvSlots;
00430 }
00431 
00432 #if 0
00433 NSS_IMPLEMENT NSSSlot *
00434 nssSlotList_GetBestSlotForAlgorithmAndParameters (
00435   nssSlotList *slotList,
00436   NSSAlgorithmAndParameters *ap
00437 )
00438 {
00439     PRCList *link;
00440     struct nssSlotListNodeStr *node;
00441     NSSSlot *rvSlot = NULL;
00442     PZ_Lock(slotList->lock);
00443     link = PR_NEXT_LINK(&slotList->head);
00444     while (link != &slotList->head) {
00445        node = (struct nssSlotListNodeStr *)link;
00446        if (nssSlot_DoesAlgorithmAndParameters(ap)) {
00447            rvSlot = nssSlot_AddRef(node->slot); /* XXX check isPresent? */
00448        }
00449        link = PR_NEXT_LINK(link);
00450     }
00451     PZ_Unlock(slotList->lock);
00452     return rvSlot;
00453 }
00454 #endif
00455 
00456 NSS_IMPLEMENT NSSSlot *
00457 nssSlotList_GetBestSlot (
00458   nssSlotList *slotList
00459 )
00460 {
00461     PRCList *link;
00462     struct nssSlotListNodeStr *node;
00463     NSSSlot *rvSlot = NULL;
00464     PZ_Lock(slotList->lock);
00465     if (PR_CLIST_IS_EMPTY(&slotList->head)) {
00466        PZ_Unlock(slotList->lock);
00467        return (NSSSlot *)NULL;
00468     }
00469     link = PR_NEXT_LINK(&slotList->head);
00470     node = (struct nssSlotListNodeStr *)link;
00471     rvSlot = nssSlot_AddRef(node->slot); /* XXX check isPresent? */
00472     PZ_Unlock(slotList->lock);
00473     return rvSlot;
00474 }
00475 
00476 NSS_IMPLEMENT NSSSlot *
00477 nssSlotList_FindSlotByName (
00478   nssSlotList *slotList,
00479   NSSUTF8 *slotName
00480 )
00481 {
00482     PRCList *link;
00483     struct nssSlotListNodeStr *node;
00484     NSSSlot *rvSlot = NULL;
00485     PZ_Lock(slotList->lock);
00486     link = PR_NEXT_LINK(&slotList->head);
00487     while (link != &slotList->head) {
00488        NSSUTF8 *sName;
00489        node = (struct nssSlotListNodeStr *)link;
00490        sName = nssSlot_GetName(node->slot);
00491        if (nssUTF8_Equal(sName, slotName, NULL)) {
00492            rvSlot = nssSlot_AddRef(node->slot);
00493            break;
00494        }
00495        link = PR_NEXT_LINK(link);
00496     }
00497     PZ_Unlock(slotList->lock);
00498     return rvSlot;
00499 }
00500 
00501 NSS_IMPLEMENT NSSToken *
00502 nssSlotList_FindTokenByName (
00503   nssSlotList *slotList,
00504   NSSUTF8 *tokenName
00505 )
00506 {
00507     PRCList *link;
00508     struct nssSlotListNodeStr *node;
00509     NSSToken *rvToken = NULL;
00510     PZ_Lock(slotList->lock);
00511     link = PR_NEXT_LINK(&slotList->head);
00512     while (link != &slotList->head) {
00513        NSSUTF8 *tName;
00514        node = (struct nssSlotListNodeStr *)link;
00515        tName = nssSlot_GetTokenName(node->slot);
00516        if (nssUTF8_Equal(tName, tokenName, NULL)) {
00517            rvToken = nssSlot_GetToken(node->slot);
00518            break;
00519        }
00520        link = PR_NEXT_LINK(link);
00521     }
00522     PZ_Unlock(slotList->lock);
00523     return rvToken;
00524 }
00525 #endif /* PURE_STAN_BUILD */
00526 
00527 /* object cache for token */
00528 
00529 typedef struct
00530 {
00531   NSSArena *arena;
00532   nssCryptokiObject *object;
00533   CK_ATTRIBUTE_PTR attributes;
00534   CK_ULONG numAttributes;
00535 }
00536 nssCryptokiObjectAndAttributes;
00537 
00538 enum {
00539   cachedCerts = 0,
00540   cachedTrust = 1,
00541   cachedCRLs = 2
00542 } cachedObjectType;
00543 
00544 struct nssTokenObjectCacheStr
00545 {
00546   NSSToken *token;
00547   PZLock *lock;
00548   PRBool loggedIn;
00549   PRBool doObjectType[3];
00550   PRBool searchedObjectType[3];
00551   nssCryptokiObjectAndAttributes **objects[3];
00552 };
00553 
00554 NSS_IMPLEMENT nssTokenObjectCache *
00555 nssTokenObjectCache_Create (
00556   NSSToken *token,
00557   PRBool cacheCerts,
00558   PRBool cacheTrust,
00559   PRBool cacheCRLs
00560 )
00561 {
00562     nssTokenObjectCache *rvCache;
00563     rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
00564     if (!rvCache) {
00565        goto loser;
00566     }
00567     rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
00568     if (!rvCache->lock) {
00569        goto loser;
00570     }
00571     rvCache->doObjectType[cachedCerts] = cacheCerts;
00572     rvCache->doObjectType[cachedTrust] = cacheTrust;
00573     rvCache->doObjectType[cachedCRLs] = cacheCRLs;
00574     rvCache->token = token; /* cache goes away with token */
00575     return rvCache;
00576 loser:
00577     return (nssTokenObjectCache *)NULL;
00578 }
00579 
00580 static void
00581 clear_cache (
00582   nssTokenObjectCache *cache
00583 )
00584 {
00585     nssCryptokiObjectAndAttributes **oa;
00586     PRUint32 objectType;
00587     for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
00588        cache->searchedObjectType[objectType] = PR_FALSE;
00589        if (!cache->objects[objectType]) {
00590            continue;
00591        }
00592        for (oa = cache->objects[objectType]; *oa; oa++) {
00593            /* prevent the token from being destroyed */
00594            (*oa)->object->token = NULL;
00595            nssCryptokiObject_Destroy((*oa)->object);
00596            nssArena_Destroy((*oa)->arena);
00597        }
00598        nss_ZFreeIf(cache->objects[objectType]);
00599        cache->objects[objectType] = NULL;
00600     }
00601 }
00602 
00603 NSS_IMPLEMENT void
00604 nssTokenObjectCache_Clear (
00605   nssTokenObjectCache *cache
00606 )
00607 {
00608     if (cache) {
00609        PZ_Lock(cache->lock);
00610        clear_cache(cache);
00611        PZ_Unlock(cache->lock);
00612     }
00613 }
00614 
00615 NSS_IMPLEMENT void
00616 nssTokenObjectCache_Destroy (
00617   nssTokenObjectCache *cache
00618 )
00619 {
00620     if (cache) {
00621        clear_cache(cache);
00622        PZ_DestroyLock(cache->lock);
00623        nss_ZFreeIf(cache);
00624     }
00625 }
00626 
00627 NSS_IMPLEMENT PRBool
00628 nssTokenObjectCache_HaveObjectClass (
00629   nssTokenObjectCache *cache,
00630   CK_OBJECT_CLASS objclass
00631 )
00632 {
00633     PRBool haveIt;
00634     PZ_Lock(cache->lock);
00635     switch (objclass) {
00636     case CKO_CERTIFICATE:    haveIt = cache->doObjectType[cachedCerts]; break;
00637     case CKO_NETSCAPE_TRUST: haveIt = cache->doObjectType[cachedTrust]; break;
00638     case CKO_NETSCAPE_CRL:   haveIt = cache->doObjectType[cachedCRLs];  break;
00639     default:                 haveIt = PR_FALSE;
00640     }
00641     PZ_Unlock(cache->lock);
00642     return haveIt;
00643 }
00644 
00645 static nssCryptokiObjectAndAttributes **
00646 create_object_array (
00647   nssCryptokiObject **objects,
00648   PRBool *doObjects,
00649   PRUint32 *numObjects,
00650   PRStatus *status
00651 )
00652 {
00653     nssCryptokiObjectAndAttributes **rvOandA = NULL;
00654     *numObjects = 0;
00655     /* There are no objects for this type */
00656     if (!objects || !*objects) {
00657        *status = PR_SUCCESS;
00658        return rvOandA;
00659     }
00660     while (*objects++) (*numObjects)++;
00661     if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
00662        /* Hit the maximum allowed, so don't use a cache (there are
00663         * too many objects to make caching worthwhile, presumably, if
00664         * the token can handle that many objects, it can handle searching.
00665         */
00666        *doObjects = PR_FALSE;
00667        *status = PR_FAILURE;
00668        *numObjects = 0;
00669     } else {
00670        rvOandA = nss_ZNEWARRAY(NULL, 
00671                                nssCryptokiObjectAndAttributes *, 
00672                                *numObjects + 1);
00673        *status = rvOandA ? PR_SUCCESS : PR_FAILURE;
00674     }
00675     return rvOandA;
00676 }
00677 
00678 static nssCryptokiObjectAndAttributes *
00679 create_object (
00680   nssCryptokiObject *object,
00681   const CK_ATTRIBUTE_TYPE *types,
00682   PRUint32 numTypes,
00683   PRStatus *status
00684 )
00685 {
00686     PRUint32 j;
00687     NSSArena *arena;
00688     NSSSlot *slot = NULL;
00689     nssSession *session = NULL;
00690     nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
00691 
00692     slot = nssToken_GetSlot(object->token);
00693     session = nssToken_GetDefaultSession(object->token);
00694 
00695     arena = nssArena_Create();
00696     if (!arena) {
00697        goto loser;
00698     }
00699     rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
00700     if (!rvCachedObject) {
00701        goto loser;
00702     }
00703     rvCachedObject->arena = arena;
00704     /* The cache is tied to the token, and therefore the objects
00705      * in it should not hold references to the token.
00706      */
00707     nssToken_Destroy(object->token);
00708     rvCachedObject->object = object;
00709     rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
00710     if (!rvCachedObject->attributes) {
00711        goto loser;
00712     }
00713     for (j=0; j<numTypes; j++) {
00714        rvCachedObject->attributes[j].type = types[j];
00715     }
00716     *status = nssCKObject_GetAttributes(object->handle,
00717                                         rvCachedObject->attributes,
00718                                         numTypes,
00719                                         arena,
00720                                         session,
00721                                         slot);
00722     if (*status != PR_SUCCESS) {
00723        goto loser;
00724     }
00725     rvCachedObject->numAttributes = numTypes;
00726     *status = PR_SUCCESS;
00727     if (slot) {
00728        nssSlot_Destroy(slot);
00729     }
00730     return rvCachedObject;
00731 loser:
00732     *status = PR_FAILURE;
00733     if (slot) {
00734        nssSlot_Destroy(slot);
00735     }
00736     if (arena)
00737        nssArena_Destroy(arena);
00738     return (nssCryptokiObjectAndAttributes *)NULL;
00739 }
00740 
00741 /*
00742  *
00743  * State diagram for cache:
00744  *
00745  *            token !present            token removed
00746  *        +-------------------------+<----------------------+
00747  *        |                         ^                       |
00748  *        v                         |                       |
00749  *  +----------+   slot friendly    |  token present   +----------+ 
00750  *  |   cache  | -----------------> % ---------------> |   cache  |
00751  *  | unloaded |                                       |  loaded  |
00752  *  +----------+                                       +----------+
00753  *    ^   |                                                 ^   |
00754  *    |   |   slot !friendly           slot logged in       |   |
00755  *    |   +-----------------------> % ----------------------+   |
00756  *    |                             |                           |
00757  *    | slot logged out             v  slot !friendly           |
00758  *    +-----------------------------+<--------------------------+
00759  *
00760  */
00761 
00762 /* This function must not be called with cache->lock locked. */
00763 static PRBool
00764 token_is_present (
00765   nssTokenObjectCache *cache
00766 )
00767 {
00768     NSSSlot *slot = nssToken_GetSlot(cache->token);
00769     PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
00770     nssSlot_Destroy(slot);
00771     return tokenPresent;
00772 }
00773 
00774 static PRBool
00775 search_for_objects (
00776   nssTokenObjectCache *cache
00777 )
00778 {
00779     PRBool doSearch = PR_FALSE;
00780     NSSSlot *slot = nssToken_GetSlot(cache->token);
00781     /* Handle non-friendly slots (slots which require login for objects) */
00782     if (!nssSlot_IsFriendly(slot)) {
00783        if (nssSlot_IsLoggedIn(slot)) {
00784            /* Either no state change, or went from !logged in -> logged in */
00785            cache->loggedIn = PR_TRUE;
00786            doSearch = PR_TRUE;
00787        } else {
00788            if (cache->loggedIn) {
00789               /* went from logged in -> !logged in, destroy cached objects */
00790               clear_cache(cache);
00791               cache->loggedIn = PR_FALSE;
00792            } /* else no state change, still not logged in, so exit */
00793        }
00794     } else {
00795        /* slot is friendly, thus always available for search */
00796        doSearch = PR_TRUE;
00797     }
00798     nssSlot_Destroy(slot);
00799     return doSearch;
00800 }
00801 
00802 static nssCryptokiObjectAndAttributes *
00803 create_cert (
00804   nssCryptokiObject *object,
00805   PRStatus *status
00806 )
00807 {
00808     static const CK_ATTRIBUTE_TYPE certAttr[] = {
00809        CKA_CLASS,
00810        CKA_TOKEN,
00811        CKA_LABEL,
00812        CKA_CERTIFICATE_TYPE,
00813        CKA_ID,
00814        CKA_VALUE,
00815        CKA_ISSUER,
00816        CKA_SERIAL_NUMBER,
00817        CKA_SUBJECT,
00818        CKA_NETSCAPE_EMAIL
00819     };
00820     static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
00821     return create_object(object, certAttr, numCertAttr, status);
00822 }
00823 
00824 static PRStatus
00825 get_token_certs_for_cache (
00826   nssTokenObjectCache *cache
00827 )
00828 {
00829     PRStatus status;
00830     nssCryptokiObject **objects;
00831     PRBool *doIt = &cache->doObjectType[cachedCerts];
00832     PRUint32 i, numObjects;
00833 
00834     if (!search_for_objects(cache) || 
00835          cache->searchedObjectType[cachedCerts] || 
00836         !cache->doObjectType[cachedCerts]) 
00837     {
00838        /* Either there was a state change that prevents a search
00839         * (token logged out), or the search was already done,
00840         * or certs are not being cached.
00841         */
00842        return PR_SUCCESS;
00843     }
00844     objects = nssToken_FindCertificates(cache->token, NULL,
00845                                         nssTokenSearchType_TokenForced,
00846                                     MAX_LOCAL_CACHE_OBJECTS, &status);
00847     if (status != PR_SUCCESS) {
00848        return status;
00849     }
00850     cache->objects[cachedCerts] = create_object_array(objects,
00851                                                       doIt,
00852                                                       &numObjects,
00853                                                       &status);
00854     if (status != PR_SUCCESS) {
00855        return status;
00856     }
00857     for (i=0; i<numObjects; i++) {
00858        cache->objects[cachedCerts][i] = create_cert(objects[i], &status);
00859        if (status != PR_SUCCESS) {
00860            break;
00861        }
00862     }
00863     if (status == PR_SUCCESS) {
00864        nss_ZFreeIf(objects);
00865     } else {
00866        PRUint32 j;
00867        for (j=0; j<i; j++) {
00868            /* sigh */
00869            nssToken_AddRef(cache->objects[cachedCerts][j]->object->token);
00870            nssArena_Destroy(cache->objects[cachedCerts][j]->arena);
00871        }
00872        nssCryptokiObjectArray_Destroy(objects);
00873     }
00874     cache->searchedObjectType[cachedCerts] = PR_TRUE;
00875     return status;
00876 }
00877 
00878 static nssCryptokiObjectAndAttributes *
00879 create_trust (
00880   nssCryptokiObject *object,
00881   PRStatus *status
00882 )
00883 {
00884     static const CK_ATTRIBUTE_TYPE trustAttr[] = {
00885        CKA_CLASS,
00886        CKA_TOKEN,
00887        CKA_LABEL,
00888        CKA_CERT_SHA1_HASH,
00889        CKA_CERT_MD5_HASH,
00890        CKA_ISSUER,
00891        CKA_SUBJECT,
00892        CKA_TRUST_SERVER_AUTH,
00893        CKA_TRUST_CLIENT_AUTH,
00894        CKA_TRUST_EMAIL_PROTECTION,
00895        CKA_TRUST_CODE_SIGNING
00896     };
00897     static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
00898     return create_object(object, trustAttr, numTrustAttr, status);
00899 }
00900 
00901 static PRStatus
00902 get_token_trust_for_cache (
00903   nssTokenObjectCache *cache
00904 )
00905 {
00906     PRStatus status;
00907     nssCryptokiObject **objects;
00908     PRBool *doIt = &cache->doObjectType[cachedTrust];
00909     PRUint32 i, numObjects;
00910 
00911     if (!search_for_objects(cache) || 
00912          cache->searchedObjectType[cachedTrust] || 
00913         !cache->doObjectType[cachedTrust]) 
00914     {
00915        /* Either there was a state change that prevents a search
00916         * (token logged out), or the search was already done,
00917         * or trust is not being cached.
00918         */
00919        return PR_SUCCESS;
00920     }
00921     objects = nssToken_FindTrustObjects(cache->token, NULL,
00922                                         nssTokenSearchType_TokenForced,
00923                                     MAX_LOCAL_CACHE_OBJECTS, &status);
00924     if (status != PR_SUCCESS) {
00925        return status;
00926     }
00927     cache->objects[cachedTrust] = create_object_array(objects,
00928                                                       doIt,
00929                                                       &numObjects,
00930                                                       &status);
00931     if (status != PR_SUCCESS) {
00932        return status;
00933     }
00934     for (i=0; i<numObjects; i++) {
00935        cache->objects[cachedTrust][i] = create_trust(objects[i], &status);
00936        if (status != PR_SUCCESS) {
00937            break;
00938        }
00939     }
00940     if (status == PR_SUCCESS) {
00941        nss_ZFreeIf(objects);
00942     } else {
00943        PRUint32 j;
00944        for (j=0; j<i; j++) {
00945            /* sigh */
00946            nssToken_AddRef(cache->objects[cachedTrust][j]->object->token);
00947            nssArena_Destroy(cache->objects[cachedTrust][j]->arena);
00948        }
00949        nssCryptokiObjectArray_Destroy(objects);
00950     }
00951     cache->searchedObjectType[cachedTrust] = PR_TRUE;
00952     return status;
00953 }
00954 
00955 static nssCryptokiObjectAndAttributes *
00956 create_crl (
00957   nssCryptokiObject *object,
00958   PRStatus *status
00959 )
00960 {
00961     static const CK_ATTRIBUTE_TYPE crlAttr[] = {
00962        CKA_CLASS,
00963        CKA_TOKEN,
00964        CKA_LABEL,
00965        CKA_VALUE,
00966        CKA_SUBJECT,
00967        CKA_NETSCAPE_KRL,
00968        CKA_NETSCAPE_URL
00969     };
00970     static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
00971     return create_object(object, crlAttr, numCRLAttr, status);
00972 }
00973 
00974 static PRStatus
00975 get_token_crls_for_cache (
00976   nssTokenObjectCache *cache
00977 )
00978 {
00979     PRStatus status;
00980     nssCryptokiObject **objects;
00981     PRBool *doIt = &cache->doObjectType[cachedCRLs];
00982     PRUint32 i, numObjects;
00983 
00984     if (!search_for_objects(cache) || 
00985          cache->searchedObjectType[cachedCRLs] || 
00986         !cache->doObjectType[cachedCRLs]) 
00987     {
00988        /* Either there was a state change that prevents a search
00989         * (token logged out), or the search was already done,
00990         * or CRLs are not being cached.
00991         */
00992        return PR_SUCCESS;
00993     }
00994     objects = nssToken_FindCRLs(cache->token, NULL,
00995                                 nssTokenSearchType_TokenForced,
00996                             MAX_LOCAL_CACHE_OBJECTS, &status);
00997     if (status != PR_SUCCESS) {
00998        return status;
00999     }
01000     cache->objects[cachedCRLs] = create_object_array(objects,
01001                                                      doIt,
01002                                                      &numObjects,
01003                                                      &status);
01004     if (status != PR_SUCCESS) {
01005        return status;
01006     }
01007     for (i=0; i<numObjects; i++) {
01008        cache->objects[cachedCRLs][i] = create_crl(objects[i], &status);
01009        if (status != PR_SUCCESS) {
01010            break;
01011        }
01012     }
01013     if (status == PR_SUCCESS) {
01014        nss_ZFreeIf(objects);
01015     } else {
01016        PRUint32 j;
01017        for (j=0; j<i; j++) {
01018            /* sigh */
01019            nssToken_AddRef(cache->objects[cachedCRLs][j]->object->token);
01020            nssArena_Destroy(cache->objects[cachedCRLs][j]->arena);
01021        }
01022        nssCryptokiObjectArray_Destroy(objects);
01023     }
01024     cache->searchedObjectType[cachedCRLs] = PR_TRUE;
01025     return status;
01026 }
01027 
01028 static CK_ATTRIBUTE_PTR
01029 find_attribute_in_object (
01030   nssCryptokiObjectAndAttributes *obj,
01031   CK_ATTRIBUTE_TYPE attrType
01032 )
01033 {
01034     PRUint32 j;
01035     for (j=0; j<obj->numAttributes; j++) {
01036        if (attrType == obj->attributes[j].type) {
01037            return &obj->attributes[j];
01038        }
01039     }
01040     return (CK_ATTRIBUTE_PTR)NULL;
01041 }
01042 
01043 /* Find all objects in the array that match the supplied template */
01044 static nssCryptokiObject **
01045 find_objects_in_array (
01046   nssCryptokiObjectAndAttributes **objArray,
01047   CK_ATTRIBUTE_PTR ot,
01048   CK_ULONG otlen,
01049   PRUint32 maximumOpt
01050 )
01051 {
01052     PRIntn oi = 0;
01053     PRUint32 i;
01054     NSSArena *arena;
01055     PRUint32 size = 8;
01056     PRUint32 numMatches = 0;
01057     nssCryptokiObject **objects = NULL;
01058     nssCryptokiObjectAndAttributes **matches = NULL;
01059     CK_ATTRIBUTE_PTR attr;
01060 
01061     if (!objArray) {
01062        return (nssCryptokiObject **)NULL;
01063     }
01064     arena = nssArena_Create();
01065     if (!arena) {
01066        return (nssCryptokiObject **)NULL;
01067     }
01068     matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
01069     if (!matches) {
01070        goto loser;
01071     }
01072     if (maximumOpt == 0) maximumOpt = ~0;
01073     /* loop over the cached objects */
01074     for (; *objArray && numMatches < maximumOpt; objArray++) {
01075        nssCryptokiObjectAndAttributes *obj = *objArray;
01076        /* loop over the test template */
01077        for (i=0; i<otlen; i++) {
01078            /* see if the object has the attribute */
01079            attr = find_attribute_in_object(obj, ot[i].type);
01080            if (!attr) {
01081               /* nope, match failed */
01082               break;
01083            }
01084            /* compare the attribute against the test value */
01085            if (ot[i].ulValueLen != attr->ulValueLen ||
01086                !nsslibc_memequal(ot[i].pValue, 
01087                                  attr->pValue,
01088                                  attr->ulValueLen, NULL))
01089            {
01090               /* nope, match failed */
01091               break;
01092            }
01093        }
01094        if (i == otlen) {
01095            /* all of the attributes in the test template were found
01096             * in the object's template, and they all matched
01097             */
01098            matches[numMatches++] = obj;
01099            if (numMatches == size) {
01100               size *= 2;
01101               matches = nss_ZREALLOCARRAY(matches, 
01102                                           nssCryptokiObjectAndAttributes *, 
01103                                           size);
01104               if (!matches) {
01105                   goto loser;
01106               }
01107            }
01108        }
01109     }
01110     if (numMatches > 0) {
01111        objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
01112        if (!objects) {
01113            goto loser;
01114        }
01115        for (oi=0; oi<(PRIntn)numMatches; oi++) {
01116            objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
01117            if (!objects[oi]) {
01118               goto loser;
01119            }
01120        }
01121     }
01122     nssArena_Destroy(arena);
01123     return objects;
01124 loser:
01125     if (objects) {
01126        for (--oi; oi>=0; --oi) {
01127            nssCryptokiObject_Destroy(objects[oi]);
01128        }
01129     }
01130     nssArena_Destroy(arena);
01131     return (nssCryptokiObject **)NULL;
01132 }
01133 
01134 NSS_IMPLEMENT nssCryptokiObject **
01135 nssTokenObjectCache_FindObjectsByTemplate (
01136   nssTokenObjectCache *cache,
01137   CK_OBJECT_CLASS objclass,
01138   CK_ATTRIBUTE_PTR otemplate,
01139   CK_ULONG otlen,
01140   PRUint32 maximumOpt,
01141   PRStatus *statusOpt
01142 )
01143 {
01144     PRStatus status = PR_FAILURE;
01145     nssCryptokiObject **rvObjects = NULL;
01146     if (!token_is_present(cache)) {
01147        status = PR_SUCCESS;
01148        goto finish;
01149     }
01150     PZ_Lock(cache->lock);
01151     switch (objclass) {
01152     case CKO_CERTIFICATE:
01153        if (cache->doObjectType[cachedCerts]) {
01154            status = get_token_certs_for_cache(cache);
01155            if (status != PR_SUCCESS) {
01156               goto unlock;
01157            }
01158            rvObjects = find_objects_in_array(cache->objects[cachedCerts], 
01159                                              otemplate, otlen, maximumOpt);
01160        }
01161        break;
01162     case CKO_NETSCAPE_TRUST:
01163        if (cache->doObjectType[cachedTrust]) {
01164            status = get_token_trust_for_cache(cache);
01165            if (status != PR_SUCCESS) {
01166               goto unlock;
01167            }
01168            rvObjects = find_objects_in_array(cache->objects[cachedTrust], 
01169                                              otemplate, otlen, maximumOpt);
01170        }
01171        break;
01172     case CKO_NETSCAPE_CRL:
01173        if (cache->doObjectType[cachedCRLs]) {
01174            status = get_token_crls_for_cache(cache);
01175            if (status != PR_SUCCESS) {
01176               goto unlock;
01177            }
01178            rvObjects = find_objects_in_array(cache->objects[cachedCRLs], 
01179                                              otemplate, otlen, maximumOpt);
01180        }
01181        break;
01182     default: break;
01183     }
01184 unlock:
01185     PZ_Unlock(cache->lock);
01186 finish:
01187     if (statusOpt) {
01188        *statusOpt = status;
01189     }
01190     return rvObjects;
01191 }
01192 
01193 static PRBool
01194 cache_available_for_object_type (
01195   nssTokenObjectCache *cache,
01196   PRUint32 objectType
01197 )
01198 {
01199     if (!cache->doObjectType[objectType]) {
01200        /* not caching this object kind */
01201        return PR_FALSE;
01202     }
01203     if (!cache->searchedObjectType[objectType]) {
01204        /* objects are not cached yet */
01205        return PR_FALSE;
01206     }
01207     if (!search_for_objects(cache)) {
01208        /* not logged in */
01209        return PR_FALSE;
01210     }
01211     return PR_TRUE;
01212 }
01213 
01214 NSS_IMPLEMENT PRStatus
01215 nssTokenObjectCache_GetObjectAttributes (
01216   nssTokenObjectCache *cache,
01217   NSSArena *arenaOpt,
01218   nssCryptokiObject *object,
01219   CK_OBJECT_CLASS objclass,
01220   CK_ATTRIBUTE_PTR atemplate,
01221   CK_ULONG atlen
01222 )
01223 {
01224     PRUint32 i, j;
01225     NSSArena *arena = NULL;
01226     nssArenaMark *mark = NULL;
01227     nssCryptokiObjectAndAttributes *cachedOA = NULL;
01228     nssCryptokiObjectAndAttributes **oa = NULL;
01229     PRUint32 objectType;
01230     if (!token_is_present(cache)) {
01231        return PR_FAILURE;
01232     }
01233     PZ_Lock(cache->lock);
01234     switch (objclass) {
01235     case CKO_CERTIFICATE:    objectType = cachedCerts; break;
01236     case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
01237     case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
01238     default: goto loser;
01239     }
01240     if (!cache_available_for_object_type(cache, objectType)) {
01241        goto loser;
01242     }
01243     oa = cache->objects[objectType];
01244     if (!oa) {
01245        goto loser;
01246     }
01247     for (; *oa; oa++) {
01248        if (nssCryptokiObject_Equal((*oa)->object, object)) {
01249            cachedOA = *oa;
01250            break;
01251        }
01252     }
01253     if (!cachedOA) {
01254        goto loser; /* don't have this object */
01255     }
01256     if (arenaOpt) {
01257        arena = arenaOpt;
01258        mark = nssArena_Mark(arena);
01259     }
01260     for (i=0; i<atlen; i++) {
01261        for (j=0; j<cachedOA->numAttributes; j++) {
01262            if (atemplate[i].type == cachedOA->attributes[j].type) {
01263               CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
01264               if (cachedOA->attributes[j].ulValueLen == 0 ||
01265                   cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) 
01266               {
01267                   break; /* invalid attribute */
01268               }
01269               if (atemplate[i].ulValueLen > 0) {
01270                   if (atemplate[i].pValue == NULL ||
01271                       atemplate[i].ulValueLen < attr->ulValueLen) 
01272                   {
01273                      goto loser;
01274                   }
01275               } else {
01276                   atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
01277                   if (!atemplate[i].pValue) {
01278                      goto loser;
01279                   }
01280               }
01281               nsslibc_memcpy(atemplate[i].pValue,
01282                              attr->pValue, attr->ulValueLen);
01283               atemplate[i].ulValueLen = attr->ulValueLen;
01284               break;
01285            }
01286        }
01287        if (j == cachedOA->numAttributes) {
01288            atemplate[i].ulValueLen = (CK_ULONG)-1;
01289        }
01290     }
01291     PZ_Unlock(cache->lock);
01292     if (mark) {
01293        nssArena_Unmark(arena, mark);
01294     }
01295     return PR_SUCCESS;
01296 loser:
01297     PZ_Unlock(cache->lock);
01298     if (mark) {
01299        nssArena_Release(arena, mark);
01300     }
01301     return PR_FAILURE;
01302 }
01303 
01304 NSS_IMPLEMENT PRStatus
01305 nssTokenObjectCache_ImportObject (
01306   nssTokenObjectCache *cache,
01307   nssCryptokiObject *object,
01308   CK_OBJECT_CLASS objclass,
01309   CK_ATTRIBUTE_PTR ot,
01310   CK_ULONG otlen
01311 )
01312 {
01313     PRStatus status = PR_SUCCESS;
01314     PRUint32 count;
01315     nssCryptokiObjectAndAttributes **oa, ***otype;
01316     PRUint32 objectType;
01317     PRBool haveIt = PR_FALSE;
01318 
01319     if (!token_is_present(cache)) {
01320        return PR_SUCCESS; /* cache not active, ignored */
01321     }
01322     PZ_Lock(cache->lock);
01323     switch (objclass) {
01324     case CKO_CERTIFICATE:    objectType = cachedCerts; break;
01325     case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
01326     case CKO_NETSCAPE_CRL:   objectType = cachedCRLs;  break;
01327     default:
01328        PZ_Unlock(cache->lock);
01329        return PR_SUCCESS; /* don't need to import it here */
01330     }
01331     if (!cache_available_for_object_type(cache, objectType)) {
01332        PZ_Unlock(cache->lock);
01333        return PR_SUCCESS; /* cache not active, ignored */
01334     }
01335     count = 0;
01336     otype = &cache->objects[objectType]; /* index into array of types */
01337     oa = *otype; /* the array of objects for this type */
01338     while (oa && *oa) {
01339        if (nssCryptokiObject_Equal((*oa)->object, object)) {
01340            haveIt = PR_TRUE;
01341            break;
01342        }
01343        count++;
01344        oa++;
01345     }
01346     if (haveIt) {
01347        /* Destroy the old entry */
01348        (*oa)->object->token = NULL;
01349        nssCryptokiObject_Destroy((*oa)->object);
01350        nssArena_Destroy((*oa)->arena);
01351     } else {
01352        /* Create space for a new entry */
01353        if (count > 0) {
01354            *otype = nss_ZREALLOCARRAY(*otype,
01355                                       nssCryptokiObjectAndAttributes *, 
01356                                       count + 2);
01357        } else {
01358            *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
01359        }
01360     }
01361     if (*otype) {
01362        nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
01363        if (objectType == cachedCerts) {
01364            (*otype)[count] = create_cert(copyObject, &status);
01365        } else if (objectType == cachedTrust) {
01366            (*otype)[count] = create_trust(copyObject, &status);
01367        } else if (objectType == cachedCRLs) {
01368            (*otype)[count] = create_crl(copyObject, &status);
01369        }
01370     } else {
01371        status = PR_FAILURE;
01372     }
01373     PZ_Unlock(cache->lock);
01374     return status;
01375 }
01376 
01377 NSS_IMPLEMENT void
01378 nssTokenObjectCache_RemoveObject (
01379   nssTokenObjectCache *cache,
01380   nssCryptokiObject *object
01381 )
01382 {
01383     PRUint32 oType;
01384     nssCryptokiObjectAndAttributes **oa, **swp = NULL;
01385     if (!token_is_present(cache)) {
01386        return;
01387     }
01388     PZ_Lock(cache->lock);
01389     for (oType=0; oType<3; oType++) {
01390        if (!cache_available_for_object_type(cache, oType) ||
01391            !cache->objects[oType])
01392        {
01393            continue;
01394        }
01395        for (oa = cache->objects[oType]; *oa; oa++) {
01396            if (nssCryptokiObject_Equal((*oa)->object, object)) {
01397               swp = oa; /* the entry to remove */
01398               while (oa[1]) oa++; /* go to the tail */
01399               (*swp)->object->token = NULL;
01400               nssCryptokiObject_Destroy((*swp)->object);
01401               nssArena_Destroy((*swp)->arena); /* destroy it */
01402               *swp = *oa; /* swap the last with the removed */
01403               *oa = NULL; /* null-terminate the array */
01404               break;
01405            }
01406        }
01407        if (swp) {
01408            break;
01409        }
01410     }
01411     if ((oType <3) &&
01412               cache->objects[oType] && cache->objects[oType][0] == NULL) {
01413        nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
01414        cache->objects[oType] = NULL;
01415     }
01416     PZ_Unlock(cache->lock);
01417 }
01418 
01419 /* These two hash algorithms are presently sufficient.
01420 ** They are used for fingerprints of certs which are stored as the 
01421 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
01422 ** We don't need to add SHAxxx to these now.
01423 */
01424 /* XXX of course this doesn't belong here */
01425 NSS_IMPLEMENT NSSAlgorithmAndParameters *
01426 NSSAlgorithmAndParameters_CreateSHA1Digest (
01427   NSSArena *arenaOpt
01428 )
01429 {
01430     NSSAlgorithmAndParameters *rvAP = NULL;
01431     rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
01432     if (rvAP) {
01433        rvAP->mechanism.mechanism = CKM_SHA_1;
01434        rvAP->mechanism.pParameter = NULL;
01435        rvAP->mechanism.ulParameterLen = 0;
01436     }
01437     return rvAP;
01438 }
01439 
01440 NSS_IMPLEMENT NSSAlgorithmAndParameters *
01441 NSSAlgorithmAndParameters_CreateMD5Digest (
01442   NSSArena *arenaOpt
01443 )
01444 {
01445     NSSAlgorithmAndParameters *rvAP = NULL;
01446     rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
01447     if (rvAP) {
01448        rvAP->mechanism.mechanism = CKM_MD5;
01449        rvAP->mechanism.pParameter = NULL;
01450        rvAP->mechanism.ulParameterLen = 0;
01451     }
01452     return rvAP;
01453 }
01454