Back to index

lightning-sunbird  0.9+nobinonly
devtoken.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: devtoken.c,v $ $Revision: 1.39 $ $Date: 2005/01/20 02:25:47 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef NSSCKEPV_H
00042 #include "nssckepv.h"
00043 #endif /* NSSCKEPV_H */
00044 
00045 #ifndef DEVM_H
00046 #include "devm.h"
00047 #endif /* DEVM_H */
00048 
00049 #ifndef CKHELPER_H
00050 #include "ckhelper.h"
00051 #endif /* CKHELPER_H */
00052 
00053 #ifdef NSS_3_4_CODE
00054 #include "pk11func.h"
00055 #include "dev3hack.h"
00056 #include "secerr.h"
00057 #endif
00058 
00059 extern const NSSError NSS_ERROR_NOT_FOUND;
00060 
00061 /* The number of object handles to grab during each call to C_FindObjects */
00062 #define OBJECT_STACK_SIZE 16
00063 
00064 #ifdef PURE_STAN_BUILD
00065 struct NSSTokenStr
00066 {
00067   struct nssDeviceBaseStr base;
00068   NSSSlot *slot;  /* Peer */
00069   CK_FLAGS ckFlags; /* from CK_TOKEN_INFO.flags */
00070   nssSession *defaultSession;
00071   nssTokenObjectCache *cache;
00072 };
00073 
00074 NSS_IMPLEMENT NSSToken *
00075 nssToken_Create (
00076   CK_SLOT_ID slotID,
00077   NSSSlot *peer
00078 )
00079 {
00080     NSSArena *arena;
00081     NSSToken *rvToken;
00082     nssSession *session = NULL;
00083     NSSUTF8 *tokenName = NULL;
00084     PRUint32 length;
00085     PRBool readWrite;
00086     CK_TOKEN_INFO tokenInfo;
00087     CK_RV ckrv;
00088     void *epv = nssSlot_GetCryptokiEPV(peer);
00089     arena = NSSArena_Create();
00090     if(!arena) {
00091        return (NSSToken *)NULL;
00092     }
00093     rvToken = nss_ZNEW(arena, NSSToken);
00094     if (!rvToken) {
00095        goto loser;
00096     }
00097     /* Get token information */
00098     ckrv = CKAPI(epv)->C_GetTokenInfo(slotID, &tokenInfo);
00099     if (ckrv != CKR_OK) {
00100        /* set an error here, eh? */
00101        goto loser;
00102     }
00103     /* Grab the slot description from the PKCS#11 fixed-length buffer */
00104     length = nssPKCS11String_Length(tokenInfo.label, sizeof(tokenInfo.label));
00105     if (length > 0) {
00106        tokenName = nssUTF8_Create(arena, nssStringType_UTF8String, 
00107                                   (void *)tokenInfo.label, length);
00108        if (!tokenName) {
00109            goto loser;
00110        }
00111     }
00112     /* Open a default session handle for the token. */
00113     if (tokenInfo.ulMaxSessionCount == 1) {
00114        /* if the token can only handle one session, it must be RW. */
00115        readWrite = PR_TRUE;
00116     } else {
00117        readWrite = PR_FALSE;
00118     }
00119     session = nssSlot_CreateSession(peer, arena, readWrite);
00120     if (session == NULL) {
00121        goto loser;
00122     }
00123     /* TODO: seed the RNG here */
00124     rvToken->base.arena = arena;
00125     rvToken->base.refCount = 1;
00126     rvToken->base.name = tokenName;
00127     rvToken->base.lock = PZ_NewLock(nssNSSILockOther); /* XXX */
00128     if (!rvToken->base.lock) {
00129        goto loser;
00130     }
00131     rvToken->slot = peer; /* slot owns ref to token */
00132     rvToken->ckFlags = tokenInfo.flags;
00133     rvToken->defaultSession = session;
00134     if (nssSlot_IsHardware(peer)) {
00135        rvToken->cache = nssTokenObjectCache_Create(rvToken, 
00136                                                    PR_TRUE, PR_TRUE, PR_TRUE);
00137        if (!rvToken->cache) {
00138            nssSlot_Destroy(peer);
00139            goto loser;
00140        }
00141     }
00142     return rvToken;
00143 loser:
00144     if (session) {
00145        nssSession_Destroy(session);
00146     }
00147     nssArena_Destroy(arena);
00148     return (NSSToken *)NULL;
00149 }
00150 #endif /* PURE_STAN_BUILD */
00151 
00152 NSS_IMPLEMENT PRStatus
00153 nssToken_Destroy (
00154   NSSToken *tok
00155 )
00156 {
00157     if (tok) {
00158        if (PR_AtomicDecrement(&tok->base.refCount) == 0) {
00159            PZ_DestroyLock(tok->base.lock);
00160            nssTokenObjectCache_Destroy(tok->cache);
00161            return nssArena_Destroy(tok->base.arena);
00162        }
00163     }
00164     return PR_SUCCESS;
00165 }
00166 
00167 NSS_IMPLEMENT void
00168 nssToken_Remove (
00169   NSSToken *tok
00170 )
00171 {
00172     nssTokenObjectCache_Clear(tok->cache);
00173 }
00174 
00175 NSS_IMPLEMENT void
00176 NSSToken_Destroy (
00177   NSSToken *tok
00178 )
00179 {
00180     (void)nssToken_Destroy(tok);
00181 }
00182 
00183 NSS_IMPLEMENT NSSToken *
00184 nssToken_AddRef (
00185   NSSToken *tok
00186 )
00187 {
00188     PR_AtomicIncrement(&tok->base.refCount);
00189     return tok;
00190 }
00191 
00192 NSS_IMPLEMENT NSSSlot *
00193 nssToken_GetSlot (
00194   NSSToken *tok
00195 )
00196 {
00197     return nssSlot_AddRef(tok->slot);
00198 }
00199 
00200 #ifdef PURE_STAN_BUILD
00201 NSS_IMPLEMENT NSSModule *
00202 nssToken_GetModule (
00203   NSSToken *token
00204 )
00205 {
00206     return nssSlot_GetModule(token->slot);
00207 }
00208 #endif
00209 
00210 NSS_IMPLEMENT void *
00211 nssToken_GetCryptokiEPV (
00212   NSSToken *token
00213 )
00214 {
00215     return nssSlot_GetCryptokiEPV(token->slot);
00216 }
00217 
00218 NSS_IMPLEMENT nssSession *
00219 nssToken_GetDefaultSession (
00220   NSSToken *token
00221 )
00222 {
00223     return token->defaultSession;
00224 }
00225 
00226 NSS_IMPLEMENT NSSUTF8 *
00227 nssToken_GetName (
00228   NSSToken *tok
00229 )
00230 {
00231     if (tok == NULL) {
00232        return "";
00233     }
00234     if (tok->base.name[0] == 0) {
00235        (void) nssSlot_IsTokenPresent(tok->slot);
00236     } 
00237     return tok->base.name;
00238 }
00239 
00240 NSS_IMPLEMENT NSSUTF8 *
00241 NSSToken_GetName (
00242   NSSToken *token
00243 )
00244 {
00245     return nssToken_GetName(token);
00246 }
00247 
00248 NSS_IMPLEMENT PRBool
00249 nssToken_IsLoginRequired (
00250   NSSToken *token
00251 )
00252 {
00253     return (token->ckFlags & CKF_LOGIN_REQUIRED);
00254 }
00255 
00256 NSS_IMPLEMENT PRBool
00257 nssToken_NeedsPINInitialization (
00258   NSSToken *token
00259 )
00260 {
00261     return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
00262 }
00263 
00264 NSS_IMPLEMENT PRStatus
00265 nssToken_DeleteStoredObject (
00266   nssCryptokiObject *instance
00267 )
00268 {
00269     CK_RV ckrv;
00270     PRStatus status;
00271     PRBool createdSession = PR_FALSE;
00272     NSSToken *token = instance->token;
00273     nssSession *session = NULL;
00274     void *epv = nssToken_GetCryptokiEPV(instance->token);
00275     if (token->cache) {
00276        nssTokenObjectCache_RemoveObject(token->cache, instance);
00277     }
00278     if (instance->isTokenObject) {
00279        if (nssSession_IsReadWrite(token->defaultSession)) {
00280           session = token->defaultSession;
00281        } else {
00282           session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
00283           createdSession = PR_TRUE;
00284        }
00285     }
00286     if (session == NULL) {
00287        return PR_FAILURE;
00288     }
00289     nssSession_EnterMonitor(session);
00290     ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
00291     nssSession_ExitMonitor(session);
00292     if (createdSession) {
00293        nssSession_Destroy(session);
00294     }
00295     status = (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
00296     return status;
00297 }
00298 
00299 static nssCryptokiObject *
00300 import_object (
00301   NSSToken *tok,
00302   nssSession *sessionOpt,
00303   CK_ATTRIBUTE_PTR objectTemplate,
00304   CK_ULONG otsize
00305 )
00306 {
00307     nssSession *session = NULL;
00308     PRBool createdSession = PR_FALSE;
00309     nssCryptokiObject *object = NULL;
00310     CK_OBJECT_HANDLE handle;
00311     CK_RV ckrv;
00312     void *epv = nssToken_GetCryptokiEPV(tok);
00313     if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
00314        if (sessionOpt) {
00315            if (!nssSession_IsReadWrite(sessionOpt)) {
00316               return CK_INVALID_HANDLE;
00317            } else {
00318               session = sessionOpt;
00319            }
00320        } else if (nssSession_IsReadWrite(tok->defaultSession)) {
00321            session = tok->defaultSession;
00322        } else {
00323            session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
00324            createdSession = PR_TRUE;
00325        }
00326     } else {
00327        session = (sessionOpt) ? sessionOpt : tok->defaultSession;
00328     }
00329     if (session == NULL) {
00330        return CK_INVALID_HANDLE;
00331     }
00332     nssSession_EnterMonitor(session);
00333     ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
00334                                       objectTemplate, otsize,
00335                                       &handle);
00336     nssSession_ExitMonitor(session);
00337     if (ckrv == CKR_OK) {
00338        object = nssCryptokiObject_Create(tok, session, handle);
00339     }
00340     if (createdSession) {
00341        nssSession_Destroy(session);
00342     }
00343     return object;
00344 }
00345 
00346 static nssCryptokiObject **
00347 create_objects_from_handles (
00348   NSSToken *tok,
00349   nssSession *session,
00350   CK_OBJECT_HANDLE *handles,
00351   PRUint32 numH
00352 )
00353 {
00354     nssCryptokiObject **objects;
00355     objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
00356     if (objects) {
00357        PRInt32 i;
00358        for (i=0; i<(PRInt32)numH; i++) {
00359            objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
00360            if (!objects[i]) {
00361               for (--i; i>0; --i) {
00362                   nssCryptokiObject_Destroy(objects[i]);
00363               }
00364               return (nssCryptokiObject **)NULL;
00365            }
00366        }
00367     }
00368     return objects;
00369 }
00370 
00371 static nssCryptokiObject **
00372 find_objects (
00373   NSSToken *tok,
00374   nssSession *sessionOpt,
00375   CK_ATTRIBUTE_PTR obj_template,
00376   CK_ULONG otsize,
00377   PRUint32 maximumOpt,
00378   PRStatus *statusOpt
00379 )
00380 {
00381     CK_RV ckrv = CKR_OK;
00382     CK_ULONG count;
00383     CK_OBJECT_HANDLE *objectHandles;
00384     CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
00385     PRUint32 arraySize, numHandles;
00386     void *epv = nssToken_GetCryptokiEPV(tok);
00387     nssCryptokiObject **objects;
00388     nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
00389 
00390     /* the arena is only for the array of object handles */
00391     if (maximumOpt > 0) {
00392        arraySize = maximumOpt;
00393     } else {
00394        arraySize = OBJECT_STACK_SIZE;
00395     }
00396     numHandles = 0;
00397     if (arraySize <= OBJECT_STACK_SIZE) {
00398        objectHandles = staticObjects;
00399     } else {
00400        objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
00401     }
00402     if (!objectHandles) {
00403        ckrv = CKR_HOST_MEMORY;
00404        goto loser;
00405     }
00406     nssSession_EnterMonitor(session); /* ==== session lock === */
00407     /* Initialize the find with the template */
00408     ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
00409                                          obj_template, otsize);
00410     if (ckrv != CKR_OK) {
00411        nssSession_ExitMonitor(session);
00412        goto loser;
00413     }
00414     while (PR_TRUE) {
00415        /* Issue the find for up to arraySize - numHandles objects */
00416        ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
00417                                         objectHandles + numHandles, 
00418                                         arraySize - numHandles, 
00419                                         &count);
00420        if (ckrv != CKR_OK) {
00421            nssSession_ExitMonitor(session);
00422            goto loser;
00423        }
00424        /* bump the number of found objects */
00425        numHandles += count;
00426        if (maximumOpt > 0 || numHandles < arraySize) {
00427            /* When a maximum is provided, the search is done all at once,
00428             * so the search is finished.  If the number returned was less 
00429             * than the number sought, the search is finished.
00430             */
00431            break;
00432        }
00433        /* the array is filled, double it and continue */
00434        arraySize *= 2;
00435        if (objectHandles == staticObjects) {
00436            objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
00437            if (objectHandles) {
00438               PORT_Memcpy(objectHandles, staticObjects, 
00439                      OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
00440            }
00441        } else {
00442            objectHandles = nss_ZREALLOCARRAY(objectHandles, 
00443                                          CK_OBJECT_HANDLE, 
00444                                          arraySize);
00445        }
00446        if (!objectHandles) {
00447            nssSession_ExitMonitor(session);
00448            ckrv = CKR_HOST_MEMORY;
00449            goto loser;
00450        }
00451     }
00452     ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
00453     nssSession_ExitMonitor(session); /* ==== end session lock === */
00454     if (ckrv != CKR_OK) {
00455        goto loser;
00456     }
00457     if (numHandles > 0) {
00458        objects = create_objects_from_handles(tok, session,
00459                                              objectHandles, numHandles);
00460     } else {
00461        nss_SetError(NSS_ERROR_NOT_FOUND);
00462        objects = NULL;
00463     }
00464     if (objectHandles && objectHandles != staticObjects) {
00465        nss_ZFreeIf(objectHandles);
00466     }
00467     if (statusOpt) *statusOpt = PR_SUCCESS;
00468     return objects;
00469 loser:
00470     if (objectHandles && objectHandles != staticObjects) {
00471        nss_ZFreeIf(objectHandles);
00472     }
00473     /*
00474      * These errors should be treated the same as if the objects just weren't
00475      * found..
00476      */
00477     if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
00478        (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
00479        (ckrv == CKR_DATA_INVALID) ||
00480        (ckrv == CKR_DATA_LEN_RANGE) ||
00481        (ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
00482        (ckrv == CKR_TEMPLATE_INCOMPLETE) ||
00483        (ckrv == CKR_TEMPLATE_INCONSISTENT)) {
00484 
00485        nss_SetError(NSS_ERROR_NOT_FOUND);
00486        if (statusOpt) *statusOpt = PR_SUCCESS;
00487     } else {
00488        if (statusOpt) *statusOpt = PR_FAILURE;
00489     }
00490     return (nssCryptokiObject **)NULL;
00491 }
00492 
00493 static nssCryptokiObject **
00494 find_objects_by_template (
00495   NSSToken *token,
00496   nssSession *sessionOpt,
00497   CK_ATTRIBUTE_PTR obj_template,
00498   CK_ULONG otsize,
00499   PRUint32 maximumOpt,
00500   PRStatus *statusOpt
00501 )
00502 {
00503     CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
00504     nssCryptokiObject **objects = NULL;
00505     PRUint32 i;
00506     for (i=0; i<otsize; i++) {
00507        if (obj_template[i].type == CKA_CLASS) {
00508            objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
00509            break;
00510        }
00511     }
00512     PR_ASSERT(i < otsize);
00513     if (i == otsize) {
00514 #ifdef NSS_3_4_CODE
00515        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00516 #endif
00517        if (statusOpt) *statusOpt = PR_FAILURE;
00518        return NULL;
00519     }
00520     /* If these objects are being cached, try looking there first */
00521     if (token->cache && 
00522         nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
00523     {
00524        PRStatus status;
00525        objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
00526                                                            objclass,
00527                                                            obj_template,
00528                                                            otsize,
00529                                                            maximumOpt,
00530                                                            &status);
00531        if (status == PR_SUCCESS) {
00532            if (statusOpt) *statusOpt = status;
00533            return objects;
00534        }
00535     }
00536     /* Either they are not cached, or cache failed; look on token. */
00537     objects = find_objects(token, sessionOpt, 
00538                            obj_template, otsize, 
00539                            maximumOpt, statusOpt);
00540     return objects;
00541 }
00542 
00543 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
00544 
00545 NSS_IMPLEMENT nssCryptokiObject *
00546 nssToken_ImportCertificate (
00547   NSSToken *tok,
00548   nssSession *sessionOpt,
00549   NSSCertificateType certType,
00550   NSSItem *id,
00551   NSSUTF8 *nickname,
00552   NSSDER *encoding,
00553   NSSDER *issuer,
00554   NSSDER *subject,
00555   NSSDER *serial,
00556   NSSASCII7 *email,
00557   PRBool asTokenObject
00558 )
00559 {
00560     PRStatus status;
00561     CK_CERTIFICATE_TYPE cert_type;
00562     CK_ATTRIBUTE_PTR attr;
00563     CK_ATTRIBUTE cert_tmpl[10];
00564     CK_ULONG ctsize;
00565     nssTokenSearchType searchType;
00566     nssCryptokiObject *rvObject = NULL;
00567 
00568     if (certType == NSSCertificateType_PKIX) {
00569        cert_type = CKC_X_509;
00570     } else {
00571        return (nssCryptokiObject *)NULL;
00572     }
00573     NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
00574     if (asTokenObject) {
00575        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00576        searchType = nssTokenSearchType_TokenOnly;
00577     } else {
00578        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00579        searchType = nssTokenSearchType_SessionOnly;
00580     }
00581     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
00582     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
00583     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
00584     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
00585     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
00586     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
00587     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
00588     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
00589     if (email) {
00590        NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL,    email);
00591     }
00592     NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
00593     /* see if the cert is already there */
00594     rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
00595                                                                sessionOpt,
00596                                                                issuer,
00597                                                                serial,
00598                                                                searchType,
00599                                                                NULL);
00600     if (rvObject) {
00601        NSSItem existingDER;
00602        NSSSlot *slot = nssToken_GetSlot(tok);
00603        nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
00604        if (!session) {
00605            nssCryptokiObject_Destroy(rvObject);
00606            nssSlot_Destroy(slot);
00607            return (nssCryptokiObject *)NULL;
00608        }
00609        /* Reject any attempt to import a new cert that has the same
00610         * issuer/serial as an existing cert, but does not have the
00611         * same encoding
00612         */
00613        NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
00614        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
00615        NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
00616        status = nssCKObject_GetAttributes(rvObject->handle, 
00617                                           cert_tmpl, ctsize, NULL,
00618                                           session, slot);
00619        NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
00620        if (status == PR_SUCCESS) {
00621            if (!nssItem_Equal(encoding, &existingDER, NULL)) {
00622               nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
00623               status = PR_FAILURE;
00624            }
00625            nss_ZFreeIf(existingDER.data);
00626        }
00627        if (status == PR_FAILURE) {
00628            nssCryptokiObject_Destroy(rvObject);
00629            nssSession_Destroy(session);
00630            nssSlot_Destroy(slot);
00631            return (nssCryptokiObject *)NULL;
00632        }
00633        /* according to PKCS#11, label, ID, issuer, and serial number 
00634         * may change after the object has been created.  For PKIX, the
00635         * last two attributes can't change, so for now we'll only worry
00636         * about the first two.
00637         */
00638        NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
00639        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
00640        NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
00641        NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
00642        /* reset the mutable attributes on the token */
00643        nssCKObject_SetAttributes(rvObject->handle, 
00644                                  cert_tmpl, ctsize,
00645                                  session, slot);
00646        if (!rvObject->label && nickname) {
00647            rvObject->label = nssUTF8_Duplicate(nickname, NULL);
00648        }
00649        nssSession_Destroy(session);
00650        nssSlot_Destroy(slot);
00651     } else {
00652        /* Import the certificate onto the token */
00653        rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
00654     }
00655     if (rvObject && tok->cache) {
00656        /* The cache will overwrite the attributes if the object already
00657         * exists.
00658         */
00659        nssTokenObjectCache_ImportObject(tok->cache, rvObject,
00660                                         CKO_CERTIFICATE,
00661                                         cert_tmpl, ctsize);
00662     }
00663     return rvObject;
00664 }
00665 
00666 /* traverse all certificates - this should only happen if the token
00667  * has been marked as "traversable"
00668  */
00669 NSS_IMPLEMENT nssCryptokiObject **
00670 nssToken_FindCertificates (
00671   NSSToken *token,
00672   nssSession *sessionOpt,
00673   nssTokenSearchType searchType,
00674   PRUint32 maximumOpt,
00675   PRStatus *statusOpt
00676 )
00677 {
00678     CK_ATTRIBUTE_PTR attr;
00679     CK_ATTRIBUTE cert_template[2];
00680     CK_ULONG ctsize;
00681     nssCryptokiObject **objects;
00682     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
00683     /* Set the search to token/session only if provided */
00684     if (searchType == nssTokenSearchType_SessionOnly) {
00685        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00686     } else if (searchType == nssTokenSearchType_TokenOnly ||
00687                searchType == nssTokenSearchType_TokenForced) {
00688        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00689     }
00690     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
00691     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
00692 
00693     if (searchType == nssTokenSearchType_TokenForced) {
00694        objects = find_objects(token, sessionOpt,
00695                               cert_template, ctsize,
00696                               maximumOpt, statusOpt);
00697     } else {
00698        objects = find_objects_by_template(token, sessionOpt,
00699                                           cert_template, ctsize,
00700                                           maximumOpt, statusOpt);
00701     }
00702     return objects;
00703 }
00704 
00705 NSS_IMPLEMENT nssCryptokiObject **
00706 nssToken_FindCertificatesBySubject (
00707   NSSToken *token,
00708   nssSession *sessionOpt,
00709   NSSDER *subject,
00710   nssTokenSearchType searchType,
00711   PRUint32 maximumOpt,
00712   PRStatus *statusOpt
00713 )
00714 {
00715     CK_ATTRIBUTE_PTR attr;
00716     CK_ATTRIBUTE subj_template[3];
00717     CK_ULONG stsize;
00718     nssCryptokiObject **objects;
00719     NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
00720     /* Set the search to token/session only if provided */
00721     if (searchType == nssTokenSearchType_SessionOnly) {
00722        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00723     } else if (searchType == nssTokenSearchType_TokenOnly) {
00724        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00725     }
00726     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
00727     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
00728     NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
00729     /* now locate the token certs matching this template */
00730     objects = find_objects_by_template(token, sessionOpt,
00731                                        subj_template, stsize,
00732                                        maximumOpt, statusOpt);
00733     return objects;
00734 }
00735 
00736 NSS_IMPLEMENT nssCryptokiObject **
00737 nssToken_FindCertificatesByNickname (
00738   NSSToken *token,
00739   nssSession *sessionOpt,
00740   NSSUTF8 *name,
00741   nssTokenSearchType searchType,
00742   PRUint32 maximumOpt,
00743   PRStatus *statusOpt
00744 )
00745 {
00746     CK_ATTRIBUTE_PTR attr;
00747     CK_ATTRIBUTE nick_template[3];
00748     CK_ULONG ntsize;
00749     nssCryptokiObject **objects;
00750     NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
00751     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
00752     /* Set the search to token/session only if provided */
00753     if (searchType == nssTokenSearchType_SessionOnly) {
00754        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00755     } else if (searchType == nssTokenSearchType_TokenOnly) {
00756        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00757     }
00758     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
00759     NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
00760     /* now locate the token certs matching this template */
00761     objects = find_objects_by_template(token, sessionOpt,
00762                                        nick_template, ntsize, 
00763                                        maximumOpt, statusOpt);
00764     if (!objects) {
00765        /* This is to workaround the fact that PKCS#11 doesn't specify
00766         * whether the '\0' should be included.  XXX Is that still true?
00767         * im - this is not needed by the current softoken.  However, I'm 
00768         * leaving it in until I have surveyed more tokens to see if it needed.
00769         * well, its needed by the builtin token...
00770         */
00771        nick_template[0].ulValueLen++;
00772        objects = find_objects_by_template(token, sessionOpt,
00773                                           nick_template, ntsize, 
00774                                           maximumOpt, statusOpt);
00775     }
00776     return objects;
00777 }
00778 
00779 /* XXX
00780  * This function *does not* use the token object cache, because not even
00781  * the softoken will return a value for CKA_NETSCAPE_EMAIL from a call
00782  * to GetAttributes.  The softoken does allow searches with that attribute,
00783  * it just won't return a value for it.
00784  */
00785 NSS_IMPLEMENT nssCryptokiObject **
00786 nssToken_FindCertificatesByEmail (
00787   NSSToken *token,
00788   nssSession *sessionOpt,
00789   NSSASCII7 *email,
00790   nssTokenSearchType searchType,
00791   PRUint32 maximumOpt,
00792   PRStatus *statusOpt
00793 )
00794 {
00795     CK_ATTRIBUTE_PTR attr;
00796     CK_ATTRIBUTE email_template[3];
00797     CK_ULONG etsize;
00798     nssCryptokiObject **objects;
00799     NSS_CK_TEMPLATE_START(email_template, attr, etsize);
00800     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_EMAIL, email);
00801     /* Set the search to token/session only if provided */
00802     if (searchType == nssTokenSearchType_SessionOnly) {
00803        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00804     } else if (searchType == nssTokenSearchType_TokenOnly) {
00805        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00806     }
00807     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
00808     NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
00809     /* now locate the token certs matching this template */
00810     objects = find_objects(token, sessionOpt,
00811                            email_template, etsize,
00812                            maximumOpt, statusOpt);
00813     if (!objects) {
00814        /* This is to workaround the fact that PKCS#11 doesn't specify
00815         * whether the '\0' should be included.  XXX Is that still true?
00816         * im - this is not needed by the current softoken.  However, I'm 
00817         * leaving it in until I have surveyed more tokens to see if it needed.
00818         * well, its needed by the builtin token...
00819         */
00820        email_template[0].ulValueLen++;
00821        objects = find_objects(token, sessionOpt,
00822                               email_template, etsize,
00823                               maximumOpt, statusOpt);
00824     }
00825     return objects;
00826 }
00827 
00828 NSS_IMPLEMENT nssCryptokiObject **
00829 nssToken_FindCertificatesByID (
00830   NSSToken *token,
00831   nssSession *sessionOpt,
00832   NSSItem *id,
00833   nssTokenSearchType searchType,
00834   PRUint32 maximumOpt,
00835   PRStatus *statusOpt
00836 )
00837 {
00838     CK_ATTRIBUTE_PTR attr;
00839     CK_ATTRIBUTE id_template[3];
00840     CK_ULONG idtsize;
00841     nssCryptokiObject **objects;
00842     NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
00843     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
00844     /* Set the search to token/session only if provided */
00845     if (searchType == nssTokenSearchType_SessionOnly) {
00846        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00847     } else if (searchType == nssTokenSearchType_TokenOnly) {
00848        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00849     }
00850     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
00851     NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
00852     /* now locate the token certs matching this template */
00853     objects = find_objects_by_template(token, sessionOpt,
00854                                        id_template, idtsize,
00855                                        maximumOpt, statusOpt);
00856     return objects;
00857 }
00858 
00859 /*
00860  * decode the serial item and return our result.
00861  * NOTE serialDecode's data is really stored in serial. Don't free it.
00862  */
00863 static PRStatus
00864 nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
00865 {
00866     unsigned char *data = (unsigned char *)serial->data;
00867     int data_left, data_len, index;
00868 
00869     if ((serial->size >= 3) && (data[0] == 0x2)) {
00870        /* remove the der encoding of the serial number before generating the
00871         * key.. */
00872        data_left = serial->size-2;
00873        data_len = data[1];
00874        index = 2;
00875 
00876        /* extended length ? (not very likely for a serial number) */
00877        if (data_len & 0x80) {
00878            int len_count = data_len & 0x7f;
00879 
00880            data_len = 0;
00881            data_left -= len_count;
00882            if (data_left > 0) {
00883               while (len_count --) {
00884                   data_len = (data_len << 8) | data[index++];
00885               }
00886            } 
00887        }
00888        /* XXX leaving any leading zeros on the serial number for backwards
00889         * compatibility
00890         */
00891        /* not a valid der, must be just an unlucky serial number value */
00892        if (data_len == data_left) {
00893            serialDecode->size = data_len;
00894            serialDecode->data = &data[index];
00895            return PR_SUCCESS;
00896        }
00897     }
00898     return PR_FAILURE;
00899 }
00900 
00901 NSS_IMPLEMENT nssCryptokiObject *
00902 nssToken_FindCertificateByIssuerAndSerialNumber (
00903   NSSToken *token,
00904   nssSession *sessionOpt,
00905   NSSDER *issuer,
00906   NSSDER *serial,
00907   nssTokenSearchType searchType,
00908   PRStatus *statusOpt
00909 )
00910 {
00911     CK_ATTRIBUTE_PTR attr;
00912     CK_ATTRIBUTE_PTR serialAttr;
00913     CK_ATTRIBUTE cert_template[4];
00914     CK_ULONG ctsize;
00915     nssCryptokiObject **objects;
00916     nssCryptokiObject *rvObject = NULL;
00917     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
00918     /* Set the search to token/session only if provided */
00919     if (searchType == nssTokenSearchType_SessionOnly) {
00920        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00921     } else if ((searchType == nssTokenSearchType_TokenOnly) ||
00922                (searchType == nssTokenSearchType_TokenForced)) {
00923        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00924     }
00925     /* Set the unique id */
00926     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
00927     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
00928     serialAttr = attr;
00929     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
00930     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
00931     /* get the object handle */
00932     if (searchType == nssTokenSearchType_TokenForced) {
00933        objects = find_objects(token, sessionOpt,
00934                               cert_template, ctsize,
00935                               1, statusOpt);
00936     } else {
00937        objects = find_objects_by_template(token, sessionOpt,
00938                                        cert_template, ctsize,
00939                                        1, statusOpt);
00940     }
00941     if (objects) {
00942        rvObject = objects[0];
00943        nss_ZFreeIf(objects);
00944     }
00945 
00946     /*
00947      * NSS used to incorrectly store serial numbers in their decoded form.
00948      * because of this old tokens have decoded serial numbers.
00949      */
00950     if (!objects) {
00951        NSSItem serialDecode;
00952        PRStatus status;
00953 
00954        status = nssToken_decodeSerialItem(serial, &serialDecode);
00955        if (status != PR_SUCCESS) {
00956            return NULL;
00957        }
00958        NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
00959        if (searchType == nssTokenSearchType_TokenForced) {
00960            objects = find_objects(token, sessionOpt,
00961                               cert_template, ctsize,
00962                               1, statusOpt);
00963        } else {
00964            objects = find_objects_by_template(token, sessionOpt,
00965                                        cert_template, ctsize,
00966                                        1, statusOpt);
00967        }
00968        if (objects) {
00969            rvObject = objects[0];
00970            nss_ZFreeIf(objects);
00971        }
00972     }
00973     return rvObject;
00974 }
00975 
00976 NSS_IMPLEMENT nssCryptokiObject *
00977 nssToken_FindCertificateByEncodedCertificate (
00978   NSSToken *token,
00979   nssSession *sessionOpt,
00980   NSSBER *encodedCertificate,
00981   nssTokenSearchType searchType,
00982   PRStatus *statusOpt
00983 )
00984 {
00985     CK_ATTRIBUTE_PTR attr;
00986     CK_ATTRIBUTE cert_template[3];
00987     CK_ULONG ctsize;
00988     nssCryptokiObject **objects;
00989     nssCryptokiObject *rvObject = NULL;
00990     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
00991     /* Set the search to token/session only if provided */
00992     if (searchType == nssTokenSearchType_SessionOnly) {
00993        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
00994     } else if (searchType == nssTokenSearchType_TokenOnly) {
00995        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
00996     }
00997     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
00998     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
00999     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
01000     /* get the object handle */
01001     objects = find_objects_by_template(token, sessionOpt,
01002                                        cert_template, ctsize,
01003                                        1, statusOpt);
01004     if (objects) {
01005        rvObject = objects[0];
01006        nss_ZFreeIf(objects);
01007     }
01008     return rvObject;
01009 }
01010 
01011 NSS_IMPLEMENT nssCryptokiObject **
01012 nssToken_FindPrivateKeys (
01013   NSSToken *token,
01014   nssSession *sessionOpt,
01015   nssTokenSearchType searchType,
01016   PRUint32 maximumOpt,
01017   PRStatus *statusOpt
01018 )
01019 {
01020     CK_ATTRIBUTE_PTR attr;
01021     CK_ATTRIBUTE key_template[2];
01022     CK_ULONG ktsize;
01023     nssCryptokiObject **objects;
01024 
01025     NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
01026     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
01027     if (searchType == nssTokenSearchType_SessionOnly) {
01028        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01029     } else if (searchType == nssTokenSearchType_TokenOnly) {
01030        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01031     }
01032     NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
01033 
01034     objects = find_objects_by_template(token, sessionOpt,
01035                                        key_template, ktsize, 
01036                                        maximumOpt, statusOpt);
01037     return objects;
01038 }
01039 
01040 /* XXX ?there are no session cert objects, so only search token objects */
01041 NSS_IMPLEMENT nssCryptokiObject *
01042 nssToken_FindPrivateKeyByID (
01043   NSSToken *token,
01044   nssSession *sessionOpt,
01045   NSSItem *keyID
01046 )
01047 {
01048     CK_ATTRIBUTE_PTR attr;
01049     CK_ATTRIBUTE key_template[3];
01050     CK_ULONG ktsize;
01051     nssCryptokiObject **objects;
01052     nssCryptokiObject *rvKey = NULL;
01053 
01054     NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
01055     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
01056     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01057     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
01058     NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
01059 
01060     objects = find_objects_by_template(token, sessionOpt,
01061                                        key_template, ktsize, 
01062                                        1, NULL);
01063     if (objects) {
01064        rvKey = objects[0];
01065        nss_ZFreeIf(objects);
01066     }
01067     return rvKey;
01068 }
01069 
01070 /* XXX ?there are no session cert objects, so only search token objects */
01071 NSS_IMPLEMENT nssCryptokiObject *
01072 nssToken_FindPublicKeyByID (
01073   NSSToken *token,
01074   nssSession *sessionOpt,
01075   NSSItem *keyID
01076 )
01077 {
01078     CK_ATTRIBUTE_PTR attr;
01079     CK_ATTRIBUTE key_template[3];
01080     CK_ULONG ktsize;
01081     nssCryptokiObject **objects;
01082     nssCryptokiObject *rvKey = NULL;
01083 
01084     NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
01085     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
01086     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01087     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
01088     NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
01089 
01090     objects = find_objects_by_template(token, sessionOpt,
01091                                        key_template, ktsize, 
01092                                        1, NULL);
01093     if (objects) {
01094        rvKey = objects[0];
01095        nss_ZFreeIf(objects);
01096     }
01097     return rvKey;
01098 }
01099 
01100 static void
01101 sha1_hash(NSSItem *input, NSSItem *output)
01102 {
01103     NSSAlgorithmAndParameters *ap;
01104 #ifdef NSS_3_4_CODE
01105     PK11SlotInfo *internal = PK11_GetInternalSlot();
01106     NSSToken *token = PK11Slot_GetNSSToken(internal);
01107 #else
01108     NSSToken *token = nss_GetDefaultCryptoToken();
01109 #endif
01110     ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
01111     (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
01112 #ifdef NSS_3_4_CODE
01113     PK11_FreeSlot(token->pk11slot);
01114 #endif
01115     nss_ZFreeIf(ap);
01116 }
01117 
01118 static void
01119 md5_hash(NSSItem *input, NSSItem *output)
01120 {
01121     NSSAlgorithmAndParameters *ap;
01122 #ifdef NSS_3_4_CODE
01123     PK11SlotInfo *internal = PK11_GetInternalSlot();
01124     NSSToken *token = PK11Slot_GetNSSToken(internal);
01125 #else
01126     NSSToken *token = nss_GetDefaultCryptoToken();
01127 #endif
01128     ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
01129     (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
01130 #ifdef NSS_3_4_CODE
01131     PK11_FreeSlot(token->pk11slot);
01132 #endif
01133     nss_ZFreeIf(ap);
01134 }
01135 
01136 static CK_TRUST
01137 get_ck_trust (
01138   nssTrustLevel nssTrust
01139 )
01140 {
01141     CK_TRUST t;
01142     switch (nssTrust) {
01143     case nssTrustLevel_NotTrusted: t = CKT_NETSCAPE_UNTRUSTED; break;
01144     case nssTrustLevel_TrustedDelegator: t = CKT_NETSCAPE_TRUSTED_DELEGATOR; 
01145        break;
01146     case nssTrustLevel_ValidDelegator: t = CKT_NETSCAPE_VALID_DELEGATOR; break;
01147     case nssTrustLevel_Trusted: t = CKT_NETSCAPE_TRUSTED; break;
01148     case nssTrustLevel_Valid: t = CKT_NETSCAPE_VALID; break;
01149     case nssTrustLevel_Unknown:
01150     default: t = CKT_NETSCAPE_TRUST_UNKNOWN; break;
01151     }
01152     return t;
01153 }
01154  
01155 NSS_IMPLEMENT nssCryptokiObject *
01156 nssToken_ImportTrust (
01157   NSSToken *tok,
01158   nssSession *sessionOpt,
01159   NSSDER *certEncoding,
01160   NSSDER *certIssuer,
01161   NSSDER *certSerial,
01162   nssTrustLevel serverAuth,
01163   nssTrustLevel clientAuth,
01164   nssTrustLevel codeSigning,
01165   nssTrustLevel emailProtection,
01166   PRBool stepUpApproved,
01167   PRBool asTokenObject
01168 )
01169 {
01170     nssCryptokiObject *object;
01171     CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
01172     CK_TRUST ckSA, ckCA, ckCS, ckEP;
01173     CK_ATTRIBUTE_PTR attr;
01174     CK_ATTRIBUTE trust_tmpl[11];
01175     CK_ULONG tsize;
01176     PRUint8 sha1[20]; /* this is cheating... */
01177     PRUint8 md5[16];
01178     NSSItem sha1_result, md5_result;
01179     sha1_result.data = sha1; sha1_result.size = sizeof sha1;
01180     md5_result.data = md5; md5_result.size = sizeof md5;
01181     sha1_hash(certEncoding, &sha1_result);
01182     md5_hash(certEncoding, &md5_result);
01183     ckSA = get_ck_trust(serverAuth);
01184     ckCA = get_ck_trust(clientAuth);
01185     ckCS = get_ck_trust(codeSigning);
01186     ckEP = get_ck_trust(emailProtection);
01187     NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
01188     if (asTokenObject) {
01189        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01190     } else {
01191        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01192     }
01193     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
01194     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
01195     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
01196     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
01197     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
01198     /* now set the trust values */
01199     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
01200     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
01201     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
01202     NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
01203     if (stepUpApproved) {
01204        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
01205                                  &g_ck_true);
01206     } else {
01207        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
01208                                  &g_ck_false);
01209     }
01210     NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
01211     /* import the trust object onto the token */
01212     object = import_object(tok, sessionOpt, trust_tmpl, tsize);
01213     if (object && tok->cache) {
01214        nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
01215                                         trust_tmpl, tsize);
01216     }
01217     return object;
01218 }
01219 
01220 NSS_IMPLEMENT nssCryptokiObject **
01221 nssToken_FindTrustObjects (
01222   NSSToken *token,
01223   nssSession *sessionOpt,
01224   nssTokenSearchType searchType,
01225   PRUint32 maximumOpt,
01226   PRStatus *statusOpt
01227 )
01228 {
01229     CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
01230     CK_ATTRIBUTE_PTR attr;
01231     CK_ATTRIBUTE tobj_template[2];
01232     CK_ULONG tobj_size;
01233     nssCryptokiObject **objects;
01234     nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
01235 
01236     NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
01237     if (searchType == nssTokenSearchType_SessionOnly) {
01238        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01239     } else if (searchType == nssTokenSearchType_TokenOnly ||
01240                searchType == nssTokenSearchType_TokenForced) {
01241        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01242     }
01243     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
01244     NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
01245 
01246     if (searchType == nssTokenSearchType_TokenForced) {
01247        objects = find_objects(token, session,
01248                               tobj_template, tobj_size,
01249                               maximumOpt, statusOpt);
01250     } else {
01251        objects = find_objects_by_template(token, session,
01252                                           tobj_template, tobj_size,
01253                                           maximumOpt, statusOpt);
01254     }
01255     return objects;
01256 }
01257 
01258 NSS_IMPLEMENT nssCryptokiObject *
01259 nssToken_FindTrustForCertificate (
01260   NSSToken *token,
01261   nssSession *sessionOpt,
01262   NSSDER *certEncoding,
01263   NSSDER *certIssuer,
01264   NSSDER *certSerial,
01265   nssTokenSearchType searchType
01266 )
01267 {
01268     CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
01269     CK_ATTRIBUTE_PTR attr;
01270     CK_ATTRIBUTE tobj_template[5];
01271     CK_ULONG tobj_size;
01272     nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
01273     nssCryptokiObject *object, **objects;
01274 
01275     NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
01276     if (searchType == nssTokenSearchType_SessionOnly) {
01277        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01278     } else if (searchType == nssTokenSearchType_TokenOnly) {
01279        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01280     }
01281     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
01282     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
01283     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
01284     NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
01285     object = NULL;
01286     objects = find_objects_by_template(token, session,
01287                                        tobj_template, tobj_size,
01288                                        1, NULL);
01289     if (objects) {
01290        object = objects[0];
01291        nss_ZFreeIf(objects);
01292     }
01293     return object;
01294 }
01295  
01296 NSS_IMPLEMENT nssCryptokiObject *
01297 nssToken_ImportCRL (
01298   NSSToken *token,
01299   nssSession *sessionOpt,
01300   NSSDER *subject,
01301   NSSDER *encoding,
01302   PRBool isKRL,
01303   NSSUTF8 *url,
01304   PRBool asTokenObject
01305 )
01306 {
01307     nssCryptokiObject *object;
01308     CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
01309     CK_ATTRIBUTE_PTR attr;
01310     CK_ATTRIBUTE crl_tmpl[6];
01311     CK_ULONG crlsize;
01312 
01313     NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
01314     if (asTokenObject) {
01315        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01316     } else {
01317        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01318     }
01319     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
01320     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
01321     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
01322     NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NETSCAPE_URL, url);
01323     if (isKRL) {
01324        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_true);
01325     } else {
01326        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NETSCAPE_KRL, &g_ck_false);
01327     }
01328     NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
01329 
01330     /* import the crl object onto the token */
01331     object = import_object(token, sessionOpt, crl_tmpl, crlsize);
01332     if (object && token->cache) {
01333        nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
01334                                         crl_tmpl, crlsize);
01335     }
01336     return object;
01337 }
01338 
01339 NSS_IMPLEMENT nssCryptokiObject **
01340 nssToken_FindCRLs (
01341   NSSToken *token,
01342   nssSession *sessionOpt,
01343   nssTokenSearchType searchType,
01344   PRUint32 maximumOpt,
01345   PRStatus *statusOpt
01346 )
01347 {
01348     CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
01349     CK_ATTRIBUTE_PTR attr;
01350     CK_ATTRIBUTE crlobj_template[2];
01351     CK_ULONG crlobj_size;
01352     nssCryptokiObject **objects;
01353     nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
01354 
01355     NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
01356     if (searchType == nssTokenSearchType_SessionOnly) {
01357        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01358     } else if (searchType == nssTokenSearchType_TokenOnly ||
01359                searchType == nssTokenSearchType_TokenForced) {
01360        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01361     }
01362     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
01363     NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
01364 
01365     if (searchType == nssTokenSearchType_TokenForced) {
01366        objects = find_objects(token, session,
01367                               crlobj_template, crlobj_size,
01368                               maximumOpt, statusOpt);
01369     } else {
01370        objects = find_objects_by_template(token, session,
01371                                           crlobj_template, crlobj_size,
01372                                           maximumOpt, statusOpt);
01373     }
01374     return objects;
01375 }
01376 
01377 NSS_IMPLEMENT nssCryptokiObject **
01378 nssToken_FindCRLsBySubject (
01379   NSSToken *token,
01380   nssSession *sessionOpt,
01381   NSSDER *subject,
01382   nssTokenSearchType searchType,
01383   PRUint32 maximumOpt,
01384   PRStatus *statusOpt
01385 )
01386 {
01387     CK_OBJECT_CLASS crlobjc = CKO_NETSCAPE_CRL;
01388     CK_ATTRIBUTE_PTR attr;
01389     CK_ATTRIBUTE crlobj_template[3];
01390     CK_ULONG crlobj_size;
01391     nssCryptokiObject **objects;
01392     nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
01393 
01394     NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
01395     if (searchType == nssTokenSearchType_SessionOnly) {
01396        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01397     } else if (searchType == nssTokenSearchType_TokenOnly ||
01398                searchType == nssTokenSearchType_TokenForced) {
01399        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01400     }
01401     NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
01402     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
01403     NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
01404 
01405     objects = find_objects_by_template(token, session,
01406                                        crlobj_template, crlobj_size,
01407                                        maximumOpt, statusOpt);
01408     return objects;
01409 }
01410 
01411 NSS_IMPLEMENT PRStatus
01412 nssToken_GetCachedObjectAttributes (
01413   NSSToken *token,
01414   NSSArena *arenaOpt,
01415   nssCryptokiObject *object,
01416   CK_OBJECT_CLASS objclass,
01417   CK_ATTRIBUTE_PTR atemplate,
01418   CK_ULONG atlen
01419 )
01420 {
01421     if (!token->cache) {
01422        return PR_FAILURE;
01423     }
01424     return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
01425                                                    object, objclass,
01426                                                    atemplate, atlen);
01427 }
01428 
01429 NSS_IMPLEMENT NSSItem *
01430 nssToken_Digest (
01431   NSSToken *tok,
01432   nssSession *sessionOpt,
01433   NSSAlgorithmAndParameters *ap,
01434   NSSItem *data,
01435   NSSItem *rvOpt,
01436   NSSArena *arenaOpt
01437 )
01438 {
01439     CK_RV ckrv;
01440     CK_ULONG digestLen;
01441     CK_BYTE_PTR digest;
01442     NSSItem *rvItem = NULL;
01443     void *epv = nssToken_GetCryptokiEPV(tok);
01444     nssSession *session;
01445     session = (sessionOpt) ? sessionOpt : tok->defaultSession;
01446     nssSession_EnterMonitor(session);
01447     ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
01448     if (ckrv != CKR_OK) {
01449        nssSession_ExitMonitor(session);
01450        return NULL;
01451     }
01452 #if 0
01453     /* XXX the standard says this should work, but it doesn't */
01454     ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
01455     if (ckrv != CKR_OK) {
01456        nssSession_ExitMonitor(session);
01457        return NULL;
01458     }
01459 #endif
01460     digestLen = 0; /* XXX for now */
01461     digest = NULL;
01462     if (rvOpt) {
01463        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
01464            nssSession_ExitMonitor(session);
01465            /* the error should be bad args */
01466            return NULL;
01467        }
01468        if (rvOpt->data) {
01469            digest = rvOpt->data;
01470        }
01471        digestLen = rvOpt->size;
01472     }
01473     if (!digest) {
01474        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
01475        if (!digest) {
01476            nssSession_ExitMonitor(session);
01477            return NULL;
01478        }
01479     }
01480     ckrv = CKAPI(epv)->C_Digest(session->handle, 
01481                                 (CK_BYTE_PTR)data->data, 
01482                                 (CK_ULONG)data->size,
01483                                 (CK_BYTE_PTR)digest,
01484                                 &digestLen);
01485     nssSession_ExitMonitor(session);
01486     if (ckrv != CKR_OK) {
01487        nss_ZFreeIf(digest);
01488        return NULL;
01489     }
01490     if (!rvOpt) {
01491        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
01492     }
01493     return rvItem;
01494 }
01495 
01496 NSS_IMPLEMENT PRStatus
01497 nssToken_BeginDigest (
01498   NSSToken *tok,
01499   nssSession *sessionOpt,
01500   NSSAlgorithmAndParameters *ap
01501 )
01502 {
01503     CK_RV ckrv;
01504     nssSession *session;
01505     void *epv = nssToken_GetCryptokiEPV(tok);
01506     session = (sessionOpt) ? sessionOpt : tok->defaultSession;
01507     nssSession_EnterMonitor(session);
01508     ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
01509     nssSession_ExitMonitor(session);
01510     return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
01511 }
01512 
01513 NSS_IMPLEMENT PRStatus
01514 nssToken_ContinueDigest (
01515   NSSToken *tok,
01516   nssSession *sessionOpt,
01517   NSSItem *item
01518 )
01519 {
01520     CK_RV ckrv;
01521     nssSession *session;
01522     void *epv = nssToken_GetCryptokiEPV(tok);
01523     session = (sessionOpt) ? sessionOpt : tok->defaultSession;
01524     nssSession_EnterMonitor(session);
01525     ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
01526                                       (CK_BYTE_PTR)item->data, 
01527                                       (CK_ULONG)item->size);
01528     nssSession_ExitMonitor(session);
01529     return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
01530 }
01531 
01532 NSS_IMPLEMENT NSSItem *
01533 nssToken_FinishDigest (
01534   NSSToken *tok,
01535   nssSession *sessionOpt,
01536   NSSItem *rvOpt,
01537   NSSArena *arenaOpt
01538 )
01539 {
01540     CK_RV ckrv;
01541     CK_ULONG digestLen;
01542     CK_BYTE_PTR digest;
01543     NSSItem *rvItem = NULL;
01544     void *epv = nssToken_GetCryptokiEPV(tok);
01545     nssSession *session;
01546     session = (sessionOpt) ? sessionOpt : tok->defaultSession;
01547     nssSession_EnterMonitor(session);
01548     ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
01549     if (ckrv != CKR_OK || digestLen == 0) {
01550        nssSession_ExitMonitor(session);
01551        return NULL;
01552     }
01553     digest = NULL;
01554     if (rvOpt) {
01555        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
01556            nssSession_ExitMonitor(session);
01557            /* the error should be bad args */
01558            return NULL;
01559        }
01560        if (rvOpt->data) {
01561            digest = rvOpt->data;
01562        }
01563        digestLen = rvOpt->size;
01564     }
01565     if (!digest) {
01566        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
01567        if (!digest) {
01568            nssSession_ExitMonitor(session);
01569            return NULL;
01570        }
01571     }
01572     ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
01573     nssSession_ExitMonitor(session);
01574     if (ckrv != CKR_OK) {
01575        nss_ZFreeIf(digest);
01576        return NULL;
01577     }
01578     if (!rvOpt) {
01579        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
01580     }
01581     return rvItem;
01582 }
01583 
01584 NSS_IMPLEMENT PRBool
01585 nssToken_IsPresent (
01586   NSSToken *token
01587 )
01588 {
01589     return nssSlot_IsTokenPresent(token->slot);
01590 }
01591 
01592 /* Sigh.  The methods to find objects declared above cause problems with
01593  * the low-level object cache in the softoken -- the objects are found in 
01594  * toto, then one wave of GetAttributes is done, then another.  Having a 
01595  * large number of objects causes the cache to be thrashed, as the objects 
01596  * are gone before there's any chance to ask for their attributes.
01597  * So, for now, bringing back traversal methods for certs.  This way all of 
01598  * the cert's attributes can be grabbed immediately after finding it,
01599  * increasing the likelihood that the cache takes care of it.
01600  */
01601 NSS_IMPLEMENT PRStatus
01602 nssToken_TraverseCertificates (
01603   NSSToken *token,
01604   nssSession *sessionOpt,
01605   nssTokenSearchType searchType,
01606   PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
01607   void *arg
01608 )
01609 {
01610     CK_RV ckrv;
01611     CK_ULONG count;
01612     CK_OBJECT_HANDLE *objectHandles;
01613     CK_ATTRIBUTE_PTR attr;
01614     CK_ATTRIBUTE cert_template[2];
01615     CK_ULONG ctsize;
01616     NSSArena *arena;
01617     PRStatus status;
01618     PRUint32 arraySize, numHandles;
01619     nssCryptokiObject **objects;
01620     void *epv = nssToken_GetCryptokiEPV(token);
01621     nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
01622 
01623     /* template for all certs */
01624     NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
01625     if (searchType == nssTokenSearchType_SessionOnly) {
01626        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
01627     } else if (searchType == nssTokenSearchType_TokenOnly ||
01628                searchType == nssTokenSearchType_TokenForced) {
01629        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
01630     }
01631     NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
01632     NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
01633 
01634     /* the arena is only for the array of object handles */
01635     arena = nssArena_Create();
01636     if (!arena) {
01637        return PR_FAILURE;
01638     }
01639     arraySize = OBJECT_STACK_SIZE;
01640     numHandles = 0;
01641     objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
01642     if (!objectHandles) {
01643        goto loser;
01644     }
01645     nssSession_EnterMonitor(session); /* ==== session lock === */
01646     /* Initialize the find with the template */
01647     ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
01648                                          cert_template, ctsize);
01649     if (ckrv != CKR_OK) {
01650        nssSession_ExitMonitor(session);
01651        goto loser;
01652     }
01653     while (PR_TRUE) {
01654        /* Issue the find for up to arraySize - numHandles objects */
01655        ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
01656                                         objectHandles + numHandles, 
01657                                         arraySize - numHandles, 
01658                                         &count);
01659        if (ckrv != CKR_OK) {
01660            nssSession_ExitMonitor(session);
01661            goto loser;
01662        }
01663        /* bump the number of found objects */
01664        numHandles += count;
01665        if (numHandles < arraySize) {
01666            break;
01667        }
01668        /* the array is filled, double it and continue */
01669        arraySize *= 2;
01670        objectHandles = nss_ZREALLOCARRAY(objectHandles, 
01671                                          CK_OBJECT_HANDLE, 
01672                                          arraySize);
01673        if (!objectHandles) {
01674            nssSession_ExitMonitor(session);
01675            goto loser;
01676        }
01677     }
01678     ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
01679     nssSession_ExitMonitor(session); /* ==== end session lock === */
01680     if (ckrv != CKR_OK) {
01681        goto loser;
01682     }
01683     if (numHandles > 0) {
01684        objects = create_objects_from_handles(token, session,
01685                                              objectHandles, numHandles);
01686        if (objects) {
01687            nssCryptokiObject **op;
01688            for (op = objects; *op; op++) {
01689               status = (*callback)(*op, arg);
01690            }
01691            nss_ZFreeIf(objects);
01692        }
01693     }
01694     nssArena_Destroy(arena);
01695     return PR_SUCCESS;
01696 loser:
01697     nssArena_Destroy(arena);
01698     return PR_FAILURE;
01699 }
01700 
01701 NSS_IMPLEMENT PRBool
01702 nssToken_IsPrivateKeyAvailable (
01703   NSSToken *token,
01704   NSSCertificate *c,
01705   nssCryptokiObject *instance
01706 )
01707 {
01708     CK_OBJECT_CLASS theClass;
01709 
01710     if (token == NULL) return PR_FALSE;
01711     if (c == NULL) return PR_FALSE;
01712 
01713     theClass = CKO_PRIVATE_KEY;
01714     if (!nssSlot_IsLoggedIn(token->slot)) {
01715        theClass = CKO_PUBLIC_KEY;
01716     }
01717     if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
01718                                           != CK_INVALID_HANDLE) {
01719        return PR_TRUE;
01720     }
01721     return PR_FALSE;
01722 }