diff nss/lib/dev/devtoken.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/dev/devtoken.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,1580 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "pkcs11.h"
+
+#ifndef DEVM_H
+#include "devm.h"
+#endif /* DEVM_H */
+
+#ifndef CKHELPER_H
+#include "ckhelper.h"
+#endif /* CKHELPER_H */
+
+#include "pk11func.h"
+#include "dev3hack.h"
+#include "secerr.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+extern const NSSError NSS_ERROR_PKCS11;
+
+/* The number of object handles to grab during each call to C_FindObjects */
+#define OBJECT_STACK_SIZE 16
+
+NSS_IMPLEMENT PRStatus
+nssToken_Destroy (
+  NSSToken *tok
+)
+{
+    if (tok) {
+	if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
+	    PZ_DestroyLock(tok->base.lock);
+	    nssTokenObjectCache_Destroy(tok->cache);
+	    /* The token holds the first/last reference to the slot.
+	     * When the token is actually destroyed, that ref must go too.
+	     */
+	    (void)nssSlot_Destroy(tok->slot);
+	    return nssArena_Destroy(tok->base.arena);
+	}
+    }
+    return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void
+nssToken_Remove (
+  NSSToken *tok
+)
+{
+    nssTokenObjectCache_Clear(tok->cache);
+}
+
+NSS_IMPLEMENT void
+NSSToken_Destroy (
+  NSSToken *tok
+)
+{
+    (void)nssToken_Destroy(tok);
+}
+
+NSS_IMPLEMENT NSSToken *
+nssToken_AddRef (
+  NSSToken *tok
+)
+{
+    PR_ATOMIC_INCREMENT(&tok->base.refCount);
+    return tok;
+}
+
+NSS_IMPLEMENT NSSSlot *
+nssToken_GetSlot (
+  NSSToken *tok
+)
+{
+    return nssSlot_AddRef(tok->slot);
+}
+
+NSS_IMPLEMENT void *
+nssToken_GetCryptokiEPV (
+  NSSToken *token
+)
+{
+    return nssSlot_GetCryptokiEPV(token->slot);
+}
+
+NSS_IMPLEMENT nssSession *
+nssToken_GetDefaultSession (
+  NSSToken *token
+)
+{
+    return token->defaultSession;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssToken_GetName (
+  NSSToken *tok
+)
+{
+    if (tok == NULL) {
+	return "";
+    }
+    if (tok->base.name[0] == 0) {
+	(void) nssSlot_IsTokenPresent(tok->slot);
+    } 
+    return tok->base.name;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+NSSToken_GetName (
+  NSSToken *token
+)
+{
+    return nssToken_GetName(token);
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_IsLoginRequired (
+  NSSToken *token
+)
+{
+    return (token->ckFlags & CKF_LOGIN_REQUIRED);
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_NeedsPINInitialization (
+  NSSToken *token
+)
+{
+    return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_DeleteStoredObject (
+  nssCryptokiObject *instance
+)
+{
+    CK_RV ckrv;
+    PRStatus status;
+    PRBool createdSession = PR_FALSE;
+    NSSToken *token = instance->token;
+    nssSession *session = NULL;
+    void *epv = nssToken_GetCryptokiEPV(instance->token);
+    if (token->cache) {
+	nssTokenObjectCache_RemoveObject(token->cache, instance);
+    }
+    if (instance->isTokenObject) {
+       if (token->defaultSession && 
+           nssSession_IsReadWrite(token->defaultSession)) {
+	   session = token->defaultSession;
+       } else {
+	   session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
+	   createdSession = PR_TRUE;
+       }
+    }
+    if (session == NULL) {
+	return PR_FAILURE;
+    }
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
+    nssSession_ExitMonitor(session);
+    if (createdSession) {
+	nssSession_Destroy(session);
+    }
+    status = PR_SUCCESS;
+    if (ckrv != CKR_OK) {
+	status = PR_FAILURE;
+	/* use the error stack to pass the PKCS #11 error out  */
+	nss_SetError(ckrv);
+	nss_SetError(NSS_ERROR_PKCS11);
+    }
+    return status;
+}
+
+static nssCryptokiObject *
+import_object (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  CK_ATTRIBUTE_PTR objectTemplate,
+  CK_ULONG otsize
+)
+{
+    nssSession *session = NULL;
+    PRBool createdSession = PR_FALSE;
+    nssCryptokiObject *object = NULL;
+    CK_OBJECT_HANDLE handle;
+    CK_RV ckrv;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
+	if (sessionOpt) {
+	    if (!nssSession_IsReadWrite(sessionOpt)) {
+		nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+		return NULL;
+	    }
+	    session = sessionOpt;
+	} else if (tok->defaultSession && 
+	           nssSession_IsReadWrite(tok->defaultSession)) {
+	    session = tok->defaultSession;
+	} else {
+	    session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
+	    createdSession = PR_TRUE;
+	}
+    } else {
+	session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+    }
+    if (session == NULL) {
+	nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+	return NULL;
+    }
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_CreateObject(session->handle, 
+                                      objectTemplate, otsize,
+                                      &handle);
+    nssSession_ExitMonitor(session);
+    if (ckrv == CKR_OK) {
+	object = nssCryptokiObject_Create(tok, session, handle);
+    } else {
+	nss_SetError(ckrv);
+	nss_SetError(NSS_ERROR_PKCS11);
+    }
+    if (createdSession) {
+	nssSession_Destroy(session);
+    }
+    return object;
+}
+
+static nssCryptokiObject **
+create_objects_from_handles (
+  NSSToken *tok,
+  nssSession *session,
+  CK_OBJECT_HANDLE *handles,
+  PRUint32 numH
+)
+{
+    nssCryptokiObject **objects;
+    objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
+    if (objects) {
+	PRInt32 i;
+	for (i=0; i<(PRInt32)numH; i++) {
+	    objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
+	    if (!objects[i]) {
+		for (--i; i>0; --i) {
+		    nssCryptokiObject_Destroy(objects[i]);
+		}
+		nss_ZFreeIf(objects);
+		objects = NULL;
+		break;
+	    }
+	}
+    }
+    return objects;
+}
+
+static nssCryptokiObject **
+find_objects (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG otsize,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_RV ckrv = CKR_OK;
+    CK_ULONG count;
+    CK_OBJECT_HANDLE *objectHandles = NULL;
+    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
+    PRUint32 arraySize, numHandles;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssCryptokiObject **objects;
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	ckrv = CKR_SESSION_HANDLE_INVALID;
+	goto loser;                
+    }
+
+    /* the arena is only for the array of object handles */
+    if (maximumOpt > 0) {
+	arraySize = maximumOpt;
+    } else {
+	arraySize = OBJECT_STACK_SIZE;
+    }
+    numHandles = 0;
+    if (arraySize <= OBJECT_STACK_SIZE) {
+	objectHandles = staticObjects;
+    } else {
+	objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
+    }
+    if (!objectHandles) {
+	ckrv = CKR_HOST_MEMORY;
+	goto loser;
+    }
+    nssSession_EnterMonitor(session); /* ==== session lock === */
+    /* Initialize the find with the template */
+    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
+                                         obj_template, otsize);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	goto loser;
+    }
+    while (PR_TRUE) {
+	/* Issue the find for up to arraySize - numHandles objects */
+	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
+	                                 objectHandles + numHandles, 
+	                                 arraySize - numHandles, 
+	                                 &count);
+	if (ckrv != CKR_OK) {
+	    nssSession_ExitMonitor(session);
+	    goto loser;
+	}
+	/* bump the number of found objects */
+	numHandles += count;
+	if (maximumOpt > 0 || numHandles < arraySize) {
+	    /* When a maximum is provided, the search is done all at once,
+	     * so the search is finished.  If the number returned was less 
+	     * than the number sought, the search is finished.
+	     */
+	    break;
+	}
+	/* the array is filled, double it and continue */
+	arraySize *= 2;
+	if (objectHandles == staticObjects) {
+	    objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
+	    if (objectHandles) {
+		PORT_Memcpy(objectHandles, staticObjects, 
+			OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
+	    }
+	} else {
+	    objectHandles = nss_ZREALLOCARRAY(objectHandles, 
+	                                  CK_OBJECT_HANDLE, 
+	                                  arraySize);
+	}
+	if (!objectHandles) {
+	    nssSession_ExitMonitor(session);
+	    ckrv = CKR_HOST_MEMORY;
+	    goto loser;
+	}
+    }
+    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
+    nssSession_ExitMonitor(session); /* ==== end session lock === */
+    if (ckrv != CKR_OK) {
+	goto loser;
+    }
+    if (numHandles > 0) {
+	objects = create_objects_from_handles(tok, session,
+	                                      objectHandles, numHandles);
+    } else {
+	nss_SetError(NSS_ERROR_NOT_FOUND);
+	objects = NULL;
+    }
+    if (objectHandles && objectHandles != staticObjects) {
+	nss_ZFreeIf(objectHandles);
+    }
+    if (statusOpt) *statusOpt = PR_SUCCESS;
+    return objects;
+loser:
+    if (objectHandles && objectHandles != staticObjects) {
+	nss_ZFreeIf(objectHandles);
+    }
+    /*
+     * These errors should be treated the same as if the objects just weren't
+     * found..
+     */
+    if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
+	(ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
+	(ckrv == CKR_DATA_INVALID) ||
+	(ckrv == CKR_DATA_LEN_RANGE) ||
+	(ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
+	(ckrv == CKR_TEMPLATE_INCOMPLETE) ||
+	(ckrv == CKR_TEMPLATE_INCONSISTENT)) {
+
+	nss_SetError(NSS_ERROR_NOT_FOUND);
+	if (statusOpt) *statusOpt = PR_SUCCESS;
+    } else {
+	nss_SetError(ckrv);
+	nss_SetError(NSS_ERROR_PKCS11);
+	if (statusOpt) *statusOpt = PR_FAILURE;
+    }
+    return (nssCryptokiObject **)NULL;
+}
+
+static nssCryptokiObject **
+find_objects_by_template (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  CK_ATTRIBUTE_PTR obj_template,
+  CK_ULONG otsize,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
+    nssCryptokiObject **objects = NULL;
+    PRUint32 i;
+
+    if (!token) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	if (statusOpt) 
+	    *statusOpt = PR_FAILURE;
+	return NULL;
+    }
+    for (i=0; i<otsize; i++) {
+	if (obj_template[i].type == CKA_CLASS) {
+	    objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
+	    break;
+	}
+    }
+    PR_ASSERT(i < otsize);
+    if (i == otsize) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	if (statusOpt) *statusOpt = PR_FAILURE;
+	return NULL;
+    }
+    /* If these objects are being cached, try looking there first */
+    if (token->cache && 
+        nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) 
+    {
+	PRStatus status;
+	objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
+	                                                    objclass,
+	                                                    obj_template,
+	                                                    otsize,
+	                                                    maximumOpt,
+	                                                    &status);
+	if (status == PR_SUCCESS) {
+	    if (statusOpt) *statusOpt = status;
+	    return objects;
+	}
+    }
+    /* Either they are not cached, or cache failed; look on token. */
+    objects = find_objects(token, sessionOpt, 
+                           obj_template, otsize, 
+                           maximumOpt, statusOpt);
+    return objects;
+}
+
+extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_ImportCertificate (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSCertificateType certType,
+  NSSItem *id,
+  const NSSUTF8 *nickname,
+  NSSDER *encoding,
+  NSSDER *issuer,
+  NSSDER *subject,
+  NSSDER *serial,
+  NSSASCII7 *email,
+  PRBool asTokenObject
+)
+{
+    PRStatus status;
+    CK_CERTIFICATE_TYPE cert_type;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_tmpl[10];
+    CK_ULONG ctsize;
+    nssTokenSearchType searchType;
+    nssCryptokiObject *rvObject = NULL;
+
+    if (!tok) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+    if (certType == NSSCertificateType_PKIX) {
+	cert_type = CKC_X_509;
+    } else {
+	return (nssCryptokiObject *)NULL;
+    }
+    NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
+    if (asTokenObject) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+	searchType = nssTokenSearchType_TokenOnly;
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+	searchType = nssTokenSearchType_SessionOnly;
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,            &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE,  cert_type);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,                id);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL,             nickname);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,             encoding);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,            issuer);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,           subject);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,     serial);
+    if (email) {
+	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL,    email);
+    }
+    NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
+    /* see if the cert is already there */
+    rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
+                                                               sessionOpt,
+                                                               issuer,
+                                                               serial,
+                                                               searchType,
+                                                               NULL);
+    if (rvObject) {
+	NSSItem existingDER;
+	NSSSlot *slot = nssToken_GetSlot(tok);
+	nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
+	if (!session) {
+	    nssCryptokiObject_Destroy(rvObject);
+	    nssSlot_Destroy(slot);
+	    return (nssCryptokiObject *)NULL;
+	}
+	/* Reject any attempt to import a new cert that has the same
+	 * issuer/serial as an existing cert, but does not have the
+	 * same encoding
+	 */
+	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
+	NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
+	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
+	status = nssCKObject_GetAttributes(rvObject->handle, 
+	                                   cert_tmpl, ctsize, NULL,
+	                                   session, slot);
+	NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
+	if (status == PR_SUCCESS) {
+	    if (!nssItem_Equal(encoding, &existingDER, NULL)) {
+		nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
+		status = PR_FAILURE;
+	    }
+	    nss_ZFreeIf(existingDER.data);
+	}
+	if (status == PR_FAILURE) {
+	    nssCryptokiObject_Destroy(rvObject);
+	    nssSession_Destroy(session);
+	    nssSlot_Destroy(slot);
+	    return (nssCryptokiObject *)NULL;
+	}
+	/* according to PKCS#11, label, ID, issuer, and serial number 
+	 * may change after the object has been created.  For PKIX, the
+	 * last two attributes can't change, so for now we'll only worry
+	 * about the first two.
+	 */
+	NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID,    id);
+	NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
+	NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
+	/* reset the mutable attributes on the token */
+	nssCKObject_SetAttributes(rvObject->handle, 
+	                          cert_tmpl, ctsize,
+	                          session, slot);
+	if (!rvObject->label && nickname) {
+	    rvObject->label = nssUTF8_Duplicate(nickname, NULL);
+	}
+	nssSession_Destroy(session);
+	nssSlot_Destroy(slot);
+    } else {
+	/* Import the certificate onto the token */
+	rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
+    }
+    if (rvObject && tok->cache) {
+	/* The cache will overwrite the attributes if the object already
+	 * exists.
+	 */
+	nssTokenObjectCache_ImportObject(tok->cache, rvObject,
+	                                 CKO_CERTIFICATE,
+	                                 cert_tmpl, ctsize);
+    }
+    return rvObject;
+}
+
+/* traverse all objects of the given class - this should only happen
+ * if the token has been marked as "traversable"
+ */
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindObjects (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  CK_OBJECT_CLASS objclass,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE obj_template[2];
+    CK_ULONG obj_size;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly ||
+               searchType == nssTokenSearchType_TokenForced) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
+    NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
+
+    if (searchType == nssTokenSearchType_TokenForced) {
+	objects = find_objects(token, sessionOpt,
+	                       obj_template, obj_size,
+	                       maximumOpt, statusOpt);
+    } else {
+	objects = find_objects_by_template(token, sessionOpt,
+	                                   obj_template, obj_size,
+	                                   maximumOpt, statusOpt);
+    }
+    return objects;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesBySubject (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE subj_template[3];
+    CK_ULONG stsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
+    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       subj_template, stsize,
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesByNickname (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  const NSSUTF8 *name,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE nick_template[3];
+    CK_ULONG ntsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       nick_template, ntsize, 
+                                       maximumOpt, statusOpt);
+    if (!objects) {
+	/* This is to workaround the fact that PKCS#11 doesn't specify
+	 * whether the '\0' should be included.  XXX Is that still true?
+	 * im - this is not needed by the current softoken.  However, I'm 
+	 * leaving it in until I have surveyed more tokens to see if it needed.
+	 * well, its needed by the builtin token...
+	 */
+	nick_template[0].ulValueLen++;
+	objects = find_objects_by_template(token, sessionOpt,
+	                                   nick_template, ntsize, 
+	                                   maximumOpt, statusOpt);
+    }
+    return objects;
+}
+
+/* XXX
+ * This function *does not* use the token object cache, because not even
+ * the softoken will return a value for CKA_NSS_EMAIL from a call
+ * to GetAttributes.  The softoken does allow searches with that attribute,
+ * it just won't return a value for it.
+ */
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesByEmail (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSASCII7 *email,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE email_template[3];
+    CK_ULONG etsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(email_template, attr, etsize);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects(token, sessionOpt,
+                           email_template, etsize,
+                           maximumOpt, statusOpt);
+    if (!objects) {
+	/* This is to workaround the fact that PKCS#11 doesn't specify
+	 * whether the '\0' should be included.  XXX Is that still true?
+	 * im - this is not needed by the current softoken.  However, I'm 
+	 * leaving it in until I have surveyed more tokens to see if it needed.
+	 * well, its needed by the builtin token...
+	 */
+	email_template[0].ulValueLen++;
+	objects = find_objects(token, sessionOpt,
+	                       email_template, etsize,
+	                       maximumOpt, statusOpt);
+    }
+    return objects;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCertificatesByID (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *id,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE id_template[3];
+    CK_ULONG idtsize;
+    nssCryptokiObject **objects;
+    NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
+    /* now locate the token certs matching this template */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       id_template, idtsize,
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+/*
+ * decode the serial item and return our result.
+ * NOTE serialDecode's data is really stored in serial. Don't free it.
+ */
+static PRStatus
+nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
+{
+    unsigned char *data = (unsigned char *)serial->data;
+    int data_left, data_len, index;
+
+    if ((serial->size >= 3) && (data[0] == 0x2)) {
+	/* remove the der encoding of the serial number before generating the
+	 * key.. */
+	data_left = serial->size-2;
+	data_len = data[1];
+	index = 2;
+
+	/* extended length ? (not very likely for a serial number) */
+	if (data_len & 0x80) {
+	    int len_count = data_len & 0x7f;
+
+	    data_len = 0;
+	    data_left -= len_count;
+	    if (data_left > 0) {
+		while (len_count --) {
+		    data_len = (data_len << 8) | data[index++];
+		}
+	    } 
+	}
+	/* XXX leaving any leading zeros on the serial number for backwards
+	 * compatibility
+	 */
+	/* not a valid der, must be just an unlucky serial number value */
+	if (data_len == data_left) {
+	    serialDecode->size = data_len;
+	    serialDecode->data = &data[index];
+	    return PR_SUCCESS;
+	}
+    }
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindCertificateByIssuerAndSerialNumber (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *issuer,
+  NSSDER *serial,
+  nssTokenSearchType searchType,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE_PTR serialAttr;
+    CK_ATTRIBUTE cert_template[4];
+    CK_ULONG ctsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvObject = NULL;
+    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
+
+    if (!token) {
+    	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	if (statusOpt) 
+	    *statusOpt = PR_FAILURE;
+	return NULL;
+    }
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
+               (searchType == nssTokenSearchType_TokenForced)) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    /* Set the unique id */
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS,         &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         issuer);
+    serialAttr = attr;
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,  serial);
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
+    /* get the object handle */
+    if (searchType == nssTokenSearchType_TokenForced) {
+	objects = find_objects(token, sessionOpt,
+	                       cert_template, ctsize,
+	                       1, statusOpt);
+    } else {
+	objects = find_objects_by_template(token, sessionOpt,
+                                       cert_template, ctsize,
+                                       1, statusOpt);
+    }
+    if (objects) {
+	rvObject = objects[0];
+	nss_ZFreeIf(objects);
+    }
+
+    /*
+     * NSS used to incorrectly store serial numbers in their decoded form.
+     * because of this old tokens have decoded serial numbers.
+     */
+    if (!objects) {
+	NSSItem serialDecode;
+	PRStatus status;
+
+	status = nssToken_decodeSerialItem(serial, &serialDecode);
+	if (status != PR_SUCCESS) {
+	    return NULL;
+	}
+    	NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
+	if (searchType == nssTokenSearchType_TokenForced) {
+	    objects = find_objects(token, sessionOpt,
+	                       cert_template, ctsize,
+	                       1, statusOpt);
+	} else {
+	    objects = find_objects_by_template(token, sessionOpt,
+                                       cert_template, ctsize,
+                                       1, statusOpt);
+	}
+	if (objects) {
+	    rvObject = objects[0];
+	    nss_ZFreeIf(objects);
+	}
+    }
+    return rvObject;
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindCertificateByEncodedCertificate (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSBER *encodedCertificate,
+  nssTokenSearchType searchType,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_template[3];
+    CK_ULONG ctsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvObject = NULL;
+    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
+    /* Set the search to token/session only if provided */
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
+    /* get the object handle */
+    objects = find_objects_by_template(token, sessionOpt,
+                                       cert_template, ctsize,
+                                       1, statusOpt);
+    if (objects) {
+	rvObject = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return rvObject;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindPrivateKeys (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[2];
+    CK_ULONG ktsize;
+    nssCryptokiObject **objects;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
+
+    objects = find_objects_by_template(token, sessionOpt,
+                                       key_template, ktsize, 
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+/* XXX ?there are no session cert objects, so only search token objects */
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindPrivateKeyByID (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *keyID
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[3];
+    CK_ULONG ktsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvKey = NULL;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
+
+    objects = find_objects_by_template(token, sessionOpt,
+                                       key_template, ktsize, 
+                                       1, NULL);
+    if (objects) {
+	rvKey = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return rvKey;
+}
+
+/* XXX ?there are no session cert objects, so only search token objects */
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindPublicKeyByID (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSItem *keyID
+)
+{
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE key_template[3];
+    CK_ULONG ktsize;
+    nssCryptokiObject **objects;
+    nssCryptokiObject *rvKey = NULL;
+
+    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
+    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
+
+    objects = find_objects_by_template(token, sessionOpt,
+                                       key_template, ktsize, 
+                                       1, NULL);
+    if (objects) {
+	rvKey = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return rvKey;
+}
+
+static void
+sha1_hash(NSSItem *input, NSSItem *output)
+{
+    NSSAlgorithmAndParameters *ap;
+    PK11SlotInfo *internal = PK11_GetInternalSlot();
+    NSSToken *token = PK11Slot_GetNSSToken(internal);
+    ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
+    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
+    PK11_FreeSlot(token->pk11slot);
+    nss_ZFreeIf(ap);
+}
+
+static void
+md5_hash(NSSItem *input, NSSItem *output)
+{
+    NSSAlgorithmAndParameters *ap;
+    PK11SlotInfo *internal = PK11_GetInternalSlot();
+    NSSToken *token = PK11Slot_GetNSSToken(internal);
+    ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
+    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
+    PK11_FreeSlot(token->pk11slot);
+    nss_ZFreeIf(ap);
+}
+
+static CK_TRUST
+get_ck_trust (
+  nssTrustLevel nssTrust
+)
+{
+    CK_TRUST t;
+    switch (nssTrust) {
+    case nssTrustLevel_NotTrusted: t = CKT_NSS_NOT_TRUSTED; break;
+    case nssTrustLevel_TrustedDelegator: t = CKT_NSS_TRUSTED_DELEGATOR; 
+	break;
+    case nssTrustLevel_ValidDelegator: t = CKT_NSS_VALID_DELEGATOR; break;
+    case nssTrustLevel_Trusted: t = CKT_NSS_TRUSTED; break;
+    case nssTrustLevel_MustVerify: t = CKT_NSS_MUST_VERIFY_TRUST; break;
+    case nssTrustLevel_Unknown:
+    default: t = CKT_NSS_TRUST_UNKNOWN; break;
+    }
+    return t;
+}
+ 
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_ImportTrust (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSDER *certEncoding,
+  NSSDER *certIssuer,
+  NSSDER *certSerial,
+  nssTrustLevel serverAuth,
+  nssTrustLevel clientAuth,
+  nssTrustLevel codeSigning,
+  nssTrustLevel emailProtection,
+  PRBool stepUpApproved,
+  PRBool asTokenObject
+)
+{
+    nssCryptokiObject *object;
+    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
+    CK_TRUST ckSA, ckCA, ckCS, ckEP;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE trust_tmpl[11];
+    CK_ULONG tsize;
+    PRUint8 sha1[20]; /* this is cheating... */
+    PRUint8 md5[16];
+    NSSItem sha1_result, md5_result;
+    sha1_result.data = sha1; sha1_result.size = sizeof sha1;
+    md5_result.data = md5; md5_result.size = sizeof md5;
+    sha1_hash(certEncoding, &sha1_result);
+    md5_hash(certEncoding, &md5_result);
+    ckSA = get_ck_trust(serverAuth);
+    ckCA = get_ck_trust(clientAuth);
+    ckCS = get_ck_trust(codeSigning);
+    ckEP = get_ck_trust(emailProtection);
+    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
+    if (asTokenObject) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,           tobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,          certIssuer);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER,   certSerial);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH,  &md5_result);
+    /* now set the trust values */
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH,      ckSA);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH,      ckCA);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING,     ckCS);
+    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
+    if (stepUpApproved) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
+	                          &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED, 
+	                          &g_ck_false);
+    }
+    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
+    /* import the trust object onto the token */
+    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
+    if (object && tok->cache) {
+	nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
+	                                 trust_tmpl, tsize);
+    }
+    return object;
+}
+
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_FindTrustForCertificate (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *certEncoding,
+  NSSDER *certIssuer,
+  NSSDER *certSerial,
+  nssTokenSearchType searchType
+)
+{
+    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE tobj_template[5];
+    CK_ULONG tobj_size;
+    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
+    nssCryptokiObject *object = NULL, **objects;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return object;
+    }
+
+    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
+    if (searchType == nssTokenSearchType_TokenOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,          tobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER,         certIssuer);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
+    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
+    objects = find_objects_by_template(token, session,
+                                       tobj_template, tobj_size,
+                                       1, NULL);
+    if (objects) {
+	object = objects[0];
+	nss_ZFreeIf(objects);
+    }
+    return object;
+}
+ 
+NSS_IMPLEMENT nssCryptokiObject *
+nssToken_ImportCRL (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  NSSDER *encoding,
+  PRBool isKRL,
+  NSSUTF8 *url,
+  PRBool asTokenObject
+)
+{
+    nssCryptokiObject *object;
+    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE crl_tmpl[6];
+    CK_ULONG crlsize;
+
+    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
+    if (asTokenObject) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS,        crlobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT,      subject);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE,        encoding);
+    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
+    if (isKRL) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
+    } else {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
+    }
+    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
+
+    /* import the crl object onto the token */
+    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
+    if (object && token->cache) {
+	nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
+	                                 crl_tmpl, crlsize);
+    }
+    return object;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssToken_FindCRLsBySubject (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  NSSDER *subject,
+  nssTokenSearchType searchType,
+  PRUint32 maximumOpt,
+  PRStatus *statusOpt
+)
+{
+    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE crlobj_template[3];
+    CK_ULONG crlobj_size;
+    nssCryptokiObject **objects = NULL;
+    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return objects;
+    }
+
+    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly ||
+               searchType == nssTokenSearchType_TokenForced) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
+    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
+
+    objects = find_objects_by_template(token, session,
+                                       crlobj_template, crlobj_size,
+                                       maximumOpt, statusOpt);
+    return objects;
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_GetCachedObjectAttributes (
+  NSSToken *token,
+  NSSArena *arenaOpt,
+  nssCryptokiObject *object,
+  CK_OBJECT_CLASS objclass,
+  CK_ATTRIBUTE_PTR atemplate,
+  CK_ULONG atlen
+)
+{
+    if (!token->cache) {
+	return PR_FAILURE;
+    }
+    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
+                                                   object, objclass,
+                                                   atemplate, atlen);
+}
+
+NSS_IMPLEMENT NSSItem *
+nssToken_Digest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSAlgorithmAndParameters *ap,
+  NSSItem *data,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    CK_RV ckrv;
+    CK_ULONG digestLen;
+    CK_BYTE_PTR digest;
+    NSSItem *rvItem = NULL;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return rvItem;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	return NULL;
+    }
+#if 0
+    /* XXX the standard says this should work, but it doesn't */
+    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	return NULL;
+    }
+#endif
+    digestLen = 0; /* XXX for now */
+    digest = NULL;
+    if (rvOpt) {
+	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
+	    nssSession_ExitMonitor(session);
+	    /* the error should be bad args */
+	    return NULL;
+	}
+	if (rvOpt->data) {
+	    digest = rvOpt->data;
+	}
+	digestLen = rvOpt->size;
+    }
+    if (!digest) {
+	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
+	if (!digest) {
+	    nssSession_ExitMonitor(session);
+	    return NULL;
+	}
+    }
+    ckrv = CKAPI(epv)->C_Digest(session->handle, 
+                                (CK_BYTE_PTR)data->data, 
+                                (CK_ULONG)data->size,
+                                (CK_BYTE_PTR)digest,
+                                &digestLen);
+    nssSession_ExitMonitor(session);
+    if (ckrv != CKR_OK) {
+	nss_ZFreeIf(digest);
+	return NULL;
+    }
+    if (!rvOpt) {
+	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
+    }
+    return rvItem;
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_BeginDigest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSAlgorithmAndParameters *ap
+)
+{
+    CK_RV ckrv;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return PR_FAILURE;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
+    nssSession_ExitMonitor(session);
+    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssToken_ContinueDigest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSItem *item
+)
+{
+    CK_RV ckrv;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return PR_FAILURE;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, 
+                                      (CK_BYTE_PTR)item->data, 
+                                      (CK_ULONG)item->size);
+    nssSession_ExitMonitor(session);
+    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+nssToken_FinishDigest (
+  NSSToken *tok,
+  nssSession *sessionOpt,
+  NSSItem *rvOpt,
+  NSSArena *arenaOpt
+)
+{
+    CK_RV ckrv;
+    CK_ULONG digestLen;
+    CK_BYTE_PTR digest;
+    NSSItem *rvItem = NULL;
+    void *epv = nssToken_GetCryptokiEPV(tok);
+    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return NULL;
+    }
+
+    nssSession_EnterMonitor(session);
+    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
+    if (ckrv != CKR_OK || digestLen == 0) {
+	nssSession_ExitMonitor(session);
+	return NULL;
+    }
+    digest = NULL;
+    if (rvOpt) {
+	if (rvOpt->size > 0 && rvOpt->size < digestLen) {
+	    nssSession_ExitMonitor(session);
+	    /* the error should be bad args */
+	    return NULL;
+	}
+	if (rvOpt->data) {
+	    digest = rvOpt->data;
+	}
+	digestLen = rvOpt->size;
+    }
+    if (!digest) {
+	digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
+	if (!digest) {
+	    nssSession_ExitMonitor(session);
+	    return NULL;
+	}
+    }
+    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
+    nssSession_ExitMonitor(session);
+    if (ckrv != CKR_OK) {
+	nss_ZFreeIf(digest);
+	return NULL;
+    }
+    if (!rvOpt) {
+	rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
+    }
+    return rvItem;
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_IsPresent (
+  NSSToken *token
+)
+{
+    return nssSlot_IsTokenPresent(token->slot);
+}
+
+/* Sigh.  The methods to find objects declared above cause problems with
+ * the low-level object cache in the softoken -- the objects are found in 
+ * toto, then one wave of GetAttributes is done, then another.  Having a 
+ * large number of objects causes the cache to be thrashed, as the objects 
+ * are gone before there's any chance to ask for their attributes.
+ * So, for now, bringing back traversal methods for certs.  This way all of 
+ * the cert's attributes can be grabbed immediately after finding it,
+ * increasing the likelihood that the cache takes care of it.
+ */
+NSS_IMPLEMENT PRStatus
+nssToken_TraverseCertificates (
+  NSSToken *token,
+  nssSession *sessionOpt,
+  nssTokenSearchType searchType,
+  PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
+  void *arg
+)
+{
+    CK_RV ckrv;
+    CK_ULONG count;
+    CK_OBJECT_HANDLE *objectHandles;
+    CK_ATTRIBUTE_PTR attr;
+    CK_ATTRIBUTE cert_template[2];
+    CK_ULONG ctsize;
+    NSSArena *arena;
+    PRStatus status;
+    PRUint32 arraySize, numHandles;
+    nssCryptokiObject **objects;
+    void *epv = nssToken_GetCryptokiEPV(token);
+    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
+
+    /* Don't ask the module to use an invalid session handle. */
+    if (!session || session->handle == CK_INVALID_SESSION) {
+	PORT_SetError(SEC_ERROR_NO_TOKEN);
+	return PR_FAILURE;
+    }
+
+    /* template for all certs */
+    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
+    if (searchType == nssTokenSearchType_SessionOnly) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
+    } else if (searchType == nssTokenSearchType_TokenOnly ||
+               searchType == nssTokenSearchType_TokenForced) {
+	NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
+    }
+    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
+    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
+
+    /* the arena is only for the array of object handles */
+    arena = nssArena_Create();
+    if (!arena) {
+	return PR_FAILURE;
+    }
+    arraySize = OBJECT_STACK_SIZE;
+    numHandles = 0;
+    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
+    if (!objectHandles) {
+	goto loser;
+    }
+    nssSession_EnterMonitor(session); /* ==== session lock === */
+    /* Initialize the find with the template */
+    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, 
+                                         cert_template, ctsize);
+    if (ckrv != CKR_OK) {
+	nssSession_ExitMonitor(session);
+	goto loser;
+    }
+    while (PR_TRUE) {
+	/* Issue the find for up to arraySize - numHandles objects */
+	ckrv = CKAPI(epv)->C_FindObjects(session->handle, 
+	                                 objectHandles + numHandles, 
+	                                 arraySize - numHandles, 
+	                                 &count);
+	if (ckrv != CKR_OK) {
+	    nssSession_ExitMonitor(session);
+	    goto loser;
+	}
+	/* bump the number of found objects */
+	numHandles += count;
+	if (numHandles < arraySize) {
+	    break;
+	}
+	/* the array is filled, double it and continue */
+	arraySize *= 2;
+	objectHandles = nss_ZREALLOCARRAY(objectHandles, 
+	                                  CK_OBJECT_HANDLE, 
+	                                  arraySize);
+	if (!objectHandles) {
+	    nssSession_ExitMonitor(session);
+	    goto loser;
+	}
+    }
+    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
+    nssSession_ExitMonitor(session); /* ==== end session lock === */
+    if (ckrv != CKR_OK) {
+	goto loser;
+    }
+    if (numHandles > 0) {
+	objects = create_objects_from_handles(token, session,
+	                                      objectHandles, numHandles);
+	if (objects) {
+	    nssCryptokiObject **op;
+	    for (op = objects; *op; op++) {
+		status = (*callback)(*op, arg);
+	    }
+	    nss_ZFreeIf(objects);
+	}
+    }
+    nssArena_Destroy(arena);
+    return PR_SUCCESS;
+loser:
+    nssArena_Destroy(arena);
+    return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRBool
+nssToken_IsPrivateKeyAvailable (
+  NSSToken *token,
+  NSSCertificate *c,
+  nssCryptokiObject *instance
+)
+{
+    CK_OBJECT_CLASS theClass;
+
+    if (token == NULL) return PR_FALSE;
+    if (c == NULL) return PR_FALSE;
+
+    theClass = CKO_PRIVATE_KEY;
+    if (!nssSlot_IsLoggedIn(token->slot)) {
+	theClass = CKO_PUBLIC_KEY;
+    }
+    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) 
+						!= CK_INVALID_HANDLE) {
+	return PR_TRUE;
+    }
+    return PR_FALSE;
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)