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